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