wayland: Add a DBus message handler for the cursor size and theme properties.
Add a DBus message handler to watch and respond to changes to the system cursor size and theme properties. Upon these settings being changed, a cursor refresh will be triggered so the new changes will take effect immediately, without the cursor having to leave and re-enter the window surface.main
parent
e643d28d9c
commit
fd6cb4dc86
|
@ -58,19 +58,30 @@ typedef struct
|
||||||
void *shm_data;
|
void *shm_data;
|
||||||
} Wayland_CursorData;
|
} Wayland_CursorData;
|
||||||
|
|
||||||
|
static int dbus_cursor_size;
|
||||||
|
static char *dbus_cursor_theme;
|
||||||
|
|
||||||
#ifdef SDL_USE_LIBDBUS
|
#ifdef SDL_USE_LIBDBUS
|
||||||
|
|
||||||
#include "../../core/linux/SDL_dbus.h"
|
#include "../../core/linux/SDL_dbus.h"
|
||||||
|
|
||||||
static DBusMessage *wayland_read_dbus_setting(SDL_DBusContext *dbus, const char *key)
|
#define CURSOR_NODE "org.freedesktop.portal.Desktop"
|
||||||
|
#define CURSOR_PATH "/org/freedesktop/portal/desktop"
|
||||||
|
#define CURSOR_INTERFACE "org.freedesktop.portal.Settings"
|
||||||
|
#define CURSOR_NAMESPACE "org.gnome.desktop.interface"
|
||||||
|
#define CURSOR_SIGNAL_NAME "SettingChanged"
|
||||||
|
#define CURSOR_SIZE_KEY "cursor-size"
|
||||||
|
#define CURSOR_THEME_KEY "cursor-theme"
|
||||||
|
|
||||||
|
static DBusMessage *Wayland_ReadDBusProperty(SDL_DBusContext *dbus, const char *key)
|
||||||
{
|
{
|
||||||
static const char *iface = "org.gnome.desktop.interface";
|
static const char *iface = "org.gnome.desktop.interface";
|
||||||
|
|
||||||
DBusMessage *reply = NULL;
|
DBusMessage *reply = NULL;
|
||||||
DBusMessage *msg = dbus->message_new_method_call("org.freedesktop.portal.Desktop", /* Node */
|
DBusMessage *msg = dbus->message_new_method_call(CURSOR_NODE,
|
||||||
"/org/freedesktop/portal/desktop", /* Path */
|
CURSOR_PATH,
|
||||||
"org.freedesktop.portal.Settings", /* Interface */
|
CURSOR_INTERFACE,
|
||||||
"Read"); /* Method */
|
"Read"); /* Method */
|
||||||
|
|
||||||
if (msg) {
|
if (msg) {
|
||||||
if (dbus->message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_STRING, &key, DBUS_TYPE_INVALID)) {
|
if (dbus->message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_STRING, &key, DBUS_TYPE_INVALID)) {
|
||||||
|
@ -82,7 +93,7 @@ static DBusMessage *wayland_read_dbus_setting(SDL_DBusContext *dbus, const char
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_bool wayland_parse_dbus_reply(SDL_DBusContext *dbus, DBusMessage *reply, int type, void *value)
|
static SDL_bool Wayland_ParseDBusReply(SDL_DBusContext *dbus, DBusMessage *reply, int type, void *value)
|
||||||
{
|
{
|
||||||
DBusMessageIter iter[3];
|
DBusMessageIter iter[3];
|
||||||
|
|
||||||
|
@ -106,50 +117,127 @@ static SDL_bool wayland_parse_dbus_reply(SDL_DBusContext *dbus, DBusMessage *rep
|
||||||
return SDL_TRUE;
|
return SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_bool wayland_dbus_read_cursor_size(int *size)
|
static DBusHandlerResult Wayland_DBusCursorMessageFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||||
{
|
{
|
||||||
static const char *cursor_size_value = "cursor-size";
|
|
||||||
|
|
||||||
DBusMessage *reply;
|
|
||||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||||
|
|
||||||
if (dbus == NULL || size == NULL) {
|
if (dbus->message_is_signal(msg, CURSOR_INTERFACE, CURSOR_SIGNAL_NAME)) {
|
||||||
return SDL_FALSE;
|
DBusMessageIter signal_iter, variant_iter;
|
||||||
}
|
const char *namespace, *key;
|
||||||
|
|
||||||
if ((reply = wayland_read_dbus_setting(dbus, cursor_size_value))) {
|
dbus->message_iter_init(msg, &signal_iter);
|
||||||
if (wayland_parse_dbus_reply(dbus, reply, DBUS_TYPE_INT32, size)) {
|
/* Check if the parameters are what we expect */
|
||||||
dbus->message_unref(reply);
|
if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_STRING) {
|
||||||
return SDL_TRUE;
|
goto not_our_signal;
|
||||||
}
|
}
|
||||||
dbus->message_unref(reply);
|
dbus->message_iter_get_basic(&signal_iter, &namespace);
|
||||||
|
if (SDL_strcmp(CURSOR_NAMESPACE, namespace) != 0) {
|
||||||
|
goto not_our_signal;
|
||||||
|
}
|
||||||
|
if (!dbus->message_iter_next(&signal_iter)) {
|
||||||
|
goto not_our_signal;
|
||||||
|
}
|
||||||
|
if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_STRING) {
|
||||||
|
goto not_our_signal;
|
||||||
|
}
|
||||||
|
dbus->message_iter_get_basic(&signal_iter, &key);
|
||||||
|
if (SDL_strcmp(CURSOR_SIZE_KEY, key) == 0) {
|
||||||
|
int new_cursor_size;
|
||||||
|
|
||||||
|
if (!dbus->message_iter_next(&signal_iter)) {
|
||||||
|
goto not_our_signal;
|
||||||
|
}
|
||||||
|
if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_VARIANT) {
|
||||||
|
goto not_our_signal;
|
||||||
|
}
|
||||||
|
dbus->message_iter_recurse(&signal_iter, &variant_iter);
|
||||||
|
if (dbus->message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_INT32) {
|
||||||
|
goto not_our_signal;
|
||||||
|
}
|
||||||
|
dbus->message_iter_get_basic(&variant_iter, &new_cursor_size);
|
||||||
|
|
||||||
|
if (dbus_cursor_size != new_cursor_size) {
|
||||||
|
dbus_cursor_size = new_cursor_size;
|
||||||
|
SDL_SetCursor(NULL); /* Force cursor update */
|
||||||
|
}
|
||||||
|
} else if (SDL_strcmp(CURSOR_THEME_KEY, key) == 0) {
|
||||||
|
const char *new_cursor_theme = NULL;
|
||||||
|
|
||||||
|
if (!dbus->message_iter_next(&signal_iter)) {
|
||||||
|
goto not_our_signal;
|
||||||
|
}
|
||||||
|
if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_VARIANT) {
|
||||||
|
goto not_our_signal;
|
||||||
|
}
|
||||||
|
dbus->message_iter_recurse(&signal_iter, &variant_iter);
|
||||||
|
if (dbus->message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) {
|
||||||
|
goto not_our_signal;
|
||||||
|
}
|
||||||
|
dbus->message_iter_get_basic(&variant_iter, &new_cursor_theme);
|
||||||
|
|
||||||
|
if (!dbus_cursor_theme || !new_cursor_theme || SDL_strcmp(dbus_cursor_theme, new_cursor_theme) != 0) {
|
||||||
|
SDL_free(dbus_cursor_theme);
|
||||||
|
if (new_cursor_theme) {
|
||||||
|
dbus_cursor_theme = SDL_strdup(new_cursor_theme);
|
||||||
|
SDL_SetCursor(NULL); /* Force cursor update */
|
||||||
|
} else {
|
||||||
|
dbus_cursor_theme = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
goto not_our_signal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DBUS_HANDLER_RESULT_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SDL_FALSE;
|
not_our_signal:
|
||||||
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_bool wayland_dbus_read_cursor_theme(char **theme)
|
static void Wayland_DBusInitCursorProperties()
|
||||||
{
|
{
|
||||||
static const char *cursor_theme_value = "cursor-theme";
|
|
||||||
|
|
||||||
DBusMessage *reply;
|
DBusMessage *reply;
|
||||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||||
|
SDL_bool add_filter = SDL_FALSE;
|
||||||
|
|
||||||
if (dbus == NULL || theme == NULL) {
|
if (dbus == NULL) {
|
||||||
return SDL_FALSE;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((reply = wayland_read_dbus_setting(dbus, cursor_theme_value))) {
|
if ((reply = Wayland_ReadDBusProperty(dbus, CURSOR_SIZE_KEY))) {
|
||||||
const char *temp;
|
if (Wayland_ParseDBusReply(dbus, reply, DBUS_TYPE_INT32, &dbus_cursor_size)) {
|
||||||
if (wayland_parse_dbus_reply(dbus, reply, DBUS_TYPE_STRING, &temp)) {
|
add_filter = SDL_TRUE;
|
||||||
*theme = SDL_strdup(temp);
|
|
||||||
dbus->message_unref(reply);
|
|
||||||
return SDL_TRUE;
|
|
||||||
}
|
}
|
||||||
dbus->message_unref(reply);
|
dbus->message_unref(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SDL_FALSE;
|
if ((reply = Wayland_ReadDBusProperty(dbus, CURSOR_THEME_KEY))) {
|
||||||
|
const char *temp = NULL;
|
||||||
|
if (Wayland_ParseDBusReply(dbus, reply, DBUS_TYPE_STRING, &temp)) {
|
||||||
|
add_filter = SDL_TRUE;
|
||||||
|
|
||||||
|
if (temp) {
|
||||||
|
dbus_cursor_theme = SDL_strdup(temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dbus->message_unref(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only add the filter if at least one of the settings we want is present. */
|
||||||
|
if (add_filter) {
|
||||||
|
dbus->bus_add_match(dbus->session_conn,
|
||||||
|
"type='signal', interface='"CURSOR_INTERFACE"',"
|
||||||
|
"member='"CURSOR_SIGNAL_NAME"', arg0='"CURSOR_NAMESPACE"'", NULL);
|
||||||
|
dbus->connection_add_filter(dbus->session_conn, &Wayland_DBusCursorMessageFilter, NULL, NULL);
|
||||||
|
dbus->connection_flush(dbus->session_conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Wayland_DBusFinishCursorProperties()
|
||||||
|
{
|
||||||
|
SDL_free(dbus_cursor_theme);
|
||||||
|
dbus_cursor_theme = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -159,29 +247,19 @@ static SDL_bool wayland_get_system_cursor(SDL_VideoData *vdata, Wayland_CursorDa
|
||||||
struct wl_cursor_theme *theme = NULL;
|
struct wl_cursor_theme *theme = NULL;
|
||||||
struct wl_cursor *cursor;
|
struct wl_cursor *cursor;
|
||||||
|
|
||||||
char *xcursor_size;
|
int size = dbus_cursor_size;
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
SDL_Window *focus;
|
SDL_Window *focus;
|
||||||
SDL_WindowData *focusdata;
|
SDL_WindowData *focusdata;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/* Fallback envvar if the DBus properties don't exist */
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
if ((xcursor_size = SDL_getenv("XCURSOR_SIZE"))) {
|
|
||||||
size = SDL_atoi(xcursor_size);
|
|
||||||
}
|
|
||||||
#ifdef SDL_USE_LIBDBUS
|
|
||||||
if (size <= 0) {
|
if (size <= 0) {
|
||||||
wayland_dbus_read_cursor_size(&size);
|
const char *xcursor_size = SDL_getenv("XCURSOR_SIZE");
|
||||||
|
if (xcursor_size) {
|
||||||
|
size = SDL_atoi(xcursor_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (size <= 0) {
|
if (size <= 0) {
|
||||||
size = 24;
|
size = 24;
|
||||||
}
|
}
|
||||||
|
@ -203,8 +281,7 @@ static SDL_bool wayland_get_system_cursor(SDL_VideoData *vdata, Wayland_CursorDa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (theme == NULL) {
|
if (theme == NULL) {
|
||||||
char *xcursor_theme = NULL;
|
const char *xcursor_theme = dbus_cursor_theme;
|
||||||
SDL_bool free_theme_str = SDL_FALSE;
|
|
||||||
|
|
||||||
vdata->cursor_themes = SDL_realloc(vdata->cursor_themes,
|
vdata->cursor_themes = SDL_realloc(vdata->cursor_themes,
|
||||||
sizeof(SDL_WaylandCursorTheme) * (vdata->num_cursor_themes + 1));
|
sizeof(SDL_WaylandCursorTheme) * (vdata->num_cursor_themes + 1));
|
||||||
|
@ -212,20 +289,15 @@ static SDL_bool wayland_get_system_cursor(SDL_VideoData *vdata, Wayland_CursorDa
|
||||||
SDL_OutOfMemory();
|
SDL_OutOfMemory();
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
xcursor_theme = SDL_getenv("XCURSOR_THEME");
|
|
||||||
#ifdef SDL_USE_LIBDBUS
|
/* Fallback envvar if the DBus properties don't exist */
|
||||||
if (xcursor_theme == NULL) {
|
if (!xcursor_theme) {
|
||||||
/* Allocates the string with SDL_strdup, which must be freed. */
|
xcursor_theme = SDL_getenv("XCURSOR_THEME");
|
||||||
free_theme_str = wayland_dbus_read_cursor_theme(&xcursor_theme);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
theme = WAYLAND_wl_cursor_theme_load(xcursor_theme, size, vdata->shm);
|
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].size = size;
|
||||||
vdata->cursor_themes[vdata->num_cursor_themes++].theme = theme;
|
vdata->cursor_themes[vdata->num_cursor_themes++].theme = theme;
|
||||||
|
|
||||||
if (free_theme_str) {
|
|
||||||
SDL_free(xcursor_theme);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Next, find the cursor from the theme... */
|
/* Next, find the cursor from the theme... */
|
||||||
|
@ -684,6 +756,10 @@ void Wayland_InitMouse(void)
|
||||||
input->relative_mode_override = SDL_FALSE;
|
input->relative_mode_override = SDL_FALSE;
|
||||||
input->cursor_visible = SDL_TRUE;
|
input->cursor_visible = SDL_TRUE;
|
||||||
|
|
||||||
|
#ifdef SDL_USE_LIBDBUS
|
||||||
|
Wayland_DBusInitCursorProperties();
|
||||||
|
#endif
|
||||||
|
|
||||||
SDL_SetDefaultCursor(Wayland_CreateDefaultCursor());
|
SDL_SetDefaultCursor(Wayland_CreateDefaultCursor());
|
||||||
|
|
||||||
SDL_AddHintCallback(SDL_HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP,
|
SDL_AddHintCallback(SDL_HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP,
|
||||||
|
@ -701,6 +777,10 @@ void Wayland_FiniMouse(SDL_VideoData *data)
|
||||||
SDL_free(data->cursor_themes);
|
SDL_free(data->cursor_themes);
|
||||||
data->cursor_themes = NULL;
|
data->cursor_themes = NULL;
|
||||||
|
|
||||||
|
#ifdef SDL_USE_LIBDBUS
|
||||||
|
Wayland_DBusFinishCursorProperties();
|
||||||
|
#endif
|
||||||
|
|
||||||
SDL_DelHintCallback(SDL_HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP,
|
SDL_DelHintCallback(SDL_HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP,
|
||||||
Wayland_EmulateMouseWarpChanged, input);
|
Wayland_EmulateMouseWarpChanged, input);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue