blob: 83e5d309647de16aaedac9c326424c2b928fea5f [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
195 if (wsurface->width == width && wsurface->height == height)
196 return;
197
198 surface->requested_size.width = width;
199 surface->requested_size.height = height;
200 weston_desktop_xdg_surface_schedule_configure(surface);
201}
202
203static void
204weston_desktop_xdg_surface_committed(struct weston_desktop_surface *dsurface,
Quentin Glidic003da882016-08-15 12:21:39 +0200205 void *user_data,
Quentin Glidic248dd102016-08-12 10:41:34 +0200206 int32_t sx, int32_t sy)
207{
208 struct weston_desktop_xdg_surface *surface = user_data;
209 struct weston_surface *wsurface =
210 weston_desktop_surface_get_surface(surface->surface);
211 bool reconfigure = false;
212
213 if (surface->next_state.maximized || surface->next_state.fullscreen)
214 reconfigure = surface->requested_size.width != wsurface->width ||
215 surface->requested_size.height != wsurface->height;
216
217 if (reconfigure) {
218 weston_desktop_xdg_surface_schedule_configure(surface);
219 } else {
220 surface->state = surface->next_state;
221 if (surface->has_next_geometry) {
222 surface->has_next_geometry = false;
223 weston_desktop_surface_set_geometry(surface->surface,
224 surface->next_geometry);
225 }
226
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200227 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200228 weston_desktop_api_committed(surface->desktop, surface->surface,
229 sx, sy);
230 }
231}
232
233static void
234weston_desktop_xdg_surface_ping(struct weston_desktop_surface *dsurface,
235 uint32_t serial, void *user_data)
236{
237 struct weston_desktop_client *client =
238 weston_desktop_surface_get_client(dsurface);
239
240 xdg_shell_send_ping(weston_desktop_client_get_resource(client),
241 serial);
242}
243
244static void
245weston_desktop_xdg_surface_close(struct weston_desktop_surface *dsurface,
246 void *user_data)
247{
248 struct weston_desktop_xdg_surface *surface = user_data;
249
250 xdg_surface_send_close(surface->resource);
251}
252
253static bool
254weston_desktop_xdg_surface_get_maximized(struct weston_desktop_surface *dsurface,
255 void *user_data)
256{
257 struct weston_desktop_xdg_surface *surface = user_data;
258
259 return surface->state.maximized;
260}
261
262static bool
263weston_desktop_xdg_surface_get_fullscreen(struct weston_desktop_surface *dsurface,
264 void *user_data)
265{
266 struct weston_desktop_xdg_surface *surface = user_data;
267
268 return surface->state.fullscreen;
269}
270
271static bool
272weston_desktop_xdg_surface_get_resizing(struct weston_desktop_surface *dsurface,
273 void *user_data)
274{
275 struct weston_desktop_xdg_surface *surface = user_data;
276
277 return surface->state.resizing;
278}
279
280static bool
281weston_desktop_xdg_surface_get_activated(struct weston_desktop_surface *dsurface,
282 void *user_data)
283{
284 struct weston_desktop_xdg_surface *surface = user_data;
285
286 return surface->state.activated;
287}
288
289static void
290weston_desktop_xdg_surface_destroy(struct weston_desktop_surface *dsurface,
291 void *user_data)
292{
293 struct weston_desktop_xdg_surface *surface = user_data;
294
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200295 if (surface->added)
296 weston_desktop_api_surface_removed(surface->desktop,
297 surface->surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200298
299 if (surface->add_idle != NULL)
300 wl_event_source_remove(surface->add_idle);
301
302 if (surface->configure_idle != NULL)
303 wl_event_source_remove(surface->configure_idle);
304
305 free(surface);
306}
307
308static void
309weston_desktop_xdg_surface_protocol_set_parent(struct wl_client *wl_client,
310 struct wl_resource *resource,
311 struct wl_resource *parent_resource)
312{
313 struct weston_desktop_surface *dsurface =
314 wl_resource_get_user_data(resource);
315 struct weston_desktop_xdg_surface *surface =
316 weston_desktop_surface_get_implementation_data(dsurface);
317 struct weston_desktop_surface *parent = NULL;
318
319 if (parent_resource != NULL)
320 parent = wl_resource_get_user_data(parent_resource);
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200321
322 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200323 weston_desktop_api_set_parent(surface->desktop, dsurface, parent);
324}
325
326static void
327weston_desktop_xdg_surface_protocol_set_title(struct wl_client *wl_client,
328 struct wl_resource *resource,
329 const char *title)
330{
331 struct weston_desktop_surface *surface =
332 wl_resource_get_user_data(resource);
333
334 weston_desktop_surface_set_title(surface, title);
335}
336
337static void
338weston_desktop_xdg_surface_protocol_set_app_id(struct wl_client *wl_client,
339 struct wl_resource *resource,
340 const char *app_id)
341{
342 struct weston_desktop_surface *surface =
343 wl_resource_get_user_data(resource);
344
345 weston_desktop_surface_set_app_id(surface, app_id);
346}
347
348static void
349weston_desktop_xdg_surface_protocol_show_window_menu(struct wl_client *wl_client,
350 struct wl_resource *resource,
351 struct wl_resource *seat_resource,
352 uint32_t serial,
353 int32_t x, int32_t y)
354{
355 struct weston_desktop_surface *dsurface =
356 wl_resource_get_user_data(resource);
357 struct weston_seat *seat =
358 wl_resource_get_user_data(seat_resource);
359 struct weston_desktop_xdg_surface *surface =
360 weston_desktop_surface_get_implementation_data(dsurface);
361
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200362 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200363 weston_desktop_api_show_window_menu(surface->desktop, dsurface, seat, x, y);
364}
365
366static void
367weston_desktop_xdg_surface_protocol_move(struct wl_client *wl_client,
368 struct wl_resource *resource,
369 struct wl_resource *seat_resource,
370 uint32_t serial)
371{
372 struct weston_desktop_surface *dsurface =
373 wl_resource_get_user_data(resource);
374 struct weston_seat *seat =
375 wl_resource_get_user_data(seat_resource);
376 struct weston_desktop_xdg_surface *surface =
377 weston_desktop_surface_get_implementation_data(dsurface);
378
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200379 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200380 weston_desktop_api_move(surface->desktop, dsurface, seat, serial);
381}
382
383static void
384weston_desktop_xdg_surface_protocol_resize(struct wl_client *wl_client,
385 struct wl_resource *resource,
386 struct wl_resource *seat_resource,
387 uint32_t serial,
388 enum xdg_surface_resize_edge edges)
389{
390 struct weston_desktop_surface *dsurface =
391 wl_resource_get_user_data(resource);
392 struct weston_seat *seat =
393 wl_resource_get_user_data(seat_resource);
394 struct weston_desktop_xdg_surface *surface =
395 weston_desktop_surface_get_implementation_data(dsurface);
396
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200397 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200398 weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, edges);
399}
400
401static void
402weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client,
403 struct wl_resource *resource,
404 uint32_t serial)
405{
406 struct weston_desktop_surface *dsurface =
407 wl_resource_get_user_data(resource);
408 struct weston_desktop_xdg_surface *surface =
409 weston_desktop_surface_get_implementation_data(dsurface);
410
411 if (surface->configure_serial != serial)
412 return;
413
414 surface->next_state = surface->requested_state;
415}
416
417static void
418weston_desktop_xdg_surface_protocol_set_window_geometry(struct wl_client *wl_client,
419 struct wl_resource *resource,
420 int32_t x, int32_t y,
421 int32_t width, int32_t height)
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 surface->has_next_geometry = true;
429 surface->next_geometry.x = x;
430 surface->next_geometry.y = y;
431 surface->next_geometry.width = width;
432 surface->next_geometry.height = height;
433}
434
435static void
436weston_desktop_xdg_surface_protocol_set_maximized(struct wl_client *wl_client,
437 struct wl_resource *resource)
438{
439 struct weston_desktop_surface *dsurface =
440 wl_resource_get_user_data(resource);
441 struct weston_desktop_xdg_surface *surface =
442 weston_desktop_surface_get_implementation_data(dsurface);
443
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200444 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200445 weston_desktop_api_maximized_requested(surface->desktop, dsurface, true);
446}
447
448static void
449weston_desktop_xdg_surface_protocol_unset_maximized(struct wl_client *wl_client,
450 struct wl_resource *resource)
451{
452 struct weston_desktop_surface *dsurface =
453 wl_resource_get_user_data(resource);
454 struct weston_desktop_xdg_surface *surface =
455 weston_desktop_surface_get_implementation_data(dsurface);
456
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200457 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200458 weston_desktop_api_maximized_requested(surface->desktop, dsurface, false);
459}
460
461static void
462weston_desktop_xdg_surface_protocol_set_fullscreen(struct wl_client *wl_client,
463 struct wl_resource *resource,
464 struct wl_resource *output_resource)
465{
466 struct weston_desktop_surface *dsurface =
467 wl_resource_get_user_data(resource);
468 struct weston_desktop_xdg_surface *surface =
469 weston_desktop_surface_get_implementation_data(dsurface);
470 struct weston_output *output = NULL;
471
472 if (output_resource != NULL)
473 output = wl_resource_get_user_data(output_resource);
474
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200475 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200476 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
477 true, output);
478}
479
480static void
481weston_desktop_xdg_surface_protocol_unset_fullscreen(struct wl_client *wl_client,
482 struct wl_resource *resource)
483{
484 struct weston_desktop_surface *dsurface =
485 wl_resource_get_user_data(resource);
486 struct weston_desktop_xdg_surface *surface =
487 weston_desktop_surface_get_implementation_data(dsurface);
488
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200489 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200490 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
491 false, NULL);
492}
493
494static void
495weston_desktop_xdg_surface_protocol_set_minimized(struct wl_client *wl_client,
496 struct wl_resource *resource)
497{
498 struct weston_desktop_surface *dsurface =
499 wl_resource_get_user_data(resource);
500 struct weston_desktop_xdg_surface *surface =
501 weston_desktop_surface_get_implementation_data(dsurface);
502
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200503 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200504 weston_desktop_api_minimized_requested(surface->desktop, dsurface);
505}
506
507static const struct xdg_surface_interface weston_desktop_xdg_surface_implementation = {
508 .destroy = weston_desktop_destroy_request,
509 .set_parent = weston_desktop_xdg_surface_protocol_set_parent,
510 .set_title = weston_desktop_xdg_surface_protocol_set_title,
511 .set_app_id = weston_desktop_xdg_surface_protocol_set_app_id,
512 .show_window_menu = weston_desktop_xdg_surface_protocol_show_window_menu,
513 .move = weston_desktop_xdg_surface_protocol_move,
514 .resize = weston_desktop_xdg_surface_protocol_resize,
515 .ack_configure = weston_desktop_xdg_surface_protocol_ack_configure,
516 .set_window_geometry = weston_desktop_xdg_surface_protocol_set_window_geometry,
517 .set_maximized = weston_desktop_xdg_surface_protocol_set_maximized,
518 .unset_maximized = weston_desktop_xdg_surface_protocol_unset_maximized,
519 .set_fullscreen = weston_desktop_xdg_surface_protocol_set_fullscreen,
520 .unset_fullscreen = weston_desktop_xdg_surface_protocol_unset_fullscreen,
521 .set_minimized = weston_desktop_xdg_surface_protocol_set_minimized,
522};
523
524static const struct weston_desktop_surface_implementation weston_desktop_xdg_surface_internal_implementation = {
525 .set_maximized = weston_desktop_xdg_surface_set_maximized,
526 .set_fullscreen = weston_desktop_xdg_surface_set_fullscreen,
527 .set_resizing = weston_desktop_xdg_surface_set_resizing,
528 .set_activated = weston_desktop_xdg_surface_set_activated,
529 .set_size = weston_desktop_xdg_surface_set_size,
530 .committed = weston_desktop_xdg_surface_committed,
531 .ping = weston_desktop_xdg_surface_ping,
532 .close = weston_desktop_xdg_surface_close,
533
534 .get_maximized = weston_desktop_xdg_surface_get_maximized,
535 .get_fullscreen = weston_desktop_xdg_surface_get_fullscreen,
536 .get_resizing = weston_desktop_xdg_surface_get_resizing,
537 .get_activated = weston_desktop_xdg_surface_get_activated,
538
539 .destroy = weston_desktop_xdg_surface_destroy,
540};
541
542static void
543weston_desktop_xdg_popup_close(struct weston_desktop_surface *dsurface,
544 void *user_data)
545{
546 struct weston_desktop_xdg_popup *popup = user_data;
547
548 xdg_popup_send_popup_done(popup->resource);
549}
550
551static void
552weston_desktop_xdg_popup_destroy(struct weston_desktop_surface *dsurface,
553 void *user_data)
554{
555 struct weston_desktop_xdg_popup *popup = user_data;
556 struct weston_desktop_surface *topmost;
557 struct weston_desktop_client *client =
558 weston_desktop_surface_get_client(popup->popup);
559
560 if (!weston_desktop_surface_get_grab(popup->popup))
561 goto end;
562
563 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(popup->seat);
564 if (topmost != popup->popup) {
565 struct wl_resource *client_resource =
566 weston_desktop_client_get_resource(client);
567
568 wl_resource_post_error(client_resource,
569 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
570 "xdg_popup was destroyed while it was not the topmost popup.");
571 }
572
573 weston_desktop_surface_popup_ungrab(popup->popup, popup->seat);
574
575end:
576 free(popup);
577}
578
579static const struct xdg_popup_interface weston_desktop_xdg_popup_implementation = {
580 .destroy = weston_desktop_destroy_request,
581};
582
583static const struct weston_desktop_surface_implementation weston_desktop_xdg_popup_internal_implementation = {
584 .close = weston_desktop_xdg_popup_close,
585
586 .destroy = weston_desktop_xdg_popup_destroy,
587};
588
589static void
590weston_desktop_xdg_shell_protocol_use_unstable_version(struct wl_client *wl_client,
591 struct wl_resource *resource,
592 int32_t version)
593{
594 if (version > 1) {
595 wl_resource_post_error(resource,
596 1, "xdg_shell version not supported");
597 return;
598 }
599}
600
601static void
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200602weston_desktop_xdg_surface_add_idle_callback(void *user_data)
Quentin Glidic248dd102016-08-12 10:41:34 +0200603{
604 struct weston_desktop_xdg_surface *surface = user_data;
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200605
Quentin Glidic248dd102016-08-12 10:41:34 +0200606 surface->add_idle = NULL;
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200607 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200608}
609
610static void
611weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client,
612 struct wl_resource *resource,
613 uint32_t id,
614 struct wl_resource *surface_resource)
615{
616 struct weston_desktop_client *client =
617 wl_resource_get_user_data(resource);
618 struct weston_desktop *desktop =
619 weston_desktop_client_get_desktop(client);
620 struct weston_surface *wsurface =
621 wl_resource_get_user_data(surface_resource);
622 struct weston_desktop_xdg_surface *surface;
623 struct wl_display *display = weston_desktop_get_display(desktop);
624 struct wl_event_loop *loop = wl_display_get_event_loop(display);
625
626 if (weston_surface_set_role(wsurface, "xdg_surface", resource, XDG_SHELL_ERROR_ROLE) < 0)
627 return;
628
629 surface = zalloc(sizeof(struct weston_desktop_xdg_surface));
630 if (surface == NULL) {
631 wl_client_post_no_memory(wl_client);
632 return;
633 }
634
635 surface->desktop = desktop;
636
637 surface->surface =
638 weston_desktop_surface_create(surface->desktop, client,
639 wsurface,
640 &weston_desktop_xdg_surface_internal_implementation,
641 surface);
642 if (surface->surface == NULL) {
643 free(surface);
644 return;
645 }
646
647 surface->resource =
648 weston_desktop_surface_add_resource(surface->surface,
649 &xdg_surface_interface,
650 &weston_desktop_xdg_surface_implementation,
651 id, NULL);
652 if (surface->resource == NULL)
653 return;
654
655 surface->add_idle =
656 wl_event_loop_add_idle(loop,
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200657 weston_desktop_xdg_surface_add_idle_callback,
Quentin Glidic248dd102016-08-12 10:41:34 +0200658 surface);
659}
660
661static void
662weston_desktop_xdg_shell_protocol_get_xdg_popup(struct wl_client *wl_client,
663 struct wl_resource *resource,
664 uint32_t id,
665 struct wl_resource *surface_resource,
666 struct wl_resource *parent_resource,
667 struct wl_resource *seat_resource,
668 uint32_t serial,
669 int32_t x, int32_t y)
670{
671 struct weston_desktop_client *client =
672 wl_resource_get_user_data(resource);
673 struct weston_surface *wsurface =
674 wl_resource_get_user_data(surface_resource);
675 struct weston_surface *wparent =
676 wl_resource_get_user_data(parent_resource);
677 struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
678 struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
679 struct weston_desktop_surface *parent, *topmost;
680 bool parent_is_popup, parent_is_xdg;
681 struct weston_desktop_xdg_popup *popup;
682
683 if (weston_surface_set_role(wsurface, "xdg_popup", resource, XDG_SHELL_ERROR_ROLE) < 0)
684 return;
685
686 if (!weston_surface_is_desktop_surface(wparent)) {
687 wl_resource_post_error(resource,
688 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
689 "xdg_popup parent was invalid");
690 return;
691 }
692
693 parent = weston_surface_get_desktop_surface(wparent);
694 parent_is_xdg =
695 weston_desktop_surface_has_implementation(parent,
696 &weston_desktop_xdg_surface_internal_implementation);
697 parent_is_popup =
698 weston_desktop_surface_has_implementation(parent,
699 &weston_desktop_xdg_popup_internal_implementation);
700
701 if (!parent_is_xdg && !parent_is_popup) {
702 wl_resource_post_error(resource,
703 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
704 "xdg_popup parent was invalid");
705 return;
706 }
707
708 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(seat);
709 if ((topmost == NULL && parent_is_popup) ||
710 (topmost != NULL && topmost != parent)) {
711 wl_resource_post_error(resource,
712 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
713 "xdg_popup was not created on the topmost popup");
714 return;
715 }
716
717 popup = zalloc(sizeof(struct weston_desktop_xdg_popup));
718 if (popup == NULL) {
719 wl_client_post_no_memory(wl_client);
720 return;
721 }
722
723 popup->desktop = weston_desktop_client_get_desktop(client);
724 popup->display = weston_desktop_get_display(popup->desktop);
725 popup->seat = seat;
726
727 popup->popup =
728 weston_desktop_surface_create(popup->desktop, client, wsurface,
729 &weston_desktop_xdg_popup_internal_implementation,
730 popup);
731 if (popup->popup == NULL) {
732 free(popup);
733 return;
734 }
735
736 popup->resource =
737 weston_desktop_surface_add_resource(popup->popup,
738 &xdg_popup_interface,
739 &weston_desktop_xdg_popup_implementation,
740 id, NULL);
741 if (popup->resource == NULL)
742 return;
743
744 weston_desktop_surface_set_relative_to(popup->popup, parent, x, y, false);
745 weston_desktop_surface_popup_grab(popup->popup, popup->seat, serial);
746}
747
748static void
749weston_desktop_xdg_shell_protocol_pong(struct wl_client *wl_client,
750 struct wl_resource *resource,
751 uint32_t serial)
752{
753 struct weston_desktop_client *client =
754 wl_resource_get_user_data(resource);
755
756 weston_desktop_client_pong(client, serial);
757}
758
759static const struct xdg_shell_interface weston_desktop_xdg_shell_implementation = {
760 .destroy = weston_desktop_destroy_request,
761 .use_unstable_version = weston_desktop_xdg_shell_protocol_use_unstable_version,
762 .get_xdg_surface = weston_desktop_xdg_shell_protocol_get_xdg_surface,
763 .get_xdg_popup = weston_desktop_xdg_shell_protocol_get_xdg_popup,
764 .pong = weston_desktop_xdg_shell_protocol_pong,
765};
766
767static int
768xdg_shell_unversioned_dispatch(const void *implementation,
769 void *_target, uint32_t opcode,
770 const struct wl_message *message,
771 union wl_argument *args)
772{
773 struct wl_resource *resource = _target;
774 struct weston_desktop_client *client =
775 wl_resource_get_user_data(resource);
776
777 if (opcode != 1 /* XDG_SHELL_USE_UNSTABLE_VERSION */) {
778 wl_resource_post_error(resource,
779 WL_DISPLAY_ERROR_INVALID_OBJECT,
780 "must call use_unstable_version first");
781 return 0;
782 }
783
784#define XDG_SERVER_VERSION 5
785
786 if (args[0].i != XDG_SERVER_VERSION) {
787 wl_resource_post_error(resource,
788 WL_DISPLAY_ERROR_INVALID_OBJECT,
789 "incompatible version, server is %d " "client wants %d",
790 XDG_SERVER_VERSION, args[0].i);
791 return 0;
792 }
793
794 wl_resource_set_implementation(resource,
795 &weston_desktop_xdg_shell_implementation,
796 client, implementation);
797
798 return 1;
799}
800
801static void
802weston_desktop_xdg_shell_bind(struct wl_client *client, void *data,
803 uint32_t version, uint32_t id)
804{
805 struct weston_desktop *desktop = data;
806
807 weston_desktop_client_create(desktop, client,
808 xdg_shell_unversioned_dispatch,
809 &xdg_shell_interface, NULL, version, id);
810}
811
812struct wl_global *
813weston_desktop_xdg_shell_v5_create(struct weston_desktop *desktop,
814 struct wl_display *display)
815{
816 return wl_global_create(display,
817 &xdg_shell_interface,
818 WD_XDG_SHELL_PROTOCOL_VERSION,
819 desktop, weston_desktop_xdg_shell_bind);
820}