blob: 14216b0845461e403b6f9244d43be6d2fe2d6f7b [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;
Quentin Glidic6967f0e2016-08-18 15:51:38 +020046 bool added;
Quentin Glidic248dd102016-08-12 10:41:34 +020047 struct wl_event_source *add_idle;
48 struct wl_event_source *configure_idle;
49 uint32_t configure_serial;
50 struct weston_size requested_size;
51 struct {
52 bool maximized;
53 bool fullscreen;
54 bool resizing;
55 bool activated;
56 } requested_state, next_state, state;
57 bool has_next_geometry;
58 struct weston_geometry next_geometry;
59};
60
61struct weston_desktop_xdg_popup {
62 struct wl_resource *resource;
63 struct weston_desktop_surface *popup;
64 struct weston_desktop *desktop;
65 struct weston_desktop_seat *seat;
66 struct wl_display *display;
67};
68
69static void
Quentin Glidic6967f0e2016-08-18 15:51:38 +020070weston_desktop_xdg_surface_ensure_added(struct weston_desktop_xdg_surface *surface)
71{
72 if (surface->added)
73 return;
74
75 if (surface->add_idle != NULL)
76 wl_event_source_remove(surface->add_idle);
77 surface->add_idle = NULL;
78 weston_desktop_api_surface_added(surface->desktop, surface->surface);
79 surface->added = true;
80}
81
82static void
Quentin Glidic248dd102016-08-12 10:41:34 +020083weston_desktop_xdg_surface_send_configure(void *data)
84{
85 struct weston_desktop_xdg_surface *surface = data;
86 uint32_t *s;
87 struct wl_array states;
88
89 surface->configure_idle = NULL;
90
91 surface->configure_serial =
92 wl_display_next_serial(weston_desktop_get_display(surface->desktop));
93
94 wl_array_init(&states);
95 if (surface->requested_state.maximized) {
96 s = wl_array_add(&states, sizeof(uint32_t));
97 *s = XDG_SURFACE_STATE_MAXIMIZED;
98 }
99 if (surface->requested_state.fullscreen) {
100 s = wl_array_add(&states, sizeof(uint32_t));
101 *s = XDG_SURFACE_STATE_FULLSCREEN;
102 }
103 if (surface->requested_state.resizing) {
104 s = wl_array_add(&states, sizeof(uint32_t));
105 *s = XDG_SURFACE_STATE_RESIZING;
106 }
107 if (surface->requested_state.activated) {
108 s = wl_array_add(&states, sizeof(uint32_t));
109 *s = XDG_SURFACE_STATE_ACTIVATED;
110 }
111
112 xdg_surface_send_configure(surface->resource,
113 surface->requested_size.width,
114 surface->requested_size.height,
115 &states,
116 surface->configure_serial);
117
118 wl_array_release(&states);
119};
120
121static void
122weston_desktop_xdg_surface_schedule_configure(struct weston_desktop_xdg_surface *surface)
123{
124 struct wl_display *display = weston_desktop_get_display(surface->desktop);
125 struct wl_event_loop *loop = wl_display_get_event_loop(display);
126
127 if (surface->configure_idle != NULL)
128 return;
129 surface->configure_idle =
130 wl_event_loop_add_idle(loop,
131 weston_desktop_xdg_surface_send_configure,
132 surface);
133}
134
135static void
136weston_desktop_xdg_surface_set_maximized(struct weston_desktop_surface *dsurface,
137 void *user_data, bool maximized)
138{
139 struct weston_desktop_xdg_surface *surface = user_data;
140
141 if (surface->state.maximized == maximized)
142 return;
143
144 surface->requested_state.maximized = maximized;
145 weston_desktop_xdg_surface_schedule_configure(surface);
146}
147
148static void
149weston_desktop_xdg_surface_set_fullscreen(struct weston_desktop_surface *dsurface,
150 void *user_data, bool fullscreen)
151{
152 struct weston_desktop_xdg_surface *surface = user_data;
153
154 if (surface->state.fullscreen == fullscreen)
155 return;
156
157 surface->requested_state.fullscreen = fullscreen;
158 weston_desktop_xdg_surface_schedule_configure(surface);
159}
160
161static void
162weston_desktop_xdg_surface_set_resizing(struct weston_desktop_surface *dsurface,
163 void *user_data, bool resizing)
164{
165 struct weston_desktop_xdg_surface *surface = user_data;
166
167 if (surface->state.resizing == resizing)
168 return;
169
170 surface->requested_state.resizing = resizing;
171 weston_desktop_xdg_surface_schedule_configure(surface);
172}
173
174static void
175weston_desktop_xdg_surface_set_activated(struct weston_desktop_surface *dsurface,
176 void *user_data, bool activated)
177{
178 struct weston_desktop_xdg_surface *surface = user_data;
179
180 if (surface->state.activated == activated)
181 return;
182
183 surface->requested_state.activated = activated;
184 weston_desktop_xdg_surface_schedule_configure(surface);
185}
186
187static void
188weston_desktop_xdg_surface_set_size(struct weston_desktop_surface *dsurface,
189 void *user_data,
190 int32_t width, int32_t height)
191{
192 struct weston_desktop_xdg_surface *surface = user_data;
193 struct weston_surface *wsurface = weston_desktop_surface_get_surface(surface->surface);
194
Quentin Glidic248dd102016-08-12 10:41:34 +0200195 surface->requested_size.width = width;
196 surface->requested_size.height = height;
Quentin Glidica56b0532016-09-13 10:05:58 +0200197
198 if ((wsurface->width == width && wsurface->height == height) ||
199 (width == 0 && height == 0))
200 return;
201
Quentin Glidic248dd102016-08-12 10:41:34 +0200202 weston_desktop_xdg_surface_schedule_configure(surface);
203}
204
205static void
206weston_desktop_xdg_surface_committed(struct weston_desktop_surface *dsurface,
Quentin Glidic003da882016-08-15 12:21:39 +0200207 void *user_data,
Quentin Glidic248dd102016-08-12 10:41:34 +0200208 int32_t sx, int32_t sy)
209{
210 struct weston_desktop_xdg_surface *surface = user_data;
211 struct weston_surface *wsurface =
212 weston_desktop_surface_get_surface(surface->surface);
213 bool reconfigure = false;
214
215 if (surface->next_state.maximized || surface->next_state.fullscreen)
216 reconfigure = surface->requested_size.width != wsurface->width ||
217 surface->requested_size.height != wsurface->height;
218
219 if (reconfigure) {
220 weston_desktop_xdg_surface_schedule_configure(surface);
221 } else {
222 surface->state = surface->next_state;
223 if (surface->has_next_geometry) {
224 surface->has_next_geometry = false;
225 weston_desktop_surface_set_geometry(surface->surface,
226 surface->next_geometry);
227 }
228
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200229 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200230 weston_desktop_api_committed(surface->desktop, surface->surface,
231 sx, sy);
232 }
233}
234
235static void
236weston_desktop_xdg_surface_ping(struct weston_desktop_surface *dsurface,
237 uint32_t serial, void *user_data)
238{
239 struct weston_desktop_client *client =
240 weston_desktop_surface_get_client(dsurface);
241
242 xdg_shell_send_ping(weston_desktop_client_get_resource(client),
243 serial);
244}
245
246static void
247weston_desktop_xdg_surface_close(struct weston_desktop_surface *dsurface,
248 void *user_data)
249{
250 struct weston_desktop_xdg_surface *surface = user_data;
251
252 xdg_surface_send_close(surface->resource);
253}
254
255static bool
256weston_desktop_xdg_surface_get_maximized(struct weston_desktop_surface *dsurface,
257 void *user_data)
258{
259 struct weston_desktop_xdg_surface *surface = user_data;
260
261 return surface->state.maximized;
262}
263
264static bool
265weston_desktop_xdg_surface_get_fullscreen(struct weston_desktop_surface *dsurface,
266 void *user_data)
267{
268 struct weston_desktop_xdg_surface *surface = user_data;
269
270 return surface->state.fullscreen;
271}
272
273static bool
274weston_desktop_xdg_surface_get_resizing(struct weston_desktop_surface *dsurface,
275 void *user_data)
276{
277 struct weston_desktop_xdg_surface *surface = user_data;
278
279 return surface->state.resizing;
280}
281
282static bool
283weston_desktop_xdg_surface_get_activated(struct weston_desktop_surface *dsurface,
284 void *user_data)
285{
286 struct weston_desktop_xdg_surface *surface = user_data;
287
288 return surface->state.activated;
289}
290
291static void
292weston_desktop_xdg_surface_destroy(struct weston_desktop_surface *dsurface,
293 void *user_data)
294{
295 struct weston_desktop_xdg_surface *surface = user_data;
296
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200297 if (surface->added)
298 weston_desktop_api_surface_removed(surface->desktop,
299 surface->surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200300
301 if (surface->add_idle != NULL)
302 wl_event_source_remove(surface->add_idle);
303
304 if (surface->configure_idle != NULL)
305 wl_event_source_remove(surface->configure_idle);
306
307 free(surface);
308}
309
310static void
311weston_desktop_xdg_surface_protocol_set_parent(struct wl_client *wl_client,
312 struct wl_resource *resource,
313 struct wl_resource *parent_resource)
314{
315 struct weston_desktop_surface *dsurface =
316 wl_resource_get_user_data(resource);
317 struct weston_desktop_xdg_surface *surface =
318 weston_desktop_surface_get_implementation_data(dsurface);
319 struct weston_desktop_surface *parent = NULL;
320
321 if (parent_resource != NULL)
322 parent = wl_resource_get_user_data(parent_resource);
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200323
324 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200325 weston_desktop_api_set_parent(surface->desktop, dsurface, parent);
326}
327
328static void
329weston_desktop_xdg_surface_protocol_set_title(struct wl_client *wl_client,
330 struct wl_resource *resource,
331 const char *title)
332{
333 struct weston_desktop_surface *surface =
334 wl_resource_get_user_data(resource);
335
336 weston_desktop_surface_set_title(surface, title);
337}
338
339static void
340weston_desktop_xdg_surface_protocol_set_app_id(struct wl_client *wl_client,
341 struct wl_resource *resource,
342 const char *app_id)
343{
344 struct weston_desktop_surface *surface =
345 wl_resource_get_user_data(resource);
346
347 weston_desktop_surface_set_app_id(surface, app_id);
348}
349
350static void
351weston_desktop_xdg_surface_protocol_show_window_menu(struct wl_client *wl_client,
352 struct wl_resource *resource,
353 struct wl_resource *seat_resource,
354 uint32_t serial,
355 int32_t x, int32_t y)
356{
357 struct weston_desktop_surface *dsurface =
358 wl_resource_get_user_data(resource);
359 struct weston_seat *seat =
360 wl_resource_get_user_data(seat_resource);
361 struct weston_desktop_xdg_surface *surface =
362 weston_desktop_surface_get_implementation_data(dsurface);
363
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200364 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200365 weston_desktop_api_show_window_menu(surface->desktop, dsurface, seat, x, y);
366}
367
368static void
369weston_desktop_xdg_surface_protocol_move(struct wl_client *wl_client,
370 struct wl_resource *resource,
371 struct wl_resource *seat_resource,
372 uint32_t serial)
373{
374 struct weston_desktop_surface *dsurface =
375 wl_resource_get_user_data(resource);
376 struct weston_seat *seat =
377 wl_resource_get_user_data(seat_resource);
378 struct weston_desktop_xdg_surface *surface =
379 weston_desktop_surface_get_implementation_data(dsurface);
380
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200381 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200382 weston_desktop_api_move(surface->desktop, dsurface, seat, serial);
383}
384
385static void
386weston_desktop_xdg_surface_protocol_resize(struct wl_client *wl_client,
387 struct wl_resource *resource,
388 struct wl_resource *seat_resource,
389 uint32_t serial,
390 enum xdg_surface_resize_edge edges)
391{
392 struct weston_desktop_surface *dsurface =
393 wl_resource_get_user_data(resource);
394 struct weston_seat *seat =
395 wl_resource_get_user_data(seat_resource);
396 struct weston_desktop_xdg_surface *surface =
397 weston_desktop_surface_get_implementation_data(dsurface);
398
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200399 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200400 weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, edges);
401}
402
403static void
404weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client,
405 struct wl_resource *resource,
406 uint32_t serial)
407{
408 struct weston_desktop_surface *dsurface =
409 wl_resource_get_user_data(resource);
410 struct weston_desktop_xdg_surface *surface =
411 weston_desktop_surface_get_implementation_data(dsurface);
412
413 if (surface->configure_serial != serial)
414 return;
415
416 surface->next_state = surface->requested_state;
417}
418
419static void
420weston_desktop_xdg_surface_protocol_set_window_geometry(struct wl_client *wl_client,
421 struct wl_resource *resource,
422 int32_t x, int32_t y,
423 int32_t width, int32_t height)
424{
425 struct weston_desktop_surface *dsurface =
426 wl_resource_get_user_data(resource);
427 struct weston_desktop_xdg_surface *surface =
428 weston_desktop_surface_get_implementation_data(dsurface);
429
430 surface->has_next_geometry = true;
431 surface->next_geometry.x = x;
432 surface->next_geometry.y = y;
433 surface->next_geometry.width = width;
434 surface->next_geometry.height = height;
435}
436
437static void
438weston_desktop_xdg_surface_protocol_set_maximized(struct wl_client *wl_client,
439 struct wl_resource *resource)
440{
441 struct weston_desktop_surface *dsurface =
442 wl_resource_get_user_data(resource);
443 struct weston_desktop_xdg_surface *surface =
444 weston_desktop_surface_get_implementation_data(dsurface);
445
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200446 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200447 weston_desktop_api_maximized_requested(surface->desktop, dsurface, true);
448}
449
450static void
451weston_desktop_xdg_surface_protocol_unset_maximized(struct wl_client *wl_client,
452 struct wl_resource *resource)
453{
454 struct weston_desktop_surface *dsurface =
455 wl_resource_get_user_data(resource);
456 struct weston_desktop_xdg_surface *surface =
457 weston_desktop_surface_get_implementation_data(dsurface);
458
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200459 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200460 weston_desktop_api_maximized_requested(surface->desktop, dsurface, false);
461}
462
463static void
464weston_desktop_xdg_surface_protocol_set_fullscreen(struct wl_client *wl_client,
465 struct wl_resource *resource,
466 struct wl_resource *output_resource)
467{
468 struct weston_desktop_surface *dsurface =
469 wl_resource_get_user_data(resource);
470 struct weston_desktop_xdg_surface *surface =
471 weston_desktop_surface_get_implementation_data(dsurface);
472 struct weston_output *output = NULL;
473
474 if (output_resource != NULL)
475 output = wl_resource_get_user_data(output_resource);
476
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200477 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200478 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
479 true, output);
480}
481
482static void
483weston_desktop_xdg_surface_protocol_unset_fullscreen(struct wl_client *wl_client,
484 struct wl_resource *resource)
485{
486 struct weston_desktop_surface *dsurface =
487 wl_resource_get_user_data(resource);
488 struct weston_desktop_xdg_surface *surface =
489 weston_desktop_surface_get_implementation_data(dsurface);
490
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200491 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200492 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
493 false, NULL);
494}
495
496static void
497weston_desktop_xdg_surface_protocol_set_minimized(struct wl_client *wl_client,
498 struct wl_resource *resource)
499{
500 struct weston_desktop_surface *dsurface =
501 wl_resource_get_user_data(resource);
502 struct weston_desktop_xdg_surface *surface =
503 weston_desktop_surface_get_implementation_data(dsurface);
504
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200505 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200506 weston_desktop_api_minimized_requested(surface->desktop, dsurface);
507}
508
509static const struct xdg_surface_interface weston_desktop_xdg_surface_implementation = {
510 .destroy = weston_desktop_destroy_request,
511 .set_parent = weston_desktop_xdg_surface_protocol_set_parent,
512 .set_title = weston_desktop_xdg_surface_protocol_set_title,
513 .set_app_id = weston_desktop_xdg_surface_protocol_set_app_id,
514 .show_window_menu = weston_desktop_xdg_surface_protocol_show_window_menu,
515 .move = weston_desktop_xdg_surface_protocol_move,
516 .resize = weston_desktop_xdg_surface_protocol_resize,
517 .ack_configure = weston_desktop_xdg_surface_protocol_ack_configure,
518 .set_window_geometry = weston_desktop_xdg_surface_protocol_set_window_geometry,
519 .set_maximized = weston_desktop_xdg_surface_protocol_set_maximized,
520 .unset_maximized = weston_desktop_xdg_surface_protocol_unset_maximized,
521 .set_fullscreen = weston_desktop_xdg_surface_protocol_set_fullscreen,
522 .unset_fullscreen = weston_desktop_xdg_surface_protocol_unset_fullscreen,
523 .set_minimized = weston_desktop_xdg_surface_protocol_set_minimized,
524};
525
526static const struct weston_desktop_surface_implementation weston_desktop_xdg_surface_internal_implementation = {
527 .set_maximized = weston_desktop_xdg_surface_set_maximized,
528 .set_fullscreen = weston_desktop_xdg_surface_set_fullscreen,
529 .set_resizing = weston_desktop_xdg_surface_set_resizing,
530 .set_activated = weston_desktop_xdg_surface_set_activated,
531 .set_size = weston_desktop_xdg_surface_set_size,
532 .committed = weston_desktop_xdg_surface_committed,
533 .ping = weston_desktop_xdg_surface_ping,
534 .close = weston_desktop_xdg_surface_close,
535
536 .get_maximized = weston_desktop_xdg_surface_get_maximized,
537 .get_fullscreen = weston_desktop_xdg_surface_get_fullscreen,
538 .get_resizing = weston_desktop_xdg_surface_get_resizing,
539 .get_activated = weston_desktop_xdg_surface_get_activated,
540
541 .destroy = weston_desktop_xdg_surface_destroy,
542};
543
544static void
545weston_desktop_xdg_popup_close(struct weston_desktop_surface *dsurface,
546 void *user_data)
547{
548 struct weston_desktop_xdg_popup *popup = user_data;
549
550 xdg_popup_send_popup_done(popup->resource);
551}
552
553static void
554weston_desktop_xdg_popup_destroy(struct weston_desktop_surface *dsurface,
555 void *user_data)
556{
557 struct weston_desktop_xdg_popup *popup = user_data;
558 struct weston_desktop_surface *topmost;
559 struct weston_desktop_client *client =
560 weston_desktop_surface_get_client(popup->popup);
561
562 if (!weston_desktop_surface_get_grab(popup->popup))
563 goto end;
564
565 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(popup->seat);
566 if (topmost != popup->popup) {
567 struct wl_resource *client_resource =
568 weston_desktop_client_get_resource(client);
569
570 wl_resource_post_error(client_resource,
571 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
572 "xdg_popup was destroyed while it was not the topmost popup.");
573 }
574
575 weston_desktop_surface_popup_ungrab(popup->popup, popup->seat);
576
577end:
578 free(popup);
579}
580
581static const struct xdg_popup_interface weston_desktop_xdg_popup_implementation = {
582 .destroy = weston_desktop_destroy_request,
583};
584
585static const struct weston_desktop_surface_implementation weston_desktop_xdg_popup_internal_implementation = {
586 .close = weston_desktop_xdg_popup_close,
587
588 .destroy = weston_desktop_xdg_popup_destroy,
589};
590
591static void
592weston_desktop_xdg_shell_protocol_use_unstable_version(struct wl_client *wl_client,
593 struct wl_resource *resource,
594 int32_t version)
595{
596 if (version > 1) {
597 wl_resource_post_error(resource,
598 1, "xdg_shell version not supported");
599 return;
600 }
601}
602
603static void
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200604weston_desktop_xdg_surface_add_idle_callback(void *user_data)
Quentin Glidic248dd102016-08-12 10:41:34 +0200605{
606 struct weston_desktop_xdg_surface *surface = user_data;
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200607
Quentin Glidic248dd102016-08-12 10:41:34 +0200608 surface->add_idle = NULL;
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200609 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200610}
611
612static void
613weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client,
614 struct wl_resource *resource,
615 uint32_t id,
616 struct wl_resource *surface_resource)
617{
618 struct weston_desktop_client *client =
619 wl_resource_get_user_data(resource);
620 struct weston_desktop *desktop =
621 weston_desktop_client_get_desktop(client);
622 struct weston_surface *wsurface =
623 wl_resource_get_user_data(surface_resource);
624 struct weston_desktop_xdg_surface *surface;
625 struct wl_display *display = weston_desktop_get_display(desktop);
626 struct wl_event_loop *loop = wl_display_get_event_loop(display);
627
628 if (weston_surface_set_role(wsurface, "xdg_surface", resource, XDG_SHELL_ERROR_ROLE) < 0)
629 return;
630
631 surface = zalloc(sizeof(struct weston_desktop_xdg_surface));
632 if (surface == NULL) {
633 wl_client_post_no_memory(wl_client);
634 return;
635 }
636
637 surface->desktop = desktop;
638
639 surface->surface =
640 weston_desktop_surface_create(surface->desktop, client,
641 wsurface,
642 &weston_desktop_xdg_surface_internal_implementation,
643 surface);
644 if (surface->surface == NULL) {
645 free(surface);
646 return;
647 }
648
649 surface->resource =
650 weston_desktop_surface_add_resource(surface->surface,
651 &xdg_surface_interface,
652 &weston_desktop_xdg_surface_implementation,
653 id, NULL);
654 if (surface->resource == NULL)
655 return;
656
657 surface->add_idle =
658 wl_event_loop_add_idle(loop,
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200659 weston_desktop_xdg_surface_add_idle_callback,
Quentin Glidic248dd102016-08-12 10:41:34 +0200660 surface);
661}
662
663static void
664weston_desktop_xdg_shell_protocol_get_xdg_popup(struct wl_client *wl_client,
665 struct wl_resource *resource,
666 uint32_t id,
667 struct wl_resource *surface_resource,
668 struct wl_resource *parent_resource,
669 struct wl_resource *seat_resource,
670 uint32_t serial,
671 int32_t x, int32_t y)
672{
673 struct weston_desktop_client *client =
674 wl_resource_get_user_data(resource);
675 struct weston_surface *wsurface =
676 wl_resource_get_user_data(surface_resource);
677 struct weston_surface *wparent =
678 wl_resource_get_user_data(parent_resource);
679 struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
680 struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
681 struct weston_desktop_surface *parent, *topmost;
682 bool parent_is_popup, parent_is_xdg;
683 struct weston_desktop_xdg_popup *popup;
684
685 if (weston_surface_set_role(wsurface, "xdg_popup", resource, XDG_SHELL_ERROR_ROLE) < 0)
686 return;
687
688 if (!weston_surface_is_desktop_surface(wparent)) {
689 wl_resource_post_error(resource,
690 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
691 "xdg_popup parent was invalid");
692 return;
693 }
694
695 parent = weston_surface_get_desktop_surface(wparent);
696 parent_is_xdg =
697 weston_desktop_surface_has_implementation(parent,
698 &weston_desktop_xdg_surface_internal_implementation);
699 parent_is_popup =
700 weston_desktop_surface_has_implementation(parent,
701 &weston_desktop_xdg_popup_internal_implementation);
702
703 if (!parent_is_xdg && !parent_is_popup) {
704 wl_resource_post_error(resource,
705 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
706 "xdg_popup parent was invalid");
707 return;
708 }
709
710 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(seat);
711 if ((topmost == NULL && parent_is_popup) ||
712 (topmost != NULL && topmost != parent)) {
713 wl_resource_post_error(resource,
714 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
715 "xdg_popup was not created on the topmost popup");
716 return;
717 }
718
719 popup = zalloc(sizeof(struct weston_desktop_xdg_popup));
720 if (popup == NULL) {
721 wl_client_post_no_memory(wl_client);
722 return;
723 }
724
725 popup->desktop = weston_desktop_client_get_desktop(client);
726 popup->display = weston_desktop_get_display(popup->desktop);
727 popup->seat = seat;
728
729 popup->popup =
730 weston_desktop_surface_create(popup->desktop, client, wsurface,
731 &weston_desktop_xdg_popup_internal_implementation,
732 popup);
733 if (popup->popup == NULL) {
734 free(popup);
735 return;
736 }
737
738 popup->resource =
739 weston_desktop_surface_add_resource(popup->popup,
740 &xdg_popup_interface,
741 &weston_desktop_xdg_popup_implementation,
742 id, NULL);
743 if (popup->resource == NULL)
744 return;
745
746 weston_desktop_surface_set_relative_to(popup->popup, parent, x, y, false);
747 weston_desktop_surface_popup_grab(popup->popup, popup->seat, serial);
748}
749
750static void
751weston_desktop_xdg_shell_protocol_pong(struct wl_client *wl_client,
752 struct wl_resource *resource,
753 uint32_t serial)
754{
755 struct weston_desktop_client *client =
756 wl_resource_get_user_data(resource);
757
758 weston_desktop_client_pong(client, serial);
759}
760
761static const struct xdg_shell_interface weston_desktop_xdg_shell_implementation = {
762 .destroy = weston_desktop_destroy_request,
763 .use_unstable_version = weston_desktop_xdg_shell_protocol_use_unstable_version,
764 .get_xdg_surface = weston_desktop_xdg_shell_protocol_get_xdg_surface,
765 .get_xdg_popup = weston_desktop_xdg_shell_protocol_get_xdg_popup,
766 .pong = weston_desktop_xdg_shell_protocol_pong,
767};
768
769static int
770xdg_shell_unversioned_dispatch(const void *implementation,
771 void *_target, uint32_t opcode,
772 const struct wl_message *message,
773 union wl_argument *args)
774{
775 struct wl_resource *resource = _target;
776 struct weston_desktop_client *client =
777 wl_resource_get_user_data(resource);
778
779 if (opcode != 1 /* XDG_SHELL_USE_UNSTABLE_VERSION */) {
780 wl_resource_post_error(resource,
781 WL_DISPLAY_ERROR_INVALID_OBJECT,
782 "must call use_unstable_version first");
783 return 0;
784 }
785
786#define XDG_SERVER_VERSION 5
787
788 if (args[0].i != XDG_SERVER_VERSION) {
789 wl_resource_post_error(resource,
790 WL_DISPLAY_ERROR_INVALID_OBJECT,
791 "incompatible version, server is %d " "client wants %d",
792 XDG_SERVER_VERSION, args[0].i);
793 return 0;
794 }
795
796 wl_resource_set_implementation(resource,
797 &weston_desktop_xdg_shell_implementation,
798 client, implementation);
799
800 return 1;
801}
802
803static void
804weston_desktop_xdg_shell_bind(struct wl_client *client, void *data,
805 uint32_t version, uint32_t id)
806{
807 struct weston_desktop *desktop = data;
808
809 weston_desktop_client_create(desktop, client,
810 xdg_shell_unversioned_dispatch,
811 &xdg_shell_interface, NULL, version, id);
812}
813
814struct wl_global *
815weston_desktop_xdg_shell_v5_create(struct weston_desktop *desktop,
816 struct wl_display *display)
817{
818 return wl_global_create(display,
819 &xdg_shell_interface,
820 WD_XDG_SHELL_PROTOCOL_VERSION,
821 desktop, weston_desktop_xdg_shell_bind);
822}