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