1/*
2 * Copyright © 2010 Intel Corporation
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19
20#include "gdksurface-wayland.h"
21
22#include "gdkdeviceprivate.h"
23#include "gdkdisplay-wayland.h"
24#include "gdkdragsurfaceprivate.h"
25#include "gdkeventsprivate.h"
26#include "gdkframeclockidleprivate.h"
27#include "gdkglcontext-wayland.h"
28#include "gdkmonitor-wayland.h"
29#include "gdkpopupprivate.h"
30#include "gdkprivate-wayland.h"
31#include "gdkprivate-wayland.h"
32#include "gdkseat-wayland.h"
33#include "gdksurfaceprivate.h"
34#include "gdktoplevelprivate.h"
35#include "gdkdevice-wayland-private.h"
36
37#include <wayland/xdg-shell-unstable-v6-client-protocol.h>
38
39#include <stdlib.h>
40#include <stdio.h>
41#include <string.h>
42#include <errno.h>
43
44#include <netinet/in.h>
45#include <unistd.h>
46
47/**
48 * GdkWaylandSurface:
49 *
50 * The Wayland implementation of `GdkSurface`.
51 *
52 * Beyond the [class@Gdk.Surface] API, the Wayland implementation offers
53 * access to the Wayland `wl_surface` object with
54 * [method@GdkWayland.WaylandSurface.get_wl_surface].
55 */
56
57/**
58 * GdkWaylandToplevel:
59 *
60 * The Wayland implementation of `GdkToplevel`.
61 *
62 * Beyond the [iface@Gdk.Toplevel] API, the Wayland implementation
63 * has API to set up cross-process parent-child relationships between
64 * surfaces with [method@GdkWayland.WaylandToplevel.export_handle] and
65 * [method@GdkWayland.WaylandToplevel.set_transient_for_exported].
66 */
67
68/**
69 * GdkWaylandPopup:
70 *
71 * The Wayland implementation of `GdkPopup`.
72 */
73
74#define SURFACE_IS_TOPLEVEL(surface) TRUE
75
76#define MAX_WL_BUFFER_SIZE (4083) /* 4096 minus header, string argument length and NUL byte */
77
78typedef enum _PopupState
79{
80 POPUP_STATE_IDLE,
81 POPUP_STATE_WAITING_FOR_REPOSITIONED,
82 POPUP_STATE_WAITING_FOR_CONFIGURE,
83 POPUP_STATE_WAITING_FOR_FRAME,
84} PopupState;
85
86struct _GdkWaylandSurface
87{
88 GdkSurface parent_instance;
89
90 struct {
91 /* The wl_outputs that this surface currently touches */
92 GSList *outputs;
93
94 struct wl_surface *wl_surface;
95
96 struct xdg_surface *xdg_surface;
97 struct xdg_toplevel *xdg_toplevel;
98 struct xdg_popup *xdg_popup;
99
100 /* Legacy xdg-shell unstable v6 fallback support */
101 struct zxdg_surface_v6 *zxdg_surface_v6;
102 struct zxdg_toplevel_v6 *zxdg_toplevel_v6;
103 struct zxdg_popup_v6 *zxdg_popup_v6;
104
105 struct gtk_surface1 *gtk_surface;
106 struct wl_egl_window *egl_window;
107 } display_server;
108
109 struct wl_event_queue *event_queue;
110
111 uint32_t reposition_token;
112 uint32_t received_reposition_token;
113
114 PopupState popup_state;
115
116 unsigned int popup_thaw_upon_show : 1;
117 unsigned int initial_configure_received : 1;
118 unsigned int has_uncommitted_ack_configure : 1;
119 unsigned int mapped : 1;
120 unsigned int awaiting_frame : 1;
121 unsigned int awaiting_frame_frozen : 1;
122
123 int pending_buffer_offset_x;
124 int pending_buffer_offset_y;
125
126 char *title;
127
128 struct {
129 gboolean was_set;
130
131 char *application_id;
132 char *app_menu_path;
133 char *menubar_path;
134 char *window_object_path;
135 char *application_object_path;
136 char *unique_bus_name;
137 } application;
138
139 GdkGeometry geometry_hints;
140 GdkSurfaceHints geometry_mask;
141
142 GdkSeat *grab_input_seat;
143
144 gint64 pending_frame_counter;
145 guint32 scale;
146
147 int shadow_left;
148 int shadow_right;
149 int shadow_top;
150 int shadow_bottom;
151
152 struct wl_output *initial_fullscreen_output;
153
154 cairo_region_t *opaque_region;
155 gboolean opaque_region_dirty;
156
157 cairo_region_t *input_region;
158 gboolean input_region_dirty;
159
160 GdkRectangle last_sent_window_geometry;
161 int last_sent_min_width;
162 int last_sent_min_height;
163 int last_sent_max_width;
164 int last_sent_max_height;
165
166 int saved_width;
167 int saved_height;
168
169 struct {
170 GdkToplevelLayout *layout;
171 } toplevel;
172
173 struct {
174 GdkPopupLayout *layout;
175 int unconstrained_width;
176 int unconstrained_height;
177 } popup;
178
179 struct {
180 struct {
181 int width;
182 int height;
183 GdkToplevelState state;
184 gboolean is_resizing;
185 } toplevel;
186
187 struct {
188 int x;
189 int y;
190 int width;
191 int height;
192 uint32_t repositioned_token;
193 gboolean has_repositioned_token;
194 } popup;
195
196 gboolean is_initial_configure;
197
198 uint32_t serial;
199 gboolean is_dirty;
200 } pending;
201
202 struct {
203 GdkToplevelState unset_flags;
204 GdkToplevelState set_flags;
205 } initial_state;
206
207 struct {
208 struct {
209 gboolean should_constrain;
210 gboolean size_is_fixed;
211 } toplevel;
212 struct {
213 int x;
214 int y;
215 } popup;
216 int configured_width;
217 int configured_height;
218 gboolean surface_geometry_dirty;
219 } next_layout;
220
221 uint32_t last_configure_serial;
222
223 int state_freeze_count;
224
225 struct zxdg_imported_v1 *imported_transient_for;
226 GHashTable *shortcuts_inhibitors;
227};
228
229typedef struct _GdkWaylandSurfaceClass GdkWaylandSurfaceClass;
230struct _GdkWaylandSurfaceClass
231{
232 GdkSurfaceClass parent_class;
233};
234
235G_DEFINE_TYPE (GdkWaylandSurface, gdk_wayland_surface, GDK_TYPE_SURFACE)
236
237struct _GdkWaylandToplevel
238{
239 GdkWaylandSurface parent_instance;
240
241 GdkWaylandToplevel *transient_for;
242
243 struct org_kde_kwin_server_decoration *server_decoration;
244 struct zxdg_exported_v1 *xdg_exported;
245
246 struct {
247 GdkWaylandToplevelExported callback;
248 gpointer user_data;
249 GDestroyNotify destroy_func;
250 } exported;
251
252 struct zwp_idle_inhibitor_v1 *idle_inhibitor;
253 size_t idle_inhibitor_refcount;
254};
255
256typedef struct
257{
258 GdkWaylandSurfaceClass parent_class;
259} GdkWaylandToplevelClass;
260
261static void gdk_wayland_toplevel_iface_init (GdkToplevelInterface *iface);
262
263G_DEFINE_TYPE_WITH_CODE (GdkWaylandToplevel, gdk_wayland_toplevel, GDK_TYPE_WAYLAND_SURFACE,
264 G_IMPLEMENT_INTERFACE (GDK_TYPE_TOPLEVEL,
265 gdk_wayland_toplevel_iface_init))
266
267struct _GdkWaylandPopup
268{
269 GdkWaylandSurface parent_instance;
270};
271
272typedef struct
273{
274 GdkWaylandSurfaceClass parent_class;
275} GdkWaylandPopupClass;
276
277static void gdk_wayland_popup_iface_init (GdkPopupInterface *iface);
278
279G_DEFINE_TYPE_WITH_CODE (GdkWaylandPopup, gdk_wayland_popup, GDK_TYPE_WAYLAND_SURFACE,
280 G_IMPLEMENT_INTERFACE (GDK_TYPE_POPUP,
281 gdk_wayland_popup_iface_init))
282
283typedef struct
284{
285 GdkWaylandSurface parent_instance;
286} GdkWaylandDragSurface;
287
288typedef struct
289{
290 GdkWaylandSurfaceClass parent_class;
291} GdkWaylandDragSurfaceClass;
292
293static void gdk_wayland_drag_surface_iface_init (GdkDragSurfaceInterface *iface);
294
295GType gdk_wayland_drag_surface_get_type (void) G_GNUC_CONST;
296
297#define GDK_IS_WAYLAND_DRAG_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_DRAG_SURFACE))
298
299#define GDK_TYPE_WAYLAND_DRAG_SURFACE (gdk_wayland_drag_surface_get_type ())
300G_DEFINE_TYPE_WITH_CODE (GdkWaylandDragSurface, gdk_wayland_drag_surface, GDK_TYPE_WAYLAND_SURFACE,
301 G_IMPLEMENT_INTERFACE (GDK_TYPE_DRAG_SURFACE,
302 gdk_wayland_drag_surface_iface_init))
303
304static void gdk_wayland_surface_maybe_resize (GdkSurface *surface,
305 int width,
306 int height,
307 int scale);
308
309static void gdk_wayland_surface_configure (GdkSurface *surface);
310
311static void maybe_set_gtk_surface_dbus_properties (GdkWaylandSurface *impl);
312static void maybe_set_gtk_surface_modal (GdkSurface *surface);
313
314static void gdk_wayland_surface_sync_shadow (GdkSurface *surface);
315static void gdk_wayland_surface_sync_input_region (GdkSurface *surface);
316static void gdk_wayland_surface_sync_opaque_region (GdkSurface *surface);
317
318static void unset_transient_for_exported (GdkSurface *surface);
319
320static void gdk_wayland_surface_move_resize (GdkSurface *surface,
321 int x,
322 int y,
323 int width,
324 int height);
325
326static void update_popup_layout_state (GdkSurface *surface,
327 int x,
328 int y,
329 int width,
330 int height,
331 GdkPopupLayout *layout);
332
333static gboolean gdk_wayland_toplevel_is_exported (GdkWaylandToplevel *wayland_toplevel);
334
335static void configure_toplevel_geometry (GdkSurface *surface);
336
337static void
338gdk_wayland_surface_init (GdkWaylandSurface *impl)
339{
340 impl->scale = 1;
341 impl->initial_fullscreen_output = NULL;
342 impl->saved_width = -1;
343 impl->saved_height = -1;
344 impl->shortcuts_inhibitors = g_hash_table_new (NULL, NULL);
345}
346
347static void
348gdk_wayland_surface_freeze_state (GdkSurface *surface)
349{
350 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
351
352 impl->state_freeze_count++;
353}
354
355static void
356gdk_wayland_surface_thaw_state (GdkSurface *surface)
357{
358 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
359
360 g_assert (impl->state_freeze_count > 0);
361
362 impl->state_freeze_count--;
363
364 if (impl->state_freeze_count > 0)
365 return;
366
367 if (impl->pending.is_dirty)
368 gdk_wayland_surface_configure (surface);
369
370 g_assert (!impl->display_server.xdg_popup);
371}
372
373static void
374_gdk_wayland_surface_save_size (GdkSurface *surface)
375{
376 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
377
378 if (surface->state & (GDK_TOPLEVEL_STATE_FULLSCREEN |
379 GDK_TOPLEVEL_STATE_MAXIMIZED |
380 GDK_TOPLEVEL_STATE_TILED))
381 return;
382
383 if (surface->width <= 1 || surface->height <= 1)
384 return;
385
386 impl->saved_width = surface->width - impl->shadow_left - impl->shadow_right;
387 impl->saved_height = surface->height - impl->shadow_top - impl->shadow_bottom;
388}
389
390static void
391_gdk_wayland_surface_clear_saved_size (GdkSurface *surface)
392{
393 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
394
395 if (surface->state & (GDK_TOPLEVEL_STATE_FULLSCREEN | GDK_TOPLEVEL_STATE_MAXIMIZED))
396 return;
397
398 impl->saved_width = -1;
399 impl->saved_height = -1;
400}
401
402static void
403gdk_wayland_surface_update_size (GdkSurface *surface,
404 int32_t width,
405 int32_t height,
406 int scale)
407{
408 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
409 gboolean width_changed, height_changed, scale_changed;
410
411 width_changed = surface->width != width;
412 height_changed = surface->height != height;
413 scale_changed = impl->scale != scale;
414
415 if (!width_changed && !height_changed && !scale_changed)
416 return;
417
418 surface->width = width;
419 surface->height = height;
420 impl->scale = scale;
421
422 if (impl->display_server.egl_window)
423 wl_egl_window_resize (egl_window: impl->display_server.egl_window, width: width * scale, height: height * scale, dx: 0, dy: 0);
424 if (impl->display_server.wl_surface)
425 wl_surface_set_buffer_scale (wl_surface: impl->display_server.wl_surface, scale);
426
427 gdk_surface_invalidate_rect (surface, NULL);
428
429 if (width_changed)
430 g_object_notify (G_OBJECT (surface), property_name: "width");
431 if (height_changed)
432 g_object_notify (G_OBJECT (surface), property_name: "height");
433 if (scale_changed)
434 g_object_notify (G_OBJECT (surface), property_name: "scale-factor");
435
436 _gdk_surface_update_size (surface);
437}
438
439static const char *
440get_default_title (void)
441{
442 const char *title;
443
444 title = g_get_application_name ();
445 if (!title)
446 title = g_get_prgname ();
447 if (!title)
448 title = "";
449
450 return title;
451}
452
453static void
454fill_presentation_time_from_frame_time (GdkFrameTimings *timings,
455 guint32 frame_time)
456{
457 /* The timestamp in a wayland frame is a msec time value that in some
458 * way reflects the time at which the server started drawing the frame.
459 * This is not useful from our perspective.
460 *
461 * However, for the DRM backend of Weston, on reasonably recent
462 * Linux, we know that the time is the
463 * clock_gettime (CLOCK_MONOTONIC) value at the vblank, and that
464 * backend starts drawing immediately after receiving the vblank
465 * notification. If we detect this, and make the assumption that the
466 * compositor will finish drawing before the next vblank, we can
467 * then determine the presentation time as the frame time we
468 * received plus one refresh interval.
469 *
470 * If a backend is using clock_gettime(CLOCK_MONOTONIC), but not
471 * picking values right at the vblank, then the presentation times
472 * we compute won't be accurate, but not really worse than then
473 * the alternative of not providing presentation times at all.
474 *
475 * The complexity here is dealing with the fact that we receive
476 * only the low 32 bits of the CLOCK_MONOTONIC value in milliseconds.
477 */
478 gint64 now_monotonic = g_get_monotonic_time ();
479 gint64 now_monotonic_msec = now_monotonic / 1000;
480 uint32_t now_monotonic_low = (uint32_t)now_monotonic_msec;
481
482 if (frame_time - now_monotonic_low < 1000 ||
483 frame_time - now_monotonic_low > (uint32_t)-1000)
484 {
485 /* Timestamp we received is within one second of the current time.
486 */
487 gint64 last_frame_time = now_monotonic + (gint64)1000 * (gint32)(frame_time - now_monotonic_low);
488 if ((gint32)now_monotonic_low < 0 && (gint32)frame_time > 0)
489 last_frame_time += (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
490 else if ((gint32)now_monotonic_low > 0 && (gint32)frame_time < 0)
491 last_frame_time -= (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
492
493 timings->presentation_time = last_frame_time + timings->refresh_interval;
494 }
495}
496
497static GdkSurface *
498get_popup_toplevel (GdkSurface *surface)
499{
500 if (surface->parent)
501 return get_popup_toplevel (surface: surface->parent);
502 else
503 return surface;
504}
505
506static void
507freeze_popup_toplevel_state (GdkSurface *surface)
508{
509 GdkSurface *toplevel;
510
511 toplevel = get_popup_toplevel (surface);
512 gdk_wayland_surface_freeze_state (surface: toplevel);
513}
514
515static void
516thaw_popup_toplevel_state (GdkSurface *surface)
517{
518 GdkSurface *toplevel;
519
520 toplevel = get_popup_toplevel (surface);
521 gdk_wayland_surface_thaw_state (surface: toplevel);
522}
523
524static void
525finish_pending_relayout (GdkSurface *surface)
526{
527 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
528
529 g_assert (impl->popup_state == POPUP_STATE_WAITING_FOR_FRAME);
530 impl->popup_state = POPUP_STATE_IDLE;
531
532 thaw_popup_toplevel_state (surface);
533}
534
535static void
536frame_callback (void *data,
537 struct wl_callback *callback,
538 uint32_t time)
539{
540 GdkSurface *surface = data;
541 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
542 GdkWaylandDisplay *display_wayland =
543 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
544 GdkFrameClock *clock = gdk_surface_get_frame_clock (surface);
545 GdkFrameTimings *timings;
546
547 gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "wayland", "frame event");
548 GDK_DISPLAY_NOTE (GDK_DISPLAY (display_wayland), EVENTS, g_message ("frame %p", surface));
549
550 wl_callback_destroy (wl_callback: callback);
551
552 if (GDK_SURFACE_DESTROYED (surface))
553 return;
554
555 if (!impl->awaiting_frame)
556 return;
557
558 switch (impl->popup_state)
559 {
560 case POPUP_STATE_IDLE:
561 case POPUP_STATE_WAITING_FOR_REPOSITIONED:
562 case POPUP_STATE_WAITING_FOR_CONFIGURE:
563 break;
564 case POPUP_STATE_WAITING_FOR_FRAME:
565 finish_pending_relayout (surface);
566 break;
567 default:
568 g_assert_not_reached ();
569 }
570
571 impl->awaiting_frame = FALSE;
572 if (impl->awaiting_frame_frozen)
573 {
574 impl->awaiting_frame_frozen = FALSE;
575 gdk_surface_thaw_updates (surface);
576 }
577
578 timings = gdk_frame_clock_get_timings (frame_clock: clock, frame_counter: impl->pending_frame_counter);
579 impl->pending_frame_counter = 0;
580
581 if (timings == NULL)
582 return;
583
584 timings->refresh_interval = 16667; /* default to 1/60th of a second */
585 if (impl->display_server.outputs)
586 {
587 /* We pick a random output out of the outputs that the surface touches
588 * The rate here is in milli-hertz */
589 int refresh_rate =
590 gdk_wayland_display_get_output_refresh_rate (display_wayland,
591 output: impl->display_server.outputs->data);
592 if (refresh_rate != 0)
593 timings->refresh_interval = G_GINT64_CONSTANT(1000000000) / refresh_rate;
594 }
595
596 fill_presentation_time_from_frame_time (timings, frame_time: time);
597
598 timings->complete = TRUE;
599
600#ifdef G_ENABLE_DEBUG
601 if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0)
602 _gdk_frame_clock_debug_print_timings (clock, timings);
603#endif
604
605 if (GDK_PROFILER_IS_RUNNING)
606 _gdk_frame_clock_add_timings_to_profiler (frame_clock: clock, timings);
607}
608
609static const struct wl_callback_listener frame_listener = {
610 frame_callback
611};
612
613static void
614on_frame_clock_before_paint (GdkFrameClock *clock,
615 GdkSurface *surface)
616{
617 GdkFrameTimings *timings = gdk_frame_clock_get_current_timings (frame_clock: clock);
618 gint64 presentation_time;
619 gint64 refresh_interval;
620
621 if (surface->update_freeze_count > 0)
622 return;
623
624 gdk_frame_clock_get_refresh_info (frame_clock: clock,
625 base_time: timings->frame_time,
626 refresh_interval_return: &refresh_interval, presentation_time_return: &presentation_time);
627
628 if (presentation_time != 0)
629 {
630 /* Assume the algorithm used by the DRM backend of Weston - it
631 * starts drawing at the next vblank after receiving the commit
632 * for this frame, and presentation occurs at the vblank
633 * after that.
634 */
635 timings->predicted_presentation_time = presentation_time + refresh_interval;
636 }
637 else
638 {
639 /* As above, but we don't actually know the phase of the vblank,
640 * so just assume that we're half way through a refresh cycle.
641 */
642 timings->predicted_presentation_time = timings->frame_time + refresh_interval / 2 + refresh_interval;
643 }
644
645 gdk_surface_apply_state_change (surface);
646}
647
648static void
649configure_popup_geometry (GdkSurface *surface)
650{
651 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
652 int x, y;
653 int width, height;
654
655 x = impl->next_layout.popup.x - impl->shadow_left;
656 y = impl->next_layout.popup.y - impl->shadow_top;
657 width =
658 impl->next_layout.configured_width +
659 (impl->shadow_left + impl->shadow_right);
660 height =
661 impl->next_layout.configured_height +
662 (impl->shadow_top + impl->shadow_bottom);
663
664 gdk_wayland_surface_move_resize (surface, x, y, width, height);
665}
666
667static void
668configure_drag_surface_geometry (GdkSurface *surface)
669{
670 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
671
672 gdk_wayland_surface_update_size (surface,
673 width: impl->next_layout.configured_width,
674 height: impl->next_layout.configured_height,
675 scale: impl->scale);
676}
677
678static gboolean
679gdk_wayland_surface_compute_size (GdkSurface *surface)
680{
681 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
682
683 if (impl->next_layout.surface_geometry_dirty)
684 {
685 if (GDK_IS_TOPLEVEL (ptr: impl))
686 configure_toplevel_geometry (surface);
687 else if (GDK_IS_POPUP (ptr: impl))
688 configure_popup_geometry (surface);
689 else if (GDK_IS_DRAG_SURFACE (ptr: impl))
690 configure_drag_surface_geometry (surface);
691
692 impl->next_layout.surface_geometry_dirty = FALSE;
693 }
694
695 return FALSE;
696}
697
698static void
699gdk_wayland_surface_request_layout (GdkSurface *surface)
700{
701 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
702
703 impl->next_layout.surface_geometry_dirty = TRUE;
704}
705
706void
707gdk_wayland_surface_request_frame (GdkSurface *surface)
708{
709 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
710 struct wl_callback *callback;
711 GdkFrameClock *clock;
712
713 if (impl->awaiting_frame)
714 return;
715
716 clock = gdk_surface_get_frame_clock (surface);
717
718 callback = wl_surface_frame (wl_surface: impl->display_server.wl_surface);
719 wl_proxy_set_queue (proxy: (struct wl_proxy *) callback, NULL);
720 wl_callback_add_listener (wl_callback: callback, listener: &frame_listener, data: surface);
721 impl->pending_frame_counter = gdk_frame_clock_get_frame_counter (frame_clock: clock);
722 impl->awaiting_frame = TRUE;
723}
724
725gboolean
726gdk_wayland_surface_has_surface (GdkSurface *surface)
727{
728 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
729
730 return !!impl->display_server.wl_surface;
731}
732
733void
734gdk_wayland_surface_commit (GdkSurface *surface)
735{
736 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
737
738 wl_surface_commit (wl_surface: impl->display_server.wl_surface);
739}
740
741void
742gdk_wayland_surface_notify_committed (GdkSurface *surface)
743{
744 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
745
746 impl->has_uncommitted_ack_configure = FALSE;
747}
748
749static void
750on_frame_clock_after_paint (GdkFrameClock *clock,
751 GdkSurface *surface)
752{
753 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
754
755 if (surface->update_freeze_count == 0 && impl->has_uncommitted_ack_configure)
756 {
757 gdk_wayland_surface_commit (surface);
758 gdk_wayland_surface_notify_committed (surface);
759 }
760
761 if (impl->awaiting_frame &&
762 impl->pending_frame_counter == gdk_frame_clock_get_frame_counter (frame_clock: clock))
763 {
764 impl->awaiting_frame_frozen = TRUE;
765 gdk_surface_freeze_updates (surface);
766 }
767}
768
769void
770gdk_wayland_surface_update_scale (GdkSurface *surface)
771{
772 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
773 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
774 guint32 scale;
775 GSList *l;
776
777 if (display_wayland->compositor_version < WL_SURFACE_HAS_BUFFER_SCALE)
778 {
779 /* We can't set the scale on this surface */
780 return;
781 }
782
783 if (!impl->display_server.outputs)
784 {
785 scale = impl->scale;
786 }
787 else
788 {
789 scale = 1;
790 for (l = impl->display_server.outputs; l != NULL; l = l->next)
791 {
792 struct wl_output *output = l->data;
793 uint32_t output_scale;
794
795 output_scale = gdk_wayland_display_get_output_scale (display_wayland,
796 output);
797 scale = MAX (scale, output_scale);
798 }
799 }
800
801 /* Notify app that scale changed */
802 gdk_wayland_surface_maybe_resize (surface,
803 width: surface->width, height: surface->height,
804 scale);
805}
806
807static void gdk_wayland_surface_create_surface (GdkSurface *surface);
808static void gdk_wayland_surface_set_title (GdkSurface *surface,
809 const char *title);
810
811GdkSurface *
812_gdk_wayland_display_create_surface (GdkDisplay *display,
813 GdkSurfaceType surface_type,
814 GdkSurface *parent,
815 int x,
816 int y,
817 int width,
818 int height)
819{
820 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
821 GdkSurface *surface;
822 GdkWaylandSurface *impl;
823 GdkFrameClock *frame_clock;
824
825 if (parent)
826 frame_clock = g_object_ref (gdk_surface_get_frame_clock (parent));
827 else
828 frame_clock = _gdk_frame_clock_idle_new ();
829
830 switch (surface_type)
831 {
832 case GDK_SURFACE_TOPLEVEL:
833 surface = g_object_new (GDK_TYPE_WAYLAND_TOPLEVEL,
834 first_property_name: "display", display,
835 "frame-clock", frame_clock,
836 NULL);
837 display_wayland->toplevels = g_list_prepend (list: display_wayland->toplevels,
838 data: surface);
839 g_warn_if_fail (!parent);
840 break;
841 case GDK_SURFACE_POPUP:
842 surface = g_object_new (GDK_TYPE_WAYLAND_POPUP,
843 first_property_name: "parent", parent,
844 "display", display,
845 "frame-clock", frame_clock,
846 NULL);
847 break;
848 case GDK_SURFACE_TEMP:
849 surface = g_object_new (GDK_TYPE_WAYLAND_DRAG_SURFACE,
850 first_property_name: "display", display,
851 "frame-clock", frame_clock,
852 NULL);
853 break;
854 default:
855 g_assert_not_reached ();
856 break;
857 }
858
859 impl = GDK_WAYLAND_SURFACE (surface);
860
861 if (width > 65535)
862 {
863 g_warning ("Native Surfaces wider than 65535 pixels are not supported");
864 width = 65535;
865 }
866 if (height > 65535)
867 {
868 g_warning ("Native Surfaces taller than 65535 pixels are not supported");
869 height = 65535;
870 }
871
872 surface->x = x;
873 surface->y = y;
874 surface->width = width;
875 surface->height = height;
876
877 g_object_ref (surface);
878
879 /* More likely to be right than just assuming 1 */
880 if (display_wayland->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE)
881 {
882 GdkMonitor *monitor = g_list_model_get_item (list: gdk_display_get_monitors (self: display), position: 0);
883 if (monitor)
884 {
885 impl->scale = gdk_monitor_get_scale_factor (monitor);
886 g_object_unref (object: monitor);
887 }
888 }
889
890 gdk_wayland_surface_set_title (surface, title: get_default_title ());
891
892
893 gdk_wayland_surface_create_surface (surface);
894
895 g_signal_connect (frame_clock, "before-paint", G_CALLBACK (on_frame_clock_before_paint), surface);
896 g_signal_connect (frame_clock, "after-paint", G_CALLBACK (on_frame_clock_after_paint), surface);
897
898 g_object_unref (object: frame_clock);
899
900 return surface;
901}
902
903void
904gdk_wayland_surface_attach_image (GdkSurface *surface,
905 cairo_surface_t *cairo_surface,
906 const cairo_region_t *damage)
907{
908 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
909 GdkWaylandDisplay *display;
910 cairo_rectangle_int_t rect;
911 int i, n;
912
913 if (GDK_SURFACE_DESTROYED (surface))
914 return;
915
916 g_assert (_gdk_wayland_is_shm_surface (cairo_surface));
917
918 /* Attach this new buffer to the surface */
919 wl_surface_attach (wl_surface: impl->display_server.wl_surface,
920 buffer: _gdk_wayland_shm_surface_get_wl_buffer (surface: cairo_surface),
921 x: impl->pending_buffer_offset_x,
922 y: impl->pending_buffer_offset_y);
923 impl->pending_buffer_offset_x = 0;
924 impl->pending_buffer_offset_y = 0;
925
926 /* Only set the buffer scale if supported by the compositor */
927 display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
928 if (display->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE)
929 wl_surface_set_buffer_scale (wl_surface: impl->display_server.wl_surface, scale: impl->scale);
930
931 n = cairo_region_num_rectangles (region: damage);
932 for (i = 0; i < n; i++)
933 {
934 cairo_region_get_rectangle (region: damage, nth: i, rectangle: &rect);
935 wl_surface_damage (wl_surface: impl->display_server.wl_surface, x: rect.x, y: rect.y, width: rect.width, height: rect.height);
936 }
937}
938
939static void
940gdk_wayland_surface_sync_offset (GdkSurface *surface)
941{
942 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
943
944 if (wl_surface_get_version (wl_surface: impl->display_server.wl_surface) <
945 WL_SURFACE_OFFSET_SINCE_VERSION)
946 return;
947
948 if (impl->pending_buffer_offset_x == 0 &&
949 impl->pending_buffer_offset_y == 0)
950 return;
951
952 wl_surface_offset (wl_surface: impl->display_server.wl_surface,
953 x: impl->pending_buffer_offset_x,
954 y: impl->pending_buffer_offset_y);
955 impl->pending_buffer_offset_x = 0;
956 impl->pending_buffer_offset_y = 0;
957}
958
959void
960gdk_wayland_surface_sync (GdkSurface *surface)
961{
962 gdk_wayland_surface_sync_shadow (surface);
963 gdk_wayland_surface_sync_opaque_region (surface);
964 gdk_wayland_surface_sync_input_region (surface);
965 gdk_wayland_surface_sync_offset (surface);
966}
967
968static gboolean
969gdk_wayland_surface_beep (GdkSurface *surface)
970{
971 gdk_wayland_display_system_bell (display: gdk_surface_get_display (surface),
972 surface);
973
974 return TRUE;
975}
976
977static void
978gdk_wayland_surface_constructed (GObject *object)
979{
980 GdkSurface *surface = GDK_SURFACE (object);
981 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
982 GdkWaylandDisplay *display_wayland =
983 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
984
985 G_OBJECT_CLASS (gdk_wayland_surface_parent_class)->constructed (object);
986
987 impl->event_queue = wl_display_create_queue (display: display_wayland->wl_display);
988 display_wayland->event_queues = g_list_prepend (list: display_wayland->event_queues,
989 data: impl->event_queue);
990}
991
992static void
993gdk_wayland_surface_dispose (GObject *object)
994{
995 GdkSurface *surface = GDK_SURFACE (object);
996 GdkWaylandSurface *impl;
997
998 g_return_if_fail (GDK_IS_WAYLAND_SURFACE (surface));
999
1000 impl = GDK_WAYLAND_SURFACE (surface);
1001
1002 if (impl->event_queue)
1003 {
1004 GdkWaylandDisplay *display_wayland =
1005 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
1006
1007 display_wayland->event_queues =
1008 g_list_remove (list: display_wayland->event_queues, data: surface);
1009 g_clear_pointer (&impl->event_queue, wl_event_queue_destroy);
1010 }
1011
1012 G_OBJECT_CLASS (gdk_wayland_surface_parent_class)->dispose (object);
1013}
1014
1015static void
1016gdk_wayland_surface_finalize (GObject *object)
1017{
1018 GdkWaylandSurface *impl;
1019
1020 g_return_if_fail (GDK_IS_WAYLAND_SURFACE (object));
1021
1022 impl = GDK_WAYLAND_SURFACE (object);
1023
1024 g_free (mem: impl->title);
1025
1026 g_free (mem: impl->application.application_id);
1027 g_free (mem: impl->application.app_menu_path);
1028 g_free (mem: impl->application.menubar_path);
1029 g_free (mem: impl->application.window_object_path);
1030 g_free (mem: impl->application.application_object_path);
1031 g_free (mem: impl->application.unique_bus_name);
1032
1033 g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
1034 g_clear_pointer (&impl->input_region, cairo_region_destroy);
1035 g_clear_pointer (&impl->shortcuts_inhibitors, g_hash_table_unref);
1036
1037 G_OBJECT_CLASS (gdk_wayland_surface_parent_class)->finalize (object);
1038}
1039
1040static gboolean
1041is_realized_shell_surface (GdkWaylandSurface *impl)
1042{
1043 return (impl->display_server.xdg_surface ||
1044 impl->display_server.zxdg_surface_v6);
1045}
1046
1047static gboolean
1048is_realized_toplevel (GdkWaylandSurface *impl)
1049{
1050 return (impl->display_server.xdg_toplevel ||
1051 impl->display_server.zxdg_toplevel_v6);
1052}
1053
1054static gboolean
1055is_realized_popup (GdkWaylandSurface *impl)
1056{
1057 return (impl->display_server.xdg_popup ||
1058 impl->display_server.zxdg_popup_v6);
1059}
1060
1061static void gdk_wayland_surface_show (GdkSurface *surface);
1062static void gdk_wayland_surface_hide (GdkSurface *surface);
1063
1064static void
1065gdk_wayland_surface_maybe_resize (GdkSurface *surface,
1066 int width,
1067 int height,
1068 int scale)
1069{
1070 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1071 gboolean is_xdg_popup;
1072 gboolean is_visible;
1073
1074 if (surface->width == width &&
1075 surface->height == height &&
1076 impl->scale == scale)
1077 return;
1078
1079 /* For xdg_popup using an xdg_positioner, there is a race condition if
1080 * the application tries to change the size after it's mapped, but before
1081 * the initial configure is received, so hide and show the surface again
1082 * force the new size onto the compositor. See bug #772505.
1083 */
1084
1085 is_xdg_popup = is_realized_popup (impl);
1086 is_visible = gdk_surface_get_mapped (surface);
1087
1088 if (is_xdg_popup && is_visible && !impl->initial_configure_received)
1089 gdk_wayland_surface_hide (surface);
1090
1091 gdk_wayland_surface_update_size (surface, width, height, scale);
1092
1093 if (is_xdg_popup && is_visible && !impl->initial_configure_received)
1094 gdk_wayland_surface_show (surface);
1095}
1096
1097static void
1098gdk_wayland_surface_sync_parent (GdkSurface *surface,
1099 GdkSurface *parent)
1100{
1101 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1102 GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (impl);
1103 GdkWaylandDisplay *display_wayland =
1104 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
1105 GdkWaylandSurface *impl_parent = NULL;
1106
1107 g_assert (parent == NULL ||
1108 gdk_surface_get_display (surface) == gdk_surface_get_display (parent));
1109
1110 if (!is_realized_toplevel (impl))
1111 return;
1112
1113 if (toplevel->transient_for)
1114 impl_parent = GDK_WAYLAND_SURFACE (toplevel->transient_for);
1115 else if (parent)
1116 impl_parent = GDK_WAYLAND_SURFACE (parent);
1117
1118 /* XXX: Is this correct? */
1119 if (impl_parent && !impl_parent->display_server.wl_surface)
1120 return;
1121
1122 switch (display_wayland->shell_variant)
1123 {
1124 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
1125 {
1126 struct xdg_toplevel *parent_toplevel;
1127
1128 if (impl_parent)
1129 parent_toplevel = impl_parent->display_server.xdg_toplevel;
1130 else
1131 parent_toplevel = NULL;
1132
1133 xdg_toplevel_set_parent (impl->display_server.xdg_toplevel,
1134 parent_toplevel);
1135 break;
1136 }
1137 break;
1138 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
1139 {
1140 struct zxdg_toplevel_v6 *parent_toplevel;
1141
1142 if (impl_parent)
1143 parent_toplevel = impl_parent->display_server.zxdg_toplevel_v6;
1144 else
1145 parent_toplevel = NULL;
1146
1147 zxdg_toplevel_v6_set_parent (impl->display_server.zxdg_toplevel_v6,
1148 parent_toplevel);
1149 break;
1150 }
1151 default:
1152 g_assert_not_reached ();
1153 }
1154}
1155
1156static void
1157gdk_wayland_surface_sync_parent_of_imported (GdkWaylandSurface *impl)
1158{
1159 if (!impl->display_server.wl_surface)
1160 return;
1161
1162 if (!impl->imported_transient_for)
1163 return;
1164
1165 if (!is_realized_toplevel (impl))
1166 return;
1167
1168 zxdg_imported_v1_set_parent_of (impl->imported_transient_for,
1169 impl->display_server.wl_surface);
1170}
1171
1172static void
1173gdk_wayland_surface_sync_title (GdkSurface *surface)
1174{
1175 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1176 GdkWaylandDisplay *display_wayland =
1177 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
1178
1179 if (!is_realized_toplevel (impl))
1180 return;
1181
1182 if (!impl->title)
1183 return;
1184
1185 switch (display_wayland->shell_variant)
1186 {
1187 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
1188 xdg_toplevel_set_title (impl->display_server.xdg_toplevel,
1189 impl->title);
1190 break;
1191 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
1192 zxdg_toplevel_v6_set_title (impl->display_server.zxdg_toplevel_v6,
1193 impl->title);
1194 break;
1195 default:
1196 g_assert_not_reached ();
1197 }
1198}
1199
1200static void
1201gdk_wayland_surface_get_window_geometry (GdkSurface *surface,
1202 GdkRectangle *geometry)
1203{
1204 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1205
1206 *geometry = (GdkRectangle) {
1207 .x = impl->shadow_left,
1208 .y = impl->shadow_top,
1209 .width = surface->width - (impl->shadow_left + impl->shadow_right),
1210 .height = surface->height - (impl->shadow_top + impl->shadow_bottom)
1211 };
1212}
1213
1214static void gdk_wayland_surface_set_geometry_hints (GdkWaylandSurface *impl,
1215 const GdkGeometry *geometry,
1216 GdkSurfaceHints geom_mask);
1217
1218static void
1219gdk_wayland_surface_sync_shadow (GdkSurface *surface)
1220{
1221 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1222 GdkWaylandDisplay *display_wayland =
1223 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
1224 GdkRectangle geometry;
1225
1226 if (!is_realized_shell_surface (impl))
1227 return;
1228
1229 gdk_wayland_surface_get_window_geometry (surface, geometry: &geometry);
1230 gdk_wayland_surface_set_geometry_hints (impl,
1231 geometry: &impl->geometry_hints,
1232 geom_mask: impl->geometry_mask);
1233
1234 if (gdk_rectangle_equal (rect1: &geometry, rect2: &impl->last_sent_window_geometry))
1235 return;
1236
1237 switch (display_wayland->shell_variant)
1238 {
1239 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
1240 xdg_surface_set_window_geometry (impl->display_server.xdg_surface,
1241 geometry.x,
1242 geometry.y,
1243 geometry.width,
1244 geometry.height);
1245 break;
1246 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
1247 zxdg_surface_v6_set_window_geometry (impl->display_server.zxdg_surface_v6,
1248 geometry.x,
1249 geometry.y,
1250 geometry.width,
1251 geometry.height);
1252 break;
1253 default:
1254 g_assert_not_reached ();
1255 }
1256
1257 impl->last_sent_window_geometry = geometry;
1258}
1259
1260static struct wl_region *
1261wl_region_from_cairo_region (GdkWaylandDisplay *display,
1262 cairo_region_t *region)
1263{
1264 struct wl_region *wl_region;
1265 int i, n_rects;
1266
1267 wl_region = wl_compositor_create_region (wl_compositor: display->compositor);
1268 if (wl_region == NULL)
1269 return NULL;
1270
1271 n_rects = cairo_region_num_rectangles (region);
1272 for (i = 0; i < n_rects; i++)
1273 {
1274 cairo_rectangle_int_t rect;
1275 cairo_region_get_rectangle (region, nth: i, rectangle: &rect);
1276 wl_region_add (wl_region, x: rect.x, y: rect.y, width: rect.width, height: rect.height);
1277 }
1278
1279 return wl_region;
1280}
1281
1282static void
1283gdk_wayland_surface_sync_opaque_region (GdkSurface *surface)
1284{
1285 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1286 struct wl_region *wl_region = NULL;
1287
1288 if (!impl->display_server.wl_surface)
1289 return;
1290
1291 if (!impl->opaque_region_dirty)
1292 return;
1293
1294 if (impl->opaque_region != NULL)
1295 wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)),
1296 region: impl->opaque_region);
1297
1298 wl_surface_set_opaque_region (wl_surface: impl->display_server.wl_surface, region: wl_region);
1299
1300 if (wl_region != NULL)
1301 wl_region_destroy (wl_region);
1302
1303 impl->opaque_region_dirty = FALSE;
1304}
1305
1306static void
1307gdk_wayland_surface_sync_input_region (GdkSurface *surface)
1308{
1309 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1310 struct wl_region *wl_region = NULL;
1311
1312 if (!impl->display_server.wl_surface)
1313 return;
1314
1315 if (!impl->input_region_dirty)
1316 return;
1317
1318 if (impl->input_region != NULL)
1319 wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)),
1320 region: impl->input_region);
1321
1322 wl_surface_set_input_region (wl_surface: impl->display_server.wl_surface, region: wl_region);
1323
1324 if (wl_region != NULL)
1325 wl_region_destroy (wl_region);
1326
1327 impl->input_region_dirty = FALSE;
1328}
1329
1330static void
1331surface_enter (void *data,
1332 struct wl_surface *wl_surface,
1333 struct wl_output *output)
1334{
1335 GdkSurface *surface = GDK_SURFACE (data);
1336 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1337 GdkDisplay *display = gdk_surface_get_display (surface);
1338 GdkMonitor *monitor;
1339
1340 GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS,
1341 g_message ("surface enter, surface %p output %p", surface, output));
1342
1343 impl->display_server.outputs = g_slist_prepend (list: impl->display_server.outputs, data: output);
1344
1345 gdk_wayland_surface_update_scale (surface);
1346
1347 monitor = gdk_wayland_display_get_monitor_for_output (display, output);
1348 gdk_surface_enter_monitor (surface, monitor);
1349}
1350
1351static void
1352surface_leave (void *data,
1353 struct wl_surface *wl_surface,
1354 struct wl_output *output)
1355{
1356 GdkSurface *surface = GDK_SURFACE (data);
1357 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1358 GdkDisplay *display = gdk_surface_get_display (surface);
1359 GdkMonitor *monitor;
1360
1361 GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS,
1362 g_message ("surface leave, surface %p output %p", surface, output));
1363
1364 impl->display_server.outputs = g_slist_remove (list: impl->display_server.outputs, data: output);
1365
1366 if (impl->display_server.outputs)
1367 gdk_wayland_surface_update_scale (surface);
1368
1369 monitor = gdk_wayland_display_get_monitor_for_output (display, output);
1370 gdk_surface_leave_monitor (surface, monitor);
1371}
1372
1373static const struct wl_surface_listener surface_listener = {
1374 surface_enter,
1375 surface_leave
1376};
1377
1378static void
1379gdk_wayland_surface_create_surface (GdkSurface *surface)
1380{
1381 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1382 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
1383 struct wl_surface *wl_surface;
1384
1385 wl_surface = wl_compositor_create_surface (wl_compositor: display_wayland->compositor);
1386 wl_proxy_set_queue (proxy: (struct wl_proxy *) wl_surface, queue: impl->event_queue);
1387 wl_surface_add_listener (wl_surface, listener: &surface_listener, data: surface);
1388
1389 impl->display_server.wl_surface = wl_surface;
1390}
1391
1392static void
1393configure_toplevel_geometry (GdkSurface *surface)
1394{
1395 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1396 GdkDisplay *display = gdk_surface_get_display (surface);
1397 GdkMonitor *monitor;
1398 int bounds_width, bounds_height;
1399 GdkToplevelSize size;
1400 GdkToplevelLayout *layout;
1401 GdkGeometry geometry;
1402 GdkSurfaceHints mask;
1403
1404 monitor = g_list_model_get_item (list: gdk_display_get_monitors (self: display), position: 0);
1405 if (monitor)
1406 {
1407 GdkRectangle monitor_geometry;
1408
1409 gdk_monitor_get_geometry (monitor, geometry: &monitor_geometry);
1410 g_object_unref (object: monitor);
1411 bounds_width = monitor_geometry.width;
1412 bounds_height = monitor_geometry.height;
1413 }
1414 else
1415 {
1416 bounds_width = 0;
1417 bounds_height = 0;
1418 }
1419
1420 gdk_toplevel_size_init (size: &size, bounds_width, bounds_height);
1421 gdk_toplevel_notify_compute_size (toplevel: GDK_TOPLEVEL (ptr: surface), size: &size);
1422 g_warn_if_fail (size.width > 0);
1423 g_warn_if_fail (size.height > 0);
1424
1425 layout = impl->toplevel.layout;
1426 if (gdk_toplevel_layout_get_resizable (layout))
1427 {
1428 geometry.min_width = size.min_width;
1429 geometry.min_height = size.min_height;
1430 mask = GDK_HINT_MIN_SIZE;
1431 }
1432 else
1433 {
1434 geometry.max_width = geometry.min_width = size.width;
1435 geometry.max_height = geometry.min_height = size.height;
1436 mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
1437 }
1438 gdk_wayland_surface_set_geometry_hints (impl, geometry: &geometry, geom_mask: mask);
1439
1440 if (size.shadow.is_valid)
1441 {
1442 impl->shadow_left = size.shadow.left;
1443 impl->shadow_right = size.shadow.right;
1444 impl->shadow_top = size.shadow.top;
1445 impl->shadow_bottom = size.shadow.bottom;
1446 }
1447
1448 if (impl->next_layout.configured_width > 0 &&
1449 impl->next_layout.configured_height > 0)
1450 {
1451 int width, height;
1452
1453 width = impl->next_layout.configured_width +
1454 impl->shadow_left + impl->shadow_right;
1455 height = impl->next_layout.configured_height +
1456 impl->shadow_top + impl->shadow_bottom;
1457
1458 if (impl->next_layout.toplevel.should_constrain)
1459 {
1460 gdk_surface_constrain_size (geometry: &impl->geometry_hints,
1461 flags: impl->geometry_mask,
1462 width, height,
1463 new_width: &width, new_height: &height);
1464 }
1465 gdk_wayland_surface_update_size (surface, width, height, scale: impl->scale);
1466
1467 if (!impl->next_layout.toplevel.size_is_fixed)
1468 {
1469 impl->next_layout.toplevel.should_constrain = FALSE;
1470 impl->next_layout.configured_width = 0;
1471 impl->next_layout.configured_height = 0;
1472 }
1473 }
1474 else
1475 {
1476 int width, height;
1477
1478 width = size.width;
1479 height = size.height;
1480 gdk_surface_constrain_size (geometry: &geometry, flags: mask,
1481 width, height,
1482 new_width: &width, new_height: &height);
1483 gdk_wayland_surface_update_size (surface, width, height, scale: impl->scale);
1484 }
1485}
1486
1487static void
1488synthesize_initial_surface_state (GdkSurface *surface,
1489 GdkToplevelState unset_flags,
1490 GdkToplevelState set_flags)
1491{
1492 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1493
1494 impl->initial_state.unset_flags |= unset_flags;
1495 impl->initial_state.set_flags &= ~unset_flags;
1496
1497 impl->initial_state.set_flags |= set_flags;
1498 impl->initial_state.unset_flags &= ~set_flags;
1499}
1500
1501static void
1502gdk_wayland_surface_configure_toplevel (GdkSurface *surface)
1503{
1504 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1505 GdkWaylandDisplay *display_wayland =
1506 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
1507 GdkToplevelState new_state;
1508 int width, height;
1509 gboolean is_resizing;
1510 gboolean fixed_size;
1511 gboolean was_fixed_size;
1512 gboolean saved_size;
1513
1514 new_state = impl->pending.toplevel.state;
1515 impl->pending.toplevel.state = 0;
1516
1517 is_resizing = impl->pending.toplevel.is_resizing;
1518 impl->pending.toplevel.is_resizing = FALSE;
1519
1520 fixed_size =
1521 new_state & (GDK_TOPLEVEL_STATE_MAXIMIZED |
1522 GDK_TOPLEVEL_STATE_FULLSCREEN |
1523 GDK_TOPLEVEL_STATE_TILED) ||
1524 is_resizing;
1525
1526 was_fixed_size =
1527 surface->state & (GDK_TOPLEVEL_STATE_MAXIMIZED |
1528 GDK_TOPLEVEL_STATE_FULLSCREEN |
1529 GDK_TOPLEVEL_STATE_TILED);
1530
1531 width = impl->pending.toplevel.width;
1532 height = impl->pending.toplevel.height;
1533
1534 saved_size = (width == 0 && height == 0);
1535 /* According to xdg_shell, an xdg_surface.configure with size 0x0
1536 * should be interpreted as that it is up to the client to set a
1537 * size.
1538 *
1539 * When transitioning from maximize or fullscreen state, this means
1540 * the client should configure its size back to what it was before
1541 * being maximize or fullscreen.
1542 */
1543 if (saved_size && !fixed_size && was_fixed_size)
1544 {
1545 width = impl->saved_width;
1546 height = impl->saved_height;
1547 }
1548
1549 if (width > 0 && height > 0)
1550 {
1551 if (!saved_size)
1552 {
1553 impl->next_layout.toplevel.should_constrain = TRUE;
1554
1555 /* Save size for next time we get 0x0 */
1556 _gdk_wayland_surface_save_size (surface);
1557 }
1558 else if (is_resizing)
1559 {
1560 impl->next_layout.toplevel.should_constrain = TRUE;
1561 }
1562 else
1563 {
1564 impl->next_layout.toplevel.should_constrain = FALSE;
1565 }
1566
1567 impl->next_layout.toplevel.size_is_fixed = fixed_size;
1568 impl->next_layout.configured_width = width;
1569 impl->next_layout.configured_height = height;
1570 }
1571 else
1572 {
1573 impl->next_layout.toplevel.should_constrain = FALSE;
1574 impl->next_layout.toplevel.size_is_fixed = FALSE;
1575 impl->next_layout.configured_width = 0;
1576 impl->next_layout.configured_height = 0;
1577 }
1578
1579 impl->next_layout.surface_geometry_dirty = TRUE;
1580 gdk_surface_request_layout (surface);
1581
1582 GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS,
1583 g_message ("configure, surface %p %dx%d,%s%s%s%s",
1584 surface, width, height,
1585 (new_state & GDK_TOPLEVEL_STATE_FULLSCREEN) ? " fullscreen" : "",
1586 (new_state & GDK_TOPLEVEL_STATE_MAXIMIZED) ? " maximized" : "",
1587 (new_state & GDK_TOPLEVEL_STATE_FOCUSED) ? " focused" : "",
1588 (new_state & GDK_TOPLEVEL_STATE_TILED) ? " tiled" : ""));
1589
1590 gdk_surface_queue_state_change (surface, unset_flags: ~0 & ~new_state, set_flags: new_state);
1591
1592 switch (display_wayland->shell_variant)
1593 {
1594 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
1595 xdg_surface_ack_configure (impl->display_server.xdg_surface,
1596 impl->pending.serial);
1597 break;
1598 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
1599 zxdg_surface_v6_ack_configure (impl->display_server.zxdg_surface_v6,
1600 impl->pending.serial);
1601 break;
1602 default:
1603 g_assert_not_reached ();
1604 }
1605}
1606
1607static void
1608gdk_wayland_surface_configure_popup (GdkSurface *surface)
1609{
1610 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1611 GdkRectangle parent_geometry;
1612 int x, y, width, height;
1613
1614 if (impl->display_server.xdg_popup)
1615 {
1616 xdg_surface_ack_configure (impl->display_server.xdg_surface,
1617 impl->pending.serial);
1618 }
1619 else if (impl->display_server.zxdg_popup_v6)
1620 {
1621 zxdg_surface_v6_ack_configure (impl->display_server.zxdg_surface_v6,
1622 impl->pending.serial);
1623 }
1624
1625 if (impl->pending.popup.has_repositioned_token)
1626 impl->received_reposition_token = impl->pending.popup.repositioned_token;
1627
1628 switch (impl->popup_state)
1629 {
1630 case POPUP_STATE_WAITING_FOR_REPOSITIONED:
1631 if (impl->received_reposition_token != impl->reposition_token)
1632 return;
1633 else
1634 gdk_surface_thaw_updates (surface);
1635 G_GNUC_FALLTHROUGH;
1636 case POPUP_STATE_WAITING_FOR_CONFIGURE:
1637 impl->popup_state = POPUP_STATE_WAITING_FOR_FRAME;
1638 break;
1639 case POPUP_STATE_IDLE:
1640 case POPUP_STATE_WAITING_FOR_FRAME:
1641 break;
1642 default:
1643 g_assert_not_reached ();
1644 }
1645
1646 x = impl->pending.popup.x;
1647 y = impl->pending.popup.y;
1648 width = impl->pending.popup.width;
1649 height = impl->pending.popup.height;
1650
1651 gdk_wayland_surface_get_window_geometry (surface: surface->parent, geometry: &parent_geometry);
1652 x += parent_geometry.x;
1653 y += parent_geometry.y;
1654
1655 update_popup_layout_state (surface,
1656 x, y,
1657 width, height,
1658 layout: impl->popup.layout);
1659
1660 impl->next_layout.popup.x = x;
1661 impl->next_layout.popup.y = y;
1662 impl->next_layout.configured_width = width;
1663 impl->next_layout.configured_height = height;
1664 impl->next_layout.surface_geometry_dirty = TRUE;
1665 gdk_surface_request_layout (surface);
1666}
1667
1668static void
1669maybe_notify_mapped (GdkSurface *surface)
1670{
1671 if (surface->destroyed)
1672 return;
1673
1674 if (!GDK_SURFACE_IS_MAPPED (surface))
1675 gdk_surface_set_is_mapped (surface, TRUE);
1676}
1677
1678static void
1679gdk_wayland_surface_configure (GdkSurface *surface)
1680{
1681 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1682
1683 if (!impl->initial_configure_received)
1684 {
1685 gdk_surface_thaw_updates (surface);
1686 impl->initial_configure_received = TRUE;
1687 impl->pending.is_initial_configure = TRUE;
1688 maybe_notify_mapped (surface);
1689 }
1690
1691 impl->has_uncommitted_ack_configure = TRUE;
1692
1693 if (is_realized_popup (impl))
1694 gdk_wayland_surface_configure_popup (surface);
1695 else if (is_realized_toplevel (impl))
1696 gdk_wayland_surface_configure_toplevel (surface);
1697 else
1698 g_warn_if_reached ();
1699
1700 impl->last_configure_serial = impl->pending.serial;
1701
1702 memset (s: &impl->pending, c: 0, n: sizeof (impl->pending));
1703}
1704
1705static void
1706gdk_wayland_surface_handle_configure (GdkSurface *surface,
1707 uint32_t serial)
1708{
1709 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1710
1711 impl->pending.is_dirty = TRUE;
1712 impl->pending.serial = serial;
1713
1714 if (impl->state_freeze_count > 0)
1715 return;
1716
1717 gdk_wayland_surface_configure (surface);
1718}
1719
1720static void
1721gdk_wayland_surface_handle_configure_toplevel (GdkSurface *surface,
1722 int32_t width,
1723 int32_t height,
1724 GdkToplevelState state)
1725{
1726 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1727
1728 impl->pending.toplevel.state |= state;
1729 impl->pending.toplevel.width = width;
1730 impl->pending.toplevel.height = height;
1731}
1732
1733static void
1734gdk_wayland_surface_handle_close (GdkSurface *surface)
1735{
1736 GdkDisplay *display;
1737 GdkEvent *event;
1738
1739 display = gdk_surface_get_display (surface);
1740
1741 GDK_DISPLAY_NOTE (display, EVENTS, g_message ("close %p", surface));
1742
1743 event = gdk_delete_event_new (surface);
1744
1745 _gdk_wayland_display_deliver_event (display, event);
1746}
1747
1748static void
1749xdg_surface_configure (void *data,
1750 struct xdg_surface *xdg_surface,
1751 uint32_t serial)
1752{
1753 GdkSurface *surface = GDK_SURFACE (data);
1754
1755 gdk_wayland_surface_handle_configure (surface, serial);
1756}
1757
1758static const struct xdg_surface_listener xdg_surface_listener = {
1759 xdg_surface_configure,
1760};
1761
1762static void
1763zxdg_surface_v6_configure (void *data,
1764 struct zxdg_surface_v6 *xdg_surface,
1765 uint32_t serial)
1766{
1767 GdkSurface *surface = GDK_SURFACE (data);
1768
1769 gdk_wayland_surface_handle_configure (surface, serial);
1770}
1771
1772static const struct zxdg_surface_v6_listener zxdg_surface_v6_listener = {
1773 zxdg_surface_v6_configure,
1774};
1775
1776static void
1777gdk_wayland_surface_create_xdg_surface_resources (GdkSurface *surface)
1778{
1779 GdkWaylandDisplay *display =
1780 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
1781 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1782
1783 switch (display->shell_variant)
1784 {
1785 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
1786 impl->display_server.xdg_surface =
1787 xdg_wm_base_get_xdg_surface (display->xdg_wm_base,
1788 impl->display_server.wl_surface);
1789 wl_proxy_set_queue (proxy: (struct wl_proxy *) impl->display_server.xdg_surface,
1790 queue: impl->event_queue);
1791 xdg_surface_add_listener (impl->display_server.xdg_surface,
1792 &xdg_surface_listener,
1793 surface);
1794 break;
1795 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
1796 impl->display_server.zxdg_surface_v6 =
1797 zxdg_shell_v6_get_xdg_surface (display->zxdg_shell_v6,
1798 impl->display_server.wl_surface);
1799 zxdg_surface_v6_add_listener (impl->display_server.zxdg_surface_v6,
1800 &zxdg_surface_v6_listener,
1801 surface);
1802 break;
1803 default:
1804 g_assert_not_reached ();
1805 }
1806}
1807
1808static void
1809xdg_toplevel_configure (void *data,
1810 struct xdg_toplevel *xdg_toplevel,
1811 int32_t width,
1812 int32_t height,
1813 struct wl_array *states)
1814{
1815 GdkSurface *surface = GDK_SURFACE (data);
1816 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1817 uint32_t *p;
1818 GdkToplevelState pending_state = 0;
1819
1820 impl->pending.toplevel.is_resizing = FALSE;
1821
1822 wl_array_for_each (p, states)
1823 {
1824 uint32_t state = *p;
1825
1826 switch (state)
1827 {
1828 case XDG_TOPLEVEL_STATE_FULLSCREEN:
1829 pending_state |= GDK_TOPLEVEL_STATE_FULLSCREEN;
1830 break;
1831 case XDG_TOPLEVEL_STATE_MAXIMIZED:
1832 pending_state |= GDK_TOPLEVEL_STATE_MAXIMIZED;
1833 break;
1834 case XDG_TOPLEVEL_STATE_ACTIVATED:
1835 pending_state |= GDK_TOPLEVEL_STATE_FOCUSED;
1836 break;
1837 case XDG_TOPLEVEL_STATE_RESIZING:
1838 impl->pending.toplevel.is_resizing = TRUE;
1839 break;
1840 default:
1841 /* Unknown state */
1842 break;
1843 }
1844 }
1845
1846 gdk_wayland_surface_handle_configure_toplevel (surface, width, height,
1847 state: pending_state);
1848}
1849
1850static void
1851xdg_toplevel_close (void *data,
1852 struct xdg_toplevel *xdg_toplevel)
1853{
1854 GdkSurface *surface = GDK_SURFACE (data);
1855
1856 gdk_wayland_surface_handle_close (surface);
1857}
1858
1859static const struct xdg_toplevel_listener xdg_toplevel_listener = {
1860 xdg_toplevel_configure,
1861 xdg_toplevel_close,
1862};
1863
1864static void
1865create_xdg_toplevel_resources (GdkSurface *surface)
1866{
1867 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1868
1869 impl->display_server.xdg_toplevel =
1870 xdg_surface_get_toplevel (impl->display_server.xdg_surface);
1871 xdg_toplevel_add_listener (impl->display_server.xdg_toplevel,
1872 &xdg_toplevel_listener,
1873 surface);
1874}
1875
1876static void
1877zxdg_toplevel_v6_configure (void *data,
1878 struct zxdg_toplevel_v6 *xdg_toplevel,
1879 int32_t width,
1880 int32_t height,
1881 struct wl_array *states)
1882{
1883 GdkSurface *surface = GDK_SURFACE (data);
1884 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1885 uint32_t *p;
1886 GdkToplevelState pending_state = 0;
1887
1888 impl->pending.toplevel.is_resizing = FALSE;
1889
1890 wl_array_for_each (p, states)
1891 {
1892 uint32_t state = *p;
1893
1894 switch (state)
1895 {
1896 case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN:
1897 pending_state |= GDK_TOPLEVEL_STATE_FULLSCREEN;
1898 break;
1899 case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED:
1900 pending_state |= GDK_TOPLEVEL_STATE_MAXIMIZED;
1901 break;
1902 case ZXDG_TOPLEVEL_V6_STATE_ACTIVATED:
1903 pending_state |= GDK_TOPLEVEL_STATE_FOCUSED;
1904 break;
1905 case ZXDG_TOPLEVEL_V6_STATE_RESIZING:
1906 impl->pending.toplevel.is_resizing = TRUE;
1907 break;
1908 default:
1909 /* Unknown state */
1910 break;
1911 }
1912 }
1913
1914 gdk_wayland_surface_handle_configure_toplevel (surface, width, height,
1915 state: pending_state);
1916}
1917
1918static void
1919zxdg_toplevel_v6_close (void *data,
1920 struct zxdg_toplevel_v6 *xdg_toplevel)
1921{
1922 GdkSurface *surface = GDK_SURFACE (data);
1923
1924 gdk_wayland_surface_handle_close (surface);
1925}
1926
1927static const struct zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = {
1928 zxdg_toplevel_v6_configure,
1929 zxdg_toplevel_v6_close,
1930};
1931
1932static void
1933create_zxdg_toplevel_v6_resources (GdkSurface *surface)
1934{
1935 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1936
1937 impl->display_server.zxdg_toplevel_v6 =
1938 zxdg_surface_v6_get_toplevel (impl->display_server.zxdg_surface_v6);
1939 zxdg_toplevel_v6_add_listener (impl->display_server.zxdg_toplevel_v6,
1940 &zxdg_toplevel_v6_listener,
1941 surface);
1942}
1943
1944/**
1945 * gdk_wayland_toplevel_set_application_id:
1946 * @toplevel: (type GdkWaylandToplevel): a `GdkToplevel`
1947 * @application_id: the application id for the @toplevel
1948 *
1949 * Sets the application id on a `GdkToplevel`.
1950 */
1951void
1952gdk_wayland_toplevel_set_application_id (GdkToplevel *toplevel,
1953 const char *application_id)
1954{
1955 GdkWaylandSurface *impl;
1956 GdkWaylandDisplay *display_wayland;
1957
1958 g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
1959
1960 g_return_if_fail (application_id != NULL);
1961
1962 if (GDK_SURFACE_DESTROYED (toplevel))
1963 return;
1964
1965 impl = GDK_WAYLAND_SURFACE (toplevel);
1966
1967 if (!is_realized_toplevel (impl))
1968 return;
1969
1970 display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
1971
1972 switch (display_wayland->shell_variant)
1973 {
1974 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
1975 xdg_toplevel_set_app_id (impl->display_server.xdg_toplevel,
1976 application_id);
1977 break;
1978 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
1979 zxdg_toplevel_v6_set_app_id (impl->display_server.zxdg_toplevel_v6,
1980 application_id);
1981 break;
1982 default:
1983 g_assert_not_reached ();
1984 }
1985}
1986
1987static void
1988gdk_wayland_surface_create_xdg_toplevel (GdkSurface *surface)
1989{
1990 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
1991 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
1992 const char *app_id;
1993
1994 gdk_surface_freeze_updates (surface);
1995 gdk_wayland_surface_create_xdg_surface_resources (surface);
1996
1997 switch (display_wayland->shell_variant)
1998 {
1999 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
2000 create_xdg_toplevel_resources (surface);
2001 break;
2002 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
2003 create_zxdg_toplevel_v6_resources (surface);
2004 break;
2005 default:
2006 g_assert_not_reached ();
2007 }
2008
2009 gdk_wayland_surface_sync_parent (surface, NULL);
2010 gdk_wayland_surface_sync_parent_of_imported (impl);
2011 gdk_wayland_surface_sync_title (surface);
2012
2013 switch (display_wayland->shell_variant)
2014 {
2015 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
2016 if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MAXIMIZED)
2017 xdg_toplevel_set_maximized (impl->display_server.xdg_toplevel);
2018 if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MINIMIZED)
2019 xdg_toplevel_set_minimized (impl->display_server.xdg_toplevel);
2020 if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_FULLSCREEN)
2021 xdg_toplevel_set_fullscreen (impl->display_server.xdg_toplevel,
2022 impl->initial_fullscreen_output);
2023 break;
2024 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
2025 if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MAXIMIZED)
2026 zxdg_toplevel_v6_set_maximized (impl->display_server.zxdg_toplevel_v6);
2027 if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MINIMIZED)
2028 zxdg_toplevel_v6_set_minimized (impl->display_server.zxdg_toplevel_v6);
2029 if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_FULLSCREEN)
2030 zxdg_toplevel_v6_set_fullscreen (impl->display_server.zxdg_toplevel_v6,
2031 impl->initial_fullscreen_output);
2032 break;
2033 default:
2034 g_assert_not_reached ();
2035 }
2036
2037 impl->initial_fullscreen_output = NULL;
2038
2039 app_id = impl->application.application_id;
2040 if (app_id == NULL)
2041 app_id = g_get_prgname ();
2042
2043 if (app_id == NULL)
2044 app_id = "GTK Application";
2045
2046 gdk_wayland_toplevel_set_application_id (toplevel: GDK_TOPLEVEL (ptr: impl), application_id: app_id);
2047
2048 maybe_set_gtk_surface_dbus_properties (impl);
2049 maybe_set_gtk_surface_modal (surface);
2050
2051 gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "wayland", "surface commit");
2052 wl_surface_commit (wl_surface: impl->display_server.wl_surface);
2053}
2054
2055static void
2056gdk_wayland_surface_handle_configure_popup (GdkSurface *surface,
2057 int32_t x,
2058 int32_t y,
2059 int32_t width,
2060 int32_t height)
2061{
2062 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
2063
2064 impl->pending.popup.x = x;
2065 impl->pending.popup.y = y;
2066 impl->pending.popup.width = width;
2067 impl->pending.popup.height = height;
2068}
2069
2070static void
2071xdg_popup_configure (void *data,
2072 struct xdg_popup *xdg_popup,
2073 int32_t x,
2074 int32_t y,
2075 int32_t width,
2076 int32_t height)
2077{
2078 GdkSurface *surface = GDK_SURFACE (data);
2079
2080 gdk_wayland_surface_handle_configure_popup (surface, x, y, width, height);
2081}
2082
2083static void
2084xdg_popup_done (void *data,
2085 struct xdg_popup *xdg_popup)
2086{
2087 GdkSurface *surface = GDK_SURFACE (data);
2088
2089 GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS, g_message ("done %p", surface));
2090
2091 gdk_surface_hide (surface);
2092}
2093
2094static void
2095xdg_popup_repositioned (void *data,
2096 struct xdg_popup *xdg_popup,
2097 uint32_t token)
2098{
2099 GdkSurface *surface = GDK_SURFACE (data);
2100 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
2101
2102 GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS,
2103 g_message ("repositioned %p", surface));
2104
2105 if (impl->popup_state != POPUP_STATE_WAITING_FOR_REPOSITIONED)
2106 {
2107 g_warning ("Unexpected xdg_popup.repositioned event, probably buggy compositor");
2108 return;
2109 }
2110
2111 impl->pending.popup.repositioned_token = token;
2112 impl->pending.popup.has_repositioned_token = TRUE;
2113}
2114
2115static const struct xdg_popup_listener xdg_popup_listener = {
2116 xdg_popup_configure,
2117 xdg_popup_done,
2118 xdg_popup_repositioned,
2119};
2120
2121static void
2122zxdg_popup_v6_configure (void *data,
2123 struct zxdg_popup_v6 *xdg_popup,
2124 int32_t x,
2125 int32_t y,
2126 int32_t width,
2127 int32_t height)
2128{
2129 GdkSurface *surface = GDK_SURFACE (data);
2130
2131 gdk_wayland_surface_handle_configure_popup (surface, x, y, width, height);
2132}
2133
2134static void
2135zxdg_popup_v6_done (void *data,
2136 struct zxdg_popup_v6 *xdg_popup)
2137{
2138 GdkSurface *surface = GDK_SURFACE (data);
2139
2140 GDK_NOTE (EVENTS,
2141 g_message ("done %p", surface));
2142
2143 gdk_surface_hide (surface);
2144}
2145
2146static const struct zxdg_popup_v6_listener zxdg_popup_v6_listener = {
2147 zxdg_popup_v6_configure,
2148 zxdg_popup_v6_done,
2149};
2150
2151static enum xdg_positioner_anchor
2152rect_anchor_to_anchor (GdkGravity rect_anchor)
2153{
2154 switch (rect_anchor)
2155 {
2156 case GDK_GRAVITY_NORTH_WEST:
2157 case GDK_GRAVITY_STATIC:
2158 return XDG_POSITIONER_ANCHOR_TOP_LEFT;
2159 case GDK_GRAVITY_NORTH:
2160 return XDG_POSITIONER_ANCHOR_TOP;
2161 case GDK_GRAVITY_NORTH_EAST:
2162 return XDG_POSITIONER_ANCHOR_TOP_RIGHT;
2163 case GDK_GRAVITY_WEST:
2164 return XDG_POSITIONER_ANCHOR_LEFT;
2165 case GDK_GRAVITY_CENTER:
2166 return XDG_POSITIONER_ANCHOR_NONE;
2167 case GDK_GRAVITY_EAST:
2168 return XDG_POSITIONER_ANCHOR_RIGHT;
2169 case GDK_GRAVITY_SOUTH_WEST:
2170 return XDG_POSITIONER_ANCHOR_BOTTOM_LEFT;
2171 case GDK_GRAVITY_SOUTH:
2172 return XDG_POSITIONER_ANCHOR_BOTTOM;
2173 case GDK_GRAVITY_SOUTH_EAST:
2174 return XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT;
2175 default:
2176 g_assert_not_reached ();
2177 }
2178}
2179
2180static enum xdg_positioner_gravity
2181surface_anchor_to_gravity (GdkGravity rect_anchor)
2182{
2183 switch (rect_anchor)
2184 {
2185 case GDK_GRAVITY_NORTH_WEST:
2186 case GDK_GRAVITY_STATIC:
2187 return XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT;
2188 case GDK_GRAVITY_NORTH:
2189 return XDG_POSITIONER_GRAVITY_BOTTOM;
2190 case GDK_GRAVITY_NORTH_EAST:
2191 return XDG_POSITIONER_GRAVITY_BOTTOM_LEFT;
2192 case GDK_GRAVITY_WEST:
2193 return XDG_POSITIONER_GRAVITY_RIGHT;
2194 case GDK_GRAVITY_CENTER:
2195 return XDG_POSITIONER_GRAVITY_NONE;
2196 case GDK_GRAVITY_EAST:
2197 return XDG_POSITIONER_GRAVITY_LEFT;
2198 case GDK_GRAVITY_SOUTH_WEST:
2199 return XDG_POSITIONER_GRAVITY_TOP_RIGHT;
2200 case GDK_GRAVITY_SOUTH:
2201 return XDG_POSITIONER_GRAVITY_TOP;
2202 case GDK_GRAVITY_SOUTH_EAST:
2203 return XDG_POSITIONER_GRAVITY_TOP_LEFT;
2204 default:
2205 g_assert_not_reached ();
2206 }
2207}
2208
2209static enum zxdg_positioner_v6_anchor
2210rect_anchor_to_anchor_legacy (GdkGravity rect_anchor)
2211{
2212 switch (rect_anchor)
2213 {
2214 case GDK_GRAVITY_NORTH_WEST:
2215 case GDK_GRAVITY_STATIC:
2216 return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
2217 ZXDG_POSITIONER_V6_ANCHOR_LEFT);
2218 case GDK_GRAVITY_NORTH:
2219 return ZXDG_POSITIONER_V6_ANCHOR_TOP;
2220 case GDK_GRAVITY_NORTH_EAST:
2221 return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
2222 ZXDG_POSITIONER_V6_ANCHOR_RIGHT);
2223 case GDK_GRAVITY_WEST:
2224 return ZXDG_POSITIONER_V6_ANCHOR_LEFT;
2225 case GDK_GRAVITY_CENTER:
2226 return ZXDG_POSITIONER_V6_ANCHOR_NONE;
2227 case GDK_GRAVITY_EAST:
2228 return ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
2229 case GDK_GRAVITY_SOUTH_WEST:
2230 return (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
2231 ZXDG_POSITIONER_V6_ANCHOR_LEFT);
2232 case GDK_GRAVITY_SOUTH:
2233 return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
2234 case GDK_GRAVITY_SOUTH_EAST:
2235 return (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
2236 ZXDG_POSITIONER_V6_ANCHOR_RIGHT);
2237 default:
2238 g_assert_not_reached ();
2239 }
2240
2241 return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
2242 ZXDG_POSITIONER_V6_ANCHOR_LEFT);
2243}
2244
2245static enum zxdg_positioner_v6_gravity
2246surface_anchor_to_gravity_legacy (GdkGravity rect_anchor)
2247{
2248 switch (rect_anchor)
2249 {
2250 case GDK_GRAVITY_NORTH_WEST:
2251 case GDK_GRAVITY_STATIC:
2252 return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
2253 ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
2254 case GDK_GRAVITY_NORTH:
2255 return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
2256 case GDK_GRAVITY_NORTH_EAST:
2257 return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
2258 ZXDG_POSITIONER_V6_GRAVITY_LEFT);
2259 case GDK_GRAVITY_WEST:
2260 return ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
2261 case GDK_GRAVITY_CENTER:
2262 return ZXDG_POSITIONER_V6_GRAVITY_NONE;
2263 case GDK_GRAVITY_EAST:
2264 return ZXDG_POSITIONER_V6_GRAVITY_LEFT;
2265 case GDK_GRAVITY_SOUTH_WEST:
2266 return (ZXDG_POSITIONER_V6_GRAVITY_TOP |
2267 ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
2268 case GDK_GRAVITY_SOUTH:
2269 return ZXDG_POSITIONER_V6_GRAVITY_TOP;
2270 case GDK_GRAVITY_SOUTH_EAST:
2271 return (ZXDG_POSITIONER_V6_GRAVITY_TOP |
2272 ZXDG_POSITIONER_V6_GRAVITY_LEFT);
2273 default:
2274 g_assert_not_reached ();
2275 }
2276
2277 return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
2278 ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
2279}
2280
2281void
2282gdk_wayland_toplevel_announce_csd (GdkToplevel *toplevel)
2283{
2284 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
2285 GdkWaylandToplevel *toplevel_wayland;
2286
2287 g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
2288 toplevel_wayland = GDK_WAYLAND_TOPLEVEL (toplevel);
2289
2290 if (!display_wayland->server_decoration_manager)
2291 return;
2292 toplevel_wayland->server_decoration =
2293 org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
2294 gdk_wayland_surface_get_wl_surface (GDK_SURFACE (toplevel_wayland)));
2295 if (toplevel_wayland->server_decoration)
2296 org_kde_kwin_server_decoration_request_mode (toplevel_wayland->server_decoration,
2297 ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT);
2298}
2299
2300void
2301gdk_wayland_toplevel_announce_ssd (GdkToplevel *toplevel)
2302{
2303 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
2304 GdkWaylandToplevel *toplevel_wayland;
2305
2306 g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
2307 toplevel_wayland = GDK_WAYLAND_TOPLEVEL (toplevel);
2308
2309 if (!display_wayland->server_decoration_manager)
2310 return;
2311 toplevel_wayland->server_decoration =
2312 org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
2313 gdk_wayland_surface_get_wl_surface (GDK_SURFACE (toplevel_wayland)));
2314 if (toplevel_wayland->server_decoration)
2315 org_kde_kwin_server_decoration_request_mode (toplevel_wayland->server_decoration,
2316 ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER);
2317}
2318
2319gboolean
2320gdk_wayland_toplevel_inhibit_idle (GdkToplevel *toplevel)
2321{
2322 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
2323 GdkWaylandToplevel *wayland_toplevel;
2324
2325 g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE);
2326 wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
2327
2328 if (!display_wayland->idle_inhibit_manager)
2329 return FALSE;
2330
2331 if (!wayland_toplevel->idle_inhibitor)
2332 {
2333 g_assert (wayland_toplevel->idle_inhibitor_refcount == 0);
2334
2335 wayland_toplevel->idle_inhibitor =
2336 zwp_idle_inhibit_manager_v1_create_inhibitor (display_wayland->idle_inhibit_manager,
2337 gdk_wayland_surface_get_wl_surface (GDK_SURFACE (wayland_toplevel)));
2338 }
2339 ++wayland_toplevel->idle_inhibitor_refcount;
2340
2341 return TRUE;
2342}
2343
2344void
2345gdk_wayland_toplevel_uninhibit_idle (GdkToplevel *toplevel)
2346{
2347 GdkWaylandToplevel *wayland_toplevel;
2348
2349 g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
2350 wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
2351
2352 g_assert (wayland_toplevel->idle_inhibitor &&
2353 wayland_toplevel->idle_inhibitor_refcount > 0);
2354
2355 if (--wayland_toplevel->idle_inhibitor_refcount == 0)
2356 {
2357 g_clear_pointer (&wayland_toplevel->idle_inhibitor,
2358 zwp_idle_inhibitor_v1_destroy);
2359 }
2360}
2361
2362static void
2363calculate_popup_rect (GdkSurface *surface,
2364 GdkPopupLayout *layout,
2365 GdkRectangle *out_rect)
2366{
2367 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
2368 int width, height;
2369 GdkRectangle anchor_rect;
2370 int dx, dy;
2371 int shadow_left, shadow_right, shadow_top, shadow_bottom;
2372 int x = 0, y = 0;
2373
2374 gdk_popup_layout_get_shadow_width (layout,
2375 left: &shadow_left,
2376 right: &shadow_right,
2377 top: &shadow_top,
2378 bottom: &shadow_bottom);
2379
2380 width = (impl->popup.unconstrained_width - (shadow_left + shadow_right));
2381 height = (impl->popup.unconstrained_height - (shadow_top + shadow_bottom));
2382
2383 anchor_rect = *gdk_popup_layout_get_anchor_rect (layout);
2384 gdk_popup_layout_get_offset (layout, dx: &dx, dy: &dy);
2385 anchor_rect.x += dx;
2386 anchor_rect.y += dy;
2387
2388 switch (gdk_popup_layout_get_rect_anchor (layout))
2389 {
2390 default:
2391 case GDK_GRAVITY_STATIC:
2392 case GDK_GRAVITY_NORTH_WEST:
2393 x = anchor_rect.x;
2394 y = anchor_rect.y;
2395 break;
2396 case GDK_GRAVITY_NORTH:
2397 x = anchor_rect.x + (anchor_rect.width / 2);
2398 y = anchor_rect.y;
2399 break;
2400 case GDK_GRAVITY_NORTH_EAST:
2401 x = anchor_rect.x + anchor_rect.width;
2402 y = anchor_rect.y;
2403 break;
2404 case GDK_GRAVITY_WEST:
2405 x = anchor_rect.x;
2406 y = anchor_rect.y + (anchor_rect.height / 2);
2407 break;
2408 case GDK_GRAVITY_CENTER:
2409 x = anchor_rect.x + (anchor_rect.width / 2);
2410 y = anchor_rect.y + (anchor_rect.height / 2);
2411 break;
2412 case GDK_GRAVITY_EAST:
2413 x = anchor_rect.x + anchor_rect.width;
2414 y = anchor_rect.y + (anchor_rect.height / 2);
2415 break;
2416 case GDK_GRAVITY_SOUTH_WEST:
2417 x = anchor_rect.x;
2418 y = anchor_rect.y + anchor_rect.height;
2419 break;
2420 case GDK_GRAVITY_SOUTH:
2421 x = anchor_rect.x + (anchor_rect.width / 2);
2422 y = anchor_rect.y + anchor_rect.height;
2423 break;
2424 case GDK_GRAVITY_SOUTH_EAST:
2425 x = anchor_rect.x + anchor_rect.width;
2426 y = anchor_rect.y + anchor_rect.height;
2427 break;
2428 }
2429
2430 switch (gdk_popup_layout_get_surface_anchor (layout))
2431 {
2432 default:
2433 case GDK_GRAVITY_STATIC:
2434 case GDK_GRAVITY_NORTH_WEST:
2435 break;
2436 case GDK_GRAVITY_NORTH:
2437 x -= width / 2;
2438 break;
2439 case GDK_GRAVITY_NORTH_EAST:
2440 x -= width;
2441 break;
2442 case GDK_GRAVITY_WEST:
2443 y -= height / 2;
2444 break;
2445 case GDK_GRAVITY_CENTER:
2446 x -= width / 2;
2447 y -= height / 2;
2448 break;
2449 case GDK_GRAVITY_EAST:
2450 x -= width;
2451 y -= height / 2;
2452 break;
2453 case GDK_GRAVITY_SOUTH_WEST:
2454 y -= height;
2455 break;
2456 case GDK_GRAVITY_SOUTH:
2457 x -= width / 2;
2458 y -= height;
2459 break;
2460 case GDK_GRAVITY_SOUTH_EAST:
2461 x -= width;
2462 y -= height;
2463 break;
2464 }
2465
2466 *out_rect = (GdkRectangle) {
2467 .x = x,
2468 .y = y,
2469 .width = width,
2470 .height = height
2471 };
2472}
2473
2474static void
2475update_popup_layout_state (GdkSurface *surface,
2476 int x,
2477 int y,
2478 int width,
2479 int height,
2480 GdkPopupLayout *layout)
2481{
2482 GdkRectangle best_rect;
2483 GdkRectangle flipped_rect;
2484 GdkGravity rect_anchor;
2485 GdkGravity surface_anchor;
2486 GdkAnchorHints anchor_hints;
2487
2488 rect_anchor = gdk_popup_layout_get_rect_anchor (layout);
2489 surface_anchor = gdk_popup_layout_get_surface_anchor (layout);
2490 anchor_hints = gdk_popup_layout_get_anchor_hints (layout);
2491
2492 calculate_popup_rect (surface, layout, out_rect: &best_rect);
2493
2494 flipped_rect = best_rect;
2495
2496 if (x != best_rect.x &&
2497 anchor_hints & GDK_ANCHOR_FLIP_X)
2498 {
2499 GdkRectangle flipped_x_rect;
2500 GdkGravity flipped_rect_anchor;
2501 GdkGravity flipped_surface_anchor;
2502 GdkPopupLayout *flipped_layout;
2503
2504 flipped_rect_anchor = gdk_gravity_flip_horizontally (anchor: rect_anchor);
2505 flipped_surface_anchor = gdk_gravity_flip_horizontally (anchor: surface_anchor);
2506 flipped_layout = gdk_popup_layout_copy (layout);
2507 gdk_popup_layout_set_rect_anchor (layout: flipped_layout,
2508 anchor: flipped_rect_anchor);
2509 gdk_popup_layout_set_surface_anchor (layout: flipped_layout,
2510 anchor: flipped_surface_anchor);
2511 calculate_popup_rect (surface,
2512 layout: flipped_layout,
2513 out_rect: &flipped_x_rect);
2514 gdk_popup_layout_unref (layout: flipped_layout);
2515
2516 if (flipped_x_rect.x == x)
2517 flipped_rect.x = x;
2518 }
2519 if (y != best_rect.y &&
2520 anchor_hints & GDK_ANCHOR_FLIP_Y)
2521 {
2522 GdkRectangle flipped_y_rect;
2523 GdkGravity flipped_rect_anchor;
2524 GdkGravity flipped_surface_anchor;
2525 GdkPopupLayout *flipped_layout;
2526
2527 flipped_rect_anchor = gdk_gravity_flip_vertically (anchor: rect_anchor);
2528 flipped_surface_anchor = gdk_gravity_flip_vertically (anchor: surface_anchor);
2529 flipped_layout = gdk_popup_layout_copy (layout);
2530 gdk_popup_layout_set_rect_anchor (layout: flipped_layout,
2531 anchor: flipped_rect_anchor);
2532 gdk_popup_layout_set_surface_anchor (layout: flipped_layout,
2533 anchor: flipped_surface_anchor);
2534 calculate_popup_rect (surface,
2535 layout: flipped_layout,
2536 out_rect: &flipped_y_rect);
2537 gdk_popup_layout_unref (layout: flipped_layout);
2538
2539 if (flipped_y_rect.y == y)
2540 flipped_rect.y = y;
2541 }
2542
2543 if (flipped_rect.x != best_rect.x)
2544 {
2545 rect_anchor = gdk_gravity_flip_horizontally (anchor: rect_anchor);
2546 surface_anchor = gdk_gravity_flip_horizontally (anchor: surface_anchor);
2547 }
2548 if (flipped_rect.y != best_rect.y)
2549 {
2550 rect_anchor = gdk_gravity_flip_vertically (anchor: rect_anchor);
2551 surface_anchor = gdk_gravity_flip_vertically (anchor: surface_anchor);
2552 }
2553
2554 surface->popup.rect_anchor = rect_anchor;
2555 surface->popup.surface_anchor = surface_anchor;
2556}
2557
2558static gpointer
2559create_dynamic_positioner (GdkSurface *surface,
2560 int width,
2561 int height,
2562 GdkPopupLayout *layout,
2563 gboolean ack_parent_configure)
2564{
2565 GdkSurface *parent = surface->parent;
2566 GdkWaylandSurface *parent_impl = GDK_WAYLAND_SURFACE (parent);
2567 GdkWaylandDisplay *display =
2568 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
2569 GdkRectangle geometry;
2570 uint32_t constraint_adjustment = ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE;
2571 const GdkRectangle *anchor_rect;
2572 int real_anchor_rect_x, real_anchor_rect_y;
2573 int anchor_rect_width, anchor_rect_height;
2574 int rect_anchor_dx;
2575 int rect_anchor_dy;
2576 GdkGravity rect_anchor;
2577 GdkGravity surface_anchor;
2578 GdkAnchorHints anchor_hints;
2579 GdkRectangle parent_geometry;
2580 int shadow_left;
2581 int shadow_right;
2582 int shadow_top;
2583 int shadow_bottom;
2584
2585 gdk_popup_layout_get_shadow_width (layout,
2586 left: &shadow_left,
2587 right: &shadow_right,
2588 top: &shadow_top,
2589 bottom: &shadow_bottom);
2590 geometry = (GdkRectangle) {
2591 .x = shadow_left,
2592 .y = shadow_top,
2593 .width = width - (shadow_left + shadow_right),
2594 .height = height - (shadow_top + shadow_bottom),
2595 };
2596
2597 gdk_wayland_surface_get_window_geometry (surface: surface->parent, geometry: &parent_geometry);
2598
2599 anchor_rect = gdk_popup_layout_get_anchor_rect (layout);
2600 real_anchor_rect_x = anchor_rect->x - parent_geometry.x;
2601 real_anchor_rect_y = anchor_rect->y - parent_geometry.y;
2602
2603 anchor_rect_width = MAX (anchor_rect->width, 1);
2604 anchor_rect_height = MAX (anchor_rect->height, 1);
2605
2606 gdk_popup_layout_get_offset (layout, dx: &rect_anchor_dx, dy: &rect_anchor_dy);
2607
2608 rect_anchor = gdk_popup_layout_get_rect_anchor (layout);
2609 surface_anchor = gdk_popup_layout_get_surface_anchor (layout);
2610
2611 anchor_hints = gdk_popup_layout_get_anchor_hints (layout);
2612
2613 switch (display->shell_variant)
2614 {
2615 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
2616 {
2617 struct xdg_positioner *positioner;
2618 enum xdg_positioner_anchor anchor;
2619 enum xdg_positioner_gravity gravity;
2620
2621 positioner = xdg_wm_base_create_positioner (display->xdg_wm_base);
2622
2623 xdg_positioner_set_size (positioner, geometry.width, geometry.height);
2624 xdg_positioner_set_anchor_rect (positioner,
2625 real_anchor_rect_x,
2626 real_anchor_rect_y,
2627 anchor_rect_width,
2628 anchor_rect_height);
2629 xdg_positioner_set_offset (positioner, rect_anchor_dx, rect_anchor_dy);
2630
2631 anchor = rect_anchor_to_anchor (rect_anchor);
2632 xdg_positioner_set_anchor (positioner, anchor);
2633
2634 gravity = surface_anchor_to_gravity (surface_anchor);
2635 xdg_positioner_set_gravity (positioner, gravity);
2636
2637 if (anchor_hints & GDK_ANCHOR_FLIP_X)
2638 constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X;
2639 if (anchor_hints & GDK_ANCHOR_FLIP_Y)
2640 constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y;
2641 if (anchor_hints & GDK_ANCHOR_SLIDE_X)
2642 constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X;
2643 if (anchor_hints & GDK_ANCHOR_SLIDE_Y)
2644 constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
2645 if (anchor_hints & GDK_ANCHOR_RESIZE_X)
2646 constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X;
2647 if (anchor_hints & GDK_ANCHOR_RESIZE_Y)
2648 constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
2649 xdg_positioner_set_constraint_adjustment (positioner,
2650 constraint_adjustment);
2651
2652 if (xdg_positioner_get_version (positioner) >=
2653 XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION)
2654 xdg_positioner_set_reactive (positioner);
2655
2656 if (ack_parent_configure &&
2657 xdg_positioner_get_version (positioner) >=
2658 XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION)
2659 {
2660 xdg_positioner_set_parent_size (positioner,
2661 parent_geometry.width,
2662 parent_geometry.height);
2663 xdg_positioner_set_parent_configure (positioner,
2664 parent_impl->last_configure_serial);
2665 }
2666
2667 return positioner;
2668 }
2669 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
2670 {
2671 struct zxdg_positioner_v6 *positioner;
2672 enum zxdg_positioner_v6_anchor anchor;
2673 enum zxdg_positioner_v6_gravity gravity;
2674
2675 positioner = zxdg_shell_v6_create_positioner (display->zxdg_shell_v6);
2676
2677 zxdg_positioner_v6_set_size (positioner, geometry.width, geometry.height);
2678 zxdg_positioner_v6_set_anchor_rect (positioner,
2679 real_anchor_rect_x,
2680 real_anchor_rect_y,
2681 anchor_rect_width,
2682 anchor_rect_height);
2683 zxdg_positioner_v6_set_offset (positioner,
2684 rect_anchor_dx,
2685 rect_anchor_dy);
2686
2687 anchor = rect_anchor_to_anchor_legacy (rect_anchor);
2688 zxdg_positioner_v6_set_anchor (positioner, anchor);
2689
2690 gravity = surface_anchor_to_gravity_legacy (surface_anchor);
2691 zxdg_positioner_v6_set_gravity (positioner, gravity);
2692
2693 if (anchor_hints & GDK_ANCHOR_FLIP_X)
2694 constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X;
2695 if (anchor_hints & GDK_ANCHOR_FLIP_Y)
2696 constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y;
2697 if (anchor_hints & GDK_ANCHOR_SLIDE_X)
2698 constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X;
2699 if (anchor_hints & GDK_ANCHOR_SLIDE_Y)
2700 constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
2701 if (anchor_hints & GDK_ANCHOR_RESIZE_X)
2702 constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X;
2703 if (anchor_hints & GDK_ANCHOR_RESIZE_Y)
2704 constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
2705 zxdg_positioner_v6_set_constraint_adjustment (positioner,
2706 constraint_adjustment);
2707
2708 return positioner;
2709 }
2710 default:
2711 g_assert_not_reached ();
2712 }
2713
2714 g_assert_not_reached ();
2715}
2716
2717static gboolean
2718can_map_grabbing_popup (GdkSurface *surface,
2719 GdkSurface *parent)
2720{
2721 GdkDisplay *display = gdk_surface_get_display (surface);
2722 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
2723 GdkSurface *top_most_popup;
2724
2725 if (!display_wayland->current_grabbing_popups)
2726 return TRUE;
2727
2728 top_most_popup = g_list_first (list: display_wayland->current_grabbing_popups)->data;
2729 return top_most_popup == parent;
2730}
2731
2732static gboolean
2733gdk_wayland_surface_create_xdg_popup (GdkSurface *surface,
2734 GdkSurface *parent,
2735 GdkWaylandSeat *grab_input_seat,
2736 int width,
2737 int height,
2738 GdkPopupLayout *layout)
2739{
2740 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
2741 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
2742 GdkWaylandSurface *parent_impl = GDK_WAYLAND_SURFACE (parent);
2743 gpointer positioner;
2744
2745 if (!impl->display_server.wl_surface)
2746 return FALSE;
2747
2748 if (!is_realized_shell_surface (impl: parent_impl))
2749 return FALSE;
2750
2751 if (is_realized_toplevel (impl))
2752 {
2753 g_warning ("Can't map popup, already mapped as toplevel");
2754 return FALSE;
2755 }
2756 if (is_realized_popup (impl))
2757 {
2758 g_warning ("Can't map popup, already mapped");
2759 return FALSE;
2760 }
2761
2762 if (grab_input_seat &&
2763 !can_map_grabbing_popup (surface, parent))
2764 {
2765 g_warning ("Tried to map a grabbing popup with a non-top most parent");
2766 return FALSE;
2767 }
2768
2769 gdk_surface_freeze_updates (surface);
2770
2771 positioner = create_dynamic_positioner (surface, width, height, layout, FALSE);
2772 gdk_wayland_surface_create_xdg_surface_resources (surface);
2773
2774 switch (display->shell_variant)
2775 {
2776 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
2777 impl->display_server.xdg_popup =
2778 xdg_surface_get_popup (impl->display_server.xdg_surface,
2779 parent_impl->display_server.xdg_surface,
2780 positioner);
2781 xdg_popup_add_listener (impl->display_server.xdg_popup,
2782 &xdg_popup_listener,
2783 surface);
2784 xdg_positioner_destroy (positioner);
2785 break;
2786 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
2787 impl->display_server.zxdg_popup_v6 =
2788 zxdg_surface_v6_get_popup (impl->display_server.zxdg_surface_v6,
2789 parent_impl->display_server.zxdg_surface_v6,
2790 positioner);
2791 zxdg_popup_v6_add_listener (impl->display_server.zxdg_popup_v6,
2792 &zxdg_popup_v6_listener,
2793 surface);
2794 zxdg_positioner_v6_destroy (positioner);
2795 break;
2796 default:
2797 g_assert_not_reached ();
2798 }
2799
2800 gdk_popup_layout_get_shadow_width (layout,
2801 left: &impl->shadow_left,
2802 right: &impl->shadow_right,
2803 top: &impl->shadow_top,
2804 bottom: &impl->shadow_bottom);
2805
2806 if (grab_input_seat)
2807 {
2808 struct wl_seat *seat;
2809 guint32 serial;
2810
2811 seat = gdk_wayland_seat_get_wl_seat (GDK_SEAT (grab_input_seat));
2812 serial = _gdk_wayland_seat_get_last_implicit_grab_serial (seat: grab_input_seat, NULL);
2813
2814 switch (display->shell_variant)
2815 {
2816 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
2817 xdg_popup_grab (impl->display_server.xdg_popup, seat, serial);
2818 break;
2819 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
2820 zxdg_popup_v6_grab (impl->display_server.zxdg_popup_v6, seat, serial);
2821 break;
2822 default:
2823 g_assert_not_reached ();
2824 }
2825 }
2826
2827 gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "wayland", "surface commit");
2828 wl_surface_commit (wl_surface: impl->display_server.wl_surface);
2829
2830 if (GDK_IS_POPUP (ptr: surface))
2831 {
2832 g_assert (impl->popup_state == POPUP_STATE_IDLE);
2833 impl->popup_state = POPUP_STATE_WAITING_FOR_CONFIGURE;
2834 freeze_popup_toplevel_state (surface);
2835 }
2836
2837 display->current_popups = g_list_append (list: display->current_popups, data: surface);
2838 if (grab_input_seat)
2839 {
2840 display->current_grabbing_popups =
2841 g_list_prepend (list: display->current_grabbing_popups, data: surface);
2842 }
2843
2844 return TRUE;
2845}
2846
2847static GdkWaylandSeat *
2848find_grab_input_seat (GdkSurface *surface,
2849 GdkSurface *parent)
2850{
2851 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
2852 GdkWaylandSurface *tmp_impl;
2853
2854 /* Use the device that was used for the grab as the device for
2855 * the popup surface setup - so this relies on GTK taking the
2856 * grab before showing the popup surface.
2857 */
2858 if (impl->grab_input_seat)
2859 return GDK_WAYLAND_SEAT (impl->grab_input_seat);
2860
2861 while (parent)
2862 {
2863 tmp_impl = GDK_WAYLAND_SURFACE (parent);
2864
2865 if (tmp_impl->grab_input_seat)
2866 return GDK_WAYLAND_SEAT (tmp_impl->grab_input_seat);
2867
2868 parent = parent->parent;
2869 }
2870
2871 return NULL;
2872}
2873
2874static void
2875gdk_wayland_surface_map_toplevel (GdkSurface *surface)
2876{
2877 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
2878
2879 if (!GDK_IS_WAYLAND_TOPLEVEL (surface))
2880 return;
2881
2882 if (impl->mapped)
2883 return;
2884
2885 gdk_wayland_surface_create_xdg_toplevel (surface);
2886
2887 impl->mapped = TRUE;
2888}
2889
2890static void
2891gdk_wayland_surface_show (GdkSurface *surface)
2892{
2893 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
2894
2895 if (!impl->display_server.wl_surface)
2896 gdk_wayland_surface_create_surface (surface);
2897
2898 gdk_wayland_surface_map_toplevel (surface);
2899}
2900
2901static void
2902unmap_popups_for_surface (GdkSurface *surface)
2903{
2904 GdkWaylandDisplay *display_wayland;
2905 GList *l;
2906
2907 display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
2908 for (l = display_wayland->current_popups; l; l = l->next)
2909 {
2910 GdkSurface *popup = l->data;
2911
2912 if (popup->parent == surface)
2913 {
2914 g_warning ("Tried to unmap the parent of a popup");
2915 gdk_surface_hide (surface: popup);
2916
2917 return;
2918 }
2919 }
2920}
2921
2922static void
2923gdk_wayland_surface_hide_surface (GdkSurface *surface)
2924{
2925 GdkDisplay *display = gdk_surface_get_display (surface);
2926 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
2927 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
2928
2929 unmap_popups_for_surface (surface);
2930
2931 if (impl->display_server.wl_surface)
2932 {
2933 if (impl->display_server.egl_window)
2934 {
2935 gdk_surface_set_egl_native_window (self: surface, NULL);
2936 wl_egl_window_destroy (egl_window: impl->display_server.egl_window);
2937 impl->display_server.egl_window = NULL;
2938 }
2939
2940 if (impl->display_server.xdg_toplevel)
2941 {
2942 xdg_toplevel_destroy (impl->display_server.xdg_toplevel);
2943 impl->display_server.xdg_toplevel = NULL;
2944 }
2945 else if (impl->display_server.xdg_popup)
2946 {
2947 xdg_popup_destroy (impl->display_server.xdg_popup);
2948 impl->display_server.xdg_popup = NULL;
2949 display_wayland->current_popups =
2950 g_list_remove (list: display_wayland->current_popups, data: surface);
2951 display_wayland->current_grabbing_popups =
2952 g_list_remove (list: display_wayland->current_grabbing_popups, data: surface);
2953 }
2954 if (impl->display_server.xdg_surface)
2955 {
2956 xdg_surface_destroy (impl->display_server.xdg_surface);
2957 impl->display_server.xdg_surface = NULL;
2958 if (!impl->initial_configure_received)
2959 gdk_surface_thaw_updates (surface);
2960 else
2961 impl->initial_configure_received = FALSE;
2962 }
2963
2964 if (impl->display_server.zxdg_toplevel_v6)
2965 {
2966 zxdg_toplevel_v6_destroy (impl->display_server.zxdg_toplevel_v6);
2967 impl->display_server.zxdg_toplevel_v6 = NULL;
2968 }
2969 else if (impl->display_server.zxdg_popup_v6)
2970 {
2971 zxdg_popup_v6_destroy (impl->display_server.zxdg_popup_v6);
2972 impl->display_server.zxdg_popup_v6 = NULL;
2973 display_wayland->current_popups =
2974 g_list_remove (list: display_wayland->current_popups, data: surface);
2975 display_wayland->current_grabbing_popups =
2976 g_list_remove (list: display_wayland->current_grabbing_popups, data: surface);
2977 }
2978 if (impl->display_server.zxdg_surface_v6)
2979 {
2980 zxdg_surface_v6_destroy (impl->display_server.zxdg_surface_v6);
2981 impl->display_server.zxdg_surface_v6 = NULL;
2982 if (!impl->initial_configure_received)
2983 gdk_surface_thaw_updates (surface);
2984 else
2985 impl->initial_configure_received = FALSE;
2986 }
2987
2988 impl->awaiting_frame = FALSE;
2989 if (impl->awaiting_frame_frozen)
2990 {
2991 impl->awaiting_frame_frozen = FALSE;
2992 gdk_surface_thaw_updates (surface);
2993 }
2994
2995 if (GDK_IS_POPUP (ptr: surface))
2996 {
2997 impl->popup_thaw_upon_show = TRUE;
2998 gdk_surface_freeze_updates (surface);
2999
3000 switch (impl->popup_state)
3001 {
3002 case POPUP_STATE_WAITING_FOR_REPOSITIONED:
3003 gdk_surface_thaw_updates (surface);
3004 G_GNUC_FALLTHROUGH;
3005 case POPUP_STATE_WAITING_FOR_CONFIGURE:
3006 case POPUP_STATE_WAITING_FOR_FRAME:
3007 thaw_popup_toplevel_state (surface);
3008 break;
3009 case POPUP_STATE_IDLE:
3010 break;
3011 default:
3012 g_assert_not_reached ();
3013 }
3014
3015 impl->popup_state = POPUP_STATE_IDLE;
3016 }
3017
3018 if (impl->display_server.gtk_surface)
3019 {
3020 if (display_wayland->gtk_shell_version >=
3021 GTK_SURFACE1_RELEASE_SINCE_VERSION)
3022 gtk_surface1_release (impl->display_server.gtk_surface);
3023 else
3024 gtk_surface1_destroy (impl->display_server.gtk_surface);
3025 impl->display_server.gtk_surface = NULL;
3026 impl->application.was_set = FALSE;
3027 }
3028
3029 wl_surface_destroy (wl_surface: impl->display_server.wl_surface);
3030 impl->display_server.wl_surface = NULL;
3031
3032 g_slist_free (list: impl->display_server.outputs);
3033 impl->display_server.outputs = NULL;
3034
3035 g_clear_pointer (&impl->toplevel.layout, gdk_toplevel_layout_unref);
3036 g_clear_pointer (&impl->popup.layout, gdk_popup_layout_unref);
3037 }
3038
3039 impl->has_uncommitted_ack_configure = FALSE;
3040 impl->input_region_dirty = TRUE;
3041 impl->opaque_region_dirty = TRUE;
3042
3043 unset_transient_for_exported (surface);
3044
3045 impl->last_sent_window_geometry = (GdkRectangle) { 0 };
3046 impl->last_sent_min_width = 0;
3047 impl->last_sent_min_height = 0;
3048 impl->last_sent_max_width = 0;
3049 impl->last_sent_max_height = 0;
3050
3051 _gdk_wayland_surface_clear_saved_size (surface);
3052 impl->mapped = FALSE;
3053}
3054
3055static void
3056gdk_wayland_surface_hide (GdkSurface *surface)
3057{
3058 GdkSeat *seat;
3059
3060 seat = gdk_display_get_default_seat (display: surface->display);
3061 if (seat)
3062 {
3063 if (surface->autohide)
3064 gdk_seat_ungrab (seat);
3065
3066 gdk_wayland_seat_clear_touchpoints (GDK_WAYLAND_SEAT (seat), surface);
3067 }
3068 gdk_wayland_surface_hide_surface (surface);
3069 _gdk_surface_clear_update_area (surface);
3070}
3071
3072static void
3073gdk_wayland_surface_move_resize (GdkSurface *surface,
3074 int x,
3075 int y,
3076 int width,
3077 int height)
3078{
3079 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3080
3081 surface->x = x;
3082 surface->y = y;
3083 gdk_wayland_surface_maybe_resize (surface, width, height, scale: impl->scale);
3084}
3085
3086static gboolean
3087is_fallback_relayout_possible (GdkSurface *surface)
3088{
3089 GList *l;
3090
3091 for (l = surface->children; l; l = l->next)
3092 {
3093 GdkSurface *child = l->data;
3094
3095 if (GDK_WAYLAND_SURFACE (child)->mapped)
3096 return FALSE;
3097 }
3098
3099 return TRUE;
3100}
3101
3102static gboolean gdk_wayland_surface_present_popup (GdkSurface *surface,
3103 int width,
3104 int height,
3105 GdkPopupLayout *layout);
3106
3107static void
3108queue_relayout_fallback (GdkSurface *surface,
3109 GdkPopupLayout *layout)
3110{
3111 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3112
3113 if (!is_fallback_relayout_possible (surface))
3114 return;
3115
3116 gdk_wayland_surface_hide_surface (surface);
3117 gdk_wayland_surface_present_popup (surface,
3118 width: impl->popup.unconstrained_width,
3119 height: impl->popup.unconstrained_height,
3120 layout);
3121}
3122
3123static void
3124do_queue_relayout (GdkSurface *surface,
3125 int width,
3126 int height,
3127 GdkPopupLayout *layout)
3128{
3129 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3130 struct xdg_positioner *positioner;
3131
3132 g_assert (is_realized_popup (impl));
3133 g_assert (impl->popup_state == POPUP_STATE_IDLE ||
3134 impl->popup_state == POPUP_STATE_WAITING_FOR_FRAME);
3135
3136 g_clear_pointer (&impl->popup.layout, gdk_popup_layout_unref);
3137 impl->popup.layout = gdk_popup_layout_copy (layout);
3138 impl->popup.unconstrained_width = width;
3139 impl->popup.unconstrained_height = height;
3140
3141 if (!impl->display_server.xdg_popup ||
3142 xdg_popup_get_version (impl->display_server.xdg_popup) <
3143 XDG_POPUP_REPOSITION_SINCE_VERSION)
3144 {
3145 g_warning_once ("Compositor doesn't support moving popups, "
3146 "relying on remapping");
3147 queue_relayout_fallback (surface, layout);
3148
3149 return;
3150 }
3151
3152 positioner = create_dynamic_positioner (surface,
3153 width, height, layout,
3154 TRUE);
3155 xdg_popup_reposition (impl->display_server.xdg_popup,
3156 positioner,
3157 ++impl->reposition_token);
3158 xdg_positioner_destroy (positioner);
3159
3160 gdk_surface_freeze_updates (surface);
3161
3162 switch (impl->popup_state)
3163 {
3164 case POPUP_STATE_IDLE:
3165 freeze_popup_toplevel_state (surface);
3166 break;
3167 case POPUP_STATE_WAITING_FOR_FRAME:
3168 break;
3169 case POPUP_STATE_WAITING_FOR_CONFIGURE:
3170 case POPUP_STATE_WAITING_FOR_REPOSITIONED:
3171 default:
3172 g_assert_not_reached ();
3173 }
3174
3175 impl->popup_state = POPUP_STATE_WAITING_FOR_REPOSITIONED;
3176}
3177
3178static gboolean
3179is_relayout_finished (GdkSurface *surface)
3180{
3181 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3182
3183 if (!impl->initial_configure_received)
3184 return FALSE;
3185
3186 if (impl->reposition_token != impl->received_reposition_token)
3187 return FALSE;
3188
3189 return TRUE;
3190}
3191
3192static void
3193gdk_wayland_surface_map_popup (GdkSurface *surface,
3194 int width,
3195 int height,
3196 GdkPopupLayout *layout)
3197{
3198 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3199 GdkSurface *parent;
3200 GdkWaylandSeat *grab_input_seat;
3201
3202 parent = surface->parent;
3203 if (!parent)
3204 {
3205 g_warning ("Couldn't map as surface %p as popup because it doesn't have a parent",
3206 surface);
3207 return;
3208 }
3209
3210 if (surface->autohide)
3211 grab_input_seat = find_grab_input_seat (surface, parent);
3212 else
3213 grab_input_seat = NULL;
3214
3215 if (!gdk_wayland_surface_create_xdg_popup (surface,
3216 parent,
3217 grab_input_seat,
3218 width, height,
3219 layout))
3220 return;
3221
3222 impl->popup.layout = gdk_popup_layout_copy (layout);
3223 impl->popup.unconstrained_width = width;
3224 impl->popup.unconstrained_height = height;
3225 impl->mapped = TRUE;
3226}
3227
3228static void
3229show_popup (GdkSurface *surface,
3230 int width,
3231 int height,
3232 GdkPopupLayout *layout)
3233{
3234 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3235
3236 if (!impl->display_server.wl_surface)
3237 gdk_wayland_surface_create_surface (surface);
3238
3239 if (impl->popup_thaw_upon_show)
3240 {
3241 impl->popup_thaw_upon_show = FALSE;
3242 gdk_surface_thaw_updates (surface);
3243 }
3244
3245 gdk_wayland_surface_map_popup (surface, width, height, layout);
3246}
3247
3248typedef struct
3249{
3250 int width;
3251 int height;
3252 GdkPopupLayout *layout;
3253} GrabPrepareData;
3254
3255static void
3256show_grabbing_popup (GdkSeat *seat,
3257 GdkSurface *surface,
3258 gpointer user_data)
3259{
3260 GrabPrepareData *data = user_data;
3261
3262 show_popup (surface, width: data->width, height: data->height, layout: data->layout);
3263}
3264
3265static void
3266reposition_popup (GdkSurface *surface,
3267 int width,
3268 int height,
3269 GdkPopupLayout *layout)
3270{
3271 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3272
3273 switch (impl->popup_state)
3274 {
3275 case POPUP_STATE_IDLE:
3276 case POPUP_STATE_WAITING_FOR_FRAME:
3277 do_queue_relayout (surface, width, height, layout);
3278 break;
3279 case POPUP_STATE_WAITING_FOR_REPOSITIONED:
3280 case POPUP_STATE_WAITING_FOR_CONFIGURE:
3281 g_warn_if_reached ();
3282 break;
3283 default:
3284 g_assert_not_reached ();
3285 }
3286}
3287
3288static gboolean
3289gdk_wayland_surface_present_popup (GdkSurface *surface,
3290 int width,
3291 int height,
3292 GdkPopupLayout *layout)
3293{
3294 GdkWaylandDisplay *display_wayland =
3295 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
3296 GdkWaylandSurface *impl;
3297
3298 impl = GDK_WAYLAND_SURFACE (surface);
3299
3300 if (!impl->mapped)
3301 {
3302 if (surface->autohide)
3303 {
3304 GdkSeat *seat;
3305
3306 seat = gdk_display_get_default_seat (display: surface->display);
3307 if (seat)
3308 {
3309 GrabPrepareData data;
3310 GdkGrabStatus result;
3311
3312 data = (GrabPrepareData) {
3313 .width = width,
3314 .height = height,
3315 .layout = layout,
3316 };
3317
3318 result = gdk_seat_grab (seat,
3319 surface,
3320 capabilities: GDK_SEAT_CAPABILITY_ALL,
3321 TRUE,
3322 NULL, NULL,
3323 prepare_func: show_grabbing_popup, prepare_func_data: &data);
3324 if (result != GDK_GRAB_SUCCESS)
3325 {
3326 const char *grab_status[] = {
3327 "success", "already grabbed", "invalid time",
3328 "not viewable", "frozen", "failed"
3329 };
3330 g_warning ("Grab failed: %s", grab_status[result]);
3331 }
3332 }
3333 }
3334 else
3335 {
3336 show_popup (surface, width, height, layout);
3337 }
3338 }
3339 else
3340 {
3341 if (impl->popup.unconstrained_width == width &&
3342 impl->popup.unconstrained_height == height &&
3343 gdk_popup_layout_equal (layout: impl->popup.layout, other: layout))
3344 return TRUE;
3345
3346 reposition_popup (surface, width, height, layout);
3347 }
3348
3349 while (impl->display_server.xdg_popup && !is_relayout_finished (surface))
3350 wl_display_dispatch_queue (display: display_wayland->wl_display, queue: impl->event_queue);
3351
3352 if (impl->display_server.xdg_popup)
3353 {
3354 gdk_surface_invalidate_rect (surface, NULL);
3355 return TRUE;
3356 }
3357 else
3358 {
3359 return FALSE;
3360 }
3361}
3362
3363static void
3364gdk_wayland_surface_get_geometry (GdkSurface *surface,
3365 int *x,
3366 int *y,
3367 int *width,
3368 int *height)
3369{
3370 if (!GDK_SURFACE_DESTROYED (surface))
3371 {
3372 if (x)
3373 *x = surface->x;
3374 if (y)
3375 *y = surface->y;
3376 if (width)
3377 *width = surface->width;
3378 if (height)
3379 *height = surface->height;
3380 }
3381}
3382
3383static void
3384gdk_wayland_surface_get_root_coords (GdkSurface *surface,
3385 int x,
3386 int y,
3387 int *root_x,
3388 int *root_y)
3389{
3390 /*
3391 * Wayland does not have a global coordinate space shared between surfaces. In
3392 * fact, for regular toplevels, we have no idea where our surfaces are
3393 * positioned, relatively.
3394 *
3395 * However, there are some cases like popups and subsurfaces where we do have
3396 * some amount of control over the placement of our surface, and we can
3397 * semi-accurately control the x/y position of these surfaces, if they are
3398 * relative to another surface.
3399 *
3400 * To pretend we have something called a root coordinate space, assume all
3401 * parent-less surfaces are positioned in (0, 0), and all relative positioned
3402 * popups and subsurfaces are placed within this fake root coordinate space.
3403 *
3404 * For example a 200x200 large toplevel surface will have the position (0, 0).
3405 * If a popup positioned in the middle of the toplevel will have the fake
3406 * position (100,100). Furthermore, if a positioned is placed in the middle
3407 * that popup, will have the fake position (150,150), even though it has the
3408 * relative position (50,50). These three surfaces would make up one single
3409 * fake root coordinate space.
3410 */
3411
3412 if (root_x)
3413 *root_x = surface->x + x;
3414
3415 if (root_y)
3416 *root_y = surface->y + y;
3417}
3418
3419static gboolean
3420gdk_wayland_surface_get_device_state (GdkSurface *surface,
3421 GdkDevice *device,
3422 double *x,
3423 double *y,
3424 GdkModifierType *mask)
3425{
3426 if (GDK_SURFACE_DESTROYED (surface))
3427 return FALSE;
3428
3429 gdk_wayland_device_query_state (device, surface, win_x: x, win_y: y, mask);
3430
3431 return *x >= 0 && *y >= 0 && *x < surface->width && *y < surface->height;
3432}
3433
3434static void
3435gdk_wayland_surface_set_input_region (GdkSurface *surface,
3436 cairo_region_t *input_region)
3437{
3438 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3439
3440 if (GDK_SURFACE_DESTROYED (surface))
3441 return;
3442
3443 g_clear_pointer (&impl->input_region, cairo_region_destroy);
3444
3445 if (input_region)
3446 impl->input_region = cairo_region_copy (original: input_region);
3447
3448 impl->input_region_dirty = TRUE;
3449}
3450
3451static void
3452gdk_wayland_surface_destroy (GdkSurface *surface,
3453 gboolean foreign_destroy)
3454{
3455 GdkWaylandDisplay *display;
3456 GdkFrameClock *frame_clock;
3457
3458 g_return_if_fail (GDK_IS_SURFACE (surface));
3459
3460 /* Wayland surfaces can't be externally destroyed; we may possibly
3461 * eventually want to use this path at display close-down
3462 */
3463 g_return_if_fail (!foreign_destroy);
3464
3465 gdk_wayland_surface_hide_surface (surface);
3466
3467 frame_clock = gdk_surface_get_frame_clock (surface);
3468 g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_before_paint, surface);
3469 g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_after_paint, surface);
3470
3471 display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
3472 display->toplevels = g_list_remove (list: display->toplevels, data: surface);
3473}
3474
3475static void
3476token_done (gpointer data,
3477 struct xdg_activation_token_v1 *provider,
3478 const char *token)
3479{
3480 char **token_out = data;
3481
3482 *token_out = g_strdup (str: token);
3483}
3484
3485static const struct xdg_activation_token_v1_listener token_listener = {
3486 token_done,
3487};
3488
3489static void
3490gdk_wayland_surface_focus (GdkSurface *surface,
3491 guint32 timestamp)
3492{
3493 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3494 GdkDisplay *display = gdk_surface_get_display (surface);
3495 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
3496 gchar *startup_id = NULL;
3497
3498 startup_id = g_steal_pointer (&display_wayland->startup_notification_id);
3499
3500 if (display_wayland->xdg_activation)
3501 {
3502 GdkWaylandSeat *seat =
3503 GDK_WAYLAND_SEAT (gdk_display_get_default_seat (display));
3504
3505 /* If the focus request does not have a startup ID associated, get a
3506 * new token to activate the window.
3507 */
3508 if (!startup_id)
3509 {
3510 struct xdg_activation_token_v1 *token;
3511 struct wl_event_queue *event_queue;
3512
3513 event_queue = wl_display_create_queue (display: display_wayland->wl_display);
3514
3515 token = xdg_activation_v1_get_activation_token (display_wayland->xdg_activation);
3516 wl_proxy_set_queue (proxy: (struct wl_proxy *) token, queue: event_queue);
3517
3518 xdg_activation_token_v1_add_listener (token,
3519 &token_listener,
3520 &startup_id);
3521 xdg_activation_token_v1_set_serial (token,
3522 _gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL),
3523 gdk_wayland_seat_get_wl_seat (GDK_SEAT (seat)));
3524 xdg_activation_token_v1_set_surface (token,
3525 gdk_wayland_surface_get_wl_surface (surface));
3526 xdg_activation_token_v1_commit (token);
3527
3528 while (startup_id == NULL)
3529 wl_display_dispatch_queue (display: display_wayland->wl_display, queue: event_queue);
3530
3531 xdg_activation_token_v1_destroy (token);
3532 wl_event_queue_destroy (queue: event_queue);
3533 }
3534
3535 xdg_activation_v1_activate (display_wayland->xdg_activation,
3536 startup_id,
3537 impl->display_server.wl_surface);
3538 }
3539 else if (impl->display_server.gtk_surface)
3540 {
3541 if (timestamp != GDK_CURRENT_TIME)
3542 gtk_surface1_present (impl->display_server.gtk_surface, timestamp);
3543 else if (startup_id && display_wayland->gtk_shell_version >= 3)
3544 gtk_surface1_request_focus (impl->display_server.gtk_surface,
3545 startup_id);
3546 }
3547
3548 g_free (mem: startup_id);
3549}
3550
3551static void
3552gtk_surface_configure (void *data,
3553 struct gtk_surface1 *gtk_surface,
3554 struct wl_array *states)
3555{
3556 GdkSurface *surface = GDK_SURFACE (data);
3557 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3558 GdkToplevelState new_state = 0;
3559 uint32_t *p;
3560
3561 wl_array_for_each (p, states)
3562 {
3563 uint32_t state = *p;
3564
3565 switch (state)
3566 {
3567 case GTK_SURFACE1_STATE_TILED:
3568 new_state |= GDK_TOPLEVEL_STATE_TILED;
3569 break;
3570
3571 /* Since v2 */
3572 case GTK_SURFACE1_STATE_TILED_TOP:
3573 new_state |= (GDK_TOPLEVEL_STATE_TILED | GDK_TOPLEVEL_STATE_TOP_TILED);
3574 break;
3575 case GTK_SURFACE1_STATE_TILED_RIGHT:
3576 new_state |= (GDK_TOPLEVEL_STATE_TILED | GDK_TOPLEVEL_STATE_RIGHT_TILED);
3577 break;
3578 case GTK_SURFACE1_STATE_TILED_BOTTOM:
3579 new_state |= (GDK_TOPLEVEL_STATE_TILED | GDK_TOPLEVEL_STATE_BOTTOM_TILED);
3580 break;
3581 case GTK_SURFACE1_STATE_TILED_LEFT:
3582 new_state |= (GDK_TOPLEVEL_STATE_TILED | GDK_TOPLEVEL_STATE_LEFT_TILED);
3583 break;
3584 default:
3585 /* Unknown state */
3586 break;
3587 }
3588 }
3589
3590 impl->pending.toplevel.state |= new_state;
3591}
3592
3593static void
3594gtk_surface_configure_edges (void *data,
3595 struct gtk_surface1 *gtk_surface,
3596 struct wl_array *edge_constraints)
3597{
3598 GdkSurface *surface = GDK_SURFACE (data);
3599 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3600 GdkToplevelState new_state = 0;
3601 uint32_t *p;
3602
3603 wl_array_for_each (p, edge_constraints)
3604 {
3605 uint32_t constraint = *p;
3606
3607 switch (constraint)
3608 {
3609 case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_TOP:
3610 new_state |= GDK_TOPLEVEL_STATE_TOP_RESIZABLE;
3611 break;
3612 case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_RIGHT:
3613 new_state |= GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE;
3614 break;
3615 case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_BOTTOM:
3616 new_state |= GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE;
3617 break;
3618 case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_LEFT:
3619 new_state |= GDK_TOPLEVEL_STATE_LEFT_RESIZABLE;
3620 break;
3621 default:
3622 /* Unknown state */
3623 break;
3624 }
3625 }
3626
3627 impl->pending.toplevel.state |= new_state;
3628}
3629
3630static const struct gtk_surface1_listener gtk_surface_listener = {
3631 gtk_surface_configure,
3632 gtk_surface_configure_edges
3633};
3634
3635static void
3636gdk_wayland_surface_init_gtk_surface (GdkWaylandSurface *impl)
3637{
3638 GdkWaylandDisplay *display =
3639 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (impl)));
3640
3641 if (impl->display_server.gtk_surface != NULL)
3642 return;
3643 if (!is_realized_toplevel (impl))
3644 return;
3645 if (display->gtk_shell == NULL)
3646 return;
3647
3648 impl->display_server.gtk_surface =
3649 gtk_shell1_get_gtk_surface (display->gtk_shell,
3650 impl->display_server.wl_surface);
3651 wl_proxy_set_queue (proxy: (struct wl_proxy *) impl->display_server.gtk_surface,
3652 queue: impl->event_queue);
3653 gdk_wayland_surface_set_geometry_hints (impl,
3654 geometry: &impl->geometry_hints,
3655 geom_mask: impl->geometry_mask);
3656 gtk_surface1_add_listener (impl->display_server.gtk_surface,
3657 &gtk_surface_listener,
3658 impl);
3659}
3660
3661static void
3662maybe_set_gtk_surface_modal (GdkSurface *surface)
3663{
3664 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3665
3666 gdk_wayland_surface_init_gtk_surface (impl);
3667 if (impl->display_server.gtk_surface == NULL)
3668 return;
3669
3670 if (surface->modal_hint)
3671 gtk_surface1_set_modal (impl->display_server.gtk_surface);
3672 else
3673 gtk_surface1_unset_modal (impl->display_server.gtk_surface);
3674
3675}
3676
3677static void
3678gdk_wayland_surface_set_modal_hint (GdkSurface *surface,
3679 gboolean modal)
3680{
3681 surface->modal_hint = modal;
3682 maybe_set_gtk_surface_modal (surface);
3683}
3684
3685static void
3686gdk_wayland_surface_set_geometry_hints (GdkWaylandSurface *impl,
3687 const GdkGeometry *geometry,
3688 GdkSurfaceHints geom_mask)
3689{
3690 GdkWaylandDisplay *display_wayland;
3691 int min_width, min_height;
3692 int max_width, max_height;
3693
3694 if (GDK_SURFACE_DESTROYED (impl) ||
3695 !SURFACE_IS_TOPLEVEL (impl))
3696 return;
3697
3698 display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (impl)));
3699
3700 impl->geometry_hints = *geometry;
3701 impl->geometry_mask = geom_mask;
3702
3703 if (!is_realized_toplevel (impl))
3704 return;
3705
3706 if (geom_mask & GDK_HINT_MIN_SIZE)
3707 {
3708 min_width = MAX (0, (geometry->min_width -
3709 (impl->shadow_left + impl->shadow_right)));
3710 min_height = MAX (0, (geometry->min_height -
3711 (impl->shadow_top + impl->shadow_bottom)));
3712 }
3713 else
3714 {
3715 min_width = 0;
3716 min_height = 0;
3717 }
3718
3719 if (geom_mask & GDK_HINT_MAX_SIZE)
3720 {
3721 max_width = MAX (0, (geometry->max_width -
3722 (impl->shadow_left + impl->shadow_right)));
3723 max_height = MAX (0, (geometry->max_height -
3724 (impl->shadow_top + impl->shadow_bottom)));
3725 }
3726 else
3727 {
3728 max_width = 0;
3729 max_height = 0;
3730 }
3731
3732 if (impl->last_sent_min_width == min_width &&
3733 impl->last_sent_min_height == min_height &&
3734 impl->last_sent_max_width == max_width &&
3735 impl->last_sent_max_height == max_height)
3736 return;
3737
3738 switch (display_wayland->shell_variant)
3739 {
3740 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
3741 xdg_toplevel_set_min_size (impl->display_server.xdg_toplevel,
3742 min_width, min_height);
3743 xdg_toplevel_set_max_size (impl->display_server.xdg_toplevel,
3744 max_width, max_height);
3745 break;
3746 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
3747 zxdg_toplevel_v6_set_min_size (impl->display_server.zxdg_toplevel_v6,
3748 min_width, min_height);
3749 zxdg_toplevel_v6_set_max_size (impl->display_server.zxdg_toplevel_v6,
3750 max_width, max_height);
3751 break;
3752 default:
3753 g_assert_not_reached ();
3754 }
3755
3756 impl->last_sent_min_width = min_width;
3757 impl->last_sent_min_height = min_height;
3758 impl->last_sent_max_width = max_width;
3759 impl->last_sent_max_height = max_height;
3760}
3761
3762static void
3763gdk_wayland_surface_set_title (GdkSurface *surface,
3764 const char *title)
3765{
3766 GdkWaylandSurface *impl;
3767 const char *end;
3768 gsize title_length;
3769
3770 g_return_if_fail (title != NULL);
3771
3772 if (GDK_SURFACE_DESTROYED (surface))
3773 return;
3774
3775 impl = GDK_WAYLAND_SURFACE (surface);
3776
3777 if (g_strcmp0 (str1: impl->title, str2: title) == 0)
3778 return;
3779
3780 g_free (mem: impl->title);
3781
3782 title_length = MIN (strlen (title), MAX_WL_BUFFER_SIZE);
3783 if (g_utf8_validate (str: title, max_len: title_length, end: &end))
3784 {
3785 impl->title = g_malloc (n_bytes: end - title + 1);
3786 memcpy (dest: impl->title, src: title, n: end - title);
3787 impl->title[end - title] = '\0';
3788 }
3789 else
3790 {
3791 impl->title = g_utf8_make_valid (str: title, len: title_length);
3792 g_warning ("Invalid utf8 passed to gdk_surface_set_title: '%s'", title);
3793 }
3794
3795 gdk_wayland_surface_sync_title (surface);
3796}
3797
3798static void
3799gdk_wayland_surface_set_startup_id (GdkSurface *surface,
3800 const char *startup_id)
3801{
3802}
3803
3804static gboolean
3805check_transient_for_loop (GdkWaylandToplevel *toplevel,
3806 GdkWaylandToplevel *parent)
3807{
3808 while (parent)
3809 {
3810 if (parent->transient_for == toplevel)
3811 return TRUE;
3812 parent = parent->transient_for;
3813 }
3814 return FALSE;
3815}
3816
3817static void
3818gdk_wayland_toplevel_set_transient_for (GdkWaylandToplevel *toplevel,
3819 GdkSurface *parent)
3820{
3821 g_return_if_fail (!parent || GDK_IS_WAYLAND_TOPLEVEL (parent));
3822 g_return_if_fail (!parent ||
3823 gdk_surface_get_display (GDK_SURFACE (toplevel)) == gdk_surface_get_display (parent));
3824
3825 if (parent)
3826 {
3827 GdkWaylandToplevel *parent_toplevel = GDK_WAYLAND_TOPLEVEL (parent);
3828
3829 if (check_transient_for_loop (toplevel, parent: parent_toplevel))
3830 {
3831 g_warning ("Setting %p transient for %p would create a loop",
3832 toplevel, parent);
3833 return;
3834 }
3835 }
3836
3837 unset_transient_for_exported (GDK_SURFACE (toplevel));
3838
3839 if (parent)
3840 toplevel->transient_for = GDK_WAYLAND_TOPLEVEL (parent);
3841 else
3842 toplevel->transient_for = NULL;
3843
3844 gdk_wayland_surface_sync_parent (GDK_SURFACE (toplevel), NULL);
3845}
3846
3847static void
3848gdk_wayland_surface_minimize (GdkSurface *surface)
3849{
3850 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3851 GdkWaylandDisplay *display_wayland;
3852
3853 if (GDK_SURFACE_DESTROYED (surface) ||
3854 !SURFACE_IS_TOPLEVEL (surface))
3855 return;
3856
3857 if (!is_realized_toplevel (GDK_WAYLAND_SURFACE (surface)))
3858 return;
3859
3860 /* FIXME: xdg_toplevel does not come with a minimized state that we can
3861 * query or get notified of. This means we cannot implement the full
3862 * GdkSurface API, and our state will not reflect minimization.
3863 */
3864 display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
3865 switch (display_wayland->shell_variant)
3866 {
3867 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
3868 xdg_toplevel_set_minimized (impl->display_server.xdg_toplevel);
3869 break;
3870 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
3871 zxdg_toplevel_v6_set_minimized (impl->display_server.zxdg_toplevel_v6);
3872 break;
3873 default:
3874 g_assert_not_reached ();
3875 }
3876}
3877
3878static void
3879gdk_wayland_surface_maximize (GdkSurface *surface)
3880{
3881 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3882
3883 if (GDK_SURFACE_DESTROYED (surface))
3884 return;
3885
3886 _gdk_wayland_surface_save_size (surface);
3887
3888 if (is_realized_toplevel (impl))
3889 {
3890 GdkWaylandDisplay *display_wayland =
3891 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
3892
3893 switch (display_wayland->shell_variant)
3894 {
3895 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
3896 xdg_toplevel_set_maximized (impl->display_server.xdg_toplevel);
3897 break;
3898 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
3899 zxdg_toplevel_v6_set_maximized (impl->display_server.zxdg_toplevel_v6);
3900 break;
3901 default:
3902 g_assert_not_reached ();
3903 }
3904 }
3905 else
3906 {
3907 synthesize_initial_surface_state (surface, unset_flags: 0, set_flags: GDK_TOPLEVEL_STATE_MAXIMIZED);
3908 }
3909}
3910
3911static void
3912gdk_wayland_surface_unmaximize (GdkSurface *surface)
3913{
3914 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3915
3916 if (GDK_SURFACE_DESTROYED (surface))
3917 return;
3918
3919 if (is_realized_toplevel (impl))
3920 {
3921 GdkWaylandDisplay *display_wayland =
3922 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
3923
3924 switch (display_wayland->shell_variant)
3925 {
3926 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
3927 xdg_toplevel_unset_maximized (impl->display_server.xdg_toplevel);
3928 break;
3929 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
3930 zxdg_toplevel_v6_unset_maximized (impl->display_server.zxdg_toplevel_v6);
3931 break;
3932 default:
3933 g_assert_not_reached ();
3934 }
3935 }
3936 else
3937 {
3938 synthesize_initial_surface_state (surface, unset_flags: GDK_TOPLEVEL_STATE_MAXIMIZED, set_flags: 0);
3939 }
3940}
3941
3942static void
3943gdk_wayland_surface_fullscreen_on_monitor (GdkSurface *surface,
3944 GdkMonitor *monitor)
3945{
3946 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3947 struct wl_output *output = ((GdkWaylandMonitor *)monitor)->output;
3948
3949 if (GDK_SURFACE_DESTROYED (surface))
3950 return;
3951
3952 _gdk_wayland_surface_save_size (surface);
3953
3954 if (is_realized_toplevel (impl))
3955 {
3956 GdkWaylandDisplay *display_wayland =
3957 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
3958
3959 switch (display_wayland->shell_variant)
3960 {
3961 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
3962 xdg_toplevel_set_fullscreen (impl->display_server.xdg_toplevel,
3963 output);
3964 break;
3965 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
3966 zxdg_toplevel_v6_set_fullscreen (impl->display_server.zxdg_toplevel_v6,
3967 output);
3968 break;
3969 default:
3970 g_assert_not_reached ();
3971 }
3972 }
3973 else
3974 {
3975 synthesize_initial_surface_state (surface, unset_flags: 0, set_flags: GDK_TOPLEVEL_STATE_FULLSCREEN);
3976 impl->initial_fullscreen_output = output;
3977 }
3978}
3979
3980static void
3981gdk_wayland_surface_fullscreen (GdkSurface *surface)
3982{
3983 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
3984
3985 if (GDK_SURFACE_DESTROYED (surface))
3986 return;
3987
3988 impl->initial_fullscreen_output = NULL;
3989
3990 _gdk_wayland_surface_save_size (surface);
3991
3992 if (is_realized_toplevel (impl))
3993 {
3994 GdkWaylandDisplay *display_wayland =
3995 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
3996
3997 switch (display_wayland->shell_variant)
3998 {
3999 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4000 xdg_toplevel_set_fullscreen (impl->display_server.xdg_toplevel,
4001 NULL);
4002 break;
4003 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4004 zxdg_toplevel_v6_set_fullscreen (impl->display_server.zxdg_toplevel_v6,
4005 NULL);
4006 break;
4007 default:
4008 g_assert_not_reached ();
4009 }
4010 }
4011 else
4012 {
4013 synthesize_initial_surface_state (surface, unset_flags: 0, set_flags: GDK_TOPLEVEL_STATE_FULLSCREEN);
4014 }
4015}
4016
4017static void
4018gdk_wayland_surface_unfullscreen (GdkSurface *surface)
4019{
4020 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
4021
4022 if (GDK_SURFACE_DESTROYED (surface))
4023 return;
4024
4025 impl->initial_fullscreen_output = NULL;
4026
4027 if (is_realized_toplevel (impl))
4028 {
4029 GdkWaylandDisplay *display_wayland =
4030 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
4031
4032 switch (display_wayland->shell_variant)
4033 {
4034 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4035 xdg_toplevel_unset_fullscreen (impl->display_server.xdg_toplevel);
4036 break;
4037 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4038 zxdg_toplevel_v6_unset_fullscreen (impl->display_server.zxdg_toplevel_v6);
4039 break;
4040 default:
4041 g_assert_not_reached ();
4042 }
4043 }
4044 else
4045 {
4046 synthesize_initial_surface_state (surface, unset_flags: GDK_TOPLEVEL_STATE_FULLSCREEN, set_flags: 0);
4047 }
4048}
4049
4050static void
4051gdk_wayland_toplevel_begin_resize (GdkToplevel *toplevel,
4052 GdkSurfaceEdge edge,
4053 GdkDevice *device,
4054 int button,
4055 double x,
4056 double y,
4057 guint32 timestamp)
4058{
4059 GdkSurface *surface = GDK_SURFACE (toplevel);
4060 GdkWaylandSurface *impl;
4061 GdkWaylandDisplay *display_wayland;
4062 GdkEventSequence *sequence;
4063 uint32_t resize_edges, serial;
4064
4065 if (GDK_SURFACE_DESTROYED (surface) ||
4066 !SURFACE_IS_TOPLEVEL (surface))
4067 return;
4068
4069 switch (edge)
4070 {
4071 case GDK_SURFACE_EDGE_NORTH_WEST:
4072 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT;
4073 break;
4074
4075 case GDK_SURFACE_EDGE_NORTH:
4076 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP;
4077 break;
4078
4079 case GDK_SURFACE_EDGE_NORTH_EAST:
4080 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT;
4081 break;
4082
4083 case GDK_SURFACE_EDGE_WEST:
4084 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT;
4085 break;
4086
4087 case GDK_SURFACE_EDGE_EAST:
4088 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT;
4089 break;
4090
4091 case GDK_SURFACE_EDGE_SOUTH_WEST:
4092 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT;
4093 break;
4094
4095 case GDK_SURFACE_EDGE_SOUTH:
4096 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM;
4097 break;
4098
4099 case GDK_SURFACE_EDGE_SOUTH_EAST:
4100 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT;
4101 break;
4102
4103 default:
4104 g_warning ("gdk_toplevel_begin_resize: bad resize edge %d!", edge);
4105 return;
4106 }
4107
4108 impl = GDK_WAYLAND_SURFACE (surface);
4109 display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
4110
4111 if (!is_realized_toplevel (impl))
4112 return;
4113
4114 serial = _gdk_wayland_seat_get_last_implicit_grab_serial (GDK_WAYLAND_SEAT (gdk_device_get_seat (device)),
4115 sequence: &sequence);
4116
4117 switch (display_wayland->shell_variant)
4118 {
4119 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4120 xdg_toplevel_resize (impl->display_server.xdg_toplevel,
4121 gdk_wayland_device_get_wl_seat (device),
4122 serial, resize_edges);
4123 break;
4124 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4125 zxdg_toplevel_v6_resize (impl->display_server.zxdg_toplevel_v6,
4126 gdk_wayland_device_get_wl_seat (device),
4127 serial, resize_edges);
4128 break;
4129 default:
4130 g_assert_not_reached ();
4131 }
4132
4133 if (sequence)
4134 gdk_wayland_device_unset_touch_grab (device, sequence);
4135}
4136
4137static void
4138gdk_wayland_toplevel_begin_move (GdkToplevel *toplevel,
4139 GdkDevice *device,
4140 int button,
4141 double x,
4142 double y,
4143 guint32 timestamp)
4144{
4145 GdkSurface *surface = GDK_SURFACE (toplevel);
4146 GdkWaylandSurface *impl;
4147 GdkWaylandDisplay *display_wayland;
4148 GdkEventSequence *sequence;
4149 uint32_t serial;
4150
4151 if (GDK_SURFACE_DESTROYED (surface) ||
4152 !SURFACE_IS_TOPLEVEL (surface))
4153 return;
4154
4155 impl = GDK_WAYLAND_SURFACE (surface);
4156 display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
4157
4158 if (!is_realized_toplevel (impl))
4159 return;
4160
4161 serial = _gdk_wayland_seat_get_last_implicit_grab_serial (GDK_WAYLAND_SEAT (gdk_device_get_seat (device)),
4162 sequence: &sequence);
4163 switch (display_wayland->shell_variant)
4164 {
4165 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4166 xdg_toplevel_move (impl->display_server.xdg_toplevel,
4167 gdk_wayland_device_get_wl_seat (device),
4168 serial);
4169 break;
4170 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4171 zxdg_toplevel_v6_move (impl->display_server.zxdg_toplevel_v6,
4172 gdk_wayland_device_get_wl_seat (device),
4173 serial);
4174 break;
4175 default:
4176 g_assert_not_reached ();
4177 }
4178
4179 if (sequence)
4180 gdk_wayland_device_unset_touch_grab (device, sequence);
4181}
4182
4183static void
4184gdk_wayland_surface_destroy_notify (GdkSurface *surface)
4185{
4186 if (!GDK_SURFACE_DESTROYED (surface))
4187 {
4188 g_warning ("GdkSurface %p unexpectedly destroyed", surface);
4189 _gdk_surface_destroy (surface, TRUE);
4190 }
4191
4192 g_object_unref (object: surface);
4193}
4194
4195static int
4196gdk_wayland_surface_get_scale_factor (GdkSurface *surface)
4197{
4198 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
4199
4200 if (GDK_SURFACE_DESTROYED (surface))
4201 return 1;
4202
4203 return impl->scale;
4204}
4205
4206static void
4207gdk_wayland_surface_set_opaque_region (GdkSurface *surface,
4208 cairo_region_t *region)
4209{
4210 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
4211
4212 if (GDK_SURFACE_DESTROYED (surface))
4213 return;
4214
4215 g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
4216 impl->opaque_region = cairo_region_reference (region);
4217 impl->opaque_region_dirty = TRUE;
4218}
4219
4220static gboolean
4221gdk_wayland_surface_show_window_menu (GdkSurface *surface,
4222 GdkEvent *event)
4223{
4224 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
4225 GdkWaylandDisplay *display_wayland =
4226 GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
4227 GdkSeat *seat;
4228 struct wl_seat *wl_seat;
4229 double x, y;
4230 uint32_t serial;
4231
4232 GdkEventType event_type = gdk_event_get_event_type (event);
4233 switch ((guint) event_type)
4234 {
4235 case GDK_BUTTON_PRESS:
4236 case GDK_BUTTON_RELEASE:
4237 case GDK_TOUCH_BEGIN:
4238 case GDK_TOUCH_END:
4239 break;
4240 default:
4241 return FALSE;
4242 }
4243
4244 if (!is_realized_toplevel (impl))
4245 return FALSE;
4246
4247 seat = gdk_event_get_seat (event);
4248 wl_seat = gdk_wayland_seat_get_wl_seat (seat);
4249 gdk_event_get_position (event, x: &x, y: &y);
4250
4251 serial = _gdk_wayland_seat_get_implicit_grab_serial (seat, event);
4252
4253 switch (display_wayland->shell_variant)
4254 {
4255 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4256 xdg_toplevel_show_window_menu (impl->display_server.xdg_toplevel,
4257 wl_seat, serial, x, y);
4258 break;
4259 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4260 zxdg_toplevel_v6_show_window_menu (impl->display_server.zxdg_toplevel_v6,
4261 wl_seat, serial, x, y);
4262 break;
4263 default:
4264 g_assert_not_reached ();
4265 }
4266
4267 return TRUE;
4268}
4269
4270static gboolean
4271translate_gesture (GdkTitlebarGesture gesture,
4272 enum gtk_surface1_gesture *out_gesture)
4273{
4274 switch (gesture)
4275 {
4276 case GDK_TITLEBAR_GESTURE_DOUBLE_CLICK:
4277 *out_gesture = GTK_SURFACE1_GESTURE_DOUBLE_CLICK;
4278 break;
4279
4280 case GDK_TITLEBAR_GESTURE_RIGHT_CLICK:
4281 *out_gesture = GTK_SURFACE1_GESTURE_RIGHT_CLICK;
4282 break;
4283
4284 case GDK_TITLEBAR_GESTURE_MIDDLE_CLICK:
4285 *out_gesture = GTK_SURFACE1_GESTURE_MIDDLE_CLICK;
4286 break;
4287
4288 default:
4289 g_warning ("Not handling unknown titlebar gesture %u", gesture);
4290 return FALSE;
4291 }
4292
4293 return TRUE;
4294}
4295
4296static gboolean
4297gdk_wayland_surface_titlebar_gesture (GdkSurface *surface,
4298 GdkTitlebarGesture gesture)
4299{
4300 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
4301 struct gtk_surface1 *gtk_surface = impl->display_server.gtk_surface;
4302 enum gtk_surface1_gesture gtk_gesture;
4303 GdkSeat *seat;
4304 struct wl_seat *wl_seat;
4305 uint32_t serial;
4306
4307 if (!gtk_surface)
4308 return FALSE;
4309
4310 if (gtk_surface1_get_version (gtk_surface) < GTK_SURFACE1_TITLEBAR_GESTURE_SINCE_VERSION)
4311 return FALSE;
4312
4313 if (!translate_gesture (gesture, out_gesture: &gtk_gesture))
4314 return FALSE;
4315
4316 seat = gdk_display_get_default_seat (display: surface->display);
4317 wl_seat = gdk_wayland_seat_get_wl_seat (seat);
4318
4319 serial = _gdk_wayland_seat_get_last_implicit_grab_serial (GDK_WAYLAND_SEAT (seat), NULL);
4320
4321 gtk_surface1_titlebar_gesture (impl->display_server.gtk_surface,
4322 serial,
4323 wl_seat,
4324 gtk_gesture);
4325
4326 return TRUE;
4327}
4328
4329static gboolean
4330gdk_wayland_surface_supports_edge_constraints (GdkSurface *surface)
4331{
4332 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
4333 struct gtk_surface1 *gtk_surface = impl->display_server.gtk_surface;
4334
4335 if (!gtk_surface)
4336 return FALSE;
4337
4338 return gtk_surface1_get_version (gtk_surface) >= GTK_SURFACE1_CONFIGURE_EDGES_SINCE_VERSION;
4339}
4340
4341static void
4342gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *klass)
4343{
4344 GObjectClass *object_class = G_OBJECT_CLASS (klass);
4345 GdkSurfaceClass *impl_class = GDK_SURFACE_CLASS (klass);
4346
4347 object_class->constructed = gdk_wayland_surface_constructed;
4348 object_class->dispose = gdk_wayland_surface_dispose;
4349 object_class->finalize = gdk_wayland_surface_finalize;
4350
4351 impl_class->hide = gdk_wayland_surface_hide;
4352 impl_class->get_geometry = gdk_wayland_surface_get_geometry;
4353 impl_class->get_root_coords = gdk_wayland_surface_get_root_coords;
4354 impl_class->get_device_state = gdk_wayland_surface_get_device_state;
4355 impl_class->set_input_region = gdk_wayland_surface_set_input_region;
4356 impl_class->destroy = gdk_wayland_surface_destroy;
4357 impl_class->beep = gdk_wayland_surface_beep;
4358
4359 impl_class->destroy_notify = gdk_wayland_surface_destroy_notify;
4360 impl_class->drag_begin = _gdk_wayland_surface_drag_begin;
4361 impl_class->get_scale_factor = gdk_wayland_surface_get_scale_factor;
4362 impl_class->set_opaque_region = gdk_wayland_surface_set_opaque_region;
4363 impl_class->request_layout = gdk_wayland_surface_request_layout;
4364 impl_class->compute_size = gdk_wayland_surface_compute_size;
4365}
4366
4367void
4368_gdk_wayland_surface_set_grab_seat (GdkSurface *surface,
4369 GdkSeat *seat)
4370{
4371 GdkWaylandSurface *impl;
4372
4373 g_return_if_fail (surface != NULL);
4374
4375 impl = GDK_WAYLAND_SURFACE (surface);
4376 impl->grab_input_seat = seat;
4377}
4378
4379/**
4380 * gdk_wayland_surface_get_wl_surface: (skip)
4381 * @surface: (type GdkWaylandSurface): a `GdkSurface`
4382 *
4383 * Returns the Wayland `wl_surface` of a `GdkSurface`.
4384 *
4385 * Returns: (transfer none): a Wayland `wl_surface`
4386 */
4387struct wl_surface *
4388gdk_wayland_surface_get_wl_surface (GdkSurface *surface)
4389{
4390 g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL);
4391
4392 return GDK_WAYLAND_SURFACE (surface)->display_server.wl_surface;
4393}
4394
4395struct wl_output *
4396gdk_wayland_surface_get_wl_output (GdkSurface *surface)
4397{
4398 GdkWaylandSurface *impl;
4399
4400 g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL);
4401
4402 impl = GDK_WAYLAND_SURFACE (surface);
4403 /* We pick the head of the list as this is the last entered output */
4404 if (impl->display_server.outputs)
4405 return (struct wl_output *) impl->display_server.outputs->data;
4406
4407 return NULL;
4408}
4409
4410void
4411gdk_wayland_surface_ensure_wl_egl_window (GdkSurface *surface)
4412{
4413 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
4414
4415 if (impl->display_server.egl_window == NULL)
4416 {
4417 impl->display_server.egl_window =
4418 wl_egl_window_create (surface: impl->display_server.wl_surface,
4419 width: surface->width * impl->scale,
4420 height: surface->height * impl->scale);
4421 wl_surface_set_buffer_scale (wl_surface: impl->display_server.wl_surface, scale: impl->scale);
4422
4423 gdk_surface_set_egl_native_window (self: surface, native_window: impl->display_server.egl_window);
4424 }
4425}
4426
4427struct gtk_surface1 *
4428gdk_wayland_surface_get_gtk_surface (GdkSurface *surface)
4429{
4430 g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL);
4431
4432 return GDK_WAYLAND_SURFACE (surface)->display_server.gtk_surface;
4433}
4434
4435static void
4436maybe_set_gtk_surface_dbus_properties (GdkWaylandSurface *impl)
4437{
4438 if (impl->application.was_set)
4439 return;
4440
4441 if (impl->application.application_id == NULL &&
4442 impl->application.app_menu_path == NULL &&
4443 impl->application.menubar_path == NULL &&
4444 impl->application.window_object_path == NULL &&
4445 impl->application.application_object_path == NULL &&
4446 impl->application.unique_bus_name == NULL)
4447 return;
4448
4449 gdk_wayland_surface_init_gtk_surface (impl);
4450 if (impl->display_server.gtk_surface == NULL)
4451 return;
4452
4453 gtk_surface1_set_dbus_properties (impl->display_server.gtk_surface,
4454 impl->application.application_id,
4455 impl->application.app_menu_path,
4456 impl->application.menubar_path,
4457 impl->application.window_object_path,
4458 impl->application.application_object_path,
4459 impl->application.unique_bus_name);
4460 impl->application.was_set = TRUE;
4461}
4462
4463void
4464gdk_wayland_toplevel_set_dbus_properties (GdkToplevel *toplevel,
4465 const char *application_id,
4466 const char *app_menu_path,
4467 const char *menubar_path,
4468 const char *window_object_path,
4469 const char *application_object_path,
4470 const char *unique_bus_name)
4471{
4472 GdkWaylandSurface *impl;
4473
4474 g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
4475
4476 impl = GDK_WAYLAND_SURFACE (toplevel);
4477
4478 impl->application.application_id = g_strdup (str: application_id);
4479 impl->application.app_menu_path = g_strdup (str: app_menu_path);
4480 impl->application.menubar_path = g_strdup (str: menubar_path);
4481 impl->application.window_object_path = g_strdup (str: window_object_path);
4482 impl->application.application_object_path =
4483 g_strdup (str: application_object_path);
4484 impl->application.unique_bus_name = g_strdup (str: unique_bus_name);
4485
4486 maybe_set_gtk_surface_dbus_properties (impl);
4487}
4488
4489void
4490_gdk_wayland_surface_offset_next_wl_buffer (GdkSurface *surface,
4491 int x,
4492 int y)
4493{
4494 GdkWaylandSurface *impl;
4495
4496 g_return_if_fail (GDK_IS_WAYLAND_SURFACE (surface));
4497
4498 impl = GDK_WAYLAND_SURFACE (surface);
4499
4500 impl->pending_buffer_offset_x = x;
4501 impl->pending_buffer_offset_y = y;
4502}
4503
4504static void
4505xdg_exported_handle (void *data,
4506 struct zxdg_exported_v1 *zxdg_exported_v1,
4507 const char *handle)
4508{
4509 GdkToplevel *toplevel = data;
4510 GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
4511
4512 wayland_toplevel->exported.callback (toplevel, handle, wayland_toplevel->exported.user_data);
4513 if (wayland_toplevel->exported.destroy_func)
4514 {
4515 g_clear_pointer (&wayland_toplevel->exported.user_data,
4516 wayland_toplevel->exported.destroy_func);
4517 }
4518}
4519
4520static const struct zxdg_exported_v1_listener xdg_exported_listener = {
4521 xdg_exported_handle
4522};
4523
4524/**
4525 * GdkWaylandToplevelExported:
4526 * @toplevel: (type GdkWaylandToplevel): the `GdkToplevel` that is exported
4527 * @handle: the handle
4528 * @user_data: user data that was passed to [method@GdkWayland.WaylandToplevel.export_handle]
4529 *
4530 * Callback that gets called when the handle for a surface has been
4531 * obtained from the Wayland compositor.
4532 *
4533 * This callback is used in [method@GdkWayland.WaylandToplevel.export_handle].
4534 *
4535 * The @handle can be passed to other processes, for the purpose of
4536 * marking surfaces as transient for out-of-process surfaces.
4537 */
4538
4539static gboolean
4540gdk_wayland_toplevel_is_exported (GdkWaylandToplevel *wayland_toplevel)
4541{
4542 return !!wayland_toplevel->xdg_exported;
4543}
4544
4545/**
4546 * gdk_wayland_toplevel_export_handle:
4547 * @toplevel: (type GdkWaylandToplevel): the `GdkToplevel` to obtain a handle for
4548 * @callback: callback to call with the handle
4549 * @user_data: (closure): user data for @callback
4550 * @destroy_func: destroy notify for @user_data
4551 *
4552 * Asynchronously obtains a handle for a surface that can be passed
4553 * to other processes.
4554 *
4555 * When the handle has been obtained, @callback will be called.
4556 *
4557 * It is an error to call this function on a surface that is already
4558 * exported.
4559 *
4560 * When the handle is no longer needed, [method@GdkWayland.WaylandToplevel.unexport_handle]
4561 * should be called to clean up resources.
4562 *
4563 * The main purpose for obtaining a handle is to mark a surface
4564 * from another surface as transient for this one, see
4565 * [method@GdkWayland.WaylandToplevel.set_transient_for_exported].
4566 *
4567 * Note that this API depends on an unstable Wayland protocol,
4568 * and thus may require changes in the future.
4569 *
4570 * Return value: %TRUE if the handle has been requested, %FALSE if
4571 * an error occurred.
4572 */
4573gboolean
4574gdk_wayland_toplevel_export_handle (GdkToplevel *toplevel,
4575 GdkWaylandToplevelExported callback,
4576 gpointer user_data,
4577 GDestroyNotify destroy_func)
4578{
4579 GdkWaylandToplevel *wayland_toplevel;
4580 GdkSurface *surface;
4581 GdkWaylandDisplay *display_wayland;
4582 GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel));
4583 struct zxdg_exported_v1 *xdg_exported;
4584
4585 g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE);
4586 g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
4587
4588 wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
4589 surface = GDK_SURFACE (toplevel);
4590 display_wayland = GDK_WAYLAND_DISPLAY (display);
4591
4592 g_return_val_if_fail (!wayland_toplevel->xdg_exported, FALSE);
4593
4594 if (!display_wayland->xdg_exporter)
4595 {
4596 g_warning ("Server is missing xdg_foreign support");
4597 return FALSE;
4598 }
4599
4600 xdg_exported =
4601 zxdg_exporter_v1_export (display_wayland->xdg_exporter,
4602 gdk_wayland_surface_get_wl_surface (surface));
4603 zxdg_exported_v1_add_listener (xdg_exported, &xdg_exported_listener,
4604 wayland_toplevel);
4605
4606 wayland_toplevel->xdg_exported = xdg_exported;
4607 wayland_toplevel->exported.callback = callback;
4608 wayland_toplevel->exported.user_data = user_data;
4609 wayland_toplevel->exported.destroy_func = destroy_func;
4610
4611 return TRUE;
4612}
4613
4614/**
4615 * gdk_wayland_toplevel_unexport_handle:
4616 * @toplevel: (type GdkWaylandToplevel): the `GdkToplevel` to unexport
4617 *
4618 * Destroys the handle that was obtained with
4619 * gdk_wayland_toplevel_export_handle().
4620 *
4621 * It is an error to call this function on a surface that
4622 * does not have a handle.
4623 *
4624 * Note that this API depends on an unstable Wayland protocol,
4625 * and thus may require changes in the future.
4626 */
4627void
4628gdk_wayland_toplevel_unexport_handle (GdkToplevel *toplevel)
4629{
4630 GdkWaylandToplevel *wayland_toplevel;
4631
4632 g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
4633
4634 wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
4635
4636 g_return_if_fail (wayland_toplevel->xdg_exported);
4637
4638 g_clear_pointer (&wayland_toplevel->xdg_exported,
4639 zxdg_exported_v1_destroy);
4640 if (wayland_toplevel->exported.destroy_func)
4641 {
4642 g_clear_pointer (&wayland_toplevel->exported.user_data,
4643 wayland_toplevel->exported.destroy_func);
4644 }
4645}
4646
4647static void
4648unset_transient_for_exported (GdkSurface *surface)
4649{
4650 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
4651
4652 g_clear_pointer (&impl->imported_transient_for, zxdg_imported_v1_destroy);
4653}
4654
4655static void
4656xdg_imported_destroyed (void *data,
4657 struct zxdg_imported_v1 *zxdg_imported_v1)
4658{
4659 GdkSurface *surface = data;
4660
4661 unset_transient_for_exported (surface);
4662}
4663
4664static const struct zxdg_imported_v1_listener xdg_imported_listener = {
4665 xdg_imported_destroyed,
4666};
4667
4668/**
4669 * gdk_wayland_toplevel_set_transient_for_exported:
4670 * @toplevel: (type GdkWaylandToplevel): the `GdkToplevel` to make as transient
4671 * @parent_handle_str: an exported handle for a surface
4672 *
4673 * Marks @toplevel as transient for the surface to which the given
4674 * @parent_handle_str refers.
4675 *
4676 * Typically, the handle will originate from a
4677 * [method@GdkWayland.WaylandToplevel.export_handle] call in another process.
4678 *
4679 * Note that this API depends on an unstable Wayland protocol,
4680 * and thus may require changes in the future.
4681 *
4682 * Return value: %TRUE if the surface has been marked as transient,
4683 * %FALSE if an error occurred.
4684 */
4685gboolean
4686gdk_wayland_toplevel_set_transient_for_exported (GdkToplevel *toplevel,
4687 const char *parent_handle_str)
4688{
4689 GdkWaylandSurface *impl;
4690 GdkWaylandDisplay *display_wayland;
4691 GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel));
4692
4693 g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE);
4694 g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
4695
4696 impl = GDK_WAYLAND_SURFACE (toplevel);
4697 display_wayland = GDK_WAYLAND_DISPLAY (display);
4698
4699 if (!display_wayland->xdg_importer)
4700 {
4701 g_warning ("Server is missing xdg_foreign support");
4702 return FALSE;
4703 }
4704
4705 gdk_wayland_toplevel_set_transient_for (GDK_WAYLAND_TOPLEVEL (impl), NULL);
4706
4707 impl->imported_transient_for =
4708 zxdg_importer_v1_import (display_wayland->xdg_importer, parent_handle_str);
4709 zxdg_imported_v1_add_listener (impl->imported_transient_for,
4710 &xdg_imported_listener,
4711 toplevel);
4712
4713 gdk_wayland_surface_sync_parent_of_imported (impl);
4714
4715 return TRUE;
4716}
4717
4718static struct zwp_keyboard_shortcuts_inhibitor_v1 *
4719gdk_wayland_surface_get_inhibitor (GdkWaylandSurface *impl,
4720 GdkSeat *gdk_seat)
4721{
4722 return g_hash_table_lookup (hash_table: impl->shortcuts_inhibitors, key: gdk_seat);
4723}
4724
4725/*
4726 * gdk_wayland_surface_inhibit_shortcuts:
4727 * @surface: (type GdkWaylandSurface): a `GdkSurface`
4728 * @seat: the seat to inhibit
4729 *
4730 * Inhibits the shortcuts coming from the given @seat.
4731 */
4732void
4733gdk_wayland_surface_inhibit_shortcuts (GdkSurface *surface,
4734 GdkSeat *gdk_seat)
4735{
4736 GdkWaylandSurface *impl= GDK_WAYLAND_SURFACE (surface);
4737 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
4738 struct wl_surface *wl_surface = impl->display_server.wl_surface;
4739 struct wl_seat *seat = gdk_wayland_seat_get_wl_seat (seat: gdk_seat);
4740 struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
4741
4742 if (display->keyboard_shortcuts_inhibit == NULL)
4743 return;
4744
4745 if (gdk_wayland_surface_get_inhibitor (impl, gdk_seat))
4746 return; /* Already inhibited */
4747
4748 inhibitor =
4749 zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts (
4750 display->keyboard_shortcuts_inhibit, wl_surface, seat);
4751
4752 g_hash_table_insert (hash_table: impl->shortcuts_inhibitors, key: gdk_seat, value: inhibitor);
4753}
4754
4755/*
4756 * gdk_wayland_surface_restore_shortcuts:
4757 * @surface: (type GdkWaylandSurface): a `GdkSurface`
4758 * @seat: the seat to inhibit
4759 *
4760 * Restores the shortcuts on the given @seat inhibited by calling
4761 * gdk_wayland_surface_inhibit_shortcuts().
4762 */
4763void
4764gdk_wayland_surface_restore_shortcuts (GdkSurface *surface,
4765 GdkSeat *gdk_seat)
4766{
4767 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
4768 struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
4769
4770 inhibitor = gdk_wayland_surface_get_inhibitor (impl, gdk_seat);
4771 if (inhibitor == NULL)
4772 return; /* Not inhibitted */
4773
4774 zwp_keyboard_shortcuts_inhibitor_v1_destroy (inhibitor);
4775 g_hash_table_remove (hash_table: impl->shortcuts_inhibitors, key: gdk_seat);
4776}
4777
4778GdkSurface *
4779create_dnd_surface (GdkDisplay *display)
4780{
4781 GdkSurface *surface;
4782
4783 surface = _gdk_wayland_display_create_surface (display,
4784 surface_type: GDK_SURFACE_TEMP,
4785 NULL,
4786 x: 0, y: 0, width: 100, height: 100);
4787
4788 return surface;
4789}
4790
4791#define LAST_PROP 1
4792
4793static void
4794gdk_wayland_popup_init (GdkWaylandPopup *popup)
4795{
4796}
4797
4798static void
4799gdk_wayland_popup_get_property (GObject *object,
4800 guint prop_id,
4801 GValue *value,
4802 GParamSpec *pspec)
4803{
4804 GdkSurface *surface = GDK_SURFACE (object);
4805
4806 switch (prop_id)
4807 {
4808 case LAST_PROP + GDK_POPUP_PROP_PARENT:
4809 g_value_set_object (value, v_object: surface->parent);
4810 break;
4811
4812 case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
4813 g_value_set_boolean (value, v_boolean: surface->autohide);
4814 break;
4815
4816 default:
4817 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4818 break;
4819 }
4820}
4821
4822static void
4823gdk_wayland_popup_set_property (GObject *object,
4824 guint prop_id,
4825 const GValue *value,
4826 GParamSpec *pspec)
4827{
4828 GdkSurface *surface = GDK_SURFACE (object);
4829
4830 switch (prop_id)
4831 {
4832 case LAST_PROP + GDK_POPUP_PROP_PARENT:
4833 surface->parent = g_value_dup_object (value);
4834 if (surface->parent != NULL)
4835 surface->parent->children = g_list_prepend (list: surface->parent->children, data: surface);
4836 break;
4837
4838 case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
4839 surface->autohide = g_value_get_boolean (value);
4840 break;
4841
4842 default:
4843 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4844 break;
4845 }
4846}
4847
4848static void
4849gdk_wayland_popup_class_init (GdkWaylandPopupClass *class)
4850{
4851 GObjectClass *object_class = G_OBJECT_CLASS (class);
4852
4853 object_class->get_property = gdk_wayland_popup_get_property;
4854 object_class->set_property = gdk_wayland_popup_set_property;
4855
4856 gdk_popup_install_properties (object_class, first_prop: 1);
4857}
4858
4859static gboolean
4860gdk_wayland_popup_present (GdkPopup *popup,
4861 int width,
4862 int height,
4863 GdkPopupLayout *layout)
4864{
4865 return gdk_wayland_surface_present_popup (GDK_SURFACE (popup), width, height, layout);
4866}
4867
4868static GdkGravity
4869gdk_wayland_popup_get_surface_anchor (GdkPopup *popup)
4870{
4871 return GDK_SURFACE (popup)->popup.surface_anchor;
4872}
4873
4874static GdkGravity
4875gdk_wayland_popup_get_rect_anchor (GdkPopup *popup)
4876{
4877 return GDK_SURFACE (popup)->popup.rect_anchor;
4878}
4879
4880static int
4881gdk_wayland_popup_get_position_x (GdkPopup *popup)
4882{
4883 return GDK_SURFACE (popup)->x;
4884}
4885
4886static int
4887gdk_wayland_popup_get_position_y (GdkPopup *popup)
4888{
4889 return GDK_SURFACE (popup)->y;
4890}
4891
4892static void
4893gdk_wayland_popup_iface_init (GdkPopupInterface *iface)
4894{
4895 iface->present = gdk_wayland_popup_present;
4896 iface->get_surface_anchor = gdk_wayland_popup_get_surface_anchor;
4897 iface->get_rect_anchor = gdk_wayland_popup_get_rect_anchor;
4898 iface->get_position_x = gdk_wayland_popup_get_position_x;
4899 iface->get_position_y = gdk_wayland_popup_get_position_y;
4900}
4901
4902static void
4903gdk_wayland_toplevel_init (GdkWaylandToplevel *toplevel)
4904{
4905}
4906
4907static void
4908gdk_wayland_toplevel_set_property (GObject *object,
4909 guint prop_id,
4910 const GValue *value,
4911 GParamSpec *pspec)
4912{
4913 GdkSurface *surface = GDK_SURFACE (object);
4914 GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
4915
4916 switch (prop_id)
4917 {
4918 case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
4919 gdk_wayland_surface_set_title (surface, title: g_value_get_string (value));
4920 g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4921 break;
4922
4923 case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
4924 gdk_wayland_surface_set_startup_id (surface, startup_id: g_value_get_string (value));
4925 g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4926 break;
4927
4928 case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
4929 gdk_wayland_toplevel_set_transient_for (toplevel,
4930 parent: g_value_get_object (value));
4931 g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4932 break;
4933
4934 case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
4935 gdk_wayland_surface_set_modal_hint (surface, modal: g_value_get_boolean (value));
4936 g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4937 break;
4938
4939 case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
4940 break;
4941
4942 case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
4943 break;
4944
4945 case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
4946 break;
4947
4948 case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
4949 surface->fullscreen_mode = g_value_get_enum (value);
4950 g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4951 break;
4952
4953 case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
4954 break;
4955
4956 default:
4957 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4958 break;
4959 }
4960}
4961
4962static void
4963gdk_wayland_toplevel_get_property (GObject *object,
4964 guint prop_id,
4965 GValue *value,
4966 GParamSpec *pspec)
4967{
4968 GdkSurface *surface = GDK_SURFACE (object);
4969 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
4970 GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
4971
4972 switch (prop_id)
4973 {
4974 case LAST_PROP + GDK_TOPLEVEL_PROP_STATE:
4975 g_value_set_flags (value, v_flags: surface->state);
4976 break;
4977
4978 case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
4979 g_value_set_string (value, v_string: impl->title);
4980 break;
4981
4982 case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
4983 g_value_set_string (value, v_string: "");
4984 break;
4985
4986 case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
4987 g_value_set_object (value, v_object: toplevel->transient_for);
4988 break;
4989
4990 case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
4991 g_value_set_boolean (value, v_boolean: surface->modal_hint);
4992 break;
4993
4994 case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
4995 g_value_set_pointer (value, NULL);
4996 break;
4997
4998 case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
4999 break;
5000
5001 case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
5002 break;
5003
5004 case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
5005 g_value_set_enum (value, v_enum: surface->fullscreen_mode);
5006 break;
5007
5008 case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
5009 g_value_set_boolean (value, v_boolean: surface->shortcuts_inhibited);
5010 break;
5011
5012 default:
5013 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5014 break;
5015 }
5016}
5017
5018static void
5019gdk_wayland_toplevel_finalize (GObject *object)
5020{
5021 GdkWaylandToplevel *wayland_toplevel;
5022
5023 g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (object));
5024
5025 wayland_toplevel = GDK_WAYLAND_TOPLEVEL (object);
5026
5027 if (gdk_wayland_toplevel_is_exported (wayland_toplevel))
5028 gdk_wayland_toplevel_unexport_handle (toplevel: GDK_TOPLEVEL (ptr: wayland_toplevel));
5029
5030 G_OBJECT_CLASS (gdk_wayland_toplevel_parent_class)->finalize (object);
5031}
5032
5033static void
5034gdk_wayland_toplevel_class_init (GdkWaylandToplevelClass *class)
5035{
5036 GObjectClass *object_class = G_OBJECT_CLASS (class);
5037
5038 object_class->get_property = gdk_wayland_toplevel_get_property;
5039 object_class->set_property = gdk_wayland_toplevel_set_property;
5040 object_class->finalize = gdk_wayland_toplevel_finalize;
5041
5042 gdk_toplevel_install_properties (object_class, first_prop: 1);
5043}
5044
5045static void
5046gdk_wayland_toplevel_present (GdkToplevel *toplevel,
5047 GdkToplevelLayout *layout)
5048{
5049 GdkSurface *surface = GDK_SURFACE (toplevel);
5050 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
5051 gboolean pending_configure = FALSE;
5052 gboolean maximize;
5053 gboolean fullscreen;
5054
5055 if (gdk_toplevel_layout_get_maximized (layout, maximized: &maximize))
5056 {
5057 if (maximize)
5058 gdk_wayland_surface_maximize (surface);
5059 else
5060 gdk_wayland_surface_unmaximize (surface);
5061 pending_configure = TRUE;
5062 }
5063
5064 if (gdk_toplevel_layout_get_fullscreen (layout, fullscreen: &fullscreen))
5065 {
5066 if (fullscreen)
5067 {
5068 GdkMonitor *monitor;
5069
5070 monitor = gdk_toplevel_layout_get_fullscreen_monitor (layout);
5071 if (monitor)
5072 gdk_wayland_surface_fullscreen_on_monitor (surface, monitor);
5073 else
5074 gdk_wayland_surface_fullscreen (surface);
5075 }
5076 else
5077 {
5078 gdk_wayland_surface_unfullscreen (surface);
5079 }
5080 pending_configure = TRUE;
5081 }
5082
5083 g_clear_pointer (&impl->toplevel.layout, gdk_toplevel_layout_unref);
5084 impl->toplevel.layout = gdk_toplevel_layout_copy (layout);
5085
5086 gdk_wayland_surface_show (surface);
5087
5088 if (!pending_configure)
5089 {
5090 impl->next_layout.surface_geometry_dirty = TRUE;
5091 gdk_surface_request_layout (surface);
5092 }
5093}
5094
5095static gboolean
5096gdk_wayland_toplevel_minimize (GdkToplevel *toplevel)
5097{
5098 gdk_wayland_surface_minimize (GDK_SURFACE (toplevel));
5099
5100 return TRUE;
5101}
5102
5103static gboolean
5104gdk_wayland_toplevel_lower (GdkToplevel *toplevel)
5105{
5106 return FALSE;
5107}
5108
5109static void
5110gdk_wayland_toplevel_focus (GdkToplevel *toplevel,
5111 guint32 timestamp)
5112{
5113 gdk_wayland_surface_focus (GDK_SURFACE (toplevel), timestamp);
5114}
5115
5116static gboolean
5117gdk_wayland_toplevel_show_window_menu (GdkToplevel *toplevel,
5118 GdkEvent *event)
5119{
5120 return gdk_wayland_surface_show_window_menu (GDK_SURFACE (toplevel), event);
5121}
5122
5123static gboolean
5124gdk_wayland_toplevel_titlebar_gesture (GdkToplevel *toplevel,
5125 GdkTitlebarGesture gesture)
5126{
5127 return gdk_wayland_surface_titlebar_gesture (GDK_SURFACE (toplevel), gesture);
5128}
5129
5130static gboolean
5131gdk_wayland_toplevel_supports_edge_constraints (GdkToplevel *toplevel)
5132{
5133 return gdk_wayland_surface_supports_edge_constraints (GDK_SURFACE (toplevel));
5134}
5135
5136static void
5137inhibitor_active (void *data,
5138 struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor)
5139{
5140 GdkToplevel *toplevel = GDK_TOPLEVEL (ptr: data);
5141 GdkSurface *surface = GDK_SURFACE (toplevel);
5142
5143 surface->shortcuts_inhibited = TRUE;
5144 g_object_notify (G_OBJECT (toplevel), property_name: "shortcuts-inhibited");
5145}
5146
5147static void
5148inhibitor_inactive (void *data,
5149 struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor)
5150{
5151 GdkToplevel *toplevel = GDK_TOPLEVEL (ptr: data);
5152 GdkSurface *surface = GDK_SURFACE (toplevel);
5153
5154 surface->shortcuts_inhibited = FALSE;
5155 g_object_notify (G_OBJECT (toplevel), property_name: "shortcuts-inhibited");
5156}
5157
5158static const struct zwp_keyboard_shortcuts_inhibitor_v1_listener
5159zwp_keyboard_shortcuts_inhibitor_listener = {
5160 inhibitor_active,
5161 inhibitor_inactive,
5162};
5163
5164static void
5165gdk_wayland_toplevel_inhibit_system_shortcuts (GdkToplevel *toplevel,
5166 GdkEvent *event)
5167{
5168 struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
5169 GdkSurface *surface = GDK_SURFACE (toplevel);
5170 GdkWaylandSurface *impl= GDK_WAYLAND_SURFACE (surface);
5171 GdkSeat *gdk_seat;
5172
5173 if (surface->shortcuts_inhibited)
5174 return;
5175
5176 gdk_seat = gdk_surface_get_seat_from_event (surface, event);
5177 gdk_wayland_surface_inhibit_shortcuts (surface, gdk_seat);
5178
5179 inhibitor = gdk_wayland_surface_get_inhibitor (impl, gdk_seat);
5180 if (!inhibitor)
5181 return;
5182
5183 surface->current_shortcuts_inhibited_seat = gdk_seat;
5184 zwp_keyboard_shortcuts_inhibitor_v1_add_listener
5185 (inhibitor, &zwp_keyboard_shortcuts_inhibitor_listener, toplevel);
5186}
5187
5188static void
5189gdk_wayland_toplevel_restore_system_shortcuts (GdkToplevel *toplevel)
5190{
5191 GdkSurface *surface = GDK_SURFACE (toplevel);
5192
5193 gdk_wayland_surface_restore_shortcuts (surface,
5194 gdk_seat: surface->current_shortcuts_inhibited_seat);
5195 surface->current_shortcuts_inhibited_seat = NULL;
5196 surface->shortcuts_inhibited = FALSE;
5197 g_object_notify (G_OBJECT (toplevel), property_name: "shortcuts-inhibited");
5198}
5199
5200static void
5201gdk_wayland_toplevel_iface_init (GdkToplevelInterface *iface)
5202{
5203 iface->present = gdk_wayland_toplevel_present;
5204 iface->minimize = gdk_wayland_toplevel_minimize;
5205 iface->lower = gdk_wayland_toplevel_lower;
5206 iface->focus = gdk_wayland_toplevel_focus;
5207 iface->show_window_menu = gdk_wayland_toplevel_show_window_menu;
5208 iface->titlebar_gesture = gdk_wayland_toplevel_titlebar_gesture;
5209 iface->supports_edge_constraints = gdk_wayland_toplevel_supports_edge_constraints;
5210 iface->inhibit_system_shortcuts = gdk_wayland_toplevel_inhibit_system_shortcuts;
5211 iface->restore_system_shortcuts = gdk_wayland_toplevel_restore_system_shortcuts;
5212 iface->begin_resize = gdk_wayland_toplevel_begin_resize;
5213 iface->begin_move = gdk_wayland_toplevel_begin_move;
5214}
5215
5216static void
5217gdk_wayland_drag_surface_init (GdkWaylandDragSurface *surface)
5218{
5219}
5220
5221static void
5222gdk_wayland_drag_surface_class_init (GdkWaylandDragSurfaceClass *class)
5223{
5224}
5225
5226static gboolean
5227gdk_wayland_drag_surface_present (GdkDragSurface *drag_surface,
5228 int width,
5229 int height)
5230{
5231 GdkSurface *surface = GDK_SURFACE (drag_surface);
5232 GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
5233
5234 gdk_wayland_surface_show (surface);
5235
5236 impl->next_layout.configured_width = width;
5237 impl->next_layout.configured_height = height;
5238 impl->next_layout.surface_geometry_dirty = TRUE;
5239 gdk_surface_request_layout (surface);
5240
5241 maybe_notify_mapped (surface);
5242
5243 return TRUE;
5244}
5245
5246static void
5247gdk_wayland_drag_surface_iface_init (GdkDragSurfaceInterface *iface)
5248{
5249 iface->present = gdk_wayland_drag_surface_present;
5250}
5251
5252

source code of gtk/gdk/wayland/gdksurface-wayland.c