From 30c84a915ac53065bd82cbed4d012ff477d08206 Mon Sep 17 00:00:00 2001 From: maelstrom Date: Fri, 17 Apr 2026 09:22:30 +0200 Subject: [PATCH 1/2] minor adjustments for compliance --- include/Mw/LowLevel/Wayland.h | 1 + src/backend/wayland.c | 15 ++++++------- src/lowlevel.c | 42 +++++++++++++++++------------------ 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 7f9e762..a21c0da 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -454,6 +454,7 @@ struct _MwLLWayland { #endif MwBool dark_theme_detection; + MwU32 dark_theme; /* clipboard related stuff. * Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/ diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 5660125..a738aa3 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -17,8 +17,6 @@ wayland_call_table_t wl_call_tbl; MwBool MwWaylandAlwaysRender = MwFALSE; -MwU32 wl_dark_theme = -1; - /* Standard procedure before most event callbacks in Wayland ("most" because the setup ones don't need this). Wait for the Mutex to be freed, if we're deadlocking for longer then a quarter of a second then do nothing with the event. */ #define WAYLAND_EVENT_OP_START(self) \ do { \ @@ -1782,20 +1780,20 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh #ifdef USE_DBUS static void dark_theme_listener(MwLL handle, MwU32 new_value) { - wl_dark_theme = (new_value == 1) ? 1 : 0; + handle->wayland.dark_theme = (new_value == 1) ? 1 : 0; - MwLLDispatch(handle, dark_theme, &wl_dark_theme); + MwLLDispatch(handle, dark_theme, &handle->wayland.dark_theme); } static void detect_dark_theme(MwLL handle) { - MwU32 value = 0; + MwU32 value = 0; MwLLDBusPortalGet(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); - wl_dark_theme = (value == 1) ? 1 : 0; + handle->wayland.dark_theme = (value == 1) ? 1 : 0; MwLLDBusPortalWatch(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings"); - MwLLDispatch(handle, dark_theme, &wl_dark_theme); + MwLLDispatch(handle, dark_theme, &handle->wayland.dark_theme); } #endif @@ -1811,6 +1809,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { if(!parent && wl_call_tbl.has_dbus) { wl_call_tbl.has_dbus = MwLLDBusNewContext(&wl_call_tbl.dbus, &r->wayland.dbus); r->wayland.dark_theme_detection = MwTRUE; + r->wayland.dark_theme = -1; } #endif @@ -2439,7 +2438,7 @@ static void MwLLShowImpl(MwLL handle, int show) { static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { (void)handle; (void)parent; - /* Wayland doesn't have "popups" in the Milsko sense persay. xdg_popup is closer to ToolWindow and as such is what we use there. So just like the Mac backend, this is just left alone. */ + /* Wayland doesn't have "popups" in the Milsko sense per se. xdg_popup is closer to ToolWindow and as such is what we use there. So just like the Mac backend, this is just left alone. */ } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { diff --git a/src/lowlevel.c b/src/lowlevel.c index 935bf9b..32d5bca 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -184,48 +184,48 @@ MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, char filter_string[2048]; MwStringPrintIntoBuffer(filter_string, sizeof(filter_string), "type='%s',interface=%s", "signal", portal); - dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); - dbus_connection_flush(ctx->dbus_conn); + dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); + dbus_connection_flush(ctx->dbus_conn); return MwTRUE; } -// Technically this will swallow all other results, so this is not usable multiple times. -// TODO: Use a hashmap instead +/* Technically this will swallow all other results, so this is not usable multiple times. + TODO: Use a hashmap instead */ MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, MwLL handle, const char* portal, const char* namespace, const char* key, MwLLDBusPortalPollListener listener) { - DBusMessage* msg; + DBusMessage* msg; DBusMessageIter args, msg_value; - const char* msg_namespace; - const char* msg_key; - MwU32 msg_value_content; + const char* msg_namespace; + const char* msg_key; + MwU32 msg_value_content; if(!ctx->dbus_conn) { return MwFALSE; } - dbus_connection_read_write(ctx->dbus_conn, 0); + dbus_connection_read_write(ctx->dbus_conn, 0); msg = dbus_connection_pop_message(ctx->dbus_conn); - if (NULL == msg) { + if(NULL == msg) { return MwFALSE; } - // check if the message is a signal from the correct interface and with the correct name - if (dbus_message_is_signal(msg, portal, "SettingChanged")) { - // read the parameters - if (!dbus_message_iter_init(msg, &args)) - fprintf(stderr, "[WARNING] Message has no arguments\n"); - else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) - fprintf(stderr, "[WARNING] Argument is not string\n"); + /* check if the message is a signal from the correct interface and with the correct name */ + if(dbus_message_is_signal(msg, portal, "SettingChanged")) { + /* read the parameters */ + if(!dbus_message_iter_init(msg, &args)) + fprintf(stderr, "[WARNING] Message has no arguments\n"); + else if(DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) + fprintf(stderr, "[WARNING] Argument is not string\n"); else { dbus_message_iter_get_basic(&args, &msg_namespace); dbus_message_iter_next(&args); dbus_message_iter_get_basic(&args, &msg_key); - // Check that key and namespace match - if (strcmp(msg_namespace, namespace) == 0 && strcmp(msg_key, key) == 0) { - // Assuming the value is a basic type + /* Check that key and namespace match */ + if(strcmp(msg_namespace, namespace) == 0 && strcmp(msg_key, key) == 0) { + /* Assuming the value is a basic type */ dbus_message_iter_next(&args); dbus_message_iter_recurse(&args, &msg_value); dbus_message_iter_get_basic(&msg_value, &msg_value_content); @@ -235,7 +235,7 @@ MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, M } } - // free the message + /* free the message */ dbus_message_unref(msg); } From d6b96d0f8cca830e09b1a37a551855bd4c90b776 Mon Sep 17 00:00:00 2001 From: maelstrom Date: Fri, 17 Apr 2026 10:05:35 +0200 Subject: [PATCH 2/2] major surgery on dbus code --- include/Mw/LowLevel.h | 7 ++- src/lowlevel.c | 118 +++++++++++++++++++++++++++++++----------- 2 files changed, 93 insertions(+), 32 deletions(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 2ba3ff0..1b5ec52 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -66,11 +66,17 @@ typedef struct _MwLLDBusFuncTable { DBusMessage* (*dbus_message_new_method_call)(const char* bus_name, const char* path, const char* iface, const char* method); void (*dbus_message_iter_init_append)(DBusMessage* message, DBusMessageIter* iter); dbus_bool_t (*dbus_message_iter_append_basic)(DBusMessageIter* iter, int type, const void* value); + void (*dbus_connection_flush)(DBusConnection* connection); + dbus_bool_t (*dbus_connection_read_write)(DBusConnection* connection, int timeout_milliseconds); DBusMessage* (*dbus_connection_send_with_reply_and_block)(DBusConnection* connection, DBusMessage* message, int timeout_milliseconds, DBusError* error); + DBusMessage* (*dbus_connection_pop_message)(DBusConnection* connection); + void (*dbus_bus_add_match)(DBusConnection* connection, const char* rule, DBusError* error); void (*dbus_message_unref)(DBusMessage* message); dbus_bool_t (*dbus_message_iter_init)(DBusMessage* message, DBusMessageIter* iter); + dbus_bool_t (*dbus_message_is_signal)(DBusMessage* message, const char* iface, const char* signal_name); int (*dbus_message_iter_get_arg_type)(DBusMessageIter* iter); void (*dbus_message_iter_recurse)(DBusMessageIter* iter, DBusMessageIter* sub); + void (*dbus_message_iter_next)(DBusMessageIter* iter); void (*dbus_connection_unref)(DBusConnection* connection); void (*dbus_message_iter_get_basic)(DBusMessageIter* iter, void* value); } MwLLDBusFuncTable; @@ -80,7 +86,6 @@ typedef struct _MwLLDBusContext { DBusError dbus_err; DBusMessage* dbus_msg; DBusMessage* dbus_reply; - DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; } MwLLDBusContext; typedef void (*MwLLDBusPortalPollListener)(MwLL handle, MwU32 new_value); diff --git a/src/lowlevel.c b/src/lowlevel.c index 32d5bca..7dfeea1 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -82,16 +82,22 @@ MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl) { DBUS_FUNC(dbus_error_init); DBUS_FUNC(dbus_bus_get); + DBUS_FUNC(dbus_bus_add_match); DBUS_FUNC(dbus_error_is_set); DBUS_FUNC(dbus_error_free); DBUS_FUNC(dbus_message_new_method_call); + DBUS_FUNC(dbus_message_is_signal); DBUS_FUNC(dbus_message_iter_init_append); DBUS_FUNC(dbus_message_iter_append_basic); + DBUS_FUNC(dbus_connection_flush); + DBUS_FUNC(dbus_connection_pop_message); + DBUS_FUNC(dbus_connection_read_write); DBUS_FUNC(dbus_connection_send_with_reply_and_block); DBUS_FUNC(dbus_message_unref); DBUS_FUNC(dbus_message_iter_init); DBUS_FUNC(dbus_message_iter_get_arg_type); DBUS_FUNC(dbus_message_iter_recurse); + DBUS_FUNC(dbus_message_iter_next); DBUS_FUNC(dbus_connection_unref); DBUS_FUNC(dbus_message_iter_get_basic); @@ -121,6 +127,8 @@ MwBool MwLLDBusNewContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { }; MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal, const char* namespace, const char* key, void* out) { + DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; + char arg_type; if(!ctx->dbus_conn) { return MwFALSE; } @@ -135,9 +143,9 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co return MwFALSE; } - tbl->dbus_message_iter_init_append(ctx->dbus_msg, &ctx->dbus_args); - tbl->dbus_message_iter_append_basic(&ctx->dbus_args, 's', &namespace); - tbl->dbus_message_iter_append_basic(&ctx->dbus_args, 's', &key); + tbl->dbus_message_iter_init_append(ctx->dbus_msg, &dbus_args); + tbl->dbus_message_iter_append_basic(&dbus_args, 's', &namespace); + tbl->dbus_message_iter_append_basic(&dbus_args, 's', &key); ctx->dbus_reply = tbl->dbus_connection_send_with_reply_and_block(ctx->dbus_conn, ctx->dbus_msg, 100, &ctx->dbus_err); @@ -151,25 +159,35 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co return MwFALSE; } - if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &ctx->dbus_args)) { + if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &dbus_args)) { fprintf(stderr, "[WARNING] Couldn't get %s::%s: Reply has no arguments\n", namespace, key); tbl->dbus_message_unref(ctx->dbus_reply); return MwFALSE; } - if(tbl->dbus_message_iter_get_arg_type(&ctx->dbus_args) != 'v') { - fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant\n", namespace, key); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_args)) != 'v') { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant, got: %c\n", namespace, key, arg_type); tbl->dbus_message_unref(ctx->dbus_reply); return MwFALSE; } - tbl->dbus_message_iter_recurse(&ctx->dbus_args, &ctx->dbus_variant); + tbl->dbus_message_iter_recurse(&dbus_args, &dbus_variant); /* Some portals wrap the value in a second variant */ - if(tbl->dbus_message_iter_get_arg_type(&ctx->dbus_variant) == 'v') { - tbl->dbus_message_iter_recurse(&ctx->dbus_variant, &ctx->dbus_inner_variant); - tbl->dbus_message_iter_get_basic(&ctx->dbus_inner_variant, out); + arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_variant); + if(arg_type == 'v') { + tbl->dbus_message_iter_recurse(&dbus_variant, &dbus_inner_variant); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_inner_variant)) != 'u') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 'u' (uint32) for 'value', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&dbus_inner_variant, out); + } else if (arg_type == 'u') { + tbl->dbus_message_iter_get_basic(&dbus_variant, out); } else { - tbl->dbus_message_iter_get_basic(&ctx->dbus_variant, out); + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected variant or string, got: %c\n", namespace, key, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; } tbl->dbus_message_unref(ctx->dbus_msg); @@ -177,15 +195,15 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co } MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal) { + char filter_string[2048]; if(!ctx->dbus_conn) { return MwFALSE; } - char filter_string[2048]; MwStringPrintIntoBuffer(filter_string, sizeof(filter_string), "type='%s',interface=%s", "signal", portal); - dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); - dbus_connection_flush(ctx->dbus_conn); + tbl->dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); + tbl->dbus_connection_flush(ctx->dbus_conn); return MwTRUE; } @@ -193,42 +211,79 @@ MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, /* Technically this will swallow all other results, so this is not usable multiple times. TODO: Use a hashmap instead */ MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, MwLL handle, const char* portal, const char* namespace, const char* key, MwLLDBusPortalPollListener listener) { - DBusMessage* msg; - DBusMessageIter args, msg_value; + DBusMessageIter args, msg_value, msg_value_inner; const char* msg_namespace; const char* msg_key; MwU32 msg_value_content; + char arg_type; if(!ctx->dbus_conn) { return MwFALSE; } - dbus_connection_read_write(ctx->dbus_conn, 0); - msg = dbus_connection_pop_message(ctx->dbus_conn); + tbl->dbus_connection_read_write(ctx->dbus_conn, 0); + tbl->dbus_connection_read_write(ctx->dbus_conn, 0); + ctx->dbus_reply = tbl->dbus_connection_pop_message(ctx->dbus_conn); - if(NULL == msg) { + if(tbl->dbus_error_is_set(&ctx->dbus_err)) { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Poll error: %s\n", portal, ctx->dbus_err.message); + tbl->dbus_error_free(&ctx->dbus_err); + return MwFALSE; + } + if(!ctx->dbus_reply) { return MwFALSE; } /* check if the message is a signal from the correct interface and with the correct name */ - if(dbus_message_is_signal(msg, portal, "SettingChanged")) { + if(tbl->dbus_message_is_signal(ctx->dbus_reply, portal, "SettingChanged")) { /* read the parameters */ - if(!dbus_message_iter_init(msg, &args)) - fprintf(stderr, "[WARNING] Message has no arguments\n"); - else if(DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) - fprintf(stderr, "[WARNING] Argument is not string\n"); + if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &args)) + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged has no arguments\n", portal); else { - dbus_message_iter_get_basic(&args, &msg_namespace); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 's') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 's' (string) for 'namespace', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&args, &msg_namespace); - dbus_message_iter_next(&args); - dbus_message_iter_get_basic(&args, &msg_key); + tbl->dbus_message_iter_next(&args); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 's') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 's' (string) for 'key', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&args, &msg_key); /* Check that key and namespace match */ if(strcmp(msg_namespace, namespace) == 0 && strcmp(msg_key, key) == 0) { /* Assuming the value is a basic type */ - dbus_message_iter_next(&args); - dbus_message_iter_recurse(&args, &msg_value); - dbus_message_iter_get_basic(&msg_value, &msg_value_content); + tbl->dbus_message_iter_next(&args); + + if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 'v') { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant, got: %c\n", namespace, key, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_recurse(&args, &msg_value); + + /* Some portals wrap the value in a second variant */ + arg_type = tbl->dbus_message_iter_get_arg_type(&msg_value); + if(arg_type == 'v') { + tbl->dbus_message_iter_recurse(&msg_value, &msg_value_inner); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&msg_value_inner)) != 'u') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 'u' (uint32) for 'value', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&msg_value_inner, &msg_value_content); + } else if (arg_type == 'u') { + tbl->dbus_message_iter_get_basic(&msg_value, &msg_value_content); + } else { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected variant or string, got: %c\n", namespace, key, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } listener(handle, msg_value_content); } @@ -236,7 +291,8 @@ MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, M } /* free the message */ - dbus_message_unref(msg); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwTRUE; } void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) {