commit fc92a02

shrub  ·  2025-12-16 01:03:48 +0000 UTC
parent b8d53ba
scroll/axis bindings
this adds bindings for the pointer axis. it also adds a
swc_pointer_send-axis helper for compositors that want to sometimes
intercept axis events.
various window stacking helpers were also added
5 files changed,  +238, -1
+65, -1
  1@@ -40,6 +40,13 @@ struct binding {
  2 	void *data;
  3 };
  4 
  5+struct axis_binding {
  6+	uint32_t axis;
  7+	uint32_t modifiers;
  8+	swc_axis_binding_handler handler;
  9+	void *data;
 10+};
 11+
 12 static bool handle_key(struct keyboard *keyboard, uint32_t time, struct key *key, uint32_t state);
 13 
 14 static struct keyboard_handler key_binding_handler = {
 15@@ -47,12 +54,15 @@ static struct keyboard_handler key_binding_handler = {
 16 };
 17 
 18 static bool handle_button(struct pointer_handler *handler, uint32_t time, struct button *button, uint32_t state);
 19+static bool handle_axis(struct pointer_handler *handler, uint32_t time, enum wl_pointer_axis axis,
 20+                        enum wl_pointer_axis_source source, wl_fixed_t value, int value120);
 21 
 22 static struct pointer_handler button_binding_handler = {
 23 	.button = handle_button,
 24+	.axis = handle_axis,
 25 };
 26 
 27-static struct wl_array key_bindings, button_bindings;
 28+static struct wl_array key_bindings, button_bindings, axis_bindings;
 29 
 30 const struct swc_bindings swc_bindings = {
 31 	.keyboard_handler = &key_binding_handler,
 32@@ -107,6 +117,19 @@ find_button_binding(uint32_t modifiers, uint32_t value)
 33 	return find_binding(&button_bindings, modifiers, value);
 34 }
 35 
 36+static struct axis_binding *
 37+find_axis_binding(uint32_t modifiers, uint32_t axis)
 38+{
 39+	struct axis_binding *binding;
 40+
 41+	wl_array_for_each (binding, &axis_bindings) {
 42+		if (binding->axis == axis && (binding->modifiers == modifiers || binding->modifiers == SWC_MOD_ANY))
 43+			return binding;
 44+	}
 45+
 46+	return NULL;
 47+}
 48+
 49 static bool
 50 handle_binding(uint32_t time, struct press *press, uint32_t state, struct binding *(*find_binding)(uint32_t, uint32_t))
 51 {
 52@@ -140,11 +163,35 @@ handle_button(struct pointer_handler *handler, uint32_t time, struct button *but
 53 	return handle_binding(time, &button->press, state, &find_button_binding);
 54 }
 55 
 56+bool
 57+handle_axis(struct pointer_handler *handler, uint32_t time, enum wl_pointer_axis axis,
 58+            enum wl_pointer_axis_source source, wl_fixed_t value, int value120)
 59+{
 60+	(void)handler;
 61+	(void)source;
 62+
 63+	struct axis_binding *binding = find_axis_binding(swc.seat->keyboard->modifiers, axis);
 64+	int32_t delta120 = value120;
 65+
 66+	if (!binding)
 67+		return false;
 68+
 69+	if (!delta120 && value) {
 70+		delta120 = (int32_t)(wl_fixed_to_double(value) * 120.0);
 71+		if (!delta120)
 72+			delta120 = value > 0 ? 1 : -1;
 73+	}
 74+
 75+	binding->handler(binding->data, time, axis, delta120);
 76+	return true;
 77+}
 78+
 79 bool
 80 bindings_initialize(void)
 81 {
 82 	wl_array_init(&key_bindings);
 83 	wl_array_init(&button_bindings);
 84+	wl_array_init(&axis_bindings);
 85 
 86 	return true;
 87 }
 88@@ -154,6 +201,7 @@ bindings_finalize(void)
 89 {
 90 	wl_array_release(&key_bindings);
 91 	wl_array_release(&button_bindings);
 92+	wl_array_release(&axis_bindings);
 93 }
 94 
 95 EXPORT int
 96@@ -183,3 +231,19 @@ swc_add_binding(enum swc_binding_type type, uint32_t modifiers, uint32_t value,
 97 
 98 	return 0;
 99 }
100+
101+EXPORT int
102+swc_add_axis_binding(uint32_t modifiers, uint32_t axis, swc_axis_binding_handler handler, void *data)
103+{
104+	struct axis_binding *binding;
105+
106+	if (!(binding = wl_array_add(&axis_bindings, sizeof(*binding))))
107+		return -ENOMEM;
108+
109+	binding->axis = axis;
110+	binding->modifiers = modifiers;
111+	binding->handler = handler;
112+	binding->data = data;
113+
114+	return 0;
115+}
+92, -0
 1@@ -634,6 +634,98 @@ swc_window_at(int32_t x, int32_t y)
 2 	return view ? &view->window->base : NULL;
 3 }
 4 
 5+static struct compositor_view *
 6+view_for_window(struct swc_window *base)
 7+{
 8+	struct window *window;
 9+
10+	if (!base)
11+		return NULL;
12+
13+	window = (struct window *)base;
14+	return window->view;
15+}
16+
17+static struct compositor_view *
18+prev_window_view(struct compositor_view *view)
19+{
20+	struct wl_list *link;
21+	struct compositor_view *other;
22+
23+	for (link = view->link.prev; link != &compositor.views; link = link->prev) {
24+		other = wl_container_of(link, other, link);
25+
26+		if (other->visible && other->window)
27+			return other;
28+	}
29+
30+	return NULL;
31+}
32+
33+static struct compositor_view *
34+next_window_view(struct compositor_view *view)
35+{
36+	struct wl_list *link;
37+	struct compositor_view *other;
38+
39+	for (link = view->link.next; link != &compositor.views; link = link->next) {
40+		other = wl_container_of(link, other, link);
41+
42+		if (other->visible && other->window)
43+			return other;
44+	}
45+
46+	return NULL;
47+}
48+
49+static void
50+damage_views(struct compositor_view *a, struct compositor_view *b)
51+{
52+	uint32_t screens = a->base.screens | (b ? b->base.screens : 0);
53+
54+	a->border.damaged = true;
55+	pixman_region32_union_rect(&compositor.damage, &compositor.damage,
56+	                           a->extents.x1, a->extents.y1,
57+	                           (uint32_t)(a->extents.x2 - a->extents.x1),
58+	                           (uint32_t)(a->extents.y2 - a->extents.y1));
59+
60+	if (b) {
61+		b->border.damaged = true;
62+		pixman_region32_union_rect(&compositor.damage, &compositor.damage,
63+		                           b->extents.x1, b->extents.y1,
64+		                           (uint32_t)(b->extents.x2 - b->extents.x1),
65+		                           (uint32_t)(b->extents.y2 - b->extents.y1));
66+	}
67+
68+	schedule_updates(screens);
69+}
70+
71+EXPORT void
72+swc_window_stack(struct swc_window *window, int32_t direction)
73+{
74+	struct compositor_view *view = view_for_window(window);
75+	struct compositor_view *other = NULL;
76+
77+	if (!view || !view->visible || direction == 0)
78+		return;
79+
80+	if (direction < 0) {
81+		other = prev_window_view(view);
82+		if (!other)
83+			return;
84+		wl_list_remove(&view->link);
85+		wl_list_insert(other->link.prev, &view->link);
86+	} else {
87+		other = next_window_view(view);
88+		if (!other)
89+			return;
90+		wl_list_remove(&view->link);
91+		wl_list_insert(&other->link, &view->link);
92+	}
93+
94+	damage_views(view, other);
95+}
96+
97 struct compositor_view *
98 compositor_create_view(struct surface *surface)
99 {
+37, -0
 1@@ -57,6 +57,43 @@ swc_pointer_send_button(uint32_t time, uint32_t button, uint32_t state)
 2 	pointer->client_axis_source = -1;
 3 }
 4 
 5+EXPORT void
 6+swc_pointer_send_axis(uint32_t time, uint32_t axis, int32_t value120)
 7+{
 8+	struct pointer *pointer = swc.seat ? swc.seat->pointer : NULL;
 9+	struct wl_resource *resource;
10+	wl_fixed_t value;
11+
12+	if (!pointer || wl_list_empty(&pointer->focus.active))
13+		return;
14+
15+	value = wl_fixed_from_double((double)value120 / 120.0);
16+
17+	wl_resource_for_each (resource, &pointer->focus.active) {
18+		int ver = wl_resource_get_version(resource);
19+
20+		if (ver >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION)
21+			wl_pointer_send_axis_source(resource, WL_POINTER_AXIS_SOURCE_WHEEL);
22+		if (value120) {
23+			if (ver >= WL_POINTER_AXIS_VALUE120_SINCE_VERSION)
24+				wl_pointer_send_axis_value120(resource, axis, value120);
25+			else if (ver >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION)
26+				wl_pointer_send_axis_discrete(resource, axis, value120 / 120);
27+		}
28+
29+		if (value)
30+			wl_pointer_send_axis(resource, time, axis, value);
31+		else if (ver >= WL_POINTER_AXIS_STOP_SINCE_VERSION)
32+			wl_pointer_send_axis_stop(resource, time, axis);
33+	}
34+
35+	wl_resource_for_each (resource, &pointer->focus.active) {
36+		if (wl_resource_get_version(resource) >= WL_POINTER_FRAME_SINCE_VERSION)
37+			wl_pointer_send_frame(resource);
38+	}
39+	pointer->client_axis_source = -1;
40+}
41+
42 static void
43 enter(struct input_focus_handler *handler, struct wl_list *resources, struct compositor_view *view)
44 {
+32, -0
 1@@ -53,6 +53,16 @@ bool swc_cursor_position(int32_t *x, int32_t *y);
 2  */
 3 void swc_pointer_send_button(uint32_t time, uint32_t button, uint32_t state);
 4 
 5+/**
 6+ * Send a pointer axis event to the currently focused client.
 7+ *
 8+ * This is intended for window managers which intercept axis events (for
 9+ * example for mouse chords) but want normal scrolling to still reach clients.
10+ *
11+ * value120 uses the wl_pointer "120 units" convention.
12+ */
13+void swc_pointer_send_axis(uint32_t time, uint32_t axis, int32_t value120);
14+
15 /**
16  * draw [or update] a simple box overlay
17  *
18@@ -262,6 +272,11 @@ void swc_window_set_size(struct swc_window *window, uint32_t width, uint32_t hei
19  */
20 void swc_window_set_geometry(struct swc_window *window, const struct swc_rectangle *geometry);
21 
22+/**
23+ * Get the window's current geometry in compositor-global coordinates.
24+ */
25+bool swc_window_get_geometry(const struct swc_window *window, struct swc_rectangle *geometry);
26+
27 /**
28  * Set the window's border color and width.
29  *
30@@ -307,6 +322,14 @@ void swc_window_end_resize(struct swc_window *window);
31  */
32 struct swc_window *swc_window_at(int32_t x, int32_t y);
33 
34+/**
35+ * move a window in the stacking order by one step
36+ *
37+ * direction < 0 moves the window towards the front (higher)
38+ * direction > 0 moves the window towards the back (lower)
39+ */
40+void swc_window_stack(struct swc_window *window, int32_t direction);
41+
42 /* }}} */
43 
44 /* Bindings {{{ */
45@@ -325,6 +348,7 @@ enum swc_binding_type {
46 };
47 
48 typedef void (*swc_binding_handler)(void *data, uint32_t time, uint32_t value, uint32_t state);
49+typedef void (*swc_axis_binding_handler)(void *data, uint32_t time, uint32_t axis, int32_t value120);
50 
51 /**
52  * Register a new input binding.
53@@ -333,6 +357,14 @@ typedef void (*swc_binding_handler)(void *data, uint32_t time, uint32_t value, u
54  */
55 int swc_add_binding(enum swc_binding_type type, uint32_t modifiers, uint32_t value, swc_binding_handler handler, void *data);
56 
57+/**
58+ * register a new pointer axis binding
59+ *
60+ * this will intercept axis events from clients; use swc_pointer_send_axis()
61+ * from the handler to forward events when appropriate
62+ */
63+int swc_add_axis_binding(uint32_t modifiers, uint32_t axis, swc_axis_binding_handler handler, void *data);
64+
65 /* }}} */
66 
67 /**
+12, -0
 1@@ -248,6 +248,18 @@ swc_window_set_geometry(struct swc_window *window, const struct swc_rectangle *g
 2 	swc_window_set_position(window, geometry->x, geometry->y);
 3 }
 4 
 5+EXPORT bool
 6+swc_window_get_geometry(const struct swc_window *base, struct swc_rectangle *geometry)
 7+{
 8+	struct window *window = INTERNAL((struct swc_window *)base);
 9+
10+	if (!window || !geometry)
11+		return false;
12+
13+	*geometry = window->view->base.geometry;
14+	return true;
15+}
16+
17 EXPORT void
18 swc_window_set_border(struct swc_window *window, uint32_t inner_border_color, uint32_t inner_border_width, 
19 		uint32_t outer_border_color, uint32_t outer_border_width)