1 #include <assert.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <strings.h>
5 #include <unistd.h>
6 #include <wayland-server-core.h>
7 #include <wlr/types/wlr_data_device.h>
8 #include <wlr/types/wlr_seat.h>
9 #include <wlr/util/log.h>
10 #include "types/wlr_data_device.h"
11 #include "util/signal.h"
12 
drag_handle_seat_client_destroy(struct wl_listener * listener,void * data)13 static void drag_handle_seat_client_destroy(struct wl_listener *listener,
14 		void *data) {
15 	struct wlr_drag *drag =
16 		wl_container_of(listener, drag, seat_client_destroy);
17 
18 	drag->focus_client = NULL;
19 	wl_list_remove(&drag->seat_client_destroy.link);
20 }
21 
drag_set_focus(struct wlr_drag * drag,struct wlr_surface * surface,double sx,double sy)22 static void drag_set_focus(struct wlr_drag *drag,
23 		struct wlr_surface *surface, double sx, double sy) {
24 	if (drag->focus == surface) {
25 		return;
26 	}
27 
28 	if (drag->focus_client) {
29 		wl_list_remove(&drag->seat_client_destroy.link);
30 
31 		// If we're switching focus to another client, we want to destroy all
32 		// offers without destroying the source. If the drag operation ends, we
33 		// want to keep the offer around for the data transfer.
34 		struct wlr_data_offer *offer, *tmp;
35 		wl_list_for_each_safe(offer, tmp,
36 				&drag->focus_client->seat->drag_offers, link) {
37 			struct wl_client *client = wl_resource_get_client(offer->resource);
38 			if (!drag->dropped && offer->source == drag->source &&
39 					client == drag->focus_client->client) {
40 				offer->source = NULL;
41 				data_offer_destroy(offer);
42 			}
43 		}
44 
45 		struct wl_resource *resource;
46 		wl_resource_for_each(resource, &drag->focus_client->data_devices) {
47 			wl_data_device_send_leave(resource);
48 		}
49 
50 		drag->focus_client = NULL;
51 		drag->focus = NULL;
52 	}
53 
54 	if (!surface) {
55 		goto out;
56 	}
57 
58 	if (!drag->source &&
59 			wl_resource_get_client(surface->resource) !=
60 			drag->seat_client->client) {
61 		goto out;
62 	}
63 
64 	struct wlr_seat_client *focus_client = wlr_seat_client_for_wl_client(
65 		drag->seat_client->seat, wl_resource_get_client(surface->resource));
66 	if (!focus_client) {
67 		goto out;
68 	}
69 
70 	if (drag->source != NULL) {
71 		drag->source->accepted = false;
72 
73 		uint32_t serial =
74 			wl_display_next_serial(drag->seat_client->seat->display);
75 
76 		struct wl_resource *device_resource;
77 		wl_resource_for_each(device_resource, &focus_client->data_devices) {
78 			struct wlr_data_offer *offer = data_offer_create(device_resource,
79 				drag->source, WLR_DATA_OFFER_DRAG);
80 			if (offer == NULL) {
81 				wl_resource_post_no_memory(device_resource);
82 				return;
83 			}
84 
85 			data_offer_update_action(offer);
86 
87 			if (wl_resource_get_version(offer->resource) >=
88 					WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) {
89 				wl_data_offer_send_source_actions(offer->resource,
90 					drag->source->actions);
91 			}
92 
93 			wl_data_device_send_enter(device_resource, serial,
94 				surface->resource,
95 				wl_fixed_from_double(sx), wl_fixed_from_double(sy),
96 				offer->resource);
97 		}
98 	}
99 
100 	drag->focus = surface;
101 	drag->focus_client = focus_client;
102 	drag->seat_client_destroy.notify = drag_handle_seat_client_destroy;
103 	wl_signal_add(&focus_client->events.destroy, &drag->seat_client_destroy);
104 
105 out:
106 	wlr_signal_emit_safe(&drag->events.focus, drag);
107 }
108 
drag_icon_set_mapped(struct wlr_drag_icon * icon,bool mapped)109 static void drag_icon_set_mapped(struct wlr_drag_icon *icon, bool mapped) {
110 	if (mapped && !icon->mapped) {
111 		icon->mapped = true;
112 		wlr_signal_emit_safe(&icon->events.map, icon);
113 	} else if (!mapped && icon->mapped) {
114 		wlr_signal_emit_safe(&icon->events.unmap, icon);
115 		icon->mapped = false;
116 	}
117 }
118 
119 static void drag_icon_destroy(struct wlr_drag_icon *icon);
120 
drag_destroy(struct wlr_drag * drag)121 static void drag_destroy(struct wlr_drag *drag) {
122 	if (drag->cancelling) {
123 		return;
124 	}
125 	drag->cancelling = true;
126 
127 	if (drag->started) {
128 		wlr_seat_keyboard_end_grab(drag->seat);
129 		switch (drag->grab_type) {
130 		case WLR_DRAG_GRAB_KEYBOARD:
131 			break;
132 		case WLR_DRAG_GRAB_KEYBOARD_POINTER:
133 			wlr_seat_pointer_end_grab(drag->seat);
134 			break;
135 		case WLR_DRAG_GRAB_KEYBOARD_TOUCH:
136 			wlr_seat_touch_end_grab(drag->seat);
137 			break;
138 		}
139 	}
140 
141 	// We issue destroy after ending the grab to allow focus changes.
142 	wlr_signal_emit_safe(&drag->events.destroy, drag);
143 
144 	if (drag->started) {
145 		drag_set_focus(drag, NULL, 0, 0);
146 
147 		assert(drag->seat->drag == drag);
148 		drag->seat->drag = NULL;
149 	}
150 
151 	if (drag->source) {
152 		wl_list_remove(&drag->source_destroy.link);
153 	}
154 
155 	drag_icon_destroy(drag->icon);
156 	free(drag);
157 }
158 
drag_handle_pointer_enter(struct wlr_seat_pointer_grab * grab,struct wlr_surface * surface,double sx,double sy)159 static void drag_handle_pointer_enter(struct wlr_seat_pointer_grab *grab,
160 		struct wlr_surface *surface, double sx, double sy) {
161 	struct wlr_drag *drag = grab->data;
162 	drag_set_focus(drag, surface, sx, sy);
163 }
164 
drag_handle_pointer_clear_focus(struct wlr_seat_pointer_grab * grab)165 static void drag_handle_pointer_clear_focus(struct wlr_seat_pointer_grab *grab) {
166 	struct wlr_drag *drag = grab->data;
167 	drag_set_focus(drag, NULL, 0, 0);
168 }
169 
drag_handle_pointer_motion(struct wlr_seat_pointer_grab * grab,uint32_t time,double sx,double sy)170 static void drag_handle_pointer_motion(struct wlr_seat_pointer_grab *grab,
171 		uint32_t time, double sx, double sy) {
172 	struct wlr_drag *drag = grab->data;
173 	if (drag->focus != NULL && drag->focus_client != NULL) {
174 		struct wl_resource *resource;
175 		wl_resource_for_each(resource, &drag->focus_client->data_devices) {
176 			wl_data_device_send_motion(resource, time, wl_fixed_from_double(sx),
177 				wl_fixed_from_double(sy));
178 		}
179 
180 		struct wlr_drag_motion_event event = {
181 			.drag = drag,
182 			.time = time,
183 			.sx = sx,
184 			.sy = sy,
185 		};
186 		wlr_signal_emit_safe(&drag->events.motion, &event);
187 	}
188 }
189 
drag_drop(struct wlr_drag * drag,uint32_t time)190 static void drag_drop(struct wlr_drag *drag, uint32_t time) {
191 	assert(drag->focus_client);
192 
193 	drag->dropped = true;
194 
195 	struct wl_resource *resource;
196 	wl_resource_for_each(resource, &drag->focus_client->data_devices) {
197 		wl_data_device_send_drop(resource);
198 	}
199 	if (drag->source) {
200 		wlr_data_source_dnd_drop(drag->source);
201 	}
202 
203 	struct wlr_drag_drop_event event = {
204 		.drag = drag,
205 		.time = time,
206 	};
207 	wlr_signal_emit_safe(&drag->events.drop, &event);
208 }
209 
drag_handle_pointer_button(struct wlr_seat_pointer_grab * grab,uint32_t time,uint32_t button,uint32_t state)210 static uint32_t drag_handle_pointer_button(struct wlr_seat_pointer_grab *grab,
211 		uint32_t time, uint32_t button, uint32_t state) {
212 	struct wlr_drag *drag = grab->data;
213 
214 	if (drag->source &&
215 			grab->seat->pointer_state.grab_button == button &&
216 			state == WL_POINTER_BUTTON_STATE_RELEASED) {
217 		if (drag->focus_client && drag->source->current_dnd_action &&
218 				drag->source->accepted) {
219 			drag_drop(drag, time);
220 		} else if (drag->source->impl->dnd_finish) {
221 			// This will end the grab and free `drag`
222 			wlr_data_source_destroy(drag->source);
223 			return 0;
224 		}
225 	}
226 
227 	if (grab->seat->pointer_state.button_count == 0 &&
228 			state == WL_POINTER_BUTTON_STATE_RELEASED) {
229 		drag_destroy(drag);
230 	}
231 
232 	return 0;
233 }
234 
drag_handle_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)235 static void drag_handle_pointer_axis(struct wlr_seat_pointer_grab *grab,
236 		uint32_t time, enum wlr_axis_orientation orientation, double value,
237 		int32_t value_discrete, enum wlr_axis_source source) {
238 	// This space is intentionally left blank
239 }
240 
drag_handle_pointer_cancel(struct wlr_seat_pointer_grab * grab)241 static void drag_handle_pointer_cancel(struct wlr_seat_pointer_grab *grab) {
242 	struct wlr_drag *drag = grab->data;
243 	drag_destroy(drag);
244 }
245 
246 static const struct wlr_pointer_grab_interface
247 		data_device_pointer_drag_interface = {
248 	.enter = drag_handle_pointer_enter,
249 	.clear_focus = drag_handle_pointer_clear_focus,
250 	.motion = drag_handle_pointer_motion,
251 	.button = drag_handle_pointer_button,
252 	.axis = drag_handle_pointer_axis,
253 	.cancel = drag_handle_pointer_cancel,
254 };
255 
drag_handle_touch_down(struct wlr_seat_touch_grab * grab,uint32_t time,struct wlr_touch_point * point)256 static uint32_t drag_handle_touch_down(struct wlr_seat_touch_grab *grab,
257 		uint32_t time, struct wlr_touch_point *point) {
258 	// eat the event
259 	return 0;
260 }
261 
drag_handle_touch_up(struct wlr_seat_touch_grab * grab,uint32_t time,struct wlr_touch_point * point)262 static void drag_handle_touch_up(struct wlr_seat_touch_grab *grab,
263 		uint32_t time, struct wlr_touch_point *point) {
264 	struct wlr_drag *drag = grab->data;
265 	if (drag->grab_touch_id != point->touch_id) {
266 		return;
267 	}
268 
269 	if (drag->focus_client) {
270 		drag_drop(drag, time);
271 	}
272 
273 	drag_destroy(drag);
274 }
275 
drag_handle_touch_motion(struct wlr_seat_touch_grab * grab,uint32_t time,struct wlr_touch_point * point)276 static void drag_handle_touch_motion(struct wlr_seat_touch_grab *grab,
277 		uint32_t time, struct wlr_touch_point *point) {
278 	struct wlr_drag *drag = grab->data;
279 	if (drag->focus && drag->focus_client) {
280 		struct wl_resource *resource;
281 		wl_resource_for_each(resource, &drag->focus_client->data_devices) {
282 			wl_data_device_send_motion(resource, time,
283 				wl_fixed_from_double(point->sx),
284 				wl_fixed_from_double(point->sy));
285 		}
286 	}
287 }
288 
drag_handle_touch_enter(struct wlr_seat_touch_grab * grab,uint32_t time,struct wlr_touch_point * point)289 static void drag_handle_touch_enter(struct wlr_seat_touch_grab *grab,
290 		uint32_t time, struct wlr_touch_point *point) {
291 	struct wlr_drag *drag = grab->data;
292 	drag_set_focus(drag, point->focus_surface, point->sx, point->sy);
293 }
294 
drag_handle_touch_cancel(struct wlr_seat_touch_grab * grab)295 static void drag_handle_touch_cancel(struct wlr_seat_touch_grab *grab) {
296 	struct wlr_drag *drag = grab->data;
297 	drag_destroy(drag);
298 }
299 
300 static const struct wlr_touch_grab_interface
301 		data_device_touch_drag_interface = {
302 	.down = drag_handle_touch_down,
303 	.up = drag_handle_touch_up,
304 	.motion = drag_handle_touch_motion,
305 	.enter = drag_handle_touch_enter,
306 	.cancel = drag_handle_touch_cancel,
307 };
308 
drag_handle_keyboard_enter(struct wlr_seat_keyboard_grab * grab,struct wlr_surface * surface,uint32_t keycodes[],size_t num_keycodes,struct wlr_keyboard_modifiers * modifiers)309 static void drag_handle_keyboard_enter(struct wlr_seat_keyboard_grab *grab,
310 		struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
311 		struct wlr_keyboard_modifiers *modifiers) {
312 	// nothing has keyboard focus during drags
313 }
314 
drag_handle_keyboard_clear_focus(struct wlr_seat_keyboard_grab * grab)315 static void drag_handle_keyboard_clear_focus(struct wlr_seat_keyboard_grab *grab) {
316 	// nothing has keyboard focus during drags
317 }
318 
drag_handle_keyboard_key(struct wlr_seat_keyboard_grab * grab,uint32_t time,uint32_t key,uint32_t state)319 static void drag_handle_keyboard_key(struct wlr_seat_keyboard_grab *grab,
320 		uint32_t time, uint32_t key, uint32_t state) {
321 	// no keyboard input during drags
322 }
323 
drag_handle_keyboard_modifiers(struct wlr_seat_keyboard_grab * grab,struct wlr_keyboard_modifiers * modifiers)324 static void drag_handle_keyboard_modifiers(struct wlr_seat_keyboard_grab *grab,
325 		struct wlr_keyboard_modifiers *modifiers) {
326 	//struct wlr_keyboard *keyboard = grab->seat->keyboard_state.keyboard;
327 	// TODO change the dnd action based on what modifier is pressed on the
328 	// keyboard
329 }
330 
drag_handle_keyboard_cancel(struct wlr_seat_keyboard_grab * grab)331 static void drag_handle_keyboard_cancel(struct wlr_seat_keyboard_grab *grab) {
332 	struct wlr_drag *drag = grab->data;
333 	drag_destroy(drag);
334 }
335 
336 static const struct wlr_keyboard_grab_interface
337 		data_device_keyboard_drag_interface = {
338 	.enter = drag_handle_keyboard_enter,
339 	.clear_focus = drag_handle_keyboard_clear_focus,
340 	.key = drag_handle_keyboard_key,
341 	.modifiers = drag_handle_keyboard_modifiers,
342 	.cancel = drag_handle_keyboard_cancel,
343 };
344 
drag_handle_icon_destroy(struct wl_listener * listener,void * data)345 static void drag_handle_icon_destroy(struct wl_listener *listener, void *data) {
346 	struct wlr_drag *drag = wl_container_of(listener, drag, icon_destroy);
347 	drag->icon = NULL;
348 }
349 
drag_handle_drag_source_destroy(struct wl_listener * listener,void * data)350 static void drag_handle_drag_source_destroy(struct wl_listener *listener,
351 		void *data) {
352 	struct wlr_drag *drag = wl_container_of(listener, drag, source_destroy);
353 	drag_destroy(drag);
354 }
355 
356 
drag_icon_destroy(struct wlr_drag_icon * icon)357 static void drag_icon_destroy(struct wlr_drag_icon *icon) {
358 	if (icon == NULL) {
359 		return;
360 	}
361 	drag_icon_set_mapped(icon, false);
362 	wlr_signal_emit_safe(&icon->events.destroy, icon);
363 	icon->surface->role_data = NULL;
364 	wl_list_remove(&icon->surface_destroy.link);
365 	free(icon);
366 }
367 
drag_icon_handle_surface_destroy(struct wl_listener * listener,void * data)368 static void drag_icon_handle_surface_destroy(struct wl_listener *listener,
369 		void *data) {
370 	struct wlr_drag_icon *icon =
371 		wl_container_of(listener, icon, surface_destroy);
372 	drag_icon_destroy(icon);
373 }
374 
drag_icon_surface_role_commit(struct wlr_surface * surface)375 static void drag_icon_surface_role_commit(struct wlr_surface *surface) {
376 	assert(surface->role == &drag_icon_surface_role);
377 	struct wlr_drag_icon *icon = surface->role_data;
378 	if (icon == NULL) {
379 		return;
380 	}
381 
382 	drag_icon_set_mapped(icon, wlr_surface_has_buffer(surface));
383 }
384 
385 const struct wlr_surface_role drag_icon_surface_role = {
386 	.name = "wl_data_device-icon",
387 	.commit = drag_icon_surface_role_commit,
388 };
389 
drag_icon_create(struct wlr_drag * drag,struct wlr_surface * surface)390 static struct wlr_drag_icon *drag_icon_create(struct wlr_drag *drag,
391 		struct wlr_surface *surface) {
392 	struct wlr_drag_icon *icon = calloc(1, sizeof(struct wlr_drag_icon));
393 	if (!icon) {
394 		return NULL;
395 	}
396 
397 	icon->drag = drag;
398 	icon->surface = surface;
399 
400 	wl_signal_init(&icon->events.map);
401 	wl_signal_init(&icon->events.unmap);
402 	wl_signal_init(&icon->events.destroy);
403 
404 	wl_signal_add(&icon->surface->events.destroy, &icon->surface_destroy);
405 	icon->surface_destroy.notify = drag_icon_handle_surface_destroy;
406 
407 	icon->surface->role_data = icon;
408 
409 	if (wlr_surface_has_buffer(surface)) {
410 		drag_icon_set_mapped(icon, true);
411 	}
412 
413 	return icon;
414 }
415 
416 
wlr_drag_create(struct wlr_seat_client * seat_client,struct wlr_data_source * source,struct wlr_surface * icon_surface)417 struct wlr_drag *wlr_drag_create(struct wlr_seat_client *seat_client,
418 		struct wlr_data_source *source, struct wlr_surface *icon_surface) {
419 	struct wlr_drag *drag = calloc(1, sizeof(struct wlr_drag));
420 	if (drag == NULL) {
421 		return NULL;
422 	}
423 
424 	wl_signal_init(&drag->events.focus);
425 	wl_signal_init(&drag->events.motion);
426 	wl_signal_init(&drag->events.drop);
427 	wl_signal_init(&drag->events.destroy);
428 
429 	drag->seat = seat_client->seat;
430 	drag->seat_client = seat_client;
431 
432 	if (icon_surface) {
433 		struct wlr_drag_icon *icon = drag_icon_create(drag, icon_surface);
434 		if (icon == NULL) {
435 			free(drag);
436 			return NULL;
437 		}
438 
439 		drag->icon = icon;
440 
441 		drag->icon_destroy.notify = drag_handle_icon_destroy;
442 		wl_signal_add(&icon->events.destroy, &drag->icon_destroy);
443 	}
444 
445 	drag->source = source;
446 	if (source != NULL) {
447 		drag->source_destroy.notify = drag_handle_drag_source_destroy;
448 		wl_signal_add(&source->events.destroy, &drag->source_destroy);
449 	}
450 
451 	drag->pointer_grab.data = drag;
452 	drag->pointer_grab.interface = &data_device_pointer_drag_interface;
453 
454 	drag->touch_grab.data = drag;
455 	drag->touch_grab.interface = &data_device_touch_drag_interface;
456 
457 	drag->keyboard_grab.data = drag;
458 	drag->keyboard_grab.interface = &data_device_keyboard_drag_interface;
459 
460 	return drag;
461 }
462 
wlr_seat_request_start_drag(struct wlr_seat * seat,struct wlr_drag * drag,struct wlr_surface * origin,uint32_t serial)463 void wlr_seat_request_start_drag(struct wlr_seat *seat, struct wlr_drag *drag,
464 		struct wlr_surface *origin, uint32_t serial) {
465 	assert(drag->seat == seat);
466 
467 	if (seat->drag != NULL) {
468 		wlr_log(WLR_DEBUG, "Rejecting start_drag request, "
469 			"another drag-and-drop operation is already in progress");
470 		return;
471 	}
472 
473 	struct wlr_seat_request_start_drag_event event = {
474 		.drag = drag,
475 		.origin = origin,
476 		.serial = serial,
477 	};
478 	wlr_signal_emit_safe(&seat->events.request_start_drag, &event);
479 }
480 
seat_handle_drag_source_destroy(struct wl_listener * listener,void * data)481 static void seat_handle_drag_source_destroy(struct wl_listener *listener,
482 		void *data) {
483 	struct wlr_seat *seat =
484 		wl_container_of(listener, seat, drag_source_destroy);
485 	wl_list_remove(&seat->drag_source_destroy.link);
486 	seat->drag_source = NULL;
487 }
488 
wlr_seat_start_drag(struct wlr_seat * seat,struct wlr_drag * drag,uint32_t serial)489 void wlr_seat_start_drag(struct wlr_seat *seat, struct wlr_drag *drag,
490 		uint32_t serial) {
491 	assert(drag->seat == seat);
492 	assert(!drag->started);
493 	drag->started = true;
494 
495 	wlr_seat_keyboard_start_grab(seat, &drag->keyboard_grab);
496 
497 	seat->drag = drag;
498 	seat->drag_serial = serial;
499 
500 	// We need to destroy the previous source, because listeners only expect one
501 	// active drag source at a time.
502 	wlr_data_source_destroy(seat->drag_source);
503 	seat->drag_source = drag->source;
504 	if (drag->source != NULL) {
505 		seat->drag_source_destroy.notify = seat_handle_drag_source_destroy;
506 		wl_signal_add(&drag->source->events.destroy, &seat->drag_source_destroy);
507 	}
508 
509 	wlr_signal_emit_safe(&seat->events.start_drag, drag);
510 }
511 
wlr_seat_start_pointer_drag(struct wlr_seat * seat,struct wlr_drag * drag,uint32_t serial)512 void wlr_seat_start_pointer_drag(struct wlr_seat *seat, struct wlr_drag *drag,
513 		uint32_t serial) {
514 	drag->grab_type = WLR_DRAG_GRAB_KEYBOARD_POINTER;
515 
516 	wlr_seat_pointer_clear_focus(seat);
517 	wlr_seat_pointer_start_grab(seat, &drag->pointer_grab);
518 
519 	wlr_seat_start_drag(seat, drag, serial);
520 }
521 
wlr_seat_start_touch_drag(struct wlr_seat * seat,struct wlr_drag * drag,uint32_t serial,struct wlr_touch_point * point)522 void wlr_seat_start_touch_drag(struct wlr_seat *seat, struct wlr_drag *drag,
523 		uint32_t serial, struct wlr_touch_point *point) {
524 	drag->grab_type = WLR_DRAG_GRAB_KEYBOARD_TOUCH;
525 	drag->grab_touch_id = seat->touch_state.grab_id;
526 	drag->touch_id = point->touch_id;
527 
528 	wlr_seat_touch_start_grab(seat, &drag->touch_grab);
529 	drag_set_focus(drag, point->surface, point->sx, point->sy);
530 
531 	wlr_seat_start_drag(seat, drag, serial);
532 }
533