summaryrefslogtreecommitdiff
path: root/lib/CWayland/CWayland.cc
diff options
context:
space:
mode:
authorHannes Schulze <haschu0103@outlook.de>2026-03-15 15:56:57 +0100
committerHannes Schulze <haschu0103@outlook.de>2026-03-15 15:56:57 +0100
commit79b911b020ae492203688cb4c75884edc8ab20c9 (patch)
tree7717e0436becc6ee6203fadd3262f4136a69b62a /lib/CWayland/CWayland.cc
parent0b7ad07db1be69f75ca9b469fd6210c64ba87dd5 (diff)
native api sketch
Diffstat (limited to 'lib/CWayland/CWayland.cc')
-rw-r--r--lib/CWayland/CWayland.cc445
1 files changed, 436 insertions, 9 deletions
diff --git a/lib/CWayland/CWayland.cc b/lib/CWayland/CWayland.cc
index cf1687a..cff3fd1 100644
--- a/lib/CWayland/CWayland.cc
+++ b/lib/CWayland/CWayland.cc
@@ -40,7 +40,7 @@ namespace
return ref{ ptr, steal_token{} };
}
- explicit ref() : ptr{ nullptr }
+ ref() : ptr{ nullptr }
{
}
@@ -122,6 +122,19 @@ namespace
return lean_io_result_mk_error(error);
}
+
+ std::size_t message_argument_count(const wl_message* msg)
+ {
+ std::size_t res = 0;
+ for (char c : std::string_view{ msg->signature })
+ {
+ if (c >= 'a' && c <= 'z') { res += 1; }
+ }
+ return res;
+ }
+
+ // Global dispatcher func, assumes a user_data of type (UInt32 → ArgumentReader → EventLoop M × M)
+ int dispatcher_func(const void* user_data, void* target, uint32_t opcode, const wl_message* msg, wl_argument* args);
}
// -- Constants
@@ -148,7 +161,15 @@ namespace
lean_external_class* waylean_display_class()
{
static lean_external_class* klass = lean_register_external_class(
- [](void* ptr) { wl_display_disconnect(static_cast<wl_display*>(ptr)); },
+ [](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*, b_lean_obj_arg fn) { }
);
return klass;
@@ -161,8 +182,10 @@ 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);
+
+ wl_proxy_add_dispatcher((wl_proxy*)disp, dispatcher_func, waylean_disp, nullptr);
+
return lean_io_result_mk_ok(waylean_disp);
}
@@ -320,6 +343,8 @@ namespace
timer_source_queue timers;
std::vector<pollfd> pollfds;
std::deque<scheduled_event> scheduled;
+ // Display source ID currently in dispatch_pending, used to associate events with their source ID.
+ size_t dispatching_display{};
void rebuild_pollfds()
{
@@ -403,6 +428,14 @@ namespace
return res;
}
+ void queue_display_message(ref message)
+ {
+ auto ev = scheduled_event{};
+ ev.id = dispatching_display;
+ ev.message = std::move(message);
+ scheduled.emplace_back(std::move(ev));
+ }
+
void remove(event_source const& source)
{
// Discharge event source long-term.
@@ -456,6 +489,7 @@ namespace
// Otherwise, fetch any new events.
for (auto& src : displays)
{
+ dispatching_display = src.id;
while (wl_display_prepare_read(src.disp))
{
if (wl_display_dispatch_pending(src.disp) == -1)
@@ -509,6 +543,7 @@ namespace
// 2. Process display events.
for (auto& src : displays)
{
+ dispatching_display = src.id;
if (wl_display_read_events(src.disp) == -1)
{
perror("event_loop::poll: wl_display_read_events");
@@ -810,24 +845,416 @@ lean_obj_res waylean_type_map_register(b_lean_obj_arg map_obj, b_lean_obj_arg if
return lean_io_result_mk_ok(lean_box(0));
}
+// -- Argument Writer
+
+namespace
+{
+ class argument_writer
+ {
+ static constexpr std::size_t max_args = 64;
+
+ std::size_t used{ 0 };
+ std::array<wl_argument, max_args> args{};
+ std::array<ref, max_args> refs{};
+
+ std::size_t new_arg()
+ {
+ assert(used + 1 < max_args && "reached maximum number of arguments");
+ return used++;
+ }
+
+ public:
+ wl_argument* get_args() { return args.data(); }
+
+ void write_int(int32_t value)
+ {
+ auto i = new_arg();
+ args[i].i = value;
+ }
+
+ void write_uint(uint32_t value)
+ {
+ auto i = new_arg();
+ args[i].u = value;
+ }
+
+ void write_fixed(float value)
+ {
+ auto i = new_arg();
+ args[i].f = wl_fixed_from_double(value);
+ }
+
+ void write_string(b_lean_obj_arg value)
+ {
+ auto i = new_arg();
+ if (lean_is_scalar(value))
+ {
+ args[i].s = nullptr;
+ }
+ else
+ {
+ lean_object* val = lean_ctor_get(value, 0);
+ args[i].s = lean_string_cstr(val);
+ refs[i] = ref{ val };
+ }
+ }
+
+ void write_object(b_lean_obj_arg value)
+ {
+ auto i = new_arg();
+ if (lean_is_scalar(value))
+ {
+ args[i].o = nullptr;
+ }
+ else
+ {
+ lean_object* val = lean_ctor_get(value, 0);
+ args[i].o = static_cast<wl_object*>(lean_get_external_data(val));
+ refs[i] = ref{ val };
+ }
+ }
+
+ void write_new_id(b_lean_obj_arg value)
+ {
+ auto i = new_arg();
+ args[i].n = wl_proxy_get_id(static_cast<wl_proxy*>(lean_get_external_data(value)));
+ refs[i] = ref{ value };
+ }
+
+ void write_array(b_lean_obj_arg value)
+ {
+ auto i = new_arg();
+ std::size_t size = lean_sarray_size(value);
+ args[i].a->alloc = size;
+ args[i].a->size = size;
+ args[i].a->data = lean_sarray_cptr(value);
+ refs[i] = ref{ value };
+ }
+
+ void write_fd(int32_t value)
+ {
+ auto i = new_arg();
+ args[i].h = value;
+ }
+ };
+
+ lean_external_class* waylean_argument_writer_class()
+ {
+ static lean_external_class* klass = lean_register_external_class(
+ [](void* ptr) { delete static_cast<argument_writer*>(ptr); },
+ [](void*, b_lean_obj_arg fn) { }
+ );
+ return klass;
+ }
+}
+
+// ArgumentWriter.new : IO ArgumentWriter
+lean_obj_res waylean_argument_writer_new(void)
+{
+ argument_writer* writer = new argument_writer;
+ lean_object* waylean_writer = lean_alloc_external(waylean_argument_writer_class(), writer);
+ return lean_io_result_mk_ok(waylean_writer);
+}
+
+// ArgumentWriter.writeInt : (writer : @& ArgumentWriter) → (value : Int32) → IO Unit
+lean_obj_res waylean_argument_writer_write_int(b_lean_obj_arg writer_obj, int32_t value)
+{
+ auto writer = static_cast<argument_writer*>(lean_get_external_data(writer_obj));
+ writer->write_int(value);
+ return lean_io_result_mk_ok(lean_box(0));
+}
+
+// ArgumentWriter.writeUInt : (writer : @& ArgumentWriter) → (value : UInt32) → IO Unit
+lean_obj_res waylean_argument_writer_write_uint(b_lean_obj_arg writer_obj, uint32_t value)
+{
+ auto writer = static_cast<argument_writer*>(lean_get_external_data(writer_obj));
+ writer->write_uint(value);
+ return lean_io_result_mk_ok(lean_box(0));
+}
+
+// ArgumentWriter.writeFloat : (writer : @& ArgumentWriter) → (value : Float) → IO Unit
+lean_obj_res waylean_argument_writer_write_fixed(b_lean_obj_arg writer_obj, float value)
+{
+ auto writer = static_cast<argument_writer*>(lean_get_external_data(writer_obj));
+ writer->write_fixed(value);
+ return lean_io_result_mk_ok(lean_box(0));
+}
+
+// ArgumentWriter.writeString : (writer : @& ArgumentWriter) → (value : @& Option String) → IO Unit
+lean_obj_res waylean_argument_writer_write_string(b_lean_obj_arg writer_obj, b_lean_obj_arg value)
+{
+ auto writer = static_cast<argument_writer*>(lean_get_external_data(writer_obj));
+ writer->write_string(value);
+ return lean_io_result_mk_ok(lean_box(0));
+}
+
+// ArgumentWriter.writeObject : (writer : @& ArgumentWriter) → (value : @& Option Proxy) → IO Unit
+lean_obj_res waylean_argument_writer_write_object(b_lean_obj_arg writer_obj, b_lean_obj_arg value)
+{
+ auto writer = static_cast<argument_writer*>(lean_get_external_data(writer_obj));
+ writer->write_object(value);
+ return lean_io_result_mk_ok(lean_box(0));
+}
+
+// ArgumentWriter.writeNewID : (writer : @& ArgumentWriter) → (value : @& Proxy) → IO Unit
+lean_obj_res waylean_argument_writer_write_new_id(b_lean_obj_arg writer_obj, b_lean_obj_arg value)
+{
+ auto writer = static_cast<argument_writer*>(lean_get_external_data(writer_obj));
+ writer->write_new_id(value);
+ return lean_io_result_mk_ok(lean_box(0));
+}
+
+// ArgumentWriter.writeArray : (writer : @& ArgumentWriter) → (value : @& ByteArray) → IO Unit
+lean_obj_res waylean_argument_writer_write_array(b_lean_obj_arg writer_obj, b_lean_obj_arg value)
+{
+ auto writer = static_cast<argument_writer*>(lean_get_external_data(writer_obj));
+ writer->write_array(value);
+ return lean_io_result_mk_ok(lean_box(0));
+}
+
+// ArgumentWriter.writeFD : (writer : @& ArgumentWriter) → (value : Int32) → IO Unit
+lean_obj_res waylean_argument_writer_write_fd(b_lean_obj_arg writer_obj, int32_t value)
+{
+ auto writer = static_cast<argument_writer*>(lean_get_external_data(writer_obj));
+ writer->write_fd(value);
+ return lean_io_result_mk_ok(lean_box(0));
+}
+
+// -- Argument Reader
+
+namespace
+{
+ struct argument_reader
+ {
+ wl_argument* args{ nullptr };
+ std::size_t current{ 0 };
+
+ wl_argument next_arg()
+ {
+ assert(args != nullptr && "expected argument reader to still be alive");
+ return args[current++];
+ }
+
+ ref read_int()
+ {
+ return ref::steal(lean_box_uint32(next_arg().i));
+ }
+
+ ref read_uint()
+ {
+ return ref::steal(lean_box_uint32(next_arg().u));
+ }
+
+ ref read_fixed()
+ {
+ return ref::steal(lean_box_float(wl_fixed_to_double(next_arg().f)));
+ }
+
+ ref read_string()
+ {
+ auto s = next_arg().s;
+ if (s)
+ {
+ auto res = ref::steal(lean_alloc_ctor(1, 1, 0));
+ lean_ctor_set(res.get(), 0, lean_mk_string_from_bytes(s, strlen(s)));
+ return res;
+ }
+ else
+ {
+ return ref::steal(lean_box(0));
+ }
+ }
+
+ ref read_object()
+ {
+ auto o = next_arg().o;
+ if (o)
+ {
+ auto res = ref::steal(lean_alloc_ctor(1, 1, 0));
+ auto proxy_obj = (lean_object*)(wl_proxy_get_listener((wl_proxy*)o)); // set as dispatcher_data
+ lean_inc(proxy_obj);
+ lean_ctor_set(res.get(), 0, proxy_obj);
+ return res;
+ }
+ else
+ {
+ return ref::steal(lean_box(0));
+ }
+ }
+
+ ref read_new_id()
+ {
+ return ref::steal(lean_box_uint32(next_arg().n));
+ }
+
+ ref read_array()
+ {
+ auto a = next_arg().a;
+ auto res = ref::steal(lean_alloc_sarray(1, a->size, a->size));
+ std::copy_n(static_cast<uint8_t*>(a->data), a->size, lean_sarray_cptr(res.get()));
+ return res;
+ }
+
+ ref read_fd()
+ {
+ return ref::steal(lean_box_uint32(next_arg().h));
+ }
+ };
+
+ lean_external_class* waylean_argument_reader_class()
+ {
+ static lean_external_class* klass = lean_register_external_class(
+ [](void* ptr) { delete static_cast<argument_reader*>(ptr); },
+ [](void*, b_lean_obj_arg fn) { }
+ );
+ return klass;
+ }
+}
+
+// ArgumentReader.readInt : (reader : @& ArgumentReader) → IO Int32
+lean_obj_res waylean_argument_reader_read_int(b_lean_obj_arg reader_obj)
+{
+ auto reader = static_cast<argument_reader*>(lean_get_external_data(reader_obj));
+ return lean_io_result_mk_ok(reader->read_int().release());
+}
+
+// ArgumentReader.readUInt : (reader : @& ArgumentReader) → IO Int32
+lean_obj_res waylean_argument_reader_read_uint(b_lean_obj_arg reader_obj)
+{
+ auto reader = static_cast<argument_reader*>(lean_get_external_data(reader_obj));
+ return lean_io_result_mk_ok(reader->read_uint().release());
+}
+
+// ArgumentReader.readFixed : (reader : @& ArgumentReader) → IO Float
+lean_obj_res waylean_argument_reader_read_fixed(b_lean_obj_arg reader_obj)
+{
+ auto reader = static_cast<argument_reader*>(lean_get_external_data(reader_obj));
+ return lean_io_result_mk_ok(reader->read_fixed().release());
+}
+
+// ArgumentReader.readString : (reader : @& ArgumentReader) → IO (Option String)
+lean_obj_res waylean_argument_reader_read_string(b_lean_obj_arg reader_obj)
+{
+ auto reader = static_cast<argument_reader*>(lean_get_external_data(reader_obj));
+ return lean_io_result_mk_ok(reader->read_string().release());
+}
+
+// ArgumentReader.readObject : (reader : @& ArgumentReader) → IO (Option Proxy)
+lean_obj_res waylean_argument_reader_read_object(b_lean_obj_arg reader_obj)
+{
+ auto reader = static_cast<argument_reader*>(lean_get_external_data(reader_obj));
+ return lean_io_result_mk_ok(reader->read_object().release());
+}
+
+// ArgumentReader.readNewID : (reader : @& ArgumentReader) → IO UInt32
+lean_obj_res waylean_argument_reader_read_new_id(b_lean_obj_arg reader_obj)
+{
+ auto reader = static_cast<argument_reader*>(lean_get_external_data(reader_obj));
+ return lean_io_result_mk_ok(reader->read_new_id().release());
+}
+
+// ArgumentReader.readArray : (reader : @& ArgumentReader) → IO ByteArray
+lean_obj_res waylean_argument_reader_read_array(b_lean_obj_arg reader_obj)
+{
+ auto reader = static_cast<argument_reader*>(lean_get_external_data(reader_obj));
+ return lean_io_result_mk_ok(reader->read_array().release());
+}
+
+// ArgumentReader.readFD : (reader : @& ArgumentReader) → IO Int32
+lean_obj_res waylean_argument_reader_read_fd(b_lean_obj_arg reader_obj)
+{
+ auto reader = static_cast<argument_reader*>(lean_get_external_data(reader_obj));
+ return lean_io_result_mk_ok(reader->read_fd().release());
+}
+
// -- Proxy
-// Proxy.fromDisplay : (display : @& Display) → IO Proxy
-lean_obj_res waylean_proxy_from_display(b_lean_obj_arg display)
+namespace
+{
+ int dispatcher_func(const void* user_data, void* target, uint32_t opcode, const wl_message* msg, wl_argument* args)
+ {
+ if (!user_data) { return 0; }
+
+ auto handler = ref{ (lean_object*)user_data };
+ auto reader = new argument_reader;
+ auto reader_obj = ref::steal(lean_alloc_external(waylean_argument_reader_class(), reader));
+
+ reader->args = args;
+ auto tuple = ref::steal(
+ lean_apply_2(
+ std::move(handler).release(),
+ lean_box_uint32(opcode),
+ std::move(reader_obj).release()
+ )
+ );
+ // TODO: Won't work because reader is only used in the event loop.
+ reader->args = nullptr;
+
+ auto loop_obj = lean_ctor_get(tuple.get(), 0);
+ auto loop = static_cast<event_loop*>(lean_get_external_data(loop_obj));
+ auto message_obj = lean_ctor_get(tuple.get(), 1);
+
+ loop->queue_display_message(ref{ message_obj });
+
+ return 0;
+ }
+
+ 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*, b_lean_obj_arg fn) { }
+ );
+ return klass;
+ }
+}
+
+// Proxy.fromDisplay : (display : Display) → IO Proxy
+lean_obj_res waylean_proxy_from_display(lean_obj_arg display)
{
+ return lean_io_result_mk_ok(display);
}
// Proxy.new : (factory : @& Proxy) → (typeMap : @& TypeMap) → (ifaceName : @& String) → IO Proxy
-lean_obj_res waylean_proxy_new(b_lean_obj_arg factory, b_lean_obj_arg type_map, b_lean_obj_arg iface_name)
+lean_obj_res waylean_proxy_new(b_lean_obj_arg factory_obj, b_lean_obj_arg map_obj, b_lean_obj_arg iface_name)
{
+ auto factory = static_cast<wl_proxy*>(lean_get_external_data(factory_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->initialized && "expected interface to be initialized during construction");
+ wl_proxy* res = wl_proxy_create(factory, &iface->desc);
+ lean_object* waylean_res = lean_alloc_external(waylean_proxy_class(), res);
+ if (!res) { return io_result_mk_from_errno("<unknown>"); }
+
+ wl_proxy_add_dispatcher(res, dispatcher_func, waylean_res, nullptr);
+
+ return lean_io_result_mk_ok(waylean_res);
}
// Proxy.send : (proxy : @& Proxy) → (opcode : UInt32) → (argumentWriter : @& ArgumentWriter) → IO Unit
-lean_obj_res waylean_proxy_send(b_lean_obj_arg proxy, uint32_t opcode, b_lean_obj_arg argument_writer)
+lean_obj_res waylean_proxy_send(b_lean_obj_arg proxy_obj, uint32_t opcode, b_lean_obj_arg writer_obj)
{
+ auto proxy = static_cast<wl_proxy*>(lean_get_external_data(proxy_obj));
+ auto writer = static_cast<argument_writer*>(lean_get_external_data(writer_obj));
+ wl_proxy_marshal_array(proxy, opcode, writer->get_args());
+ return lean_io_result_mk_ok(lean_box(0));
}
-// Proxy.listen : (proxy : @& Proxy) → (handler : @& UInt32 → ArgumentReader → EventLoop M × M) → IO Unit
-lean_obj_res waylean_proxy_listen(b_lean_obj_arg proxy, b_lean_obj_arg handler)
+// Proxy.listen : (proxy : @& Proxy) → (handler : UInt32 → ArgumentReader → 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 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);
+ return lean_io_result_mk_ok(lean_box(0));
} \ No newline at end of file