From 2fed0ec562f2841b3020eba37a9fd7e1795d714d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 8 May 2025 15:22:42 +0530 Subject: [PATCH] Linux: Handle desktop settings portals that are so old they don't implement ReadOne Sigh, outdated Linux software, just creating busy work for everyone. --- glfw/dbus_glfw.c | 11 ++-------- glfw/dbus_glfw.h | 2 +- glfw/ibus_glfw.c | 12 +++++------ glfw/linux_desktop_settings.c | 39 +++++++++++++++++++++++++++++++---- glfw/linux_notify.c | 10 ++++----- 5 files changed, 49 insertions(+), 25 deletions(-) diff --git a/glfw/dbus_glfw.c b/glfw/dbus_glfw.c index 328fad359..f0ceace28 100644 --- a/glfw/dbus_glfw.c +++ b/glfw/dbus_glfw.c @@ -214,13 +214,6 @@ typedef struct { void *user_data; } MethodResponse; -static const char* -format_message_error(DBusError *err) { - static char buf[1024]; - snprintf(buf, sizeof(buf), "[%s] %s", err->name ? err->name : "", err->message); - return buf; -} - static void method_reply_received(DBusPendingCall *pending, void *user_data) { MethodResponse *res = (MethodResponse*)user_data; @@ -228,7 +221,7 @@ method_reply_received(DBusPendingCall *pending, void *user_data) { if (msg) { DBusError err; dbus_error_init(&err); - if (dbus_set_error_from_message(&err, msg)) res->callback(NULL, format_message_error(&err), res->user_data); + if (dbus_set_error_from_message(&err, msg)) res->callback(NULL, &err, res->user_data); else res->callback(msg, NULL, res->user_data); } } @@ -243,7 +236,7 @@ call_method_with_msg(DBusConnection *conn, DBusMessage *msg, int timeout, dbus_p DBusError error; dbus_error_init(&error); RAII_MSG(reply, dbus_connection_send_with_reply_and_block(session_bus, msg, timeout, &error)); if (dbus_error_is_set(&error)) { - callback(reply, error.message, user_data); + callback(reply, &error, user_data); return false; } else if (reply) { callback(reply, NULL, user_data); diff --git a/glfw/dbus_glfw.h b/glfw/dbus_glfw.h index 58eff276e..e78b83762 100644 --- a/glfw/dbus_glfw.h +++ b/glfw/dbus_glfw.h @@ -33,7 +33,7 @@ static inline void cleanup_msg(void *p) { DBusMessage *m = *(DBusMessage**)p; if (m) dbus_message_unref(m); m = NULL; } #define RAII_MSG(name, initializer) __attribute__((cleanup(cleanup_msg))) DBusMessage *name = initializer -typedef void(*dbus_pending_callback)(DBusMessage *msg, const char* err, void* data); +typedef void(*dbus_pending_callback)(DBusMessage *msg, const DBusError *err, void* data); typedef struct { EventLoopData* eld; diff --git a/glfw/ibus_glfw.c b/glfw/ibus_glfw.c index ab4d81dad..081987ff5 100644 --- a/glfw/ibus_glfw.c +++ b/glfw/ibus_glfw.c @@ -373,9 +373,9 @@ read_ibus_address(_GLFWIBUSData *ibus) { } void -input_context_created(DBusMessage *msg, const char* errmsg, void *data) { - if (errmsg) { - _glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to create input context with error: %s", errmsg); +input_context_created(DBusMessage *msg, const DBusError *err, void *data) { + if (err) { + _glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to create input context with error: %s: %s", err->name, err->message); return; } const char *path = NULL; @@ -488,15 +488,15 @@ glfw_ibus_set_cursor_geometry(_GLFWIBUSData *ibus, int x, int y, int w, int h) { } void -key_event_processed(DBusMessage *msg, const char* errmsg, void *data) { +key_event_processed(DBusMessage *msg, const DBusError *err, void *data) { uint32_t handled = 0; _GLFWIBUSKeyEvent *ev = (_GLFWIBUSKeyEvent*)data; // Restore key's text from the text embedded in the structure. ev->glfw_ev.text = ev->__embedded_text; bool is_release = ev->glfw_ev.action == GLFW_RELEASE; bool failed = false; - if (errmsg) { - _glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to process key with error: %s", errmsg); + if (err) { + _glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to process key with error: %s: %s", err->name, err->message); failed = true; } else { glfw_dbus_get_args(msg, "Failed to get IBUS handled key from reply", DBUS_TYPE_BOOLEAN, &handled, DBUS_TYPE_INVALID); diff --git a/glfw/linux_desktop_settings.c b/glfw/linux_desktop_settings.c index de52f40df..089fc4106 100644 --- a/glfw/linux_desktop_settings.c +++ b/glfw/linux_desktop_settings.c @@ -24,15 +24,46 @@ static int theme_size = -1; static GLFWColorScheme appearance = GLFW_COLOR_SCHEME_NO_PREFERENCE; static bool cursor_theme_changed = false, appearance_initialized = false; -#define HANDLER(name) static void name(DBusMessage *msg, const char* errmsg, void *data) { \ +#define HANDLER(name_) static void name_(DBusMessage *msg, const DBusError* err, void *data) { \ (void)data; \ - if (errmsg) { \ - _glfwInputError(GLFW_PLATFORM_ERROR, "%s: failed with error: %s", #name, errmsg); \ + if (err) { \ + _glfwInputError(GLFW_PLATFORM_ERROR, "%s: failed with error: %s: %s", #name_, err->name, err->message); \ return; \ } +HANDLER(get_color_scheme_legacy) + DBusMessageIter iter, variant_iter, variant_iter2; + if (!dbus_message_iter_init(msg, &iter)) return; + dbus_message_iter_recurse(&iter, &variant_iter); + int type = dbus_message_iter_get_arg_type(&variant_iter); + if (type != DBUS_TYPE_VARIANT) { + _glfwInputError(GLFW_PLATFORM_ERROR, "Read for color-scheme did not return a variant"); return; + } + dbus_message_iter_recurse(&variant_iter, &variant_iter2); + if (type != DBUS_TYPE_VARIANT) { + _glfwInputError(GLFW_PLATFORM_ERROR, "Read for color-scheme did not return a nested variant"); return; + } + uint32_t val; + dbus_message_iter_get_basic(&variant_iter2, &val); + if (val < 3) appearance = val; +} -HANDLER(get_color_scheme) +static void get_color_scheme(DBusMessage *msg, const DBusError* err, void *data) { + (void) data; + if (err) { + if (strcmp("org.freedesktop.DBus.Error.UnknownMethod", err->name) == 0) { + DBusConnection *session_bus = glfw_dbus_session_bus(); + if (session_bus) { + const char *namespace = FDO_DESKTOP_NAMESPACE, *key = FDO_APPEARANCE_KEY; + glfw_dbus_call_blocking_method(session_bus, DESKTOP_SERVICE, DESKTOP_PATH, DESKTOP_INTERFACE, "Read", DBUS_TIMEOUT_USE_DEFAULT, + get_color_scheme_legacy, NULL, DBUS_TYPE_STRING, &namespace, DBUS_TYPE_STRING, &key, DBUS_TYPE_INVALID); + } + return; + } else { + _glfwInputError(GLFW_PLATFORM_ERROR, "%s: failed with error: %s: %s", "get_color_scheme", err->name, err->message); + return; + } + } uint32_t val; DBusMessageIter iter, variant_iter; if (!dbus_message_iter_init(msg, &iter)) return; diff --git a/glfw/linux_notify.c b/glfw/linux_notify.c index f0ef298f6..8bcb10ca9 100644 --- a/glfw/linux_notify.c +++ b/glfw/linux_notify.c @@ -32,9 +32,9 @@ glfw_dbus_set_user_notification_activated_handler(GLFWDBusnotificationactivatedf } void -notification_created(DBusMessage *msg, const char* errmsg, void *data) { - if (errmsg) { - _glfwInputError(GLFW_PLATFORM_ERROR, "Notify: Failed to create notification error: %s", errmsg); +notification_created(DBusMessage *msg, const DBusError* err, void *data) { + if (err) { + _glfwInputError(GLFW_PLATFORM_ERROR, "Notify: Failed to create notification error: %s: %s", err->name, err->message); if (data) free(data); return; } @@ -95,9 +95,9 @@ cancel_user_notification(DBusConnection *session_bus, uint32_t *id) { } static void -got_capabilities(DBusMessage *msg, const char* err, void* data UNUSED) { +got_capabilities(DBusMessage *msg, const DBusError* err, void* data UNUSED) { if (err) { - _glfwInputError(GLFW_PLATFORM_ERROR, "Notify: Failed to get server capabilities error: %s", err); + _glfwInputError(GLFW_PLATFORM_ERROR, "Notify: Failed to get server capabilities error: %s: %s", err->name, err->message); return; } #define check_call(func, err, ...) if (!func(__VA_ARGS__)) { _glfwInputError(GLFW_PLATFORM_ERROR, "Notify: GetCapabilities: %s", err); return; }