diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c index 4545c663d..4b3d6f734 100644 --- a/src/video/wayland/SDL_waylandmouse.c +++ b/src/video/wayland/SDL_waylandmouse.c @@ -55,6 +55,106 @@ typedef struct { void *shm_data; } Wayland_CursorData; +#ifdef SDL_USE_LIBDBUS + +#include "../../core/linux/SDL_dbus.h" + +static DBusMessage* +wayland_read_dbus_setting(SDL_DBusContext *dbus, const char *key) +{ + static const char *iface = "org.gnome.desktop.interface"; + + DBusMessage *reply = NULL; + DBusMessage *msg = dbus->message_new_method_call("org.freedesktop.portal.Desktop", /* Node */ + "/org/freedesktop/portal/desktop", /* Path */ + "org.freedesktop.portal.Settings", /* Interface */ + "Read"); /* Method */ + + if (msg) { + if (dbus->message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_STRING, &key, DBUS_TYPE_INVALID)) { + reply = dbus->connection_send_with_reply_and_block(dbus->session_conn, msg, DBUS_TIMEOUT_USE_DEFAULT, NULL); + } + dbus->message_unref(msg); + } + + return reply; +} + +static SDL_bool +wayland_parse_dbus_reply(SDL_DBusContext *dbus, DBusMessage *reply, int type, void *value) +{ + DBusMessageIter iter[3]; + + dbus->message_iter_init(reply, &iter[0]); + if (dbus->message_iter_get_arg_type(&iter[0]) != DBUS_TYPE_VARIANT) { + return SDL_FALSE; + } + + dbus->message_iter_recurse(&iter[0], &iter[1]); + if (dbus->message_iter_get_arg_type(&iter[1]) != DBUS_TYPE_VARIANT) { + return SDL_FALSE; + } + + dbus->message_iter_recurse(&iter[1], &iter[2]); + if (dbus->message_iter_get_arg_type(&iter[2]) != type) { + return SDL_FALSE; + } + + dbus->message_iter_get_basic(&iter[2], value); + + return SDL_TRUE; +} + +static SDL_bool +wayland_dbus_read_cursor_size(int *size) +{ + static const char *cursor_size_value = "cursor-size"; + + DBusMessage *reply; + SDL_DBusContext *dbus = SDL_DBus_GetContext(); + + if (!dbus || !size) { + return SDL_FALSE; + } + + if ((reply = wayland_read_dbus_setting(dbus, cursor_size_value))) { + if (wayland_parse_dbus_reply(dbus, reply, DBUS_TYPE_INT32, size)) { + dbus->message_unref(reply); + return SDL_TRUE; + } + dbus->message_unref(reply); + } + + return SDL_FALSE; +} + +static SDL_bool +wayland_dbus_read_cursor_theme(char **theme) +{ + static const char *cursor_theme_value = "cursor-theme"; + + DBusMessage *reply; + SDL_DBusContext *dbus = SDL_DBus_GetContext(); + + if (!dbus || !theme) { + return SDL_FALSE; + } + + if ((reply = wayland_read_dbus_setting(dbus, cursor_theme_value))) { + const char *temp; + if (wayland_parse_dbus_reply(dbus, reply, DBUS_TYPE_STRING, &temp)) { + *theme = SDL_strdup(temp); + dbus->message_unref(reply); + return SDL_TRUE; + } + dbus->message_unref(reply); + } + + return SDL_FALSE; +} + +#endif + static SDL_bool wayland_get_system_cursor(SDL_VideoData *vdata, Wayland_CursorData *cdata, float *scale) { @@ -68,20 +168,25 @@ wayland_get_system_cursor(SDL_VideoData *vdata, Wayland_CursorData *cdata, float SDL_WindowData *focusdata; int i; - /* FIXME: We need to be able to query the cursor size from the desktop at - * some point! For a while this was 32, but when testing on real desktops it - * seems like most of them default to 24. We'll need a protocol to get this - * for real, but for now this is a pretty safe bet. - * -flibit + /* + * GNOME based desktops expose the cursor size and theme via the + * org.freedesktop.portal.Settings interface of the xdg-desktop portal. + * Try XCURSOR_SIZE and XCURSOR_THEME first, so user specified sizes and + * themes take precedence over all, then try D-Bus if the envvar isn't + * set, then fall back to the defaults if none of the preceding values + * are available or valid. */ - xcursor_size = SDL_getenv("XCURSOR_SIZE"); - if (xcursor_size != NULL) { + if ((xcursor_size = SDL_getenv("XCURSOR_SIZE"))) { size = SDL_atoi(xcursor_size); } +#if SDL_USE_LIBDBUS + if (size <= 0) { + wayland_dbus_read_cursor_size(&size); + } +#endif if (size <= 0) { size = 24; } - /* First, find the appropriate theme based on the current scale... */ focus = SDL_GetMouse()->focus; if (focus == NULL) { @@ -98,15 +203,29 @@ wayland_get_system_cursor(SDL_VideoData *vdata, Wayland_CursorData *cdata, float } } if (theme == NULL) { + char *xcursor_theme = NULL; + SDL_bool free_theme_str = SDL_FALSE; + vdata->cursor_themes = SDL_realloc(vdata->cursor_themes, sizeof(SDL_WaylandCursorTheme) * (vdata->num_cursor_themes + 1)); if (vdata->cursor_themes == NULL) { SDL_OutOfMemory(); return SDL_FALSE; } - theme = WAYLAND_wl_cursor_theme_load(SDL_getenv("XCURSOR_THEME"), size, vdata->shm); + xcursor_theme = SDL_getenv("XCURSOR_THEME"); +#if SDL_USE_LIBDBUS + if (xcursor_theme == NULL) { + /* Allocates the string with SDL_strdup, which must be freed. */ + free_theme_str = wayland_dbus_read_cursor_theme(&xcursor_theme); + } +#endif + theme = WAYLAND_wl_cursor_theme_load(xcursor_theme, size, vdata->shm); vdata->cursor_themes[vdata->num_cursor_themes].size = size; vdata->cursor_themes[vdata->num_cursor_themes++].theme = theme; + + if (free_theme_str) { + SDL_free(xcursor_theme); + } } /* Next, find the cursor from the theme... */