blob: 77d004e1a31e80993a65d6824c9cb23b03643250 [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
Quentin Glidic19d1f6e2017-07-12 09:42:57 +020042struct weston_desktop_xdg_surface_state {
43 bool maximized;
44 bool fullscreen;
45 bool resizing;
46 bool activated;
47};
48
Quentin Glidic749637a2017-07-18 12:59:14 +020049struct weston_desktop_xdg_surface_configure {
50 struct wl_list link; /* weston_desktop_xdg_surface::configure_list */
51 uint32_t serial;
52 struct weston_desktop_xdg_surface_state state;
53 struct weston_size size;
54};
55
Quentin Glidic248dd102016-08-12 10:41:34 +020056struct weston_desktop_xdg_surface {
57 struct wl_resource *resource;
58 struct weston_desktop_surface *surface;
59 struct weston_desktop *desktop;
Quentin Glidic6967f0e2016-08-18 15:51:38 +020060 bool added;
Quentin Glidic248dd102016-08-12 10:41:34 +020061 struct wl_event_source *add_idle;
62 struct wl_event_source *configure_idle;
Quentin Glidic749637a2017-07-18 12:59:14 +020063 struct wl_list configure_list; /* weston_desktop_xdg_surface_configure::link */
Quentin Glidic248dd102016-08-12 10:41:34 +020064 struct {
Quentin Glidic19d1f6e2017-07-12 09:42:57 +020065 struct weston_desktop_xdg_surface_state state;
66 struct weston_size size;
67 } pending;
68 struct {
69 struct weston_desktop_xdg_surface_state state;
Quentin Glidicac394a12017-07-12 09:45:43 +020070 struct weston_size size;
Quentin Glidic19d1f6e2017-07-12 09:42:57 +020071 } next;
72 struct {
73 struct weston_desktop_xdg_surface_state state;
74 } current;
Quentin Glidic248dd102016-08-12 10:41:34 +020075 bool has_next_geometry;
76 struct weston_geometry next_geometry;
77};
78
79struct weston_desktop_xdg_popup {
80 struct wl_resource *resource;
81 struct weston_desktop_surface *popup;
82 struct weston_desktop *desktop;
83 struct weston_desktop_seat *seat;
84 struct wl_display *display;
85};
86
87static void
Quentin Glidic6967f0e2016-08-18 15:51:38 +020088weston_desktop_xdg_surface_ensure_added(struct weston_desktop_xdg_surface *surface)
89{
90 if (surface->added)
91 return;
92
93 if (surface->add_idle != NULL)
94 wl_event_source_remove(surface->add_idle);
95 surface->add_idle = NULL;
96 weston_desktop_api_surface_added(surface->desktop, surface->surface);
97 surface->added = true;
98}
99
100static void
Quentin Glidic248dd102016-08-12 10:41:34 +0200101weston_desktop_xdg_surface_send_configure(void *data)
102{
103 struct weston_desktop_xdg_surface *surface = data;
Quentin Glidic749637a2017-07-18 12:59:14 +0200104 struct weston_desktop_xdg_surface_configure *configure;
Quentin Glidic248dd102016-08-12 10:41:34 +0200105 uint32_t *s;
106 struct wl_array states;
107
108 surface->configure_idle = NULL;
109
Quentin Glidic749637a2017-07-18 12:59:14 +0200110 configure = zalloc(sizeof(struct weston_desktop_xdg_surface_configure));
111 if (configure == NULL) {
112 struct weston_desktop_client *client =
113 weston_desktop_surface_get_client(surface->surface);
114 struct wl_client *wl_client =
115 weston_desktop_client_get_client(client);
116 wl_client_post_no_memory(wl_client);
117 return;
118 }
119 wl_list_insert(surface->configure_list.prev, &configure->link);
120 configure->serial =
Quentin Glidic248dd102016-08-12 10:41:34 +0200121 wl_display_next_serial(weston_desktop_get_display(surface->desktop));
Quentin Glidic749637a2017-07-18 12:59:14 +0200122 configure->state = surface->pending.state;
123 configure->size = surface->pending.size;
Quentin Glidic248dd102016-08-12 10:41:34 +0200124
125 wl_array_init(&states);
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200126 if (surface->pending.state.maximized) {
Quentin Glidic248dd102016-08-12 10:41:34 +0200127 s = wl_array_add(&states, sizeof(uint32_t));
128 *s = XDG_SURFACE_STATE_MAXIMIZED;
129 }
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200130 if (surface->pending.state.fullscreen) {
Quentin Glidic248dd102016-08-12 10:41:34 +0200131 s = wl_array_add(&states, sizeof(uint32_t));
132 *s = XDG_SURFACE_STATE_FULLSCREEN;
133 }
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200134 if (surface->pending.state.resizing) {
Quentin Glidic248dd102016-08-12 10:41:34 +0200135 s = wl_array_add(&states, sizeof(uint32_t));
136 *s = XDG_SURFACE_STATE_RESIZING;
137 }
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200138 if (surface->pending.state.activated) {
Quentin Glidic248dd102016-08-12 10:41:34 +0200139 s = wl_array_add(&states, sizeof(uint32_t));
140 *s = XDG_SURFACE_STATE_ACTIVATED;
141 }
142
143 xdg_surface_send_configure(surface->resource,
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200144 surface->pending.size.width,
145 surface->pending.size.height,
Quentin Glidic248dd102016-08-12 10:41:34 +0200146 &states,
Quentin Glidic749637a2017-07-18 12:59:14 +0200147 configure->serial);
Quentin Glidic248dd102016-08-12 10:41:34 +0200148
149 wl_array_release(&states);
150};
151
Quentin Glidicd51f8262017-04-13 20:25:27 +0200152static bool
153weston_desktop_xdg_surface_state_compare(struct weston_desktop_xdg_surface *surface)
154{
155 struct weston_surface *wsurface =
156 weston_desktop_surface_get_surface(surface->surface);
157
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200158 if (surface->pending.state.activated != surface->current.state.activated)
Quentin Glidicd51f8262017-04-13 20:25:27 +0200159 return false;
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200160 if (surface->pending.state.fullscreen != surface->current.state.fullscreen)
Quentin Glidicd51f8262017-04-13 20:25:27 +0200161 return false;
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200162 if (surface->pending.state.maximized != surface->current.state.maximized)
Quentin Glidicd51f8262017-04-13 20:25:27 +0200163 return false;
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200164 if (surface->pending.state.resizing != surface->current.state.resizing)
Quentin Glidicd51f8262017-04-13 20:25:27 +0200165 return false;
166
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200167 if (wsurface->width == surface->pending.size.width &&
168 wsurface->height == surface->pending.size.height)
Quentin Glidicd51f8262017-04-13 20:25:27 +0200169 return true;
170
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200171 if (surface->pending.size.width == 0 &&
172 surface->pending.size.height == 0)
Quentin Glidicd51f8262017-04-13 20:25:27 +0200173 return true;
174
175 return false;
176}
177
Quentin Glidic248dd102016-08-12 10:41:34 +0200178static void
Quentin Glidicd51f8262017-04-13 20:25:27 +0200179weston_desktop_xdg_surface_schedule_configure(struct weston_desktop_xdg_surface *surface,
180 bool force)
Quentin Glidic248dd102016-08-12 10:41:34 +0200181{
182 struct wl_display *display = weston_desktop_get_display(surface->desktop);
183 struct wl_event_loop *loop = wl_display_get_event_loop(display);
Quentin Glidic218126d2017-07-11 13:31:36 +0200184 bool pending_same =
Quentin Glidicd51f8262017-04-13 20:25:27 +0200185 !force && weston_desktop_xdg_surface_state_compare(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200186
Quentin Glidicd51f8262017-04-13 20:25:27 +0200187 if (surface->configure_idle != NULL) {
Quentin Glidic218126d2017-07-11 13:31:36 +0200188 if (!pending_same)
Quentin Glidicd51f8262017-04-13 20:25:27 +0200189 return;
190
191 wl_event_source_remove(surface->configure_idle);
192 surface->configure_idle = NULL;
193 } else {
Quentin Glidic218126d2017-07-11 13:31:36 +0200194 if (pending_same)
Quentin Glidicd51f8262017-04-13 20:25:27 +0200195 return;
196
197 surface->configure_idle =
198 wl_event_loop_add_idle(loop,
199 weston_desktop_xdg_surface_send_configure,
200 surface);
201 }
Quentin Glidic248dd102016-08-12 10:41:34 +0200202}
203
204static void
205weston_desktop_xdg_surface_set_maximized(struct weston_desktop_surface *dsurface,
206 void *user_data, bool maximized)
207{
208 struct weston_desktop_xdg_surface *surface = user_data;
209
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200210 surface->pending.state.maximized = maximized;
Quentin Glidicd51f8262017-04-13 20:25:27 +0200211 weston_desktop_xdg_surface_schedule_configure(surface, false);
Quentin Glidic248dd102016-08-12 10:41:34 +0200212}
213
214static void
215weston_desktop_xdg_surface_set_fullscreen(struct weston_desktop_surface *dsurface,
216 void *user_data, bool fullscreen)
217{
218 struct weston_desktop_xdg_surface *surface = user_data;
219
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200220 surface->pending.state.fullscreen = fullscreen;
Quentin Glidicd51f8262017-04-13 20:25:27 +0200221 weston_desktop_xdg_surface_schedule_configure(surface, false);
Quentin Glidic248dd102016-08-12 10:41:34 +0200222}
223
224static void
225weston_desktop_xdg_surface_set_resizing(struct weston_desktop_surface *dsurface,
226 void *user_data, bool resizing)
227{
228 struct weston_desktop_xdg_surface *surface = user_data;
229
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200230 surface->pending.state.resizing = resizing;
Quentin Glidicd51f8262017-04-13 20:25:27 +0200231 weston_desktop_xdg_surface_schedule_configure(surface, false);
Quentin Glidic248dd102016-08-12 10:41:34 +0200232}
233
234static void
235weston_desktop_xdg_surface_set_activated(struct weston_desktop_surface *dsurface,
236 void *user_data, bool activated)
237{
238 struct weston_desktop_xdg_surface *surface = user_data;
239
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200240 surface->pending.state.activated = activated;
Quentin Glidicd51f8262017-04-13 20:25:27 +0200241 weston_desktop_xdg_surface_schedule_configure(surface, false);
Quentin Glidic248dd102016-08-12 10:41:34 +0200242}
243
244static void
245weston_desktop_xdg_surface_set_size(struct weston_desktop_surface *dsurface,
246 void *user_data,
247 int32_t width, int32_t height)
248{
249 struct weston_desktop_xdg_surface *surface = user_data;
Quentin Glidic248dd102016-08-12 10:41:34 +0200250
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200251 surface->pending.size.width = width;
252 surface->pending.size.height = height;
Quentin Glidica56b0532016-09-13 10:05:58 +0200253
Quentin Glidicd51f8262017-04-13 20:25:27 +0200254 weston_desktop_xdg_surface_schedule_configure(surface, false);
Quentin Glidic248dd102016-08-12 10:41:34 +0200255}
256
257static void
258weston_desktop_xdg_surface_committed(struct weston_desktop_surface *dsurface,
Quentin Glidic003da882016-08-15 12:21:39 +0200259 void *user_data,
Quentin Glidic248dd102016-08-12 10:41:34 +0200260 int32_t sx, int32_t sy)
261{
262 struct weston_desktop_xdg_surface *surface = user_data;
263 struct weston_surface *wsurface =
264 weston_desktop_surface_get_surface(surface->surface);
265 bool reconfigure = false;
266
Philipp Kerlingc6239022017-07-26 14:02:21 +0200267 /* TODO: use the window geometry and not the surface size here
268 * We need to check the next geometry if there is one, but not accept it
269 * until we checked it, maybe.
270 */
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200271 if (surface->next.state.maximized || surface->next.state.fullscreen)
Quentin Glidicac394a12017-07-12 09:45:43 +0200272 reconfigure = surface->next.size.width != wsurface->width ||
273 surface->next.size.height != wsurface->height;
Quentin Glidic248dd102016-08-12 10:41:34 +0200274
275 if (reconfigure) {
Quentin Glidicd51f8262017-04-13 20:25:27 +0200276 weston_desktop_xdg_surface_schedule_configure(surface, true);
Quentin Glidic248dd102016-08-12 10:41:34 +0200277 } else {
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200278 surface->current.state = surface->next.state;
Quentin Glidic248dd102016-08-12 10:41:34 +0200279 if (surface->has_next_geometry) {
280 surface->has_next_geometry = false;
281 weston_desktop_surface_set_geometry(surface->surface,
282 surface->next_geometry);
283 }
284
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200285 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200286 weston_desktop_api_committed(surface->desktop, surface->surface,
287 sx, sy);
288 }
289}
290
291static void
292weston_desktop_xdg_surface_ping(struct weston_desktop_surface *dsurface,
293 uint32_t serial, void *user_data)
294{
295 struct weston_desktop_client *client =
296 weston_desktop_surface_get_client(dsurface);
297
298 xdg_shell_send_ping(weston_desktop_client_get_resource(client),
299 serial);
300}
301
302static void
303weston_desktop_xdg_surface_close(struct weston_desktop_surface *dsurface,
304 void *user_data)
305{
306 struct weston_desktop_xdg_surface *surface = user_data;
307
308 xdg_surface_send_close(surface->resource);
309}
310
311static bool
312weston_desktop_xdg_surface_get_maximized(struct weston_desktop_surface *dsurface,
313 void *user_data)
314{
315 struct weston_desktop_xdg_surface *surface = user_data;
316
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200317 return surface->current.state.maximized;
Quentin Glidic248dd102016-08-12 10:41:34 +0200318}
319
320static bool
321weston_desktop_xdg_surface_get_fullscreen(struct weston_desktop_surface *dsurface,
322 void *user_data)
323{
324 struct weston_desktop_xdg_surface *surface = user_data;
325
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200326 return surface->current.state.fullscreen;
Quentin Glidic248dd102016-08-12 10:41:34 +0200327}
328
329static bool
330weston_desktop_xdg_surface_get_resizing(struct weston_desktop_surface *dsurface,
331 void *user_data)
332{
333 struct weston_desktop_xdg_surface *surface = user_data;
334
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200335 return surface->current.state.resizing;
Quentin Glidic248dd102016-08-12 10:41:34 +0200336}
337
338static bool
339weston_desktop_xdg_surface_get_activated(struct weston_desktop_surface *dsurface,
340 void *user_data)
341{
342 struct weston_desktop_xdg_surface *surface = user_data;
343
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200344 return surface->current.state.activated;
Quentin Glidic248dd102016-08-12 10:41:34 +0200345}
346
347static void
348weston_desktop_xdg_surface_destroy(struct weston_desktop_surface *dsurface,
349 void *user_data)
350{
351 struct weston_desktop_xdg_surface *surface = user_data;
Quentin Glidic749637a2017-07-18 12:59:14 +0200352 struct weston_desktop_xdg_surface_configure *configure, *temp;
Quentin Glidic248dd102016-08-12 10:41:34 +0200353
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200354 if (surface->added)
355 weston_desktop_api_surface_removed(surface->desktop,
356 surface->surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200357
358 if (surface->add_idle != NULL)
359 wl_event_source_remove(surface->add_idle);
360
361 if (surface->configure_idle != NULL)
362 wl_event_source_remove(surface->configure_idle);
363
Quentin Glidic749637a2017-07-18 12:59:14 +0200364 wl_list_for_each_safe(configure, temp, &surface->configure_list, link)
365 free(configure);
366
Quentin Glidic248dd102016-08-12 10:41:34 +0200367 free(surface);
368}
369
370static void
371weston_desktop_xdg_surface_protocol_set_parent(struct wl_client *wl_client,
372 struct wl_resource *resource,
373 struct wl_resource *parent_resource)
374{
375 struct weston_desktop_surface *dsurface =
376 wl_resource_get_user_data(resource);
377 struct weston_desktop_xdg_surface *surface =
378 weston_desktop_surface_get_implementation_data(dsurface);
379 struct weston_desktop_surface *parent = NULL;
380
381 if (parent_resource != NULL)
382 parent = wl_resource_get_user_data(parent_resource);
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200383
384 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200385 weston_desktop_api_set_parent(surface->desktop, dsurface, parent);
386}
387
388static void
389weston_desktop_xdg_surface_protocol_set_title(struct wl_client *wl_client,
390 struct wl_resource *resource,
391 const char *title)
392{
393 struct weston_desktop_surface *surface =
394 wl_resource_get_user_data(resource);
395
396 weston_desktop_surface_set_title(surface, title);
397}
398
399static void
400weston_desktop_xdg_surface_protocol_set_app_id(struct wl_client *wl_client,
401 struct wl_resource *resource,
402 const char *app_id)
403{
404 struct weston_desktop_surface *surface =
405 wl_resource_get_user_data(resource);
406
407 weston_desktop_surface_set_app_id(surface, app_id);
408}
409
410static void
411weston_desktop_xdg_surface_protocol_show_window_menu(struct wl_client *wl_client,
412 struct wl_resource *resource,
413 struct wl_resource *seat_resource,
414 uint32_t serial,
415 int32_t x, int32_t y)
416{
417 struct weston_desktop_surface *dsurface =
418 wl_resource_get_user_data(resource);
419 struct weston_seat *seat =
420 wl_resource_get_user_data(seat_resource);
421 struct weston_desktop_xdg_surface *surface =
422 weston_desktop_surface_get_implementation_data(dsurface);
423
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200424 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200425 weston_desktop_api_show_window_menu(surface->desktop, dsurface, seat, x, y);
426}
427
428static void
429weston_desktop_xdg_surface_protocol_move(struct wl_client *wl_client,
430 struct wl_resource *resource,
431 struct wl_resource *seat_resource,
432 uint32_t serial)
433{
434 struct weston_desktop_surface *dsurface =
435 wl_resource_get_user_data(resource);
436 struct weston_seat *seat =
437 wl_resource_get_user_data(seat_resource);
438 struct weston_desktop_xdg_surface *surface =
439 weston_desktop_surface_get_implementation_data(dsurface);
440
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200441 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200442 weston_desktop_api_move(surface->desktop, dsurface, seat, serial);
443}
444
445static void
446weston_desktop_xdg_surface_protocol_resize(struct wl_client *wl_client,
447 struct wl_resource *resource,
448 struct wl_resource *seat_resource,
449 uint32_t serial,
450 enum xdg_surface_resize_edge edges)
451{
452 struct weston_desktop_surface *dsurface =
453 wl_resource_get_user_data(resource);
454 struct weston_seat *seat =
455 wl_resource_get_user_data(seat_resource);
456 struct weston_desktop_xdg_surface *surface =
457 weston_desktop_surface_get_implementation_data(dsurface);
Armin Krezović4e2fa0a2016-09-10 19:11:21 +0200458 enum weston_desktop_surface_edge surf_edges =
459 (enum weston_desktop_surface_edge) edges;
Quentin Glidic248dd102016-08-12 10:41:34 +0200460
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200461 weston_desktop_xdg_surface_ensure_added(surface);
Armin Krezović4e2fa0a2016-09-10 19:11:21 +0200462 weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, surf_edges);
Quentin Glidic248dd102016-08-12 10:41:34 +0200463}
464
465static void
466weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client,
467 struct wl_resource *resource,
468 uint32_t serial)
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);
Quentin Glidic749637a2017-07-18 12:59:14 +0200474 struct weston_desktop_xdg_surface_configure *configure, *temp;
475 bool found = false;
Quentin Glidic248dd102016-08-12 10:41:34 +0200476
Quentin Glidic749637a2017-07-18 12:59:14 +0200477 wl_list_for_each_safe(configure, temp, &surface->configure_list, link) {
478 if (configure->serial < serial) {
479 wl_list_remove(&configure->link);
480 free(configure);
481 } else if (configure->serial == serial) {
482 wl_list_remove(&configure->link);
483 found = true;
484 }
485 break;
486 }
487 if (!found) {
488 struct weston_desktop_client *client =
489 weston_desktop_surface_get_client(dsurface);
490 struct wl_resource *client_resource =
491 weston_desktop_client_get_resource(client);
492 wl_resource_post_error(client_resource,
493 XDG_SHELL_ERROR_DEFUNCT_SURFACES,
494 "Wrong configure serial: %u", serial);
Quentin Glidic248dd102016-08-12 10:41:34 +0200495 return;
Quentin Glidic749637a2017-07-18 12:59:14 +0200496 }
Quentin Glidic248dd102016-08-12 10:41:34 +0200497
Quentin Glidic749637a2017-07-18 12:59:14 +0200498 surface->next.state = configure->state;
499 surface->next.size = configure->size;
500
501 free(configure);
Quentin Glidic248dd102016-08-12 10:41:34 +0200502}
503
504static void
505weston_desktop_xdg_surface_protocol_set_window_geometry(struct wl_client *wl_client,
506 struct wl_resource *resource,
507 int32_t x, int32_t y,
508 int32_t width, int32_t height)
509{
510 struct weston_desktop_surface *dsurface =
511 wl_resource_get_user_data(resource);
512 struct weston_desktop_xdg_surface *surface =
513 weston_desktop_surface_get_implementation_data(dsurface);
514
515 surface->has_next_geometry = true;
516 surface->next_geometry.x = x;
517 surface->next_geometry.y = y;
518 surface->next_geometry.width = width;
519 surface->next_geometry.height = height;
520}
521
522static void
523weston_desktop_xdg_surface_protocol_set_maximized(struct wl_client *wl_client,
524 struct wl_resource *resource)
525{
526 struct weston_desktop_surface *dsurface =
527 wl_resource_get_user_data(resource);
528 struct weston_desktop_xdg_surface *surface =
529 weston_desktop_surface_get_implementation_data(dsurface);
530
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200531 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200532 weston_desktop_api_maximized_requested(surface->desktop, dsurface, true);
533}
534
535static void
536weston_desktop_xdg_surface_protocol_unset_maximized(struct wl_client *wl_client,
537 struct wl_resource *resource)
538{
539 struct weston_desktop_surface *dsurface =
540 wl_resource_get_user_data(resource);
541 struct weston_desktop_xdg_surface *surface =
542 weston_desktop_surface_get_implementation_data(dsurface);
543
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200544 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200545 weston_desktop_api_maximized_requested(surface->desktop, dsurface, false);
546}
547
548static void
549weston_desktop_xdg_surface_protocol_set_fullscreen(struct wl_client *wl_client,
550 struct wl_resource *resource,
551 struct wl_resource *output_resource)
552{
553 struct weston_desktop_surface *dsurface =
554 wl_resource_get_user_data(resource);
555 struct weston_desktop_xdg_surface *surface =
556 weston_desktop_surface_get_implementation_data(dsurface);
557 struct weston_output *output = NULL;
558
559 if (output_resource != NULL)
Pekka Paalanen9ffb2502017-03-27 15:14:32 +0300560 output = weston_output_from_resource(output_resource);
Quentin Glidic248dd102016-08-12 10:41:34 +0200561
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200562 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200563 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
564 true, output);
565}
566
567static void
568weston_desktop_xdg_surface_protocol_unset_fullscreen(struct wl_client *wl_client,
569 struct wl_resource *resource)
570{
571 struct weston_desktop_surface *dsurface =
572 wl_resource_get_user_data(resource);
573 struct weston_desktop_xdg_surface *surface =
574 weston_desktop_surface_get_implementation_data(dsurface);
575
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200576 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200577 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
578 false, NULL);
579}
580
581static void
582weston_desktop_xdg_surface_protocol_set_minimized(struct wl_client *wl_client,
583 struct wl_resource *resource)
584{
585 struct weston_desktop_surface *dsurface =
586 wl_resource_get_user_data(resource);
587 struct weston_desktop_xdg_surface *surface =
588 weston_desktop_surface_get_implementation_data(dsurface);
589
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200590 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200591 weston_desktop_api_minimized_requested(surface->desktop, dsurface);
592}
593
594static const struct xdg_surface_interface weston_desktop_xdg_surface_implementation = {
595 .destroy = weston_desktop_destroy_request,
596 .set_parent = weston_desktop_xdg_surface_protocol_set_parent,
597 .set_title = weston_desktop_xdg_surface_protocol_set_title,
598 .set_app_id = weston_desktop_xdg_surface_protocol_set_app_id,
599 .show_window_menu = weston_desktop_xdg_surface_protocol_show_window_menu,
600 .move = weston_desktop_xdg_surface_protocol_move,
601 .resize = weston_desktop_xdg_surface_protocol_resize,
602 .ack_configure = weston_desktop_xdg_surface_protocol_ack_configure,
603 .set_window_geometry = weston_desktop_xdg_surface_protocol_set_window_geometry,
604 .set_maximized = weston_desktop_xdg_surface_protocol_set_maximized,
605 .unset_maximized = weston_desktop_xdg_surface_protocol_unset_maximized,
606 .set_fullscreen = weston_desktop_xdg_surface_protocol_set_fullscreen,
607 .unset_fullscreen = weston_desktop_xdg_surface_protocol_unset_fullscreen,
608 .set_minimized = weston_desktop_xdg_surface_protocol_set_minimized,
609};
610
611static const struct weston_desktop_surface_implementation weston_desktop_xdg_surface_internal_implementation = {
612 .set_maximized = weston_desktop_xdg_surface_set_maximized,
613 .set_fullscreen = weston_desktop_xdg_surface_set_fullscreen,
614 .set_resizing = weston_desktop_xdg_surface_set_resizing,
615 .set_activated = weston_desktop_xdg_surface_set_activated,
616 .set_size = weston_desktop_xdg_surface_set_size,
617 .committed = weston_desktop_xdg_surface_committed,
618 .ping = weston_desktop_xdg_surface_ping,
619 .close = weston_desktop_xdg_surface_close,
620
621 .get_maximized = weston_desktop_xdg_surface_get_maximized,
622 .get_fullscreen = weston_desktop_xdg_surface_get_fullscreen,
623 .get_resizing = weston_desktop_xdg_surface_get_resizing,
624 .get_activated = weston_desktop_xdg_surface_get_activated,
625
626 .destroy = weston_desktop_xdg_surface_destroy,
627};
628
629static void
630weston_desktop_xdg_popup_close(struct weston_desktop_surface *dsurface,
631 void *user_data)
632{
633 struct weston_desktop_xdg_popup *popup = user_data;
634
635 xdg_popup_send_popup_done(popup->resource);
636}
637
638static void
639weston_desktop_xdg_popup_destroy(struct weston_desktop_surface *dsurface,
640 void *user_data)
641{
642 struct weston_desktop_xdg_popup *popup = user_data;
643 struct weston_desktop_surface *topmost;
644 struct weston_desktop_client *client =
645 weston_desktop_surface_get_client(popup->popup);
646
647 if (!weston_desktop_surface_get_grab(popup->popup))
648 goto end;
649
650 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(popup->seat);
651 if (topmost != popup->popup) {
652 struct wl_resource *client_resource =
653 weston_desktop_client_get_resource(client);
654
655 wl_resource_post_error(client_resource,
656 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
657 "xdg_popup was destroyed while it was not the topmost popup.");
658 }
659
660 weston_desktop_surface_popup_ungrab(popup->popup, popup->seat);
661
662end:
663 free(popup);
664}
665
666static const struct xdg_popup_interface weston_desktop_xdg_popup_implementation = {
667 .destroy = weston_desktop_destroy_request,
668};
669
670static const struct weston_desktop_surface_implementation weston_desktop_xdg_popup_internal_implementation = {
671 .close = weston_desktop_xdg_popup_close,
672
673 .destroy = weston_desktop_xdg_popup_destroy,
674};
675
676static void
677weston_desktop_xdg_shell_protocol_use_unstable_version(struct wl_client *wl_client,
678 struct wl_resource *resource,
679 int32_t version)
680{
681 if (version > 1) {
682 wl_resource_post_error(resource,
683 1, "xdg_shell version not supported");
684 return;
685 }
686}
687
688static void
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200689weston_desktop_xdg_surface_add_idle_callback(void *user_data)
Quentin Glidic248dd102016-08-12 10:41:34 +0200690{
691 struct weston_desktop_xdg_surface *surface = user_data;
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200692
Quentin Glidic248dd102016-08-12 10:41:34 +0200693 surface->add_idle = NULL;
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200694 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200695}
696
697static void
698weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client,
699 struct wl_resource *resource,
700 uint32_t id,
701 struct wl_resource *surface_resource)
702{
703 struct weston_desktop_client *client =
704 wl_resource_get_user_data(resource);
705 struct weston_desktop *desktop =
706 weston_desktop_client_get_desktop(client);
707 struct weston_surface *wsurface =
708 wl_resource_get_user_data(surface_resource);
709 struct weston_desktop_xdg_surface *surface;
710 struct wl_display *display = weston_desktop_get_display(desktop);
711 struct wl_event_loop *loop = wl_display_get_event_loop(display);
712
713 if (weston_surface_set_role(wsurface, "xdg_surface", resource, XDG_SHELL_ERROR_ROLE) < 0)
714 return;
715
716 surface = zalloc(sizeof(struct weston_desktop_xdg_surface));
717 if (surface == NULL) {
718 wl_client_post_no_memory(wl_client);
719 return;
720 }
721
722 surface->desktop = desktop;
723
724 surface->surface =
725 weston_desktop_surface_create(surface->desktop, client,
726 wsurface,
727 &weston_desktop_xdg_surface_internal_implementation,
728 surface);
729 if (surface->surface == NULL) {
730 free(surface);
731 return;
732 }
733
734 surface->resource =
735 weston_desktop_surface_add_resource(surface->surface,
736 &xdg_surface_interface,
737 &weston_desktop_xdg_surface_implementation,
738 id, NULL);
739 if (surface->resource == NULL)
740 return;
741
742 surface->add_idle =
743 wl_event_loop_add_idle(loop,
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200744 weston_desktop_xdg_surface_add_idle_callback,
Quentin Glidic248dd102016-08-12 10:41:34 +0200745 surface);
746}
747
748static void
749weston_desktop_xdg_shell_protocol_get_xdg_popup(struct wl_client *wl_client,
750 struct wl_resource *resource,
751 uint32_t id,
752 struct wl_resource *surface_resource,
753 struct wl_resource *parent_resource,
754 struct wl_resource *seat_resource,
755 uint32_t serial,
756 int32_t x, int32_t y)
757{
758 struct weston_desktop_client *client =
759 wl_resource_get_user_data(resource);
760 struct weston_surface *wsurface =
761 wl_resource_get_user_data(surface_resource);
762 struct weston_surface *wparent =
763 wl_resource_get_user_data(parent_resource);
764 struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
765 struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
766 struct weston_desktop_surface *parent, *topmost;
767 bool parent_is_popup, parent_is_xdg;
768 struct weston_desktop_xdg_popup *popup;
769
770 if (weston_surface_set_role(wsurface, "xdg_popup", resource, XDG_SHELL_ERROR_ROLE) < 0)
771 return;
772
773 if (!weston_surface_is_desktop_surface(wparent)) {
774 wl_resource_post_error(resource,
775 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
776 "xdg_popup parent was invalid");
777 return;
778 }
779
780 parent = weston_surface_get_desktop_surface(wparent);
781 parent_is_xdg =
782 weston_desktop_surface_has_implementation(parent,
783 &weston_desktop_xdg_surface_internal_implementation);
784 parent_is_popup =
785 weston_desktop_surface_has_implementation(parent,
786 &weston_desktop_xdg_popup_internal_implementation);
787
788 if (!parent_is_xdg && !parent_is_popup) {
789 wl_resource_post_error(resource,
790 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
791 "xdg_popup parent was invalid");
792 return;
793 }
794
795 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(seat);
796 if ((topmost == NULL && parent_is_popup) ||
797 (topmost != NULL && topmost != parent)) {
798 wl_resource_post_error(resource,
799 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
800 "xdg_popup was not created on the topmost popup");
801 return;
802 }
803
804 popup = zalloc(sizeof(struct weston_desktop_xdg_popup));
805 if (popup == NULL) {
806 wl_client_post_no_memory(wl_client);
807 return;
808 }
809
810 popup->desktop = weston_desktop_client_get_desktop(client);
811 popup->display = weston_desktop_get_display(popup->desktop);
812 popup->seat = seat;
813
814 popup->popup =
815 weston_desktop_surface_create(popup->desktop, client, wsurface,
816 &weston_desktop_xdg_popup_internal_implementation,
817 popup);
818 if (popup->popup == NULL) {
819 free(popup);
820 return;
821 }
822
823 popup->resource =
824 weston_desktop_surface_add_resource(popup->popup,
825 &xdg_popup_interface,
826 &weston_desktop_xdg_popup_implementation,
827 id, NULL);
828 if (popup->resource == NULL)
829 return;
830
831 weston_desktop_surface_set_relative_to(popup->popup, parent, x, y, false);
832 weston_desktop_surface_popup_grab(popup->popup, popup->seat, serial);
833}
834
835static void
836weston_desktop_xdg_shell_protocol_pong(struct wl_client *wl_client,
837 struct wl_resource *resource,
838 uint32_t serial)
839{
840 struct weston_desktop_client *client =
841 wl_resource_get_user_data(resource);
842
843 weston_desktop_client_pong(client, serial);
844}
845
846static const struct xdg_shell_interface weston_desktop_xdg_shell_implementation = {
847 .destroy = weston_desktop_destroy_request,
848 .use_unstable_version = weston_desktop_xdg_shell_protocol_use_unstable_version,
849 .get_xdg_surface = weston_desktop_xdg_shell_protocol_get_xdg_surface,
850 .get_xdg_popup = weston_desktop_xdg_shell_protocol_get_xdg_popup,
851 .pong = weston_desktop_xdg_shell_protocol_pong,
852};
853
854static int
855xdg_shell_unversioned_dispatch(const void *implementation,
856 void *_target, uint32_t opcode,
857 const struct wl_message *message,
858 union wl_argument *args)
859{
860 struct wl_resource *resource = _target;
861 struct weston_desktop_client *client =
862 wl_resource_get_user_data(resource);
863
864 if (opcode != 1 /* XDG_SHELL_USE_UNSTABLE_VERSION */) {
865 wl_resource_post_error(resource,
866 WL_DISPLAY_ERROR_INVALID_OBJECT,
867 "must call use_unstable_version first");
868 return 0;
869 }
870
871#define XDG_SERVER_VERSION 5
872
873 if (args[0].i != XDG_SERVER_VERSION) {
874 wl_resource_post_error(resource,
875 WL_DISPLAY_ERROR_INVALID_OBJECT,
876 "incompatible version, server is %d " "client wants %d",
877 XDG_SERVER_VERSION, args[0].i);
878 return 0;
879 }
880
881 wl_resource_set_implementation(resource,
882 &weston_desktop_xdg_shell_implementation,
883 client, implementation);
884
885 return 1;
886}
887
888static void
889weston_desktop_xdg_shell_bind(struct wl_client *client, void *data,
890 uint32_t version, uint32_t id)
891{
892 struct weston_desktop *desktop = data;
893
894 weston_desktop_client_create(desktop, client,
895 xdg_shell_unversioned_dispatch,
896 &xdg_shell_interface, NULL, version, id);
897}
898
899struct wl_global *
900weston_desktop_xdg_shell_v5_create(struct weston_desktop *desktop,
901 struct wl_display *display)
902{
903 return wl_global_create(display,
904 &xdg_shell_interface,
905 WD_XDG_SHELL_PROTOCOL_VERSION,
906 desktop, weston_desktop_xdg_shell_bind);
907}