blob: c91c25905913e2ec32552f94eb424ff31da17522 [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
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200267 if (surface->next.state.maximized || surface->next.state.fullscreen)
Quentin Glidicac394a12017-07-12 09:45:43 +0200268 reconfigure = surface->next.size.width != wsurface->width ||
269 surface->next.size.height != wsurface->height;
Quentin Glidic248dd102016-08-12 10:41:34 +0200270
271 if (reconfigure) {
Quentin Glidicd51f8262017-04-13 20:25:27 +0200272 weston_desktop_xdg_surface_schedule_configure(surface, true);
Quentin Glidic248dd102016-08-12 10:41:34 +0200273 } else {
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200274 surface->current.state = surface->next.state;
Quentin Glidic248dd102016-08-12 10:41:34 +0200275 if (surface->has_next_geometry) {
276 surface->has_next_geometry = false;
277 weston_desktop_surface_set_geometry(surface->surface,
278 surface->next_geometry);
279 }
280
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200281 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200282 weston_desktop_api_committed(surface->desktop, surface->surface,
283 sx, sy);
284 }
285}
286
287static void
288weston_desktop_xdg_surface_ping(struct weston_desktop_surface *dsurface,
289 uint32_t serial, void *user_data)
290{
291 struct weston_desktop_client *client =
292 weston_desktop_surface_get_client(dsurface);
293
294 xdg_shell_send_ping(weston_desktop_client_get_resource(client),
295 serial);
296}
297
298static void
299weston_desktop_xdg_surface_close(struct weston_desktop_surface *dsurface,
300 void *user_data)
301{
302 struct weston_desktop_xdg_surface *surface = user_data;
303
304 xdg_surface_send_close(surface->resource);
305}
306
307static bool
308weston_desktop_xdg_surface_get_maximized(struct weston_desktop_surface *dsurface,
309 void *user_data)
310{
311 struct weston_desktop_xdg_surface *surface = user_data;
312
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200313 return surface->current.state.maximized;
Quentin Glidic248dd102016-08-12 10:41:34 +0200314}
315
316static bool
317weston_desktop_xdg_surface_get_fullscreen(struct weston_desktop_surface *dsurface,
318 void *user_data)
319{
320 struct weston_desktop_xdg_surface *surface = user_data;
321
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200322 return surface->current.state.fullscreen;
Quentin Glidic248dd102016-08-12 10:41:34 +0200323}
324
325static bool
326weston_desktop_xdg_surface_get_resizing(struct weston_desktop_surface *dsurface,
327 void *user_data)
328{
329 struct weston_desktop_xdg_surface *surface = user_data;
330
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200331 return surface->current.state.resizing;
Quentin Glidic248dd102016-08-12 10:41:34 +0200332}
333
334static bool
335weston_desktop_xdg_surface_get_activated(struct weston_desktop_surface *dsurface,
336 void *user_data)
337{
338 struct weston_desktop_xdg_surface *surface = user_data;
339
Quentin Glidic19d1f6e2017-07-12 09:42:57 +0200340 return surface->current.state.activated;
Quentin Glidic248dd102016-08-12 10:41:34 +0200341}
342
343static void
344weston_desktop_xdg_surface_destroy(struct weston_desktop_surface *dsurface,
345 void *user_data)
346{
347 struct weston_desktop_xdg_surface *surface = user_data;
Quentin Glidic749637a2017-07-18 12:59:14 +0200348 struct weston_desktop_xdg_surface_configure *configure, *temp;
Quentin Glidic248dd102016-08-12 10:41:34 +0200349
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200350 if (surface->added)
351 weston_desktop_api_surface_removed(surface->desktop,
352 surface->surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200353
354 if (surface->add_idle != NULL)
355 wl_event_source_remove(surface->add_idle);
356
357 if (surface->configure_idle != NULL)
358 wl_event_source_remove(surface->configure_idle);
359
Quentin Glidic749637a2017-07-18 12:59:14 +0200360 wl_list_for_each_safe(configure, temp, &surface->configure_list, link)
361 free(configure);
362
Quentin Glidic248dd102016-08-12 10:41:34 +0200363 free(surface);
364}
365
366static void
367weston_desktop_xdg_surface_protocol_set_parent(struct wl_client *wl_client,
368 struct wl_resource *resource,
369 struct wl_resource *parent_resource)
370{
371 struct weston_desktop_surface *dsurface =
372 wl_resource_get_user_data(resource);
373 struct weston_desktop_xdg_surface *surface =
374 weston_desktop_surface_get_implementation_data(dsurface);
375 struct weston_desktop_surface *parent = NULL;
376
377 if (parent_resource != NULL)
378 parent = wl_resource_get_user_data(parent_resource);
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200379
380 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200381 weston_desktop_api_set_parent(surface->desktop, dsurface, parent);
382}
383
384static void
385weston_desktop_xdg_surface_protocol_set_title(struct wl_client *wl_client,
386 struct wl_resource *resource,
387 const char *title)
388{
389 struct weston_desktop_surface *surface =
390 wl_resource_get_user_data(resource);
391
392 weston_desktop_surface_set_title(surface, title);
393}
394
395static void
396weston_desktop_xdg_surface_protocol_set_app_id(struct wl_client *wl_client,
397 struct wl_resource *resource,
398 const char *app_id)
399{
400 struct weston_desktop_surface *surface =
401 wl_resource_get_user_data(resource);
402
403 weston_desktop_surface_set_app_id(surface, app_id);
404}
405
406static void
407weston_desktop_xdg_surface_protocol_show_window_menu(struct wl_client *wl_client,
408 struct wl_resource *resource,
409 struct wl_resource *seat_resource,
410 uint32_t serial,
411 int32_t x, int32_t y)
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);
419
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200420 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200421 weston_desktop_api_show_window_menu(surface->desktop, dsurface, seat, x, y);
422}
423
424static void
425weston_desktop_xdg_surface_protocol_move(struct wl_client *wl_client,
426 struct wl_resource *resource,
427 struct wl_resource *seat_resource,
428 uint32_t serial)
429{
430 struct weston_desktop_surface *dsurface =
431 wl_resource_get_user_data(resource);
432 struct weston_seat *seat =
433 wl_resource_get_user_data(seat_resource);
434 struct weston_desktop_xdg_surface *surface =
435 weston_desktop_surface_get_implementation_data(dsurface);
436
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200437 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200438 weston_desktop_api_move(surface->desktop, dsurface, seat, serial);
439}
440
441static void
442weston_desktop_xdg_surface_protocol_resize(struct wl_client *wl_client,
443 struct wl_resource *resource,
444 struct wl_resource *seat_resource,
445 uint32_t serial,
446 enum xdg_surface_resize_edge edges)
447{
448 struct weston_desktop_surface *dsurface =
449 wl_resource_get_user_data(resource);
450 struct weston_seat *seat =
451 wl_resource_get_user_data(seat_resource);
452 struct weston_desktop_xdg_surface *surface =
453 weston_desktop_surface_get_implementation_data(dsurface);
Armin Krezović4e2fa0a2016-09-10 19:11:21 +0200454 enum weston_desktop_surface_edge surf_edges =
455 (enum weston_desktop_surface_edge) edges;
Quentin Glidic248dd102016-08-12 10:41:34 +0200456
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200457 weston_desktop_xdg_surface_ensure_added(surface);
Armin Krezović4e2fa0a2016-09-10 19:11:21 +0200458 weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, surf_edges);
Quentin Glidic248dd102016-08-12 10:41:34 +0200459}
460
461static void
462weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client,
463 struct wl_resource *resource,
464 uint32_t serial)
465{
466 struct weston_desktop_surface *dsurface =
467 wl_resource_get_user_data(resource);
468 struct weston_desktop_xdg_surface *surface =
469 weston_desktop_surface_get_implementation_data(dsurface);
Quentin Glidic749637a2017-07-18 12:59:14 +0200470 struct weston_desktop_xdg_surface_configure *configure, *temp;
471 bool found = false;
Quentin Glidic248dd102016-08-12 10:41:34 +0200472
Quentin Glidic749637a2017-07-18 12:59:14 +0200473 wl_list_for_each_safe(configure, temp, &surface->configure_list, link) {
474 if (configure->serial < serial) {
475 wl_list_remove(&configure->link);
476 free(configure);
477 } else if (configure->serial == serial) {
478 wl_list_remove(&configure->link);
479 found = true;
480 }
481 break;
482 }
483 if (!found) {
484 struct weston_desktop_client *client =
485 weston_desktop_surface_get_client(dsurface);
486 struct wl_resource *client_resource =
487 weston_desktop_client_get_resource(client);
488 wl_resource_post_error(client_resource,
489 XDG_SHELL_ERROR_DEFUNCT_SURFACES,
490 "Wrong configure serial: %u", serial);
Quentin Glidic248dd102016-08-12 10:41:34 +0200491 return;
Quentin Glidic749637a2017-07-18 12:59:14 +0200492 }
Quentin Glidic248dd102016-08-12 10:41:34 +0200493
Quentin Glidic749637a2017-07-18 12:59:14 +0200494 surface->next.state = configure->state;
495 surface->next.size = configure->size;
496
497 free(configure);
Quentin Glidic248dd102016-08-12 10:41:34 +0200498}
499
500static void
501weston_desktop_xdg_surface_protocol_set_window_geometry(struct wl_client *wl_client,
502 struct wl_resource *resource,
503 int32_t x, int32_t y,
504 int32_t width, int32_t height)
505{
506 struct weston_desktop_surface *dsurface =
507 wl_resource_get_user_data(resource);
508 struct weston_desktop_xdg_surface *surface =
509 weston_desktop_surface_get_implementation_data(dsurface);
510
511 surface->has_next_geometry = true;
512 surface->next_geometry.x = x;
513 surface->next_geometry.y = y;
514 surface->next_geometry.width = width;
515 surface->next_geometry.height = height;
516}
517
518static void
519weston_desktop_xdg_surface_protocol_set_maximized(struct wl_client *wl_client,
520 struct wl_resource *resource)
521{
522 struct weston_desktop_surface *dsurface =
523 wl_resource_get_user_data(resource);
524 struct weston_desktop_xdg_surface *surface =
525 weston_desktop_surface_get_implementation_data(dsurface);
526
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200527 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200528 weston_desktop_api_maximized_requested(surface->desktop, dsurface, true);
529}
530
531static void
532weston_desktop_xdg_surface_protocol_unset_maximized(struct wl_client *wl_client,
533 struct wl_resource *resource)
534{
535 struct weston_desktop_surface *dsurface =
536 wl_resource_get_user_data(resource);
537 struct weston_desktop_xdg_surface *surface =
538 weston_desktop_surface_get_implementation_data(dsurface);
539
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200540 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200541 weston_desktop_api_maximized_requested(surface->desktop, dsurface, false);
542}
543
544static void
545weston_desktop_xdg_surface_protocol_set_fullscreen(struct wl_client *wl_client,
546 struct wl_resource *resource,
547 struct wl_resource *output_resource)
548{
549 struct weston_desktop_surface *dsurface =
550 wl_resource_get_user_data(resource);
551 struct weston_desktop_xdg_surface *surface =
552 weston_desktop_surface_get_implementation_data(dsurface);
553 struct weston_output *output = NULL;
554
555 if (output_resource != NULL)
556 output = wl_resource_get_user_data(output_resource);
557
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200558 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200559 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
560 true, output);
561}
562
563static void
564weston_desktop_xdg_surface_protocol_unset_fullscreen(struct wl_client *wl_client,
565 struct wl_resource *resource)
566{
567 struct weston_desktop_surface *dsurface =
568 wl_resource_get_user_data(resource);
569 struct weston_desktop_xdg_surface *surface =
570 weston_desktop_surface_get_implementation_data(dsurface);
571
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200572 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200573 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
574 false, NULL);
575}
576
577static void
578weston_desktop_xdg_surface_protocol_set_minimized(struct wl_client *wl_client,
579 struct wl_resource *resource)
580{
581 struct weston_desktop_surface *dsurface =
582 wl_resource_get_user_data(resource);
583 struct weston_desktop_xdg_surface *surface =
584 weston_desktop_surface_get_implementation_data(dsurface);
585
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200586 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200587 weston_desktop_api_minimized_requested(surface->desktop, dsurface);
588}
589
590static const struct xdg_surface_interface weston_desktop_xdg_surface_implementation = {
591 .destroy = weston_desktop_destroy_request,
592 .set_parent = weston_desktop_xdg_surface_protocol_set_parent,
593 .set_title = weston_desktop_xdg_surface_protocol_set_title,
594 .set_app_id = weston_desktop_xdg_surface_protocol_set_app_id,
595 .show_window_menu = weston_desktop_xdg_surface_protocol_show_window_menu,
596 .move = weston_desktop_xdg_surface_protocol_move,
597 .resize = weston_desktop_xdg_surface_protocol_resize,
598 .ack_configure = weston_desktop_xdg_surface_protocol_ack_configure,
599 .set_window_geometry = weston_desktop_xdg_surface_protocol_set_window_geometry,
600 .set_maximized = weston_desktop_xdg_surface_protocol_set_maximized,
601 .unset_maximized = weston_desktop_xdg_surface_protocol_unset_maximized,
602 .set_fullscreen = weston_desktop_xdg_surface_protocol_set_fullscreen,
603 .unset_fullscreen = weston_desktop_xdg_surface_protocol_unset_fullscreen,
604 .set_minimized = weston_desktop_xdg_surface_protocol_set_minimized,
605};
606
607static const struct weston_desktop_surface_implementation weston_desktop_xdg_surface_internal_implementation = {
608 .set_maximized = weston_desktop_xdg_surface_set_maximized,
609 .set_fullscreen = weston_desktop_xdg_surface_set_fullscreen,
610 .set_resizing = weston_desktop_xdg_surface_set_resizing,
611 .set_activated = weston_desktop_xdg_surface_set_activated,
612 .set_size = weston_desktop_xdg_surface_set_size,
613 .committed = weston_desktop_xdg_surface_committed,
614 .ping = weston_desktop_xdg_surface_ping,
615 .close = weston_desktop_xdg_surface_close,
616
617 .get_maximized = weston_desktop_xdg_surface_get_maximized,
618 .get_fullscreen = weston_desktop_xdg_surface_get_fullscreen,
619 .get_resizing = weston_desktop_xdg_surface_get_resizing,
620 .get_activated = weston_desktop_xdg_surface_get_activated,
621
622 .destroy = weston_desktop_xdg_surface_destroy,
623};
624
625static void
626weston_desktop_xdg_popup_close(struct weston_desktop_surface *dsurface,
627 void *user_data)
628{
629 struct weston_desktop_xdg_popup *popup = user_data;
630
631 xdg_popup_send_popup_done(popup->resource);
632}
633
634static void
635weston_desktop_xdg_popup_destroy(struct weston_desktop_surface *dsurface,
636 void *user_data)
637{
638 struct weston_desktop_xdg_popup *popup = user_data;
639 struct weston_desktop_surface *topmost;
640 struct weston_desktop_client *client =
641 weston_desktop_surface_get_client(popup->popup);
642
643 if (!weston_desktop_surface_get_grab(popup->popup))
644 goto end;
645
646 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(popup->seat);
647 if (topmost != popup->popup) {
648 struct wl_resource *client_resource =
649 weston_desktop_client_get_resource(client);
650
651 wl_resource_post_error(client_resource,
652 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
653 "xdg_popup was destroyed while it was not the topmost popup.");
654 }
655
656 weston_desktop_surface_popup_ungrab(popup->popup, popup->seat);
657
658end:
659 free(popup);
660}
661
662static const struct xdg_popup_interface weston_desktop_xdg_popup_implementation = {
663 .destroy = weston_desktop_destroy_request,
664};
665
666static const struct weston_desktop_surface_implementation weston_desktop_xdg_popup_internal_implementation = {
667 .close = weston_desktop_xdg_popup_close,
668
669 .destroy = weston_desktop_xdg_popup_destroy,
670};
671
672static void
673weston_desktop_xdg_shell_protocol_use_unstable_version(struct wl_client *wl_client,
674 struct wl_resource *resource,
675 int32_t version)
676{
677 if (version > 1) {
678 wl_resource_post_error(resource,
679 1, "xdg_shell version not supported");
680 return;
681 }
682}
683
684static void
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200685weston_desktop_xdg_surface_add_idle_callback(void *user_data)
Quentin Glidic248dd102016-08-12 10:41:34 +0200686{
687 struct weston_desktop_xdg_surface *surface = user_data;
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200688
Quentin Glidic248dd102016-08-12 10:41:34 +0200689 surface->add_idle = NULL;
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200690 weston_desktop_xdg_surface_ensure_added(surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200691}
692
693static void
694weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client,
695 struct wl_resource *resource,
696 uint32_t id,
697 struct wl_resource *surface_resource)
698{
699 struct weston_desktop_client *client =
700 wl_resource_get_user_data(resource);
701 struct weston_desktop *desktop =
702 weston_desktop_client_get_desktop(client);
703 struct weston_surface *wsurface =
704 wl_resource_get_user_data(surface_resource);
705 struct weston_desktop_xdg_surface *surface;
706 struct wl_display *display = weston_desktop_get_display(desktop);
707 struct wl_event_loop *loop = wl_display_get_event_loop(display);
708
709 if (weston_surface_set_role(wsurface, "xdg_surface", resource, XDG_SHELL_ERROR_ROLE) < 0)
710 return;
711
712 surface = zalloc(sizeof(struct weston_desktop_xdg_surface));
713 if (surface == NULL) {
714 wl_client_post_no_memory(wl_client);
715 return;
716 }
717
718 surface->desktop = desktop;
719
720 surface->surface =
721 weston_desktop_surface_create(surface->desktop, client,
722 wsurface,
723 &weston_desktop_xdg_surface_internal_implementation,
724 surface);
725 if (surface->surface == NULL) {
726 free(surface);
727 return;
728 }
729
730 surface->resource =
731 weston_desktop_surface_add_resource(surface->surface,
732 &xdg_surface_interface,
733 &weston_desktop_xdg_surface_implementation,
734 id, NULL);
735 if (surface->resource == NULL)
736 return;
737
738 surface->add_idle =
739 wl_event_loop_add_idle(loop,
Quentin Glidic6967f0e2016-08-18 15:51:38 +0200740 weston_desktop_xdg_surface_add_idle_callback,
Quentin Glidic248dd102016-08-12 10:41:34 +0200741 surface);
742}
743
744static void
745weston_desktop_xdg_shell_protocol_get_xdg_popup(struct wl_client *wl_client,
746 struct wl_resource *resource,
747 uint32_t id,
748 struct wl_resource *surface_resource,
749 struct wl_resource *parent_resource,
750 struct wl_resource *seat_resource,
751 uint32_t serial,
752 int32_t x, int32_t y)
753{
754 struct weston_desktop_client *client =
755 wl_resource_get_user_data(resource);
756 struct weston_surface *wsurface =
757 wl_resource_get_user_data(surface_resource);
758 struct weston_surface *wparent =
759 wl_resource_get_user_data(parent_resource);
760 struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
761 struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
762 struct weston_desktop_surface *parent, *topmost;
763 bool parent_is_popup, parent_is_xdg;
764 struct weston_desktop_xdg_popup *popup;
765
766 if (weston_surface_set_role(wsurface, "xdg_popup", resource, XDG_SHELL_ERROR_ROLE) < 0)
767 return;
768
769 if (!weston_surface_is_desktop_surface(wparent)) {
770 wl_resource_post_error(resource,
771 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
772 "xdg_popup parent was invalid");
773 return;
774 }
775
776 parent = weston_surface_get_desktop_surface(wparent);
777 parent_is_xdg =
778 weston_desktop_surface_has_implementation(parent,
779 &weston_desktop_xdg_surface_internal_implementation);
780 parent_is_popup =
781 weston_desktop_surface_has_implementation(parent,
782 &weston_desktop_xdg_popup_internal_implementation);
783
784 if (!parent_is_xdg && !parent_is_popup) {
785 wl_resource_post_error(resource,
786 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
787 "xdg_popup parent was invalid");
788 return;
789 }
790
791 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(seat);
792 if ((topmost == NULL && parent_is_popup) ||
793 (topmost != NULL && topmost != parent)) {
794 wl_resource_post_error(resource,
795 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
796 "xdg_popup was not created on the topmost popup");
797 return;
798 }
799
800 popup = zalloc(sizeof(struct weston_desktop_xdg_popup));
801 if (popup == NULL) {
802 wl_client_post_no_memory(wl_client);
803 return;
804 }
805
806 popup->desktop = weston_desktop_client_get_desktop(client);
807 popup->display = weston_desktop_get_display(popup->desktop);
808 popup->seat = seat;
809
810 popup->popup =
811 weston_desktop_surface_create(popup->desktop, client, wsurface,
812 &weston_desktop_xdg_popup_internal_implementation,
813 popup);
814 if (popup->popup == NULL) {
815 free(popup);
816 return;
817 }
818
819 popup->resource =
820 weston_desktop_surface_add_resource(popup->popup,
821 &xdg_popup_interface,
822 &weston_desktop_xdg_popup_implementation,
823 id, NULL);
824 if (popup->resource == NULL)
825 return;
826
827 weston_desktop_surface_set_relative_to(popup->popup, parent, x, y, false);
828 weston_desktop_surface_popup_grab(popup->popup, popup->seat, serial);
829}
830
831static void
832weston_desktop_xdg_shell_protocol_pong(struct wl_client *wl_client,
833 struct wl_resource *resource,
834 uint32_t serial)
835{
836 struct weston_desktop_client *client =
837 wl_resource_get_user_data(resource);
838
839 weston_desktop_client_pong(client, serial);
840}
841
842static const struct xdg_shell_interface weston_desktop_xdg_shell_implementation = {
843 .destroy = weston_desktop_destroy_request,
844 .use_unstable_version = weston_desktop_xdg_shell_protocol_use_unstable_version,
845 .get_xdg_surface = weston_desktop_xdg_shell_protocol_get_xdg_surface,
846 .get_xdg_popup = weston_desktop_xdg_shell_protocol_get_xdg_popup,
847 .pong = weston_desktop_xdg_shell_protocol_pong,
848};
849
850static int
851xdg_shell_unversioned_dispatch(const void *implementation,
852 void *_target, uint32_t opcode,
853 const struct wl_message *message,
854 union wl_argument *args)
855{
856 struct wl_resource *resource = _target;
857 struct weston_desktop_client *client =
858 wl_resource_get_user_data(resource);
859
860 if (opcode != 1 /* XDG_SHELL_USE_UNSTABLE_VERSION */) {
861 wl_resource_post_error(resource,
862 WL_DISPLAY_ERROR_INVALID_OBJECT,
863 "must call use_unstable_version first");
864 return 0;
865 }
866
867#define XDG_SERVER_VERSION 5
868
869 if (args[0].i != XDG_SERVER_VERSION) {
870 wl_resource_post_error(resource,
871 WL_DISPLAY_ERROR_INVALID_OBJECT,
872 "incompatible version, server is %d " "client wants %d",
873 XDG_SERVER_VERSION, args[0].i);
874 return 0;
875 }
876
877 wl_resource_set_implementation(resource,
878 &weston_desktop_xdg_shell_implementation,
879 client, implementation);
880
881 return 1;
882}
883
884static void
885weston_desktop_xdg_shell_bind(struct wl_client *client, void *data,
886 uint32_t version, uint32_t id)
887{
888 struct weston_desktop *desktop = data;
889
890 weston_desktop_client_create(desktop, client,
891 xdg_shell_unversioned_dispatch,
892 &xdg_shell_interface, NULL, version, id);
893}
894
895struct wl_global *
896weston_desktop_xdg_shell_v5_create(struct weston_desktop *desktop,
897 struct wl_display *display)
898{
899 return wl_global_create(display,
900 &xdg_shell_interface,
901 WD_XDG_SHELL_PROTOCOL_VERSION,
902 desktop, weston_desktop_xdg_shell_bind);
903}