summaryrefslogtreecommitdiff
path: root/lib/CWayland/CWayland.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CWayland/CWayland.cc')
-rw-r--r--lib/CWayland/CWayland.cc220
1 files changed, 159 insertions, 61 deletions
diff --git a/lib/CWayland/CWayland.cc b/lib/CWayland/CWayland.cc
index 08df50b..88586bb 100644
--- a/lib/CWayland/CWayland.cc
+++ b/lib/CWayland/CWayland.cc
@@ -15,6 +15,7 @@
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
+#include <atomic>
namespace
{
@@ -104,6 +105,32 @@ namespace
}
};
+ struct stable_ptr
+ {
+ static inline std::atomic<std::uint64_t> current_id = 0;
+
+ std::uint64_t id;
+ void* ptr;
+ void (*destructor)(void*);
+
+ explicit stable_ptr(void* ptr, void (*destructor)(void*))
+ : id{ current_id++ }
+ , ptr{ ptr }
+ , destructor{ destructor }
+ {
+ }
+
+ stable_ptr(stable_ptr const&) = delete;
+ stable_ptr(stable_ptr&&) = delete;
+ stable_ptr& operator=(stable_ptr const&) = delete;
+ stable_ptr& operator=(stable_ptr&&) = delete;
+
+ ~stable_ptr()
+ {
+ if (ptr) { destructor(ptr); }
+ }
+ };
+
char const* option_cstr_or_null(b_lean_obj_arg str)
{
if (lean_is_scalar(str))
@@ -126,6 +153,13 @@ namespace
return lean_io_result_mk_error(error);
}
+ lean_obj_res io_result_mk_resource_vanished()
+ {
+ ref file_name_str = ref::steal(lean_mk_string("<unknown>"));
+ lean_object* error = lean_decode_io_error(EIDRM, file_name_str.get());
+ return lean_io_result_mk_error(error);
+ }
+
// Global dispatcher func, assumes a user_data of type (UInt32 → ArgumentBuffer → EventLoop M × M)
int dispatcher_func(const void* user_data, void* target, uint32_t opcode, const wl_message* msg, wl_argument* args);
}
@@ -154,19 +188,27 @@ namespace
lean_external_class* waylean_display_class()
{
static lean_external_class* klass = lean_register_external_class(
- [](void* ptr)
- {
- auto disp = static_cast<wl_display*>(ptr);
- if (auto user_data = wl_proxy_get_user_data((wl_proxy*)disp))
- {
- lean_dec(static_cast<lean_object*>(user_data));
- }
- wl_display_disconnect(disp);
- },
+ [](void* ptr) { delete static_cast<stable_ptr*>(ptr); },
[](void*, b_lean_obj_arg fn) { }
);
return klass;
}
+
+ void waylean_proxy_deref_user_data(wl_proxy* proxy)
+ {
+ if (auto user_data = wl_proxy_get_user_data(proxy))
+ {
+ lean_dec(static_cast<lean_object*>(user_data));
+ }
+ }
+
+ void waylean_display_destructor(void* ptr)
+ {
+ auto proxy = static_cast<wl_proxy*>(ptr);
+ auto disp = static_cast<wl_display*>(ptr);
+ waylean_proxy_deref_user_data(proxy);
+ wl_display_disconnect(disp);
+ }
}
// Display.new : (name : @& Option String) → IO Display
@@ -175,7 +217,8 @@ lean_obj_res waylean_display_new(b_lean_obj_arg name)
char const* name_cstr = option_cstr_or_null(name);
wl_display* disp = wl_display_connect(name_cstr);
if (!disp) { return io_result_mk_from_errno(name_cstr ? name_cstr : "<default>"); }
- lean_object* waylean_disp = lean_alloc_external(waylean_display_class(), disp);
+ auto sptr = new stable_ptr{ disp, waylean_display_destructor };
+ lean_object* waylean_disp = lean_alloc_external(waylean_display_class(), sptr);
return lean_io_result_mk_ok(waylean_disp);
}
@@ -183,7 +226,9 @@ lean_obj_res waylean_display_new(b_lean_obj_arg name)
// Display.flush : (display : @& Display) → IO Unit
lean_obj_res waylean_display_flush(b_lean_obj_arg disp_obj)
{
- wl_display* disp = static_cast<wl_display*>(lean_get_external_data(disp_obj));
+ auto sptr = static_cast<stable_ptr*>(lean_get_external_data(disp_obj));
+ auto disp = static_cast<wl_display*>(sptr->ptr);
+ if (!disp) { return io_result_mk_resource_vanished(); }
if (wl_display_flush(disp) == -1) { return io_result_mk_from_errno("<unknown>"); }
return lean_io_result_mk_ok(lean_box(0));
}
@@ -281,7 +326,7 @@ namespace
struct display_source
{
ref display_ref{};
- wl_display* disp{};
+ stable_ptr* disp{};
size_t id{};
};
@@ -349,10 +394,13 @@ namespace
for (auto& src : displays)
{
- pollfd disp_pollfd{};
- disp_pollfd.fd = wl_display_get_fd(src.disp);
- disp_pollfd.events = POLLIN;
- pollfds.emplace_back(disp_pollfd);
+ if (auto disp = static_cast<wl_display*>(src.disp->ptr))
+ {
+ pollfd disp_pollfd{};
+ disp_pollfd.fd = wl_display_get_fd(disp);
+ disp_pollfd.events = POLLIN;
+ pollfds.emplace_back(disp_pollfd);
+ }
}
}
@@ -378,7 +426,7 @@ namespace
res.id = next_id++;
auto source = display_source{};
- source.disp = static_cast<wl_display*>(lean_get_external_data(display.get()));
+ source.disp = static_cast<stable_ptr*>(lean_get_external_data(display.get()));
source.display_ref = std::move(display);
source.id = res.id;
displays.emplace_back(std::move(source));
@@ -482,14 +530,17 @@ namespace
for (auto& src : displays)
{
dispatching_display = src.id;
- while (wl_display_prepare_read(src.disp))
+ if (auto disp = static_cast<wl_display*>(src.disp->ptr))
{
- return ref::steal(io_result_mk_from_errno("<default>"));
- }
+ while (wl_display_prepare_read(disp))
+ {
+ return ref::steal(io_result_mk_from_errno("<default>"));
+ }
- if (wl_display_flush(src.disp) == -1)
- {
- return ref::steal(io_result_mk_from_errno("<default>"));
+ if (wl_display_flush(disp) == -1)
+ {
+ return ref::steal(io_result_mk_from_errno("<default>"));
+ }
}
}
@@ -533,13 +584,16 @@ namespace
for (auto& src : displays)
{
dispatching_display = src.id;
- if (wl_display_read_events(src.disp) == -1)
- {
- return ref::steal(io_result_mk_from_errno("<default>"));
- }
- if (wl_display_dispatch_pending(src.disp) == -1)
+ if (auto disp = static_cast<wl_display*>(src.disp->ptr))
{
- return ref::steal(io_result_mk_from_errno("<default>"));
+ if (wl_display_read_events(disp) == -1)
+ {
+ return ref::steal(io_result_mk_from_errno("<default>"));
+ }
+ if (wl_display_dispatch_pending(disp) == -1)
+ {
+ return ref::steal(io_result_mk_from_errno("<default>"));
+ }
}
}
@@ -905,17 +959,10 @@ namespace
meta[i].r = std::move(value);
}
- void write_object(ref value)
+ void write_object(ref value, wl_object* value_obj)
{
auto i = next_write();
- if (lean_is_scalar(value.get()))
- {
- args[i].o = nullptr;
- }
- else
- {
- args[i].o = static_cast<wl_object*>(lean_get_external_data(lean_ctor_get(value.get(), 0)));
- }
+ args[i].o = value_obj;
meta[i].t = type::object;
meta[i].r = std::move(value);
}
@@ -1101,7 +1148,14 @@ lean_obj_res waylean_argument_buffer_write_string(b_lean_obj_arg buffer_obj, b_l
lean_obj_res waylean_argument_buffer_write_object(b_lean_obj_arg buffer_obj, b_lean_obj_arg value)
{
auto buffer = static_cast<argument_buffer*>(lean_get_external_data(buffer_obj));
- buffer->write_object(ref{ value });
+ wl_object* obj = nullptr;
+ if (!lean_is_scalar(value))
+ {
+ auto sptr = static_cast<stable_ptr*>(lean_get_external_data(lean_ctor_get(value, 0)));
+ obj = static_cast<wl_object*>(sptr->ptr);
+ if (!obj) { return io_result_mk_resource_vanished(); }
+ }
+ buffer->write_object(ref{ value }, obj);
return lean_io_result_mk_ok(lean_box(0));
}
@@ -1219,23 +1273,23 @@ namespace
lean_external_class* waylean_proxy_class()
{
static lean_external_class* klass = lean_register_external_class(
- [](void* ptr)
- {
- auto proxy = static_cast<wl_proxy*>(ptr);
- if (auto user_data = wl_proxy_get_user_data(proxy))
- {
- lean_dec(static_cast<lean_object*>(user_data));
- }
- wl_proxy_destroy(proxy);
- },
+ [](void* ptr) { delete static_cast<stable_ptr*>(ptr); },
[](void*, b_lean_obj_arg fn) { }
);
return klass;
}
+ void waylean_proxy_destructor(void* ptr)
+ {
+ auto proxy = static_cast<wl_proxy*>(ptr);
+ waylean_proxy_deref_user_data(proxy);
+ wl_proxy_destroy(proxy);
+ }
+
ref init_proxy_wrapper(wl_proxy* proxy)
{
- lean_object* waylean_res = lean_alloc_external(waylean_proxy_class(), proxy);
+ auto sptr = new stable_ptr{ proxy, waylean_proxy_destructor };
+ auto waylean_res = lean_alloc_external(waylean_proxy_class(), sptr);
wl_proxy_add_dispatcher(proxy, dispatcher_func, waylean_res, nullptr);
return ref::steal(waylean_res);
@@ -1248,27 +1302,55 @@ lean_obj_res waylean_proxy_from_display(lean_obj_arg display)
return lean_io_result_mk_ok(display);
}
-// Proxy.send : (proxy : @& Proxy) → (opcode : UInt32) → (argumentBuffer : @& ArgumentBuffer) → IO Unit
-lean_obj_res waylean_proxy_send(b_lean_obj_arg proxy_obj, uint32_t opcode, b_lean_obj_arg buffer_obj)
+// Proxy.send : (proxy : @& Proxy) → (opcode : UInt32) → (argumentBuffer : @& ArgumentBuffer) → (destroy : UInt32) → IO Unit
+lean_obj_res waylean_proxy_send(b_lean_obj_arg proxy_obj, uint32_t opcode, b_lean_obj_arg buffer_obj, uint32_t destroy)
{
- auto proxy = static_cast<wl_proxy*>(lean_get_external_data(proxy_obj));
+ auto sptr = static_cast<stable_ptr*>(lean_get_external_data(proxy_obj));
+ auto proxy = static_cast<wl_proxy*>(sptr->ptr);
+ if (!proxy) { return io_result_mk_resource_vanished(); }
+
auto buffer = static_cast<argument_buffer*>(lean_get_external_data(buffer_obj));
- wl_proxy_marshal_array(proxy, opcode, buffer->get_args());
+ wl_proxy_marshal_array_flags(
+ proxy,
+ opcode,
+ nullptr,
+ wl_proxy_get_version(proxy),
+ destroy ? WL_MARSHAL_FLAG_DESTROY : 0,
+ buffer->get_args());
+ if (destroy)
+ {
+ waylean_proxy_deref_user_data(proxy);
+ sptr->ptr = nullptr;
+ }
return lean_io_result_mk_ok(lean_box(0));
}
-// Proxy.sendConstructor : (proxy : @& Proxy) → (opcode : UInt32) → (argumentBuffer : @& ArgumentBuffer) → (typeMap : @& TypeMap) → (ifaceName : @& String) → IO Proxy
-lean_obj_res waylean_proxy_send_constructor(b_lean_obj_arg proxy_obj, uint32_t opcode, b_lean_obj_arg buffer_obj, b_lean_obj_arg map_obj, b_lean_obj_arg iface_name)
+// Proxy.sendConstructor : (proxy : @& Proxy) → (opcode : UInt32) → (argumentBuffer : @& ArgumentBuffer) → (destroy : UInt32) → (typeMap : @& TypeMap) → (ifaceName : @& String) → IO Proxy
+lean_obj_res waylean_proxy_send_constructor(b_lean_obj_arg proxy_obj, uint32_t opcode, b_lean_obj_arg buffer_obj, uint32_t destroy, b_lean_obj_arg map_obj, b_lean_obj_arg iface_name)
{
- auto proxy = static_cast<wl_proxy*>(lean_get_external_data(proxy_obj));
+ auto sptr = static_cast<stable_ptr*>(lean_get_external_data(proxy_obj));
+ auto proxy = static_cast<wl_proxy*>(sptr->ptr);
+ if (!proxy) { return io_result_mk_resource_vanished(); }
+
auto buffer = static_cast<argument_buffer*>(lean_get_external_data(buffer_obj));
auto map = static_cast<type_map*>(lean_get_external_data(map_obj));
auto iface = map->resolve_iface(lean_string_cstr(iface_name));
assert(iface->is_complete && "expected interface to be initialized during construction");
- wl_proxy* res = wl_proxy_marshal_array_constructor(proxy, opcode, buffer->get_args(), &iface->desc);
+ wl_proxy* res = wl_proxy_marshal_array_flags(
+ proxy,
+ opcode,
+ &iface->desc,
+ wl_proxy_get_version(proxy),
+ destroy ? WL_MARSHAL_FLAG_DESTROY : 0,
+ buffer->get_args());
+ if (destroy)
+ {
+ waylean_proxy_deref_user_data(proxy);
+ sptr->ptr = nullptr;
+ }
if (!res) { return io_result_mk_from_errno("<unknown>"); }
return lean_io_result_mk_ok(init_proxy_wrapper(res).release());
@@ -1277,7 +1359,10 @@ lean_obj_res waylean_proxy_send_constructor(b_lean_obj_arg proxy_obj, uint32_t o
// Proxy.listen : (proxy : @& Proxy) → (handler : UInt32 → ArgumentBuffer → EventLoop M × M) → IO Unit
lean_obj_res waylean_proxy_listen(b_lean_obj_arg proxy_obj, lean_obj_arg handler)
{
- auto proxy = static_cast<wl_proxy*>(lean_get_external_data(proxy_obj));
+ auto sptr = static_cast<stable_ptr*>(lean_get_external_data(proxy_obj));
+ auto proxy = static_cast<wl_proxy*>(sptr->ptr);
+ if (!proxy) { return io_result_mk_resource_vanished(); }
+
auto old_data = static_cast<lean_object*>(wl_proxy_get_user_data(proxy));
if (old_data) { lean_dec(old_data); }
wl_proxy_set_user_data(proxy, handler);
@@ -1294,14 +1379,27 @@ lean_obj_res waylean_proxy_keep(b_lean_obj_arg proxy)
// Proxy.getType : (proxy : @& Proxy) → IO String
lean_obj_res waylean_proxy_get_type(b_lean_obj_arg proxy_obj)
{
- auto proxy = static_cast<wl_proxy*>(lean_get_external_data(proxy_obj));
+ auto sptr = static_cast<stable_ptr*>(lean_get_external_data(proxy_obj));
+ auto proxy = static_cast<wl_proxy*>(sptr->ptr);
+ if (!proxy) { return io_result_mk_resource_vanished(); }
+
auto name = wl_proxy_get_interface(proxy)->name;
return lean_io_result_mk_ok(lean_mk_string(name));
}
// Proxy.getID : (x : @& Proxy) → IO UInt64
-lean_obj_res waylean_proxy_get_id(b_lean_obj_arg x)
+lean_obj_res waylean_proxy_get_id(b_lean_obj_arg proxy_obj)
{
- auto proxy = static_cast<wl_proxy*>(lean_get_external_data(x));
+ auto sptr = static_cast<stable_ptr*>(lean_get_external_data(proxy_obj));
+ auto proxy = static_cast<wl_proxy*>(sptr->ptr);
+ if (!proxy) { return io_result_mk_resource_vanished(); }
+
return lean_io_result_mk_ok(lean_box_uint64(wl_proxy_get_id(proxy)));
+}
+
+// Proxy.getStableID : (x : @& Proxy) → IO UInt64
+lean_obj_res waylean_proxy_get_stable_id(b_lean_obj_arg proxy_obj)
+{
+ auto sptr = static_cast<stable_ptr*>(lean_get_external_data(proxy_obj));
+ return lean_io_result_mk_ok(lean_box_uint64(sptr->id));
} \ No newline at end of file