auto detect dark theme change via dbus signals #18
3 changed files with 86 additions and 7 deletions
|
|
@ -83,11 +83,15 @@ typedef struct _MwLLDBusContext {
|
||||||
DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant;
|
DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant;
|
||||||
} MwLLDBusContext;
|
} MwLLDBusContext;
|
||||||
|
|
||||||
|
typedef void (*MwLLDBusPortalPollListener)(MwLL handle, MwU32 new_value);
|
||||||
|
|
||||||
/* setup the dbus func table. Returns false and prints a warning if dbus couldn't be found. */
|
/* setup the dbus func table. Returns false and prints a warning if dbus couldn't be found. */
|
||||||
MWDECL MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl);
|
MWDECL MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl);
|
||||||
|
|
||||||
MWDECL MwBool MwLLDBusNewContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx);
|
MWDECL MwBool MwLLDBusNewContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx);
|
||||||
MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal, const char* namespace, const char* key, void* out);
|
MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal, const char* namespace, const char* key, void* out);
|
||||||
|
MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal);
|
||||||
|
MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, MwLL handle, const char* portal, const char* namespace, const char* key, MwLLDBusPortalPollListener);
|
||||||
MWDECL void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx);
|
MWDECL void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
wayland_call_table_t wl_call_tbl;
|
wayland_call_table_t wl_call_tbl;
|
||||||
MwBool MwWaylandAlwaysRender = MwFALSE;
|
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. */
|
/* 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) \
|
#define WAYLAND_EVENT_OP_START(self) \
|
||||||
do { \
|
do { \
|
||||||
|
|
@ -1818,14 +1820,21 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_DBUS
|
#ifdef USE_DBUS
|
||||||
|
static void dark_theme_listener(MwLL handle, MwU32 new_value) {
|
||||||
|
wl_dark_theme = (new_value == 1) ? 1 : 0;
|
||||||
|
|
||||||
|
MwLLDispatch(handle, dark_theme, &wl_dark_theme);
|
||||||
|
}
|
||||||
|
|
||||||
static void detect_dark_theme(MwLL handle) {
|
static void detect_dark_theme(MwLL handle) {
|
||||||
MwU32 value = 0;
|
MwU32 value = 0;
|
||||||
MwU32 dark_theme = 0;
|
|
||||||
MwLLDBusPortalGet(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value);
|
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;
|
||||||
|
|
||||||
dark_theme = (value == 1) ? 1 : 0;
|
MwLLDBusPortalWatch(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings");
|
||||||
|
|
||||||
MwLLDispatch(handle, dark_theme, &dark_theme);
|
MwLLDispatch(handle, dark_theme, &wl_dark_theme);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -2164,15 +2173,18 @@ static int MwLLPendingImpl(MwLL handle) {
|
||||||
};
|
};
|
||||||
int pending = 0;
|
int pending = 0;
|
||||||
|
|
||||||
if(handle->wayland.dark_theme_detection) {
|
|
||||||
handle->wayland.dark_theme_detection = MwFALSE;
|
|
||||||
#ifdef USE_DBUS
|
#ifdef USE_DBUS
|
||||||
if(wl_call_tbl.has_dbus) {
|
if(wl_call_tbl.has_dbus) {
|
||||||
|
if(handle->wayland.dark_theme_detection) {
|
||||||
|
|
||||||
|
handle->wayland.dark_theme_detection = MwFALSE;
|
||||||
detect_dark_theme(handle);
|
detect_dark_theme(handle);
|
||||||
MwLLDispatch(handle, draw, NULL);
|
MwLLDispatch(handle, draw, NULL);
|
||||||
|
} else {
|
||||||
|
MwLLDBusPortalPoll(&wl_call_tbl.dbus, &handle->wayland.dbus, handle, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &dark_theme_listener);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if(!handle->wayland.did_initial_resize) {
|
if(!handle->wayland.did_initial_resize) {
|
||||||
recursive_dispatch_resize(handle);
|
recursive_dispatch_resize(handle);
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,69 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co
|
||||||
return MwTRUE;
|
return MwTRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
return MwTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
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);
|
||||||
|
msg = dbus_connection_pop_message(ctx->dbus_conn);
|
||||||
|
|
||||||
|
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");
|
||||||
|
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
|
||||||
|
dbus_message_iter_next(&args);
|
||||||
|
dbus_message_iter_recurse(&args, &msg_value);
|
||||||
|
dbus_message_iter_get_basic(&msg_value, &msg_value_content);
|
||||||
|
|
||||||
|
listener(handle, msg_value_content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// free the message
|
||||||
|
dbus_message_unref(msg);
|
||||||
|
}
|
||||||
|
|
||||||
void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) {
|
void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) {
|
||||||
if(!tbl->lib) {
|
if(!tbl->lib) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue