1 #include <assert.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <wlr/util/log.h>
5 #include "types/wlr_xdg_shell.h"
6 #include "util/signal.h"
7 
wlr_surface_is_xdg_surface(struct wlr_surface * surface)8 bool wlr_surface_is_xdg_surface(struct wlr_surface *surface) {
9 	return surface->role == &xdg_toplevel_surface_role ||
10 		surface->role == &xdg_popup_surface_role;
11 }
12 
wlr_xdg_surface_from_wlr_surface(struct wlr_surface * surface)13 struct wlr_xdg_surface *wlr_xdg_surface_from_wlr_surface(
14 		struct wlr_surface *surface) {
15 	assert(wlr_surface_is_xdg_surface(surface));
16 	return (struct wlr_xdg_surface *)surface->role_data;
17 }
18 
xdg_surface_configure_destroy(struct wlr_xdg_surface_configure * configure)19 static void xdg_surface_configure_destroy(
20 		struct wlr_xdg_surface_configure *configure) {
21 	if (configure == NULL) {
22 		return;
23 	}
24 	wl_list_remove(&configure->link);
25 	free(configure->toplevel_state);
26 	free(configure);
27 }
28 
unmap_xdg_surface(struct wlr_xdg_surface * surface)29 void unmap_xdg_surface(struct wlr_xdg_surface *surface) {
30 	assert(surface->role != WLR_XDG_SURFACE_ROLE_NONE);
31 
32 	struct wlr_xdg_popup *popup, *popup_tmp;
33 	wl_list_for_each_safe(popup, popup_tmp, &surface->popups, link) {
34 		wlr_xdg_popup_destroy(popup->base);
35 	}
36 
37 	// TODO: probably need to ungrab before this event
38 	if (surface->mapped) {
39 		wlr_signal_emit_safe(&surface->events.unmap, surface);
40 	}
41 
42 	switch (surface->role) {
43 	case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
44 		if (surface->toplevel->parent) {
45 			wl_list_remove(&surface->toplevel->parent_unmap.link);
46 			surface->toplevel->parent = NULL;
47 		}
48 		free(surface->toplevel->title);
49 		surface->toplevel->title = NULL;
50 		free(surface->toplevel->app_id);
51 		surface->toplevel->app_id = NULL;
52 		break;
53 	case WLR_XDG_SURFACE_ROLE_POPUP:
54 		if (surface->popup->seat != NULL) {
55 			struct wlr_xdg_popup_grab *grab =
56 				get_xdg_shell_popup_grab_from_seat(surface->client->shell,
57 					surface->popup->seat);
58 
59 			wl_list_remove(&surface->popup->grab_link);
60 
61 			if (wl_list_empty(&grab->popups)) {
62 				if (grab->seat->pointer_state.grab == &grab->pointer_grab) {
63 					wlr_seat_pointer_end_grab(grab->seat);
64 				}
65 				if (grab->seat->keyboard_state.grab == &grab->keyboard_grab) {
66 					wlr_seat_keyboard_end_grab(grab->seat);
67 				}
68 			}
69 
70 			surface->popup->seat = NULL;
71 		}
72 		break;
73 	case WLR_XDG_SURFACE_ROLE_NONE:
74 		assert(false && "not reached");
75 	}
76 
77 	struct wlr_xdg_surface_configure *configure, *tmp;
78 	wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) {
79 		xdg_surface_configure_destroy(configure);
80 	}
81 
82 	surface->configured = surface->mapped = false;
83 	surface->configure_serial = 0;
84 	if (surface->configure_idle) {
85 		wl_event_source_remove(surface->configure_idle);
86 		surface->configure_idle = NULL;
87 	}
88 	surface->configure_next_serial = 0;
89 
90 	surface->has_next_geometry = false;
91 	memset(&surface->geometry, 0, sizeof(struct wlr_box));
92 	memset(&surface->next_geometry, 0, sizeof(struct wlr_box));
93 }
94 
95 
xdg_surface_handle_ack_configure(struct wl_client * client,struct wl_resource * resource,uint32_t serial)96 static void xdg_surface_handle_ack_configure(struct wl_client *client,
97 		struct wl_resource *resource, uint32_t serial) {
98 	struct wlr_xdg_surface *surface = wlr_xdg_surface_from_resource(resource);
99 	if (surface == NULL) {
100 		return;
101 	}
102 
103 	if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) {
104 		wl_resource_post_error(surface->resource,
105 			XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
106 			"xdg_surface must have a role");
107 		return;
108 	}
109 
110 	// First find the ack'ed configure
111 	bool found = false;
112 	struct wlr_xdg_surface_configure *configure, *tmp;
113 	wl_list_for_each(configure, &surface->configure_list, link) {
114 		if (configure->serial == serial) {
115 			found = true;
116 			break;
117 		}
118 	}
119 	if (!found) {
120 		wl_resource_post_error(surface->client->resource,
121 			XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
122 			"wrong configure serial: %u", serial);
123 		return;
124 	}
125 	// Then remove old configures from the list
126 	wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) {
127 		if (configure->serial == serial) {
128 			break;
129 		}
130 		wlr_signal_emit_safe(&surface->events.ack_configure, configure);
131 		xdg_surface_configure_destroy(configure);
132 	}
133 
134 	switch (surface->role) {
135 	case WLR_XDG_SURFACE_ROLE_NONE:
136 		assert(0 && "not reached");
137 		break;
138 	case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
139 		handle_xdg_toplevel_ack_configure(surface, configure);
140 		break;
141 	case WLR_XDG_SURFACE_ROLE_POPUP:
142 		break;
143 	}
144 
145 	surface->configured = true;
146 	surface->configure_serial = serial;
147 
148 	wlr_signal_emit_safe(&surface->events.ack_configure, configure);
149 	xdg_surface_configure_destroy(configure);
150 }
151 
surface_send_configure(void * user_data)152 static void surface_send_configure(void *user_data) {
153 	struct wlr_xdg_surface *surface = user_data;
154 
155 	surface->configure_idle = NULL;
156 
157 	struct wlr_xdg_surface_configure *configure =
158 		calloc(1, sizeof(struct wlr_xdg_surface_configure));
159 	if (configure == NULL) {
160 		wl_client_post_no_memory(surface->client->client);
161 		return;
162 	}
163 
164 	wl_list_insert(surface->configure_list.prev, &configure->link);
165 	configure->serial = surface->configure_next_serial;
166 	configure->surface = surface;
167 
168 	switch (surface->role) {
169 	case WLR_XDG_SURFACE_ROLE_NONE:
170 		assert(0 && "not reached");
171 		break;
172 	case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
173 		send_xdg_toplevel_configure(surface, configure);
174 		break;
175 	case WLR_XDG_SURFACE_ROLE_POPUP:
176 		xdg_popup_send_configure(surface->popup->resource,
177 			surface->popup->geometry.x,
178 			surface->popup->geometry.y,
179 			surface->popup->geometry.width,
180 			surface->popup->geometry.height);
181 		break;
182 	}
183 
184 	wlr_signal_emit_safe(&surface->events.configure, configure);
185 
186 	xdg_surface_send_configure(surface->resource, configure->serial);
187 }
188 
schedule_configure(struct wlr_xdg_surface * surface,bool pending_same)189 static uint32_t schedule_configure(struct wlr_xdg_surface *surface,
190 		bool pending_same) {
191 	struct wl_display *display = wl_client_get_display(surface->client->client);
192 	struct wl_event_loop *loop = wl_display_get_event_loop(display);
193 
194 	if (surface->configure_idle != NULL) {
195 		if (!pending_same) {
196 			// configure request already scheduled
197 			return surface->configure_next_serial;
198 		}
199 
200 		// configure request not necessary anymore
201 		wl_event_source_remove(surface->configure_idle);
202 		surface->configure_idle = NULL;
203 		return 0;
204 	} else {
205 		if (pending_same) {
206 			// configure request not necessary
207 			return 0;
208 		}
209 
210 		surface->configure_next_serial = wl_display_next_serial(display);
211 		surface->configure_idle = wl_event_loop_add_idle(loop,
212 			surface_send_configure, surface);
213 		return surface->configure_next_serial;
214 	}
215 }
216 
schedule_xdg_surface_configure(struct wlr_xdg_surface * surface)217 uint32_t schedule_xdg_surface_configure(struct wlr_xdg_surface *surface) {
218 	bool pending_same = false;
219 
220 	switch (surface->role) {
221 	case WLR_XDG_SURFACE_ROLE_NONE:
222 		assert(0 && "not reached");
223 		break;
224 	case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
225 		pending_same = compare_xdg_surface_toplevel_state(surface->toplevel);
226 		break;
227 	case WLR_XDG_SURFACE_ROLE_POPUP:
228 		break;
229 	}
230 
231 	return schedule_configure(surface, pending_same);
232 }
233 
wlr_xdg_surface_schedule_configure(struct wlr_xdg_surface * surface)234 uint32_t wlr_xdg_surface_schedule_configure(struct wlr_xdg_surface *surface) {
235 	return schedule_configure(surface, false);
236 }
237 
xdg_surface_handle_get_popup(struct wl_client * client,struct wl_resource * resource,uint32_t id,struct wl_resource * parent_resource,struct wl_resource * positioner_resource)238 static void xdg_surface_handle_get_popup(struct wl_client *client,
239 		struct wl_resource *resource, uint32_t id,
240 		struct wl_resource *parent_resource,
241 		struct wl_resource *positioner_resource) {
242 	struct wlr_xdg_surface *xdg_surface =
243 		wlr_xdg_surface_from_resource(resource);
244 	struct wlr_xdg_surface *parent = NULL;
245 	if (parent_resource != NULL) {
246 		parent = wlr_xdg_surface_from_resource(parent_resource);
247 	}
248 	if (xdg_surface == NULL) {
249 		return; // TODO: create an inert xdg_popup
250 	}
251 	struct wlr_xdg_positioner_resource *positioner =
252 		get_xdg_positioner_from_resource(positioner_resource);
253 	create_xdg_popup(xdg_surface, parent, positioner, id);
254 }
255 
xdg_surface_handle_get_toplevel(struct wl_client * client,struct wl_resource * resource,uint32_t id)256 static void xdg_surface_handle_get_toplevel(struct wl_client *client,
257 		struct wl_resource *resource, uint32_t id) {
258 	struct wlr_xdg_surface *xdg_surface =
259 		wlr_xdg_surface_from_resource(resource);
260 	if (xdg_surface == NULL) {
261 		return; // TODO: create an inert xdg_toplevel
262 	}
263 	create_xdg_toplevel(xdg_surface, id);
264 }
265 
xdg_surface_handle_set_window_geometry(struct wl_client * client,struct wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)266 static void xdg_surface_handle_set_window_geometry(struct wl_client *client,
267 		struct wl_resource *resource, int32_t x, int32_t y, int32_t width,
268 		int32_t height) {
269 	struct wlr_xdg_surface *surface = wlr_xdg_surface_from_resource(resource);
270 	if (surface == NULL) {
271 		return;
272 	}
273 
274 	if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) {
275 		wl_resource_post_error(surface->resource,
276 			XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
277 			"xdg_surface must have a role");
278 		return;
279 	}
280 
281 	if (width <= 0 || height <= 0) {
282 		wlr_log(WLR_ERROR, "Client tried to set invalid geometry");
283 		//XXX: Switch to the proper error value once available
284 		wl_resource_post_error(resource, -1, "Tried to set invalid xdg-surface geometry");
285 		return;
286 	}
287 
288 	surface->has_next_geometry = true;
289 	surface->next_geometry.height = height;
290 	surface->next_geometry.width = width;
291 	surface->next_geometry.x = x;
292 	surface->next_geometry.y = y;
293 }
294 
xdg_surface_handle_destroy(struct wl_client * client,struct wl_resource * resource)295 static void xdg_surface_handle_destroy(struct wl_client *client,
296 		struct wl_resource *resource) {
297 	struct wlr_xdg_surface *surface = wlr_xdg_surface_from_resource(resource);
298 	if (surface == NULL) {
299 		return;
300 	}
301 
302 	if (surface->role != WLR_XDG_SURFACE_ROLE_NONE) {
303 		wlr_log(WLR_ERROR, "Tried to destroy an xdg_surface before its role "
304 			"object");
305 		return;
306 	}
307 
308 	wl_resource_destroy(resource);
309 }
310 
311 static const struct xdg_surface_interface xdg_surface_implementation = {
312 	.destroy = xdg_surface_handle_destroy,
313 	.get_toplevel = xdg_surface_handle_get_toplevel,
314 	.get_popup = xdg_surface_handle_get_popup,
315 	.ack_configure = xdg_surface_handle_ack_configure,
316 	.set_window_geometry = xdg_surface_handle_set_window_geometry,
317 };
318 
xdg_surface_handle_resource_destroy(struct wl_resource * resource)319 static void xdg_surface_handle_resource_destroy(struct wl_resource *resource) {
320 	struct wlr_xdg_surface *surface =
321 		wlr_xdg_surface_from_resource(resource);
322 	if (surface != NULL) {
323 		destroy_xdg_surface(surface);
324 	}
325 }
326 
xdg_surface_handle_surface_commit(struct wl_listener * listener,void * data)327 static void xdg_surface_handle_surface_commit(struct wl_listener *listener,
328 		void *data) {
329 	struct wlr_xdg_surface *surface =
330 		wl_container_of(listener, surface, surface_commit);
331 
332 	if (wlr_surface_has_buffer(surface->surface) && !surface->configured) {
333 		wl_resource_post_error(surface->resource,
334 			XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER,
335 			"xdg_surface has never been configured");
336 		return;
337 	}
338 
339 	// surface->role might be NONE for inert popups
340 	// So we check surface->surface->role
341 	if (surface->surface->role == NULL) {
342 		wl_resource_post_error(surface->resource,
343 			XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
344 			"xdg_surface must have a role");
345 		return;
346 	}
347 }
348 
handle_xdg_surface_commit(struct wlr_surface * wlr_surface)349 void handle_xdg_surface_commit(struct wlr_surface *wlr_surface) {
350 	struct wlr_xdg_surface *surface =
351 		wlr_xdg_surface_from_wlr_surface(wlr_surface);
352 	if (surface == NULL) {
353 		return;
354 	}
355 
356 	if (surface->has_next_geometry) {
357 		surface->has_next_geometry = false;
358 		surface->geometry.x = surface->next_geometry.x;
359 		surface->geometry.y = surface->next_geometry.y;
360 		surface->geometry.width = surface->next_geometry.width;
361 		surface->geometry.height = surface->next_geometry.height;
362 	}
363 
364 	switch (surface->role) {
365 	case WLR_XDG_SURFACE_ROLE_NONE:
366 		// inert toplevel or popup
367 		return;
368 	case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
369 		handle_xdg_surface_toplevel_committed(surface);
370 		break;
371 	case WLR_XDG_SURFACE_ROLE_POPUP:
372 		handle_xdg_surface_popup_committed(surface);
373 		break;
374 	}
375 
376 	if (!surface->added) {
377 		surface->added = true;
378 		wlr_signal_emit_safe(&surface->client->shell->events.new_surface,
379 			surface);
380 	}
381 	if (surface->configured && wlr_surface_has_buffer(surface->surface) &&
382 			!surface->mapped) {
383 		surface->mapped = true;
384 		wlr_signal_emit_safe(&surface->events.map, surface);
385 	}
386 	if (surface->configured && !wlr_surface_has_buffer(surface->surface) &&
387 			surface->mapped) {
388 		unmap_xdg_surface(surface);
389 	}
390 }
391 
handle_xdg_surface_precommit(struct wlr_surface * wlr_surface)392 void handle_xdg_surface_precommit(struct wlr_surface *wlr_surface) {
393 	struct wlr_xdg_surface *surface =
394 		wlr_xdg_surface_from_wlr_surface(wlr_surface);
395 	if (surface == NULL) {
396 		return;
397 	}
398 
399 	if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER &&
400 			wlr_surface->pending.buffer_resource == NULL) {
401 		// This is a NULL commit
402 		if (surface->configured && surface->mapped) {
403 			unmap_xdg_surface(surface);
404 		}
405 	}
406 }
407 
xdg_surface_handle_surface_destroy(struct wl_listener * listener,void * data)408 static void xdg_surface_handle_surface_destroy(struct wl_listener *listener,
409 		void *data) {
410 	struct wlr_xdg_surface *xdg_surface =
411 		wl_container_of(listener, xdg_surface, surface_destroy);
412 	destroy_xdg_surface(xdg_surface);
413 }
414 
create_xdg_surface(struct wlr_xdg_client * client,struct wlr_surface * surface,uint32_t id)415 struct wlr_xdg_surface *create_xdg_surface(
416 		struct wlr_xdg_client *client, struct wlr_surface *surface,
417 		uint32_t id) {
418 	struct wlr_xdg_surface *xdg_surface =
419 		calloc(1, sizeof(struct wlr_xdg_surface));
420 	if (xdg_surface == NULL) {
421 		wl_client_post_no_memory(client->client);
422 		return NULL;
423 	}
424 
425 	xdg_surface->client = client;
426 	xdg_surface->role = WLR_XDG_SURFACE_ROLE_NONE;
427 	xdg_surface->surface = surface;
428 	xdg_surface->resource = wl_resource_create(client->client,
429 		&xdg_surface_interface, wl_resource_get_version(client->resource),
430 		id);
431 	if (xdg_surface->resource == NULL) {
432 		free(xdg_surface);
433 		wl_client_post_no_memory(client->client);
434 		return NULL;
435 	}
436 
437 	if (wlr_surface_has_buffer(xdg_surface->surface)) {
438 		wl_resource_destroy(xdg_surface->resource);
439 		free(xdg_surface);
440 		wl_resource_post_error(client->resource,
441 			XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER,
442 			"xdg_surface must not have a buffer at creation");
443 		return NULL;
444 	}
445 
446 	wl_list_init(&xdg_surface->configure_list);
447 	wl_list_init(&xdg_surface->popups);
448 
449 	wl_signal_init(&xdg_surface->events.destroy);
450 	wl_signal_init(&xdg_surface->events.ping_timeout);
451 	wl_signal_init(&xdg_surface->events.new_popup);
452 	wl_signal_init(&xdg_surface->events.map);
453 	wl_signal_init(&xdg_surface->events.unmap);
454 	wl_signal_init(&xdg_surface->events.configure);
455 	wl_signal_init(&xdg_surface->events.ack_configure);
456 
457 	wl_signal_add(&xdg_surface->surface->events.destroy,
458 		&xdg_surface->surface_destroy);
459 	xdg_surface->surface_destroy.notify = xdg_surface_handle_surface_destroy;
460 
461 	wl_signal_add(&xdg_surface->surface->events.commit,
462 		&xdg_surface->surface_commit);
463 	xdg_surface->surface_commit.notify = xdg_surface_handle_surface_commit;
464 
465 	wlr_log(WLR_DEBUG, "new xdg_surface %p (res %p)", xdg_surface,
466 		xdg_surface->resource);
467 	wl_resource_set_implementation(xdg_surface->resource,
468 		&xdg_surface_implementation, xdg_surface,
469 		xdg_surface_handle_resource_destroy);
470 	wl_list_insert(&client->surfaces, &xdg_surface->link);
471 
472 	return xdg_surface;
473 }
474 
reset_xdg_surface(struct wlr_xdg_surface * xdg_surface)475 void reset_xdg_surface(struct wlr_xdg_surface *xdg_surface) {
476 	if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_NONE) {
477 		unmap_xdg_surface(xdg_surface);
478 	}
479 
480 	if (xdg_surface->added) {
481 		wlr_signal_emit_safe(&xdg_surface->events.destroy, xdg_surface);
482 		xdg_surface->added = false;
483 	}
484 
485 	switch (xdg_surface->role) {
486 	case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
487 		wl_resource_set_user_data(xdg_surface->toplevel->resource, NULL);
488 		xdg_surface->toplevel->resource = NULL;
489 
490 		if (xdg_surface->toplevel->client_pending.fullscreen_output) {
491 			struct wlr_xdg_toplevel_state *client_pending =
492 				&xdg_surface->toplevel->client_pending;
493 			wl_list_remove(&client_pending->fullscreen_output_destroy.link);
494 		}
495 		free(xdg_surface->toplevel);
496 		xdg_surface->toplevel = NULL;
497 		break;
498 	case WLR_XDG_SURFACE_ROLE_POPUP:
499 		wl_resource_set_user_data(xdg_surface->popup->resource, NULL);
500 		xdg_surface->popup->resource = NULL;
501 
502 		wl_list_remove(&xdg_surface->popup->link);
503 
504 		free(xdg_surface->popup);
505 		xdg_surface->popup = NULL;
506 		break;
507 	case WLR_XDG_SURFACE_ROLE_NONE:
508 		// This space is intentionally left blank
509 		break;
510 	}
511 
512 	xdg_surface->role = WLR_XDG_SURFACE_ROLE_NONE;
513 }
514 
destroy_xdg_surface(struct wlr_xdg_surface * surface)515 void destroy_xdg_surface(struct wlr_xdg_surface *surface) {
516 	reset_xdg_surface(surface);
517 
518 	wl_resource_set_user_data(surface->resource, NULL);
519 	surface->surface->role_data = NULL;
520 
521 	wl_list_remove(&surface->link);
522 	wl_list_remove(&surface->surface_destroy.link);
523 	wl_list_remove(&surface->surface_commit.link);
524 	free(surface);
525 }
526 
wlr_xdg_surface_from_resource(struct wl_resource * resource)527 struct wlr_xdg_surface *wlr_xdg_surface_from_resource(
528 		struct wl_resource *resource) {
529 	assert(wl_resource_instance_of(resource, &xdg_surface_interface,
530 		&xdg_surface_implementation));
531 	return wl_resource_get_user_data(resource);
532 }
533 
wlr_xdg_surface_ping(struct wlr_xdg_surface * surface)534 void wlr_xdg_surface_ping(struct wlr_xdg_surface *surface) {
535 	if (surface->client->ping_serial != 0) {
536 		// already pinged
537 		return;
538 	}
539 
540 	surface->client->ping_serial =
541 		wl_display_next_serial(wl_client_get_display(surface->client->client));
542 	wl_event_source_timer_update(surface->client->ping_timer,
543 		surface->client->shell->ping_timeout);
544 	xdg_wm_base_send_ping(surface->client->resource,
545 		surface->client->ping_serial);
546 }
547 
wlr_xdg_toplevel_send_close(struct wlr_xdg_surface * surface)548 void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface) {
549 	assert(surface->toplevel);
550 	assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
551 	xdg_toplevel_send_close(surface->toplevel->resource);
552 }
553 
wlr_xdg_popup_destroy(struct wlr_xdg_surface * surface)554 void wlr_xdg_popup_destroy(struct wlr_xdg_surface *surface) {
555 	if (surface == NULL) {
556 		return;
557 	}
558 	assert(surface->popup);
559 	assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP);
560 
561 	struct wlr_xdg_popup *popup, *popup_tmp;
562 	wl_list_for_each_safe(popup, popup_tmp, &surface->popups, link) {
563 		wlr_xdg_popup_destroy(popup->base);
564 	}
565 
566 	xdg_popup_send_popup_done(surface->popup->resource);
567 	wl_resource_set_user_data(surface->popup->resource, NULL);
568 	reset_xdg_surface(surface);
569 }
570 
xdg_popup_get_position(struct wlr_xdg_popup * popup,double * popup_sx,double * popup_sy)571 static void xdg_popup_get_position(struct wlr_xdg_popup *popup,
572 		double *popup_sx, double *popup_sy) {
573 	struct wlr_xdg_surface *parent =
574 		wlr_xdg_surface_from_wlr_surface(popup->parent);
575 	struct wlr_box parent_geo;
576 	wlr_xdg_surface_get_geometry(parent, &parent_geo);
577 	*popup_sx = parent_geo.x + popup->geometry.x -
578 		popup->base->geometry.x;
579 	*popup_sy = parent_geo.y + popup->geometry.y -
580 		popup->base->geometry.y;
581 }
582 
wlr_xdg_surface_surface_at(struct wlr_xdg_surface * surface,double sx,double sy,double * sub_x,double * sub_y)583 struct wlr_surface *wlr_xdg_surface_surface_at(
584 		struct wlr_xdg_surface *surface, double sx, double sy,
585 		double *sub_x, double *sub_y) {
586 	struct wlr_xdg_popup *popup_state;
587 	wl_list_for_each(popup_state, &surface->popups, link) {
588 		struct wlr_xdg_surface *popup = popup_state->base;
589 
590 		double popup_sx, popup_sy;
591 		xdg_popup_get_position(popup_state, &popup_sx, &popup_sy);
592 
593 		struct wlr_surface *sub = wlr_xdg_surface_surface_at(popup,
594 			sx - popup_sx,
595 			sy - popup_sy,
596 			sub_x, sub_y);
597 		if (sub != NULL) {
598 			return sub;
599 		}
600 	}
601 
602 	return wlr_surface_surface_at(surface->surface, sx, sy, sub_x, sub_y);
603 }
604 
605 struct xdg_surface_iterator_data {
606 	wlr_surface_iterator_func_t user_iterator;
607 	void *user_data;
608 	int x, y;
609 };
610 
xdg_surface_iterator(struct wlr_surface * surface,int sx,int sy,void * data)611 static void xdg_surface_iterator(struct wlr_surface *surface,
612 		int sx, int sy, void *data) {
613 	struct xdg_surface_iterator_data *iter_data = data;
614 	iter_data->user_iterator(surface, iter_data->x + sx, iter_data->y + sy,
615 		iter_data->user_data);
616 }
617 
xdg_surface_for_each_surface(struct wlr_xdg_surface * surface,int x,int y,wlr_surface_iterator_func_t iterator,void * user_data)618 static void xdg_surface_for_each_surface(struct wlr_xdg_surface *surface,
619 		int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) {
620 	struct xdg_surface_iterator_data data = {
621 		.user_iterator = iterator,
622 		.user_data = user_data,
623 		.x = x, .y = y,
624 	};
625 	wlr_surface_for_each_surface(surface->surface, xdg_surface_iterator,
626 		&data);
627 
628 	struct wlr_xdg_popup *popup_state;
629 	wl_list_for_each(popup_state, &surface->popups, link) {
630 		struct wlr_xdg_surface *popup = popup_state->base;
631 		if (!popup->configured) {
632 			continue;
633 		}
634 
635 		double popup_sx, popup_sy;
636 		xdg_popup_get_position(popup_state, &popup_sx, &popup_sy);
637 
638 		xdg_surface_for_each_surface(popup,
639 			x + popup_sx,
640 			y + popup_sy,
641 			iterator, user_data);
642 	}
643 }
644 
xdg_surface_for_each_popup(struct wlr_xdg_surface * surface,int x,int y,wlr_surface_iterator_func_t iterator,void * user_data)645 static void xdg_surface_for_each_popup(struct wlr_xdg_surface *surface,
646 		int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) {
647 	struct wlr_xdg_popup *popup_state;
648 	wl_list_for_each(popup_state, &surface->popups, link) {
649 		struct wlr_xdg_surface *popup = popup_state->base;
650 		if (!popup->configured) {
651 			continue;
652 		}
653 
654 		double popup_sx, popup_sy;
655 		xdg_popup_get_position(popup_state, &popup_sx, &popup_sy);
656 		iterator(popup->surface, x + popup_sx, y + popup_sy, user_data);
657 
658 		xdg_surface_for_each_popup(popup,
659 			x + popup_sx,
660 			y + popup_sy,
661 			iterator, user_data);
662 	}
663 }
664 
wlr_xdg_surface_for_each_surface(struct wlr_xdg_surface * surface,wlr_surface_iterator_func_t iterator,void * user_data)665 void wlr_xdg_surface_for_each_surface(struct wlr_xdg_surface *surface,
666 		wlr_surface_iterator_func_t iterator, void *user_data) {
667 	xdg_surface_for_each_surface(surface, 0, 0, iterator, user_data);
668 }
669 
wlr_xdg_surface_for_each_popup(struct wlr_xdg_surface * surface,wlr_surface_iterator_func_t iterator,void * user_data)670 void wlr_xdg_surface_for_each_popup(struct wlr_xdg_surface *surface,
671 		wlr_surface_iterator_func_t iterator, void *user_data) {
672 	xdg_surface_for_each_popup(surface, 0, 0, iterator, user_data);
673 }
674 
wlr_xdg_surface_get_geometry(struct wlr_xdg_surface * surface,struct wlr_box * box)675 void wlr_xdg_surface_get_geometry(struct wlr_xdg_surface *surface,
676 		struct wlr_box *box) {
677 	wlr_surface_get_extends(surface->surface, box);
678 	/* The client never set the geometry */
679 	if (!surface->geometry.width) {
680 		return;
681 	}
682 
683 	wlr_box_intersection(box, &surface->geometry, box);
684 }
685