1 #include <assert.h>
2 #include <limits.h>
3 #include <math.h>
4 #include <stdlib.h>
5 #include <wayland-server-core.h>
6 #include <wlr/types/wlr_cursor.h>
7 #include <wlr/types/wlr_input_device.h>
8 #include <wlr/types/wlr_output_layout.h>
9 #include <wlr/types/wlr_output.h>
10 #include <wlr/util/log.h>
11 #include "util/signal.h"
12
13 struct wlr_cursor_device {
14 struct wlr_cursor *cursor;
15 struct wlr_input_device *device;
16 struct wl_list link;
17 struct wlr_output *mapped_output;
18 struct wlr_box *mapped_box;
19
20 struct wl_listener motion;
21 struct wl_listener motion_absolute;
22 struct wl_listener button;
23 struct wl_listener axis;
24 struct wl_listener frame;
25 struct wl_listener swipe_begin;
26 struct wl_listener swipe_update;
27 struct wl_listener swipe_end;
28 struct wl_listener pinch_begin;
29 struct wl_listener pinch_update;
30 struct wl_listener pinch_end;
31
32 struct wl_listener touch_down;
33 struct wl_listener touch_up;
34 struct wl_listener touch_motion;
35 struct wl_listener touch_cancel;
36
37 struct wl_listener tablet_tool_axis;
38 struct wl_listener tablet_tool_proximity;
39 struct wl_listener tablet_tool_tip;
40 struct wl_listener tablet_tool_button;
41
42 struct wl_listener destroy;
43 };
44
45 struct wlr_cursor_output_cursor {
46 struct wlr_cursor *cursor;
47 struct wlr_output_cursor *output_cursor;
48 struct wl_list link;
49
50 struct wl_listener layout_output_destroy;
51 };
52
53 struct wlr_cursor_state {
54 struct wlr_cursor *cursor;
55 struct wl_list devices; // wlr_cursor_device::link
56 struct wl_list output_cursors; // wlr_cursor_output_cursor::link
57 struct wlr_output_layout *layout;
58 struct wlr_output *mapped_output;
59 struct wlr_box *mapped_box;
60
61 struct wl_listener layout_add;
62 struct wl_listener layout_change;
63 struct wl_listener layout_destroy;
64 };
65
wlr_cursor_create(void)66 struct wlr_cursor *wlr_cursor_create(void) {
67 struct wlr_cursor *cur = calloc(1, sizeof(struct wlr_cursor));
68 if (!cur) {
69 wlr_log(WLR_ERROR, "Failed to allocate wlr_cursor");
70 return NULL;
71 }
72
73 cur->state = calloc(1, sizeof(struct wlr_cursor_state));
74 if (!cur->state) {
75 wlr_log(WLR_ERROR, "Failed to allocate wlr_cursor_state");
76 free(cur);
77 return NULL;
78 }
79
80 cur->state->cursor = cur;
81 cur->state->mapped_output = NULL;
82
83 wl_list_init(&cur->state->devices);
84 wl_list_init(&cur->state->output_cursors);
85
86 // pointer signals
87 wl_signal_init(&cur->events.motion);
88 wl_signal_init(&cur->events.motion_absolute);
89 wl_signal_init(&cur->events.button);
90 wl_signal_init(&cur->events.axis);
91 wl_signal_init(&cur->events.frame);
92 wl_signal_init(&cur->events.swipe_begin);
93 wl_signal_init(&cur->events.swipe_update);
94 wl_signal_init(&cur->events.swipe_end);
95 wl_signal_init(&cur->events.pinch_begin);
96 wl_signal_init(&cur->events.pinch_update);
97 wl_signal_init(&cur->events.pinch_end);
98
99 // touch signals
100 wl_signal_init(&cur->events.touch_up);
101 wl_signal_init(&cur->events.touch_down);
102 wl_signal_init(&cur->events.touch_motion);
103 wl_signal_init(&cur->events.touch_cancel);
104
105 // tablet tool signals
106 wl_signal_init(&cur->events.tablet_tool_tip);
107 wl_signal_init(&cur->events.tablet_tool_axis);
108 wl_signal_init(&cur->events.tablet_tool_button);
109 wl_signal_init(&cur->events.tablet_tool_proximity);
110
111 cur->x = 100;
112 cur->y = 100;
113
114 return cur;
115 }
116
output_cursor_destroy(struct wlr_cursor_output_cursor * output_cursor)117 static void output_cursor_destroy(
118 struct wlr_cursor_output_cursor *output_cursor) {
119 wl_list_remove(&output_cursor->layout_output_destroy.link);
120 wl_list_remove(&output_cursor->link);
121 wlr_output_cursor_destroy(output_cursor->output_cursor);
122 free(output_cursor);
123 }
124
cursor_detach_output_layout(struct wlr_cursor * cur)125 static void cursor_detach_output_layout(struct wlr_cursor *cur) {
126 if (!cur->state->layout) {
127 return;
128 }
129
130 struct wlr_cursor_output_cursor *output_cursor, *tmp;
131 wl_list_for_each_safe(output_cursor, tmp, &cur->state->output_cursors,
132 link) {
133 output_cursor_destroy(output_cursor);
134 }
135
136 wl_list_remove(&cur->state->layout_destroy.link);
137 wl_list_remove(&cur->state->layout_change.link);
138 wl_list_remove(&cur->state->layout_add.link);
139
140 cur->state->layout = NULL;
141 }
142
cursor_device_destroy(struct wlr_cursor_device * c_device)143 static void cursor_device_destroy(struct wlr_cursor_device *c_device) {
144 struct wlr_input_device *dev = c_device->device;
145 if (dev->type == WLR_INPUT_DEVICE_POINTER) {
146 wl_list_remove(&c_device->motion.link);
147 wl_list_remove(&c_device->motion_absolute.link);
148 wl_list_remove(&c_device->button.link);
149 wl_list_remove(&c_device->axis.link);
150 wl_list_remove(&c_device->frame.link);
151 wl_list_remove(&c_device->swipe_begin.link);
152 wl_list_remove(&c_device->swipe_update.link);
153 wl_list_remove(&c_device->swipe_end.link);
154 wl_list_remove(&c_device->pinch_begin.link);
155 wl_list_remove(&c_device->pinch_update.link);
156 wl_list_remove(&c_device->pinch_end.link);
157 } else if (dev->type == WLR_INPUT_DEVICE_TOUCH) {
158 wl_list_remove(&c_device->touch_down.link);
159 wl_list_remove(&c_device->touch_up.link);
160 wl_list_remove(&c_device->touch_motion.link);
161 wl_list_remove(&c_device->touch_cancel.link);
162 } else if (dev->type == WLR_INPUT_DEVICE_TABLET_TOOL) {
163 wl_list_remove(&c_device->tablet_tool_axis.link);
164 wl_list_remove(&c_device->tablet_tool_proximity.link);
165 wl_list_remove(&c_device->tablet_tool_tip.link);
166 wl_list_remove(&c_device->tablet_tool_button.link);
167 }
168
169 wl_list_remove(&c_device->link);
170 wl_list_remove(&c_device->destroy.link);
171 free(c_device);
172 }
173
wlr_cursor_destroy(struct wlr_cursor * cur)174 void wlr_cursor_destroy(struct wlr_cursor *cur) {
175 cursor_detach_output_layout(cur);
176
177 struct wlr_cursor_device *device, *device_tmp = NULL;
178 wl_list_for_each_safe(device, device_tmp, &cur->state->devices, link) {
179 cursor_device_destroy(device);
180 }
181
182 free(cur->state);
183 free(cur);
184 }
185
get_cursor_device(struct wlr_cursor * cur,struct wlr_input_device * device)186 static struct wlr_cursor_device *get_cursor_device(struct wlr_cursor *cur,
187 struct wlr_input_device *device) {
188 struct wlr_cursor_device *c_device, *ret = NULL;
189 wl_list_for_each(c_device, &cur->state->devices, link) {
190 if (c_device->device == device) {
191 ret = c_device;
192 break;
193 }
194 }
195
196 return ret;
197 }
198
cursor_warp_unchecked(struct wlr_cursor * cur,double lx,double ly)199 static void cursor_warp_unchecked(struct wlr_cursor *cur,
200 double lx, double ly) {
201 assert(cur->state->layout);
202
203 struct wlr_cursor_output_cursor *output_cursor;
204 wl_list_for_each(output_cursor, &cur->state->output_cursors, link) {
205 double output_x = lx, output_y = ly;
206 wlr_output_layout_output_coords(cur->state->layout,
207 output_cursor->output_cursor->output, &output_x, &output_y);
208 wlr_output_cursor_move(output_cursor->output_cursor,
209 output_x, output_y);
210 }
211
212 cur->x = lx;
213 cur->y = ly;
214 }
215
216 /**
217 * Get the most specific mapping box for the device in this order:
218 *
219 * 1. device geometry mapping
220 * 2. device output mapping
221 * 3. cursor geometry mapping
222 * 4. cursor output mapping
223 *
224 * Absolute movement for touch and pen devices will be relative to this box and
225 * pointer movement will be constrained to this box.
226 *
227 * If none of these are set, returns NULL and absolute movement should be
228 * relative to the extents of the layout.
229 */
get_mapping(struct wlr_cursor * cur,struct wlr_input_device * dev)230 static struct wlr_box *get_mapping(struct wlr_cursor *cur,
231 struct wlr_input_device *dev) {
232 assert(cur->state->layout);
233 struct wlr_cursor_device *c_device = get_cursor_device(cur, dev);
234
235 if (c_device) {
236 if (c_device->mapped_box) {
237 return c_device->mapped_box;
238 }
239 if (c_device->mapped_output) {
240 return wlr_output_layout_get_box(cur->state->layout,
241 c_device->mapped_output);
242 }
243 }
244
245 if (cur->state->mapped_box) {
246 return cur->state->mapped_box;
247 }
248 if (cur->state->mapped_output) {
249 return wlr_output_layout_get_box(cur->state->layout,
250 cur->state->mapped_output);
251 }
252
253 return NULL;
254 }
255
wlr_cursor_warp(struct wlr_cursor * cur,struct wlr_input_device * dev,double lx,double ly)256 bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev,
257 double lx, double ly) {
258 assert(cur->state->layout);
259
260 bool result = false;
261 struct wlr_box *mapping = get_mapping(cur, dev);
262 if (mapping) {
263 result = wlr_box_contains_point(mapping, lx, ly);
264 } else {
265 result = wlr_output_layout_contains_point(cur->state->layout, NULL,
266 lx, ly);
267 }
268
269 if (result) {
270 cursor_warp_unchecked(cur, lx, ly);
271 }
272
273 return result;
274 }
275
wlr_cursor_warp_closest(struct wlr_cursor * cur,struct wlr_input_device * dev,double lx,double ly)276 void wlr_cursor_warp_closest(struct wlr_cursor *cur,
277 struct wlr_input_device *dev, double lx, double ly) {
278 struct wlr_box *mapping = get_mapping(cur, dev);
279 if (mapping) {
280 wlr_box_closest_point(mapping, lx, ly, &lx, &ly);
281 if (isnan(lx) || isnan(ly)) {
282 lx = 0;
283 ly = 0;
284 }
285 } else {
286 wlr_output_layout_closest_point(cur->state->layout, NULL, lx, ly,
287 &lx, &ly);
288 }
289
290 cursor_warp_unchecked(cur, lx, ly);
291 }
292
wlr_cursor_absolute_to_layout_coords(struct wlr_cursor * cur,struct wlr_input_device * dev,double x,double y,double * lx,double * ly)293 void wlr_cursor_absolute_to_layout_coords(struct wlr_cursor *cur,
294 struct wlr_input_device *dev, double x, double y,
295 double *lx, double *ly) {
296 assert(cur->state->layout);
297
298 struct wlr_box *mapping = get_mapping(cur, dev);
299 if (!mapping) {
300 mapping = wlr_output_layout_get_box(cur->state->layout, NULL);
301 }
302
303 *lx = !isnan(x) ? mapping->width * x + mapping->x : cur->x;
304 *ly = !isnan(y) ? mapping->height * y + mapping->y : cur->y;
305 }
306
wlr_cursor_warp_absolute(struct wlr_cursor * cur,struct wlr_input_device * dev,double x,double y)307 void wlr_cursor_warp_absolute(struct wlr_cursor *cur,
308 struct wlr_input_device *dev, double x, double y) {
309 assert(cur->state->layout);
310
311 double lx, ly;
312 wlr_cursor_absolute_to_layout_coords(cur, dev, x, y, &lx, &ly);
313
314 wlr_cursor_warp_closest(cur, dev, lx, ly);
315 }
316
wlr_cursor_move(struct wlr_cursor * cur,struct wlr_input_device * dev,double delta_x,double delta_y)317 void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev,
318 double delta_x, double delta_y) {
319 assert(cur->state->layout);
320
321 double lx = !isnan(delta_x) ? cur->x + delta_x : cur->x;
322 double ly = !isnan(delta_y) ? cur->y + delta_y : cur->y;
323
324 wlr_cursor_warp_closest(cur, dev, lx, ly);
325 }
326
wlr_cursor_set_image(struct wlr_cursor * cur,const uint8_t * pixels,int32_t stride,uint32_t width,uint32_t height,int32_t hotspot_x,int32_t hotspot_y,float scale)327 void wlr_cursor_set_image(struct wlr_cursor *cur, const uint8_t *pixels,
328 int32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x,
329 int32_t hotspot_y, float scale) {
330 struct wlr_cursor_output_cursor *output_cursor;
331 wl_list_for_each(output_cursor, &cur->state->output_cursors, link) {
332 float output_scale = output_cursor->output_cursor->output->scale;
333 if (scale > 0 && output_scale != scale) {
334 continue;
335 }
336
337 wlr_output_cursor_set_image(output_cursor->output_cursor, pixels,
338 stride, width, height, hotspot_x, hotspot_y);
339 }
340 }
341
wlr_cursor_set_surface(struct wlr_cursor * cur,struct wlr_surface * surface,int32_t hotspot_x,int32_t hotspot_y)342 void wlr_cursor_set_surface(struct wlr_cursor *cur, struct wlr_surface *surface,
343 int32_t hotspot_x, int32_t hotspot_y) {
344 struct wlr_cursor_output_cursor *output_cursor;
345 wl_list_for_each(output_cursor, &cur->state->output_cursors, link) {
346 wlr_output_cursor_set_surface(output_cursor->output_cursor, surface,
347 hotspot_x, hotspot_y);
348 }
349 }
350
handle_pointer_motion(struct wl_listener * listener,void * data)351 static void handle_pointer_motion(struct wl_listener *listener, void *data) {
352 struct wlr_event_pointer_motion *event = data;
353 struct wlr_cursor_device *device =
354 wl_container_of(listener, device, motion);
355 wlr_signal_emit_safe(&device->cursor->events.motion, event);
356 }
357
apply_output_transform(double * x,double * y,enum wl_output_transform transform)358 static void apply_output_transform(double *x, double *y,
359 enum wl_output_transform transform) {
360 double dx = 0.0, dy = 0.0;
361 double width = 1.0, height = 1.0;
362
363 switch (transform) {
364 case WL_OUTPUT_TRANSFORM_NORMAL:
365 dx = *x;
366 dy = *y;
367 break;
368 case WL_OUTPUT_TRANSFORM_90:
369 dx = height - *y;
370 dy = *x;
371 break;
372 case WL_OUTPUT_TRANSFORM_180:
373 dx = width - *x;
374 dy = height - *y;
375 break;
376 case WL_OUTPUT_TRANSFORM_270:
377 dx = *y;
378 dy = width - *x;
379 break;
380 case WL_OUTPUT_TRANSFORM_FLIPPED:
381 dx = width - *x;
382 dy = *y;
383 break;
384 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
385 dx = *y;
386 dy = *x;
387 break;
388 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
389 dx = *x;
390 dy = height - *y;
391 break;
392 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
393 dx = height - *y;
394 dy = width - *x;
395 break;
396 }
397 *x = dx;
398 *y = dy;
399 }
400
401
get_mapped_output(struct wlr_cursor_device * cursor_device)402 static struct wlr_output *get_mapped_output(struct wlr_cursor_device *cursor_device) {
403 if (cursor_device->mapped_output) {
404 return cursor_device->mapped_output;
405 }
406
407 struct wlr_cursor *cursor = cursor_device->cursor;
408 assert(cursor);
409 if (cursor->state->mapped_output) {
410 return cursor->state->mapped_output;
411 }
412 return NULL;
413 }
414
415
handle_pointer_motion_absolute(struct wl_listener * listener,void * data)416 static void handle_pointer_motion_absolute(struct wl_listener *listener,
417 void *data) {
418 struct wlr_event_pointer_motion_absolute *event = data;
419 struct wlr_cursor_device *device =
420 wl_container_of(listener, device, motion_absolute);
421
422 struct wlr_output *output =
423 get_mapped_output(device);
424 if (output) {
425 apply_output_transform(&event->x, &event->y, output->transform);
426 }
427 wlr_signal_emit_safe(&device->cursor->events.motion_absolute, event);
428 }
429
handle_pointer_button(struct wl_listener * listener,void * data)430 static void handle_pointer_button(struct wl_listener *listener, void *data) {
431 struct wlr_event_pointer_button *event = data;
432 struct wlr_cursor_device *device =
433 wl_container_of(listener, device, button);
434 wlr_signal_emit_safe(&device->cursor->events.button, event);
435 }
436
handle_pointer_axis(struct wl_listener * listener,void * data)437 static void handle_pointer_axis(struct wl_listener *listener, void *data) {
438 struct wlr_event_pointer_axis *event = data;
439 struct wlr_cursor_device *device = wl_container_of(listener, device, axis);
440 wlr_signal_emit_safe(&device->cursor->events.axis, event);
441 }
442
handle_pointer_frame(struct wl_listener * listener,void * data)443 static void handle_pointer_frame(struct wl_listener *listener, void *data) {
444 struct wlr_cursor_device *device = wl_container_of(listener, device, frame);
445 wlr_signal_emit_safe(&device->cursor->events.frame, device->cursor);
446 }
447
handle_pointer_swipe_begin(struct wl_listener * listener,void * data)448 static void handle_pointer_swipe_begin(struct wl_listener *listener, void *data) {
449 struct wlr_event_pointer_swipe_begin *event = data;
450 struct wlr_cursor_device *device = wl_container_of(listener, device, swipe_begin);
451 wlr_signal_emit_safe(&device->cursor->events.swipe_begin, event);
452 }
453
handle_pointer_swipe_update(struct wl_listener * listener,void * data)454 static void handle_pointer_swipe_update(struct wl_listener *listener, void *data) {
455 struct wlr_event_pointer_swipe_update *event = data;
456 struct wlr_cursor_device *device = wl_container_of(listener, device, swipe_update);
457 wlr_signal_emit_safe(&device->cursor->events.swipe_update, event);
458 }
459
handle_pointer_swipe_end(struct wl_listener * listener,void * data)460 static void handle_pointer_swipe_end(struct wl_listener *listener, void *data) {
461 struct wlr_event_pointer_swipe_end *event = data;
462 struct wlr_cursor_device *device = wl_container_of(listener, device, swipe_end);
463 wlr_signal_emit_safe(&device->cursor->events.swipe_end, event);
464 }
465
handle_pointer_pinch_begin(struct wl_listener * listener,void * data)466 static void handle_pointer_pinch_begin(struct wl_listener *listener, void *data) {
467 struct wlr_event_pointer_pinch_begin *event = data;
468 struct wlr_cursor_device *device = wl_container_of(listener, device, pinch_begin);
469 wlr_signal_emit_safe(&device->cursor->events.pinch_begin, event);
470 }
471
handle_pointer_pinch_update(struct wl_listener * listener,void * data)472 static void handle_pointer_pinch_update(struct wl_listener *listener, void *data) {
473 struct wlr_event_pointer_pinch_update *event = data;
474 struct wlr_cursor_device *device = wl_container_of(listener, device, pinch_update);
475 wlr_signal_emit_safe(&device->cursor->events.pinch_update, event);
476 }
477
handle_pointer_pinch_end(struct wl_listener * listener,void * data)478 static void handle_pointer_pinch_end(struct wl_listener *listener, void *data) {
479 struct wlr_event_pointer_pinch_end *event = data;
480 struct wlr_cursor_device *device = wl_container_of(listener, device, pinch_end);
481 wlr_signal_emit_safe(&device->cursor->events.pinch_end, event);
482 }
483
handle_touch_up(struct wl_listener * listener,void * data)484 static void handle_touch_up(struct wl_listener *listener, void *data) {
485 struct wlr_event_touch_up *event = data;
486 struct wlr_cursor_device *device;
487 device = wl_container_of(listener, device, touch_up);
488 wlr_signal_emit_safe(&device->cursor->events.touch_up, event);
489 }
490
handle_touch_down(struct wl_listener * listener,void * data)491 static void handle_touch_down(struct wl_listener *listener, void *data) {
492 struct wlr_event_touch_down *event = data;
493 struct wlr_cursor_device *device;
494 device = wl_container_of(listener, device, touch_down);
495
496 struct wlr_output *output =
497 get_mapped_output(device);
498 if (output) {
499 apply_output_transform(&event->x, &event->y, output->transform);
500 }
501 wlr_signal_emit_safe(&device->cursor->events.touch_down, event);
502 }
503
handle_touch_motion(struct wl_listener * listener,void * data)504 static void handle_touch_motion(struct wl_listener *listener, void *data) {
505 struct wlr_event_touch_motion *event = data;
506 struct wlr_cursor_device *device;
507 device = wl_container_of(listener, device, touch_motion);
508
509 struct wlr_output *output =
510 get_mapped_output(device);
511 if (output) {
512 apply_output_transform(&event->x, &event->y, output->transform);
513 }
514 wlr_signal_emit_safe(&device->cursor->events.touch_motion, event);
515 }
516
handle_touch_cancel(struct wl_listener * listener,void * data)517 static void handle_touch_cancel(struct wl_listener *listener, void *data) {
518 struct wlr_event_touch_cancel *event = data;
519 struct wlr_cursor_device *device;
520 device = wl_container_of(listener, device, touch_cancel);
521 wlr_signal_emit_safe(&device->cursor->events.touch_cancel, event);
522 }
523
handle_tablet_tool_tip(struct wl_listener * listener,void * data)524 static void handle_tablet_tool_tip(struct wl_listener *listener, void *data) {
525 struct wlr_event_tablet_tool_tip *event = data;
526 struct wlr_cursor_device *device;
527 device = wl_container_of(listener, device, tablet_tool_tip);
528
529 struct wlr_output *output =
530 get_mapped_output(device);
531 if (output) {
532 apply_output_transform(&event->x, &event->y, output->transform);
533 }
534 wlr_signal_emit_safe(&device->cursor->events.tablet_tool_tip, event);
535 }
536
handle_tablet_tool_axis(struct wl_listener * listener,void * data)537 static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) {
538 struct wlr_event_tablet_tool_axis *event = data;
539 struct wlr_cursor_device *device;
540 device = wl_container_of(listener, device, tablet_tool_axis);
541
542 struct wlr_output *output = get_mapped_output(device);
543 if (output) {
544 // In the case that only one axis received an event, rotating the input can
545 // cause the change to actually happen on the other axis, as far as clients
546 // are concerned.
547 //
548 // Here, we feed apply_output_transform NAN on the axis that didn't change,
549 // and remap the axes flags based on whether it returns NAN itself.
550 double x = event->updated_axes & WLR_TABLET_TOOL_AXIS_X ? event->x : NAN;
551 double y = event->updated_axes & WLR_TABLET_TOOL_AXIS_Y ? event->y : NAN;
552
553 apply_output_transform(&x, &y, output->transform);
554
555 event->updated_axes &= ~(WLR_TABLET_TOOL_AXIS_X | WLR_TABLET_TOOL_AXIS_Y);
556 event->x = event->y = 0;
557
558 if (!isnan(x)) {
559 event->updated_axes |= WLR_TABLET_TOOL_AXIS_X;
560 event->x = x;
561 }
562
563 if (!isnan(y)) {
564 event->updated_axes |= WLR_TABLET_TOOL_AXIS_Y;
565 event->y = y;
566 }
567 }
568
569 wlr_signal_emit_safe(&device->cursor->events.tablet_tool_axis, event);
570 }
571
handle_tablet_tool_button(struct wl_listener * listener,void * data)572 static void handle_tablet_tool_button(struct wl_listener *listener,
573 void *data) {
574 struct wlr_event_tablet_tool_button *event = data;
575 struct wlr_cursor_device *device;
576 device = wl_container_of(listener, device, tablet_tool_button);
577 wlr_signal_emit_safe(&device->cursor->events.tablet_tool_button, event);
578 }
579
handle_tablet_tool_proximity(struct wl_listener * listener,void * data)580 static void handle_tablet_tool_proximity(struct wl_listener *listener,
581 void *data) {
582 struct wlr_event_tablet_tool_proximity *event = data;
583 struct wlr_cursor_device *device;
584 device = wl_container_of(listener, device, tablet_tool_proximity);
585
586 struct wlr_output *output =
587 get_mapped_output(device);
588 if (output) {
589 apply_output_transform(&event->x, &event->y, output->transform);
590 }
591 wlr_signal_emit_safe(&device->cursor->events.tablet_tool_proximity, event);
592 }
593
handle_device_destroy(struct wl_listener * listener,void * data)594 static void handle_device_destroy(struct wl_listener *listener, void *data) {
595 struct wlr_cursor_device *c_device;
596 c_device = wl_container_of(listener, c_device, destroy);
597 wlr_cursor_detach_input_device(c_device->cursor, c_device->device);
598 }
599
cursor_device_create(struct wlr_cursor * cursor,struct wlr_input_device * device)600 static struct wlr_cursor_device *cursor_device_create(
601 struct wlr_cursor *cursor, struct wlr_input_device *device) {
602 struct wlr_cursor_device *c_device =
603 calloc(1, sizeof(struct wlr_cursor_device));
604 if (!c_device) {
605 wlr_log(WLR_ERROR, "Failed to allocate wlr_cursor_device");
606 return NULL;
607 }
608
609 c_device->cursor = cursor;
610 c_device->device = device;
611
612 // listen to events
613 wl_signal_add(&device->events.destroy, &c_device->destroy);
614 c_device->destroy.notify = handle_device_destroy;
615
616 if (device->type == WLR_INPUT_DEVICE_POINTER) {
617 wl_signal_add(&device->pointer->events.motion, &c_device->motion);
618 c_device->motion.notify = handle_pointer_motion;
619
620 wl_signal_add(&device->pointer->events.motion_absolute,
621 &c_device->motion_absolute);
622 c_device->motion_absolute.notify = handle_pointer_motion_absolute;
623
624 wl_signal_add(&device->pointer->events.button, &c_device->button);
625 c_device->button.notify = handle_pointer_button;
626
627 wl_signal_add(&device->pointer->events.axis, &c_device->axis);
628 c_device->axis.notify = handle_pointer_axis;
629
630 wl_signal_add(&device->pointer->events.frame, &c_device->frame);
631 c_device->frame.notify = handle_pointer_frame;
632
633 wl_signal_add(&device->pointer->events.swipe_begin, &c_device->swipe_begin);
634 c_device->swipe_begin.notify = handle_pointer_swipe_begin;
635
636 wl_signal_add(&device->pointer->events.swipe_update, &c_device->swipe_update);
637 c_device->swipe_update.notify = handle_pointer_swipe_update;
638
639 wl_signal_add(&device->pointer->events.swipe_end, &c_device->swipe_end);
640 c_device->swipe_end.notify = handle_pointer_swipe_end;
641
642 wl_signal_add(&device->pointer->events.pinch_begin, &c_device->pinch_begin);
643 c_device->pinch_begin.notify = handle_pointer_pinch_begin;
644
645 wl_signal_add(&device->pointer->events.pinch_update, &c_device->pinch_update);
646 c_device->pinch_update.notify = handle_pointer_pinch_update;
647
648 wl_signal_add(&device->pointer->events.pinch_end, &c_device->pinch_end);
649 c_device->pinch_end.notify = handle_pointer_pinch_end;
650 } else if (device->type == WLR_INPUT_DEVICE_TOUCH) {
651 wl_signal_add(&device->touch->events.motion, &c_device->touch_motion);
652 c_device->touch_motion.notify = handle_touch_motion;
653
654 wl_signal_add(&device->touch->events.down, &c_device->touch_down);
655 c_device->touch_down.notify = handle_touch_down;
656
657 wl_signal_add(&device->touch->events.up, &c_device->touch_up);
658 c_device->touch_up.notify = handle_touch_up;
659
660 wl_signal_add(&device->touch->events.cancel, &c_device->touch_cancel);
661 c_device->touch_cancel.notify = handle_touch_cancel;
662 } else if (device->type == WLR_INPUT_DEVICE_TABLET_TOOL) {
663 wl_signal_add(&device->tablet->events.tip,
664 &c_device->tablet_tool_tip);
665 c_device->tablet_tool_tip.notify = handle_tablet_tool_tip;
666
667 wl_signal_add(&device->tablet->events.proximity,
668 &c_device->tablet_tool_proximity);
669 c_device->tablet_tool_proximity.notify = handle_tablet_tool_proximity;
670
671 wl_signal_add(&device->tablet->events.axis,
672 &c_device->tablet_tool_axis);
673 c_device->tablet_tool_axis.notify = handle_tablet_tool_axis;
674
675 wl_signal_add(&device->tablet->events.button,
676 &c_device->tablet_tool_button);
677 c_device->tablet_tool_button.notify = handle_tablet_tool_button;
678 }
679
680 wl_list_insert(&cursor->state->devices, &c_device->link);
681
682 return c_device;
683 }
684
wlr_cursor_attach_input_device(struct wlr_cursor * cur,struct wlr_input_device * dev)685 void wlr_cursor_attach_input_device(struct wlr_cursor *cur,
686 struct wlr_input_device *dev) {
687 if (dev->type != WLR_INPUT_DEVICE_POINTER &&
688 dev->type != WLR_INPUT_DEVICE_TOUCH &&
689 dev->type != WLR_INPUT_DEVICE_TABLET_TOOL) {
690 wlr_log(WLR_ERROR, "only device types of pointer, touch or tablet tool"
691 "are supported");
692 return;
693 }
694
695 // make sure it is not already attached
696 struct wlr_cursor_device *_dev;
697 wl_list_for_each(_dev, &cur->state->devices, link) {
698 if (_dev->device == dev) {
699 return;
700 }
701 }
702
703 cursor_device_create(cur, dev);
704 }
705
wlr_cursor_detach_input_device(struct wlr_cursor * cur,struct wlr_input_device * dev)706 void wlr_cursor_detach_input_device(struct wlr_cursor *cur,
707 struct wlr_input_device *dev) {
708 struct wlr_cursor_device *c_device, *tmp = NULL;
709 wl_list_for_each_safe(c_device, tmp, &cur->state->devices, link) {
710 if (c_device->device == dev) {
711 cursor_device_destroy(c_device);
712 }
713 }
714 }
715
handle_layout_destroy(struct wl_listener * listener,void * data)716 static void handle_layout_destroy(struct wl_listener *listener, void *data) {
717 struct wlr_cursor_state *state =
718 wl_container_of(listener, state, layout_destroy);
719 cursor_detach_output_layout(state->cursor);
720 }
721
handle_layout_output_destroy(struct wl_listener * listener,void * data)722 static void handle_layout_output_destroy(struct wl_listener *listener,
723 void *data) {
724 struct wlr_cursor_output_cursor *output_cursor =
725 wl_container_of(listener, output_cursor, layout_output_destroy);
726 //struct wlr_output_layout_output *l_output = data;
727 output_cursor_destroy(output_cursor);
728 }
729
layout_add(struct wlr_cursor_state * state,struct wlr_output_layout_output * l_output)730 static void layout_add(struct wlr_cursor_state *state,
731 struct wlr_output_layout_output *l_output) {
732 struct wlr_cursor_output_cursor *output_cursor;
733 wl_list_for_each(output_cursor, &state->output_cursors, link) {
734 if (output_cursor->output_cursor->output == l_output->output) {
735 return; // already added
736 }
737 }
738
739 output_cursor = calloc(1, sizeof(struct wlr_cursor_output_cursor));
740 if (output_cursor == NULL) {
741 wlr_log(WLR_ERROR, "Failed to allocate wlr_cursor_output_cursor");
742 return;
743 }
744 output_cursor->cursor = state->cursor;
745
746 output_cursor->output_cursor = wlr_output_cursor_create(l_output->output);
747 if (output_cursor->output_cursor == NULL) {
748 wlr_log(WLR_ERROR, "Failed to create wlr_output_cursor");
749 free(output_cursor);
750 return;
751 }
752
753 output_cursor->layout_output_destroy.notify = handle_layout_output_destroy;
754 wl_signal_add(&l_output->events.destroy,
755 &output_cursor->layout_output_destroy);
756
757 wl_list_insert(&state->output_cursors, &output_cursor->link);
758 }
759
handle_layout_add(struct wl_listener * listener,void * data)760 static void handle_layout_add(struct wl_listener *listener, void *data) {
761 struct wlr_cursor_state *state =
762 wl_container_of(listener, state, layout_add);
763 struct wlr_output_layout_output *l_output = data;
764 layout_add(state, l_output);
765 }
766
handle_layout_change(struct wl_listener * listener,void * data)767 static void handle_layout_change(struct wl_listener *listener, void *data) {
768 struct wlr_cursor_state *state =
769 wl_container_of(listener, state, layout_change);
770 struct wlr_output_layout *layout = data;
771
772 if (!wlr_output_layout_contains_point(layout, NULL, state->cursor->x,
773 state->cursor->y)) {
774 // the output we were on has gone away so go to the closest boundary
775 // point
776 double x, y;
777 wlr_output_layout_closest_point(layout, NULL, state->cursor->x,
778 state->cursor->y, &x, &y);
779
780 cursor_warp_unchecked(state->cursor, x, y);
781 }
782 }
783
wlr_cursor_attach_output_layout(struct wlr_cursor * cur,struct wlr_output_layout * l)784 void wlr_cursor_attach_output_layout(struct wlr_cursor *cur,
785 struct wlr_output_layout *l) {
786 cursor_detach_output_layout(cur);
787
788 if (l == NULL) {
789 return;
790 }
791
792 wl_signal_add(&l->events.add, &cur->state->layout_add);
793 cur->state->layout_add.notify = handle_layout_add;
794 wl_signal_add(&l->events.change, &cur->state->layout_change);
795 cur->state->layout_change.notify = handle_layout_change;
796 wl_signal_add(&l->events.destroy, &cur->state->layout_destroy);
797 cur->state->layout_destroy.notify = handle_layout_destroy;
798
799 cur->state->layout = l;
800
801 struct wlr_output_layout_output *l_output;
802 wl_list_for_each(l_output, &l->outputs, link) {
803 layout_add(cur->state, l_output);
804 }
805 }
806
wlr_cursor_map_to_output(struct wlr_cursor * cur,struct wlr_output * output)807 void wlr_cursor_map_to_output(struct wlr_cursor *cur,
808 struct wlr_output *output) {
809 cur->state->mapped_output = output;
810 }
811
wlr_cursor_map_input_to_output(struct wlr_cursor * cur,struct wlr_input_device * dev,struct wlr_output * output)812 void wlr_cursor_map_input_to_output(struct wlr_cursor *cur,
813 struct wlr_input_device *dev, struct wlr_output *output) {
814 struct wlr_cursor_device *c_device = get_cursor_device(cur, dev);
815 if (!c_device) {
816 wlr_log(WLR_ERROR, "Cannot map device \"%s\" to output"
817 "(not found in this cursor)", dev->name);
818 return;
819 }
820
821 c_device->mapped_output = output;
822 }
823
wlr_cursor_map_to_region(struct wlr_cursor * cur,struct wlr_box * box)824 void wlr_cursor_map_to_region(struct wlr_cursor *cur,
825 struct wlr_box *box) {
826 if (box && wlr_box_empty(box)) {
827 wlr_log(WLR_ERROR, "cannot map cursor to an empty region");
828 return;
829 }
830
831 cur->state->mapped_box = box;
832 }
833
wlr_cursor_map_input_to_region(struct wlr_cursor * cur,struct wlr_input_device * dev,struct wlr_box * box)834 void wlr_cursor_map_input_to_region(struct wlr_cursor *cur,
835 struct wlr_input_device *dev, struct wlr_box *box) {
836 if (box && wlr_box_empty(box)) {
837 wlr_log(WLR_ERROR, "cannot map device \"%s\" input to an empty region",
838 dev->name);
839 return;
840 }
841
842 struct wlr_cursor_device *c_device = get_cursor_device(cur, dev);
843 if (!c_device) {
844 wlr_log(WLR_ERROR, "Cannot map device \"%s\" to geometry (not found in"
845 "this cursor)", dev->name);
846 return;
847 }
848
849 c_device->mapped_box = box;
850 }
851