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  *