diff options
| author | Hannes Schulze <contact@haschu.me> | 2026-06-05 21:05:23 +0200 |
|---|---|---|
| committer | Hannes Schulze <contact@haschu.me> | 2026-06-05 22:29:21 +0200 |
| commit | 648edcd81fc2045cab70ec2b82d81577158d8613 (patch) | |
| tree | f8cb8a0b3d5c0fd13f16e0eb2ffdf2ba4a8f875c /lib/CWayland | |
| parent | 350d3ca21e6a2d215016c84afa07ccb75abd8a6e (diff) | |
first working version
Diffstat (limited to 'lib/CWayland')
| -rw-r--r-- | lib/CWayland/CWayland.cc | 220 | ||||
| -rw-r--r-- | lib/CWayland/CWayland.h | 5 |
2 files changed, 163 insertions, 62 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 diff --git a/lib/CWayland/CWayland.h b/lib/CWayland/CWayland.h index ff71348..1805b9f 100644 --- a/lib/CWayland/CWayland.h +++ b/lib/CWayland/CWayland.h @@ -73,10 +73,12 @@ lean_obj_res waylean_argument_buffer_read_fd (b_lean_obj_arg reader); lean_obj_res waylean_proxy_from_display (lean_obj_arg display); lean_obj_res waylean_proxy_send (b_lean_obj_arg proxy, uint32_t opcode, - b_lean_obj_arg argument_buffer); + b_lean_obj_arg argument_buffer, + uint32_t destroy); lean_obj_res waylean_proxy_send_constructor(b_lean_obj_arg proxy, uint32_t opcode, b_lean_obj_arg argument_buffer, + uint32_t destroy, b_lean_obj_arg type_map, b_lean_obj_arg iface_name); lean_obj_res waylean_proxy_listen (b_lean_obj_arg proxy, @@ -84,6 +86,7 @@ lean_obj_res waylean_proxy_listen (b_lean_obj_arg proxy, lean_obj_res waylean_proxy_keep (b_lean_obj_arg proxy); lean_obj_res waylean_proxy_get_type (b_lean_obj_arg proxy); lean_obj_res waylean_proxy_get_id (b_lean_obj_arg x); +lean_obj_res waylean_proxy_get_stable_id (b_lean_obj_arg x); #ifdef __cplusplus } |
