blob: 08cf71ee8ce6a7abe487368fca94a1eb730bb2f9 [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
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);
Armin Krezović4e2fa0a2016-09-10 19:11:21 +0200398 enum weston_desktop_surface_edge surf_edges =
399 (enum weston_desktop_surface_edge) edges;
Quentin Glidic248dd102016-08-12 10:41:34 +0200400
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200401 weston_desktop_xdg_surface_ensure_added(surface);
Armin Krezović4e2fa0a2016-09-10 19:11:21 +0200402 weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, surf_edges);
Quentin Glidic248dd102016-08-12 10:41:34 +0200403}
404
405static void
406weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client,
407 struct wl_resource *resource,
408 uint32_t serial)
409{
410 struct weston_desktop_surface *dsurface =
411 wl_resource_get_user_data(resource);
412 struct weston_desktop_xdg_surface *surface =
413 weston_desktop_surface_get_implementation_data(dsurface);
414
415 if (surface->configure_serial != serial)
416 return;
417
418 surface->next_state = surface->requested_state;
419}
420
421static void
422weston_desktop_xdg_surface_protocol_set_window_geometry(struct wl_client *wl_client,
423 struct wl_resource *resource,
424 int32_t x, int32_t y,
425 int32_t width, int32_t height)
426{
427 struct weston_desktop_surface *dsurface =
428 wl_resource_get_user_data(resource);
429 struct weston_desktop_xdg_surface *surface =
430 weston_desktop_surface_get_implementation_data(dsurface);
431
432 surface->has_next_geometry = true;
433 surface->next_geometry.x = x;
434 surface->next_geometry.y = y;
435 surface->next_geometry.width = width;
436 surface->next_geometry.height = height;
437}
438
439static void
440weston_desktop_xdg_surface_protocol_set_maximized(struct wl_client *wl_client,
441 struct wl_resource *resource)
442{
443 struct weston_desktop_surface *dsurface =
444 wl_resource_get_user_data(resource);
445 struct weston_desktop_xdg_surface *surface =
446 weston_desktop_surface_get_implementation_data(dsurface);
447
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200448 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200449 weston_desktop_api_maximized_requested(surface->desktop, dsurface, true);
450}
451
452static void
453weston_desktop_xdg_surface_protocol_unset_maximized(struct wl_client *wl_client,
454 struct wl_resource *resource)
455{
456 struct weston_desktop_surface *dsurface =
457 wl_resource_get_user_data(resource);
458 struct weston_desktop_xdg_surface *surface =
459 weston_desktop_surface_get_implementation_data(dsurface);
460
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200461 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200462 weston_desktop_api_maximized_requested(surface->desktop, dsurface, false);
463}
464
465static void
466weston_desktop_xdg_surface_protocol_set_fullscreen(struct wl_client *wl_client,
467 struct wl_resource *resource,
468 struct wl_resource *output_resource)
469{
470 struct weston_desktop_surface *dsurface =
471 wl_resource_get_user_data(resource);
472 struct weston_desktop_xdg_surface *surface =
473 weston_desktop_surface_get_implementation_data(dsurface);
474 struct weston_output *output = NULL;
475
476 if (output_resource != NULL)
477 output = wl_resource_get_user_data(output_resource);
478
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200479 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200480 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
481 true, output);
482}
483
484static void
485weston_desktop_xdg_surface_protocol_unset_fullscreen(struct wl_client *wl_client,
486 struct wl_resource *resource)
487{
488 struct weston_desktop_surface *dsurface =
489 wl_resource_get_user_data(resource);
490 struct weston_desktop_xdg_surface *surface =
491 weston_desktop_surface_get_implementation_data(dsurface);
492
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200493 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200494 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
495 false, NULL);
496}
497
498static void
499weston_desktop_xdg_surface_protocol_set_minimized(struct wl_client *wl_client,
500 struct wl_resource *resource)
501{
502 struct weston_desktop_surface *dsurface =
503 wl_resource_get_user_data(resource);
504 struct weston_desktop_xdg_surface *surface =
505 weston_desktop_surface_get_implementation_data(dsurface);
506
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200507 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200508 weston_desktop_api_minimized_requested(surface->desktop, dsurface);
509}
510
511static const struct xdg_surface_interface weston_desktop_xdg_surface_implementation = {
512 .destroy = weston_desktop_destroy_request,
513 .set_parent = weston_desktop_xdg_surface_protocol_set_parent,
514 .set_title = weston_desktop_xdg_surface_protocol_set_title,
515 .set_app_id = weston_desktop_xdg_surface_protocol_set_app_id,
516 .show_window_menu = weston_desktop_xdg_surface_protocol_show_window_menu,
517 .move = weston_desktop_xdg_surface_protocol_move,
518 .resize = weston_desktop_xdg_surface_protocol_resize,
519 .ack_configure = weston_desktop_xdg_surface_protocol_ack_configure,
520 .set_window_geometry = weston_desktop_xdg_surface_protocol_set_window_geometry,
521 .set_maximized = weston_desktop_xdg_surface_protocol_set_maximized,
522 .unset_maximized = weston_desktop_xdg_surface_protocol_unset_maximized,
523 .set_fullscreen = weston_desktop_xdg_surface_protocol_set_fullscreen,
524 .unset_fullscreen = weston_desktop_xdg_surface_protocol_unset_fullscreen,
525 .set_minimized = weston_desktop_xdg_surface_protocol_set_minimized,
526};
527
528static const struct weston_desktop_surface_implementation weston_desktop_xdg_surface_internal_implementation = {
529 .set_maximized = weston_desktop_xdg_surface_set_maximized,
530 .set_fullscreen = weston_desktop_xdg_surface_set_fullscreen,
531 .set_resizing = weston_desktop_xdg_surface_set_resizing,
532 .set_activated = weston_desktop_xdg_surface_set_activated,
533 .set_size = weston_desktop_xdg_surface_set_size,
534 .committed = weston_desktop_xdg_surface_committed,
535 .ping = weston_desktop_xdg_surface_ping,
536 .close = weston_desktop_xdg_surface_close,
537
538 .get_maximized = weston_desktop_xdg_surface_get_maximized,
539 .get_fullscreen = weston_desktop_xdg_surface_get_fullscreen,
540 .get_resizing = weston_desktop_xdg_surface_get_resizing,
541 .get_activated = weston_desktop_xdg_surface_get_activated,
542
543 .destroy = weston_desktop_xdg_surface_destroy,
544};
545
546static void
547weston_desktop_xdg_popup_close(struct weston_desktop_surface *dsurface,
548 void *user_data)
549{
550 struct weston_desktop_xdg_popup *popup = user_data;
551
552 xdg_popup_send_popup_done(popup->resource);
553}
554
555static void
556weston_desktop_xdg_popup_destroy(struct weston_desktop_surface *dsurface,
557 void *user_data)
558{
559 struct weston_desktop_xdg_popup *popup = user_data;
560 struct weston_desktop_surface *topmost;
561 struct weston_desktop_client *client =
562 weston_desktop_surface_get_client(popup->popup);
563
564 if (!weston_desktop_surface_get_grab(popup->popup))
565 goto end;
566
567 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(popup->seat);
568 if (topmost != popup->popup) {
569 struct wl_resource *client_resource =
570 weston_desktop_client_get_resource(client);
571
572 wl_resource_post_error(client_resource,
573 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
574 "xdg_popup was destroyed while it was not the topmost popup.");
575 }
576
577 weston_desktop_surface_popup_ungrab(popup->popup, popup->seat);
578
579end:
580 free(popup);
581}
582
583static const struct xdg_popup_interface weston_desktop_xdg_popup_implementation = {
584 .destroy = weston_desktop_destroy_request,
585};
586
587static const struct weston_desktop_surface_implementation weston_desktop_xdg_popup_internal_implementation = {
588 .close = weston_desktop_xdg_popup_close,
589
590 .destroy = weston_desktop_xdg_popup_destroy,
591};
592
593static void
594weston_desktop_xdg_shell_protocol_use_unstable_version(struct wl_client *wl_client,
595 struct wl_resource *resource,
596 int32_t version)
597{
598 if (version > 1) {
599 wl_resource_post_error(resource,
600 1, "xdg_shell version not supported");
601 return;
602 }
603}
604
605static void
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200606weston_desktop_xdg_surface_add_idle_callback(void *user_data)
Quentin Glidic248dd102016-08-12 10:41:34 +0200607{
608 struct weston_desktop_xdg_surface *surface = user_data;
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200609
Quentin Glidic248dd102016-08-12 10:41:34 +0200610 surface->add_idle = NULL;
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200611 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200612}
613
614static void
615weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client,
616 struct wl_resource *resource,
617 uint32_t id,
618 struct wl_resource *surface_resource)
619{
620 struct weston_desktop_client *client =
621 wl_resource_get_user_data(resource);
622 struct weston_desktop *desktop =
623 weston_desktop_client_get_desktop(client);
624 struct weston_surface *wsurface =
625 wl_resource_get_user_data(surface_resource);
626 struct weston_desktop_xdg_surface *surface;
627 struct wl_display *display = weston_desktop_get_display(desktop);
628 struct wl_event_loop *loop = wl_display_get_event_loop(display);
629
630 if (weston_surface_set_role(wsurface, "xdg_surface", resource, XDG_SHELL_ERROR_ROLE) < 0)
631 return;
632
633 surface = zalloc(sizeof(struct weston_desktop_xdg_surface));
634 if (surface == NULL) {
635 wl_client_post_no_memory(wl_client);
636 return;
637 }
638
639 surface->desktop = desktop;
640
641 surface->surface =
642 weston_desktop_surface_create(surface->desktop, client,
643 wsurface,
644 &weston_desktop_xdg_surface_internal_implementation,
645 surface);
646 if (surface->surface == NULL) {
647 free(surface);
648 return;
649 }
650
651 surface->resource =
652 weston_desktop_surface_add_resource(surface->surface,
653 &xdg_surface_interface,
654 &weston_desktop_xdg_surface_implementation,
655 id, NULL);
656 if (surface->resource == NULL)
657 return;
658
659 surface->add_idle =
660 wl_event_loop_add_idle(loop,
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200661 weston_desktop_xdg_surface_add_idle_callback,
Quentin Glidic248dd102016-08-12 10:41:34 +0200662 surface);
663}
664
665static void
666weston_desktop_xdg_shell_protocol_get_xdg_popup(struct wl_client *wl_client,
667 struct wl_resource *resource,
668 uint32_t id,
669 struct wl_resource *surface_resource,
670 struct wl_resource *parent_resource,
671 struct wl_resource *seat_resource,
672 uint32_t serial,
673 int32_t x, int32_t y)
674{
675 struct weston_desktop_client *client =
676 wl_resource_get_user_data(resource);
677 struct weston_surface *wsurface =
678 wl_resource_get_user_data(surface_resource);
679 struct weston_surface *wparent =
680 wl_resource_get_user_data(parent_resource);
681 struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
682 struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
683 struct weston_desktop_surface *parent, *topmost;
684 bool parent_is_popup, parent_is_xdg;
685 struct weston_desktop_xdg_popup *popup;
686
687 if (weston_surface_set_role(wsurface, "xdg_popup", resource, XDG_SHELL_ERROR_ROLE) < 0)
688 return;
689
690 if (!weston_surface_is_desktop_surface(wparent)) {
691 wl_resource_post_error(resource,
692 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
693 "xdg_popup parent was invalid");
694 return;
695 }
696
697 parent = weston_surface_get_desktop_surface(wparent);
698 parent_is_xdg =
699 weston_desktop_surface_has_implementation(parent,
700 &weston_desktop_xdg_surface_internal_implementation);
701 parent_is_popup =
702 weston_desktop_surface_has_implementation(parent,
703 &weston_desktop_xdg_popup_internal_implementation);
704
705 if (!parent_is_xdg && !parent_is_popup) {
706 wl_resource_post_error(resource,
707 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
708 "xdg_popup parent was invalid");
709 return;
710 }
711
712 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(seat);
713 if ((topmost == NULL && parent_is_popup) ||
714 (topmost != NULL && topmost != parent)) {
715 wl_resource_post_error(resource,
716 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
717 "xdg_popup was not created on the topmost popup");
718 return;
719 }
720
721 popup = zalloc(sizeof(struct weston_desktop_xdg_popup));
722 if (popup == NULL) {
723 wl_client_post_no_memory(wl_client);
724 return;
725 }
726
727 popup->desktop = weston_desktop_client_get_desktop(client);
728 popup->display = weston_desktop_get_display(popup->desktop);
729 popup->seat = seat;
730
731 popup->popup =
732 weston_desktop_surface_create(popup->desktop, client, wsurface,
733 &weston_desktop_xdg_popup_internal_implementation,
734 popup);
735 if (popup->popup == NULL) {
736 free(popup);
737 return;
738 }
739
740 popup->resource =
741 weston_desktop_surface_add_resource(popup->popup,
742 &xdg_popup_interface,
743 &weston_desktop_xdg_popup_implementation,
744 id, NULL);
745 if (popup->resource == NULL)
746 return;
747
748 weston_desktop_surface_set_relative_to(popup->popup, parent, x, y, false);
749 weston_desktop_surface_popup_grab(popup->popup, popup->seat, serial);
750}
751
752static void
753weston_desktop_xdg_shell_protocol_pong(struct wl_client *wl_client,
754 struct wl_resource *resource,
755 uint32_t serial)
756{
757 struct weston_desktop_client *client =
758 wl_resource_get_user_data(resource);
759
760 weston_desktop_client_pong(client, serial);
761}
762
763static const struct xdg_shell_interface weston_desktop_xdg_shell_implementation = {
764 .destroy = weston_desktop_destroy_request,
765 .use_unstable_version = weston_desktop_xdg_shell_protocol_use_unstable_version,
766 .get_xdg_surface = weston_desktop_xdg_shell_protocol_get_xdg_surface,
767 .get_xdg_popup = weston_desktop_xdg_shell_protocol_get_xdg_popup,
768 .pong = weston_desktop_xdg_shell_protocol_pong,
769};
770
771static int
772xdg_shell_unversioned_dispatch(const void *implementation,
773 void *_target, uint32_t opcode,
774 const struct wl_message *message,
775 union wl_argument *args)
776{
777 struct wl_resource *resource = _target;
778 struct weston_desktop_client *client =
779 wl_resource_get_user_data(resource);
780
781 if (opcode != 1 /* XDG_SHELL_USE_UNSTABLE_VERSION */) {
782 wl_resource_post_error(resource,
783 WL_DISPLAY_ERROR_INVALID_OBJECT,
784 "must call use_unstable_version first");
785 return 0;
786 }
787
788#define XDG_SERVER_VERSION 5
789
790 if (args[0].i != XDG_SERVER_VERSION) {
791 wl_resource_post_error(resource,
792 WL_DISPLAY_ERROR_INVALID_OBJECT,
793 "incompatible version, server is %d " "client wants %d",
794 XDG_SERVER_VERSION, args[0].i);
795 return 0;
796 }
797
798 wl_resource_set_implementation(resource,
799 &weston_desktop_xdg_shell_implementation,
800 client, implementation);
801
802 return 1;
803}
804
805static void
806weston_desktop_xdg_shell_bind(struct wl_client *client, void *data,
807 uint32_t version, uint32_t id)
808{
809 struct weston_desktop *desktop = data;
810
811 weston_desktop_client_create(desktop, client,
812 xdg_shell_unversioned_dispatch,
813 &xdg_shell_interface, NULL, version, id);
814}
815
816struct wl_global *
817weston_desktop_xdg_shell_v5_create(struct weston_desktop *desktop,
818 struct wl_display *display)
819{
820 return wl_global_create(display,
821 &xdg_shell_interface,
822 WD_XDG_SHELL_PROTOCOL_VERSION,
823 desktop, weston_desktop_xdg_shell_bind);
824}