blob: 8a1383dd90e3fe3ca76abd3da8f34aa7e5ee0749 [file] [log] [blame]
Quentin Glidic248dd102016-08-12 10:41:34 +02001/*
2 * Copyright © 2010-2012 Intel Corporation
3 * Copyright © 2011-2012 Collabora, Ltd.
4 * Copyright © 2013 Raspberry Pi Foundation
5 * Copyright © 2016 Quentin "Sardem FF7" Glidic
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
16 * Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 */
26
27#include "config.h"
28
29#include <stdbool.h>
30
31#include <wayland-server.h>
32
33#include "compositor.h"
34#include "zalloc.h"
35#include "protocol/xdg-shell-unstable-v5-server-protocol.h"
36
37#include "libweston-desktop.h"
38#include "internal.h"
39
40#define WD_XDG_SHELL_PROTOCOL_VERSION 1
41
42struct weston_desktop_xdg_surface {
43 struct wl_resource *resource;
44 struct weston_desktop_surface *surface;
45 struct weston_desktop *desktop;
46 struct wl_event_source *add_idle;
47 struct wl_event_source *configure_idle;
48 uint32_t configure_serial;
49 struct weston_size requested_size;
50 struct {
51 bool maximized;
52 bool fullscreen;
53 bool resizing;
54 bool activated;
55 } requested_state, next_state, state;
56 bool has_next_geometry;
57 struct weston_geometry next_geometry;
58};
59
60struct weston_desktop_xdg_popup {
61 struct wl_resource *resource;
62 struct weston_desktop_surface *popup;
63 struct weston_desktop *desktop;
64 struct weston_desktop_seat *seat;
65 struct wl_display *display;
66};
67
68static void
69weston_desktop_xdg_surface_send_configure(void *data)
70{
71 struct weston_desktop_xdg_surface *surface = data;
72 uint32_t *s;
73 struct wl_array states;
74
75 surface->configure_idle = NULL;
76
77 surface->configure_serial =
78 wl_display_next_serial(weston_desktop_get_display(surface->desktop));
79
80 wl_array_init(&states);
81 if (surface->requested_state.maximized) {
82 s = wl_array_add(&states, sizeof(uint32_t));
83 *s = XDG_SURFACE_STATE_MAXIMIZED;
84 }
85 if (surface->requested_state.fullscreen) {
86 s = wl_array_add(&states, sizeof(uint32_t));
87 *s = XDG_SURFACE_STATE_FULLSCREEN;
88 }
89 if (surface->requested_state.resizing) {
90 s = wl_array_add(&states, sizeof(uint32_t));
91 *s = XDG_SURFACE_STATE_RESIZING;
92 }
93 if (surface->requested_state.activated) {
94 s = wl_array_add(&states, sizeof(uint32_t));
95 *s = XDG_SURFACE_STATE_ACTIVATED;
96 }
97
98 xdg_surface_send_configure(surface->resource,
99 surface->requested_size.width,
100 surface->requested_size.height,
101 &states,
102 surface->configure_serial);
103
104 wl_array_release(&states);
105};
106
107static void
108weston_desktop_xdg_surface_schedule_configure(struct weston_desktop_xdg_surface *surface)
109{
110 struct wl_display *display = weston_desktop_get_display(surface->desktop);
111 struct wl_event_loop *loop = wl_display_get_event_loop(display);
112
113 if (surface->configure_idle != NULL)
114 return;
115 surface->configure_idle =
116 wl_event_loop_add_idle(loop,
117 weston_desktop_xdg_surface_send_configure,
118 surface);
119}
120
121static void
122weston_desktop_xdg_surface_set_maximized(struct weston_desktop_surface *dsurface,
123 void *user_data, bool maximized)
124{
125 struct weston_desktop_xdg_surface *surface = user_data;
126
127 if (surface->state.maximized == maximized)
128 return;
129
130 surface->requested_state.maximized = maximized;
131 weston_desktop_xdg_surface_schedule_configure(surface);
132}
133
134static void
135weston_desktop_xdg_surface_set_fullscreen(struct weston_desktop_surface *dsurface,
136 void *user_data, bool fullscreen)
137{
138 struct weston_desktop_xdg_surface *surface = user_data;
139
140 if (surface->state.fullscreen == fullscreen)
141 return;
142
143 surface->requested_state.fullscreen = fullscreen;
144 weston_desktop_xdg_surface_schedule_configure(surface);
145}
146
147static void
148weston_desktop_xdg_surface_set_resizing(struct weston_desktop_surface *dsurface,
149 void *user_data, bool resizing)
150{
151 struct weston_desktop_xdg_surface *surface = user_data;
152
153 if (surface->state.resizing == resizing)
154 return;
155
156 surface->requested_state.resizing = resizing;
157 weston_desktop_xdg_surface_schedule_configure(surface);
158}
159
160static void
161weston_desktop_xdg_surface_set_activated(struct weston_desktop_surface *dsurface,
162 void *user_data, bool activated)
163{
164 struct weston_desktop_xdg_surface *surface = user_data;
165
166 if (surface->state.activated == activated)
167 return;
168
169 surface->requested_state.activated = activated;
170 weston_desktop_xdg_surface_schedule_configure(surface);
171}
172
173static void
174weston_desktop_xdg_surface_set_size(struct weston_desktop_surface *dsurface,
175 void *user_data,
176 int32_t width, int32_t height)
177{
178 struct weston_desktop_xdg_surface *surface = user_data;
179 struct weston_surface *wsurface = weston_desktop_surface_get_surface(surface->surface);
180
181 if (wsurface->width == width && wsurface->height == height)
182 return;
183
184 surface->requested_size.width = width;
185 surface->requested_size.height = height;
186 weston_desktop_xdg_surface_schedule_configure(surface);
187}
188
189static void
190weston_desktop_xdg_surface_committed(struct weston_desktop_surface *dsurface,
191 void *user_data, bool new_buffer,
192 int32_t sx, int32_t sy)
193{
194 struct weston_desktop_xdg_surface *surface = user_data;
195 struct weston_surface *wsurface =
196 weston_desktop_surface_get_surface(surface->surface);
197 bool reconfigure = false;
198
199 if (surface->next_state.maximized || surface->next_state.fullscreen)
200 reconfigure = surface->requested_size.width != wsurface->width ||
201 surface->requested_size.height != wsurface->height;
202
203 if (reconfigure) {
204 weston_desktop_xdg_surface_schedule_configure(surface);
205 } else {
206 surface->state = surface->next_state;
207 if (surface->has_next_geometry) {
208 surface->has_next_geometry = false;
209 weston_desktop_surface_set_geometry(surface->surface,
210 surface->next_geometry);
211 }
212
213 if (surface->add_idle != NULL) {
214 wl_event_source_remove(surface->add_idle);
215 surface->add_idle = NULL;
216 weston_desktop_api_surface_added(surface->desktop,
217 surface->surface);
218 }
219 weston_desktop_api_committed(surface->desktop, surface->surface,
220 sx, sy);
221 }
222}
223
224static void
225weston_desktop_xdg_surface_ping(struct weston_desktop_surface *dsurface,
226 uint32_t serial, void *user_data)
227{
228 struct weston_desktop_client *client =
229 weston_desktop_surface_get_client(dsurface);
230
231 xdg_shell_send_ping(weston_desktop_client_get_resource(client),
232 serial);
233}
234
235static void
236weston_desktop_xdg_surface_close(struct weston_desktop_surface *dsurface,
237 void *user_data)
238{
239 struct weston_desktop_xdg_surface *surface = user_data;
240
241 xdg_surface_send_close(surface->resource);
242}
243
244static bool
245weston_desktop_xdg_surface_get_maximized(struct weston_desktop_surface *dsurface,
246 void *user_data)
247{
248 struct weston_desktop_xdg_surface *surface = user_data;
249
250 return surface->state.maximized;
251}
252
253static bool
254weston_desktop_xdg_surface_get_fullscreen(struct weston_desktop_surface *dsurface,
255 void *user_data)
256{
257 struct weston_desktop_xdg_surface *surface = user_data;
258
259 return surface->state.fullscreen;
260}
261
262static bool
263weston_desktop_xdg_surface_get_resizing(struct weston_desktop_surface *dsurface,
264 void *user_data)
265{
266 struct weston_desktop_xdg_surface *surface = user_data;
267
268 return surface->state.resizing;
269}
270
271static bool
272weston_desktop_xdg_surface_get_activated(struct weston_desktop_surface *dsurface,
273 void *user_data)
274{
275 struct weston_desktop_xdg_surface *surface = user_data;
276
277 return surface->state.activated;
278}
279
280static void
281weston_desktop_xdg_surface_destroy(struct weston_desktop_surface *dsurface,
282 void *user_data)
283{
284 struct weston_desktop_xdg_surface *surface = user_data;
285
286 weston_desktop_api_surface_removed(surface->desktop, surface->surface);
287
288 if (surface->add_idle != NULL)
289 wl_event_source_remove(surface->add_idle);
290
291 if (surface->configure_idle != NULL)
292 wl_event_source_remove(surface->configure_idle);
293
294 free(surface);
295}
296
297static void
298weston_desktop_xdg_surface_protocol_set_parent(struct wl_client *wl_client,
299 struct wl_resource *resource,
300 struct wl_resource *parent_resource)
301{
302 struct weston_desktop_surface *dsurface =
303 wl_resource_get_user_data(resource);
304 struct weston_desktop_xdg_surface *surface =
305 weston_desktop_surface_get_implementation_data(dsurface);
306 struct weston_desktop_surface *parent = NULL;
307
308 if (parent_resource != NULL)
309 parent = wl_resource_get_user_data(parent_resource);
310 weston_desktop_api_set_parent(surface->desktop, dsurface, parent);
311}
312
313static void
314weston_desktop_xdg_surface_protocol_set_title(struct wl_client *wl_client,
315 struct wl_resource *resource,
316 const char *title)
317{
318 struct weston_desktop_surface *surface =
319 wl_resource_get_user_data(resource);
320
321 weston_desktop_surface_set_title(surface, title);
322}
323
324static void
325weston_desktop_xdg_surface_protocol_set_app_id(struct wl_client *wl_client,
326 struct wl_resource *resource,
327 const char *app_id)
328{
329 struct weston_desktop_surface *surface =
330 wl_resource_get_user_data(resource);
331
332 weston_desktop_surface_set_app_id(surface, app_id);
333}
334
335static void
336weston_desktop_xdg_surface_protocol_show_window_menu(struct wl_client *wl_client,
337 struct wl_resource *resource,
338 struct wl_resource *seat_resource,
339 uint32_t serial,
340 int32_t x, int32_t y)
341{
342 struct weston_desktop_surface *dsurface =
343 wl_resource_get_user_data(resource);
344 struct weston_seat *seat =
345 wl_resource_get_user_data(seat_resource);
346 struct weston_desktop_xdg_surface *surface =
347 weston_desktop_surface_get_implementation_data(dsurface);
348
349 weston_desktop_api_show_window_menu(surface->desktop, dsurface, seat, x, y);
350}
351
352static void
353weston_desktop_xdg_surface_protocol_move(struct wl_client *wl_client,
354 struct wl_resource *resource,
355 struct wl_resource *seat_resource,
356 uint32_t serial)
357{
358 struct weston_desktop_surface *dsurface =
359 wl_resource_get_user_data(resource);
360 struct weston_seat *seat =
361 wl_resource_get_user_data(seat_resource);
362 struct weston_desktop_xdg_surface *surface =
363 weston_desktop_surface_get_implementation_data(dsurface);
364
365 weston_desktop_api_move(surface->desktop, dsurface, seat, serial);
366}
367
368static void
369weston_desktop_xdg_surface_protocol_resize(struct wl_client *wl_client,
370 struct wl_resource *resource,
371 struct wl_resource *seat_resource,
372 uint32_t serial,
373 enum xdg_surface_resize_edge edges)
374{
375 struct weston_desktop_surface *dsurface =
376 wl_resource_get_user_data(resource);
377 struct weston_seat *seat =
378 wl_resource_get_user_data(seat_resource);
379 struct weston_desktop_xdg_surface *surface =
380 weston_desktop_surface_get_implementation_data(dsurface);
381
382 weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, edges);
383}
384
385static void
386weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client,
387 struct wl_resource *resource,
388 uint32_t serial)
389{
390 struct weston_desktop_surface *dsurface =
391 wl_resource_get_user_data(resource);
392 struct weston_desktop_xdg_surface *surface =
393 weston_desktop_surface_get_implementation_data(dsurface);
394
395 if (surface->configure_serial != serial)
396 return;
397
398 surface->next_state = surface->requested_state;
399}
400
401static void
402weston_desktop_xdg_surface_protocol_set_window_geometry(struct wl_client *wl_client,
403 struct wl_resource *resource,
404 int32_t x, int32_t y,
405 int32_t width, int32_t height)
406{
407 struct weston_desktop_surface *dsurface =
408 wl_resource_get_user_data(resource);
409 struct weston_desktop_xdg_surface *surface =
410 weston_desktop_surface_get_implementation_data(dsurface);
411
412 surface->has_next_geometry = true;
413 surface->next_geometry.x = x;
414 surface->next_geometry.y = y;
415 surface->next_geometry.width = width;
416 surface->next_geometry.height = height;
417}
418
419static void
420weston_desktop_xdg_surface_protocol_set_maximized(struct wl_client *wl_client,
421 struct wl_resource *resource)
422{
423 struct weston_desktop_surface *dsurface =
424 wl_resource_get_user_data(resource);
425 struct weston_desktop_xdg_surface *surface =
426 weston_desktop_surface_get_implementation_data(dsurface);
427
428 weston_desktop_api_maximized_requested(surface->desktop, dsurface, true);
429}
430
431static void
432weston_desktop_xdg_surface_protocol_unset_maximized(struct wl_client *wl_client,
433 struct wl_resource *resource)
434{
435 struct weston_desktop_surface *dsurface =
436 wl_resource_get_user_data(resource);
437 struct weston_desktop_xdg_surface *surface =
438 weston_desktop_surface_get_implementation_data(dsurface);
439
440 weston_desktop_api_maximized_requested(surface->desktop, dsurface, false);
441}
442
443static void
444weston_desktop_xdg_surface_protocol_set_fullscreen(struct wl_client *wl_client,
445 struct wl_resource *resource,
446 struct wl_resource *output_resource)
447{
448 struct weston_desktop_surface *dsurface =
449 wl_resource_get_user_data(resource);
450 struct weston_desktop_xdg_surface *surface =
451 weston_desktop_surface_get_implementation_data(dsurface);
452 struct weston_output *output = NULL;
453
454 if (output_resource != NULL)
455 output = wl_resource_get_user_data(output_resource);
456
457 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
458 true, output);
459}
460
461static void
462weston_desktop_xdg_surface_protocol_unset_fullscreen(struct wl_client *wl_client,
463 struct wl_resource *resource)
464{
465 struct weston_desktop_surface *dsurface =
466 wl_resource_get_user_data(resource);
467 struct weston_desktop_xdg_surface *surface =
468 weston_desktop_surface_get_implementation_data(dsurface);
469
470 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
471 false, NULL);
472}
473
474static void
475weston_desktop_xdg_surface_protocol_set_minimized(struct wl_client *wl_client,
476 struct wl_resource *resource)
477{
478 struct weston_desktop_surface *dsurface =
479 wl_resource_get_user_data(resource);
480 struct weston_desktop_xdg_surface *surface =
481 weston_desktop_surface_get_implementation_data(dsurface);
482
483 weston_desktop_api_minimized_requested(surface->desktop, dsurface);
484}
485
486static const struct xdg_surface_interface weston_desktop_xdg_surface_implementation = {
487 .destroy = weston_desktop_destroy_request,
488 .set_parent = weston_desktop_xdg_surface_protocol_set_parent,
489 .set_title = weston_desktop_xdg_surface_protocol_set_title,
490 .set_app_id = weston_desktop_xdg_surface_protocol_set_app_id,
491 .show_window_menu = weston_desktop_xdg_surface_protocol_show_window_menu,
492 .move = weston_desktop_xdg_surface_protocol_move,
493 .resize = weston_desktop_xdg_surface_protocol_resize,
494 .ack_configure = weston_desktop_xdg_surface_protocol_ack_configure,
495 .set_window_geometry = weston_desktop_xdg_surface_protocol_set_window_geometry,
496 .set_maximized = weston_desktop_xdg_surface_protocol_set_maximized,
497 .unset_maximized = weston_desktop_xdg_surface_protocol_unset_maximized,
498 .set_fullscreen = weston_desktop_xdg_surface_protocol_set_fullscreen,
499 .unset_fullscreen = weston_desktop_xdg_surface_protocol_unset_fullscreen,
500 .set_minimized = weston_desktop_xdg_surface_protocol_set_minimized,
501};
502
503static const struct weston_desktop_surface_implementation weston_desktop_xdg_surface_internal_implementation = {
504 .set_maximized = weston_desktop_xdg_surface_set_maximized,
505 .set_fullscreen = weston_desktop_xdg_surface_set_fullscreen,
506 .set_resizing = weston_desktop_xdg_surface_set_resizing,
507 .set_activated = weston_desktop_xdg_surface_set_activated,
508 .set_size = weston_desktop_xdg_surface_set_size,
509 .committed = weston_desktop_xdg_surface_committed,
510 .ping = weston_desktop_xdg_surface_ping,
511 .close = weston_desktop_xdg_surface_close,
512
513 .get_maximized = weston_desktop_xdg_surface_get_maximized,
514 .get_fullscreen = weston_desktop_xdg_surface_get_fullscreen,
515 .get_resizing = weston_desktop_xdg_surface_get_resizing,
516 .get_activated = weston_desktop_xdg_surface_get_activated,
517
518 .destroy = weston_desktop_xdg_surface_destroy,
519};
520
521static void
522weston_desktop_xdg_popup_close(struct weston_desktop_surface *dsurface,
523 void *user_data)
524{
525 struct weston_desktop_xdg_popup *popup = user_data;
526
527 xdg_popup_send_popup_done(popup->resource);
528}
529
530static void
531weston_desktop_xdg_popup_destroy(struct weston_desktop_surface *dsurface,
532 void *user_data)
533{
534 struct weston_desktop_xdg_popup *popup = user_data;
535 struct weston_desktop_surface *topmost;
536 struct weston_desktop_client *client =
537 weston_desktop_surface_get_client(popup->popup);
538
539 if (!weston_desktop_surface_get_grab(popup->popup))
540 goto end;
541
542 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(popup->seat);
543 if (topmost != popup->popup) {
544 struct wl_resource *client_resource =
545 weston_desktop_client_get_resource(client);
546
547 wl_resource_post_error(client_resource,
548 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
549 "xdg_popup was destroyed while it was not the topmost popup.");
550 }
551
552 weston_desktop_surface_popup_ungrab(popup->popup, popup->seat);
553
554end:
555 free(popup);
556}
557
558static const struct xdg_popup_interface weston_desktop_xdg_popup_implementation = {
559 .destroy = weston_desktop_destroy_request,
560};
561
562static const struct weston_desktop_surface_implementation weston_desktop_xdg_popup_internal_implementation = {
563 .close = weston_desktop_xdg_popup_close,
564
565 .destroy = weston_desktop_xdg_popup_destroy,
566};
567
568static void
569weston_desktop_xdg_shell_protocol_use_unstable_version(struct wl_client *wl_client,
570 struct wl_resource *resource,
571 int32_t version)
572{
573 if (version > 1) {
574 wl_resource_post_error(resource,
575 1, "xdg_shell version not supported");
576 return;
577 }
578}
579
580static void
581weston_desktop_xdg_surface_add(void *user_data)
582{
583 struct weston_desktop_xdg_surface *surface = user_data;
584 surface->add_idle = NULL;
585 weston_desktop_api_surface_added(surface->desktop, surface->surface);
586}
587
588static void
589weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client,
590 struct wl_resource *resource,
591 uint32_t id,
592 struct wl_resource *surface_resource)
593{
594 struct weston_desktop_client *client =
595 wl_resource_get_user_data(resource);
596 struct weston_desktop *desktop =
597 weston_desktop_client_get_desktop(client);
598 struct weston_surface *wsurface =
599 wl_resource_get_user_data(surface_resource);
600 struct weston_desktop_xdg_surface *surface;
601 struct wl_display *display = weston_desktop_get_display(desktop);
602 struct wl_event_loop *loop = wl_display_get_event_loop(display);
603
604 if (weston_surface_set_role(wsurface, "xdg_surface", resource, XDG_SHELL_ERROR_ROLE) < 0)
605 return;
606
607 surface = zalloc(sizeof(struct weston_desktop_xdg_surface));
608 if (surface == NULL) {
609 wl_client_post_no_memory(wl_client);
610 return;
611 }
612
613 surface->desktop = desktop;
614
615 surface->surface =
616 weston_desktop_surface_create(surface->desktop, client,
617 wsurface,
618 &weston_desktop_xdg_surface_internal_implementation,
619 surface);
620 if (surface->surface == NULL) {
621 free(surface);
622 return;
623 }
624
625 surface->resource =
626 weston_desktop_surface_add_resource(surface->surface,
627 &xdg_surface_interface,
628 &weston_desktop_xdg_surface_implementation,
629 id, NULL);
630 if (surface->resource == NULL)
631 return;
632
633 surface->add_idle =
634 wl_event_loop_add_idle(loop,
635 weston_desktop_xdg_surface_add,
636 surface);
637}
638
639static void
640weston_desktop_xdg_shell_protocol_get_xdg_popup(struct wl_client *wl_client,
641 struct wl_resource *resource,
642 uint32_t id,
643 struct wl_resource *surface_resource,
644 struct wl_resource *parent_resource,
645 struct wl_resource *seat_resource,
646 uint32_t serial,
647 int32_t x, int32_t y)
648{
649 struct weston_desktop_client *client =
650 wl_resource_get_user_data(resource);
651 struct weston_surface *wsurface =
652 wl_resource_get_user_data(surface_resource);
653 struct weston_surface *wparent =
654 wl_resource_get_user_data(parent_resource);
655 struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
656 struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
657 struct weston_desktop_surface *parent, *topmost;
658 bool parent_is_popup, parent_is_xdg;
659 struct weston_desktop_xdg_popup *popup;
660
661 if (weston_surface_set_role(wsurface, "xdg_popup", resource, XDG_SHELL_ERROR_ROLE) < 0)
662 return;
663
664 if (!weston_surface_is_desktop_surface(wparent)) {
665 wl_resource_post_error(resource,
666 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
667 "xdg_popup parent was invalid");
668 return;
669 }
670
671 parent = weston_surface_get_desktop_surface(wparent);
672 parent_is_xdg =
673 weston_desktop_surface_has_implementation(parent,
674 &weston_desktop_xdg_surface_internal_implementation);
675 parent_is_popup =
676 weston_desktop_surface_has_implementation(parent,
677 &weston_desktop_xdg_popup_internal_implementation);
678
679 if (!parent_is_xdg && !parent_is_popup) {
680 wl_resource_post_error(resource,
681 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
682 "xdg_popup parent was invalid");
683 return;
684 }
685
686 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(seat);
687 if ((topmost == NULL && parent_is_popup) ||
688 (topmost != NULL && topmost != parent)) {
689 wl_resource_post_error(resource,
690 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
691 "xdg_popup was not created on the topmost popup");
692 return;
693 }
694
695 popup = zalloc(sizeof(struct weston_desktop_xdg_popup));
696 if (popup == NULL) {
697 wl_client_post_no_memory(wl_client);
698 return;
699 }
700
701 popup->desktop = weston_desktop_client_get_desktop(client);
702 popup->display = weston_desktop_get_display(popup->desktop);
703 popup->seat = seat;
704
705 popup->popup =
706 weston_desktop_surface_create(popup->desktop, client, wsurface,
707 &weston_desktop_xdg_popup_internal_implementation,
708 popup);
709 if (popup->popup == NULL) {
710 free(popup);
711 return;
712 }
713
714 popup->resource =
715 weston_desktop_surface_add_resource(popup->popup,
716 &xdg_popup_interface,
717 &weston_desktop_xdg_popup_implementation,
718 id, NULL);
719 if (popup->resource == NULL)
720 return;
721
722 weston_desktop_surface_set_relative_to(popup->popup, parent, x, y, false);
723 weston_desktop_surface_popup_grab(popup->popup, popup->seat, serial);
724}
725
726static void
727weston_desktop_xdg_shell_protocol_pong(struct wl_client *wl_client,
728 struct wl_resource *resource,
729 uint32_t serial)
730{
731 struct weston_desktop_client *client =
732 wl_resource_get_user_data(resource);
733
734 weston_desktop_client_pong(client, serial);
735}
736
737static const struct xdg_shell_interface weston_desktop_xdg_shell_implementation = {
738 .destroy = weston_desktop_destroy_request,
739 .use_unstable_version = weston_desktop_xdg_shell_protocol_use_unstable_version,
740 .get_xdg_surface = weston_desktop_xdg_shell_protocol_get_xdg_surface,
741 .get_xdg_popup = weston_desktop_xdg_shell_protocol_get_xdg_popup,
742 .pong = weston_desktop_xdg_shell_protocol_pong,
743};
744
745static int
746xdg_shell_unversioned_dispatch(const void *implementation,
747 void *_target, uint32_t opcode,
748 const struct wl_message *message,
749 union wl_argument *args)
750{
751 struct wl_resource *resource = _target;
752 struct weston_desktop_client *client =
753 wl_resource_get_user_data(resource);
754
755 if (opcode != 1 /* XDG_SHELL_USE_UNSTABLE_VERSION */) {
756 wl_resource_post_error(resource,
757 WL_DISPLAY_ERROR_INVALID_OBJECT,
758 "must call use_unstable_version first");
759 return 0;
760 }
761
762#define XDG_SERVER_VERSION 5
763
764 if (args[0].i != XDG_SERVER_VERSION) {
765 wl_resource_post_error(resource,
766 WL_DISPLAY_ERROR_INVALID_OBJECT,
767 "incompatible version, server is %d " "client wants %d",
768 XDG_SERVER_VERSION, args[0].i);
769 return 0;
770 }
771
772 wl_resource_set_implementation(resource,
773 &weston_desktop_xdg_shell_implementation,
774 client, implementation);
775
776 return 1;
777}
778
779static void
780weston_desktop_xdg_shell_bind(struct wl_client *client, void *data,
781 uint32_t version, uint32_t id)
782{
783 struct weston_desktop *desktop = data;
784
785 weston_desktop_client_create(desktop, client,
786 xdg_shell_unversioned_dispatch,
787 &xdg_shell_interface, NULL, version, id);
788}
789
790struct wl_global *
791weston_desktop_xdg_shell_v5_create(struct weston_desktop *desktop,
792 struct wl_display *display)
793{
794 return wl_global_create(display,
795 &xdg_shell_interface,
796 WD_XDG_SHELL_PROTOCOL_VERSION,
797 desktop, weston_desktop_xdg_shell_bind);
798}