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_data_device.h>
8 #include <wlr/types/wlr_input_device.h>
9 #include <wlr/types/wlr_primary_selection.h>
10 #include <wlr/types/wlr_seat.h>
11 #include <wlr/util/log.h>
12 #include "types/wlr_seat.h"
13 #include "util/global.h"
14 #include "util/signal.h"
15 
16 #define SEAT_VERSION 7
17 
seat_handle_get_pointer(struct wl_client * client,struct wl_resource * seat_resource,uint32_t id)18 static void seat_handle_get_pointer(struct wl_client *client,
19 		struct wl_resource *seat_resource, uint32_t id) {
20 	struct wlr_seat_client *seat_client =
21 		wlr_seat_client_from_resource(seat_resource);
22 	if (!(seat_client->seat->accumulated_capabilities & WL_SEAT_CAPABILITY_POINTER)) {
23 		wl_resource_post_error(seat_resource, 0,
24 				"wl_seat.get_pointer called when no pointer capability has existed");
25 		return;
26 	}
27 
28 	uint32_t version = wl_resource_get_version(seat_resource);
29 	seat_client_create_pointer(seat_client, version, id);
30 }
31 
seat_handle_get_keyboard(struct wl_client * client,struct wl_resource * seat_resource,uint32_t id)32 static void seat_handle_get_keyboard(struct wl_client *client,
33 		struct wl_resource *seat_resource, uint32_t id) {
34 	struct wlr_seat_client *seat_client =
35 		wlr_seat_client_from_resource(seat_resource);
36 	if (!(seat_client->seat->accumulated_capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) {
37 		wl_resource_post_error(seat_resource, 0,
38 				"wl_seat.get_keyboard called when no keyboard capability has existed");
39 		return;
40 	}
41 
42 	uint32_t version = wl_resource_get_version(seat_resource);
43 	seat_client_create_keyboard(seat_client, version, id);
44 }
45 
seat_handle_get_touch(struct wl_client * client,struct wl_resource * seat_resource,uint32_t id)46 static void seat_handle_get_touch(struct wl_client *client,
47 		struct wl_resource *seat_resource, uint32_t id) {
48 	struct wlr_seat_client *seat_client =
49 		wlr_seat_client_from_resource(seat_resource);
50 	if (!(seat_client->seat->accumulated_capabilities & WL_SEAT_CAPABILITY_TOUCH)) {
51 		wl_resource_post_error(seat_resource, 0,
52 				"wl_seat.get_touch called when no touch capability has existed");
53 		return;
54 	}
55 
56 	uint32_t version = wl_resource_get_version(seat_resource);
57 	seat_client_create_touch(seat_client, version, id);
58 }
59 
seat_client_handle_resource_destroy(struct wl_resource * seat_resource)60 static void seat_client_handle_resource_destroy(
61 		struct wl_resource *seat_resource) {
62 	struct wlr_seat_client *client =
63 		wlr_seat_client_from_resource(seat_resource);
64 
65 	wl_list_remove(wl_resource_get_link(seat_resource));
66 	if (!wl_list_empty(&client->resources)) {
67 		return;
68 	}
69 
70 	wlr_signal_emit_safe(&client->events.destroy, client);
71 
72 	if (client == client->seat->pointer_state.focused_client) {
73 		client->seat->pointer_state.focused_client = NULL;
74 	}
75 	if (client == client->seat->keyboard_state.focused_client) {
76 		client->seat->keyboard_state.focused_client = NULL;
77 	}
78 
79 	struct wl_resource *resource, *tmp;
80 	wl_resource_for_each_safe(resource, tmp, &client->pointers) {
81 		wl_resource_destroy(resource);
82 	}
83 	wl_resource_for_each_safe(resource, tmp, &client->keyboards) {
84 		wl_resource_destroy(resource);
85 	}
86 	wl_resource_for_each_safe(resource, tmp, &client->touches) {
87 		wl_resource_destroy(resource);
88 	}
89 	wl_resource_for_each_safe(resource, tmp, &client->data_devices) {
90 		// Make the data device inert
91 		wl_resource_set_user_data(resource, NULL);
92 
93 		struct wl_list *link = wl_resource_get_link(resource);
94 		wl_list_remove(link);
95 		wl_list_init(link);
96 	}
97 
98 	wl_list_remove(&client->link);
99 	free(client);
100 }
101 
seat_handle_release(struct wl_client * client,struct wl_resource * resource)102 static void seat_handle_release(struct wl_client *client,
103 		struct wl_resource *resource) {
104 	wl_resource_destroy(resource);
105 }
106 
107 static const struct wl_seat_interface seat_impl = {
108 	.get_pointer = seat_handle_get_pointer,
109 	.get_keyboard = seat_handle_get_keyboard,
110 	.get_touch = seat_handle_get_touch,
111 	.release = seat_handle_release,
112 };
113 
seat_handle_bind(struct wl_client * client,void * _wlr_seat,uint32_t version,uint32_t id)114 static void seat_handle_bind(struct wl_client *client, void *_wlr_seat,
115 		uint32_t version, uint32_t id) {
116 	struct wlr_seat *wlr_seat = _wlr_seat;
117 	assert(client && wlr_seat);
118 
119 	struct wl_resource *wl_resource =
120 		wl_resource_create(client, &wl_seat_interface, version, id);
121 	if (wl_resource == NULL) {
122 		wl_client_post_no_memory(client);
123 		return;
124 	}
125 
126 	struct wlr_seat_client *seat_client =
127 		wlr_seat_client_for_wl_client(wlr_seat, client);
128 	if (seat_client == NULL) {
129 		seat_client = calloc(1, sizeof(struct wlr_seat_client));
130 		if (seat_client == NULL) {
131 			wl_resource_destroy(wl_resource);
132 			wl_client_post_no_memory(client);
133 			return;
134 		}
135 
136 		seat_client->client = client;
137 		seat_client->seat = wlr_seat;
138 		wl_list_init(&seat_client->resources);
139 		wl_list_init(&seat_client->pointers);
140 		wl_list_init(&seat_client->keyboards);
141 		wl_list_init(&seat_client->touches);
142 		wl_list_init(&seat_client->data_devices);
143 		wl_signal_init(&seat_client->events.destroy);
144 
145 		wl_list_insert(&wlr_seat->clients, &seat_client->link);
146 	}
147 
148 	wl_resource_set_implementation(wl_resource, &seat_impl,
149 		seat_client, seat_client_handle_resource_destroy);
150 	wl_list_insert(&seat_client->resources, wl_resource_get_link(wl_resource));
151 	if (version >= WL_SEAT_NAME_SINCE_VERSION) {
152 		wl_seat_send_name(wl_resource, wlr_seat->name);
153 	}
154 	wl_seat_send_capabilities(wl_resource, wlr_seat->capabilities);
155 }
156 
wlr_seat_destroy(struct wlr_seat * seat)157 void wlr_seat_destroy(struct wlr_seat *seat) {
158 	if (!seat) {
159 		return;
160 	}
161 
162 	wlr_signal_emit_safe(&seat->events.destroy, seat);
163 
164 	wl_list_remove(&seat->display_destroy.link);
165 
166 	wlr_data_source_destroy(seat->selection_source);
167 	wlr_primary_selection_source_destroy(seat->primary_selection_source);
168 
169 	struct wlr_seat_client *client, *tmp;
170 	wl_list_for_each_safe(client, tmp, &seat->clients, link) {
171 		struct wl_resource *resource, *next;
172 		/* wl_resource_for_each_safe isn't safe to use here, because the last
173 		 * wl_resource_destroy will also destroy the head we cannot do the last
174 		 * 'next' update that usually is harmless here.
175 		 * Work around this by breaking one step ahead
176 		 */
177 		wl_resource_for_each_safe(resource, next, &client->resources) {
178 			// will destroy other resources as well
179 			wl_resource_destroy(resource);
180 			if (wl_resource_get_link(next) == &client->resources) {
181 				break;
182 			}
183 		}
184 	}
185 
186 	wlr_global_destroy_safe(seat->global, seat->display);
187 	free(seat->pointer_state.default_grab);
188 	free(seat->keyboard_state.default_grab);
189 	free(seat->touch_state.default_grab);
190 	free(seat->name);
191 	free(seat);
192 }
193 
handle_display_destroy(struct wl_listener * listener,void * data)194 static void handle_display_destroy(struct wl_listener *listener, void *data) {
195 	struct wlr_seat *seat =
196 		wl_container_of(listener, seat, display_destroy);
197 	wlr_seat_destroy(seat);
198 }
199 
wlr_seat_create(struct wl_display * display,const char * name)200 struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) {
201 	struct wlr_seat *seat = calloc(1, sizeof(struct wlr_seat));
202 	if (!seat) {
203 		return NULL;
204 	}
205 
206 	// pointer state
207 	seat->pointer_state.seat = seat;
208 	wl_list_init(&seat->pointer_state.surface_destroy.link);
209 
210 	struct wlr_seat_pointer_grab *pointer_grab =
211 		calloc(1, sizeof(struct wlr_seat_pointer_grab));
212 	if (!pointer_grab) {
213 		free(seat);
214 		return NULL;
215 	}
216 	pointer_grab->interface = &default_pointer_grab_impl;
217 	pointer_grab->seat = seat;
218 	seat->pointer_state.default_grab = pointer_grab;
219 	seat->pointer_state.grab = pointer_grab;
220 
221 	wl_signal_init(&seat->pointer_state.events.focus_change);
222 
223 	// keyboard state
224 	struct wlr_seat_keyboard_grab *keyboard_grab =
225 		calloc(1, sizeof(struct wlr_seat_keyboard_grab));
226 	if (!keyboard_grab) {
227 		free(pointer_grab);
228 		free(seat);
229 		return NULL;
230 	}
231 	keyboard_grab->interface = &default_keyboard_grab_impl;
232 	keyboard_grab->seat = seat;
233 	seat->keyboard_state.default_grab = keyboard_grab;
234 	seat->keyboard_state.grab = keyboard_grab;
235 
236 	seat->keyboard_state.seat = seat;
237 	wl_list_init(&seat->keyboard_state.surface_destroy.link);
238 
239 	wl_signal_init(&seat->keyboard_state.events.focus_change);
240 
241 	// touch state
242 	struct wlr_seat_touch_grab *touch_grab =
243 		calloc(1, sizeof(struct wlr_seat_touch_grab));
244 	if (!touch_grab) {
245 		free(pointer_grab);
246 		free(keyboard_grab);
247 		free(seat);
248 		return NULL;
249 	}
250 	touch_grab->interface = &default_touch_grab_impl;
251 	touch_grab->seat = seat;
252 	seat->touch_state.default_grab = touch_grab;
253 	seat->touch_state.grab = touch_grab;
254 
255 	seat->touch_state.seat = seat;
256 	wl_list_init(&seat->touch_state.touch_points);
257 
258 	seat->global = wl_global_create(display, &wl_seat_interface,
259 		SEAT_VERSION, seat, seat_handle_bind);
260 	if (seat->global == NULL) {
261 		free(touch_grab);
262 		free(pointer_grab);
263 		free(keyboard_grab);
264 		free(seat);
265 		return NULL;
266 	}
267 	seat->display = display;
268 	seat->name = strdup(name);
269 	wl_list_init(&seat->clients);
270 	wl_list_init(&seat->selection_offers);
271 	wl_list_init(&seat->drag_offers);
272 
273 	wl_signal_init(&seat->events.request_start_drag);
274 	wl_signal_init(&seat->events.start_drag);
275 
276 	wl_signal_init(&seat->events.request_set_cursor);
277 
278 	wl_signal_init(&seat->events.request_set_selection);
279 	wl_signal_init(&seat->events.set_selection);
280 	wl_signal_init(&seat->events.request_set_primary_selection);
281 	wl_signal_init(&seat->events.set_primary_selection);
282 
283 	wl_signal_init(&seat->events.pointer_grab_begin);
284 	wl_signal_init(&seat->events.pointer_grab_end);
285 
286 	wl_signal_init(&seat->events.keyboard_grab_begin);
287 	wl_signal_init(&seat->events.keyboard_grab_end);
288 
289 	wl_signal_init(&seat->events.touch_grab_begin);
290 	wl_signal_init(&seat->events.touch_grab_end);
291 
292 	wl_signal_init(&seat->events.destroy);
293 
294 	seat->display_destroy.notify = handle_display_destroy;
295 	wl_display_add_destroy_listener(display, &seat->display_destroy);
296 
297 	return seat;
298 }
299 
wlr_seat_client_for_wl_client(struct wlr_seat * wlr_seat,struct wl_client * wl_client)300 struct wlr_seat_client *wlr_seat_client_for_wl_client(struct wlr_seat *wlr_seat,
301 		struct wl_client *wl_client) {
302 	struct wlr_seat_client *seat_client;
303 	wl_list_for_each(seat_client, &wlr_seat->clients, link) {
304 		if (seat_client->client == wl_client) {
305 			return seat_client;
306 		}
307 	}
308 	return NULL;
309 }
310 
wlr_seat_set_capabilities(struct wlr_seat * wlr_seat,uint32_t capabilities)311 void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat,
312 		uint32_t capabilities) {
313 	// if the capabilities haven't changed (i.e a redundant mouse was removed),
314 	// we don't actually have to do anything
315 	if (capabilities == wlr_seat->capabilities) {
316 		return;
317 	}
318 	wlr_seat->capabilities = capabilities;
319 	wlr_seat->accumulated_capabilities |= capabilities;
320 
321 	struct wlr_seat_client *client;
322 	wl_list_for_each(client, &wlr_seat->clients, link) {
323 		// Make resources inert if necessary
324 		if ((capabilities & WL_SEAT_CAPABILITY_POINTER) == 0) {
325 			struct wlr_seat_client *focused_client =
326 				wlr_seat->pointer_state.focused_client;
327 			struct wlr_surface *focused_surface =
328 				wlr_seat->pointer_state.focused_surface;
329 
330 			if (focused_client != NULL && focused_surface != NULL) {
331 				seat_client_send_pointer_leave_raw(focused_client, focused_surface);
332 			}
333 
334 			// Note: we don't set focused client/surface to NULL since we need
335 			// them to send the enter event if the pointer is recreated
336 
337 			struct wl_resource *resource, *tmp;
338 			wl_resource_for_each_safe(resource, tmp, &client->pointers) {
339 				seat_client_destroy_pointer(resource);
340 			}
341 		}
342 		if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) == 0) {
343 			struct wlr_seat_client *focused_client =
344 				wlr_seat->keyboard_state.focused_client;
345 			struct wlr_surface *focused_surface =
346 				wlr_seat->keyboard_state.focused_surface;
347 
348 			if (focused_client != NULL && focused_surface != NULL) {
349 				seat_client_send_keyboard_leave_raw(focused_client,
350 						focused_surface);
351 			}
352 
353 			// Note: we don't set focused client/surface to NULL since we need
354 			// them to send the enter event if the keyboard is recreated
355 
356 			struct wl_resource *resource, *tmp;
357 			wl_resource_for_each_safe(resource, tmp, &client->keyboards) {
358 				seat_client_destroy_keyboard(resource);
359 			}
360 		}
361 		if ((capabilities & WL_SEAT_CAPABILITY_TOUCH) == 0) {
362 			struct wl_resource *resource, *tmp;
363 			wl_resource_for_each_safe(resource, tmp, &client->touches) {
364 				seat_client_destroy_touch(resource);
365 			}
366 		}
367 
368 		struct wl_resource *resource;
369 		wl_resource_for_each(resource, &client->resources) {
370 			wl_seat_send_capabilities(resource, capabilities);
371 		}
372 	}
373 }
374 
wlr_seat_set_name(struct wlr_seat * wlr_seat,const char * name)375 void wlr_seat_set_name(struct wlr_seat *wlr_seat, const char *name) {
376 	free(wlr_seat->name);
377 	wlr_seat->name = strdup(name);
378 	struct wlr_seat_client *client;
379 	wl_list_for_each(client, &wlr_seat->clients, link) {
380 		struct wl_resource *resource;
381 		wl_resource_for_each(resource, &client->resources) {
382 			wl_seat_send_name(resource, name);
383 		}
384 	}
385 }
386 
wlr_seat_client_from_resource(struct wl_resource * resource)387 struct wlr_seat_client *wlr_seat_client_from_resource(
388 		struct wl_resource *resource) {
389 	assert(wl_resource_instance_of(resource, &wl_seat_interface,
390 		&seat_impl));
391 	return wl_resource_get_user_data(resource);
392 }
393 
wlr_seat_validate_grab_serial(struct wlr_seat * seat,uint32_t serial)394 bool wlr_seat_validate_grab_serial(struct wlr_seat *seat, uint32_t serial) {
395 	// TODO
396 	//return serial == seat->pointer_state.grab_serial ||
397 	//	serial == seat->touch_state.grab_serial;
398 	return true;
399 }
400 
wlr_seat_client_next_serial(struct wlr_seat_client * client)401 uint32_t wlr_seat_client_next_serial(struct wlr_seat_client *client) {
402 	uint32_t serial = wl_display_next_serial(wl_client_get_display(client->client));
403 	struct wlr_serial_ringset *set = &client->serials;
404 
405 	if (set->count == 0) {
406 		set->data[0].min_incl = serial;
407 		set->data[0].max_incl = serial;
408 		set->count = 1;
409 		set->end = 0;
410 	} else if (set->data[set->end].max_incl + 1 != serial) {
411 		if (set->count < WLR_SERIAL_RINGSET_SIZE) {
412 			set->count++;
413 		}
414 		set->end = (set->end + 1) % WLR_SERIAL_RINGSET_SIZE;
415 		set->data[set->end].min_incl = serial;
416 		set->data[set->end].max_incl = serial;
417 	} else {
418 		set->data[set->end].max_incl = serial;
419 	}
420 
421 	return serial;
422 }
423 
wlr_seat_client_validate_event_serial(struct wlr_seat_client * client,uint32_t serial)424 bool wlr_seat_client_validate_event_serial(struct wlr_seat_client *client, uint32_t serial) {
425 	uint32_t cur = wl_display_get_serial(wl_client_get_display(client->client));
426 	struct wlr_serial_ringset *set = &client->serials;
427 	uint32_t rev_dist = cur - serial;
428 
429 	if (rev_dist >= UINT32_MAX / 2) {
430 		// serial is closer to being 'newer' instead of 'older' than
431 		// the current serial, so it's either invalid or incredibly old
432 		return false;
433 	}
434 
435 	for (int i = 0; i < set->count; i++) {
436 		int j = (set->end - i + WLR_SERIAL_RINGSET_SIZE) % WLR_SERIAL_RINGSET_SIZE;
437 		if (rev_dist < cur - set->data[j].max_incl) {
438 			return false;
439 		}
440 		if (rev_dist <= cur - set->data[j].min_incl) {
441 			return true;
442 		}
443 	}
444 
445 	// Iff the set is full, then `rev_dist` is large enough that serial
446 	// could already have been recycled out of the set.
447 	return set->count == WLR_SERIAL_RINGSET_SIZE;
448 }
449