From 8605243459629f566ed5109ffd896fd57b329ceb Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 12 Nov 2017 11:10:56 +0100 Subject: [PATCH] Introduce wlr_xcursor_manager --- include/rootston/cursor.h | 2 +- include/rootston/desktop.h | 2 +- include/rootston/xcursor.h | 40 ++------- include/wlr/types/wlr_cursor.h | 1 - include/wlr/types/wlr_xcursor_manager.h | 53 ++++++++++++ include/wlr/xcursor.h | 2 +- rootston/cursor.c | 5 +- rootston/desktop.c | 21 +++-- rootston/output.c | 4 +- rootston/seat.c | 22 ++--- rootston/xcursor.c | 108 +----------------------- types/meson.build | 3 +- types/wlr_xcursor_manager.c | 84 ++++++++++++++++++ 13 files changed, 180 insertions(+), 167 deletions(-) create mode 100644 include/wlr/types/wlr_xcursor_manager.h create mode 100644 types/wlr_xcursor_manager.c diff --git a/include/rootston/cursor.h b/include/rootston/cursor.h index 575c9d0e..f49b6439 100644 --- a/include/rootston/cursor.h +++ b/include/rootston/cursor.h @@ -30,7 +30,7 @@ struct roots_cursor { enum roots_cursor_mode mode; // state from input (review if this is necessary) - struct roots_xcursor_theme *xcursor_theme; + struct wlr_xcursor_manager *xcursor_manager; struct wlr_seat *wl_seat; struct wl_client *cursor_client; int offs_x, offs_y; diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index b12fff70..7371284f 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -30,9 +30,9 @@ struct roots_desktop { struct roots_server *server; struct roots_config *config; - struct roots_xcursor_theme *xcursor_theme; struct wlr_output_layout *layout; + struct wlr_xcursor_manager *xcursor_manager; struct wlr_compositor *compositor; struct wlr_wl_shell *wl_shell; diff --git a/include/rootston/xcursor.h b/include/rootston/xcursor.h index 45fac481..bc00f79c 100644 --- a/include/rootston/xcursor.h +++ b/include/rootston/xcursor.h @@ -1,44 +1,14 @@ #ifndef _ROOTSTON_XCURSOR_H #define _ROOTSTON_XCURSOR_H -#include -#include -#include -#include +#include #define ROOTS_XCURSOR_SIZE 16 -struct roots_xcursor_scaled_theme { - uint32_t scale; - struct wlr_xcursor_theme *theme; - struct wl_list link; -}; +#define ROOTS_XCURSOR_DEFAULT "left_ptr" +#define ROOTS_XCURSOR_MOVE "grabbing" +#define ROOTS_XCURSOR_ROTATE "grabbing" -struct roots_xcursor_theme { - char *name; - struct wl_list scaled_themes; // roots_xcursor_scaled_theme::link -}; - -struct roots_xcursor_theme *roots_xcursor_theme_create(const char *name); - -void roots_xcursor_theme_destroy(struct roots_xcursor_theme *theme); - -int roots_xcursor_theme_load(struct roots_xcursor_theme *theme, - uint32_t scale); - -void roots_xcursor_theme_set_default(struct roots_xcursor_theme *theme, - struct wlr_cursor *cursor); - -void roots_xcursor_theme_set_move(struct roots_xcursor_theme *theme, - struct wlr_cursor *cursor); - -void roots_xcursor_theme_set_resize(struct roots_xcursor_theme *theme, - struct wlr_cursor *cursor, uint32_t edges); - -void roots_xcursor_theme_set_rotate(struct roots_xcursor_theme *theme, - struct wlr_cursor *cursor); - -void roots_xcursor_theme_xwayland_set_default(struct roots_xcursor_theme *theme, - struct wlr_xwayland *xwayland); +const char *roots_xcursor_get_resize_name(uint32_t edges); #endif diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 3df74d28..0db32eb2 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -6,7 +6,6 @@ #include #include #include -#include struct wlr_cursor_state; diff --git a/include/wlr/types/wlr_xcursor_manager.h b/include/wlr/types/wlr_xcursor_manager.h new file mode 100644 index 00000000..c78a6e8d --- /dev/null +++ b/include/wlr/types/wlr_xcursor_manager.h @@ -0,0 +1,53 @@ +#ifndef WLR_TYPES_WLR_XCURSOR_MANAGER_H +#define WLR_TYPES_WLR_XCURSOR_MANAGER_H + +#include +#include +#include + +/** + * A scaled XCursor theme. + */ +struct wlr_xcursor_manager_theme { + uint32_t scale; + struct wlr_xcursor_theme *theme; + struct wl_list link; +}; + +/** + * Manage multiple XCursor themes with different scales and set `wlr_cursor` + * images. + * + * This manager can be used to display cursor images on multiple outputs having + * different scale factors. + */ +struct wlr_xcursor_manager { + char *name; + uint32_t size; + struct wl_list scaled_themes; // wlr_xcursor_manager_theme::link +}; + +/** + * Create a new XCursor manager. After initialization, scaled themes need to be + * loaded with `wlr_xcursor_manager_load`. `size` is the unscaled cursor theme + * size. + */ +struct wlr_xcursor_manager *wlr_xcursor_manager_create(const char *name, + uint32_t size); + +void wlr_xcursor_manager_destroy(struct wlr_xcursor_manager *manager); + +int wlr_xcursor_manager_load(struct wlr_xcursor_manager *manager, + uint32_t scale); + +struct wlr_xcursor *wlr_xcursor_manager_get_xcursor( + struct wlr_xcursor_manager *manager, const char *name, uint32_t scale); + +/** + * Set a `wlr_cursor` image. The manager uses all currently loaded scaled + * themes. + */ +void wlr_xcursor_manager_set_cursor_image(struct wlr_xcursor_manager *manager, + const char *name, struct wlr_cursor *cursor); + +#endif diff --git a/include/wlr/xcursor.h b/include/wlr/xcursor.h index c12d5405..b6362b06 100644 --- a/include/wlr/xcursor.h +++ b/include/wlr/xcursor.h @@ -61,7 +61,7 @@ struct wlr_xcursor_theme *wlr_xcursor_theme_load(const char *name, int size); void wlr_xcursor_theme_destroy(struct wlr_xcursor_theme *theme); struct wlr_xcursor *wlr_xcursor_theme_get_cursor( - struct wlr_xcursor_theme *theme, const char *name); + struct wlr_xcursor_theme *theme, const char *name); int wlr_xcursor_frame(struct wlr_xcursor *cursor, uint32_t time); diff --git a/rootston/cursor.c b/rootston/cursor.c index 0795cea6..ecd5e9a0 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -6,6 +6,7 @@ #elif __FreeBSD__ #include #endif +#include #include #include "rootston/xcursor.h" #include "rootston/cursor.h" @@ -44,8 +45,8 @@ static void roots_cursor_update_position(struct roots_cursor *cursor, uint32_t t set_compositor_cursor = view_client != cursor->cursor_client; } if (set_compositor_cursor) { - roots_xcursor_theme_set_default(cursor->xcursor_theme, - cursor->cursor); + wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, + ROOTS_XCURSOR_DEFAULT, cursor->cursor); cursor->cursor_client = NULL; } if (view) { diff --git a/rootston/desktop.c b/rootston/desktop.c index e20fceab..bb030e74 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -324,8 +325,10 @@ struct roots_desktop *desktop_create(struct roots_server *server, desktop->server = server; desktop->config = config; - desktop->xcursor_theme = roots_xcursor_theme_create("default"); - if (desktop->xcursor_theme == NULL) { + desktop->xcursor_manager = wlr_xcursor_manager_create(NULL, + ROOTS_XCURSOR_SIZE); + if (desktop->xcursor_manager == NULL) { + wlr_log(L_ERROR, "Cannot create XCursor manager"); wlr_list_free(desktop->views); free(desktop); return NULL; @@ -353,11 +356,17 @@ struct roots_desktop *desktop_create(struct roots_server *server, &desktop->xwayland_surface); desktop->xwayland_surface.notify = handle_xwayland_surface; - if (roots_xcursor_theme_load(desktop->xcursor_theme, 1)) { - wlr_log(L_ERROR, "Cannot load xwayland xcursor theme"); + if (wlr_xcursor_manager_load(desktop->xcursor_manager, 1)) { + wlr_log(L_ERROR, "Cannot load XWayland XCursor theme"); + } + struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor( + desktop->xcursor_manager, ROOTS_XCURSOR_DEFAULT, 1); + if (xcursor != NULL) { + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_xwayland_set_cursor(desktop->xwayland, image->buffer, + image->width, image->width, image->height, image->hotspot_x, + image->hotspot_y); } - roots_xcursor_theme_xwayland_set_default(desktop->xcursor_theme, - desktop->xwayland); } #endif diff --git a/rootston/output.c b/rootston/output.c index b35e56cd..cd288195 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -5,13 +5,13 @@ #include #include #include +#include #include #include #include #include "rootston/server.h" #include "rootston/desktop.h" #include "rootston/config.h" -#include "rootston/xcursor.h" static inline int64_t timespec_to_msec(const struct timespec *a) { return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; @@ -243,7 +243,7 @@ void output_add_notify(struct wl_listener *listener, void *data) { struct roots_seat *seat; wl_list_for_each(seat, &input->seats, link) { - if (roots_xcursor_theme_load(seat->cursor->xcursor_theme, + if (wlr_xcursor_manager_load(seat->cursor->xcursor_manager, wlr_output->scale)) { wlr_log(L_ERROR, "Cannot load xcursor theme for output '%s' " "with scale %d", wlr_output->name, wlr_output->scale); diff --git a/rootston/seat.c b/rootston/seat.c index ec4e9800..8a838efe 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -3,6 +3,7 @@ #include #include +#include #include #include "rootston/xcursor.h" @@ -187,8 +188,9 @@ static void roots_seat_init_cursor(struct roots_seat *seat) { wlr_cursor_attach_output_layout(wlr_cursor, desktop->layout); // TODO: be able to configure per-seat cursor themes - seat->cursor->xcursor_theme = desktop->xcursor_theme; - roots_xcursor_theme_set_default(seat->cursor->xcursor_theme, wlr_cursor); + seat->cursor->xcursor_manager = desktop->xcursor_manager; + wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, + ROOTS_XCURSOR_DEFAULT, wlr_cursor); wl_list_init(&seat->cursor->touch_points); @@ -446,8 +448,8 @@ void roots_seat_remove_device(struct roots_seat *seat, } void roots_seat_configure_xcursor(struct roots_seat *seat) { - roots_xcursor_theme_set_default(seat->cursor->xcursor_theme, - seat->cursor->cursor); + wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, + ROOTS_XCURSOR_DEFAULT, seat->cursor->cursor); wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x, seat->cursor->cursor->y); } @@ -524,8 +526,8 @@ void roots_seat_begin_move(struct roots_seat *seat, struct roots_view *view) { view_maximize(view, false); wlr_seat_pointer_clear_focus(seat->seat); - roots_xcursor_theme_set_move(seat->cursor->xcursor_theme, - seat->cursor->cursor); + wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, + ROOTS_XCURSOR_MOVE, seat->cursor->cursor); } void roots_seat_begin_resize(struct roots_seat *seat, struct roots_view *view, @@ -551,8 +553,8 @@ void roots_seat_begin_resize(struct roots_seat *seat, struct roots_view *view, view_maximize(view, false); wlr_seat_pointer_clear_focus(seat->seat); - roots_xcursor_theme_set_resize(seat->cursor->xcursor_theme, - seat->cursor->cursor, edges); + wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, + roots_xcursor_get_resize_name(edges), seat->cursor->cursor); } void roots_seat_begin_rotate(struct roots_seat *seat, struct roots_view *view) { @@ -564,6 +566,6 @@ void roots_seat_begin_rotate(struct roots_seat *seat, struct roots_view *view) { view_maximize(view, false); wlr_seat_pointer_clear_focus(seat->seat); - roots_xcursor_theme_set_rotate(seat->cursor->xcursor_theme, - seat->cursor->cursor); + wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, + ROOTS_XCURSOR_ROTATE, seat->cursor->cursor); } diff --git a/rootston/xcursor.c b/rootston/xcursor.c index 6aa74bc4..74e732c9 100644 --- a/rootston/xcursor.c +++ b/rootston/xcursor.c @@ -4,83 +4,7 @@ #include "rootston/xcursor.h" #include "rootston/input.h" -struct roots_xcursor_theme *roots_xcursor_theme_create(const char *name) { - struct roots_xcursor_theme *theme = - calloc(1, sizeof(struct roots_xcursor_theme)); - if (theme == NULL) { - return NULL; - } - theme->name = strdup(name); - wl_list_init(&theme->scaled_themes); - return theme; -} - -void roots_xcursor_theme_destroy(struct roots_xcursor_theme *theme) { - if (theme == NULL) { - return; - } - struct roots_xcursor_scaled_theme *scaled_theme, *tmp; - wl_list_for_each_safe(scaled_theme, tmp, &theme->scaled_themes, link) { - wl_list_remove(&scaled_theme->link); - wlr_xcursor_theme_destroy(scaled_theme->theme); - free(scaled_theme); - } - free(theme->name); - free(theme); -} - -int roots_xcursor_theme_load(struct roots_xcursor_theme *theme, - uint32_t scale) { - struct roots_xcursor_scaled_theme *scaled_theme; - wl_list_for_each(scaled_theme, &theme->scaled_themes, link) { - if (scaled_theme->scale == scale) { - return 0; - } - } - - scaled_theme = calloc(1, sizeof(struct roots_xcursor_scaled_theme)); - if (scaled_theme == NULL) { - return 1; - } - scaled_theme->scale = scale; - scaled_theme->theme = wlr_xcursor_theme_load(NULL, - ROOTS_XCURSOR_SIZE * scale); - if (scaled_theme->theme == NULL) { - free(scaled_theme); - return 1; - } - wl_list_insert(&theme->scaled_themes, &scaled_theme->link); - return 0; -} - -static void roots_xcursor_theme_set(struct roots_xcursor_theme *theme, - struct wlr_cursor *cursor, const char *name) { - struct roots_xcursor_scaled_theme *scaled_theme; - wl_list_for_each(scaled_theme, &theme->scaled_themes, link) { - struct wlr_xcursor *xcursor = - wlr_xcursor_theme_get_cursor(scaled_theme->theme, name); - if (xcursor == NULL) { - continue; - } - - struct wlr_xcursor_image *image = xcursor->images[0]; - wlr_cursor_set_image(cursor, image->buffer, image->width, - image->width, image->height, image->hotspot_x, image->hotspot_y, - scaled_theme->scale); - } -} - -void roots_xcursor_theme_set_default(struct roots_xcursor_theme *theme, - struct wlr_cursor *cursor) { - roots_xcursor_theme_set(theme, cursor, "left_ptr"); -} - -void roots_xcursor_theme_set_move(struct roots_xcursor_theme *theme, - struct wlr_cursor *cursor) { - roots_xcursor_theme_set(theme, cursor, "grabbing"); -} - -static const char *get_resize_xcursor_name(uint32_t edges) { +const char *roots_xcursor_get_resize_name(uint32_t edges) { if (edges & ROOTS_CURSOR_RESIZE_EDGE_TOP) { if (edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) { return "ne-resize"; @@ -102,33 +26,3 @@ static const char *get_resize_xcursor_name(uint32_t edges) { } return "se-resize"; // fallback } - -void roots_xcursor_theme_set_resize(struct roots_xcursor_theme *theme, - struct wlr_cursor *cursor, uint32_t edges) { - roots_xcursor_theme_set(theme, cursor, get_resize_xcursor_name(edges)); -} - -void roots_xcursor_theme_set_rotate(struct roots_xcursor_theme *theme, - struct wlr_cursor *cursor) { - roots_xcursor_theme_set(theme, cursor, "grabbing"); -} - -void roots_xcursor_theme_xwayland_set_default(struct roots_xcursor_theme *theme, - struct wlr_xwayland *xwayland) { - struct roots_xcursor_scaled_theme *scaled_theme; - wl_list_for_each(scaled_theme, &theme->scaled_themes, link) { - if (scaled_theme->scale == 1) { - struct wlr_xcursor *xcursor = - wlr_xcursor_theme_get_cursor(scaled_theme->theme, "left_ptr"); - if (xcursor == NULL) { - continue; - } - - struct wlr_xcursor_image *image = xcursor->images[0]; - wlr_xwayland_set_cursor(xwayland, image->buffer, image->width, - image->width, image->height, image->hotspot_x, - image->hotspot_y); - break; - } - } -} diff --git a/types/meson.build b/types/meson.build index 2603ecfd..4669165a 100644 --- a/types/meson.build +++ b/types/meson.build @@ -20,8 +20,9 @@ lib_wlr_types = static_library( 'wlr_tablet_pad.c', 'wlr_tablet_tool.c', 'wlr_touch.c', - 'wlr_xdg_shell_v6.c', 'wlr_wl_shell.c', + 'wlr_xcursor_manager.c', + 'wlr_xdg_shell_v6.c', ), include_directories: wlr_inc, dependencies: [wayland_server, pixman, wlr_protos], diff --git a/types/wlr_xcursor_manager.c b/types/wlr_xcursor_manager.c new file mode 100644 index 00000000..6c12d04b --- /dev/null +++ b/types/wlr_xcursor_manager.c @@ -0,0 +1,84 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include + +struct wlr_xcursor_manager *wlr_xcursor_manager_create(const char *name, + uint32_t size) { + struct wlr_xcursor_manager *manager = + calloc(1, sizeof(struct wlr_xcursor_manager)); + if (manager == NULL) { + return NULL; + } + if (name != NULL) { + manager->name = strdup(name); + } + manager->size = size; + wl_list_init(&manager->scaled_themes); + return manager; +} + +void wlr_xcursor_manager_destroy(struct wlr_xcursor_manager *manager) { + if (manager == NULL) { + return; + } + struct wlr_xcursor_manager_theme *theme, *tmp; + wl_list_for_each_safe(theme, tmp, &manager->scaled_themes, link) { + wl_list_remove(&theme->link); + wlr_xcursor_theme_destroy(theme->theme); + free(theme); + } + free(manager->name); + free(manager); +} + +int wlr_xcursor_manager_load(struct wlr_xcursor_manager *manager, + uint32_t scale) { + struct wlr_xcursor_manager_theme *theme; + wl_list_for_each(theme, &manager->scaled_themes, link) { + if (theme->scale == scale) { + return 0; + } + } + + theme = calloc(1, sizeof(struct wlr_xcursor_manager_theme)); + if (theme == NULL) { + return 1; + } + theme->scale = scale; + theme->theme = wlr_xcursor_theme_load(NULL, manager->size * scale); + if (theme->theme == NULL) { + free(theme); + return 1; + } + wl_list_insert(&manager->scaled_themes, &theme->link); + return 0; +} + +struct wlr_xcursor *wlr_xcursor_manager_get_xcursor( + struct wlr_xcursor_manager *manager, const char *name, uint32_t scale) { + struct wlr_xcursor_manager_theme *theme; + wl_list_for_each(theme, &manager->scaled_themes, link) { + if (theme->scale == scale) { + return wlr_xcursor_theme_get_cursor(theme->theme, name); + } + } + return NULL; +} + +void wlr_xcursor_manager_set_cursor_image(struct wlr_xcursor_manager *manager, + const char *name, struct wlr_cursor *cursor) { + struct wlr_xcursor_manager_theme *theme; + wl_list_for_each(theme, &manager->scaled_themes, link) { + struct wlr_xcursor *xcursor = + wlr_xcursor_theme_get_cursor(theme->theme, name); + if (xcursor == NULL) { + continue; + } + + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_cursor_set_image(cursor, image->buffer, image->width, + image->width, image->height, image->hotspot_x, image->hotspot_y, + theme->scale); + } +}