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