1 #define _POSIX_C_SOURCE 200809L
2 #include <assert.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <time.h>
6 #include <wayland-server-core.h>
7 #include <wlr/types/wlr_input_device.h>
8 #include <wlr/util/log.h>
9 #include "types/wlr_seat.h"
10 #include "util/signal.h"
11 #include "util/array.h"
12
default_pointer_enter(struct wlr_seat_pointer_grab * grab,struct wlr_surface * surface,double sx,double sy)13 static void default_pointer_enter(struct wlr_seat_pointer_grab *grab,
14 struct wlr_surface *surface, double sx, double sy) {
15 wlr_seat_pointer_enter(grab->seat, surface, sx, sy);
16 }
17
default_pointer_clear_focus(struct wlr_seat_pointer_grab * grab)18 static void default_pointer_clear_focus(struct wlr_seat_pointer_grab *grab) {
19 wlr_seat_pointer_clear_focus(grab->seat);
20 }
21
default_pointer_motion(struct wlr_seat_pointer_grab * grab,uint32_t time,double sx,double sy)22 static void default_pointer_motion(struct wlr_seat_pointer_grab *grab,
23 uint32_t time, double sx, double sy) {
24 wlr_seat_pointer_send_motion(grab->seat, time, sx, sy);
25 }
26
default_pointer_button(struct wlr_seat_pointer_grab * grab,uint32_t time,uint32_t button,enum wlr_button_state state)27 static uint32_t default_pointer_button(struct wlr_seat_pointer_grab *grab,
28 uint32_t time, uint32_t button, enum wlr_button_state state) {
29 return wlr_seat_pointer_send_button(grab->seat, time, button, state);
30 }
31
default_pointer_axis(struct wlr_seat_pointer_grab * grab,uint32_t time,enum wlr_axis_orientation orientation,double value,int32_t value_discrete,enum wlr_axis_source source)32 static void default_pointer_axis(struct wlr_seat_pointer_grab *grab,
33 uint32_t time, enum wlr_axis_orientation orientation, double value,
34 int32_t value_discrete, enum wlr_axis_source source) {
35 wlr_seat_pointer_send_axis(grab->seat, time, orientation, value,
36 value_discrete, source);
37 }
38
default_pointer_frame(struct wlr_seat_pointer_grab * grab)39 static void default_pointer_frame(struct wlr_seat_pointer_grab *grab) {
40 wlr_seat_pointer_send_frame(grab->seat);
41 }
42
default_pointer_cancel(struct wlr_seat_pointer_grab * grab)43 static void default_pointer_cancel(struct wlr_seat_pointer_grab *grab) {
44 // cannot be cancelled
45 }
46
47 const struct wlr_pointer_grab_interface default_pointer_grab_impl = {
48 .enter = default_pointer_enter,
49 .clear_focus = default_pointer_clear_focus,
50 .motion = default_pointer_motion,
51 .button = default_pointer_button,
52 .axis = default_pointer_axis,
53 .frame = default_pointer_frame,
54 .cancel = default_pointer_cancel,
55 };
56
57
pointer_send_frame(struct wl_resource * resource)58 static void pointer_send_frame(struct wl_resource *resource) {
59 if (wl_resource_get_version(resource) >=
60 WL_POINTER_FRAME_SINCE_VERSION) {
61 wl_pointer_send_frame(resource);
62 }
63 }
64
65 static const struct wl_pointer_interface pointer_impl;
66
wlr_seat_client_from_pointer_resource(struct wl_resource * resource)67 struct wlr_seat_client *wlr_seat_client_from_pointer_resource(
68 struct wl_resource *resource) {
69 assert(wl_resource_instance_of(resource, &wl_pointer_interface,
70 &pointer_impl));
71 return wl_resource_get_user_data(resource);
72 }
73
74 static const struct wlr_surface_role pointer_cursor_surface_role = {
75 .name = "wl_pointer-cursor",
76 };
77
pointer_set_cursor(struct wl_client * client,struct wl_resource * pointer_resource,uint32_t serial,struct wl_resource * surface_resource,int32_t hotspot_x,int32_t hotspot_y)78 static void pointer_set_cursor(struct wl_client *client,
79 struct wl_resource *pointer_resource, uint32_t serial,
80 struct wl_resource *surface_resource,
81 int32_t hotspot_x, int32_t hotspot_y) {
82 struct wlr_seat_client *seat_client =
83 wlr_seat_client_from_pointer_resource(pointer_resource);
84 if (seat_client == NULL) {
85 return;
86 }
87
88 struct wlr_surface *surface = NULL;
89 if (surface_resource != NULL) {
90 surface = wlr_surface_from_resource(surface_resource);
91 if (!wlr_surface_set_role(surface, &pointer_cursor_surface_role, NULL,
92 surface_resource, WL_POINTER_ERROR_ROLE)) {
93 return;
94 }
95 }
96
97 struct wlr_seat_pointer_request_set_cursor_event event = {
98 .seat_client = seat_client,
99 .surface = surface,
100 .serial = serial,
101 .hotspot_x = hotspot_x,
102 .hotspot_y = hotspot_y,
103 };
104 wlr_signal_emit_safe(&seat_client->seat->events.request_set_cursor, &event);
105 }
106
pointer_release(struct wl_client * client,struct wl_resource * resource)107 static void pointer_release(struct wl_client *client,
108 struct wl_resource *resource) {
109 wl_resource_destroy(resource);
110 }
111
112 static const struct wl_pointer_interface pointer_impl = {
113 .set_cursor = pointer_set_cursor,
114 .release = pointer_release,
115 };
116
pointer_handle_resource_destroy(struct wl_resource * resource)117 static void pointer_handle_resource_destroy(struct wl_resource *resource) {
118 wl_list_remove(wl_resource_get_link(resource));
119 seat_client_destroy_pointer(resource);
120 }
121
122
wlr_seat_pointer_surface_has_focus(struct wlr_seat * wlr_seat,struct wlr_surface * surface)123 bool wlr_seat_pointer_surface_has_focus(struct wlr_seat *wlr_seat,
124 struct wlr_surface *surface) {
125 return surface == wlr_seat->pointer_state.focused_surface;
126 }
127
seat_pointer_handle_surface_destroy(struct wl_listener * listener,void * data)128 static void seat_pointer_handle_surface_destroy(struct wl_listener *listener,
129 void *data) {
130 struct wlr_seat_pointer_state *state =
131 wl_container_of(listener, state, surface_destroy);
132 wl_list_remove(&state->surface_destroy.link);
133 wl_list_init(&state->surface_destroy.link);
134 wlr_seat_pointer_clear_focus(state->seat);
135 }
136
seat_client_send_pointer_leave_raw(struct wlr_seat_client * seat_client,struct wlr_surface * surface)137 void seat_client_send_pointer_leave_raw(struct wlr_seat_client *seat_client,
138 struct wlr_surface *surface) {
139 uint32_t serial = wlr_seat_client_next_serial(seat_client);
140 struct wl_resource *resource;
141 wl_resource_for_each(resource, &seat_client->pointers) {
142 if (wlr_seat_client_from_pointer_resource(resource) == NULL) {
143 continue;
144 }
145
146 wl_pointer_send_leave(resource, serial, surface->resource);
147 pointer_send_frame(resource);
148 }
149 }
150
wlr_seat_pointer_enter(struct wlr_seat * wlr_seat,struct wlr_surface * surface,double sx,double sy)151 void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat,
152 struct wlr_surface *surface, double sx, double sy) {
153 if (wlr_seat->pointer_state.focused_surface == surface) {
154 // this surface already got an enter notify
155 return;
156 }
157
158 struct wlr_seat_client *client = NULL;
159 if (surface) {
160 struct wl_client *wl_client = wl_resource_get_client(surface->resource);
161 client = wlr_seat_client_for_wl_client(wlr_seat, wl_client);
162 }
163
164 struct wlr_seat_client *focused_client =
165 wlr_seat->pointer_state.focused_client;
166 struct wlr_surface *focused_surface =
167 wlr_seat->pointer_state.focused_surface;
168
169 // leave the previously entered surface
170 if (focused_client != NULL && focused_surface != NULL) {
171 seat_client_send_pointer_leave_raw(focused_client, focused_surface);
172 }
173
174 // enter the current surface
175 if (client != NULL && surface != NULL) {
176 uint32_t serial = wlr_seat_client_next_serial(client);
177 struct wl_resource *resource;
178 wl_resource_for_each(resource, &client->pointers) {
179 if (wlr_seat_client_from_pointer_resource(resource) == NULL) {
180 continue;
181 }
182
183 wl_pointer_send_enter(resource, serial, surface->resource,
184 wl_fixed_from_double(sx), wl_fixed_from_double(sy));
185 pointer_send_frame(resource);
186 }
187 }
188
189 // reinitialize the focus destroy events
190 wl_list_remove(&wlr_seat->pointer_state.surface_destroy.link);
191 wl_list_init(&wlr_seat->pointer_state.surface_destroy.link);
192 if (surface != NULL) {
193 wl_signal_add(&surface->events.destroy,
194 &wlr_seat->pointer_state.surface_destroy);
195 wlr_seat->pointer_state.surface_destroy.notify =
196 seat_pointer_handle_surface_destroy;
197 }
198
199 wlr_seat->pointer_state.focused_client = client;
200 wlr_seat->pointer_state.focused_surface = surface;
201 if (surface != NULL) {
202 wlr_seat_pointer_warp(wlr_seat, sx, sy);
203 } else {
204 wlr_seat_pointer_warp(wlr_seat, NAN, NAN);
205 }
206
207 struct wlr_seat_pointer_focus_change_event event = {
208 .seat = wlr_seat,
209 .new_surface = surface,
210 .old_surface = focused_surface,
211 .sx = sx,
212 .sy = sy,
213 };
214 wlr_signal_emit_safe(&wlr_seat->pointer_state.events.focus_change, &event);
215 }
216
wlr_seat_pointer_clear_focus(struct wlr_seat * wlr_seat)217 void wlr_seat_pointer_clear_focus(struct wlr_seat *wlr_seat) {
218 wlr_seat_pointer_enter(wlr_seat, NULL, 0, 0);
219 }
220
wlr_seat_pointer_warp(struct wlr_seat * wlr_seat,double sx,double sy)221 void wlr_seat_pointer_warp(struct wlr_seat *wlr_seat, double sx, double sy) {
222 wlr_seat->pointer_state.sx = sx;
223 wlr_seat->pointer_state.sy = sy;
224 }
225
wlr_seat_pointer_send_motion(struct wlr_seat * wlr_seat,uint32_t time,double sx,double sy)226 void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time,
227 double sx, double sy) {
228 struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
229 if (client == NULL) {
230 return;
231 }
232
233 if (wlr_seat->pointer_state.sx == sx && wlr_seat->pointer_state.sy == sy) {
234 return;
235 }
236
237 struct wl_resource *resource;
238 wl_resource_for_each(resource, &client->pointers) {
239 if (wlr_seat_client_from_pointer_resource(resource) == NULL) {
240 continue;
241 }
242
243 wl_pointer_send_motion(resource, time, wl_fixed_from_double(sx),
244 wl_fixed_from_double(sy));
245 }
246
247 wlr_seat_pointer_warp(wlr_seat, sx, sy);
248 }
249
wlr_seat_pointer_send_button(struct wlr_seat * wlr_seat,uint32_t time,uint32_t button,enum wlr_button_state state)250 uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time,
251 uint32_t button, enum wlr_button_state state) {
252 struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
253 if (client == NULL) {
254 return 0;
255 }
256
257 uint32_t serial = wlr_seat_client_next_serial(client);
258 struct wl_resource *resource;
259 wl_resource_for_each(resource, &client->pointers) {
260 if (wlr_seat_client_from_pointer_resource(resource) == NULL) {
261 continue;
262 }
263
264 wl_pointer_send_button(resource, serial, time, button, state);
265 }
266 return serial;
267 }
268
wlr_seat_pointer_send_axis(struct wlr_seat * wlr_seat,uint32_t time,enum wlr_axis_orientation orientation,double value,int32_t value_discrete,enum wlr_axis_source source)269 void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time,
270 enum wlr_axis_orientation orientation, double value,
271 int32_t value_discrete, enum wlr_axis_source source) {
272 struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
273 if (client == NULL) {
274 return;
275 }
276
277 struct wl_resource *resource;
278 wl_resource_for_each(resource, &client->pointers) {
279 if (wlr_seat_client_from_pointer_resource(resource) == NULL) {
280 continue;
281 }
282
283 uint32_t version = wl_resource_get_version(resource);
284
285 if (version >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION) {
286 wl_pointer_send_axis_source(resource, source);
287 }
288 if (value) {
289 if (value_discrete &&
290 version >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION) {
291 wl_pointer_send_axis_discrete(resource, orientation,
292 value_discrete);
293 }
294
295 wl_pointer_send_axis(resource, time, orientation,
296 wl_fixed_from_double(value));
297 } else if (version >= WL_POINTER_AXIS_STOP_SINCE_VERSION) {
298 wl_pointer_send_axis_stop(resource, time, orientation);
299 }
300 }
301 }
302
wlr_seat_pointer_send_frame(struct wlr_seat * wlr_seat)303 void wlr_seat_pointer_send_frame(struct wlr_seat *wlr_seat) {
304 struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
305 if (client == NULL) {
306 return;
307 }
308
309 struct wl_resource *resource;
310 wl_resource_for_each(resource, &client->pointers) {
311 if (wlr_seat_client_from_pointer_resource(resource) == NULL) {
312 continue;
313 }
314
315 pointer_send_frame(resource);
316 }
317 }
318
wlr_seat_pointer_start_grab(struct wlr_seat * wlr_seat,struct wlr_seat_pointer_grab * grab)319 void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat,
320 struct wlr_seat_pointer_grab *grab) {
321 assert(wlr_seat);
322 grab->seat = wlr_seat;
323 wlr_seat->pointer_state.grab = grab;
324
325 wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_begin, grab);
326 }
327
wlr_seat_pointer_end_grab(struct wlr_seat * wlr_seat)328 void wlr_seat_pointer_end_grab(struct wlr_seat *wlr_seat) {
329 struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
330 if (grab != wlr_seat->pointer_state.default_grab) {
331 wlr_seat->pointer_state.grab = wlr_seat->pointer_state.default_grab;
332 wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_end, grab);
333 if (grab->interface->cancel) {
334 grab->interface->cancel(grab);
335 }
336 }
337 }
338
wlr_seat_pointer_notify_enter(struct wlr_seat * wlr_seat,struct wlr_surface * surface,double sx,double sy)339 void wlr_seat_pointer_notify_enter(struct wlr_seat *wlr_seat,
340 struct wlr_surface *surface, double sx, double sy) {
341 // NULL surfaces are prohibited in the grab-compatible API. Use
342 // wlr_seat_pointer_notify_clear_focus() instead.
343 assert(surface);
344 struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
345 grab->interface->enter(grab, surface, sx, sy);
346 }
347
wlr_seat_pointer_notify_clear_focus(struct wlr_seat * wlr_seat)348 void wlr_seat_pointer_notify_clear_focus(struct wlr_seat *wlr_seat) {
349 struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
350 grab->interface->clear_focus(grab);
351 }
352
wlr_seat_pointer_notify_motion(struct wlr_seat * wlr_seat,uint32_t time,double sx,double sy)353 void wlr_seat_pointer_notify_motion(struct wlr_seat *wlr_seat, uint32_t time,
354 double sx, double sy) {
355 clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
356 struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
357 grab->interface->motion(grab, time, sx, sy);
358 }
359
wlr_seat_pointer_notify_button(struct wlr_seat * wlr_seat,uint32_t time,uint32_t button,enum wlr_button_state state)360 uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat,
361 uint32_t time, uint32_t button, enum wlr_button_state state) {
362 clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
363
364 struct wlr_seat_pointer_state* pointer_state = &wlr_seat->pointer_state;
365
366 if (state == WLR_BUTTON_PRESSED) {
367 if (pointer_state->button_count == 0) {
368 pointer_state->grab_button = button;
369 pointer_state->grab_time = time;
370 }
371 set_add(pointer_state->buttons, &pointer_state->button_count,
372 WLR_POINTER_BUTTONS_CAP, button);
373 } else {
374 set_remove(pointer_state->buttons, &pointer_state->button_count,
375 WLR_POINTER_BUTTONS_CAP, button);
376 }
377
378
379 struct wlr_seat_pointer_grab *grab = pointer_state->grab;
380 uint32_t serial = grab->interface->button(grab, time, button, state);
381
382 wlr_log(WLR_DEBUG, "button_count=%zu grab_serial=%"PRIu32" serial=%"PRIu32"",
383 pointer_state->button_count,
384 pointer_state->grab_serial, serial);
385
386 if (serial && pointer_state->button_count == 1 &&
387 state == WLR_BUTTON_PRESSED) {
388 pointer_state->grab_serial = serial;
389 }
390
391 return serial;
392 }
393
wlr_seat_pointer_notify_axis(struct wlr_seat * wlr_seat,uint32_t time,enum wlr_axis_orientation orientation,double value,int32_t value_discrete,enum wlr_axis_source source)394 void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time,
395 enum wlr_axis_orientation orientation, double value,
396 int32_t value_discrete, enum wlr_axis_source source) {
397 clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
398 struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
399 grab->interface->axis(grab, time, orientation, value, value_discrete,
400 source);
401 }
402
wlr_seat_pointer_notify_frame(struct wlr_seat * wlr_seat)403 void wlr_seat_pointer_notify_frame(struct wlr_seat *wlr_seat) {
404 clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
405 struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
406 if (grab->interface->frame) {
407 grab->interface->frame(grab);
408 }
409 }
410
wlr_seat_pointer_has_grab(struct wlr_seat * seat)411 bool wlr_seat_pointer_has_grab(struct wlr_seat *seat) {
412 return seat->pointer_state.grab->interface != &default_pointer_grab_impl;
413 }
414
415
seat_client_create_pointer(struct wlr_seat_client * seat_client,uint32_t version,uint32_t id)416 void seat_client_create_pointer(struct wlr_seat_client *seat_client,
417 uint32_t version, uint32_t id) {
418 struct wl_resource *resource = wl_resource_create(seat_client->client,
419 &wl_pointer_interface, version, id);
420 if (resource == NULL) {
421 wl_client_post_no_memory(seat_client->client);
422 return;
423 }
424 wl_resource_set_implementation(resource, &pointer_impl, seat_client,
425 &pointer_handle_resource_destroy);
426 wl_list_insert(&seat_client->pointers, wl_resource_get_link(resource));
427
428 if ((seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER) == 0) {
429 wl_resource_set_user_data(resource, NULL);
430 return;
431 }
432
433 struct wlr_seat_client *focused_client =
434 seat_client->seat->pointer_state.focused_client;
435 struct wlr_surface *focused_surface =
436 seat_client->seat->pointer_state.focused_surface;
437
438 // Send an enter event if there is a focused client/surface stored
439 if (focused_client != NULL && focused_surface != NULL) {
440 double sx = seat_client->seat->pointer_state.sx;
441 double sy = seat_client->seat->pointer_state.sy;
442
443 uint32_t serial = wlr_seat_client_next_serial(focused_client);
444 struct wl_resource *resource;
445 wl_resource_for_each(resource, &focused_client->pointers) {
446 if (wl_resource_get_id(resource) == id) {
447 if (wlr_seat_client_from_pointer_resource(resource) == NULL) {
448 continue;
449 }
450
451 wl_pointer_send_enter(resource, serial, focused_surface->resource,
452 wl_fixed_from_double(sx), wl_fixed_from_double(sy));
453 pointer_send_frame(resource);
454 }
455 }
456 }
457 }
458
seat_client_destroy_pointer(struct wl_resource * resource)459 void seat_client_destroy_pointer(struct wl_resource *resource) {
460 struct wlr_seat_client *seat_client =
461 wlr_seat_client_from_pointer_resource(resource);
462 if (seat_client == NULL) {
463 return;
464 }
465 wl_resource_set_user_data(resource, NULL);
466 }
467
wlr_seat_validate_pointer_grab_serial(struct wlr_seat * seat,struct wlr_surface * origin,uint32_t serial)468 bool wlr_seat_validate_pointer_grab_serial(struct wlr_seat *seat,
469 struct wlr_surface *origin, uint32_t serial) {
470 if (seat->pointer_state.button_count != 1 ||
471 seat->pointer_state.grab_serial != serial) {
472 wlr_log(WLR_DEBUG, "Pointer grab serial validation failed: "
473 "button_count=%zu grab_serial=%"PRIu32" (got %"PRIu32")",
474 seat->pointer_state.button_count,
475 seat->pointer_state.grab_serial, serial);
476 return false;
477 }
478
479 if (origin != NULL && seat->pointer_state.focused_surface != origin) {
480 wlr_log(WLR_DEBUG, "Pointer grab serial validation failed: "
481 "invalid origin surface");
482 return false;
483 }
484
485 return true;
486 }
487