diff --git a/include/rootston/cursor.h b/include/rootston/cursor.h index c0dbc010..fc71e31d 100644 --- a/include/rootston/cursor.h +++ b/include/rootston/cursor.h @@ -30,7 +30,6 @@ struct roots_cursor { enum roots_cursor_mode mode; // state from input (review if this is necessary) - struct wlr_xcursor_theme *xcursor_theme; 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 376412fb..b12fff70 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -12,6 +12,7 @@ #include #include "rootston/view.h" #include "rootston/config.h" +#include "rootston/xcursor.h" struct roots_output { struct roots_desktop *desktop; @@ -29,6 +30,7 @@ struct roots_desktop { struct roots_server *server; struct roots_config *config; + struct roots_xcursor_theme *xcursor_theme; struct wlr_output_layout *layout; diff --git a/include/rootston/xcursor.h b/include/rootston/xcursor.h index c96e50ef..45fac481 100644 --- a/include/rootston/xcursor.h +++ b/include/rootston/xcursor.h @@ -1,15 +1,44 @@ #ifndef _ROOTSTON_XCURSOR_H #define _ROOTSTON_XCURSOR_H +#include #include +#include +#include -struct wlr_xcursor *get_default_xcursor(struct wlr_xcursor_theme *theme); +#define ROOTS_XCURSOR_SIZE 16 -struct wlr_xcursor *get_move_xcursor(struct wlr_xcursor_theme *theme); +struct roots_xcursor_scaled_theme { + uint32_t scale; + struct wlr_xcursor_theme *theme; + struct wl_list link; +}; -struct wlr_xcursor *get_resize_xcursor(struct wlr_xcursor_theme *theme, - uint32_t edges); +struct roots_xcursor_theme { + char *name; + struct wl_list scaled_themes; // roots_xcursor_scaled_theme::link +}; -struct wlr_xcursor *get_rotate_xcursor(struct wlr_xcursor_theme *theme); +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); #endif diff --git a/rootston/cursor.c b/rootston/cursor.c index c3982e0e..46f4caea 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -27,12 +27,6 @@ void roots_cursor_destroy(struct roots_cursor *cursor) { // TODO } -static void cursor_set_xcursor_image(struct roots_cursor *cursor, - struct wlr_xcursor_image *image) { - wlr_cursor_set_image(cursor->cursor, image->buffer, image->width, - image->width, image->height, image->hotspot_x, image->hotspot_y, 0); -} - static void roots_cursor_update_position(struct roots_cursor *cursor, uint32_t time) { struct roots_desktop *desktop = cursor->seat->input->server->desktop; struct roots_seat *seat = cursor->seat; @@ -50,8 +44,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) { - struct wlr_xcursor *xcursor = get_default_xcursor(cursor->xcursor_theme); - cursor_set_xcursor_image(cursor, xcursor->images[0]); + roots_xcursor_theme_set_default(desktop->xcursor_theme, + cursor->cursor); cursor->cursor_client = NULL; } if (view) { diff --git a/rootston/desktop.c b/rootston/desktop.c index 448171ec..e20fceab 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -323,6 +323,14 @@ 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) { + wlr_list_free(desktop->views); + free(desktop); + return NULL; + } + desktop->layout = wlr_output_layout_create(); desktop->compositor = wlr_compositor_create(server->wl_display, server->renderer); @@ -344,6 +352,12 @@ struct roots_desktop *desktop_create(struct roots_server *server, wl_signal_add(&desktop->xwayland->events.new_surface, &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"); + } + roots_xcursor_theme_xwayland_set_default(desktop->xcursor_theme, + desktop->xwayland); } #endif diff --git a/rootston/output.c b/rootston/output.c index d853c45f..943e14c0 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -11,6 +11,7 @@ #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; @@ -240,6 +241,11 @@ void output_add_notify(struct wl_listener *listener, void *data) { wlr_output_layout_add_auto(desktop->layout, wlr_output); } + if (roots_xcursor_theme_load(desktop->xcursor_theme, wlr_output->scale)) { + wlr_log(L_ERROR, "Cannot load xcursor theme with scale %d", + wlr_output->scale); + } + struct roots_seat *seat; wl_list_for_each(seat, &input->seats, link) { roots_seat_configure_cursor(seat); diff --git a/rootston/seat.c b/rootston/seat.c index 280443ac..376da67f 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -176,12 +176,6 @@ void roots_seat_configure_cursor(struct roots_seat *seat) { } } -static void seat_set_xcursor_image(struct roots_seat *seat, struct - wlr_xcursor_image *image) { - wlr_cursor_set_image(seat->cursor->cursor, image->buffer, image->width, - image->width, image->height, image->hotspot_x, image->hotspot_y, 0); -} - static void roots_seat_init_cursor(struct roots_seat *seat) { seat->cursor = roots_cursor_create(seat); if (!seat->cursor) { @@ -192,33 +186,7 @@ static void roots_seat_init_cursor(struct roots_seat *seat) { struct roots_desktop *desktop = seat->input->server->desktop; wlr_cursor_attach_output_layout(wlr_cursor, desktop->layout); - seat->cursor->xcursor_theme = wlr_xcursor_theme_load("default", 16); - if (seat->cursor->xcursor_theme == NULL) { - wlr_log(L_ERROR, "Cannot load xcursor theme"); - roots_cursor_destroy(seat->cursor); - seat->cursor = NULL; - return; - } - - struct wlr_xcursor *xcursor = get_default_xcursor(seat->cursor->xcursor_theme); - if (xcursor == NULL) { - wlr_log(L_ERROR, "Cannot load xcursor from theme"); - wlr_xcursor_theme_destroy(seat->cursor->xcursor_theme); - roots_cursor_destroy(seat->cursor); - seat->cursor = NULL; - return; - } - - struct wlr_xcursor_image *image = xcursor->images[0]; - seat_set_xcursor_image(seat, image); - - // XXX: xwayland will always have the theme of the last created seat - if (seat->input->server->desktop->xwayland != NULL) { - wlr_xwayland_set_cursor(seat->input->server->desktop->xwayland, - image->buffer, image->width, image->width, - image->height, image->hotspot_x, - image->hotspot_y); - } + roots_xcursor_theme_set_default(desktop->xcursor_theme, wlr_cursor); wl_list_init(&seat->cursor->touch_points); @@ -476,11 +444,8 @@ void roots_seat_remove_device(struct roots_seat *seat, } void roots_seat_configure_xcursor(struct roots_seat *seat) { - struct wlr_xcursor *xcursor = - get_default_xcursor(seat->cursor->xcursor_theme); - struct wlr_xcursor_image *image = xcursor->images[0]; - seat_set_xcursor_image(seat, image); - + roots_xcursor_theme_set_default(seat->input->server->desktop->xcursor_theme, + seat->cursor->cursor); wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x, seat->cursor->cursor->y); } @@ -557,11 +522,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); - struct wlr_xcursor *xcursor = get_move_xcursor(seat->cursor->xcursor_theme); - if (xcursor != NULL) { - struct wlr_xcursor_image *image = xcursor->images[0]; - seat_set_xcursor_image(seat, image); - } + roots_xcursor_theme_set_move(seat->input->server->desktop->xcursor_theme, + seat->cursor->cursor); } void roots_seat_begin_resize(struct roots_seat *seat, struct roots_view *view, @@ -587,11 +549,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); - struct wlr_xcursor *xcursor = get_resize_xcursor(cursor->xcursor_theme, edges); - if (xcursor != NULL) { - seat_set_xcursor_image(seat, xcursor->images[0]); - } - + roots_xcursor_theme_set_resize(seat->input->server->desktop->xcursor_theme, + seat->cursor->cursor, edges); } void roots_seat_begin_rotate(struct roots_seat *seat, struct roots_view *view) { @@ -603,8 +562,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); - struct wlr_xcursor *xcursor = get_rotate_xcursor(cursor->xcursor_theme); - if (xcursor != NULL) { - seat_set_xcursor_image(seat, xcursor->images[0]); - } + roots_xcursor_theme_set_rotate(seat->input->server->desktop->xcursor_theme, + seat->cursor->cursor); } diff --git a/rootston/xcursor.c b/rootston/xcursor.c index 8697cdc3..6aa74bc4 100644 --- a/rootston/xcursor.c +++ b/rootston/xcursor.c @@ -1,6 +1,85 @@ -#include +#define _POSIX_C_SOURCE 200809L +#include +#include +#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) { if (edges & ROOTS_CURSOR_RESIZE_EDGE_TOP) { if (edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) { @@ -24,19 +103,32 @@ static const char *get_resize_xcursor_name(uint32_t edges) { return "se-resize"; // fallback } -struct wlr_xcursor *get_default_xcursor(struct wlr_xcursor_theme *theme) { - return wlr_xcursor_theme_get_cursor(theme, "left_ptr"); +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)); } -struct wlr_xcursor *get_move_xcursor(struct wlr_xcursor_theme *theme) { - return wlr_xcursor_theme_get_cursor(theme, "grabbing"); +void roots_xcursor_theme_set_rotate(struct roots_xcursor_theme *theme, + struct wlr_cursor *cursor) { + roots_xcursor_theme_set(theme, cursor, "grabbing"); } -struct wlr_xcursor *get_resize_xcursor(struct wlr_xcursor_theme *theme, - uint32_t edges) { - return wlr_xcursor_theme_get_cursor(theme, get_resize_xcursor_name(edges)); -} +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 *get_rotate_xcursor(struct wlr_xcursor_theme *theme) { - return wlr_xcursor_theme_get_cursor(theme, "grabbing"); + 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; + } + } }