blob: 2793100e9187e54d2d0aa5e244ec15fad68878f8 [file] [log] [blame]
ant8med8d9f5e2018-11-28 22:46:37 +01001/*
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#include <assert.h>
31
32#include <wayland-server.h>
33
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020034#include <libweston/libweston.h>
Pekka Paalanenecbdcfd2019-04-04 14:46:00 +030035#include <libweston/zalloc.h>
ant8med8d9f5e2018-11-28 22:46:37 +010036#include "xdg-shell-server-protocol.h"
37
Pekka Paalanen8ebd9812019-04-04 16:02:14 +030038#include <libweston-desktop/libweston-desktop.h>
ant8med8d9f5e2018-11-28 22:46:37 +010039#include "internal.h"
Jonas Ådahla76d2052019-12-02 22:19:21 +010040#include "shared/helpers.h"
ant8med8d9f5e2018-11-28 22:46:37 +010041
42/************************************************************************************
43 * WARNING: This file implements the stable xdg shell protocol.
44 * Any changes to this file may also need to be added to the xdg-shell-v6.c file which
45 * implements the older unstable xdg shell v6 protocol.
46 ************************************************************************************/
47
Jonas Ådahla76d2052019-12-02 22:19:21 +010048#define WD_XDG_SHELL_PROTOCOL_VERSION 3
ant8med8d9f5e2018-11-28 22:46:37 +010049
50static const char *weston_desktop_xdg_toplevel_role = "xdg_toplevel";
51static const char *weston_desktop_xdg_popup_role = "xdg_popup";
52
53struct weston_desktop_xdg_positioner {
54 struct weston_desktop *desktop;
55 struct weston_desktop_client *client;
56 struct wl_resource *resource;
57
58 struct weston_size size;
59 struct weston_geometry anchor_rect;
60 enum xdg_positioner_anchor anchor;
61 enum xdg_positioner_gravity gravity;
62 enum xdg_positioner_constraint_adjustment constraint_adjustment;
63 struct weston_position offset;
64};
65
66enum weston_desktop_xdg_surface_role {
67 WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE,
68 WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL,
69 WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP,
70};
71
72struct weston_desktop_xdg_surface {
73 struct wl_resource *resource;
74 struct weston_desktop *desktop;
75 struct weston_surface *surface;
76 struct weston_desktop_surface *desktop_surface;
77 bool configured;
78 struct wl_event_source *configure_idle;
79 struct wl_list configure_list; /* weston_desktop_xdg_surface_configure::link */
80
81 bool has_next_geometry;
82 struct weston_geometry next_geometry;
83
84 enum weston_desktop_xdg_surface_role role;
85};
86
87struct weston_desktop_xdg_surface_configure {
88 struct wl_list link; /* weston_desktop_xdg_surface::configure_list */
89 uint32_t serial;
90};
91
92struct weston_desktop_xdg_toplevel_state {
93 bool maximized;
94 bool fullscreen;
95 bool resizing;
96 bool activated;
97};
98
99struct weston_desktop_xdg_toplevel_configure {
100 struct weston_desktop_xdg_surface_configure base;
101 struct weston_desktop_xdg_toplevel_state state;
102 struct weston_size size;
103};
104
105struct weston_desktop_xdg_toplevel {
106 struct weston_desktop_xdg_surface base;
107
108 struct wl_resource *resource;
109 bool added;
110 struct {
111 struct weston_desktop_xdg_toplevel_state state;
112 struct weston_size size;
113 } pending;
114 struct {
115 struct weston_desktop_xdg_toplevel_state state;
116 struct weston_size size;
117 struct weston_size min_size, max_size;
118 } next;
119 struct {
120 struct weston_desktop_xdg_toplevel_state state;
121 struct weston_size min_size, max_size;
122 } current;
123};
124
125struct weston_desktop_xdg_popup {
126 struct weston_desktop_xdg_surface base;
127
128 struct wl_resource *resource;
129 bool committed;
130 struct weston_desktop_xdg_surface *parent;
131 struct weston_desktop_seat *seat;
132 struct weston_geometry geometry;
Jonas Ådahla76d2052019-12-02 22:19:21 +0100133
134 bool pending_reposition;
135 uint32_t pending_reposition_token;
ant8med8d9f5e2018-11-28 22:46:37 +0100136};
137
Jonas Ådahla76d2052019-12-02 22:19:21 +0100138#define weston_desktop_surface_role_biggest_size \
139 MAX(sizeof(struct weston_desktop_xdg_toplevel), \
140 sizeof(struct weston_desktop_xdg_popup))
141#define weston_desktop_surface_configure_biggest_size weston_desktop_surface_role_biggest_size
ant8med8d9f5e2018-11-28 22:46:37 +0100142
143
144static struct weston_geometry
145weston_desktop_xdg_positioner_get_geometry(struct weston_desktop_xdg_positioner *positioner,
146 struct weston_desktop_surface *dsurface,
147 struct weston_desktop_surface *parent)
148{
149 struct weston_geometry geometry = {
150 .x = positioner->offset.x,
151 .y = positioner->offset.y,
152 .width = positioner->size.width,
153 .height = positioner->size.height,
154 };
155
156 switch (positioner->anchor) {
157 case XDG_POSITIONER_ANCHOR_TOP:
158 case XDG_POSITIONER_ANCHOR_TOP_LEFT:
159 case XDG_POSITIONER_ANCHOR_TOP_RIGHT:
160 geometry.y += positioner->anchor_rect.y;
161 break;
162 case XDG_POSITIONER_ANCHOR_BOTTOM:
163 case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT:
164 case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT:
165 geometry.y += positioner->anchor_rect.y + positioner->anchor_rect.height;
166 break;
167 default:
168 geometry.y += positioner->anchor_rect.y + positioner->anchor_rect.height / 2;
169 }
170
171 switch (positioner->anchor) {
172 case XDG_POSITIONER_ANCHOR_LEFT:
173 case XDG_POSITIONER_ANCHOR_TOP_LEFT:
174 case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT:
175 geometry.x += positioner->anchor_rect.x;
176 break;
177 case XDG_POSITIONER_ANCHOR_RIGHT:
178 case XDG_POSITIONER_ANCHOR_TOP_RIGHT:
179 case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT:
180 geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width;
181 break;
182 default:
183 geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width / 2;
184 }
185
186 switch (positioner->gravity) {
187 case XDG_POSITIONER_GRAVITY_TOP:
188 case XDG_POSITIONER_GRAVITY_TOP_LEFT:
189 case XDG_POSITIONER_GRAVITY_TOP_RIGHT:
190 geometry.y -= geometry.height;
191 break;
192 case XDG_POSITIONER_GRAVITY_BOTTOM:
193 case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT:
194 case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT:
195 geometry.y = geometry.y;
196 break;
197 default:
198 geometry.y -= geometry.height / 2;
199 }
200
201 switch (positioner->gravity) {
202 case XDG_POSITIONER_GRAVITY_LEFT:
203 case XDG_POSITIONER_GRAVITY_TOP_LEFT:
204 case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT:
205 geometry.x -= geometry.width;
206 break;
207 case XDG_POSITIONER_GRAVITY_RIGHT:
208 case XDG_POSITIONER_GRAVITY_TOP_RIGHT:
209 case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT:
210 geometry.x = geometry.x;
211 break;
212 default:
213 geometry.x -= geometry.width / 2;
214 }
215
216 if (positioner->constraint_adjustment == XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE)
217 return geometry;
218
219 /* TODO: add compositor policy configuration and the code here */
220
221 return geometry;
222}
223
224static void
225weston_desktop_xdg_positioner_protocol_set_size(struct wl_client *wl_client,
226 struct wl_resource *resource,
227 int32_t width, int32_t height)
228{
229 struct weston_desktop_xdg_positioner *positioner =
230 wl_resource_get_user_data(resource);
231
232 if (width < 1 || height < 1) {
233 wl_resource_post_error(resource,
234 XDG_POSITIONER_ERROR_INVALID_INPUT,
235 "width and height must be positives and non-zero");
236 return;
237 }
238
239 positioner->size.width = width;
240 positioner->size.height = height;
241}
242
243static void
244weston_desktop_xdg_positioner_protocol_set_anchor_rect(struct wl_client *wl_client,
245 struct wl_resource *resource,
246 int32_t x, int32_t y,
247 int32_t width, int32_t height)
248{
249 struct weston_desktop_xdg_positioner *positioner =
250 wl_resource_get_user_data(resource);
251
252 if (width < 0 || height < 0) {
253 wl_resource_post_error(resource,
254 XDG_POSITIONER_ERROR_INVALID_INPUT,
255 "width and height must be non-negative");
256 return;
257 }
258
259 positioner->anchor_rect.x = x;
260 positioner->anchor_rect.y = y;
261 positioner->anchor_rect.width = width;
262 positioner->anchor_rect.height = height;
263}
264
265static void
266weston_desktop_xdg_positioner_protocol_set_anchor(struct wl_client *wl_client,
267 struct wl_resource *resource,
268 enum xdg_positioner_anchor anchor)
269{
270 struct weston_desktop_xdg_positioner *positioner =
271 wl_resource_get_user_data(resource);
272
273 positioner->anchor = anchor;
274}
275
276static void
277weston_desktop_xdg_positioner_protocol_set_gravity(struct wl_client *wl_client,
278 struct wl_resource *resource,
279 enum xdg_positioner_gravity gravity)
280{
281 struct weston_desktop_xdg_positioner *positioner =
282 wl_resource_get_user_data(resource);
283
284 positioner->gravity = gravity;
285}
286
287static void
288weston_desktop_xdg_positioner_protocol_set_constraint_adjustment(struct wl_client *wl_client,
289 struct wl_resource *resource,
290 enum xdg_positioner_constraint_adjustment constraint_adjustment)
291{
292 struct weston_desktop_xdg_positioner *positioner =
293 wl_resource_get_user_data(resource);
294
295 positioner->constraint_adjustment = constraint_adjustment;
296}
297
298static void
299weston_desktop_xdg_positioner_protocol_set_offset(struct wl_client *wl_client,
300 struct wl_resource *resource,
301 int32_t x, int32_t y)
302{
303 struct weston_desktop_xdg_positioner *positioner =
304 wl_resource_get_user_data(resource);
305
306 positioner->offset.x = x;
307 positioner->offset.y = y;
308}
309
310static void
Jonas Ådahla76d2052019-12-02 22:19:21 +0100311weston_desktop_xdg_positioner_protocol_set_reactive(struct wl_client *wl_client,
312 struct wl_resource *resource)
313{
314}
315
316static void
317weston_desktop_xdg_positioner_protocol_set_parent_size(struct wl_client *wl_client,
318 struct wl_resource *resource,
319 int32_t width,
320 int32_t height)
321{
322}
323
324static void
325weston_desktop_xdg_positioner_protocol_set_parent_configure(struct wl_client *wl_client,
326 struct wl_resource *resource,
327 uint32_t serial)
328{
329}
330
331static void
ant8med8d9f5e2018-11-28 22:46:37 +0100332weston_desktop_xdg_positioner_destroy(struct wl_resource *resource)
333{
334 struct weston_desktop_xdg_positioner *positioner =
335 wl_resource_get_user_data(resource);
336
337 free(positioner);
338}
339
340static const struct xdg_positioner_interface weston_desktop_xdg_positioner_implementation = {
341 .destroy = weston_desktop_destroy_request,
342 .set_size = weston_desktop_xdg_positioner_protocol_set_size,
343 .set_anchor_rect = weston_desktop_xdg_positioner_protocol_set_anchor_rect,
344 .set_anchor = weston_desktop_xdg_positioner_protocol_set_anchor,
345 .set_gravity = weston_desktop_xdg_positioner_protocol_set_gravity,
346 .set_constraint_adjustment = weston_desktop_xdg_positioner_protocol_set_constraint_adjustment,
347 .set_offset = weston_desktop_xdg_positioner_protocol_set_offset,
Jonas Ådahla76d2052019-12-02 22:19:21 +0100348 .set_reactive = weston_desktop_xdg_positioner_protocol_set_reactive,
349 .set_parent_size = weston_desktop_xdg_positioner_protocol_set_parent_size,
350 .set_parent_configure = weston_desktop_xdg_positioner_protocol_set_parent_configure,
ant8med8d9f5e2018-11-28 22:46:37 +0100351};
352
353static void
354weston_desktop_xdg_surface_schedule_configure(struct weston_desktop_xdg_surface *surface);
355
356static void
357weston_desktop_xdg_toplevel_ensure_added(struct weston_desktop_xdg_toplevel *toplevel)
358{
359 if (toplevel->added)
360 return;
361
362 weston_desktop_api_surface_added(toplevel->base.desktop,
363 toplevel->base.desktop_surface);
364 weston_desktop_xdg_surface_schedule_configure(&toplevel->base);
365 toplevel->added = true;
366}
367
368static void
369weston_desktop_xdg_toplevel_protocol_set_parent(struct wl_client *wl_client,
370 struct wl_resource *resource,
371 struct wl_resource *parent_resource)
372{
373 struct weston_desktop_surface *dsurface =
374 wl_resource_get_user_data(resource);
375 struct weston_desktop_xdg_toplevel *toplevel =
376 weston_desktop_surface_get_implementation_data(dsurface);
377 struct weston_desktop_surface *parent = NULL;
378
379 if (parent_resource != NULL)
380 parent = wl_resource_get_user_data(parent_resource);
381
382 weston_desktop_xdg_toplevel_ensure_added(toplevel);
383 weston_desktop_api_set_parent(toplevel->base.desktop, dsurface, parent);
384}
385
386static void
387weston_desktop_xdg_toplevel_protocol_set_title(struct wl_client *wl_client,
388 struct wl_resource *resource,
389 const char *title)
390{
391 struct weston_desktop_surface *toplevel =
392 wl_resource_get_user_data(resource);
393
394 weston_desktop_surface_set_title(toplevel, title);
395}
396
397static void
398weston_desktop_xdg_toplevel_protocol_set_app_id(struct wl_client *wl_client,
399 struct wl_resource *resource,
400 const char *app_id)
401{
402 struct weston_desktop_surface *toplevel =
403 wl_resource_get_user_data(resource);
404
405 weston_desktop_surface_set_app_id(toplevel, app_id);
406}
407
408static void
409weston_desktop_xdg_toplevel_protocol_show_window_menu(struct wl_client *wl_client,
410 struct wl_resource *resource,
411 struct wl_resource *seat_resource,
412 uint32_t serial,
413 int32_t x, int32_t y)
414{
415 struct weston_desktop_surface *dsurface =
416 wl_resource_get_user_data(resource);
417 struct weston_seat *seat =
418 wl_resource_get_user_data(seat_resource);
419 struct weston_desktop_xdg_toplevel *toplevel =
420 weston_desktop_surface_get_implementation_data(dsurface);
421
422 if (!toplevel->base.configured) {
423 wl_resource_post_error(toplevel->resource,
424 XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
425 "Surface has not been configured yet");
426 return;
427 }
428
429 if (seat == NULL)
430 return;
431
432 weston_desktop_api_show_window_menu(toplevel->base.desktop,
433 dsurface, seat, x, y);
434}
435
436static void
437weston_desktop_xdg_toplevel_protocol_move(struct wl_client *wl_client,
438 struct wl_resource *resource,
439 struct wl_resource *seat_resource,
440 uint32_t serial)
441{
442 struct weston_desktop_surface *dsurface =
443 wl_resource_get_user_data(resource);
444 struct weston_seat *seat =
445 wl_resource_get_user_data(seat_resource);
446 struct weston_desktop_xdg_toplevel *toplevel =
447 weston_desktop_surface_get_implementation_data(dsurface);
448
449 if (!toplevel->base.configured) {
450 wl_resource_post_error(toplevel->resource,
451 XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
452 "Surface has not been configured yet");
453 return;
454 }
455
456 if (seat == NULL)
457 return;
458
459 weston_desktop_api_move(toplevel->base.desktop, dsurface, seat, serial);
460}
461
462static void
463weston_desktop_xdg_toplevel_protocol_resize(struct wl_client *wl_client,
464 struct wl_resource *resource,
465 struct wl_resource *seat_resource,
466 uint32_t serial,
467 enum xdg_toplevel_resize_edge edges)
468{
469 struct weston_desktop_surface *dsurface =
470 wl_resource_get_user_data(resource);
471 struct weston_seat *seat =
472 wl_resource_get_user_data(seat_resource);
473 struct weston_desktop_xdg_toplevel *toplevel =
474 weston_desktop_surface_get_implementation_data(dsurface);
475 enum weston_desktop_surface_edge surf_edges =
476 (enum weston_desktop_surface_edge) edges;
477
478 if (!toplevel->base.configured) {
479 wl_resource_post_error(toplevel->resource,
480 XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
481 "Surface has not been configured yet");
482 return;
483 }
484
485 if (seat == NULL)
486 return;
487
488 weston_desktop_api_resize(toplevel->base.desktop,
489 dsurface, seat, serial, surf_edges);
490}
491
492static void
493weston_desktop_xdg_toplevel_ack_configure(struct weston_desktop_xdg_toplevel *toplevel,
494 struct weston_desktop_xdg_toplevel_configure *configure)
495{
496 toplevel->next.state = configure->state;
497 toplevel->next.size = configure->size;
498}
499
500static void
501weston_desktop_xdg_toplevel_protocol_set_min_size(struct wl_client *wl_client,
502 struct wl_resource *resource,
503 int32_t width, int32_t height)
504{
505 struct weston_desktop_surface *dsurface =
506 wl_resource_get_user_data(resource);
507 struct weston_desktop_xdg_toplevel *toplevel =
508 weston_desktop_surface_get_implementation_data(dsurface);
509
510 toplevel->next.min_size.width = width;
511 toplevel->next.min_size.height = height;
512}
513
514static void
515weston_desktop_xdg_toplevel_protocol_set_max_size(struct wl_client *wl_client,
516 struct wl_resource *resource,
517 int32_t width, int32_t height)
518{
519 struct weston_desktop_surface *dsurface =
520 wl_resource_get_user_data(resource);
521 struct weston_desktop_xdg_toplevel *toplevel =
522 weston_desktop_surface_get_implementation_data(dsurface);
523
524 toplevel->next.max_size.width = width;
525 toplevel->next.max_size.height = height;
526}
527
528static void
529weston_desktop_xdg_toplevel_protocol_set_maximized(struct wl_client *wl_client,
530 struct wl_resource *resource)
531{
532 struct weston_desktop_surface *dsurface =
533 wl_resource_get_user_data(resource);
534 struct weston_desktop_xdg_toplevel *toplevel =
535 weston_desktop_surface_get_implementation_data(dsurface);
536
537 weston_desktop_xdg_toplevel_ensure_added(toplevel);
538 weston_desktop_api_maximized_requested(toplevel->base.desktop, dsurface, true);
539}
540
541static void
542weston_desktop_xdg_toplevel_protocol_unset_maximized(struct wl_client *wl_client,
543 struct wl_resource *resource)
544{
545 struct weston_desktop_surface *dsurface =
546 wl_resource_get_user_data(resource);
547 struct weston_desktop_xdg_toplevel *toplevel =
548 weston_desktop_surface_get_implementation_data(dsurface);
549
550 weston_desktop_xdg_toplevel_ensure_added(toplevel);
551 weston_desktop_api_maximized_requested(toplevel->base.desktop, dsurface, false);
552}
553
554static void
555weston_desktop_xdg_toplevel_protocol_set_fullscreen(struct wl_client *wl_client,
556 struct wl_resource *resource,
557 struct wl_resource *output_resource)
558{
559 struct weston_desktop_surface *dsurface =
560 wl_resource_get_user_data(resource);
561 struct weston_desktop_xdg_toplevel *toplevel =
562 weston_desktop_surface_get_implementation_data(dsurface);
563 struct weston_output *output = NULL;
564
565 if (output_resource != NULL)
566 output = weston_head_from_resource(output_resource)->output;
567
568 weston_desktop_xdg_toplevel_ensure_added(toplevel);
569 weston_desktop_api_fullscreen_requested(toplevel->base.desktop, dsurface,
570 true, output);
571}
572
573static void
574weston_desktop_xdg_toplevel_protocol_unset_fullscreen(struct wl_client *wl_client,
575 struct wl_resource *resource)
576{
577 struct weston_desktop_surface *dsurface =
578 wl_resource_get_user_data(resource);
579 struct weston_desktop_xdg_toplevel *toplevel =
580 weston_desktop_surface_get_implementation_data(dsurface);
581
582 weston_desktop_xdg_toplevel_ensure_added(toplevel);
583 weston_desktop_api_fullscreen_requested(toplevel->base.desktop, dsurface,
584 false, NULL);
585}
586
587static void
588weston_desktop_xdg_toplevel_protocol_set_minimized(struct wl_client *wl_client,
589 struct wl_resource *resource)
590{
591 struct weston_desktop_surface *dsurface =
592 wl_resource_get_user_data(resource);
593 struct weston_desktop_xdg_toplevel *toplevel =
594 weston_desktop_surface_get_implementation_data(dsurface);
595
596 weston_desktop_xdg_toplevel_ensure_added(toplevel);
597 weston_desktop_api_minimized_requested(toplevel->base.desktop, dsurface);
598}
599
600static void
601weston_desktop_xdg_toplevel_send_configure(struct weston_desktop_xdg_toplevel *toplevel,
602 struct weston_desktop_xdg_toplevel_configure *configure)
603{
604 uint32_t *s;
605 struct wl_array states;
606
607 configure->state = toplevel->pending.state;
608 configure->size = toplevel->pending.size;
609
610 wl_array_init(&states);
611 if (toplevel->pending.state.maximized) {
612 s = wl_array_add(&states, sizeof(uint32_t));
613 *s = XDG_TOPLEVEL_STATE_MAXIMIZED;
614 }
615 if (toplevel->pending.state.fullscreen) {
616 s = wl_array_add(&states, sizeof(uint32_t));
617 *s = XDG_TOPLEVEL_STATE_FULLSCREEN;
618 }
619 if (toplevel->pending.state.resizing) {
620 s = wl_array_add(&states, sizeof(uint32_t));
621 *s = XDG_TOPLEVEL_STATE_RESIZING;
622 }
623 if (toplevel->pending.state.activated) {
624 s = wl_array_add(&states, sizeof(uint32_t));
625 *s = XDG_TOPLEVEL_STATE_ACTIVATED;
626 }
627
628 xdg_toplevel_send_configure(toplevel->resource,
629 toplevel->pending.size.width,
630 toplevel->pending.size.height,
631 &states);
632
633 wl_array_release(&states);
634};
635
636static void
637weston_desktop_xdg_toplevel_set_maximized(struct weston_desktop_surface *dsurface,
638 void *user_data, bool maximized)
639{
640 struct weston_desktop_xdg_toplevel *toplevel = user_data;
641
642 toplevel->pending.state.maximized = maximized;
643 weston_desktop_xdg_surface_schedule_configure(&toplevel->base);
644}
645
646static void
647weston_desktop_xdg_toplevel_set_fullscreen(struct weston_desktop_surface *dsurface,
648 void *user_data, bool fullscreen)
649{
650 struct weston_desktop_xdg_toplevel *toplevel = user_data;
651
652 toplevel->pending.state.fullscreen = fullscreen;
653 weston_desktop_xdg_surface_schedule_configure(&toplevel->base);
654}
655
656static void
657weston_desktop_xdg_toplevel_set_resizing(struct weston_desktop_surface *dsurface,
658 void *user_data, bool resizing)
659{
660 struct weston_desktop_xdg_toplevel *toplevel = user_data;
661
662 toplevel->pending.state.resizing = resizing;
663 weston_desktop_xdg_surface_schedule_configure(&toplevel->base);
664}
665
666static void
667weston_desktop_xdg_toplevel_set_activated(struct weston_desktop_surface *dsurface,
668 void *user_data, bool activated)
669{
670 struct weston_desktop_xdg_toplevel *toplevel = user_data;
671
672 toplevel->pending.state.activated = activated;
673 weston_desktop_xdg_surface_schedule_configure(&toplevel->base);
674}
675
676static void
677weston_desktop_xdg_toplevel_set_size(struct weston_desktop_surface *dsurface,
678 void *user_data,
679 int32_t width, int32_t height)
680{
681 struct weston_desktop_xdg_toplevel *toplevel = user_data;
682
683 toplevel->pending.size.width = width;
684 toplevel->pending.size.height = height;
685
686 weston_desktop_xdg_surface_schedule_configure(&toplevel->base);
687}
688
689static void
690weston_desktop_xdg_toplevel_committed(struct weston_desktop_xdg_toplevel *toplevel,
691 int32_t sx, int32_t sy)
692{
693 struct weston_surface *wsurface =
694 weston_desktop_surface_get_surface(toplevel->base.desktop_surface);
695
696 if (!wsurface->buffer_ref.buffer && !toplevel->added) {
697 weston_desktop_xdg_toplevel_ensure_added(toplevel);
698 return;
699 }
700 if (!wsurface->buffer_ref.buffer)
701 return;
702
703 struct weston_geometry geometry =
704 weston_desktop_surface_get_geometry(toplevel->base.desktop_surface);
705
Alexandros Frantzisf6bd2122020-05-13 16:33:03 +0300706 if (toplevel->next.state.maximized &&
ant8med8d9f5e2018-11-28 22:46:37 +0100707 (toplevel->next.size.width != geometry.width ||
708 toplevel->next.size.height != geometry.height)) {
709 struct weston_desktop_client *client =
710 weston_desktop_surface_get_client(toplevel->base.desktop_surface);
711 struct wl_resource *client_resource =
712 weston_desktop_client_get_resource(client);
713
714 wl_resource_post_error(client_resource,
715 XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
Daniel Stone24c0f832020-03-20 14:50:52 +0000716 "xdg_surface buffer (%" PRIi32 " x %" PRIi32 ") "
Alexandros Frantzisf6bd2122020-05-13 16:33:03 +0300717 "does not match the configured maximized state (%" PRIi32 " x %" PRIi32 ")",
718 geometry.width, geometry.height,
719 toplevel->next.size.width,
720 toplevel->next.size.height);
721 return;
722 }
723
724 if (toplevel->next.state.fullscreen &&
725 (toplevel->next.size.width < geometry.width ||
726 toplevel->next.size.height < geometry.height)) {
727 struct weston_desktop_client *client =
728 weston_desktop_surface_get_client(toplevel->base.desktop_surface);
729 struct wl_resource *client_resource =
730 weston_desktop_client_get_resource(client);
731
732 wl_resource_post_error(client_resource,
733 XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
Sebastian Krzyszkowiakce2fa932021-08-02 13:28:19 +0200734 "xdg_surface geometry (%" PRIi32 " x %" PRIi32 ") "
Alexandros Frantzisf6bd2122020-05-13 16:33:03 +0300735 "is larger than the configured fullscreen state (%" PRIi32 " x %" PRIi32 ")",
Daniel Stone24c0f832020-03-20 14:50:52 +0000736 geometry.width, geometry.height,
737 toplevel->next.size.width,
738 toplevel->next.size.height);
ant8med8d9f5e2018-11-28 22:46:37 +0100739 return;
740 }
741
742 toplevel->current.state = toplevel->next.state;
743 toplevel->current.min_size = toplevel->next.min_size;
744 toplevel->current.max_size = toplevel->next.max_size;
745
746 weston_desktop_api_committed(toplevel->base.desktop,
747 toplevel->base.desktop_surface,
748 sx, sy);
749}
750
751static void
752weston_desktop_xdg_toplevel_close(struct weston_desktop_xdg_toplevel *toplevel)
753{
754 xdg_toplevel_send_close(toplevel->resource);
755}
756
757static bool
758weston_desktop_xdg_toplevel_get_maximized(struct weston_desktop_surface *dsurface,
759 void *user_data)
760{
761 struct weston_desktop_xdg_toplevel *toplevel = user_data;
762
763 return toplevel->current.state.maximized;
764}
765
766static bool
767weston_desktop_xdg_toplevel_get_fullscreen(struct weston_desktop_surface *dsurface,
768 void *user_data)
769{
770 struct weston_desktop_xdg_toplevel *toplevel = user_data;
771
772 return toplevel->current.state.fullscreen;
773}
774
775static bool
776weston_desktop_xdg_toplevel_get_resizing(struct weston_desktop_surface *dsurface,
777 void *user_data)
778{
779 struct weston_desktop_xdg_toplevel *toplevel = user_data;
780
781 return toplevel->current.state.resizing;
782}
783
784static bool
785weston_desktop_xdg_toplevel_get_activated(struct weston_desktop_surface *dsurface,
786 void *user_data)
787{
788 struct weston_desktop_xdg_toplevel *toplevel = user_data;
789
790 return toplevel->current.state.activated;
791}
792
793static void
794weston_desktop_xdg_toplevel_destroy(struct weston_desktop_xdg_toplevel *toplevel)
795{
796 if (toplevel->added)
797 weston_desktop_api_surface_removed(toplevel->base.desktop,
798 toplevel->base.desktop_surface);
799}
800
801static void
802weston_desktop_xdg_toplevel_resource_destroy(struct wl_resource *resource)
803{
804 struct weston_desktop_surface *dsurface =
805 wl_resource_get_user_data(resource);
806
807 if (dsurface != NULL)
808 weston_desktop_surface_resource_destroy(resource);
809}
810
811static const struct xdg_toplevel_interface weston_desktop_xdg_toplevel_implementation = {
812 .destroy = weston_desktop_destroy_request,
813 .set_parent = weston_desktop_xdg_toplevel_protocol_set_parent,
814 .set_title = weston_desktop_xdg_toplevel_protocol_set_title,
815 .set_app_id = weston_desktop_xdg_toplevel_protocol_set_app_id,
816 .show_window_menu = weston_desktop_xdg_toplevel_protocol_show_window_menu,
817 .move = weston_desktop_xdg_toplevel_protocol_move,
818 .resize = weston_desktop_xdg_toplevel_protocol_resize,
819 .set_min_size = weston_desktop_xdg_toplevel_protocol_set_min_size,
820 .set_max_size = weston_desktop_xdg_toplevel_protocol_set_max_size,
821 .set_maximized = weston_desktop_xdg_toplevel_protocol_set_maximized,
822 .unset_maximized = weston_desktop_xdg_toplevel_protocol_unset_maximized,
823 .set_fullscreen = weston_desktop_xdg_toplevel_protocol_set_fullscreen,
824 .unset_fullscreen = weston_desktop_xdg_toplevel_protocol_unset_fullscreen,
825 .set_minimized = weston_desktop_xdg_toplevel_protocol_set_minimized,
826};
827
828static void
829weston_desktop_xdg_popup_protocol_grab(struct wl_client *wl_client,
830 struct wl_resource *resource,
831 struct wl_resource *seat_resource,
832 uint32_t serial)
833{
834 struct weston_desktop_surface *dsurface =
835 wl_resource_get_user_data(resource);
836 struct weston_desktop_xdg_popup *popup =
837 weston_desktop_surface_get_implementation_data(dsurface);
838 struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
839 struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
840 struct weston_desktop_surface *topmost;
841 bool parent_is_toplevel =
842 popup->parent->role == WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL;
843
844 /* Check that if we have a valid wseat we also got a valid desktop seat */
845 if (wseat != NULL && seat == NULL) {
846 wl_client_post_no_memory(wl_client);
847 return;
848 }
849
850 if (popup->committed) {
851 wl_resource_post_error(popup->resource,
852 XDG_POPUP_ERROR_INVALID_GRAB,
853 "xdg_popup already is mapped");
854 return;
855 }
856
857 /* If seat is NULL then get_topmost_surface will return NULL. In
858 * combination with setting parent_is_toplevel to TRUE here we will
859 * avoid posting an error, and we will instead gracefully fail the
860 * grab and dismiss the surface.
861 * FIXME: this is a hack because currently we cannot check the topmost
862 * parent with a destroyed weston_seat */
863 if (seat == NULL)
864 parent_is_toplevel = true;
865
866 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(seat);
867 if ((topmost == NULL && !parent_is_toplevel) ||
868 (topmost != NULL && topmost != popup->parent->desktop_surface)) {
869 struct weston_desktop_client *client =
870 weston_desktop_surface_get_client(dsurface);
871 struct wl_resource *client_resource =
872 weston_desktop_client_get_resource(client);
873
874 wl_resource_post_error(client_resource,
875 XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP,
876 "xdg_popup was not created on the topmost popup");
877 return;
878 }
879
880 popup->seat = seat;
881 weston_desktop_surface_popup_grab(popup->base.desktop_surface,
882 popup->seat, serial);
883}
884
Jonas Ådahla76d2052019-12-02 22:19:21 +0100885static bool
886is_positioner_valid(struct weston_desktop_xdg_positioner *positioner)
887{
888 /* Checking whether the size and anchor rect both have a positive size
889 * is enough to verify both have been correctly set */
890 if (positioner->size.width == 0 || positioner->anchor_rect.width == 0)
891 return false;
892
893 if (positioner->anchor_rect.height == 0)
894 return false;
895
896 return true;
897}
898
899static void
900weston_desktop_xdg_popup_protocol_reposition(struct wl_client *wl_client,
901 struct wl_resource *resource,
902 struct wl_resource *positioner_resource,
903 uint32_t token)
904{
905 struct weston_desktop_surface *dsurface =
906 wl_resource_get_user_data(resource);
907 struct weston_desktop_xdg_popup *popup =
908 weston_desktop_surface_get_implementation_data(dsurface);
909 struct weston_desktop_xdg_positioner *positioner =
910 wl_resource_get_user_data(positioner_resource);
911 struct weston_desktop_surface *parent_dsurface;
912
913 if (!is_positioner_valid(positioner)) {
914 wl_resource_post_error(resource,
915 XDG_WM_BASE_ERROR_INVALID_POSITIONER,
916 "positioner object is not complete");
917 return;
918 }
919
920 parent_dsurface = popup->parent->desktop_surface;
921 popup->geometry =
922 weston_desktop_xdg_positioner_get_geometry(positioner,
923 dsurface,
924 parent_dsurface);
925 popup->pending_reposition = true;
926 popup->pending_reposition_token = token;
927 if (popup->committed)
928 weston_desktop_xdg_surface_schedule_configure(&popup->base);
929}
930
ant8med8d9f5e2018-11-28 22:46:37 +0100931static void
932weston_desktop_xdg_popup_send_configure(struct weston_desktop_xdg_popup *popup)
933{
Jonas Ådahla76d2052019-12-02 22:19:21 +0100934 if (popup->pending_reposition) {
935 popup->pending_reposition = false;
936 xdg_popup_send_repositioned(popup->resource,
937 popup->pending_reposition_token);
938 }
ant8med8d9f5e2018-11-28 22:46:37 +0100939 xdg_popup_send_configure(popup->resource,
940 popup->geometry.x,
941 popup->geometry.y,
942 popup->geometry.width,
943 popup->geometry.height);
944}
945
946static void
947weston_desktop_xdg_popup_update_position(struct weston_desktop_surface *dsurface,
948 void *user_data);
949
950static void
951weston_desktop_xdg_popup_committed(struct weston_desktop_xdg_popup *popup)
952{
953 struct weston_surface *wsurface =
954 weston_desktop_surface_get_surface (popup->base.desktop_surface);
955 struct weston_view *view;
956
957 wl_list_for_each(view, &wsurface->views, surface_link)
958 weston_view_update_transform(view);
959
960 if (!popup->committed)
961 weston_desktop_xdg_surface_schedule_configure(&popup->base);
962 popup->committed = true;
963 weston_desktop_xdg_popup_update_position(popup->base.desktop_surface,
964 popup);
965}
966
967static void
968weston_desktop_xdg_popup_update_position(struct weston_desktop_surface *dsurface,
969 void *user_data)
970{
Jonas Ådahla76d2052019-12-02 22:19:21 +0100971 struct weston_desktop_xdg_popup *popup =
972 weston_desktop_surface_get_implementation_data(dsurface);
973 struct weston_desktop_surface *parent_dsurface;
974
975 parent_dsurface = popup->parent->desktop_surface;
976 weston_desktop_surface_set_relative_to(popup->base.desktop_surface,
977 parent_dsurface,
978 popup->geometry.x,
979 popup->geometry.y,
980 true);
ant8med8d9f5e2018-11-28 22:46:37 +0100981}
982
983static void
984weston_desktop_xdg_popup_close(struct weston_desktop_xdg_popup *popup)
985{
986 xdg_popup_send_popup_done(popup->resource);
987}
988
989static void
990weston_desktop_xdg_popup_destroy(struct weston_desktop_xdg_popup *popup)
991{
992 struct weston_desktop_surface *topmost;
993 struct weston_desktop_client *client =
994 weston_desktop_surface_get_client(popup->base.desktop_surface);
995
996 if (!weston_desktop_surface_get_grab(popup->base.desktop_surface))
997 return;
998
999 topmost = weston_desktop_seat_popup_grab_get_topmost_surface(popup->seat);
1000 if (topmost != popup->base.desktop_surface) {
1001 struct wl_resource *client_resource =
1002 weston_desktop_client_get_resource(client);
1003
1004 wl_resource_post_error(client_resource,
1005 XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP,
1006 "xdg_popup was destroyed while it was not the topmost popup.");
1007 }
1008
1009 weston_desktop_surface_popup_ungrab(popup->base.desktop_surface,
1010 popup->seat);
1011}
1012
1013static void
1014weston_desktop_xdg_popup_resource_destroy(struct wl_resource *resource)
1015{
1016 struct weston_desktop_surface *dsurface =
1017 wl_resource_get_user_data(resource);
1018
1019 if (dsurface != NULL)
1020 weston_desktop_surface_resource_destroy(resource);
1021}
1022
1023static const struct xdg_popup_interface weston_desktop_xdg_popup_implementation = {
1024 .destroy = weston_desktop_destroy_request,
1025 .grab = weston_desktop_xdg_popup_protocol_grab,
Jonas Ådahla76d2052019-12-02 22:19:21 +01001026 .reposition = weston_desktop_xdg_popup_protocol_reposition,
ant8med8d9f5e2018-11-28 22:46:37 +01001027};
1028
1029static void
1030weston_desktop_xdg_surface_send_configure(void *user_data)
1031{
1032 struct weston_desktop_xdg_surface *surface = user_data;
1033 struct weston_desktop_xdg_surface_configure *configure;
1034
1035 surface->configure_idle = NULL;
1036
1037 configure = zalloc(weston_desktop_surface_configure_biggest_size);
1038 if (configure == NULL) {
1039 struct weston_desktop_client *client =
1040 weston_desktop_surface_get_client(surface->desktop_surface);
1041 struct wl_client *wl_client =
1042 weston_desktop_client_get_client(client);
1043 wl_client_post_no_memory(wl_client);
1044 return;
1045 }
1046 wl_list_insert(surface->configure_list.prev, &configure->link);
1047 configure->serial =
1048 wl_display_next_serial(weston_desktop_get_display(surface->desktop));
1049
1050 switch (surface->role) {
1051 case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE:
1052 assert(0 && "not reached");
1053 break;
1054 case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
1055 weston_desktop_xdg_toplevel_send_configure((struct weston_desktop_xdg_toplevel *) surface,
1056 (struct weston_desktop_xdg_toplevel_configure *) configure);
1057 break;
1058 case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
1059 weston_desktop_xdg_popup_send_configure((struct weston_desktop_xdg_popup *) surface);
1060 break;
1061 }
1062
1063 xdg_surface_send_configure(surface->resource, configure->serial);
1064}
1065
1066static bool
1067weston_desktop_xdg_toplevel_state_compare(struct weston_desktop_xdg_toplevel *toplevel)
1068{
1069 struct {
1070 struct weston_desktop_xdg_toplevel_state state;
1071 struct weston_size size;
1072 } configured;
1073
1074 if (!toplevel->base.configured)
1075 return false;
1076
1077 if (wl_list_empty(&toplevel->base.configure_list)) {
1078 /* Last configure is actually the current state, just use it */
1079 configured.state = toplevel->current.state;
1080 configured.size.width = toplevel->base.surface->width;
1081 configured.size.height = toplevel->base.surface->height;
1082 } else {
1083 struct weston_desktop_xdg_toplevel_configure *configure =
1084 wl_container_of(toplevel->base.configure_list.prev,
1085 configure, base.link);
1086
1087 configured.state = configure->state;
1088 configured.size = configure->size;
1089 }
1090
1091 if (toplevel->pending.state.activated != configured.state.activated)
1092 return false;
1093 if (toplevel->pending.state.fullscreen != configured.state.fullscreen)
1094 return false;
1095 if (toplevel->pending.state.maximized != configured.state.maximized)
1096 return false;
1097 if (toplevel->pending.state.resizing != configured.state.resizing)
1098 return false;
1099
1100 if (toplevel->pending.size.width == configured.size.width &&
1101 toplevel->pending.size.height == configured.size.height)
1102 return true;
1103
1104 if (toplevel->pending.size.width == 0 &&
1105 toplevel->pending.size.height == 0)
1106 return true;
1107
1108 return false;
1109}
1110
1111static void
1112weston_desktop_xdg_surface_schedule_configure(struct weston_desktop_xdg_surface *surface)
1113{
1114 struct wl_display *display = weston_desktop_get_display(surface->desktop);
1115 struct wl_event_loop *loop = wl_display_get_event_loop(display);
1116 bool pending_same = false;
1117
1118 switch (surface->role) {
1119 case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE:
1120 assert(0 && "not reached");
1121 break;
1122 case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
1123 pending_same = weston_desktop_xdg_toplevel_state_compare((struct weston_desktop_xdg_toplevel *) surface);
1124 break;
1125 case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
1126 break;
1127 }
1128
1129 if (surface->configure_idle != NULL) {
1130 if (!pending_same)
1131 return;
1132
1133 wl_event_source_remove(surface->configure_idle);
1134 surface->configure_idle = NULL;
1135 } else {
1136 if (pending_same)
1137 return;
1138
1139 surface->configure_idle =
1140 wl_event_loop_add_idle(loop,
1141 weston_desktop_xdg_surface_send_configure,
1142 surface);
1143 }
1144}
1145
1146static void
1147weston_desktop_xdg_surface_protocol_get_toplevel(struct wl_client *wl_client,
1148 struct wl_resource *resource,
1149 uint32_t id)
1150{
1151 struct weston_desktop_surface *dsurface =
1152 wl_resource_get_user_data(resource);
1153 struct weston_surface *wsurface =
1154 weston_desktop_surface_get_surface(dsurface);
1155 struct weston_desktop_xdg_toplevel *toplevel =
1156 weston_desktop_surface_get_implementation_data(dsurface);
1157
1158 if (weston_surface_set_role(wsurface, weston_desktop_xdg_toplevel_role,
1159 resource, XDG_WM_BASE_ERROR_ROLE) < 0)
1160 return;
1161
1162 toplevel->resource =
1163 weston_desktop_surface_add_resource(toplevel->base.desktop_surface,
1164 &xdg_toplevel_interface,
1165 &weston_desktop_xdg_toplevel_implementation,
1166 id, weston_desktop_xdg_toplevel_resource_destroy);
1167 if (toplevel->resource == NULL)
1168 return;
1169
1170 toplevel->base.role = WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL;
1171}
1172
1173static void
1174weston_desktop_xdg_surface_protocol_get_popup(struct wl_client *wl_client,
1175 struct wl_resource *resource,
1176 uint32_t id,
1177 struct wl_resource *parent_resource,
1178 struct wl_resource *positioner_resource)
1179{
1180 struct weston_desktop_surface *dsurface =
1181 wl_resource_get_user_data(resource);
1182 struct weston_surface *wsurface =
1183 weston_desktop_surface_get_surface(dsurface);
1184 struct weston_desktop_xdg_popup *popup =
1185 weston_desktop_surface_get_implementation_data(dsurface);
1186 struct weston_desktop_surface *parent_surface;
1187 struct weston_desktop_xdg_surface *parent;
1188 struct weston_desktop_xdg_positioner *positioner =
1189 wl_resource_get_user_data(positioner_resource);
1190
1191 /* Popup parents are allowed to be non-null, but only if a parent is
1192 * specified 'using some other protocol' before committing. Since we
1193 * don't support such a protocol yet, clients cannot legitimately
1194 * create a popup with a non-null parent. */
1195 if (!parent_resource) {
1196 wl_resource_post_error(resource,
1197 XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT,
1198 "popup parent must be non-null");
1199 return;
1200 }
1201
1202 parent_surface = wl_resource_get_user_data(parent_resource);
1203 parent = weston_desktop_surface_get_implementation_data(parent_surface);
1204
Jonas Ådahla76d2052019-12-02 22:19:21 +01001205 if (!is_positioner_valid(positioner)) {
ant8med8d9f5e2018-11-28 22:46:37 +01001206 wl_resource_post_error(resource,
1207 XDG_WM_BASE_ERROR_INVALID_POSITIONER,
1208 "positioner object is not complete");
1209 return;
1210 }
1211
1212 if (weston_surface_set_role(wsurface, weston_desktop_xdg_popup_role,
1213 resource, XDG_WM_BASE_ERROR_ROLE) < 0)
1214 return;
1215
1216 popup->resource =
1217 weston_desktop_surface_add_resource(popup->base.desktop_surface,
1218 &xdg_popup_interface,
1219 &weston_desktop_xdg_popup_implementation,
1220 id, weston_desktop_xdg_popup_resource_destroy);
1221 if (popup->resource == NULL)
1222 return;
1223
1224 popup->base.role = WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP;
1225 popup->parent = parent;
1226
1227 popup->geometry =
1228 weston_desktop_xdg_positioner_get_geometry(positioner,
1229 dsurface,
1230 parent_surface);
1231
1232 weston_desktop_surface_set_relative_to(popup->base.desktop_surface,
1233 parent_surface,
1234 popup->geometry.x,
1235 popup->geometry.y,
1236 true);
1237}
1238
1239static bool
1240weston_desktop_xdg_surface_check_role(struct weston_desktop_xdg_surface *surface)
1241{
1242 struct weston_surface *wsurface =
1243 weston_desktop_surface_get_surface(surface->desktop_surface);
1244 const char *role;
1245
1246 role = weston_surface_get_role(wsurface);
1247 if (role != NULL &&
1248 (role == weston_desktop_xdg_toplevel_role ||
1249 role == weston_desktop_xdg_popup_role))
1250 return true;
1251
1252 wl_resource_post_error(surface->resource,
1253 XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
1254 "xdg_surface must have a role");
1255 return false;
1256}
1257
1258static void
1259weston_desktop_xdg_surface_protocol_set_window_geometry(struct wl_client *wl_client,
1260 struct wl_resource *resource,
1261 int32_t x, int32_t y,
1262 int32_t width, int32_t height)
1263{
1264 struct weston_desktop_surface *dsurface =
1265 wl_resource_get_user_data(resource);
1266 struct weston_desktop_xdg_surface *surface =
1267 weston_desktop_surface_get_implementation_data(dsurface);
1268
1269 if (!weston_desktop_xdg_surface_check_role(surface))
1270 return;
1271
1272 surface->has_next_geometry = true;
1273 surface->next_geometry.x = x;
1274 surface->next_geometry.y = y;
1275 surface->next_geometry.width = width;
1276 surface->next_geometry.height = height;
1277}
1278
1279static void
1280weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client,
1281 struct wl_resource *resource,
1282 uint32_t serial)
1283{
1284 struct weston_desktop_surface *dsurface =
1285 wl_resource_get_user_data(resource);
leng.fangdbaf6fa2024-06-20 19:31:04 +08001286 struct weston_desktop_xdg_surface *surface;
ant8med8d9f5e2018-11-28 22:46:37 +01001287 struct weston_desktop_xdg_surface_configure *configure, *temp;
1288 bool found = false;
1289
leng.fangdbaf6fa2024-06-20 19:31:04 +08001290 if (!dsurface)
1291 return;
1292
1293 surface = weston_desktop_surface_get_implementation_data(dsurface);
1294 assert(surface);
ant8med8d9f5e2018-11-28 22:46:37 +01001295 if (!weston_desktop_xdg_surface_check_role(surface))
1296 return;
1297
1298 wl_list_for_each_safe(configure, temp, &surface->configure_list, link) {
1299 if (configure->serial < serial) {
1300 wl_list_remove(&configure->link);
1301 free(configure);
1302 } else if (configure->serial == serial) {
1303 wl_list_remove(&configure->link);
1304 found = true;
1305 break;
1306 } else {
1307 break;
1308 }
1309 }
1310 if (!found) {
1311 struct weston_desktop_client *client =
1312 weston_desktop_surface_get_client(dsurface);
1313 struct wl_resource *client_resource =
1314 weston_desktop_client_get_resource(client);
1315 wl_resource_post_error(client_resource,
1316 XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
1317 "Wrong configure serial: %u", serial);
1318 return;
1319 }
1320
1321 surface->configured = true;
1322
1323 switch (surface->role) {
1324 case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE:
1325 assert(0 && "not reached");
1326 break;
1327 case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
1328 weston_desktop_xdg_toplevel_ack_configure((struct weston_desktop_xdg_toplevel *) surface,
1329 (struct weston_desktop_xdg_toplevel_configure *) configure);
1330 break;
1331 case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
1332 break;
1333 }
1334
1335 free(configure);
1336}
1337
1338static void
1339weston_desktop_xdg_surface_ping(struct weston_desktop_surface *dsurface,
1340 uint32_t serial, void *user_data)
1341{
1342 struct weston_desktop_client *client =
1343 weston_desktop_surface_get_client(dsurface);
1344
1345 xdg_wm_base_send_ping(weston_desktop_client_get_resource(client),
1346 serial);
1347}
1348
1349static void
1350weston_desktop_xdg_surface_committed(struct weston_desktop_surface *dsurface,
1351 void *user_data,
1352 int32_t sx, int32_t sy)
1353{
1354 struct weston_desktop_xdg_surface *surface = user_data;
1355 struct weston_surface *wsurface =
1356 weston_desktop_surface_get_surface (dsurface);
1357
1358 if (wsurface->buffer_ref.buffer && !surface->configured) {
1359 wl_resource_post_error(surface->resource,
1360 XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER,
1361 "xdg_surface has never been configured");
1362 return;
1363 }
1364
1365 if (surface->has_next_geometry) {
1366 surface->has_next_geometry = false;
1367 weston_desktop_surface_set_geometry(surface->desktop_surface,
1368 surface->next_geometry);
1369 }
1370
1371 switch (surface->role) {
1372 case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE:
1373 wl_resource_post_error(surface->resource,
1374 XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
1375 "xdg_surface must have a role");
1376 break;
1377 case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
1378 weston_desktop_xdg_toplevel_committed((struct weston_desktop_xdg_toplevel *) surface, sx, sy);
1379 break;
1380 case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
1381 weston_desktop_xdg_popup_committed((struct weston_desktop_xdg_popup *) surface);
1382 break;
1383 }
1384}
1385
1386static void
1387weston_desktop_xdg_surface_close(struct weston_desktop_surface *dsurface,
1388 void *user_data)
1389{
1390 struct weston_desktop_xdg_surface *surface = user_data;
1391
1392 switch (surface->role) {
1393 case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE:
1394 assert(0 && "not reached");
1395 break;
1396 case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
1397 weston_desktop_xdg_toplevel_close((struct weston_desktop_xdg_toplevel *) surface);
1398 break;
1399 case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
1400 weston_desktop_xdg_popup_close((struct weston_desktop_xdg_popup *) surface);
1401 break;
1402 }
1403}
1404
1405static void
1406weston_desktop_xdg_surface_destroy(struct weston_desktop_surface *dsurface,
1407 void *user_data)
1408{
1409 struct weston_desktop_xdg_surface *surface = user_data;
1410 struct weston_desktop_xdg_surface_configure *configure, *temp;
1411
1412 switch (surface->role) {
1413 case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE:
1414 break;
1415 case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
1416 weston_desktop_xdg_toplevel_destroy((struct weston_desktop_xdg_toplevel *) surface);
1417 break;
1418 case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
1419 weston_desktop_xdg_popup_destroy((struct weston_desktop_xdg_popup *) surface);
1420 break;
1421 }
1422
1423 if (surface->configure_idle != NULL)
1424 wl_event_source_remove(surface->configure_idle);
1425
1426 wl_list_for_each_safe(configure, temp, &surface->configure_list, link)
1427 free(configure);
1428
1429 free(surface);
1430}
1431
1432static const struct xdg_surface_interface weston_desktop_xdg_surface_implementation = {
1433 .destroy = weston_desktop_destroy_request,
1434 .get_toplevel = weston_desktop_xdg_surface_protocol_get_toplevel,
1435 .get_popup = weston_desktop_xdg_surface_protocol_get_popup,
1436 .set_window_geometry = weston_desktop_xdg_surface_protocol_set_window_geometry,
1437 .ack_configure = weston_desktop_xdg_surface_protocol_ack_configure,
1438};
1439
1440static const struct weston_desktop_surface_implementation weston_desktop_xdg_surface_internal_implementation = {
1441 /* These are used for toplevel only */
1442 .set_maximized = weston_desktop_xdg_toplevel_set_maximized,
1443 .set_fullscreen = weston_desktop_xdg_toplevel_set_fullscreen,
1444 .set_resizing = weston_desktop_xdg_toplevel_set_resizing,
1445 .set_activated = weston_desktop_xdg_toplevel_set_activated,
1446 .set_size = weston_desktop_xdg_toplevel_set_size,
1447
1448 .get_maximized = weston_desktop_xdg_toplevel_get_maximized,
1449 .get_fullscreen = weston_desktop_xdg_toplevel_get_fullscreen,
1450 .get_resizing = weston_desktop_xdg_toplevel_get_resizing,
1451 .get_activated = weston_desktop_xdg_toplevel_get_activated,
1452
1453 /* These are used for popup only */
1454 .update_position = weston_desktop_xdg_popup_update_position,
1455
1456 /* Common API */
1457 .committed = weston_desktop_xdg_surface_committed,
1458 .ping = weston_desktop_xdg_surface_ping,
1459 .close = weston_desktop_xdg_surface_close,
1460
1461 .destroy = weston_desktop_xdg_surface_destroy,
1462};
1463
1464static void
1465weston_desktop_xdg_shell_protocol_create_positioner(struct wl_client *wl_client,
1466 struct wl_resource *resource,
1467 uint32_t id)
1468{
1469 struct weston_desktop_client *client =
1470 wl_resource_get_user_data(resource);
1471 struct weston_desktop_xdg_positioner *positioner;
1472
1473 positioner = zalloc(sizeof(struct weston_desktop_xdg_positioner));
1474 if (positioner == NULL) {
1475 wl_client_post_no_memory(wl_client);
1476 return;
1477 }
1478
1479 positioner->client = client;
1480 positioner->desktop = weston_desktop_client_get_desktop(positioner->client);
1481
1482 positioner->resource =
1483 wl_resource_create(wl_client,
1484 &xdg_positioner_interface,
1485 wl_resource_get_version(resource), id);
1486 if (positioner->resource == NULL) {
1487 wl_client_post_no_memory(wl_client);
1488 free(positioner);
1489 return;
1490 }
1491 wl_resource_set_implementation(positioner->resource,
1492 &weston_desktop_xdg_positioner_implementation,
1493 positioner, weston_desktop_xdg_positioner_destroy);
1494}
1495
1496static void
1497weston_desktop_xdg_surface_resource_destroy(struct wl_resource *resource)
1498{
1499 struct weston_desktop_surface *dsurface =
1500 wl_resource_get_user_data(resource);
1501
1502 if (dsurface != NULL)
1503 weston_desktop_surface_resource_destroy(resource);
1504}
1505
1506static void
1507weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client,
1508 struct wl_resource *resource,
1509 uint32_t id,
1510 struct wl_resource *surface_resource)
1511{
1512 struct weston_desktop_client *client =
1513 wl_resource_get_user_data(resource);
1514 struct weston_surface *wsurface =
1515 wl_resource_get_user_data(surface_resource);
1516 struct weston_desktop_xdg_surface *surface;
1517
Daniel Stone80e94822021-05-18 17:19:07 +01001518 if (wsurface->committed) {
1519 wl_resource_post_error(resource,
1520 XDG_WM_BASE_ERROR_ROLE,
1521 "xdg_surface must not have any other role");
1522 return;
1523 }
1524
Daniel Stonebaa8f6b2021-05-18 17:15:58 +01001525 if (wsurface->buffer_ref.buffer != NULL) {
1526 wl_resource_post_error(resource,
1527 XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER,
1528 "xdg_surface must not have a buffer at creation");
1529 return;
1530 }
1531
ant8med8d9f5e2018-11-28 22:46:37 +01001532 surface = zalloc(weston_desktop_surface_role_biggest_size);
1533 if (surface == NULL) {
1534 wl_client_post_no_memory(wl_client);
1535 return;
1536 }
1537
1538 surface->desktop = weston_desktop_client_get_desktop(client);
1539 surface->surface = wsurface;
1540 wl_list_init(&surface->configure_list);
1541
1542 surface->desktop_surface =
1543 weston_desktop_surface_create(surface->desktop, client,
1544 surface->surface,
1545 &weston_desktop_xdg_surface_internal_implementation,
1546 surface);
1547 if (surface->desktop_surface == NULL) {
1548 free(surface);
1549 return;
1550 }
1551
1552 surface->resource =
1553 weston_desktop_surface_add_resource(surface->desktop_surface,
1554 &xdg_surface_interface,
1555 &weston_desktop_xdg_surface_implementation,
1556 id, weston_desktop_xdg_surface_resource_destroy);
1557 if (surface->resource == NULL)
1558 return;
ant8med8d9f5e2018-11-28 22:46:37 +01001559}
1560
1561static void
1562weston_desktop_xdg_shell_protocol_pong(struct wl_client *wl_client,
1563 struct wl_resource *resource,
1564 uint32_t serial)
1565{
1566 struct weston_desktop_client *client =
1567 wl_resource_get_user_data(resource);
1568
1569 weston_desktop_client_pong(client, serial);
1570}
1571
1572static const struct xdg_wm_base_interface weston_desktop_xdg_shell_implementation = {
1573 .destroy = weston_desktop_destroy_request,
1574 .create_positioner = weston_desktop_xdg_shell_protocol_create_positioner,
1575 .get_xdg_surface = weston_desktop_xdg_shell_protocol_get_xdg_surface,
1576 .pong = weston_desktop_xdg_shell_protocol_pong,
1577};
1578
1579static void
1580weston_desktop_xdg_shell_bind(struct wl_client *client, void *data,
1581 uint32_t version, uint32_t id)
1582{
1583 struct weston_desktop *desktop = data;
1584
1585 weston_desktop_client_create(desktop, client, NULL,
1586 &xdg_wm_base_interface,
1587 &weston_desktop_xdg_shell_implementation,
1588 version, id);
1589}
1590
1591struct wl_global *
1592weston_desktop_xdg_wm_base_create(struct weston_desktop *desktop,
1593 struct wl_display *display)
1594{
1595 return wl_global_create(display, &xdg_wm_base_interface,
1596 WD_XDG_SHELL_PROTOCOL_VERSION, desktop,
1597 weston_desktop_xdg_shell_bind);
1598}