Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cursor types and cursor-shape-v1 support #113

Merged
merged 3 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion include/wayland-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ typedef enum {
WAYLAND_GLOBAL_COMPOSITOR,
WAYLAND_GLOBAL_SHM,
WAYLAND_GLOBAL_LAYER_SHELL,
WAYLAND_GLOBAL_CURSOR_SHAPE,
_WAYLAND_GLOBAL_SIZE,
} wayland_global_name;

Expand All @@ -40,6 +41,10 @@ typedef struct {
uint32_t global_names[_WAYLAND_GLOBAL_SIZE];
struct wl_compositor *compositor;

#ifdef HAVE_WAYLAND_CURSOR_SHAPE
struct wp_cursor_shape_manager_v1 *cursor_shape_manager;
#endif

struct wl_data_device_manager *data_device_manager;
struct zwp_primary_selection_device_manager_v1
*primary_selection_device_manager;
Expand All @@ -50,7 +55,7 @@ typedef struct {
size_t buffer_count;
struct {
char *theme_name;
char **name;
RofiCursorType type;
struct wl_cursor_theme *theme;
struct wl_cursor *cursor;
struct wl_cursor_image *image;
Expand Down Expand Up @@ -88,9 +93,13 @@ struct _wayland_seat {
int32_t delay;
} repeat;
uint32_t serial;
uint32_t pointer_serial;
struct wl_keyboard *keyboard;
struct wl_pointer *pointer;

#ifdef HAVE_WAYLAND_CURSOR_SHAPE
struct wp_cursor_shape_device_v1 *cursor_shape_device;
#endif
struct wl_data_device *data_device;
struct zwp_primary_selection_device_v1 *primary_selection_device;

Expand Down
2 changes: 2 additions & 0 deletions include/wayland.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,6 @@ gboolean display_get_surface_dimensions(int *width, int *height);
void display_set_surface_dimensions(int width, int height, int x_margin,
int y_margin, int loc);

void wayland_display_set_cursor_type(RofiCursorType type);

#endif
9 changes: 9 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,15 @@ if wayland_enabled
'protocols/wlr-foreign-toplevel-management-unstable-v1.xml',
'protocols/wlr-layer-shell-unstable-v1.xml',
)

if wayland_protocols.version().version_compare('>=1.32')
add_project_arguments('-DHAVE_WAYLAND_CURSOR_SHAPE', language: 'c')
protocols += files(
wayland_sys_protocols_dir + '/staging/cursor-shape/cursor-shape-v1.xml',
wayland_sys_protocols_dir + '/unstable/tablet/tablet-unstable-v2.xml',
)
endif

proto_srcs = []
proto_headers = []
foreach p : protocols
Expand Down
154 changes: 138 additions & 16 deletions source/wayland/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@
#include "display.h"
#include "wayland-internal.h"

#ifdef HAVE_WAYLAND_CURSOR_SHAPE
#include "cursor-shape-v1-protocol.h"
#endif
#include "primary-selection-unstable-v1-protocol.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"

Expand Down Expand Up @@ -319,6 +322,7 @@ static void wayland_frame_callback(void *data, struct wl_callback *callback,
uint32_t timestamp) {
if (wayland->frame_cb != NULL) {
wl_callback_destroy(wayland->frame_cb);
wayland->frame_cb = NULL;
rofi_view_frame_callback();
}
if (wayland->surface != NULL) {
Expand Down Expand Up @@ -621,13 +625,60 @@ static void wayland_pointer_send_events(wayland_seat *self) {
rofi_view_maybe_update(state);
}

static void wayland_pointer_enter(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface,
wl_fixed_t x, wl_fixed_t y) {
wayland_seat *self = data;
static struct wl_cursor *
rofi_cursor_type_to_wl_cursor(struct wl_cursor_theme *theme,
RofiCursorType type) {
static const char *const default_names[] = {
"default", "left_ptr", "top_left_arrow", "left-arrow", NULL};
static const char *const pointer_names[] = {"pointer", "hand1", NULL};
static const char *const text_names[] = {"text", "xterm", NULL};

if (!wayland_cursor_reload_theme(wayland->scale))
const char *const *name;
struct wl_cursor *cursor = NULL;

switch (type) {
case ROFI_CURSOR_POINTER:
name = pointer_names;
break;
case ROFI_CURSOR_TEXT:
name = text_names;
break;
default:
name = default_names;
break;
}
for (; cursor == NULL && *name != NULL; ++name) {
cursor = wl_cursor_theme_get_cursor(theme, *name);
}
return cursor;
}

#ifdef HAVE_WAYLAND_CURSOR_SHAPE
static enum wp_cursor_shape_device_v1_shape
rofi_cursor_type_to_wp_cursor_shape(RofiCursorType type) {
switch (type) {
case ROFI_CURSOR_POINTER:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER;
case ROFI_CURSOR_TEXT:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT;
default:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
}
}
#endif

static void wayland_cursor_update_for_seat(wayland_seat *seat) {
#ifdef HAVE_WAYLAND_CURSOR_SHAPE
if (seat->cursor_shape_device != NULL) {
wp_cursor_shape_device_v1_set_shape(
seat->cursor_shape_device, seat->pointer_serial,
rofi_cursor_type_to_wp_cursor_shape(wayland->cursor.type));
return;
} else if (wayland->cursor.theme == NULL) {
// cursor-shape-v1 is available, but the seat haven't seen a pointer yet
return;
}
#endif

if (wayland->cursor.surface == NULL) {
wayland->cursor.surface = wl_compositor_create_surface(wayland->compositor);
Expand All @@ -640,17 +691,74 @@ static void wayland_pointer_enter(void *data, struct wl_pointer *pointer,
}

wl_pointer_set_cursor(
self->pointer, serial, wayland->cursor.surface,
seat->pointer, seat->pointer_serial, wayland->cursor.surface,
wayland->cursor.image->hotspot_x / wayland->cursor.scale,
wayland->cursor.image->hotspot_y / wayland->cursor.scale);
}

static void wayland_pointer_enter(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface,
wl_fixed_t x, wl_fixed_t y) {
wayland_seat *self = data;

self->pointer_serial = serial;

#ifdef HAVE_WAYLAND_CURSOR_SHAPE
if (wayland->cursor_shape_manager != NULL) {
if (self->cursor_shape_device == NULL) {
self->cursor_shape_device = wp_cursor_shape_manager_v1_get_pointer(
wayland->cursor_shape_manager, pointer);
}
} else
#endif
if (!wayland_cursor_reload_theme(wayland->scale)) {
return;
}

wayland_cursor_update_for_seat(self);
}

void wayland_display_set_cursor_type(RofiCursorType type) {
wayland_seat *seat;
GHashTableIter iter;
struct wl_cursor *cursor;

if (wayland->cursor.type == type) {
return;
}
wayland->cursor.type = type;

#ifdef HAVE_WAYLAND_CURSOR_SHAPE
if (wayland->cursor_shape_manager == NULL)
#endif
{
if (wayland->cursor.theme == NULL) {
return;
}

cursor = rofi_cursor_type_to_wl_cursor(wayland->cursor.theme, type);
if (cursor == NULL) {
g_info("Failed to load cursor type %d", type);
return;
}
wayland->cursor.cursor = cursor;
}

g_hash_table_iter_init(&iter, wayland->seats);
while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&seat)) {
if (seat->pointer != NULL) {
wayland_cursor_update_for_seat(seat);
}
}
}

static void wayland_pointer_leave(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface) {
wayland_seat *self = data;

if (wayland->cursor.frame_cb != NULL) {
wl_callback_destroy(wayland->cursor.frame_cb);
wayland->cursor.frame_cb = NULL;
}
}

Expand Down Expand Up @@ -952,6 +1060,13 @@ static void wayland_pointer_release(wayland_seat *self) {
return;
}

#ifdef HAVE_WAYLAND_CURSOR_SHAPE
if (self->cursor_shape_device != NULL) {
wp_cursor_shape_device_v1_destroy(self->cursor_shape_device);
self->cursor_shape_device = NULL;
}
#endif

if (wl_pointer_get_version(self->pointer) >=
WL_POINTER_RELEASE_SINCE_VERSION) {
wl_pointer_release(self->pointer);
Expand Down Expand Up @@ -1138,9 +1253,6 @@ static const struct wl_output_listener wayland_output_listener = {
#endif
};

static const char *const wayland_cursor_names[] = {
"left_ptr", "default", "top_left_arrow", "left-arrow", NULL};

static void wayland_registry_handle_global(void *data,
struct wl_registry *registry,
uint32_t name, const char *interface,
Expand Down Expand Up @@ -1191,6 +1303,13 @@ static void wayland_registry_handle_global(void *data,
wayland->primary_selection_device_manager = wl_registry_bind(
registry, name, &zwp_primary_selection_device_manager_v1_interface, 1);
}
#ifdef HAVE_WAYLAND_CURSOR_SHAPE
else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) {
wayland->global_names[WAYLAND_GLOBAL_CURSOR_SHAPE] = name;
wayland->cursor_shape_manager = wl_registry_bind(
registry, name, &wp_cursor_shape_manager_v1_interface, 1);
}
#endif
}

static void wayland_registry_handle_global_remove(void *data,
Expand All @@ -1208,6 +1327,12 @@ static void wayland_registry_handle_global_remove(void *data,
wl_compositor_destroy(wayland->compositor);
wayland->compositor = NULL;
break;
case WAYLAND_GLOBAL_CURSOR_SHAPE:
#ifdef HAVE_WAYLAND_CURSOR_SHAPE
wp_cursor_shape_manager_v1_destroy(wayland->cursor_shape_manager);
wayland->cursor_shape_manager = NULL;
#endif
break;
case WAYLAND_GLOBAL_LAYER_SHELL:
zwlr_layer_shell_v1_destroy(wayland->layer_shell);
wayland->layer_shell = NULL;
Expand All @@ -1225,8 +1350,8 @@ static void wayland_registry_handle_global_remove(void *data,
((wayland->compositor == NULL) || (wayland->shm == NULL))) {
if (wayland->cursor.frame_cb != NULL) {
wl_callback_destroy(wayland->cursor.frame_cb);
wayland->cursor.frame_cb = NULL;
}
wayland->cursor.frame_cb = NULL;

wl_surface_destroy(wayland->cursor.surface);
wl_cursor_theme_destroy(wayland->cursor.theme);
Expand Down Expand Up @@ -1335,12 +1460,8 @@ static gboolean wayland_cursor_reload_theme(guint scale) {
wayland->cursor.theme = wl_cursor_theme_load(wayland->cursor.theme_name,
cursor_size, wayland->shm);
if (wayland->cursor.theme != NULL) {
const char *const *cname = (const char *const *)wayland->cursor.name;
for (cname = (cname != NULL) ? cname : wayland_cursor_names;
(wayland->cursor.cursor == NULL) && (*cname != NULL); ++cname) {
wayland->cursor.cursor =
wl_cursor_theme_get_cursor(wayland->cursor.theme, *cname);
}
wayland->cursor.cursor = rofi_cursor_type_to_wl_cursor(
wayland->cursor.theme, wayland->cursor.type);
if (wayland->cursor.cursor == NULL) {
wl_cursor_theme_destroy(wayland->cursor.theme);
wayland->cursor.theme = NULL;
Expand Down Expand Up @@ -1368,6 +1489,7 @@ static gboolean wayland_display_setup(GMainLoop *main_loop,
wayland_error, NULL, NULL);

wayland->buffer_count = 3;
wayland->cursor.type = ROFI_CURSOR_DEFAULT;
wayland->scale = 1;

wayland->outputs = g_hash_table_new(g_direct_hash, g_direct_equal);
Expand Down
8 changes: 1 addition & 7 deletions source/wayland/view.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,6 @@ static void wayland_rofi_view_get_size(RofiViewState *state, gint *width,
*height = state->height;
}

static void wayland_rofi_view_set_cursor(RofiCursorType type) {
(void)type;

// TODO
}

static void wayland_rofi_view_ping_mouse(RofiViewState *state) { (void)state; }

static gboolean wayland_rofi_view_reload_idle(G_GNUC_UNUSED gpointer data) {
Expand Down Expand Up @@ -479,7 +473,7 @@ static view_proxy view_ = {
.calculate_window_height = wayland_rofi_view_calculate_window_height,
.calculate_window_width = wayland_rofi_view_calculate_window_width,
.window_update_size = wayland_rofi_view_window_update_size,
.set_cursor = wayland_rofi_view_set_cursor,
.set_cursor = wayland_display_set_cursor_type,
.ping_mouse = wayland_rofi_view_ping_mouse,

.cleanup = wayland_rofi_view_cleanup,
Expand Down