diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b06bf41..e6b6bcd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,7 @@ bindings `ctrl-+` and `ctrl+-`). * Use XRGB pixel format (instead of ARGB) when there is no transparency. +* Prefer CSS xcursor names, and fallback to legacy X11 names. [1526]: https://codeberg.org/dnkl/foot/issues/1526 [1528]: https://codeberg.org/dnkl/foot/issues/1528 diff --git a/cursor-shape.c b/cursor-shape.c index 131e6f1a..bbf75ab8 100644 --- a/cursor-shape.c +++ b/cursor-shape.c @@ -9,28 +9,26 @@ #include "debug.h" #include "util.h" -const char * +const char *const * cursor_shape_to_string(enum cursor_shape shape) { - static const char *const table[CURSOR_SHAPE_COUNT] = { - [CURSOR_SHAPE_NONE] = NULL, - [CURSOR_SHAPE_HIDDEN] = "hidden", - [CURSOR_SHAPE_LEFT_PTR] = "left_ptr", - [CURSOR_SHAPE_TEXT] = "text", - [CURSOR_SHAPE_TEXT_FALLBACK] = "xterm", - [CURSOR_SHAPE_TOP_LEFT_CORNER] = "top_left_corner", - [CURSOR_SHAPE_TOP_RIGHT_CORNER] = "top_right_corner", - [CURSOR_SHAPE_BOTTOM_LEFT_CORNER] = "bottom_left_corner", - [CURSOR_SHAPE_BOTTOM_RIGHT_CORNER] = "bottom_right_corner", - [CURSOR_SHAPE_LEFT_SIDE] = "left_side", - [CURSOR_SHAPE_RIGHT_SIDE] = "right_side", - [CURSOR_SHAPE_TOP_SIDE] = "top_side", - [CURSOR_SHAPE_BOTTOM_SIDE] = "bottom_side", + static const char *const table[][CURSOR_SHAPE_COUNT]= { + [CURSOR_SHAPE_NONE] = {NULL}, + [CURSOR_SHAPE_HIDDEN] = {"hidden", NULL}, + [CURSOR_SHAPE_LEFT_PTR] = {"default", "left_ptr", NULL}, + [CURSOR_SHAPE_TEXT] = {"text", "xterm", NULL}, + [CURSOR_SHAPE_TOP_LEFT_CORNER] = {"nw-resize", "top_left_corner", NULL}, + [CURSOR_SHAPE_TOP_RIGHT_CORNER] = {"ne-resize", "top_right_corner", NULL}, + [CURSOR_SHAPE_BOTTOM_LEFT_CORNER] = {"sw-resize", "bottom_left_corner", NULL}, + [CURSOR_SHAPE_BOTTOM_RIGHT_CORNER] = {"se-resize", "bottom_right_corner", NULL}, + [CURSOR_SHAPE_LEFT_SIDE] = {"w-resize", "left_side", NULL}, + [CURSOR_SHAPE_RIGHT_SIDE] = {"e-resize", "right_side", NULL}, + [CURSOR_SHAPE_TOP_SIDE] = {"n-resize", "top_side", NULL}, + [CURSOR_SHAPE_BOTTOM_SIDE] = {"s-resize", "bottom_side", NULL}, }; xassert(shape <= ALEN(table)); - xassert(table[shape] != NULL); return table[shape]; } @@ -40,7 +38,6 @@ cursor_shape_to_server_shape(enum cursor_shape shape) static const enum wp_cursor_shape_device_v1_shape table[CURSOR_SHAPE_COUNT] = { [CURSOR_SHAPE_LEFT_PTR] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT, [CURSOR_SHAPE_TEXT] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT, - [CURSOR_SHAPE_TEXT_FALLBACK] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT, [CURSOR_SHAPE_TOP_LEFT_CORNER] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE, [CURSOR_SHAPE_TOP_RIGHT_CORNER] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE, [CURSOR_SHAPE_BOTTOM_LEFT_CORNER] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE, diff --git a/cursor-shape.h b/cursor-shape.h index 58755382..110dbd2e 100644 --- a/cursor-shape.h +++ b/cursor-shape.h @@ -9,7 +9,6 @@ enum cursor_shape { CURSOR_SHAPE_LEFT_PTR, CURSOR_SHAPE_TEXT, - CURSOR_SHAPE_TEXT_FALLBACK, CURSOR_SHAPE_TOP_LEFT_CORNER, CURSOR_SHAPE_TOP_RIGHT_CORNER, CURSOR_SHAPE_BOTTOM_LEFT_CORNER, @@ -22,7 +21,7 @@ enum cursor_shape { CURSOR_SHAPE_COUNT, }; -const char *cursor_shape_to_string(enum cursor_shape shape); +const char *const *cursor_shape_to_string(enum cursor_shape shape); enum wp_cursor_shape_device_v1_shape cursor_shape_to_server_shape( enum cursor_shape shape); diff --git a/render.c b/render.c index 3ce8a226..91472027 100644 --- a/render.c +++ b/render.c @@ -4625,38 +4625,48 @@ render_xcursor_set(struct seat *seat, struct terminal *term, return true; } - /* TODO: skip this when using server-side cursors */ - if (shape != CURSOR_SHAPE_HIDDEN) { - const char *const xcursor = shape == CURSOR_SHAPE_CUSTOM - ? term->mouse_user_cursor - : cursor_shape_to_string(shape); - const char *const fallback = - cursor_shape_to_string(CURSOR_SHAPE_TEXT_FALLBACK); - - seat->pointer.cursor = wl_cursor_theme_get_cursor( - seat->pointer.theme, xcursor); - - if (seat->pointer.cursor == NULL) { - seat->pointer.cursor = wl_cursor_theme_get_cursor( - seat->pointer.theme, fallback); - - if (seat->pointer.cursor == NULL) { - LOG_ERR("failed to load xcursor pointer " - "'%s', and fallback '%s'", xcursor, fallback); - return false; - } - } - - if (shape == CURSOR_SHAPE_CUSTOM) { - free(seat->pointer.last_custom_xcursor); - seat->pointer.last_custom_xcursor = xstrdup(term->mouse_user_cursor); - } - } else { + if (shape == CURSOR_SHAPE_HIDDEN) { seat->pointer.cursor = NULL; free(seat->pointer.last_custom_xcursor); seat->pointer.last_custom_xcursor = NULL; } + else if (seat->pointer.shape_device == NULL) { + const char *const custom_xcursors[] = {term->mouse_user_cursor, NULL}; + const char *const *xcursors = shape == CURSOR_SHAPE_CUSTOM + ? custom_xcursors + : cursor_shape_to_string(shape); + + xassert(xcursors[0] != NULL); + + seat->pointer.cursor = NULL; + + for (size_t i = 0; xcursors[i] != NULL; i++) { + seat->pointer.cursor = + wl_cursor_theme_get_cursor(seat->pointer.theme, xcursors[i]); + + if (seat->pointer.cursor != NULL) { + LOG_DBG("loaded xcursor %s", xcursors[i]); + break; + } + } + + if (seat->pointer.cursor == NULL) { + LOG_ERR( + "failed to load xcursor pointer '%s', and all of its fallbacks", + xcursors[0]); + return false; + } + } else { + /* Server-side cursors - no need to load anything */ + } + + if (shape == CURSOR_SHAPE_CUSTOM) { + free(seat->pointer.last_custom_xcursor); + seat->pointer.last_custom_xcursor = + xstrdup(term->mouse_user_cursor); + } + /* FDM hook takes care of actual rendering */ seat->pointer.shape = shape; seat->pointer.xcursor_pending = true;