commit ed622d3
shrub
·
2025-12-17 02:04:55 +0000 UTC
parent 6570f7b
custom cursors add support for custom cursor images from ARGB. there are two modes, client-managed cursor and compositor cursor override. api has been added for switcing modes and changing cursor.
3 files changed,
+161,
-2
+0,
-1
1@@ -13,4 +13,3 @@ $(dir)/cursor_data.h: $(dir)/cursor.pcf $(dir)/convert_font
2 CLEAN_FILES += $(dir)/convert_font.o
3
4 include common.mk
5-
+118,
-1
1@@ -35,8 +35,19 @@
2
3 #include <assert.h>
4 #include <stdio.h>
5+#include <string.h>
6 #include <wld/wld.h>
7
8+static enum swc_cursor_kind cursor_override = SWC_CURSOR_DEFAULT;
9+static enum swc_cursor_mode cursor_mode = SWC_CURSOR_MODE_CLIENT;
10+
11+static struct {
12+ const uint32_t *data;
13+ uint32_t width, height;
14+ int32_t hotspot_x, hotspot_y;
15+ bool active;
16+} cursor_images[6];
17+
18 EXPORT void
19 swc_pointer_send_button(uint32_t time, uint32_t button, uint32_t state)
20 {
21@@ -205,13 +216,114 @@ update_cursor(struct pointer *pointer)
22 view_move(&pointer->cursor.view, x, y);
23 }
24
25+static void
26+drop_client_cursor_surface(struct pointer *pointer)
27+{
28+ if (!pointer || !pointer->cursor.surface)
29+ return;
30+ surface_set_view(pointer->cursor.surface, NULL);
31+ wl_list_remove(&pointer->cursor.destroy_listener.link);
32+ pointer->cursor.surface = NULL;
33+}
34+
35+static void
36+apply_cursor_override(struct pointer *pointer)
37+{
38+ if (!pointer || pointer->cursor.surface)
39+ return;
40+
41+ pointer_set_cursor(pointer, cursor_left_ptr);
42+}
43+
44+EXPORT void
45+swc_set_cursor(enum swc_cursor_kind kind)
46+{
47+ struct pointer *pointer = swc.seat ? swc.seat->pointer : NULL;
48+
49+ cursor_override = kind;
50+
51+ drop_client_cursor_surface(pointer);
52+
53+ apply_cursor_override(pointer);
54+}
55+
56+EXPORT void
57+swc_set_cursor_mode(enum swc_cursor_mode mode)
58+{
59+ struct pointer *pointer = swc.seat ? swc.seat->pointer : NULL;
60+
61+ cursor_mode = mode;
62+ if (cursor_mode == SWC_CURSOR_MODE_COMPOSITOR)
63+ drop_client_cursor_surface(pointer);
64+ apply_cursor_override(pointer);
65+}
66+
67+EXPORT void
68+swc_set_cursor_image(enum swc_cursor_kind kind,
69+ const uint32_t *argb8888,
70+ uint32_t width, uint32_t height,
71+ int32_t hotspot_x, int32_t hotspot_y)
72+{
73+ struct pointer *pointer = swc.seat ? swc.seat->pointer : NULL;
74+
75+ if (kind < 0 || kind >= (int)ARRAY_LENGTH(cursor_images))
76+ return;
77+ if (!argb8888 || width == 0 || height == 0)
78+ return;
79+
80+ cursor_images[kind].data = argb8888;
81+ cursor_images[kind].width = width;
82+ cursor_images[kind].height = height;
83+ cursor_images[kind].hotspot_x = hotspot_x;
84+ cursor_images[kind].hotspot_y = hotspot_y;
85+ cursor_images[kind].active = true;
86+
87+ if (cursor_mode == SWC_CURSOR_MODE_COMPOSITOR)
88+ drop_client_cursor_surface(pointer);
89+ apply_cursor_override(pointer);
90+}
91+
92+EXPORT void
93+swc_clear_cursor_image(enum swc_cursor_kind kind)
94+{
95+ struct pointer *pointer = swc.seat ? swc.seat->pointer : NULL;
96+
97+ if (kind < 0 || kind >= (int)ARRAY_LENGTH(cursor_images))
98+ return;
99+
100+ cursor_images[kind].active = false;
101+ cursor_images[kind].data = NULL;
102+
103+ apply_cursor_override(pointer);
104+}
105+
106 void
107 pointer_set_cursor(struct pointer *pointer, uint32_t id)
108 {
109 struct cursor *cursor = &cursor_metadata[id];
110+ const uint32_t *data = cursor_data;
111 union wld_object object = { .ptr = &cursor_data[cursor->offset] };
112 struct wld_buffer *buffer;
113
114+ if (id == cursor_left_ptr) {
115+ enum swc_cursor_kind kind = cursor_override;
116+ if (kind < 0 || kind >= (int)ARRAY_LENGTH(cursor_images))
117+ kind = SWC_CURSOR_DEFAULT;
118+
119+ if (cursor_images[kind].active) {
120+ static struct cursor custom_cursor;
121+ custom_cursor.width = (int)cursor_images[kind].width;
122+ custom_cursor.height = (int)cursor_images[kind].height;
123+ custom_cursor.hotspot_x = (int)cursor_images[kind].hotspot_x;
124+ custom_cursor.hotspot_y = (int)cursor_images[kind].hotspot_y;
125+ custom_cursor.offset = 0;
126+
127+ cursor = &custom_cursor;
128+ data = cursor_images[kind].data;
129+ object.ptr = (void *)data;
130+ }
131+ }
132+
133 if (pointer->cursor.internal_buffer)
134 wld_buffer_unreference(pointer->cursor.internal_buffer);
135 if (pointer->cursor.surface) {
136@@ -315,7 +427,6 @@ pointer_initialize(struct pointer *pointer)
137 {
138 struct screen *screen = wl_container_of(swc.screens.next, screen, link);
139 struct swc_rectangle *geom = &screen->base.geometry;
140-
141 /* Center cursor in the geometry of the first screen. */
142 screen = wl_container_of(swc.screens.next, screen, link);
143 pointer->x = wl_fixed_from_int(geom->x + geom->width / 2);
144@@ -407,9 +518,15 @@ set_cursor(struct wl_client *client, struct wl_resource *resource,
145 struct pointer *pointer = wl_resource_get_user_data(resource);
146 struct surface *surface;
147
148+ (void)serial;
149+
150 if (client != pointer->focus.client)
151 return;
152
153+ /* If forcing compositor cursor, ignore client cursor surfaces. */
154+ if (cursor_mode == SWC_CURSOR_MODE_COMPOSITOR || cursor_override != SWC_CURSOR_DEFAULT)
155+ return;
156+
157 if (pointer->cursor.surface) {
158 surface_set_view(pointer->cursor.surface, NULL);
159 wl_list_remove(&pointer->cursor.destroy_listener.link);
+43,
-0
1@@ -63,6 +63,49 @@ void swc_pointer_send_button(uint32_t time, uint32_t button, uint32_t state);
2 */
3 void swc_pointer_send_axis(uint32_t time, uint32_t axis, int32_t value120);
4
5+/* Cursor control (compositor-internal cursor) */
6+enum swc_cursor_kind {
7+ SWC_CURSOR_DEFAULT = 0,
8+ SWC_CURSOR_BOX = 1,
9+ SWC_CURSOR_CROSS = 2,
10+ SWC_CURSOR_SIGHT = 3,
11+ SWC_CURSOR_UP = 4,
12+ SWC_CURSOR_DOWN = 5,
13+};
14+
15+enum swc_cursor_mode {
16+ /* Allow clients to set their own cursors (I-beam, resize, etc). */
17+ SWC_CURSOR_MODE_CLIENT = 0,
18+ /* Force compositor cursor; ignore client wl_pointer.set_cursor. */
19+ SWC_CURSOR_MODE_COMPOSITOR = 1,
20+};
21+
22+/**
23+ * override the compositor's internal cursor
24+ *
25+ * this is intended for window managers to show mode cursors (move/resize/select) like the ones in hevel
26+ * If a client has set its own cursor surface, swc may ignore the override.
27+ */
28+void swc_set_cursor(enum swc_cursor_kind kind);
29+
30+/**
31+ * control whether client cursor surfaces are honored
32+ */
33+void swc_set_cursor_mode(enum swc_cursor_mode mode);
34+
35+/**
36+ * set a custom argb8888 cursor image for a given kind
37+ *
38+ * `argb8888` is a pointer to `width*height` pixels in ARGB8888 order.
39+ * the caller has to keep the pixel memory alive for as long as it may be used
40+ */
41+void swc_set_cursor_image(enum swc_cursor_kind kind,
42+ const uint32_t *argb8888,
43+ uint32_t width, uint32_t height,
44+ int32_t hotspot_x, int32_t hotspot_y);
45+
46+void swc_clear_cursor_image(enum swc_cursor_kind kind);
47+
48 /**
49 * draw [or update] a simple box overlay
50 *