Skip to content

Commit

Permalink
wayland: Load cursor theme/size based on settings
Browse files Browse the repository at this point in the history
  • Loading branch information
ColinKinloch committed Jun 12, 2024
1 parent af7f1f7 commit 208c7fa
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 1 deletion.
4 changes: 3 additions & 1 deletion gfx/common/wayland_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -805,8 +805,10 @@ bool gfx_ctx_wl_init_common(
wl->input.keyboard_focus = true;
wl->input.mouse.focus = true;

wl->cursor.theme_name = NULL;
wl->cursor.size = 24;
wl->cursor.surface = wl_compositor_create_surface(wl->compositor);
wl->cursor.theme = wl_cursor_theme_load(NULL, 16, wl->shm);
wl->cursor.theme = wl_cursor_theme_load(wl->cursor.theme_name, wl->cursor.size, wl->shm);
wl->cursor.default_cursor = wl_cursor_theme_get_cursor(wl->cursor.theme, "left_ptr");

wl->num_active_touches = 0;
Expand Down
198 changes: 198 additions & 0 deletions input/common/wayland_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,183 @@

#define SPLASH_SHM_NAME "retroarch-wayland-splash"


/*
* Copyright © 2019 Christian Rauch
* Copyright © 2024 Colin Kinloch
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include "config.h"

static bool
get_cursor_settings_from_env(char **theme, int *size)
{
char *env_xtheme;
char *env_xsize;

env_xtheme = getenv("XCURSOR_THEME");
if (env_xtheme != NULL)
*theme = strdup(env_xtheme);

env_xsize = getenv("XCURSOR_SIZE");
if (env_xsize != NULL)
*size = atoi(env_xsize);

return env_xtheme != NULL && env_xsize != NULL;
}

#ifdef HAVE_DBUS
#include <dbus/dbus.h>

static DBusMessage *
get_setting_sync(DBusConnection *const connection,
const char *key,
const char *value)
{
DBusError error;
dbus_bool_t success;
DBusMessage *message;
DBusMessage *reply;

message = dbus_message_new_method_call(
"org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.Settings",
"Read");

success = dbus_message_append_args(message,
DBUS_TYPE_STRING, &key,
DBUS_TYPE_STRING, &value,
DBUS_TYPE_INVALID);

if (!success)
return NULL;

dbus_error_init(&error);

reply = dbus_connection_send_with_reply_and_block(
connection,
message,
DBUS_TIMEOUT_USE_DEFAULT,
&error);

dbus_message_unref(message);

if (dbus_error_is_set(&error)) {
dbus_error_free(&error);
return NULL;
}

dbus_error_free(&error);
return reply;
}

static bool
parse_type(DBusMessage *const reply,
const 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 false;

dbus_message_iter_recurse(&iter[0], &iter[1]);
if (dbus_message_iter_get_arg_type(&iter[1]) != DBUS_TYPE_VARIANT)
return false;

dbus_message_iter_recurse(&iter[1], &iter[2]);
if (dbus_message_iter_get_arg_type(&iter[2]) != type)
return false;

dbus_message_iter_get_basic(&iter[2], value);

return true;
}

bool
libdecor_get_cursor_settings(char **theme, int *size)
{
static const char name[] = "org.gnome.desktop.interface";
static const char key_theme[] = "cursor-theme";
static const char key_size[] = "cursor-size";

DBusError error;
DBusConnection *connection;
DBusMessage *reply;
const char *value_theme = NULL;

dbus_error_init(&error);

connection = dbus_bus_get(DBUS_BUS_SESSION, &error);

if (dbus_error_is_set(&error))
goto fallback;

reply = get_setting_sync(connection, name, key_theme);
if (!reply)
goto fallback;

if (!parse_type(reply, DBUS_TYPE_STRING, &value_theme)) {
dbus_message_unref(reply);
goto fallback;
}

*theme = strdup(value_theme);

dbus_message_unref(reply);

reply = get_setting_sync(connection, name, key_size);
if (!reply)
goto fallback;

if (!parse_type(reply, DBUS_TYPE_INT32, size)) {
dbus_message_unref(reply);
goto fallback;
}

dbus_message_unref(reply);

return true;

fallback:
return get_cursor_settings_from_env(theme, size);
}
#else
bool
libdecor_get_cursor_settings(char **theme, int *size)
{
return get_cursor_settings_from_env(theme, size);
}
#endif


static void wl_keyboard_handle_keymap(void* data,
struct wl_keyboard* keyboard,
uint32_t format,
Expand Down Expand Up @@ -164,12 +341,33 @@ void gfx_ctx_wl_show_mouse(void *data, bool state)

if (state)
{
if (!libdecor_get_cursor_settings(&wl->cursor.theme_name, &wl->cursor.size)) {
wl->cursor.theme_name = NULL;
wl->cursor.size = 24;
}
int scale = FRACTIONAL_SCALE_MULT(1, wl->fractional_scale_num);
struct wl_cursor_theme *theme = wl_cursor_theme_load(
wl->cursor.theme_name,
wl->cursor.size * scale,
wl->shm);
if (theme) {
wl_cursor_theme_destroy(wl->cursor.theme);
wl->cursor.theme = theme;
}

wl->cursor.default_cursor = wl_cursor_theme_get_cursor(wl->cursor.theme, "left_ptr");
struct wl_cursor_image *image = wl->cursor.default_cursor->images[0];
wl_pointer_set_cursor(wl->wl_pointer,
wl->cursor.serial, wl->cursor.surface,
image->hotspot_x, image->hotspot_y);
wl_surface_attach(wl->cursor.surface,
wl_cursor_image_get_buffer(image), 0, 0);

if (wl_surface_get_version (wl->cursor.surface)
>= WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)
{
wl_surface_set_buffer_scale (wl->cursor.surface, scale);
}
wl_surface_damage(wl->cursor.surface, 0, 0, image->width, image->height);
wl_surface_commit(wl->cursor.surface);
}
Expand Down
4 changes: 4 additions & 0 deletions input/common/wayland_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ typedef struct gfx_ctx_wayland_data
struct wl_cursor_theme *theme;
struct wl_surface *surface;
uint32_t serial;
char *theme_name;
int size;
bool visible;
} cursor;

Expand Down Expand Up @@ -238,6 +240,8 @@ void gfx_ctx_wl_show_mouse(void *data, bool state);

void flush_wayland_fd(void *data);

bool libdecor_get_cursor_settings(char **theme, int *size);

extern const struct wl_keyboard_listener keyboard_listener;

extern const struct wl_pointer_listener pointer_listener;
Expand Down

0 comments on commit 208c7fa

Please sign in to comment.