blob: 1ec796e1e7c8c7602661f6d2b45755508bf3c3b8 [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"
Daniel Stone7dbb0e12016-11-24 15:30:41 +000035#include "xdg-shell-unstable-v5-server-protocol.h"
Quentin Glidic248dd102016-08-12 10:41:34 +020036
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
Quentin Glidicd51f8262017-04-13 20:25:27 +0200121static bool
122weston_desktop_xdg_surface_state_compare(struct weston_desktop_xdg_surface *surface)
123{
124 struct weston_surface *wsurface =
125 weston_desktop_surface_get_surface(surface->surface);
126
127 if (surface->requested_state.activated != surface->state.activated)
128 return false;
129 if (surface->requested_state.fullscreen != surface->state.fullscreen)
130 return false;
131 if (surface->requested_state.maximized != surface->state.maximized)
132 return false;
133 if (surface->requested_state.resizing != surface->state.resizing)
134 return false;
135
136 if (wsurface->width == surface->requested_size.width &&
137 wsurface->height == surface->requested_size.height)
138 return true;
139
140 if (surface->requested_size.width == 0 &&
141 surface->requested_size.height == 0)
142 return true;
143
144 return false;
145}
146
Quentin Glidic248dd102016-08-12 10:41:34 +0200147static void
Quentin Glidicd51f8262017-04-13 20:25:27 +0200148weston_desktop_xdg_surface_schedule_configure(struct weston_desktop_xdg_surface *surface,
149 bool force)
Quentin Glidic248dd102016-08-12 10:41:34 +0200150{
151 struct wl_display *display = weston_desktop_get_display(surface->desktop);
152 struct wl_event_loop *loop = wl_display_get_event_loop(display);
Quentin Glidicd51f8262017-04-13 20:25:27 +0200153 bool requested_same =
154 !force && weston_desktop_xdg_surface_state_compare(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200155
Quentin Glidicd51f8262017-04-13 20:25:27 +0200156 if (surface->configure_idle != NULL) {
157 if (!requested_same)
158 return;
159
160 wl_event_source_remove(surface->configure_idle);
161 surface->configure_idle = NULL;
162 } else {
163 if (requested_same)
164 return;
165
166 surface->configure_idle =
167 wl_event_loop_add_idle(loop,
168 weston_desktop_xdg_surface_send_configure,
169 surface);
170 }
Quentin Glidic248dd102016-08-12 10:41:34 +0200171}
172
173static void
174weston_desktop_xdg_surface_set_maximized(struct weston_desktop_surface *dsurface,
175 void *user_data, bool maximized)
176{
177 struct weston_desktop_xdg_surface *surface = user_data;
178
Quentin Glidic248dd102016-08-12 10:41:34 +0200179 surface->requested_state.maximized = maximized;
Quentin Glidicd51f8262017-04-13 20:25:27 +0200180 weston_desktop_xdg_surface_schedule_configure(surface, false);
Quentin Glidic248dd102016-08-12 10:41:34 +0200181}
182
183static void
184weston_desktop_xdg_surface_set_fullscreen(struct weston_desktop_surface *dsurface,
185 void *user_data, bool fullscreen)
186{
187 struct weston_desktop_xdg_surface *surface = user_data;
188
Quentin Glidic248dd102016-08-12 10:41:34 +0200189 surface->requested_state.fullscreen = fullscreen;
Quentin Glidicd51f8262017-04-13 20:25:27 +0200190 weston_desktop_xdg_surface_schedule_configure(surface, false);
Quentin Glidic248dd102016-08-12 10:41:34 +0200191}
192
193static void
194weston_desktop_xdg_surface_set_resizing(struct weston_desktop_surface *dsurface,
195 void *user_data, bool resizing)
196{
197 struct weston_desktop_xdg_surface *surface = user_data;
198
Quentin Glidic248dd102016-08-12 10:41:34 +0200199 surface->requested_state.resizing = resizing;
Quentin Glidicd51f8262017-04-13 20:25:27 +0200200 weston_desktop_xdg_surface_schedule_configure(surface, false);
Quentin Glidic248dd102016-08-12 10:41:34 +0200201}
202
203static void
204weston_desktop_xdg_surface_set_activated(struct weston_desktop_surface *dsurface,
205 void *user_data, bool activated)
206{
207 struct weston_desktop_xdg_surface *surface = user_data;
208
Quentin Glidic248dd102016-08-12 10:41:34 +0200209 surface->requested_state.activated = activated;
Quentin Glidicd51f8262017-04-13 20:25:27 +0200210 weston_desktop_xdg_surface_schedule_configure(surface, false);
Quentin Glidic248dd102016-08-12 10:41:34 +0200211}
212
213static void
214weston_desktop_xdg_surface_set_size(struct weston_desktop_surface *dsurface,
215 void *user_data,
216 int32_t width, int32_t height)
217{
218 struct weston_desktop_xdg_surface *surface = user_data;
Quentin Glidic248dd102016-08-12 10:41:34 +0200219
Quentin Glidic248dd102016-08-12 10:41:34 +0200220 surface->requested_size.width = width;
221 surface->requested_size.height = height;
Quentin Glidica56b0532016-09-13 10:05:58 +0200222
Quentin Glidicd51f8262017-04-13 20:25:27 +0200223 weston_desktop_xdg_surface_schedule_configure(surface, false);
Quentin Glidic248dd102016-08-12 10:41:34 +0200224}
225
226static void
227weston_desktop_xdg_surface_committed(struct weston_desktop_surface *dsurface,
Quentin Glidic003da882016-08-15 12:21:39 +0200228 void *user_data,
Quentin Glidic248dd102016-08-12 10:41:34 +0200229 int32_t sx, int32_t sy)
230{
231 struct weston_desktop_xdg_surface *surface = user_data;
232 struct weston_surface *wsurface =
233 weston_desktop_surface_get_surface(surface->surface);
234 bool reconfigure = false;
235
236 if (surface->next_state.maximized || surface->next_state.fullscreen)
237 reconfigure = surface->requested_size.width != wsurface->width ||
238 surface->requested_size.height != wsurface->height;
239
240 if (reconfigure) {
Quentin Glidicd51f8262017-04-13 20:25:27 +0200241 weston_desktop_xdg_surface_schedule_configure(surface, true);
Quentin Glidic248dd102016-08-12 10:41:34 +0200242 } else {
243 surface->state = surface->next_state;
244 if (surface->has_next_geometry) {
245 surface->has_next_geometry = false;
246 weston_desktop_surface_set_geometry(surface->surface,
247 surface->next_geometry);
248 }
249
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200250 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200251 weston_desktop_api_committed(surface->desktop, surface->surface,
252 sx, sy);
253 }
254}
255
256static void
257weston_desktop_xdg_surface_ping(struct weston_desktop_surface *dsurface,
258 uint32_t serial, void *user_data)
259{
260 struct weston_desktop_client *client =
261 weston_desktop_surface_get_client(dsurface);
262
263 xdg_shell_send_ping(weston_desktop_client_get_resource(client),
264 serial);
265}
266
267static void
268weston_desktop_xdg_surface_close(struct weston_desktop_surface *dsurface,
269 void *user_data)
270{
271 struct weston_desktop_xdg_surface *surface = user_data;
272
273 xdg_surface_send_close(surface->resource);
274}
275
276static bool
277weston_desktop_xdg_surface_get_maximized(struct weston_desktop_surface *dsurface,
278 void *user_data)
279{
280 struct weston_desktop_xdg_surface *surface = user_data;
281
282 return surface->state.maximized;
283}
284
285static bool
286weston_desktop_xdg_surface_get_fullscreen(struct weston_desktop_surface *dsurface,
287 void *user_data)
288{
289 struct weston_desktop_xdg_surface *surface = user_data;
290
291 return surface->state.fullscreen;
292}
293
294static bool
295weston_desktop_xdg_surface_get_resizing(struct weston_desktop_surface *dsurface,
296 void *user_data)
297{
298 struct weston_desktop_xdg_surface *surface = user_data;
299
300 return surface->state.resizing;
301}
302
303static bool
304weston_desktop_xdg_surface_get_activated(struct weston_desktop_surface *dsurface,
305 void *user_data)
306{
307 struct weston_desktop_xdg_surface *surface = user_data;
308
309 return surface->state.activated;
310}
311
312static void
313weston_desktop_xdg_surface_destroy(struct weston_desktop_surface *dsurface,
314 void *user_data)
315{
316 struct weston_desktop_xdg_surface *surface = user_data;
317
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200318 if (surface->added)
319 weston_desktop_api_surface_removed(surface->desktop,
320 surface->surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200321
322 if (surface->add_idle != NULL)
323 wl_event_source_remove(surface->add_idle);
324
325 if (surface->configure_idle != NULL)
326 wl_event_source_remove(surface->configure_idle);
327
328 free(surface);
329}
330
331static void
332weston_desktop_xdg_surface_protocol_set_parent(struct wl_client *wl_client,
333 struct wl_resource *resource,
334 struct wl_resource *parent_resource)
335{
336 struct weston_desktop_surface *dsurface =
337 wl_resource_get_user_data(resource);
338 struct weston_desktop_xdg_surface *surface =
339 weston_desktop_surface_get_implementation_data(dsurface);
340 struct weston_desktop_surface *parent = NULL;
341
342 if (parent_resource != NULL)
343 parent = wl_resource_get_user_data(parent_resource);
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200344
345 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200346 weston_desktop_api_set_parent(surface->desktop, dsurface, parent);
347}
348
349static void
350weston_desktop_xdg_surface_protocol_set_title(struct wl_client *wl_client,
351 struct wl_resource *resource,
352 const char *title)
353{
354 struct weston_desktop_surface *surface =
355 wl_resource_get_user_data(resource);
356
357 weston_desktop_surface_set_title(surface, title);
358}
359
360static void
361weston_desktop_xdg_surface_protocol_set_app_id(struct wl_client *wl_client,
362 struct wl_resource *resource,
363 const char *app_id)
364{
365 struct weston_desktop_surface *surface =
366 wl_resource_get_user_data(resource);
367
368 weston_desktop_surface_set_app_id(surface, app_id);
369}
370
371static void
372weston_desktop_xdg_surface_protocol_show_window_menu(struct wl_client *wl_client,
373 struct wl_resource *resource,
374 struct wl_resource *seat_resource,
375 uint32_t serial,
376 int32_t x, int32_t y)
377{
378 struct weston_desktop_surface *dsurface =
379 wl_resource_get_user_data(resource);
380 struct weston_seat *seat =
381 wl_resource_get_user_data(seat_resource);
382 struct weston_desktop_xdg_surface *surface =
383 weston_desktop_surface_get_implementation_data(dsurface);
384
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200385 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200386 weston_desktop_api_show_window_menu(surface->desktop, dsurface, seat, x, y);
387}
388
389static void
390weston_desktop_xdg_surface_protocol_move(struct wl_client *wl_client,
391 struct wl_resource *resource,
392 struct wl_resource *seat_resource,
393 uint32_t serial)
394{
395 struct weston_desktop_surface *dsurface =
396 wl_resource_get_user_data(resource);
397 struct weston_seat *seat =
398 wl_resource_get_user_data(seat_resource);
399 struct weston_desktop_xdg_surface *surface =
400 weston_desktop_surface_get_implementation_data(dsurface);
401
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200402 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200403 weston_desktop_api_move(surface->desktop, dsurface, seat, serial);
404}
405
406static void
407weston_desktop_xdg_surface_protocol_resize(struct wl_client *wl_client,
408 struct wl_resource *resource,
409 struct wl_resource *seat_resource,
410 uint32_t serial,
411 enum xdg_surface_resize_edge edges)
412{
413 struct weston_desktop_surface *dsurface =
414 wl_resource_get_user_data(resource);
415 struct weston_seat *seat =
416 wl_resource_get_user_data(seat_resource);
417 struct weston_desktop_xdg_surface *surface =
418 weston_desktop_surface_get_implementation_data(dsurface);
Armin Krezović4e2fa0a2016-09-10 19:11:21 +0200419 enum weston_desktop_surface_edge surf_edges =
420 (enum weston_desktop_surface_edge) edges;
Quentin Glidic248dd102016-08-12 10:41:34 +0200421
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200422 weston_desktop_xdg_surface_ensure_added(surface);
Armin Krezović4e2fa0a2016-09-10 19:11:21 +0200423 weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, surf_edges);
Quentin Glidic248dd102016-08-12 10:41:34 +0200424}
425
426static void
427weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client,
428 struct wl_resource *resource,
429 uint32_t serial)
430{
431 struct weston_desktop_surface *dsurface =
432 wl_resource_get_user_data(resource);
433 struct weston_desktop_xdg_surface *surface =
434 weston_desktop_surface_get_implementation_data(dsurface);
435
436 if (surface->configure_serial != serial)
437 return;
438
439 surface->next_state = surface->requested_state;
440}
441
442static void
443weston_desktop_xdg_surface_protocol_set_window_geometry(struct wl_client *wl_client,
444 struct wl_resource *resource,
445 int32_t x, int32_t y,
446 int32_t width, int32_t height)
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
453 surface->has_next_geometry = true;
454 surface->next_geometry.x = x;
455 surface->next_geometry.y = y;
456 surface->next_geometry.width = width;
457 surface->next_geometry.height = height;
458}
459
460static void
461weston_desktop_xdg_surface_protocol_set_maximized(struct wl_client *wl_client,
462 struct wl_resource *resource)
463{
464 struct weston_desktop_surface *dsurface =
465 wl_resource_get_user_data(resource);
466 struct weston_desktop_xdg_surface *surface =
467 weston_desktop_surface_get_implementation_data(dsurface);
468
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200469 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200470 weston_desktop_api_maximized_requested(surface->desktop, dsurface, true);
471}
472
473static void
474weston_desktop_xdg_surface_protocol_unset_maximized(struct wl_client *wl_client,
475 struct wl_resource *resource)
476{
477 struct weston_desktop_surface *dsurface =
478 wl_resource_get_user_data(resource);
479 struct weston_desktop_xdg_surface *surface =
480 weston_desktop_surface_get_implementation_data(dsurface);
481
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200482 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200483 weston_desktop_api_maximized_requested(surface->desktop, dsurface, false);
484}
485
486static void
487weston_desktop_xdg_surface_protocol_set_fullscreen(struct wl_client *wl_client,
488 struct wl_resource *resource,
489 struct wl_resource *output_resource)
490{
491 struct weston_desktop_surface *dsurface =
492 wl_resource_get_user_data(resource);
493 struct weston_desktop_xdg_surface *surface =
494 weston_desktop_surface_get_implementation_data(dsurface);
495 struct weston_output *output = NULL;
496
497 if (output_resource != NULL)
498 output = wl_resource_get_user_data(output_resource);
499
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200500 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200501 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
502 true, output);
503}
504
505static void
506weston_desktop_xdg_surface_protocol_unset_fullscreen(struct wl_client *wl_client,
507 struct wl_resource *resource)
508{
509 struct weston_desktop_surface *dsurface =
510 wl_resource_get_user_data(resource);
511 struct weston_desktop_xdg_surface *surface =
512 weston_desktop_surface_get_implementation_data(dsurface);
513
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200514 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200515 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
516 false, NULL);
517}
518
519static void
520weston_desktop_xdg_surface_protocol_set_minimized(struct wl_client *wl_client,
521 struct wl_resource *resource)
522{
523 struct weston_desktop_surface *dsurface =
524 wl_resource_get_user_data(resource);
525 struct weston_desktop_xdg_surface *surface =
526 weston_desktop_surface_get_implementation_data(dsurface);
527
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200528 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200529 weston_desktop_api_minimized_requested(surface->desktop, dsurface);
530}
531
532static const struct xdg_surface_interface weston_desktop_xdg_surface_implementation = {
533 .destroy = weston_desktop_destroy_request,
534 .set_parent = weston_desktop_xdg_surface_protocol_set_parent,
535 .set_title = weston_desktop_xdg_surface_protocol_set_title,
536 .set_app_id = weston_desktop_xdg_surface_protocol_set_app_id,
537 .show_window_menu = weston_desktop_xdg_surface_protocol_show_window_menu,
538 .move = weston_desktop_xdg_surface_protocol_move,
539 .resize = weston_desktop_xdg_surface_protocol_resize,
540 .ack_configure = weston_desktop_xdg_surface_protocol_ack_configure,
541 .set_window_geometry = weston_desktop_xdg_surface_protocol_set_window_geometry,
542 .set_maximized = weston_desktop_xdg_surface_protocol_set_maximized,
543 .unset_maximized = weston_desktop_xdg_surface_protocol_unset_maximized,
544 .set_fullscreen = weston_desktop_xdg_surface_protocol_set_fullscreen,
545 .unset_fullscreen = weston_desktop_xdg_surface_protocol_unset_fullscreen,
546 .set_minimized = weston_desktop_xdg_surface_protocol_set_minimized,
547};
548
549static const struct weston_desktop_surface_implementation weston_desktop_xdg_surface_internal_implementation = {
550 .set_maximized = weston_desktop_xdg_surface_set_maximized,
551 .set_fullscreen = weston_desktop_xdg_surface_set_fullscreen,
552 .set_resizing = weston_desktop_xdg_surface_set_resizing,
553 .set_activated = weston_desktop_xdg_surface_set_activated,
554 .set_size = weston_desktop_xdg_surface_set_size,
555 .committed = weston_desktop_xdg_surface_committed,
556 .ping = weston_desktop_xdg_surface_ping,
557 .close = weston_desktop_xdg_surface_close,
558
559 .get_maximized = weston_desktop_xdg_surface_get_maximized,
560 .get_fullscreen = weston_desktop_xdg_surface_get_fullscreen,
561 .get_resizing = weston_desktop_xdg_surface_get_resizing,
562 .get_activated = weston_desktop_xdg_surface_get_activated,
563
564 .destroy = weston_desktop_xdg_surface_destroy,
565};
566
567static void
568weston_desktop_xdg_popup_close(struct weston_desktop_surface *dsurface,
569 void *user_data)
570{
571 struct weston_desktop_xdg_popup *popup = user_data;
572
573 xdg_popup_send_popup_done(popup->resource);
574}
575
576static void
577weston_desktop_xdg_popup_destroy(struct weston_desktop_surface *dsurface,
578 void *user_data)
579{
580 struct weston_desktop_xdg_popup *popup = user_data;
581 struct weston_desktop_surface *topmost;
582 struct weston_desktop_client *client =
583 weston_desktop_surface_get_client(popup->popup);
584
585 if (!weston_desktop_surface_get_grab(popup->popup))
586 goto end;
587
588 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(popup->seat);
589 if (topmost != popup->popup) {
590 struct wl_resource *client_resource =
591 weston_desktop_client_get_resource(client);
592
593 wl_resource_post_error(client_resource,
594 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
595 "xdg_popup was destroyed while it was not the topmost popup.");
596 }
597
598 weston_desktop_surface_popup_ungrab(popup->popup, popup->seat);
599
600end:
601 free(popup);
602}
603
604static const struct xdg_popup_interface weston_desktop_xdg_popup_implementation = {
605 .destroy = weston_desktop_destroy_request,
606};
607
608static const struct weston_desktop_surface_implementation weston_desktop_xdg_popup_internal_implementation = {
609 .close = weston_desktop_xdg_popup_close,
610
611 .destroy = weston_desktop_xdg_popup_destroy,
612};
613
614static void
615weston_desktop_xdg_shell_protocol_use_unstable_version(struct wl_client *wl_client,
616 struct wl_resource *resource,
617 int32_t version)
618{
619 if (version > 1) {
620 wl_resource_post_error(resource,
621 1, "xdg_shell version not supported");
622 return;
623 }
624}
625
626static void
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200627weston_desktop_xdg_surface_add_idle_callback(void *user_data)
Quentin Glidic248dd102016-08-12 10:41:34 +0200628{
629 struct weston_desktop_xdg_surface *surface = user_data;
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200630
Quentin Glidic248dd102016-08-12 10:41:34 +0200631 surface->add_idle = NULL;
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200632 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200633}
634
635static void
636weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client,
637 struct wl_resource *resource,
638 uint32_t id,
639 struct wl_resource *surface_resource)
640{
641 struct weston_desktop_client *client =
642 wl_resource_get_user_data(resource);
643 struct weston_desktop *desktop =
644 weston_desktop_client_get_desktop(client);
645 struct weston_surface *wsurface =
646 wl_resource_get_user_data(surface_resource);
647 struct weston_desktop_xdg_surface *surface;
648 struct wl_display *display = weston_desktop_get_display(desktop);
649 struct wl_event_loop *loop = wl_display_get_event_loop(display);
650
651 if (weston_surface_set_role(wsurface, "xdg_surface", resource, XDG_SHELL_ERROR_ROLE) < 0)
652 return;
653
654 surface = zalloc(sizeof(struct weston_desktop_xdg_surface));
655 if (surface == NULL) {
656 wl_client_post_no_memory(wl_client);
657 return;
658 }
659
660 surface->desktop = desktop;
661
662 surface->surface =
663 weston_desktop_surface_create(surface->desktop, client,
664 wsurface,
665 &weston_desktop_xdg_surface_internal_implementation,
666 surface);
667 if (surface->surface == NULL) {
668 free(surface);
669 return;
670 }
671
672 surface->resource =
673 weston_desktop_surface_add_resource(surface->surface,
674 &xdg_surface_interface,
675 &weston_desktop_xdg_surface_implementation,
676 id, NULL);
677 if (surface->resource == NULL)
678 return;
679
680 surface->add_idle =
681 wl_event_loop_add_idle(loop,
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200682 weston_desktop_xdg_surface_add_idle_callback,
Quentin Glidic248dd102016-08-12 10:41:34 +0200683 surface);
684}
685
686static void
687weston_desktop_xdg_shell_protocol_get_xdg_popup(struct wl_client *wl_client,
688 struct wl_resource *resource,
689 uint32_t id,
690 struct wl_resource *surface_resource,
691 struct wl_resource *parent_resource,
692 struct wl_resource *seat_resource,
693 uint32_t serial,
694 int32_t x, int32_t y)
695{
696 struct weston_desktop_client *client =
697 wl_resource_get_user_data(resource);
698 struct weston_surface *wsurface =
699 wl_resource_get_user_data(surface_resource);
700 struct weston_surface *wparent =
701 wl_resource_get_user_data(parent_resource);
702 struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
703 struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
704 struct weston_desktop_surface *parent, *topmost;
705 bool parent_is_popup, parent_is_xdg;
706 struct weston_desktop_xdg_popup *popup;
707
708 if (weston_surface_set_role(wsurface, "xdg_popup", resource, XDG_SHELL_ERROR_ROLE) < 0)
709 return;
710
711 if (!weston_surface_is_desktop_surface(wparent)) {
712 wl_resource_post_error(resource,
713 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
714 "xdg_popup parent was invalid");
715 return;
716 }
717
718 parent = weston_surface_get_desktop_surface(wparent);
719 parent_is_xdg =
720 weston_desktop_surface_has_implementation(parent,
721 &weston_desktop_xdg_surface_internal_implementation);
722 parent_is_popup =
723 weston_desktop_surface_has_implementation(parent,
724 &weston_desktop_xdg_popup_internal_implementation);
725
726 if (!parent_is_xdg && !parent_is_popup) {
727 wl_resource_post_error(resource,
728 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
729 "xdg_popup parent was invalid");
730 return;
731 }
732
733 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(seat);
734 if ((topmost == NULL && parent_is_popup) ||
735 (topmost != NULL && topmost != parent)) {
736 wl_resource_post_error(resource,
737 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
738 "xdg_popup was not created on the topmost popup");
739 return;
740 }
741
742 popup = zalloc(sizeof(struct weston_desktop_xdg_popup));
743 if (popup == NULL) {
744 wl_client_post_no_memory(wl_client);
745 return;
746 }
747
748 popup->desktop = weston_desktop_client_get_desktop(client);
749 popup->display = weston_desktop_get_display(popup->desktop);
750 popup->seat = seat;
751
752 popup->popup =
753 weston_desktop_surface_create(popup->desktop, client, wsurface,
754 &weston_desktop_xdg_popup_internal_implementation,
755 popup);
756 if (popup->popup == NULL) {
757 free(popup);
758 return;
759 }
760
761 popup->resource =
762 weston_desktop_surface_add_resource(popup->popup,
763 &xdg_popup_interface,
764 &weston_desktop_xdg_popup_implementation,
765 id, NULL);
766 if (popup->resource == NULL)
767 return;
768
769 weston_desktop_surface_set_relative_to(popup->popup, parent, x, y, false);
770 weston_desktop_surface_popup_grab(popup->popup, popup->seat, serial);
771}
772
773static void
774weston_desktop_xdg_shell_protocol_pong(struct wl_client *wl_client,
775 struct wl_resource *resource,
776 uint32_t serial)
777{
778 struct weston_desktop_client *client =
779 wl_resource_get_user_data(resource);
780
781 weston_desktop_client_pong(client, serial);
782}
783
784static const struct xdg_shell_interface weston_desktop_xdg_shell_implementation = {
785 .destroy = weston_desktop_destroy_request,
786 .use_unstable_version = weston_desktop_xdg_shell_protocol_use_unstable_version,
787 .get_xdg_surface = weston_desktop_xdg_shell_protocol_get_xdg_surface,
788 .get_xdg_popup = weston_desktop_xdg_shell_protocol_get_xdg_popup,
789 .pong = weston_desktop_xdg_shell_protocol_pong,
790};
791
792static int
793xdg_shell_unversioned_dispatch(const void *implementation,
794 void *_target, uint32_t opcode,
795 const struct wl_message *message,
796 union wl_argument *args)
797{
798 struct wl_resource *resource = _target;
799 struct weston_desktop_client *client =
800 wl_resource_get_user_data(resource);
801
802 if (opcode != 1 /* XDG_SHELL_USE_UNSTABLE_VERSION */) {
803 wl_resource_post_error(resource,
804 WL_DISPLAY_ERROR_INVALID_OBJECT,
805 "must call use_unstable_version first");
806 return 0;
807 }
808
809#define XDG_SERVER_VERSION 5
810
811 if (args[0].i != XDG_SERVER_VERSION) {
812 wl_resource_post_error(resource,
813 WL_DISPLAY_ERROR_INVALID_OBJECT,
814 "incompatible version, server is %d " "client wants %d",
815 XDG_SERVER_VERSION, args[0].i);
816 return 0;
817 }
818
819 wl_resource_set_implementation(resource,
820 &weston_desktop_xdg_shell_implementation,
821 client, implementation);
822
823 return 1;
824}
825
826static void
827weston_desktop_xdg_shell_bind(struct wl_client *client, void *data,
828 uint32_t version, uint32_t id)
829{
830 struct weston_desktop *desktop = data;
831
832 weston_desktop_client_create(desktop, client,
833 xdg_shell_unversioned_dispatch,
834 &xdg_shell_interface, NULL, version, id);
835}
836
837struct wl_global *
838weston_desktop_xdg_shell_v5_create(struct weston_desktop *desktop,
839 struct wl_display *display)
840{
841 return wl_global_create(display,
842 &xdg_shell_interface,
843 WD_XDG_SHELL_PROTOCOL_VERSION,
844 desktop, weston_desktop_xdg_shell_bind);
845}