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 <netinet/in.h>
21 #include <unistd.h>
22
23 #include "gdk.h"
24 #include "gdkwayland.h"
25
26 #include "gdkwindow.h"
27 #include "gdkwindowimpl.h"
28 #include "gdkdisplay-wayland.h"
29 #include "gdkglcontext-wayland.h"
30 #include "gdkframeclockprivate.h"
31 #include "gdkprivate-wayland.h"
32 #include "gdkprofilerprivate.h"
33 #include "gdkinternals.h"
34 #include "gdkdeviceprivate.h"
35 #include "gdkprivate-wayland.h"
36 #include "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 enum {
44 COMMITTED,
45
46 LAST_SIGNAL
47 };
48
49 static guint signals[LAST_SIGNAL];
50
51 #define WINDOW_IS_TOPLEVEL_OR_FOREIGN(window) \
52 (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \
53 GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)
54
55 #define WINDOW_IS_TOPLEVEL(window) \
56 (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \
57 GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN && \
58 GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)
59
60 #define MAX_WL_BUFFER_SIZE (4083) /* 4096 minus header, string argument length and NUL byte */
61
62 typedef struct _GdkWaylandWindow GdkWaylandWindow;
63 typedef struct _GdkWaylandWindowClass GdkWaylandWindowClass;
64
65 struct _GdkWaylandWindow
66 {
67 GdkWindow parent;
68 };
69
70 struct _GdkWaylandWindowClass
71 {
72 GdkWindowClass parent_class;
73 };
74
G_DEFINE_TYPE(GdkWaylandWindow,gdk_wayland_window,GDK_TYPE_WINDOW)75 G_DEFINE_TYPE (GdkWaylandWindow, gdk_wayland_window, GDK_TYPE_WINDOW)
76
77 static void
78 gdk_wayland_window_class_init (GdkWaylandWindowClass *wayland_window_class)
79 {
80 }
81
82 static void
gdk_wayland_window_init(GdkWaylandWindow * wayland_window)83 gdk_wayland_window_init (GdkWaylandWindow *wayland_window)
84 {
85 }
86
87 #define GDK_TYPE_WINDOW_IMPL_WAYLAND (_gdk_window_impl_wayland_get_type ())
88 #define GDK_WINDOW_IMPL_WAYLAND(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WINDOW_IMPL_WAYLAND, GdkWindowImplWayland))
89 #define GDK_WINDOW_IMPL_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WINDOW_IMPL_WAYLAND, GdkWindowImplWaylandClass))
90 #define GDK_IS_WINDOW_IMPL_WAYLAND(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WINDOW_IMPL_WAYLAND))
91 #define GDK_IS_WINDOW_IMPL_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WINDOW_IMPL_WAYLAND))
92 #define GDK_WINDOW_IMPL_WAYLAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WINDOW_IMPL_WAYLAND, GdkWindowImplWaylandClass))
93
94 typedef struct _GdkWindowImplWayland GdkWindowImplWayland;
95 typedef struct _GdkWindowImplWaylandClass GdkWindowImplWaylandClass;
96
97 typedef enum _PositionMethod
98 {
99 POSITION_METHOD_NONE,
100 POSITION_METHOD_MOVE_RESIZE,
101 POSITION_METHOD_MOVE_TO_RECT
102 } PositionMethod;
103
104 typedef struct _ExportedClosure
105 {
106 GdkWaylandWindowExported callback;
107 gpointer user_data;
108 GDestroyNotify destroy_func;
109 } ExportedClosure;
110
111 struct _GdkWindowImplWayland
112 {
113 GdkWindowImpl parent_instance;
114
115 GdkWindow *wrapper;
116
117 struct {
118 /* The wl_outputs that this window currently touches */
119 GSList *outputs;
120
121 struct wl_surface *wl_surface;
122
123 struct xdg_surface *xdg_surface;
124 struct xdg_toplevel *xdg_toplevel;
125 struct xdg_popup *xdg_popup;
126
127 /* Legacy xdg-shell unstable v6 fallback support */
128 struct zxdg_surface_v6 *zxdg_surface_v6;
129 struct zxdg_toplevel_v6 *zxdg_toplevel_v6;
130 struct zxdg_popup_v6 *zxdg_popup_v6;
131
132 struct gtk_surface1 *gtk_surface;
133 struct wl_subsurface *wl_subsurface;
134 struct wl_egl_window *egl_window;
135 struct wl_egl_window *dummy_egl_window;
136 struct zxdg_exported_v1 *xdg_exported;
137 struct org_kde_kwin_server_decoration *server_decoration;
138 } display_server;
139
140 EGLSurface egl_surface;
141 EGLSurface dummy_egl_surface;
142
143 unsigned int initial_configure_received : 1;
144 unsigned int configuring_popup : 1;
145 unsigned int mapped : 1;
146 unsigned int use_custom_surface : 1;
147 unsigned int pending_buffer_attached : 1;
148 unsigned int pending_commit : 1;
149 unsigned int awaiting_frame : 1;
150 unsigned int using_csd : 1;
151 GdkWindowTypeHint hint;
152 GdkWindow *transient_for;
153 GdkWindow *popup_parent;
154 PositionMethod position_method;
155
156 cairo_surface_t *staging_cairo_surface;
157 cairo_surface_t *committed_cairo_surface;
158 cairo_surface_t *backfill_cairo_surface;
159
160 int pending_buffer_offset_x;
161 int pending_buffer_offset_y;
162
163 int subsurface_x;
164 int subsurface_y;
165
166 gchar *title;
167
168 struct {
169 gboolean was_set;
170
171 gchar *application_id;
172 gchar *app_menu_path;
173 gchar *menubar_path;
174 gchar *window_object_path;
175 gchar *application_object_path;
176 gchar *unique_bus_name;
177 } application;
178
179 GdkGeometry geometry_hints;
180 GdkWindowHints geometry_mask;
181
182 GdkSeat *grab_input_seat;
183
184 gint64 pending_frame_counter;
185 guint32 scale;
186
187 int margin_left;
188 int margin_right;
189 int margin_top;
190 int margin_bottom;
191 gboolean margin_dirty;
192
193 int initial_fullscreen_monitor;
194
195 cairo_region_t *opaque_region;
196 gboolean opaque_region_dirty;
197
198 cairo_region_t *input_region;
199 gboolean input_region_dirty;
200
201 cairo_region_t *staged_updates_region;
202
203 int saved_width;
204 int saved_height;
205 gboolean saved_size_changed;
206
207 int unconfigured_width;
208 int unconfigured_height;
209
210 int fixed_size_width;
211 int fixed_size_height;
212
213 gulong parent_surface_committed_handler;
214
215 struct {
216 GdkRectangle rect;
217 GdkGravity rect_anchor;
218 GdkGravity window_anchor;
219 GdkAnchorHints anchor_hints;
220 gint rect_anchor_dx;
221 gint rect_anchor_dy;
222 } pending_move_to_rect;
223
224 struct {
225 int width;
226 int height;
227 GdkWindowState state;
228 } pending;
229
230 struct {
231 char *handle;
232 int export_count;
233 GList *closures;
234 guint idle_source_id;
235 } exported;
236
237 struct zxdg_imported_v1 *imported_transient_for;
238 GHashTable *shortcuts_inhibitors;
239
240 struct wl_callback *surface_callback;
241 GHashTable *frame_callback_surfaces;
242 };
243
244 struct _GdkWindowImplWaylandClass
245 {
246 GdkWindowImplClass parent_class;
247 };
248
249 static void gdk_wayland_window_maybe_configure (GdkWindow *window,
250 int width,
251 int height,
252 int scale);
253
254 static void maybe_set_gtk_surface_dbus_properties (GdkWindow *window);
255 static void maybe_set_gtk_surface_modal (GdkWindow *window);
256
257 static void gdk_window_request_transient_parent_commit (GdkWindow *window);
258
259 static void gdk_wayland_window_sync_margin (GdkWindow *window);
260 static void gdk_wayland_window_sync_input_region (GdkWindow *window);
261 static void gdk_wayland_window_sync_opaque_region (GdkWindow *window);
262
263 static void unset_transient_for_exported (GdkWindow *window);
264
265 static void calculate_moved_to_rect_result (GdkWindow *window,
266 int x,
267 int y,
268 int width,
269 int height,
270 GdkRectangle *flipped_rect,
271 GdkRectangle *final_rect,
272 gboolean *flipped_x,
273 gboolean *flipped_y);
274
275 static gboolean gdk_wayland_window_is_exported (GdkWindow *window);
276 static void gdk_wayland_window_unexport (GdkWindow *window);
277 static void gdk_wayland_window_announce_decoration_mode (GdkWindow *window);
278
279 static gboolean should_map_as_subsurface (GdkWindow *window);
280 static gboolean should_map_as_popup (GdkWindow *window);
281
282 GType _gdk_window_impl_wayland_get_type (void);
283
G_DEFINE_TYPE(GdkWindowImplWayland,_gdk_window_impl_wayland,GDK_TYPE_WINDOW_IMPL)284 G_DEFINE_TYPE (GdkWindowImplWayland, _gdk_window_impl_wayland, GDK_TYPE_WINDOW_IMPL)
285
286 static void
287 _gdk_window_impl_wayland_init (GdkWindowImplWayland *impl)
288 {
289 impl->scale = 1;
290 impl->initial_fullscreen_monitor = -1;
291 impl->saved_width = -1;
292 impl->saved_height = -1;
293 }
294
295 static void
_gdk_wayland_screen_add_orphan_dialog(GdkWindow * window)296 _gdk_wayland_screen_add_orphan_dialog (GdkWindow *window)
297 {
298 GdkWaylandDisplay *display_wayland =
299 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
300
301 if (!g_list_find (display_wayland->orphan_dialogs, window))
302 display_wayland->orphan_dialogs =
303 g_list_prepend (display_wayland->orphan_dialogs, window);
304 }
305
306 static void
drop_cairo_surfaces(GdkWindow * window)307 drop_cairo_surfaces (GdkWindow *window)
308 {
309 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
310
311 g_clear_pointer (&impl->staging_cairo_surface, cairo_surface_destroy);
312 g_clear_pointer (&impl->backfill_cairo_surface, cairo_surface_destroy);
313
314 /* We nullify this so if a buffer release comes in later, we won't
315 * try to reuse that buffer since it's no longer suitable
316 */
317 impl->committed_cairo_surface = NULL;
318 }
319
320 static int
calculate_width_without_margin(GdkWindow * window,int width)321 calculate_width_without_margin (GdkWindow *window,
322 int width)
323 {
324 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
325
326 return width - (impl->margin_left + impl->margin_right);
327 }
328
329 static int
calculate_height_without_margin(GdkWindow * window,int height)330 calculate_height_without_margin (GdkWindow *window,
331 int height)
332 {
333 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
334
335 return height - (impl->margin_top + impl->margin_bottom);
336 }
337
338 static int
calculate_width_with_margin(GdkWindow * window,int width)339 calculate_width_with_margin (GdkWindow *window,
340 int width)
341 {
342 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
343
344 return width + impl->margin_left + impl->margin_right;
345 }
346
347 static int
calculate_height_with_margin(GdkWindow * window,int height)348 calculate_height_with_margin (GdkWindow *window,
349 int height)
350 {
351 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
352
353 return height + impl->margin_top + impl->margin_bottom;
354 }
355
356 static void
_gdk_wayland_window_save_size(GdkWindow * window)357 _gdk_wayland_window_save_size (GdkWindow *window)
358 {
359 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
360
361 if (window->state & (GDK_WINDOW_STATE_FULLSCREEN |
362 GDK_WINDOW_STATE_MAXIMIZED |
363 GDK_WINDOW_STATE_TILED))
364 return;
365
366 impl->saved_width = calculate_width_without_margin (window, window->width);
367 impl->saved_height = calculate_height_without_margin (window, window->height);
368 }
369
370 static void
_gdk_wayland_window_clear_saved_size(GdkWindow * window)371 _gdk_wayland_window_clear_saved_size (GdkWindow *window)
372 {
373 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
374
375 if (window->state & (GDK_WINDOW_STATE_FULLSCREEN |
376 GDK_WINDOW_STATE_MAXIMIZED |
377 GDK_WINDOW_STATE_TILED))
378 return;
379
380 impl->saved_width = -1;
381 impl->saved_height = -1;
382 }
383
384 /*
385 * gdk_wayland_window_update_size:
386 * @drawable: a #GdkDrawableImplWayland.
387 *
388 * Updates the state of the drawable (in particular the drawable's
389 * cairo surface) when its size has changed.
390 */
391 static void
gdk_wayland_window_update_size(GdkWindow * window,int32_t width,int32_t height,int scale)392 gdk_wayland_window_update_size (GdkWindow *window,
393 int32_t width,
394 int32_t height,
395 int scale)
396 {
397 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
398 GdkRectangle area;
399 cairo_region_t *region;
400
401 if ((window->width == width) &&
402 (window->height == height) &&
403 (impl->scale == scale))
404 return;
405
406 drop_cairo_surfaces (window);
407
408 window->width = width;
409 window->height = height;
410 impl->scale = scale;
411
412 if (impl->display_server.egl_window)
413 wl_egl_window_resize (impl->display_server.egl_window, width * scale, height * scale, 0, 0);
414 if (impl->display_server.wl_surface)
415 wl_surface_set_buffer_scale (impl->display_server.wl_surface, scale);
416
417 area.x = 0;
418 area.y = 0;
419 area.width = window->width;
420 area.height = window->height;
421
422 region = cairo_region_create_rectangle (&area);
423 _gdk_window_invalidate_for_expose (window, region);
424 cairo_region_destroy (region);
425 }
426
427 GdkWindow *
_gdk_wayland_screen_create_root_window(GdkScreen * screen,int width,int height)428 _gdk_wayland_screen_create_root_window (GdkScreen *screen,
429 int width,
430 int height)
431 {
432 GdkWaylandDisplay *display_wayland =
433 GDK_WAYLAND_DISPLAY (gdk_screen_get_display (screen));
434 GdkWindow *window;
435 GdkWindowImplWayland *impl;
436
437 window = _gdk_display_create_window (GDK_DISPLAY (display_wayland));
438 window->impl = g_object_new (GDK_TYPE_WINDOW_IMPL_WAYLAND, NULL);
439 window->impl_window = window;
440 window->visual = gdk_screen_get_system_visual (screen);
441
442 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
443
444 impl->wrapper = GDK_WINDOW (window);
445 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
446 if (display_wayland->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE &&
447 gdk_screen_get_n_monitors (screen) > 0)
448 impl->scale = gdk_screen_get_monitor_scale_factor (screen, 0);
449 G_GNUC_END_IGNORE_DEPRECATIONS
450
451 impl->using_csd = TRUE;
452
453 /* logical 1x1 fake buffer */
454 impl->staging_cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
455 impl->scale,
456 impl->scale);
457
458 cairo_surface_set_device_scale (impl->staging_cairo_surface, impl->scale, impl->scale);
459
460 window->window_type = GDK_WINDOW_ROOT;
461 window->depth = 32;
462
463 window->x = 0;
464 window->y = 0;
465 window->abs_x = 0;
466 window->abs_y = 0;
467 window->width = width;
468 window->height = height;
469 window->viewable = TRUE;
470
471 /* see init_randr_support() in gdkscreen-wayland.c */
472 window->event_mask = GDK_STRUCTURE_MASK;
473
474 return window;
475 }
476
477 static const gchar *
get_default_title(void)478 get_default_title (void)
479 {
480 const char *title;
481
482 title = g_get_application_name ();
483 if (!title)
484 title = g_get_prgname ();
485 if (!title)
486 title = "";
487
488 return title;
489 }
490
491 static void
fill_presentation_time_from_frame_time(GdkFrameTimings * timings,guint32 frame_time)492 fill_presentation_time_from_frame_time (GdkFrameTimings *timings,
493 guint32 frame_time)
494 {
495 /* The timestamp in a wayland frame is a msec time value that in some
496 * way reflects the time at which the server started drawing the frame.
497 * This is not useful from our perspective.
498 *
499 * However, for the DRM backend of Weston, on reasonably recent
500 * Linux, we know that the time is the
501 * clock_gettime (CLOCK_MONOTONIC) value at the vblank, and that
502 * backend starts drawing immediately after receiving the vblank
503 * notification. If we detect this, and make the assumption that the
504 * compositor will finish drawing before the next vblank, we can
505 * then determine the presentation time as the frame time we
506 * received plus one refresh interval.
507 *
508 * If a backend is using clock_gettime(CLOCK_MONOTONIC), but not
509 * picking values right at the vblank, then the presentation times
510 * we compute won't be accurate, but not really worse than then
511 * the alternative of not providing presentation times at all.
512 *
513 * The complexity here is dealing with the fact that we receive
514 * only the low 32 bits of the CLOCK_MONOTONIC value in milliseconds.
515 */
516 gint64 now_monotonic = g_get_monotonic_time ();
517 gint64 now_monotonic_msec = now_monotonic / 1000;
518 uint32_t now_monotonic_low = (uint32_t)now_monotonic_msec;
519
520 if (frame_time - now_monotonic_low < 1000 ||
521 frame_time - now_monotonic_low > (uint32_t)-1000)
522 {
523 /* Timestamp we received is within one second of the current time.
524 */
525 gint64 last_frame_time = now_monotonic + (gint64)1000 * (gint32)(frame_time - now_monotonic_low);
526 if ((gint32)now_monotonic_low < 0 && (gint32)frame_time > 0)
527 last_frame_time += (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
528 else if ((gint32)now_monotonic_low > 0 && (gint32)frame_time < 0)
529 last_frame_time -= (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
530
531 timings->presentation_time = last_frame_time + timings->refresh_interval;
532 }
533 }
534
535 static void
read_back_cairo_surface(GdkWindow * window)536 read_back_cairo_surface (GdkWindow *window)
537 {
538 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
539 cairo_t *cr;
540 cairo_region_t *paint_region = NULL;
541
542 if (!impl->backfill_cairo_surface)
543 goto out;
544
545 paint_region = cairo_region_copy (window->clip_region);
546 cairo_region_subtract (paint_region, impl->staged_updates_region);
547
548 if (cairo_region_is_empty (paint_region))
549 goto out;
550
551 cr = cairo_create (impl->staging_cairo_surface);
552 cairo_set_source_surface (cr, impl->backfill_cairo_surface, 0, 0);
553 gdk_cairo_region (cr, paint_region);
554 cairo_clip (cr);
555 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
556 cairo_paint (cr);
557 cairo_destroy (cr);
558 cairo_surface_flush (impl->staging_cairo_surface);
559
560 out:
561 g_clear_pointer (&paint_region, cairo_region_destroy);
562 g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy);
563 g_clear_pointer (&impl->backfill_cairo_surface, cairo_surface_destroy);
564 }
565
566 static void
frame_callback(void * data,struct wl_callback * callback,uint32_t time)567 frame_callback (void *data,
568 struct wl_callback *callback,
569 uint32_t time)
570 {
571 GdkWindow *window = data;
572 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
573 GdkWaylandDisplay *display_wayland =
574 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
575 GdkFrameClock *clock = gdk_window_get_frame_clock (window);
576 GdkFrameTimings *timings;
577
578 if (callback == impl->surface_callback)
579 {
580 impl->surface_callback = NULL;
581 }
582 else
583 {
584 GHashTableIter iter;
585 gpointer surface_callback;
586
587 g_hash_table_iter_init (&iter, impl->frame_callback_surfaces);
588 while (g_hash_table_iter_next (&iter, NULL, &surface_callback))
589 {
590 if (callback == surface_callback)
591 {
592 g_hash_table_iter_replace (&iter, NULL);
593 break;
594 }
595 }
596 }
597 wl_callback_destroy (callback);
598
599 if (GDK_WINDOW_DESTROYED (window))
600 return;
601
602 if (!impl->awaiting_frame)
603 return;
604
605 GDK_NOTE (EVENTS,
606 g_message ("frame %p", window));
607
608 impl->awaiting_frame = FALSE;
609 _gdk_frame_clock_thaw (clock);
610
611 timings = gdk_frame_clock_get_timings (clock, impl->pending_frame_counter);
612 impl->pending_frame_counter = 0;
613
614 if (timings == NULL)
615 return;
616
617 timings->refresh_interval = 16667; /* default to 1/60th of a second */
618 if (impl->display_server.outputs)
619 {
620 /* We pick a random output out of the outputs that the window touches
621 * The rate here is in milli-hertz */
622 int refresh_rate =
623 _gdk_wayland_screen_get_output_refresh_rate (display_wayland->screen,
624 impl->display_server.outputs->data);
625 if (refresh_rate != 0)
626 timings->refresh_interval = G_GINT64_CONSTANT(1000000000) / refresh_rate;
627 }
628
629 fill_presentation_time_from_frame_time (timings, time);
630
631 timings->complete = TRUE;
632
633 #ifdef G_ENABLE_DEBUG
634 if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0)
635 _gdk_frame_clock_debug_print_timings (clock, timings);
636
637 if (gdk_profiler_is_running ())
638 _gdk_frame_clock_add_timings_to_profiler (clock, timings);
639 #endif
640 }
641
642 static const struct wl_callback_listener frame_listener = {
643 frame_callback
644 };
645
646 static void
on_frame_clock_before_paint(GdkFrameClock * clock,GdkWindow * window)647 on_frame_clock_before_paint (GdkFrameClock *clock,
648 GdkWindow *window)
649 {
650 GdkFrameTimings *timings = gdk_frame_clock_get_current_timings (clock);
651 gint64 presentation_time;
652 gint64 refresh_interval;
653
654 if (window->update_freeze_count > 0)
655 return;
656
657 gdk_frame_clock_get_refresh_info (clock,
658 timings->frame_time,
659 &refresh_interval, &presentation_time);
660
661 if (presentation_time != 0)
662 {
663 /* Assume the algorithm used by the DRM backend of Weston - it
664 * starts drawing at the next vblank after receiving the commit
665 * for this frame, and presentation occurs at the vblank
666 * after that.
667 */
668 timings->predicted_presentation_time = presentation_time + refresh_interval;
669 }
670 else
671 {
672 /* As above, but we don't actually know the phase of the vblank,
673 * so just assume that we're half way through a refresh cycle.
674 */
675 timings->predicted_presentation_time = timings->frame_time + refresh_interval / 2 + refresh_interval;
676 }
677 }
678
679 static void
on_frame_clock_after_paint(GdkFrameClock * clock,GdkWindow * window)680 on_frame_clock_after_paint (GdkFrameClock *clock,
681 GdkWindow *window)
682 {
683 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
684 struct wl_callback *callback;
685 GHashTableIter iter;
686 gpointer surface, surface_callback;
687
688 if (!impl->pending_commit)
689 return;
690
691 if (window->update_freeze_count > 0)
692 return;
693
694 _gdk_frame_clock_freeze (clock);
695
696 /* Before we commit a new buffer, make sure we've backfilled
697 * undrawn parts from any old committed buffer
698 */
699 if (impl->pending_buffer_attached)
700 read_back_cairo_surface (window);
701
702 if (impl->surface_callback == NULL)
703 {
704 callback = wl_surface_frame (impl->display_server.wl_surface);
705 wl_callback_add_listener (callback, &frame_listener, window);
706 impl->surface_callback = callback;
707 }
708
709 g_hash_table_iter_init (&iter, impl->frame_callback_surfaces);
710 while (g_hash_table_iter_next (&iter, &surface, &surface_callback))
711 {
712 if (surface_callback)
713 continue;
714
715 callback = wl_surface_frame (surface);
716 wl_callback_add_listener (callback, &frame_listener, window);
717 g_hash_table_iter_replace (&iter, callback);
718 }
719
720 /* From this commit forward, we can't write to the buffer,
721 * it's "live". In the future, if we need to stage more changes
722 * we have to allocate a new staging buffer and draw to it instead.
723 *
724 * Our one saving grace is if the compositor releases the buffer
725 * before we need to stage any changes, then we can take it back and
726 * use it again.
727 */
728 wl_surface_commit (impl->display_server.wl_surface);
729
730 if (impl->pending_buffer_attached)
731 impl->committed_cairo_surface = g_steal_pointer (&impl->staging_cairo_surface);
732
733 impl->pending_buffer_attached = FALSE;
734 impl->pending_commit = FALSE;
735 impl->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock);
736 impl->awaiting_frame = TRUE;
737
738 g_signal_emit (impl, signals[COMMITTED], 0);
739 }
740
741 static void
window_update_scale(GdkWindow * window)742 window_update_scale (GdkWindow *window)
743 {
744 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
745 GdkWaylandDisplay *display_wayland =
746 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
747 guint32 scale;
748 GSList *l;
749
750 if (display_wayland->compositor_version < WL_SURFACE_HAS_BUFFER_SCALE)
751 {
752 /* We can't set the scale on this surface */
753 return;
754 }
755
756 scale = 1;
757 for (l = impl->display_server.outputs; l != NULL; l = l->next)
758 {
759 guint32 output_scale =
760 _gdk_wayland_screen_get_output_scale (display_wayland->screen, l->data);
761 scale = MAX (scale, output_scale);
762 }
763
764 /* Notify app that scale changed */
765 gdk_wayland_window_maybe_configure (window, window->width, window->height, scale);
766 }
767
768 static void
on_monitors_changed(GdkScreen * screen,GdkWindow * window)769 on_monitors_changed (GdkScreen *screen,
770 GdkWindow *window)
771 {
772 window_update_scale (window);
773 }
774
775
776 static void gdk_wayland_window_create_surface (GdkWindow *window);
777
778 void
_gdk_wayland_display_create_window_impl(GdkDisplay * display,GdkWindow * window,GdkWindow * real_parent,GdkScreen * screen,GdkEventMask event_mask,GdkWindowAttr * attributes,gint attributes_mask)779 _gdk_wayland_display_create_window_impl (GdkDisplay *display,
780 GdkWindow *window,
781 GdkWindow *real_parent,
782 GdkScreen *screen,
783 GdkEventMask event_mask,
784 GdkWindowAttr *attributes,
785 gint attributes_mask)
786 {
787 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
788 GdkWindowImplWayland *impl;
789 GdkFrameClock *frame_clock;
790 const char *title;
791
792 impl = g_object_new (GDK_TYPE_WINDOW_IMPL_WAYLAND, NULL);
793 window->impl = GDK_WINDOW_IMPL (impl);
794 impl->unconfigured_width = window->width;
795 impl->unconfigured_height = window->height;
796 impl->wrapper = GDK_WINDOW (window);
797 impl->shortcuts_inhibitors = g_hash_table_new (NULL, NULL);
798 impl->using_csd = TRUE;
799 impl->surface_callback = NULL;
800 impl->frame_callback_surfaces = g_hash_table_new (NULL, NULL);
801
802 if (window->width > 65535)
803 {
804 g_warning ("Native Windows wider than 65535 pixels are not supported");
805 window->width = 65535;
806 }
807 if (window->height > 65535)
808 {
809 g_warning ("Native Windows taller than 65535 pixels are not supported");
810 window->height = 65535;
811 }
812
813 g_object_ref (window);
814
815 /* More likely to be right than just assuming 1 */
816 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
817 if (display_wayland->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE &&
818 gdk_screen_get_n_monitors (screen) > 0)
819 impl->scale = gdk_screen_get_monitor_scale_factor (screen, 0);
820 G_GNUC_END_IGNORE_DEPRECATIONS
821
822 impl->title = NULL;
823
824 switch (GDK_WINDOW_TYPE (window))
825 {
826 case GDK_WINDOW_TOPLEVEL:
827 case GDK_WINDOW_TEMP:
828 if (attributes_mask & GDK_WA_TITLE)
829 title = attributes->title;
830 else
831 title = get_default_title ();
832
833 gdk_window_set_title (window, title);
834 break;
835
836 case GDK_WINDOW_CHILD:
837 default:
838 break;
839 }
840
841 gdk_wayland_window_create_surface (window);
842
843 if (attributes_mask & GDK_WA_TYPE_HINT)
844 gdk_window_set_type_hint (window, attributes->type_hint);
845
846 frame_clock = gdk_window_get_frame_clock (window);
847
848 g_signal_connect (frame_clock, "before-paint",
849 G_CALLBACK (on_frame_clock_before_paint), window);
850 g_signal_connect (frame_clock, "after-paint",
851 G_CALLBACK (on_frame_clock_after_paint), window);
852
853 g_signal_connect (screen, "monitors-changed",
854 G_CALLBACK (on_monitors_changed), window);
855 }
856
857 static void
gdk_wayland_window_attach_image(GdkWindow * window)858 gdk_wayland_window_attach_image (GdkWindow *window)
859 {
860 GdkWaylandDisplay *display;
861 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
862
863 if (GDK_WINDOW_DESTROYED (window))
864 return;
865
866 g_assert (_gdk_wayland_is_shm_surface (impl->staging_cairo_surface));
867
868 /* Attach this new buffer to the surface */
869 wl_surface_attach (impl->display_server.wl_surface,
870 _gdk_wayland_shm_surface_get_wl_buffer (impl->staging_cairo_surface),
871 impl->pending_buffer_offset_x,
872 impl->pending_buffer_offset_y);
873 impl->pending_buffer_offset_x = 0;
874 impl->pending_buffer_offset_y = 0;
875
876 /* Only set the buffer scale if supported by the compositor */
877 display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
878 if (display->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE)
879 wl_surface_set_buffer_scale (impl->display_server.wl_surface, impl->scale);
880
881 impl->pending_buffer_attached = TRUE;
882 impl->pending_commit = TRUE;
883 }
884
885 static const cairo_user_data_key_t gdk_wayland_window_cairo_key;
886
887 static void
buffer_release_callback(void * _data,struct wl_buffer * wl_buffer)888 buffer_release_callback (void *_data,
889 struct wl_buffer *wl_buffer)
890 {
891 cairo_surface_t *cairo_surface = _data;
892 GdkWindowImplWayland *impl = cairo_surface_get_user_data (cairo_surface, &gdk_wayland_window_cairo_key);
893
894 g_return_if_fail (GDK_IS_WINDOW_IMPL_WAYLAND (impl));
895
896 /* The released buffer isn't the latest committed one, we have no further
897 * use for it, so clean it up.
898 */
899 if (impl->committed_cairo_surface != cairo_surface)
900 {
901 /* If this fails, then the surface buffer got reused before it was
902 * released from the compositor
903 */
904 g_warn_if_fail (impl->staging_cairo_surface != cairo_surface);
905
906 cairo_surface_destroy (cairo_surface);
907 return;
908 }
909
910 if (impl->staged_updates_region != NULL)
911 {
912 /* If this fails, then we're tracking staged updates on a staging surface
913 * that doesn't exist.
914 */
915 g_warn_if_fail (impl->staging_cairo_surface != NULL);
916
917 /* If we've staged updates into a new buffer before the release for this
918 * buffer came in, then we can't reuse this buffer, so unref it. It may still
919 * be alive as a readback buffer though (via impl->backfill_cairo_surface).
920 *
921 * It's possible a staging surface was allocated but no updates were staged.
922 * If that happened, clean up that staging surface now, since the old commit
923 * buffer is available again, and reusing the old commit buffer for future
924 * updates will save having to do a read back later.
925 */
926 if (!cairo_region_is_empty (impl->staged_updates_region))
927 {
928 g_clear_pointer (&impl->committed_cairo_surface, cairo_surface_destroy);
929 return;
930 }
931 else
932 {
933 g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy);
934 g_clear_pointer (&impl->staging_cairo_surface, cairo_surface_destroy);
935 }
936 }
937
938 /* Release came in, we haven't done any interim updates, so we can just use
939 * the old committed buffer again.
940 */
941 impl->staging_cairo_surface = g_steal_pointer (&impl->committed_cairo_surface);
942 }
943
944 static const struct wl_buffer_listener buffer_listener = {
945 buffer_release_callback
946 };
947
948 static void
gdk_wayland_window_ensure_cairo_surface(GdkWindow * window)949 gdk_wayland_window_ensure_cairo_surface (GdkWindow *window)
950 {
951 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
952
953 /* If we are drawing using OpenGL then we only need a logical 1x1 surface. */
954 if (impl->display_server.egl_window)
955 {
956 if (impl->staging_cairo_surface &&
957 _gdk_wayland_is_shm_surface (impl->staging_cairo_surface))
958 g_clear_pointer (&impl->staging_cairo_surface, cairo_surface_destroy);
959
960 if (!impl->staging_cairo_surface)
961 {
962 impl->staging_cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
963 impl->scale,
964 impl->scale);
965 cairo_surface_set_device_scale (impl->staging_cairo_surface,
966 impl->scale, impl->scale);
967 }
968 }
969 else if (!impl->staging_cairo_surface)
970 {
971 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (impl->wrapper));
972 struct wl_buffer *buffer;
973
974 impl->staging_cairo_surface = _gdk_wayland_display_create_shm_surface (display_wayland,
975 impl->wrapper->width,
976 impl->wrapper->height,
977 impl->scale);
978 cairo_surface_set_user_data (impl->staging_cairo_surface,
979 &gdk_wayland_window_cairo_key,
980 g_object_ref (impl),
981 (cairo_destroy_func_t)
982 g_object_unref);
983 buffer = _gdk_wayland_shm_surface_get_wl_buffer (impl->staging_cairo_surface);
984 wl_buffer_add_listener (buffer, &buffer_listener, impl->staging_cairo_surface);
985 }
986 }
987
988 /* The cairo surface returned here uses a memory segment that's shared
989 * with the display server. This is not a temporary buffer that gets
990 * copied to the display server, but the actual buffer the display server
991 * will ultimately end up sending to the GPU. At the time this happens
992 * impl->committed_cairo_surface gets set to impl->staging_cairo_surface, and
993 * impl->staging_cairo_surface gets nullified.
994 */
995 static cairo_surface_t *
gdk_wayland_window_ref_cairo_surface(GdkWindow * window)996 gdk_wayland_window_ref_cairo_surface (GdkWindow *window)
997 {
998 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
999
1000 if (GDK_WINDOW_DESTROYED (impl->wrapper))
1001 return NULL;
1002
1003 gdk_wayland_window_ensure_cairo_surface (window);
1004
1005 cairo_surface_reference (impl->staging_cairo_surface);
1006
1007 return impl->staging_cairo_surface;
1008 }
1009
1010 static cairo_surface_t *
gdk_wayland_window_create_similar_image_surface(GdkWindow * window,cairo_format_t format,int width,int height)1011 gdk_wayland_window_create_similar_image_surface (GdkWindow * window,
1012 cairo_format_t format,
1013 int width,
1014 int height)
1015 {
1016 return cairo_image_surface_create (format, width, height);
1017 }
1018
1019 static gboolean
gdk_window_impl_wayland_begin_paint(GdkWindow * window)1020 gdk_window_impl_wayland_begin_paint (GdkWindow *window)
1021 {
1022 gdk_wayland_window_ensure_cairo_surface (window);
1023
1024 return FALSE;
1025 }
1026
1027 static void
gdk_window_impl_wayland_end_paint(GdkWindow * window)1028 gdk_window_impl_wayland_end_paint (GdkWindow *window)
1029 {
1030 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1031 cairo_rectangle_int_t rect;
1032 int i, n;
1033
1034 if (!GDK_WINDOW_IS_MAPPED (window))
1035 return;
1036
1037 if (impl->staging_cairo_surface &&
1038 _gdk_wayland_is_shm_surface (impl->staging_cairo_surface) &&
1039 !window->current_paint.use_gl &&
1040 !cairo_region_is_empty (window->current_paint.region))
1041 {
1042 gdk_wayland_window_attach_image (window);
1043
1044 /* If there's a committed buffer pending, then track which
1045 * updates are staged until the next frame, so we can back
1046 * fill the unstaged parts of the staging buffer with the
1047 * last frame.
1048 */
1049 if (impl->committed_cairo_surface != NULL)
1050 {
1051 if (impl->staged_updates_region == NULL)
1052 {
1053 impl->staged_updates_region = cairo_region_copy (window->current_paint.region);
1054 impl->backfill_cairo_surface = cairo_surface_reference (impl->committed_cairo_surface);
1055 }
1056 else
1057 {
1058 cairo_region_union (impl->staged_updates_region, window->current_paint.region);
1059 }
1060 }
1061
1062 n = cairo_region_num_rectangles (window->current_paint.region);
1063 for (i = 0; i < n; i++)
1064 {
1065 cairo_region_get_rectangle (window->current_paint.region, i, &rect);
1066 wl_surface_damage (impl->display_server.wl_surface, rect.x, rect.y, rect.width, rect.height);
1067 }
1068
1069 impl->pending_commit = TRUE;
1070 }
1071
1072 gdk_wayland_window_sync_margin (window);
1073 gdk_wayland_window_sync_opaque_region (window);
1074 gdk_wayland_window_sync_input_region (window);
1075 }
1076
1077 static gboolean
gdk_window_impl_wayland_beep(GdkWindow * window)1078 gdk_window_impl_wayland_beep (GdkWindow *window)
1079 {
1080 gdk_wayland_display_system_bell (gdk_window_get_display (window),
1081 window);
1082
1083 return TRUE;
1084 }
1085
1086 static void
gdk_window_impl_wayland_finalize(GObject * object)1087 gdk_window_impl_wayland_finalize (GObject *object)
1088 {
1089 GdkWindowImplWayland *impl;
1090
1091 g_return_if_fail (GDK_IS_WINDOW_IMPL_WAYLAND (object));
1092
1093 impl = GDK_WINDOW_IMPL_WAYLAND (object);
1094
1095 if (gdk_wayland_window_is_exported (impl->wrapper))
1096 gdk_wayland_window_unexport_handle (impl->wrapper);
1097
1098 g_free (impl->title);
1099
1100 g_free (impl->application.application_id);
1101 g_free (impl->application.app_menu_path);
1102 g_free (impl->application.menubar_path);
1103 g_free (impl->application.window_object_path);
1104 g_free (impl->application.application_object_path);
1105 g_free (impl->application.unique_bus_name);
1106
1107 g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
1108 g_clear_pointer (&impl->input_region, cairo_region_destroy);
1109 g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy);
1110
1111 g_clear_pointer (&impl->shortcuts_inhibitors, g_hash_table_unref);
1112 g_clear_pointer (&impl->frame_callback_surfaces, g_hash_table_unref);
1113
1114 G_OBJECT_CLASS (_gdk_window_impl_wayland_parent_class)->finalize (object);
1115 }
1116
1117 static void
gdk_wayland_window_configure(GdkWindow * window,int width,int height,int scale)1118 gdk_wayland_window_configure (GdkWindow *window,
1119 int width,
1120 int height,
1121 int scale)
1122 {
1123 GdkDisplay *display;
1124 GdkEvent *event;
1125
1126 g_return_if_fail (width > 0);
1127 g_return_if_fail (height > 0);
1128
1129 event = gdk_event_new (GDK_CONFIGURE);
1130 event->configure.window = g_object_ref (window);
1131 event->configure.send_event = FALSE;
1132 event->configure.width = width;
1133 event->configure.height = height;
1134
1135 gdk_wayland_window_update_size (window, width, height, scale);
1136 _gdk_window_update_size (window);
1137
1138 display = gdk_window_get_display (window);
1139 _gdk_wayland_display_deliver_event (display, event);
1140 }
1141
1142 static gboolean
is_realized_shell_surface(GdkWindow * window)1143 is_realized_shell_surface (GdkWindow *window)
1144 {
1145 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1146
1147 return (impl->display_server.xdg_surface ||
1148 impl->display_server.zxdg_surface_v6);
1149 }
1150
1151 static gboolean
is_realized_toplevel(GdkWindow * window)1152 is_realized_toplevel (GdkWindow *window)
1153 {
1154 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1155
1156 return (impl->display_server.xdg_toplevel ||
1157 impl->display_server.zxdg_toplevel_v6);
1158 }
1159
1160 static gboolean
is_realized_popup(GdkWindow * window)1161 is_realized_popup (GdkWindow *window)
1162 {
1163 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1164
1165 return (impl->display_server.xdg_popup ||
1166 impl->display_server.zxdg_popup_v6);
1167 }
1168
1169 static gboolean
should_inhibit_resize(GdkWindow * window)1170 should_inhibit_resize (GdkWindow *window)
1171 {
1172 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1173
1174 if (impl->display_server.wl_subsurface)
1175 return FALSE;
1176 else if (impl->use_custom_surface)
1177 return FALSE;
1178 else if (impl->hint == GDK_WINDOW_TYPE_HINT_DND)
1179 return FALSE;
1180 else if (is_realized_popup (window))
1181 return FALSE;
1182 else if (should_map_as_popup (window))
1183 return FALSE;
1184 else if (should_map_as_subsurface (window))
1185 return FALSE;
1186
1187 /* This should now either be, or eventually be, a toplevel window,
1188 * and we should wait for the initial configure to really configure it.
1189 */
1190 return !impl->initial_configure_received;
1191 }
1192
1193 static void
gdk_wayland_window_maybe_configure(GdkWindow * window,int width,int height,int scale)1194 gdk_wayland_window_maybe_configure (GdkWindow *window,
1195 int width,
1196 int height,
1197 int scale)
1198 {
1199 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1200 gboolean is_xdg_popup;
1201 gboolean is_visible;
1202 gboolean size_changed;
1203
1204 impl->unconfigured_width = calculate_width_without_margin (window, width);
1205 impl->unconfigured_height = calculate_height_without_margin (window, height);
1206
1207 if (should_inhibit_resize (window))
1208 return;
1209
1210 size_changed = (window->width != width || window->height != height);
1211 if (!size_changed && impl->scale == scale)
1212 return;
1213
1214 /* For xdg_popup using an xdg_positioner, there is a race condition if
1215 * the application tries to change the size after it's mapped, but before
1216 * the initial configure is received, so hide and show the surface again
1217 * force the new size onto the compositor. See bug #772505.
1218 */
1219
1220 is_xdg_popup = is_realized_popup (window);
1221 is_visible = gdk_window_is_visible (window);
1222
1223 if (is_xdg_popup &&
1224 is_visible &&
1225 size_changed &&
1226 !impl->initial_configure_received &&
1227 !impl->configuring_popup)
1228 gdk_window_hide (window);
1229
1230 gdk_wayland_window_configure (window, width, height, scale);
1231
1232 if (is_xdg_popup &&
1233 is_visible &&
1234 size_changed &&
1235 !impl->initial_configure_received &&
1236 !impl->configuring_popup)
1237 gdk_window_show (window);
1238 }
1239
1240 static void
gdk_wayland_window_sync_parent(GdkWindow * window,GdkWindow * parent)1241 gdk_wayland_window_sync_parent (GdkWindow *window,
1242 GdkWindow *parent)
1243 {
1244 GdkWaylandDisplay *display_wayland =
1245 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1246 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1247 GdkWindowImplWayland *impl_parent = NULL;
1248
1249 g_assert (parent == NULL ||
1250 gdk_window_get_display (window) == gdk_window_get_display (parent));
1251
1252 if (!is_realized_toplevel (window))
1253 return;
1254
1255 if (impl->transient_for)
1256 impl_parent = GDK_WINDOW_IMPL_WAYLAND (impl->transient_for->impl);
1257 else if (parent)
1258 impl_parent = GDK_WINDOW_IMPL_WAYLAND (parent->impl);
1259
1260 /* XXX: Is this correct? */
1261 if (impl_parent && !impl_parent->display_server.wl_surface)
1262 return;
1263
1264 switch (display_wayland->shell_variant)
1265 {
1266 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
1267 {
1268 struct xdg_toplevel *parent_toplevel;
1269
1270 if (impl_parent)
1271 parent_toplevel = impl_parent->display_server.xdg_toplevel;
1272 else
1273 parent_toplevel = NULL;
1274
1275 xdg_toplevel_set_parent (impl->display_server.xdg_toplevel,
1276 parent_toplevel);
1277 break;
1278 }
1279 break;
1280 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
1281 {
1282 struct zxdg_toplevel_v6 *parent_toplevel;
1283
1284 if (impl_parent)
1285 parent_toplevel = impl_parent->display_server.zxdg_toplevel_v6;
1286 else
1287 parent_toplevel = NULL;
1288
1289 zxdg_toplevel_v6_set_parent (impl->display_server.zxdg_toplevel_v6,
1290 parent_toplevel);
1291 break;
1292 }
1293 }
1294 }
1295
1296 static void
gdk_wayland_window_sync_parent_of_imported(GdkWindow * window)1297 gdk_wayland_window_sync_parent_of_imported (GdkWindow *window)
1298 {
1299 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1300
1301 if (!impl->display_server.wl_surface)
1302 return;
1303
1304 if (!impl->imported_transient_for)
1305 return;
1306
1307 if (!is_realized_toplevel (window))
1308 return;
1309
1310 zxdg_imported_v1_set_parent_of (impl->imported_transient_for,
1311 impl->display_server.wl_surface);
1312 }
1313
1314 static void
gdk_wayland_window_update_dialogs(GdkWindow * window)1315 gdk_wayland_window_update_dialogs (GdkWindow *window)
1316 {
1317 GdkWaylandDisplay *display_wayland =
1318 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1319 GList *l;
1320
1321 if (!display_wayland->orphan_dialogs)
1322 return;
1323
1324 for (l = display_wayland->orphan_dialogs; l; l = l->next)
1325 {
1326 GdkWindow *w = l->data;
1327 GdkWindowImplWayland *impl;
1328
1329 if (!GDK_IS_WINDOW_IMPL_WAYLAND(w->impl))
1330 continue;
1331
1332 impl = GDK_WINDOW_IMPL_WAYLAND (w->impl);
1333 if (w == window)
1334 continue;
1335 if (impl->hint != GDK_WINDOW_TYPE_HINT_DIALOG)
1336 continue;
1337 if (impl->transient_for)
1338 continue;
1339
1340 /* Update the parent relationship only for dialogs without transients */
1341 gdk_wayland_window_sync_parent (w, window);
1342 }
1343 }
1344
1345 static void
gdk_wayland_window_sync_title(GdkWindow * window)1346 gdk_wayland_window_sync_title (GdkWindow *window)
1347 {
1348 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1349 GdkWaylandDisplay *display_wayland =
1350 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1351
1352 if (!is_realized_toplevel (window))
1353 return;
1354
1355 if (!impl->title)
1356 return;
1357
1358 switch (display_wayland->shell_variant)
1359 {
1360 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
1361 xdg_toplevel_set_title (impl->display_server.xdg_toplevel,
1362 impl->title);
1363 break;
1364 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
1365 zxdg_toplevel_v6_set_title (impl->display_server.zxdg_toplevel_v6,
1366 impl->title);
1367 break;
1368 }
1369 }
1370
1371 static void
gdk_wayland_window_get_window_geometry(GdkWindow * window,GdkRectangle * geometry)1372 gdk_wayland_window_get_window_geometry (GdkWindow *window,
1373 GdkRectangle *geometry)
1374 {
1375 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1376
1377 *geometry = (GdkRectangle) {
1378 .x = impl->margin_left,
1379 .y = impl->margin_top,
1380 .width = calculate_width_without_margin (window, window->width),
1381 .height = calculate_height_without_margin (window, window->height)
1382 };
1383 }
1384
1385 static void
gdk_wayland_window_sync_margin(GdkWindow * window)1386 gdk_wayland_window_sync_margin (GdkWindow *window)
1387 {
1388 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1389 GdkWaylandDisplay *display_wayland =
1390 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1391 GdkRectangle geometry;
1392
1393 if (!is_realized_shell_surface (window))
1394 return;
1395
1396 gdk_wayland_window_get_window_geometry (window, &geometry);
1397
1398 g_return_if_fail (geometry.width > 0 && geometry.height > 0);
1399
1400 gdk_window_set_geometry_hints (window,
1401 &impl->geometry_hints,
1402 impl->geometry_mask);
1403
1404 switch (display_wayland->shell_variant)
1405 {
1406 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
1407 xdg_surface_set_window_geometry (impl->display_server.xdg_surface,
1408 geometry.x,
1409 geometry.y,
1410 geometry.width,
1411 geometry.height);
1412 break;
1413 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
1414 zxdg_surface_v6_set_window_geometry (impl->display_server.zxdg_surface_v6,
1415 geometry.x,
1416 geometry.y,
1417 geometry.width,
1418 geometry.height);
1419 break;
1420 }
1421 }
1422
1423 static struct wl_region *
wl_region_from_cairo_region(GdkWaylandDisplay * display,cairo_region_t * region)1424 wl_region_from_cairo_region (GdkWaylandDisplay *display,
1425 cairo_region_t *region)
1426 {
1427 struct wl_region *wl_region;
1428 int i, n_rects;
1429
1430 wl_region = wl_compositor_create_region (display->compositor);
1431 if (wl_region == NULL)
1432 return NULL;
1433
1434 n_rects = cairo_region_num_rectangles (region);
1435 for (i = 0; i < n_rects; i++)
1436 {
1437 cairo_rectangle_int_t rect;
1438 cairo_region_get_rectangle (region, i, &rect);
1439 wl_region_add (wl_region, rect.x, rect.y, rect.width, rect.height);
1440 }
1441
1442 return wl_region;
1443 }
1444
1445 static void
gdk_wayland_window_sync_opaque_region(GdkWindow * window)1446 gdk_wayland_window_sync_opaque_region (GdkWindow *window)
1447 {
1448 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1449 struct wl_region *wl_region = NULL;
1450
1451 if (!impl->display_server.wl_surface)
1452 return;
1453
1454 if (!impl->opaque_region_dirty)
1455 return;
1456
1457 if (impl->opaque_region != NULL)
1458 wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_window_get_display (window)),
1459 impl->opaque_region);
1460
1461 wl_surface_set_opaque_region (impl->display_server.wl_surface, wl_region);
1462
1463 if (wl_region != NULL)
1464 wl_region_destroy (wl_region);
1465
1466 impl->opaque_region_dirty = FALSE;
1467 }
1468
1469 static void
gdk_wayland_window_sync_input_region(GdkWindow * window)1470 gdk_wayland_window_sync_input_region (GdkWindow *window)
1471 {
1472 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1473 struct wl_region *wl_region = NULL;
1474
1475 if (!impl->display_server.wl_surface)
1476 return;
1477
1478 if (!impl->input_region_dirty)
1479 return;
1480
1481 if (impl->input_region != NULL)
1482 wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_window_get_display (window)),
1483 impl->input_region);
1484
1485 wl_surface_set_input_region (impl->display_server.wl_surface, wl_region);
1486
1487 if (wl_region != NULL)
1488 wl_region_destroy (wl_region);
1489
1490 impl->input_region_dirty = FALSE;
1491 }
1492
1493 static void
gdk_wayland_set_input_region_if_empty(GdkWindow * window)1494 gdk_wayland_set_input_region_if_empty (GdkWindow *window)
1495 {
1496 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1497 GdkWaylandDisplay *display;
1498 struct wl_region *empty;
1499
1500 if (!impl->input_region_dirty)
1501 return;
1502
1503 if (impl->input_region == NULL)
1504 return;
1505
1506 if (!cairo_region_is_empty (impl->input_region))
1507 return;
1508
1509 display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1510 empty = wl_compositor_create_region (display->compositor);
1511
1512 wl_surface_set_input_region (impl->display_server.wl_surface, empty);
1513 wl_region_destroy (empty);
1514
1515 impl->input_region_dirty = FALSE;
1516 }
1517
1518 static void
surface_enter(void * data,struct wl_surface * wl_surface,struct wl_output * output)1519 surface_enter (void *data,
1520 struct wl_surface *wl_surface,
1521 struct wl_output *output)
1522 {
1523 GdkWindow *window = GDK_WINDOW (data);
1524 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1525 GdkWaylandDisplay *display_wayland =
1526 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1527 gboolean output_is_unmanaged;
1528
1529 output_is_unmanaged =
1530 _gdk_wayland_screen_get_output_scale (display_wayland->screen, output) == 0;
1531 if (output_is_unmanaged)
1532 return;
1533
1534 GDK_NOTE (EVENTS,
1535 g_message ("surface enter, window %p output %p", window, output));
1536
1537 impl->display_server.outputs = g_slist_prepend (impl->display_server.outputs, output);
1538
1539 window_update_scale (window);
1540 }
1541
1542 static void
surface_leave(void * data,struct wl_surface * wl_surface,struct wl_output * output)1543 surface_leave (void *data,
1544 struct wl_surface *wl_surface,
1545 struct wl_output *output)
1546 {
1547 GdkWindow *window = GDK_WINDOW (data);
1548 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1549
1550 GDK_NOTE (EVENTS,
1551 g_message ("surface leave, window %p output %p", window, output));
1552
1553 impl->display_server.outputs = g_slist_remove (impl->display_server.outputs, output);
1554
1555 if (impl->display_server.outputs)
1556 window_update_scale (window);
1557 }
1558
1559 static const struct wl_surface_listener surface_listener = {
1560 surface_enter,
1561 surface_leave
1562 };
1563
1564 static void
on_parent_surface_committed(GdkWindowImplWayland * parent_impl,GdkWindow * window)1565 on_parent_surface_committed (GdkWindowImplWayland *parent_impl,
1566 GdkWindow *window)
1567 {
1568 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1569
1570 g_signal_handler_disconnect (parent_impl,
1571 impl->parent_surface_committed_handler);
1572 impl->parent_surface_committed_handler = 0;
1573
1574 wl_subsurface_set_desync (impl->display_server.wl_subsurface);
1575
1576 /* Special case if the input region is empty, it won't change on resize */
1577 gdk_wayland_set_input_region_if_empty (window);
1578 }
1579
1580 static void
gdk_wayland_window_set_subsurface_position(GdkWindow * window,int x,int y)1581 gdk_wayland_window_set_subsurface_position (GdkWindow *window,
1582 int x,
1583 int y)
1584 {
1585 GdkWindowImplWayland *impl;
1586
1587 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1588
1589 wl_subsurface_set_position (impl->display_server.wl_subsurface, x, y);
1590 impl->subsurface_x = x;
1591 impl->subsurface_y = y;
1592
1593 gdk_window_request_transient_parent_commit (window);
1594 }
1595
1596 static void
gdk_wayland_window_create_subsurface(GdkWindow * window)1597 gdk_wayland_window_create_subsurface (GdkWindow *window)
1598 {
1599 GdkWindowImplWayland *impl, *parent_impl = NULL;
1600 GdkWaylandDisplay *display_wayland;
1601
1602 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1603
1604 if (!impl->display_server.wl_surface)
1605 return; /* Bail out, surface and subsurface will be created later when shown */
1606
1607 if (impl->display_server.wl_subsurface)
1608 return;
1609
1610 if (impl->transient_for)
1611 parent_impl = GDK_WINDOW_IMPL_WAYLAND (impl->transient_for->impl);
1612
1613 if (parent_impl && parent_impl->display_server.wl_surface)
1614 {
1615 display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1616 impl->display_server.wl_subsurface =
1617 wl_subcompositor_get_subsurface (display_wayland->subcompositor,
1618 impl->display_server.wl_surface, parent_impl->display_server.wl_surface);
1619
1620 /* In order to synchronize the initial position with the initial frame
1621 * content, wait with making the subsurface desynchronized until after
1622 * the parent was committed.
1623 */
1624 impl->parent_surface_committed_handler =
1625 g_signal_connect_object (parent_impl, "committed",
1626 G_CALLBACK (on_parent_surface_committed),
1627 window, 0);
1628
1629 gdk_wayland_window_set_subsurface_position (window,
1630 window->x + window->abs_x,
1631 window->y + window->abs_y);
1632 }
1633 }
1634
1635 static void
gdk_wayland_window_create_surface(GdkWindow * window)1636 gdk_wayland_window_create_surface (GdkWindow *window)
1637 {
1638 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1639 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1640
1641 impl->display_server.wl_surface = wl_compositor_create_surface (display_wayland->compositor);
1642 wl_surface_add_listener (impl->display_server.wl_surface, &surface_listener, window);
1643 }
1644
1645 static gboolean
should_use_fixed_size(GdkWindowState state)1646 should_use_fixed_size (GdkWindowState state)
1647 {
1648 return state & (GDK_WINDOW_STATE_MAXIMIZED |
1649 GDK_WINDOW_STATE_FULLSCREEN |
1650 GDK_WINDOW_STATE_TILED);
1651 }
1652
1653 static void
gdk_wayland_window_handle_configure(GdkWindow * window,uint32_t serial)1654 gdk_wayland_window_handle_configure (GdkWindow *window,
1655 uint32_t serial)
1656 {
1657 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1658 GdkWaylandDisplay *display_wayland =
1659 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1660 GdkWindowState new_state;
1661 int width = impl->pending.width;
1662 int height = impl->pending.height;
1663 gboolean fixed_size;
1664 gboolean saved_size;
1665
1666 if (!impl->initial_configure_received)
1667 {
1668 gdk_window_thaw_updates (window);
1669 impl->initial_configure_received = TRUE;
1670 }
1671
1672 if (impl->display_server.xdg_popup)
1673 {
1674 xdg_surface_ack_configure (impl->display_server.xdg_surface, serial);
1675 return;
1676 }
1677 else if (impl->display_server.zxdg_popup_v6)
1678 {
1679 zxdg_surface_v6_ack_configure (impl->display_server.zxdg_surface_v6,
1680 serial);
1681 return;
1682 }
1683
1684 new_state = impl->pending.state;
1685 impl->pending.state = 0;
1686
1687 fixed_size = should_use_fixed_size (new_state);
1688
1689 saved_size = (width == 0 && height == 0);
1690 /* According to xdg_shell, an xdg_surface.configure with size 0x0
1691 * should be interpreted as that it is up to the client to set a
1692 * size.
1693 *
1694 * When transitioning from maximize or fullscreen state, this means
1695 * the client should configure its size back to what it was before
1696 * being maximize or fullscreen.
1697 * Additionally, if we receive a manual resize request, we must prefer this
1698 * new size instead of the compositor's size hints.
1699 * In such a scenario, and without letting the compositor know about the new
1700 * size, the client has to manage all dimensions and ignore any server hints.
1701 */
1702 if (!fixed_size && (saved_size || impl->saved_size_changed))
1703 {
1704 width = impl->saved_width;
1705 height = impl->saved_height;
1706 impl->saved_size_changed = FALSE;
1707 }
1708
1709 if (width > 0 && height > 0)
1710 {
1711 GdkWindowHints geometry_mask = impl->geometry_mask;
1712 int configure_width;
1713 int configure_height;
1714
1715 /* Ignore size increments for maximized/fullscreen windows */
1716 if (fixed_size)
1717 geometry_mask &= ~GDK_HINT_RESIZE_INC;
1718 if (!saved_size)
1719 {
1720 /* Do not reapply contrains if we are restoring original size */
1721 gdk_window_constrain_size (&impl->geometry_hints,
1722 geometry_mask,
1723 calculate_width_with_margin (window, width),
1724 calculate_height_with_margin (window, height),
1725 &width,
1726 &height);
1727
1728 /* Save size for next time we get 0x0 */
1729 _gdk_wayland_window_save_size (window);
1730 }
1731
1732 if (saved_size)
1733 {
1734 configure_width = calculate_width_with_margin (window, width);
1735 configure_height = calculate_height_with_margin (window, height);
1736 }
1737 else
1738 {
1739 configure_width = width;
1740 configure_height = height;
1741 }
1742 gdk_wayland_window_configure (window,
1743 configure_width,
1744 configure_height,
1745 impl->scale);
1746 }
1747 else
1748 {
1749 int unconfigured_width;
1750 int unconfigured_height;
1751
1752 unconfigured_width =
1753 calculate_width_with_margin (window, impl->unconfigured_width);
1754 unconfigured_height =
1755 calculate_height_with_margin (window, impl->unconfigured_height);
1756 gdk_wayland_window_configure (window,
1757 unconfigured_width,
1758 unconfigured_height,
1759 impl->scale);
1760 }
1761
1762 if (fixed_size)
1763 {
1764 impl->fixed_size_width = width;
1765 impl->fixed_size_height = height;
1766 }
1767
1768 GDK_NOTE (EVENTS,
1769 g_message ("configure, window %p %dx%d,%s%s%s%s",
1770 window, width, height,
1771 (new_state & GDK_WINDOW_STATE_FULLSCREEN) ? " fullscreen" : "",
1772 (new_state & GDK_WINDOW_STATE_MAXIMIZED) ? " maximized" : "",
1773 (new_state & GDK_WINDOW_STATE_FOCUSED) ? " focused" : "",
1774 (new_state & GDK_WINDOW_STATE_TILED) ? " tiled" : ""));
1775
1776 _gdk_set_window_state (window, new_state);
1777
1778 switch (display_wayland->shell_variant)
1779 {
1780 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
1781 xdg_surface_ack_configure (impl->display_server.xdg_surface, serial);
1782 break;
1783 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
1784 zxdg_surface_v6_ack_configure (impl->display_server.zxdg_surface_v6,
1785 serial);
1786 break;
1787 }
1788
1789 if (impl->hint != GDK_WINDOW_TYPE_HINT_DIALOG &&
1790 new_state & GDK_WINDOW_STATE_FOCUSED)
1791 gdk_wayland_window_update_dialogs (window);
1792 }
1793
1794 static void
gdk_wayland_window_handle_configure_toplevel(GdkWindow * window,int32_t width,int32_t height,GdkWindowState state)1795 gdk_wayland_window_handle_configure_toplevel (GdkWindow *window,
1796 int32_t width,
1797 int32_t height,
1798 GdkWindowState state)
1799 {
1800 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1801
1802 impl->pending.state |= state;
1803 impl->pending.width = width;
1804 impl->pending.height = height;
1805 }
1806
1807 static void
gdk_wayland_window_handle_close(GdkWindow * window)1808 gdk_wayland_window_handle_close (GdkWindow *window)
1809 {
1810 GdkDisplay *display;
1811 GdkEvent *event;
1812
1813 GDK_NOTE (EVENTS,
1814 g_message ("close %p", window));
1815
1816 event = gdk_event_new (GDK_DELETE);
1817 event->any.window = g_object_ref (window);
1818 event->any.send_event = TRUE;
1819
1820 display = gdk_window_get_display (window);
1821 _gdk_wayland_display_deliver_event (display, event);
1822 }
1823
1824 static void
xdg_surface_configure(void * data,struct xdg_surface * xdg_surface,uint32_t serial)1825 xdg_surface_configure (void *data,
1826 struct xdg_surface *xdg_surface,
1827 uint32_t serial)
1828 {
1829 GdkWindow *window = GDK_WINDOW (data);
1830
1831 gdk_wayland_window_handle_configure (window, serial);
1832 }
1833
1834 static const struct xdg_surface_listener xdg_surface_listener = {
1835 xdg_surface_configure,
1836 };
1837
1838 static void
xdg_toplevel_configure(void * data,struct xdg_toplevel * xdg_toplevel,int32_t width,int32_t height,struct wl_array * states)1839 xdg_toplevel_configure (void *data,
1840 struct xdg_toplevel *xdg_toplevel,
1841 int32_t width,
1842 int32_t height,
1843 struct wl_array *states)
1844 {
1845 GdkWindow *window = GDK_WINDOW (data);
1846 uint32_t *p;
1847 GdkWindowState pending_state = 0;
1848
1849 wl_array_for_each (p, states)
1850 {
1851 uint32_t state = *p;
1852
1853 switch (state)
1854 {
1855 case XDG_TOPLEVEL_STATE_FULLSCREEN:
1856 pending_state |= GDK_WINDOW_STATE_FULLSCREEN;
1857 break;
1858 case XDG_TOPLEVEL_STATE_MAXIMIZED:
1859 pending_state |= GDK_WINDOW_STATE_MAXIMIZED;
1860 break;
1861 case XDG_TOPLEVEL_STATE_ACTIVATED:
1862 pending_state |= GDK_WINDOW_STATE_FOCUSED;
1863 break;
1864 case XDG_TOPLEVEL_STATE_RESIZING:
1865 break;
1866 default:
1867 /* Unknown state */
1868 break;
1869 }
1870 }
1871
1872 gdk_wayland_window_handle_configure_toplevel (window, width, height,
1873 pending_state);
1874 }
1875
1876 static void
xdg_toplevel_close(void * data,struct xdg_toplevel * xdg_toplevel)1877 xdg_toplevel_close (void *data,
1878 struct xdg_toplevel *xdg_toplevel)
1879 {
1880 GdkWindow *window = GDK_WINDOW (data);
1881
1882 gdk_wayland_window_handle_close (window);
1883 }
1884
1885 static const struct xdg_toplevel_listener xdg_toplevel_listener = {
1886 xdg_toplevel_configure,
1887 xdg_toplevel_close,
1888 };
1889
1890 static void
create_xdg_toplevel_resources(GdkWindow * window)1891 create_xdg_toplevel_resources (GdkWindow *window)
1892 {
1893 GdkWaylandDisplay *display_wayland =
1894 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1895 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1896
1897 impl->display_server.xdg_surface =
1898 xdg_wm_base_get_xdg_surface (display_wayland->xdg_wm_base,
1899 impl->display_server.wl_surface);
1900 xdg_surface_add_listener (impl->display_server.xdg_surface,
1901 &xdg_surface_listener,
1902 window);
1903
1904 impl->display_server.xdg_toplevel =
1905 xdg_surface_get_toplevel (impl->display_server.xdg_surface);
1906 xdg_toplevel_add_listener (impl->display_server.xdg_toplevel,
1907 &xdg_toplevel_listener,
1908 window);
1909 }
1910
1911 static void
zxdg_surface_v6_configure(void * data,struct zxdg_surface_v6 * xdg_surface,uint32_t serial)1912 zxdg_surface_v6_configure (void *data,
1913 struct zxdg_surface_v6 *xdg_surface,
1914 uint32_t serial)
1915 {
1916 GdkWindow *window = GDK_WINDOW (data);
1917
1918 gdk_wayland_window_handle_configure (window, serial);
1919 }
1920
1921 static const struct zxdg_surface_v6_listener zxdg_surface_v6_listener = {
1922 zxdg_surface_v6_configure,
1923 };
1924
1925 static void
zxdg_toplevel_v6_configure(void * data,struct zxdg_toplevel_v6 * xdg_toplevel,int32_t width,int32_t height,struct wl_array * states)1926 zxdg_toplevel_v6_configure (void *data,
1927 struct zxdg_toplevel_v6 *xdg_toplevel,
1928 int32_t width,
1929 int32_t height,
1930 struct wl_array *states)
1931 {
1932 GdkWindow *window = GDK_WINDOW (data);
1933 uint32_t *p;
1934 GdkWindowState pending_state = 0;
1935
1936 wl_array_for_each (p, states)
1937 {
1938 uint32_t state = *p;
1939
1940 switch (state)
1941 {
1942 case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN:
1943 pending_state |= GDK_WINDOW_STATE_FULLSCREEN;
1944 break;
1945 case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED:
1946 pending_state |= GDK_WINDOW_STATE_MAXIMIZED;
1947 break;
1948 case ZXDG_TOPLEVEL_V6_STATE_ACTIVATED:
1949 pending_state |= GDK_WINDOW_STATE_FOCUSED;
1950 break;
1951 case ZXDG_TOPLEVEL_V6_STATE_RESIZING:
1952 break;
1953 default:
1954 /* Unknown state */
1955 break;
1956 }
1957 }
1958
1959 gdk_wayland_window_handle_configure_toplevel (window, width, height,
1960 pending_state);
1961 }
1962
1963 static void
zxdg_toplevel_v6_close(void * data,struct zxdg_toplevel_v6 * xdg_toplevel)1964 zxdg_toplevel_v6_close (void *data,
1965 struct zxdg_toplevel_v6 *xdg_toplevel)
1966 {
1967 GdkWindow *window = GDK_WINDOW (data);
1968
1969 gdk_wayland_window_handle_close (window);
1970 }
1971
1972 static const struct zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = {
1973 zxdg_toplevel_v6_configure,
1974 zxdg_toplevel_v6_close,
1975 };
1976
1977 static void
create_zxdg_toplevel_v6_resources(GdkWindow * window)1978 create_zxdg_toplevel_v6_resources (GdkWindow *window)
1979 {
1980 GdkWaylandDisplay *display_wayland =
1981 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1982 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1983
1984 impl->display_server.zxdg_surface_v6 =
1985 zxdg_shell_v6_get_xdg_surface (display_wayland->zxdg_shell_v6,
1986 impl->display_server.wl_surface);
1987 zxdg_surface_v6_add_listener (impl->display_server.zxdg_surface_v6,
1988 &zxdg_surface_v6_listener,
1989 window);
1990
1991 impl->display_server.zxdg_toplevel_v6 =
1992 zxdg_surface_v6_get_toplevel (impl->display_server.zxdg_surface_v6);
1993 zxdg_toplevel_v6_add_listener (impl->display_server.zxdg_toplevel_v6,
1994 &zxdg_toplevel_v6_listener,
1995 window);
1996 }
1997
1998 void
gdk_wayland_window_set_application_id(GdkWindow * window,const char * application_id)1999 gdk_wayland_window_set_application_id (GdkWindow *window, const char* application_id)
2000 {
2001 GdkWindowImplWayland *impl;
2002 GdkWaylandDisplay *display_wayland;
2003
2004 g_return_if_fail (application_id != NULL);
2005
2006 if (GDK_WINDOW_DESTROYED (window))
2007 return;
2008
2009 if (!is_realized_toplevel (window))
2010 return;
2011
2012 display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
2013 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
2014
2015 switch (display_wayland->shell_variant)
2016 {
2017 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
2018 xdg_toplevel_set_app_id (impl->display_server.xdg_toplevel,
2019 application_id);
2020 break;
2021 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
2022 zxdg_toplevel_v6_set_app_id (impl->display_server.zxdg_toplevel_v6,
2023 application_id);
2024 break;
2025 }
2026 }
2027
2028 static void
gdk_wayland_window_create_xdg_toplevel(GdkWindow * window)2029 gdk_wayland_window_create_xdg_toplevel (GdkWindow *window)
2030 {
2031 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
2032 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
2033 const gchar *app_id;
2034 GdkScreen *screen = gdk_window_get_screen (window);
2035 struct wl_output *fullscreen_output = NULL;
2036
2037 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
2038 if (impl->initial_fullscreen_monitor >= 0 &&
2039 impl->initial_fullscreen_monitor < gdk_screen_get_n_monitors (screen))
2040 fullscreen_output =
2041 _gdk_wayland_screen_get_wl_output (screen,
2042 impl->initial_fullscreen_monitor);
2043 G_GNUC_END_IGNORE_DEPRECATIONS
2044
2045 gdk_window_freeze_updates (window);
2046
2047 switch (display_wayland->shell_variant)
2048 {
2049 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
2050 create_xdg_toplevel_resources (window);
2051 break;
2052 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
2053 create_zxdg_toplevel_v6_resources (window);
2054 break;
2055 }
2056
2057 gdk_wayland_window_sync_parent (window, NULL);
2058 gdk_wayland_window_sync_parent_of_imported (window);
2059 gdk_wayland_window_sync_title (window);
2060
2061 switch (display_wayland->shell_variant)
2062 {
2063 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
2064 if (window->state & GDK_WINDOW_STATE_MAXIMIZED)
2065 xdg_toplevel_set_maximized (impl->display_server.xdg_toplevel);
2066 if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
2067 xdg_toplevel_set_fullscreen (impl->display_server.xdg_toplevel,
2068 fullscreen_output);
2069 break;
2070 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
2071 if (window->state & GDK_WINDOW_STATE_MAXIMIZED)
2072 zxdg_toplevel_v6_set_maximized (impl->display_server.zxdg_toplevel_v6);
2073 if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
2074 zxdg_toplevel_v6_set_fullscreen (impl->display_server.zxdg_toplevel_v6,
2075 fullscreen_output);
2076 break;
2077 }
2078
2079 app_id = g_get_prgname ();
2080 if (app_id == NULL)
2081 app_id = gdk_get_program_class ();
2082
2083 gdk_wayland_window_set_application_id (window, app_id);
2084
2085 maybe_set_gtk_surface_dbus_properties (window);
2086 maybe_set_gtk_surface_modal (window);
2087
2088 if (impl->hint == GDK_WINDOW_TYPE_HINT_DIALOG)
2089 _gdk_wayland_screen_add_orphan_dialog (window);
2090
2091 wl_surface_commit (impl->display_server.wl_surface);
2092 }
2093
2094 static void
gdk_wayland_window_handle_configure_popup(GdkWindow * window,int32_t x,int32_t y,int32_t width,int32_t height)2095 gdk_wayland_window_handle_configure_popup (GdkWindow *window,
2096 int32_t x,
2097 int32_t y,
2098 int32_t width,
2099 int32_t height)
2100 {
2101 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
2102 GdkRectangle flipped_rect;
2103 GdkRectangle final_rect;
2104 gboolean flipped_x;
2105 gboolean flipped_y;
2106
2107 g_return_if_fail (impl->transient_for);
2108
2109 if (impl->position_method != POSITION_METHOD_MOVE_TO_RECT)
2110 return;
2111
2112 calculate_moved_to_rect_result (window, x, y, width, height,
2113 &flipped_rect,
2114 &final_rect,
2115 &flipped_x,
2116 &flipped_y);
2117
2118 impl->position_method = POSITION_METHOD_MOVE_TO_RECT;
2119
2120 g_signal_emit_by_name (window,
2121 "moved-to-rect",
2122 &flipped_rect,
2123 &final_rect,
2124 flipped_x,
2125 flipped_y);
2126 }
2127
2128 static void
xdg_popup_configure(void * data,struct xdg_popup * xdg_popup,int32_t x,int32_t y,int32_t width,int32_t height)2129 xdg_popup_configure (void *data,
2130 struct xdg_popup *xdg_popup,
2131 int32_t x,
2132 int32_t y,
2133 int32_t width,
2134 int32_t height)
2135 {
2136 GdkWindow *window = GDK_WINDOW (data);
2137
2138 gdk_wayland_window_handle_configure_popup (window, x, y, width, height);
2139 }
2140
2141 static void
xdg_popup_done(void * data,struct xdg_popup * xdg_popup)2142 xdg_popup_done (void *data,
2143 struct xdg_popup *xdg_popup)
2144 {
2145 GdkWindow *window = GDK_WINDOW (data);
2146
2147 GDK_NOTE (EVENTS,
2148 g_message ("done %p", window));
2149
2150 gdk_window_hide (window);
2151 }
2152
2153 static const struct xdg_popup_listener xdg_popup_listener = {
2154 xdg_popup_configure,
2155 xdg_popup_done,
2156 };
2157
2158 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)2159 zxdg_popup_v6_configure (void *data,
2160 struct zxdg_popup_v6 *xdg_popup,
2161 int32_t x,
2162 int32_t y,
2163 int32_t width,
2164 int32_t height)
2165 {
2166 GdkWindow *window = GDK_WINDOW (data);
2167
2168 gdk_wayland_window_handle_configure_popup (window, x, y, width, height);
2169 }
2170
2171 static void
zxdg_popup_v6_done(void * data,struct zxdg_popup_v6 * xdg_popup)2172 zxdg_popup_v6_done (void *data,
2173 struct zxdg_popup_v6 *xdg_popup)
2174 {
2175 GdkWindow *window = GDK_WINDOW (data);
2176
2177 GDK_NOTE (EVENTS,
2178 g_message ("done %p", window));
2179
2180 gdk_window_hide (window);
2181 }
2182
2183 static const struct zxdg_popup_v6_listener zxdg_popup_v6_listener = {
2184 zxdg_popup_v6_configure,
2185 zxdg_popup_v6_done,
2186 };
2187
2188 static enum xdg_positioner_anchor
rect_anchor_to_anchor(GdkGravity rect_anchor)2189 rect_anchor_to_anchor (GdkGravity rect_anchor)
2190 {
2191 switch (rect_anchor)
2192 {
2193 case GDK_GRAVITY_NORTH_WEST:
2194 case GDK_GRAVITY_STATIC:
2195 return XDG_POSITIONER_ANCHOR_TOP_LEFT;
2196 case GDK_GRAVITY_NORTH:
2197 return XDG_POSITIONER_ANCHOR_TOP;
2198 case GDK_GRAVITY_NORTH_EAST:
2199 return XDG_POSITIONER_ANCHOR_TOP_RIGHT;
2200 case GDK_GRAVITY_WEST:
2201 return XDG_POSITIONER_ANCHOR_LEFT;
2202 case GDK_GRAVITY_CENTER:
2203 return XDG_POSITIONER_ANCHOR_NONE;
2204 case GDK_GRAVITY_EAST:
2205 return XDG_POSITIONER_ANCHOR_RIGHT;
2206 case GDK_GRAVITY_SOUTH_WEST:
2207 return XDG_POSITIONER_ANCHOR_BOTTOM_LEFT;
2208 case GDK_GRAVITY_SOUTH:
2209 return XDG_POSITIONER_ANCHOR_BOTTOM;
2210 case GDK_GRAVITY_SOUTH_EAST:
2211 return XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT;
2212 default:
2213 g_assert_not_reached ();
2214 }
2215 }
2216
2217 static enum xdg_positioner_gravity
window_anchor_to_gravity(GdkGravity rect_anchor)2218 window_anchor_to_gravity (GdkGravity rect_anchor)
2219 {
2220 switch (rect_anchor)
2221 {
2222 case GDK_GRAVITY_NORTH_WEST:
2223 case GDK_GRAVITY_STATIC:
2224 return XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT;
2225 case GDK_GRAVITY_NORTH:
2226 return XDG_POSITIONER_GRAVITY_BOTTOM;
2227 case GDK_GRAVITY_NORTH_EAST:
2228 return XDG_POSITIONER_GRAVITY_BOTTOM_LEFT;
2229 case GDK_GRAVITY_WEST:
2230 return XDG_POSITIONER_GRAVITY_RIGHT;
2231 case GDK_GRAVITY_CENTER:
2232 return XDG_POSITIONER_GRAVITY_NONE;
2233 case GDK_GRAVITY_EAST:
2234 return XDG_POSITIONER_GRAVITY_LEFT;
2235 case GDK_GRAVITY_SOUTH_WEST:
2236 return XDG_POSITIONER_GRAVITY_TOP_RIGHT;
2237 case GDK_GRAVITY_SOUTH:
2238 return XDG_POSITIONER_GRAVITY_TOP;
2239 case GDK_GRAVITY_SOUTH_EAST:
2240 return XDG_POSITIONER_GRAVITY_TOP_LEFT;
2241 default:
2242 g_assert_not_reached ();
2243 }
2244 }
2245
2246 static enum zxdg_positioner_v6_anchor
rect_anchor_to_anchor_legacy(GdkGravity rect_anchor)2247 rect_anchor_to_anchor_legacy (GdkGravity rect_anchor)
2248 {
2249 switch (rect_anchor)
2250 {
2251 case GDK_GRAVITY_NORTH_WEST:
2252 case GDK_GRAVITY_STATIC:
2253 return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
2254 ZXDG_POSITIONER_V6_ANCHOR_LEFT);
2255 case GDK_GRAVITY_NORTH:
2256 return ZXDG_POSITIONER_V6_ANCHOR_TOP;
2257 case GDK_GRAVITY_NORTH_EAST:
2258 return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
2259 ZXDG_POSITIONER_V6_ANCHOR_RIGHT);
2260 case GDK_GRAVITY_WEST:
2261 return ZXDG_POSITIONER_V6_ANCHOR_LEFT;
2262 case GDK_GRAVITY_CENTER:
2263 return ZXDG_POSITIONER_V6_ANCHOR_NONE;
2264 case GDK_GRAVITY_EAST:
2265 return ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
2266 case GDK_GRAVITY_SOUTH_WEST:
2267 return (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
2268 ZXDG_POSITIONER_V6_ANCHOR_LEFT);
2269 case GDK_GRAVITY_SOUTH:
2270 return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
2271 case GDK_GRAVITY_SOUTH_EAST:
2272 return (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
2273 ZXDG_POSITIONER_V6_ANCHOR_RIGHT);
2274 default:
2275 g_assert_not_reached ();
2276 }
2277 }
2278
2279 static enum zxdg_positioner_v6_gravity
window_anchor_to_gravity_legacy(GdkGravity rect_anchor)2280 window_anchor_to_gravity_legacy (GdkGravity rect_anchor)
2281 {
2282 switch (rect_anchor)
2283 {
2284 case GDK_GRAVITY_NORTH_WEST:
2285 case GDK_GRAVITY_STATIC:
2286 return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
2287 ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
2288 case GDK_GRAVITY_NORTH:
2289 return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
2290 case GDK_GRAVITY_NORTH_EAST:
2291 return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
2292 ZXDG_POSITIONER_V6_GRAVITY_LEFT);
2293 case GDK_GRAVITY_WEST:
2294 return ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
2295 case GDK_GRAVITY_CENTER:
2296 return ZXDG_POSITIONER_V6_GRAVITY_NONE;
2297 case GDK_GRAVITY_EAST:
2298 return ZXDG_POSITIONER_V6_GRAVITY_LEFT;
2299 case GDK_GRAVITY_SOUTH_WEST:
2300 return (ZXDG_POSITIONER_V6_GRAVITY_TOP |
2301 ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
2302 case GDK_GRAVITY_SOUTH:
2303 return ZXDG_POSITIONER_V6_GRAVITY_TOP;
2304 case GDK_GRAVITY_SOUTH_EAST:
2305 return (ZXDG_POSITIONER_V6_GRAVITY_TOP |
2306 ZXDG_POSITIONER_V6_GRAVITY_LEFT);
2307 default:
2308 g_assert_not_reached ();
2309 }
2310 }
2311
2312 static void
kwin_server_decoration_mode_set(void * data,struct org_kde_kwin_server_decoration * org_kde_kwin_server_decoration,uint32_t mode)2313 kwin_server_decoration_mode_set (void *data, struct org_kde_kwin_server_decoration *org_kde_kwin_server_decoration, uint32_t mode)
2314 {
2315 GdkWindow *window = GDK_WINDOW (data);
2316 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
2317
2318 if ((mode == ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER && impl->using_csd) ||
2319 (mode == ORG_KDE_KWIN_SERVER_DECORATION_MODE_CLIENT && !impl->using_csd))
2320 gdk_wayland_window_announce_decoration_mode (window);
2321 }
2322
2323 static const struct org_kde_kwin_server_decoration_listener kwin_server_decoration_listener = {
2324 kwin_server_decoration_mode_set
2325 };
2326
2327 static void
gdk_wayland_window_announce_decoration_mode(GdkWindow * window)2328 gdk_wayland_window_announce_decoration_mode (GdkWindow *window)
2329 {
2330 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
2331 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
2332
2333 if (!display_wayland->server_decoration_manager)
2334 return;
2335 if (!impl->display_server.server_decoration)
2336 {
2337 impl->display_server.server_decoration =
2338 org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
2339 impl->display_server.wl_surface);
2340 org_kde_kwin_server_decoration_add_listener (impl->display_server.server_decoration,
2341 &kwin_server_decoration_listener,
2342 window);
2343 }
2344
2345 if (impl->display_server.server_decoration)
2346 {
2347 if (impl->using_csd)
2348 org_kde_kwin_server_decoration_request_mode (impl->display_server.server_decoration,
2349 ORG_KDE_KWIN_SERVER_DECORATION_MODE_CLIENT);
2350 else
2351 org_kde_kwin_server_decoration_request_mode (impl->display_server.server_decoration,
2352 ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER);
2353 }
2354 }
2355
2356 void
gdk_wayland_window_announce_csd(GdkWindow * window)2357 gdk_wayland_window_announce_csd (GdkWindow *window)
2358 {
2359 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
2360
2361 impl->using_csd = TRUE;
2362 if (impl->mapped)
2363 gdk_wayland_window_announce_decoration_mode (window);
2364 }
2365
2366 void
gdk_wayland_window_announce_ssd(GdkWindow * window)2367 gdk_wayland_window_announce_ssd (GdkWindow *window)
2368 {
2369 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
2370
2371 impl->using_csd = FALSE;
2372 if (impl->mapped)
2373 gdk_wayland_window_announce_decoration_mode (window);
2374 }
2375
2376 static GdkWindow *
get_real_parent_and_translate(GdkWindow * window,gint * x,gint * y)2377 get_real_parent_and_translate (GdkWindow *window,
2378 gint *x,
2379 gint *y)
2380 {
2381 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
2382 GdkWindow *parent = impl->transient_for;
2383
2384 while (parent)
2385 {
2386 GdkWindowImplWayland *parent_impl =
2387 GDK_WINDOW_IMPL_WAYLAND (parent->impl);
2388 GdkWindow *effective_parent = gdk_window_get_effective_parent (parent);
2389
2390 if (parent == NULL || (gdk_window_has_native (parent) &&
2391 !parent_impl->display_server.wl_subsurface) ||
2392 !effective_parent)
2393 break;
2394
2395 *x += parent->x;
2396 *y += parent->y;
2397
2398 if (gdk_window_has_native (parent) &&
2399 parent_impl->display_server.wl_subsurface)
2400 parent = parent->transient_for;
2401 else
2402 parent = effective_parent;
2403 }
2404
2405 return parent;
2406 }
2407
2408 static void
translate_to_real_parent_window_geometry(GdkWindow * window,gint * x,gint * y)2409 translate_to_real_parent_window_geometry (GdkWindow *window,
2410 gint *x,
2411 gint *y)
2412 {
2413 GdkWindow *parent;
2414
2415 parent = get_real_parent_and_translate (window, x, y);
2416
2417 if (parent != NULL) {
2418 *x -= parent->shadow_left;
2419 *y -= parent->shadow_top;
2420 }
2421 }
2422
2423 static GdkWindow *
translate_from_real_parent_window_geometry(GdkWindow * window,gint * x,gint * y)2424 translate_from_real_parent_window_geometry (GdkWindow *window,
2425 gint *x,
2426 gint *y)
2427 {
2428 GdkWindow *parent;
2429 gint dx = 0;
2430 gint dy = 0;
2431
2432 parent = get_real_parent_and_translate (window, &dx, &dy);
2433
2434 *x -= dx;
2435 *y -= dy;
2436
2437 if (parent != NULL) {
2438 *x += parent->shadow_left;
2439 *y += parent->shadow_top;
2440 }
2441
2442 return parent;
2443 }
2444
2445 static void
calculate_popup_rect(GdkWindow * window,GdkGravity rect_anchor,GdkGravity window_anchor,GdkRectangle * out_rect)2446 calculate_popup_rect (GdkWindow *window,
2447 GdkGravity rect_anchor,
2448 GdkGravity window_anchor,
2449 GdkRectangle *out_rect)
2450 {
2451 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
2452 GdkRectangle geometry;
2453 GdkRectangle anchor_rect;
2454 int x = 0, y = 0;
2455
2456 gdk_wayland_window_get_window_geometry (window, &geometry);
2457
2458 anchor_rect = (GdkRectangle) {
2459 .x = (impl->pending_move_to_rect.rect.x +
2460 impl->pending_move_to_rect.rect_anchor_dx),
2461 .y = (impl->pending_move_to_rect.rect.y +
2462 impl->pending_move_to_rect.rect_anchor_dy),
2463 .width = impl->pending_move_to_rect.rect.width,
2464 .height = impl->pending_move_to_rect.rect.height
2465 };
2466
2467 switch (rect_anchor)
2468 {
2469 case GDK_GRAVITY_STATIC:
2470 case GDK_GRAVITY_NORTH_WEST:
2471 x = anchor_rect.x;
2472 y = anchor_rect.y;
2473 break;
2474 case GDK_GRAVITY_NORTH:
2475 x = anchor_rect.x + (anchor_rect.width / 2);
2476 y = anchor_rect.y;
2477 break;
2478 case GDK_GRAVITY_NORTH_EAST:
2479 x = anchor_rect.x + anchor_rect.width;
2480 y = anchor_rect.y;
2481 break;
2482 case GDK_GRAVITY_WEST:
2483 x = anchor_rect.x;
2484 y = anchor_rect.y + (anchor_rect.height / 2);
2485 break;
2486 case GDK_GRAVITY_CENTER:
2487 x = anchor_rect.x + (anchor_rect.width / 2);
2488 y = anchor_rect.y + (anchor_rect.height / 2);
2489 break;
2490 case GDK_GRAVITY_EAST:
2491 x = anchor_rect.x + anchor_rect.width;
2492 y = anchor_rect.y + (anchor_rect.height / 2);
2493 break;
2494 case GDK_GRAVITY_SOUTH_WEST:
2495 x = anchor_rect.x;
2496 y = anchor_rect.y + anchor_rect.height;
2497 break;
2498 case GDK_GRAVITY_SOUTH:
2499 x = anchor_rect.x + (anchor_rect.width / 2);
2500 y = anchor_rect.y + anchor_rect.height;
2501 break;
2502 case GDK_GRAVITY_SOUTH_EAST:
2503 x = anchor_rect.x + anchor_rect.width;
2504 y = anchor_rect.y + anchor_rect.height;
2505 break;
2506 }
2507
2508 switch (window_anchor)
2509 {
2510 case GDK_GRAVITY_STATIC:
2511 case GDK_GRAVITY_NORTH_WEST:
2512 break;
2513 case GDK_GRAVITY_NORTH:
2514 x -= geometry.width / 2;
2515 break;
2516 case GDK_GRAVITY_NORTH_EAST:
2517 x -= geometry.width;
2518 break;
2519 case GDK_GRAVITY_WEST:
2520 y -= geometry.height / 2;
2521 break;
2522 case GDK_GRAVITY_CENTER:
2523 x -= geometry.width / 2;
2524 y -= geometry.height / 2;
2525 break;
2526 case GDK_GRAVITY_EAST:
2527 x -= geometry.width;
2528 y -= geometry.height / 2;
2529 break;
2530 case GDK_GRAVITY_SOUTH_WEST:
2531 y -= geometry.height;
2532 break;
2533 case GDK_GRAVITY_SOUTH:
2534 x -= geometry.width / 2;
2535 y -= geometry.height;
2536 break;
2537 case GDK_GRAVITY_SOUTH_EAST:
2538 x -= geometry.width;
2539 y -= geometry.height;
2540 break;
2541 }
2542
2543 *out_rect = (GdkRectangle) {
2544 .x = x,
2545 .y = y,
2546 .width = geometry.width,
2547 .height = geometry.height
2548 };
2549 }
2550
2551 static GdkGravity
flip_anchor_horizontally(GdkGravity anchor)2552 flip_anchor_horizontally (GdkGravity anchor)
2553 {
2554 switch (anchor)
2555 {
2556 case GDK_GRAVITY_STATIC:
2557 case GDK_GRAVITY_NORTH_WEST:
2558 return GDK_GRAVITY_NORTH_EAST;
2559 case GDK_GRAVITY_NORTH:
2560 return GDK_GRAVITY_NORTH;
2561 case GDK_GRAVITY_NORTH_EAST:
2562 return GDK_GRAVITY_NORTH_WEST;
2563 case GDK_GRAVITY_WEST:
2564 return GDK_GRAVITY_EAST;
2565 case GDK_GRAVITY_CENTER:
2566 return GDK_GRAVITY_CENTER;
2567 case GDK_GRAVITY_EAST:
2568 return GDK_GRAVITY_WEST;
2569 case GDK_GRAVITY_SOUTH_WEST:
2570 return GDK_GRAVITY_SOUTH_EAST;
2571 case GDK_GRAVITY_SOUTH:
2572 return GDK_GRAVITY_SOUTH;
2573 case GDK_GRAVITY_SOUTH_EAST:
2574 return GDK_GRAVITY_SOUTH_WEST;
2575 }
2576
2577 g_assert_not_reached ();
2578 }
2579
2580 static GdkGravity
flip_anchor_vertically(GdkGravity anchor)2581 flip_anchor_vertically (GdkGravity anchor)
2582 {
2583 switch (anchor)
2584 {
2585 case GDK_GRAVITY_STATIC:
2586 case GDK_GRAVITY_NORTH_WEST:
2587 return GDK_GRAVITY_SOUTH_WEST;
2588 case GDK_GRAVITY_NORTH:
2589 return GDK_GRAVITY_SOUTH;
2590 case GDK_GRAVITY_NORTH_EAST:
2591 return GDK_GRAVITY_SOUTH_EAST;
2592 case GDK_GRAVITY_WEST:
2593 return GDK_GRAVITY_WEST;
2594 case GDK_GRAVITY_CENTER:
2595 return GDK_GRAVITY_CENTER;
2596 case GDK_GRAVITY_EAST:
2597 return GDK_GRAVITY_EAST;
2598 case GDK_GRAVITY_SOUTH_WEST:
2599 return GDK_GRAVITY_NORTH_WEST;
2600 case GDK_GRAVITY_SOUTH:
2601 return GDK_GRAVITY_NORTH;
2602 case GDK_GRAVITY_SOUTH_EAST:
2603 return GDK_GRAVITY_NORTH_EAST;
2604 }
2605
2606 g_assert_not_reached ();
2607 }
2608
2609 static void
calculate_moved_to_rect_result(GdkWindow * window,int x,int y,int width,int height,GdkRectangle * flipped_rect,GdkRectangle * final_rect,gboolean * flipped_x,gboolean * flipped_y)2610 calculate_moved_to_rect_result (GdkWindow *window,
2611 int x,
2612 int y,
2613 int width,
2614 int height,
2615 GdkRectangle *flipped_rect,
2616 GdkRectangle *final_rect,
2617 gboolean *flipped_x,
2618 gboolean *flipped_y)
2619 {
2620 GdkWindowImplWayland *impl;
2621 GdkWindow *parent;
2622 gint window_x, window_y;
2623 gint window_width, window_height;
2624 GdkRectangle best_rect;
2625
2626 g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window));
2627 g_return_if_fail (GDK_IS_WINDOW_IMPL_WAYLAND (window->impl));
2628
2629 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
2630
2631 parent = translate_from_real_parent_window_geometry (window, &x, &y);
2632 *final_rect = (GdkRectangle) {
2633 .x = x,
2634 .y = y,
2635 .width = width,
2636 .height = height,
2637 };
2638
2639 window_x = parent->x + x;
2640 window_y = parent->y + y;
2641 window_width = width + window->shadow_left + window->shadow_right;
2642 window_height = height + window->shadow_top + window->shadow_bottom;
2643
2644 impl->configuring_popup = TRUE;
2645 gdk_window_move_resize (window,
2646 window_x, window_y,
2647 window_width, window_height);
2648 impl->configuring_popup = FALSE;
2649
2650 calculate_popup_rect (window,
2651 impl->pending_move_to_rect.rect_anchor,
2652 impl->pending_move_to_rect.window_anchor,
2653 &best_rect);
2654
2655 *flipped_rect = best_rect;
2656
2657 if (x != best_rect.x &&
2658 impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_X)
2659 {
2660 GdkRectangle flipped_x_rect;
2661 GdkGravity flipped_rect_anchor;
2662 GdkGravity flipped_window_anchor;
2663
2664 flipped_rect_anchor =
2665 flip_anchor_horizontally (impl->pending_move_to_rect.rect_anchor);
2666 flipped_window_anchor =
2667 flip_anchor_horizontally (impl->pending_move_to_rect.window_anchor),
2668 calculate_popup_rect (window,
2669 flipped_rect_anchor,
2670 flipped_window_anchor,
2671 &flipped_x_rect);
2672
2673 if (flipped_x_rect.x == x)
2674 flipped_rect->x = x;
2675 }
2676 if (y != best_rect.y &&
2677 impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_Y)
2678 {
2679 GdkRectangle flipped_y_rect;
2680 GdkGravity flipped_rect_anchor;
2681 GdkGravity flipped_window_anchor;
2682
2683 flipped_rect_anchor =
2684 flip_anchor_vertically (impl->pending_move_to_rect.rect_anchor);
2685 flipped_window_anchor =
2686 flip_anchor_vertically (impl->pending_move_to_rect.window_anchor),
2687 calculate_popup_rect (window,
2688 flipped_rect_anchor,
2689 flipped_window_anchor,
2690 &flipped_y_rect);
2691
2692 if (flipped_y_rect.y == y)
2693 flipped_rect->y = y;
2694 }
2695
2696 *flipped_x = flipped_rect->x != best_rect.x;
2697 *flipped_y = flipped_rect->y != best_rect.y;
2698 }
2699
2700 static gpointer
create_dynamic_positioner(GdkWindow * window)2701 create_dynamic_positioner (GdkWindow *window)
2702 {
2703 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
2704 GdkWaylandDisplay *display =
2705 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
2706 GdkRectangle geometry;
2707 uint32_t constraint_adjustment = ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE;
2708 gint real_anchor_rect_x, real_anchor_rect_y;
2709 gint anchor_rect_width, anchor_rect_height;
2710
2711 gdk_wayland_window_get_window_geometry (window, &geometry);
2712
2713 real_anchor_rect_x = impl->pending_move_to_rect.rect.x;
2714 real_anchor_rect_y = impl->pending_move_to_rect.rect.y;
2715 translate_to_real_parent_window_geometry (window,
2716 &real_anchor_rect_x,
2717 &real_anchor_rect_y);
2718
2719 anchor_rect_width = impl->pending_move_to_rect.rect.width;
2720 anchor_rect_height = impl->pending_move_to_rect.rect.height;
2721
2722 switch (display->shell_variant)
2723 {
2724 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
2725 {
2726 struct xdg_positioner *positioner;
2727 enum xdg_positioner_anchor anchor;
2728 enum xdg_positioner_gravity gravity;
2729
2730 positioner = xdg_wm_base_create_positioner (display->xdg_wm_base);
2731
2732 xdg_positioner_set_size (positioner, geometry.width, geometry.height);
2733 xdg_positioner_set_anchor_rect (positioner,
2734 real_anchor_rect_x,
2735 real_anchor_rect_y,
2736 anchor_rect_width,
2737 anchor_rect_height);
2738 xdg_positioner_set_offset (positioner,
2739 impl->pending_move_to_rect.rect_anchor_dx,
2740 impl->pending_move_to_rect.rect_anchor_dy);
2741
2742 anchor = rect_anchor_to_anchor (impl->pending_move_to_rect.rect_anchor);
2743 xdg_positioner_set_anchor (positioner, anchor);
2744
2745 gravity = window_anchor_to_gravity (impl->pending_move_to_rect.window_anchor);
2746 xdg_positioner_set_gravity (positioner, gravity);
2747
2748 if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_X)
2749 constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X;
2750 if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_Y)
2751 constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y;
2752 if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_SLIDE_X)
2753 constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X;
2754 if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_SLIDE_Y)
2755 constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
2756 if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_RESIZE_X)
2757 constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X;
2758 if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_RESIZE_Y)
2759 constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
2760 xdg_positioner_set_constraint_adjustment (positioner,
2761 constraint_adjustment);
2762
2763 return positioner;
2764 }
2765 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
2766 {
2767 struct zxdg_positioner_v6 *positioner;
2768 enum zxdg_positioner_v6_anchor anchor;
2769 enum zxdg_positioner_v6_gravity gravity;
2770
2771 positioner = zxdg_shell_v6_create_positioner (display->zxdg_shell_v6);
2772
2773 zxdg_positioner_v6_set_size (positioner, geometry.width, geometry.height);
2774 zxdg_positioner_v6_set_anchor_rect (positioner,
2775 real_anchor_rect_x,
2776 real_anchor_rect_y,
2777 anchor_rect_width,
2778 anchor_rect_height);
2779 zxdg_positioner_v6_set_offset (positioner,
2780 impl->pending_move_to_rect.rect_anchor_dx,
2781 impl->pending_move_to_rect.rect_anchor_dy);
2782
2783 anchor = rect_anchor_to_anchor_legacy (impl->pending_move_to_rect.rect_anchor);
2784 zxdg_positioner_v6_set_anchor (positioner, anchor);
2785
2786 gravity = window_anchor_to_gravity_legacy (impl->pending_move_to_rect.window_anchor);
2787 zxdg_positioner_v6_set_gravity (positioner, gravity);
2788
2789 if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_X)
2790 constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X;
2791 if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_Y)
2792 constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y;
2793 if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_SLIDE_X)
2794 constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X;
2795 if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_SLIDE_Y)
2796 constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
2797 if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_RESIZE_X)
2798 constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X;
2799 if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_RESIZE_Y)
2800 constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
2801 zxdg_positioner_v6_set_constraint_adjustment (positioner,
2802 constraint_adjustment);
2803
2804 return positioner;
2805 }
2806 }
2807
2808 g_assert_not_reached ();
2809 }
2810
2811 static gpointer
create_simple_positioner(GdkWindow * window,GdkWindow * parent)2812 create_simple_positioner (GdkWindow *window,
2813 GdkWindow *parent)
2814 {
2815 GdkWaylandDisplay *display =
2816 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
2817 GdkRectangle geometry;
2818 GdkRectangle parent_geometry;
2819 int parent_x, parent_y;
2820
2821 gdk_wayland_window_get_window_geometry (window, &geometry);
2822
2823 parent_x = parent->x;
2824 parent_y = parent->y;
2825
2826 gdk_wayland_window_get_window_geometry (parent, &parent_geometry);
2827 parent_x += parent_geometry.x;
2828 parent_y += parent_geometry.y;
2829
2830 switch (display->shell_variant)
2831 {
2832 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
2833 {
2834 struct xdg_positioner *positioner;
2835
2836 positioner = xdg_wm_base_create_positioner (display->xdg_wm_base);
2837 xdg_positioner_set_size (positioner, geometry.width, geometry.height);
2838 xdg_positioner_set_anchor_rect (positioner,
2839 (window->x + geometry.x) - parent_x,
2840 (window->y + geometry.y) - parent_y,
2841 1, 1);
2842 xdg_positioner_set_anchor (positioner,
2843 XDG_POSITIONER_ANCHOR_TOP_LEFT);
2844 xdg_positioner_set_gravity (positioner,
2845 XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT);
2846
2847 return positioner;
2848 }
2849 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
2850 {
2851 struct zxdg_positioner_v6 *positioner;
2852
2853 positioner = zxdg_shell_v6_create_positioner (display->zxdg_shell_v6);
2854 zxdg_positioner_v6_set_size (positioner, geometry.width, geometry.height);
2855 zxdg_positioner_v6_set_anchor_rect (positioner,
2856 (window->x + geometry.x) - parent_x,
2857 (window->y + geometry.y) - parent_y,
2858 1, 1);
2859 zxdg_positioner_v6_set_anchor (positioner,
2860 (ZXDG_POSITIONER_V6_ANCHOR_TOP |
2861 ZXDG_POSITIONER_V6_ANCHOR_LEFT));
2862 zxdg_positioner_v6_set_gravity (positioner,
2863 (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
2864 ZXDG_POSITIONER_V6_GRAVITY_RIGHT));
2865
2866 return positioner;
2867 }
2868 }
2869
2870 g_assert_not_reached ();
2871 }
2872
2873 static void
gdk_wayland_window_create_xdg_popup(GdkWindow * window,GdkWindow * parent,struct wl_seat * seat)2874 gdk_wayland_window_create_xdg_popup (GdkWindow *window,
2875 GdkWindow *parent,
2876 struct wl_seat *seat)
2877 {
2878 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
2879 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
2880 GdkWindowImplWayland *parent_impl = GDK_WINDOW_IMPL_WAYLAND (parent->impl);
2881 gpointer positioner;
2882 GdkSeat *gdk_seat;
2883 guint32 serial;
2884
2885 if (!impl->display_server.wl_surface)
2886 return;
2887
2888 if (!is_realized_shell_surface (parent))
2889 return;
2890
2891 if (is_realized_toplevel (window))
2892 {
2893 g_warning ("Can't map popup, already mapped as toplevel");
2894 return;
2895 }
2896 if (is_realized_popup (window))
2897 {
2898 g_warning ("Can't map popup, already mapped");
2899 return;
2900 }
2901 if ((display->current_popups &&
2902 g_list_last (display->current_popups)->data != parent) ||
2903 (!display->current_popups &&
2904 !is_realized_toplevel (parent)))
2905 {
2906 g_warning ("Tried to map a popup with a non-top most parent");
2907 return;
2908 }
2909
2910 gdk_window_freeze_updates (window);
2911
2912 if (impl->position_method == POSITION_METHOD_MOVE_TO_RECT)
2913 positioner = create_dynamic_positioner (window);
2914 else
2915 positioner = create_simple_positioner (window, parent);
2916
2917 switch (display->shell_variant)
2918 {
2919 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
2920 impl->display_server.xdg_surface =
2921 xdg_wm_base_get_xdg_surface (display->xdg_wm_base,
2922 impl->display_server.wl_surface);
2923 xdg_surface_add_listener (impl->display_server.xdg_surface,
2924 &xdg_surface_listener,
2925 window);
2926 impl->display_server.xdg_popup =
2927 xdg_surface_get_popup (impl->display_server.xdg_surface,
2928 parent_impl->display_server.xdg_surface,
2929 positioner);
2930 xdg_popup_add_listener (impl->display_server.xdg_popup,
2931 &xdg_popup_listener,
2932 window);
2933 xdg_positioner_destroy (positioner);
2934 break;
2935 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
2936 impl->display_server.zxdg_surface_v6 =
2937 zxdg_shell_v6_get_xdg_surface (display->zxdg_shell_v6,
2938 impl->display_server.wl_surface);
2939 zxdg_surface_v6_add_listener (impl->display_server.zxdg_surface_v6,
2940 &zxdg_surface_v6_listener,
2941 window);
2942 impl->display_server.zxdg_popup_v6 =
2943 zxdg_surface_v6_get_popup (impl->display_server.zxdg_surface_v6,
2944 parent_impl->display_server.zxdg_surface_v6,
2945 positioner);
2946 zxdg_popup_v6_add_listener (impl->display_server.zxdg_popup_v6,
2947 &zxdg_popup_v6_listener,
2948 window);
2949 zxdg_positioner_v6_destroy (positioner);
2950 break;
2951 }
2952
2953 if (seat)
2954 {
2955 gdk_seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
2956 serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_seat, NULL);
2957
2958 switch (display->shell_variant)
2959 {
2960 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
2961 xdg_popup_grab (impl->display_server.xdg_popup, seat, serial);
2962 break;
2963 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
2964 zxdg_popup_v6_grab (impl->display_server.zxdg_popup_v6, seat, serial);
2965 break;
2966 }
2967 }
2968
2969 wl_surface_commit (impl->display_server.wl_surface);
2970
2971 impl->popup_parent = parent;
2972 display->current_popups = g_list_append (display->current_popups, window);
2973 }
2974
2975 static struct wl_seat *
find_grab_input_seat(GdkWindow * window,GdkWindow * transient_for)2976 find_grab_input_seat (GdkWindow *window, GdkWindow *transient_for)
2977 {
2978 GdkWindow *attached_grab_window;
2979 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
2980 GdkWindowImplWayland *tmp_impl;
2981
2982 /* Use the device that was used for the grab as the device for
2983 * the popup window setup - so this relies on GTK+ taking the
2984 * grab before showing the popup window.
2985 */
2986 if (impl->grab_input_seat)
2987 return gdk_wayland_seat_get_wl_seat (impl->grab_input_seat);
2988
2989 /* HACK: GtkMenu grabs a special window known as the "grab transfer window"
2990 * and then transfers the grab over to the correct window later. Look for
2991 * this window when taking the grab to know it's correct.
2992 *
2993 * See: associate_menu_grab_transfer_window in gtkmenu.c
2994 */
2995 attached_grab_window = g_object_get_data (G_OBJECT (window), "gdk-attached-grab-window");
2996 if (attached_grab_window)
2997 {
2998 tmp_impl = GDK_WINDOW_IMPL_WAYLAND (attached_grab_window->impl);
2999 if (tmp_impl->grab_input_seat)
3000 return gdk_wayland_seat_get_wl_seat (tmp_impl->grab_input_seat);
3001 }
3002
3003 while (transient_for)
3004 {
3005 tmp_impl = GDK_WINDOW_IMPL_WAYLAND (transient_for->impl);
3006
3007 if (tmp_impl->grab_input_seat)
3008 return gdk_wayland_seat_get_wl_seat (tmp_impl->grab_input_seat);
3009
3010 transient_for = tmp_impl->transient_for;
3011 }
3012
3013 return NULL;
3014 }
3015
3016 static gboolean
should_be_mapped(GdkWindow * window)3017 should_be_mapped (GdkWindow *window)
3018 {
3019 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3020
3021 /* Don't map crazy temp that GTK+ uses for internal X11 shenanigans. */
3022 if (window->window_type == GDK_WINDOW_TEMP && window->x < 0 && window->y < 0)
3023 return FALSE;
3024
3025 if (impl->hint == GDK_WINDOW_TYPE_HINT_DND)
3026 return FALSE;
3027
3028 return TRUE;
3029 }
3030
3031 static gboolean
should_map_as_popup(GdkWindow * window)3032 should_map_as_popup (GdkWindow *window)
3033 {
3034 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3035
3036 /* Ideally, popup would be temp windows with a parent and grab */
3037 if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP)
3038 {
3039 /* If a temp window has a parent and a grab, we can use a popup */
3040 if (impl->transient_for)
3041 {
3042 if (impl->grab_input_seat)
3043 return TRUE;
3044 }
3045 }
3046
3047 /* Yet we need to keep the window type hint tests for compatibility */
3048 switch (impl->hint)
3049 {
3050 case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
3051 case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU:
3052 case GDK_WINDOW_TYPE_HINT_COMBO:
3053 return TRUE;
3054
3055 default:
3056 break;
3057 }
3058
3059 if (impl->position_method == POSITION_METHOD_MOVE_TO_RECT)
3060 return TRUE;
3061
3062 return FALSE;
3063 }
3064
3065 static gboolean
should_map_as_subsurface(GdkWindow * window)3066 should_map_as_subsurface (GdkWindow *window)
3067 {
3068 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3069
3070 if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_SUBSURFACE)
3071 return TRUE;
3072
3073 if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_TEMP)
3074 return FALSE;
3075
3076 /* if we want a popup, we do not want a subsurface */
3077 if (should_map_as_popup (window))
3078 return FALSE;
3079
3080 if (impl->transient_for)
3081 {
3082 GdkWindowImplWayland *impl_parent;
3083
3084 impl_parent = GDK_WINDOW_IMPL_WAYLAND (impl->transient_for->impl);
3085 /* subsurface require that the parent is mapped */
3086 if (impl_parent->mapped)
3087 return TRUE;
3088 else
3089 g_warning ("Couldn't map window %p as subsurface because its parent is not mapped.",
3090 window);
3091
3092 }
3093
3094 return FALSE;
3095 }
3096
3097 /* Get the window that can be used as a parent for a popup, i.e. a xdg_toplevel
3098 * or xdg_popup. If the window is not, traverse up the transiency parents until
3099 * we find one.
3100 */
3101 static GdkWindow *
get_popup_parent(GdkWindow * window)3102 get_popup_parent (GdkWindow *window)
3103 {
3104 while (window)
3105 {
3106 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3107
3108 if (is_realized_popup (window) || is_realized_toplevel (window))
3109 return window;
3110
3111 window = impl->transient_for;
3112 }
3113
3114 return NULL;
3115 }
3116
3117 static void
gdk_wayland_window_map(GdkWindow * window)3118 gdk_wayland_window_map (GdkWindow *window)
3119 {
3120 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3121 GdkWindow *transient_for = NULL;
3122
3123 if (!should_be_mapped (window))
3124 return;
3125
3126 if (impl->mapped || impl->use_custom_surface)
3127 return;
3128
3129 if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP)
3130 {
3131 if (!impl->transient_for)
3132 {
3133 g_message ("Window %p is a temporary window without parent, "
3134 "application will not be able to position it on screen.",
3135 window);
3136 }
3137 }
3138
3139 if (should_map_as_subsurface (window))
3140 {
3141 if (impl->transient_for)
3142 gdk_wayland_window_create_subsurface (window);
3143 else
3144 g_warning ("Couldn't map window %p as susburface yet because it doesn't have a parent",
3145 window);
3146 }
3147 else if (should_map_as_popup (window))
3148 {
3149 gboolean create_fallback = FALSE;
3150 struct wl_seat *grab_input_seat;
3151
3152 /* Popup menus can appear without a transient parent, which means they
3153 * cannot be positioned properly on Wayland. This attempts to guess the
3154 * surface they should be positioned with by finding the surface beneath
3155 * the device that created the grab for the popup window.
3156 */
3157 if (!impl->transient_for && impl->hint == GDK_WINDOW_TYPE_HINT_POPUP_MENU)
3158 {
3159 GdkDevice *grab_device = NULL;
3160
3161 /* The popup menu window is not the grabbed window. This may mean
3162 * that a "transfer window" (see gtkmenu.c) is used, and we need
3163 * to find that window to get the grab device. If so is the case
3164 * the "transfer window" can be retrieved via the
3165 * "gdk-attached-grab-window" associated data field.
3166 */
3167 if (!impl->grab_input_seat)
3168 {
3169 GdkWindow *attached_grab_window =
3170 g_object_get_data (G_OBJECT (window),
3171 "gdk-attached-grab-window");
3172 if (attached_grab_window)
3173 {
3174 GdkWindowImplWayland *attached_impl =
3175 GDK_WINDOW_IMPL_WAYLAND (attached_grab_window->impl);
3176 grab_device = gdk_seat_get_pointer (attached_impl->grab_input_seat);
3177 transient_for =
3178 gdk_device_get_window_at_position (grab_device,
3179 NULL, NULL);
3180 }
3181 }
3182 else
3183 {
3184 grab_device = gdk_seat_get_pointer (impl->grab_input_seat);
3185 transient_for =
3186 gdk_device_get_window_at_position (grab_device, NULL, NULL);
3187 }
3188
3189 if (transient_for)
3190 transient_for = get_popup_parent (gdk_window_get_effective_toplevel (transient_for));
3191
3192 /* If the position was not explicitly set, start the popup at the
3193 * position of the device that holds the grab.
3194 */
3195 if (impl->position_method == POSITION_METHOD_NONE && grab_device)
3196 gdk_window_get_device_position (transient_for, grab_device,
3197 &window->x, &window->y, NULL);
3198 }
3199 else
3200 {
3201 transient_for = gdk_window_get_effective_toplevel (impl->transient_for);
3202 transient_for = get_popup_parent (transient_for);
3203 }
3204
3205 if (!transient_for)
3206 {
3207 g_warning ("Couldn't map as window %p as popup because it doesn't have a parent",
3208 window);
3209
3210 create_fallback = TRUE;
3211 }
3212 else
3213 {
3214 grab_input_seat = find_grab_input_seat (window, transient_for);
3215 }
3216
3217 if (!create_fallback)
3218 {
3219 gdk_wayland_window_create_xdg_popup (window,
3220 transient_for,
3221 grab_input_seat);
3222 }
3223 else
3224 {
3225 gdk_wayland_window_create_xdg_toplevel (window);
3226 gdk_wayland_window_announce_decoration_mode (window);
3227 }
3228 }
3229 else
3230 {
3231 gdk_wayland_window_create_xdg_toplevel (window);
3232 gdk_wayland_window_announce_decoration_mode (window);
3233 }
3234
3235 impl->mapped = TRUE;
3236 }
3237
3238 static void
gdk_wayland_window_show(GdkWindow * window,gboolean already_mapped)3239 gdk_wayland_window_show (GdkWindow *window,
3240 gboolean already_mapped)
3241 {
3242 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3243
3244 if (!impl->display_server.wl_surface)
3245 gdk_wayland_window_create_surface (window);
3246
3247 gdk_wayland_window_map (window);
3248
3249 _gdk_make_event (window, GDK_MAP, NULL, FALSE);
3250
3251 if (impl->staging_cairo_surface &&
3252 _gdk_wayland_is_shm_surface (impl->staging_cairo_surface))
3253 gdk_wayland_window_attach_image (window);
3254 }
3255
3256 static void
unmap_subsurface(GdkWindow * window)3257 unmap_subsurface (GdkWindow *window)
3258 {
3259 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3260 GdkWindowImplWayland *parent_impl;
3261
3262 g_return_if_fail (impl->display_server.wl_subsurface);
3263 g_return_if_fail (impl->transient_for);
3264
3265 parent_impl = GDK_WINDOW_IMPL_WAYLAND (impl->transient_for->impl);
3266 wl_subsurface_destroy (impl->display_server.wl_subsurface);
3267 if (impl->parent_surface_committed_handler)
3268 {
3269 g_signal_handler_disconnect (parent_impl,
3270 impl->parent_surface_committed_handler);
3271 impl->parent_surface_committed_handler = 0;
3272 }
3273 impl->display_server.wl_subsurface = NULL;
3274 }
3275
3276 static void
unmap_popups_for_window(GdkWindow * window)3277 unmap_popups_for_window (GdkWindow *window)
3278 {
3279 GdkWaylandDisplay *display_wayland;
3280 GList *l;
3281
3282 display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
3283 for (l = display_wayland->current_popups; l; l = l->next)
3284 {
3285 GdkWindow *popup = l->data;
3286 GdkWindowImplWayland *popup_impl = GDK_WINDOW_IMPL_WAYLAND (popup->impl);
3287
3288 if (popup_impl->popup_parent == window)
3289 {
3290 g_warning ("Tried to unmap the parent of a popup");
3291 gdk_window_hide (popup);
3292
3293 return;
3294 }
3295 }
3296 }
3297
3298 static void
gdk_wayland_window_hide_surface(GdkWindow * window)3299 gdk_wayland_window_hide_surface (GdkWindow *window)
3300 {
3301 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
3302 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3303
3304 unmap_popups_for_window (window);
3305
3306 if (impl->display_server.wl_surface)
3307 {
3308 if (impl->dummy_egl_surface)
3309 {
3310 eglDestroySurface (display_wayland->egl_display, impl->dummy_egl_surface);
3311 impl->dummy_egl_surface = NULL;
3312 }
3313
3314 if (impl->display_server.dummy_egl_window)
3315 {
3316 wl_egl_window_destroy (impl->display_server.dummy_egl_window);
3317 impl->display_server.dummy_egl_window = NULL;
3318 }
3319
3320 if (impl->egl_surface)
3321 {
3322 eglDestroySurface (display_wayland->egl_display, impl->egl_surface);
3323 impl->egl_surface = NULL;
3324 }
3325
3326 if (impl->display_server.egl_window)
3327 {
3328 wl_egl_window_destroy (impl->display_server.egl_window);
3329 impl->display_server.egl_window = NULL;
3330 }
3331
3332 if (impl->display_server.xdg_toplevel)
3333 {
3334 xdg_toplevel_destroy (impl->display_server.xdg_toplevel);
3335 impl->display_server.xdg_toplevel = NULL;
3336 }
3337 else if (impl->display_server.xdg_popup)
3338 {
3339 xdg_popup_destroy (impl->display_server.xdg_popup);
3340 impl->display_server.xdg_popup = NULL;
3341 display_wayland->current_popups =
3342 g_list_remove (display_wayland->current_popups, window);
3343
3344 if (impl->position_method == POSITION_METHOD_MOVE_TO_RECT)
3345 {
3346 window->x = 0;
3347 window->y = 0;
3348 }
3349 }
3350 if (impl->display_server.xdg_surface)
3351 {
3352 xdg_surface_destroy (impl->display_server.xdg_surface);
3353 impl->display_server.xdg_surface = NULL;
3354 if (!impl->initial_configure_received)
3355 gdk_window_thaw_updates (window);
3356 else
3357 impl->initial_configure_received = FALSE;
3358 }
3359
3360 if (impl->display_server.zxdg_toplevel_v6)
3361 {
3362 zxdg_toplevel_v6_destroy (impl->display_server.zxdg_toplevel_v6);
3363 impl->display_server.zxdg_toplevel_v6 = NULL;
3364 }
3365 else if (impl->display_server.zxdg_popup_v6)
3366 {
3367 zxdg_popup_v6_destroy (impl->display_server.zxdg_popup_v6);
3368 impl->display_server.zxdg_popup_v6 = NULL;
3369 display_wayland->current_popups =
3370 g_list_remove (display_wayland->current_popups, window);
3371
3372 if (impl->position_method == POSITION_METHOD_MOVE_TO_RECT)
3373 {
3374 window->x = 0;
3375 window->y = 0;
3376 }
3377 }
3378 if (impl->display_server.zxdg_surface_v6)
3379 {
3380 zxdg_surface_v6_destroy (impl->display_server.zxdg_surface_v6);
3381 impl->display_server.zxdg_surface_v6 = NULL;
3382 if (!impl->initial_configure_received)
3383 gdk_window_thaw_updates (window);
3384 else
3385 impl->initial_configure_received = FALSE;
3386 }
3387
3388 if (impl->display_server.wl_subsurface)
3389 unmap_subsurface (window);
3390
3391 if (impl->awaiting_frame)
3392 {
3393 GdkFrameClock *frame_clock;
3394
3395 impl->awaiting_frame = FALSE;
3396 frame_clock = gdk_window_get_frame_clock (window);
3397 if (frame_clock)
3398 _gdk_frame_clock_thaw (frame_clock);
3399 }
3400
3401 if (impl->display_server.gtk_surface)
3402 {
3403 if (display_wayland->gtk_shell_version >=
3404 GTK_SURFACE1_RELEASE_SINCE_VERSION)
3405 gtk_surface1_release (impl->display_server.gtk_surface);
3406 else
3407 gtk_surface1_destroy (impl->display_server.gtk_surface);
3408 impl->display_server.gtk_surface = NULL;
3409 impl->application.was_set = FALSE;
3410 }
3411
3412 if (impl->display_server.server_decoration)
3413 {
3414 org_kde_kwin_server_decoration_release (impl->display_server.server_decoration);
3415 impl->display_server.server_decoration = NULL;
3416 }
3417
3418 wl_surface_destroy (impl->display_server.wl_surface);
3419 impl->display_server.wl_surface = NULL;
3420 impl->surface_callback = NULL;
3421
3422 g_slist_free (impl->display_server.outputs);
3423 impl->display_server.outputs = NULL;
3424
3425 if (impl->hint == GDK_WINDOW_TYPE_HINT_DIALOG && !impl->transient_for)
3426 display_wayland->orphan_dialogs =
3427 g_list_remove (display_wayland->orphan_dialogs, window);
3428 }
3429
3430 unset_transient_for_exported (window);
3431
3432 _gdk_wayland_window_clear_saved_size (window);
3433 drop_cairo_surfaces (window);
3434 impl->pending_commit = FALSE;
3435 impl->mapped = FALSE;
3436 }
3437
3438 static void
gdk_wayland_window_hide(GdkWindow * window)3439 gdk_wayland_window_hide (GdkWindow *window)
3440 {
3441 gdk_wayland_window_hide_surface (window);
3442 _gdk_window_clear_update_area (window);
3443 }
3444
3445 static void
gdk_window_wayland_withdraw(GdkWindow * window)3446 gdk_window_wayland_withdraw (GdkWindow *window)
3447 {
3448 if (!window->destroyed)
3449 {
3450 if (GDK_WINDOW_IS_MAPPED (window))
3451 gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_WITHDRAWN);
3452
3453 g_assert (!GDK_WINDOW_IS_MAPPED (window));
3454
3455 gdk_wayland_window_hide_surface (window);
3456 }
3457 }
3458
3459 static void
gdk_window_wayland_set_events(GdkWindow * window,GdkEventMask event_mask)3460 gdk_window_wayland_set_events (GdkWindow *window,
3461 GdkEventMask event_mask)
3462 {
3463 GDK_WINDOW (window)->event_mask = event_mask;
3464 }
3465
3466 static GdkEventMask
gdk_window_wayland_get_events(GdkWindow * window)3467 gdk_window_wayland_get_events (GdkWindow *window)
3468 {
3469 if (GDK_WINDOW_DESTROYED (window))
3470 return 0;
3471 else
3472 return GDK_WINDOW (window)->event_mask;
3473 }
3474
3475 static void
gdk_window_wayland_raise(GdkWindow * window)3476 gdk_window_wayland_raise (GdkWindow *window)
3477 {
3478 }
3479
3480 static void
gdk_window_wayland_lower(GdkWindow * window)3481 gdk_window_wayland_lower (GdkWindow *window)
3482 {
3483 }
3484
3485 static void
gdk_window_wayland_restack_under(GdkWindow * window,GList * native_siblings)3486 gdk_window_wayland_restack_under (GdkWindow *window,
3487 GList *native_siblings)
3488 {
3489 }
3490
3491 static void
gdk_window_wayland_restack_toplevel(GdkWindow * window,GdkWindow * sibling,gboolean above)3492 gdk_window_wayland_restack_toplevel (GdkWindow *window,
3493 GdkWindow *sibling,
3494 gboolean above)
3495 {
3496 }
3497
3498 static void
gdk_window_request_transient_parent_commit(GdkWindow * window)3499 gdk_window_request_transient_parent_commit (GdkWindow *window)
3500 {
3501 GdkWindowImplWayland *window_impl, *impl;
3502 GdkFrameClock *frame_clock;
3503
3504 window_impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3505
3506 if (!window_impl->transient_for)
3507 return;
3508
3509 impl = GDK_WINDOW_IMPL_WAYLAND (window_impl->transient_for->impl);
3510
3511 if (!impl->display_server.wl_surface || impl->pending_commit)
3512 return;
3513
3514 frame_clock = gdk_window_get_frame_clock (window_impl->transient_for);
3515
3516 if (!frame_clock)
3517 return;
3518
3519 impl->pending_commit = TRUE;
3520 gdk_frame_clock_request_phase (frame_clock,
3521 GDK_FRAME_CLOCK_PHASE_AFTER_PAINT);
3522 }
3523
3524 static void
gdk_window_wayland_move_resize(GdkWindow * window,gboolean with_move,gint x,gint y,gint width,gint height)3525 gdk_window_wayland_move_resize (GdkWindow *window,
3526 gboolean with_move,
3527 gint x,
3528 gint y,
3529 gint width,
3530 gint height)
3531 {
3532 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3533
3534 if (with_move)
3535 {
3536 /* Each toplevel has in its own "root" coordinate system */
3537 if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_TOPLEVEL)
3538 {
3539 window->x = x;
3540 window->y = y;
3541 impl->position_method = POSITION_METHOD_MOVE_RESIZE;
3542
3543 if (impl->display_server.wl_subsurface &&
3544 (x + window->abs_x != impl->subsurface_x ||
3545 y + window->abs_y != impl->subsurface_y))
3546 {
3547 gdk_wayland_window_set_subsurface_position (window,
3548 x + window->abs_x,
3549 y + window->abs_y);
3550 }
3551 }
3552 }
3553
3554 if (window->state & (GDK_WINDOW_STATE_FULLSCREEN |
3555 GDK_WINDOW_STATE_MAXIMIZED |
3556 GDK_WINDOW_STATE_TILED))
3557 {
3558 impl->saved_width = width;
3559 impl->saved_height = height;
3560 impl->saved_size_changed = (width > 0 && height > 0);
3561 }
3562
3563 /* If this function is called with width and height = -1 then that means
3564 * just move the window - don't update its size
3565 */
3566 if (width > 0 && height > 0)
3567 {
3568 if (!should_use_fixed_size (window->state) ||
3569 (width == impl->fixed_size_width &&
3570 height == impl->fixed_size_height))
3571 {
3572 gdk_wayland_window_maybe_configure (window,
3573 width,
3574 height,
3575 impl->scale);
3576 }
3577 else if (!should_inhibit_resize (window))
3578 {
3579 gdk_wayland_window_configure (window,
3580 window->width,
3581 window->height,
3582 impl->scale);
3583 }
3584 }
3585 }
3586
3587 /* Avoid zero width/height as this is a protocol error */
3588 static void
sanitize_anchor_rect(GdkWindow * window,GdkRectangle * rect)3589 sanitize_anchor_rect (GdkWindow *window,
3590 GdkRectangle *rect)
3591 {
3592 gint original_width = rect->width;
3593 gint original_height = rect->height;
3594
3595 rect->width = MAX (1, rect->width);
3596 rect->height = MAX (1, rect->height);
3597 rect->x = MAX (rect->x + original_width - rect->width, 0);
3598 rect->y = MAX (rect->y + original_height - rect->height, 0);
3599 }
3600
3601 static void
gdk_window_wayland_move_to_rect(GdkWindow * window,const GdkRectangle * rect,GdkGravity rect_anchor,GdkGravity window_anchor,GdkAnchorHints anchor_hints,gint rect_anchor_dx,gint rect_anchor_dy)3602 gdk_window_wayland_move_to_rect (GdkWindow *window,
3603 const GdkRectangle *rect,
3604 GdkGravity rect_anchor,
3605 GdkGravity window_anchor,
3606 GdkAnchorHints anchor_hints,
3607 gint rect_anchor_dx,
3608 gint rect_anchor_dy)
3609 {
3610 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3611
3612 impl->pending_move_to_rect.rect = *rect;
3613 sanitize_anchor_rect (window, &impl->pending_move_to_rect.rect);
3614
3615 impl->pending_move_to_rect.rect_anchor = rect_anchor;
3616 impl->pending_move_to_rect.window_anchor = window_anchor;
3617 impl->pending_move_to_rect.anchor_hints = anchor_hints;
3618 impl->pending_move_to_rect.rect_anchor_dx = rect_anchor_dx;
3619 impl->pending_move_to_rect.rect_anchor_dy = rect_anchor_dy;
3620
3621 impl->position_method = POSITION_METHOD_MOVE_TO_RECT;
3622 }
3623
3624 static void
gdk_window_wayland_set_background(GdkWindow * window,cairo_pattern_t * pattern)3625 gdk_window_wayland_set_background (GdkWindow *window,
3626 cairo_pattern_t *pattern)
3627 {
3628 }
3629
3630 static gboolean
gdk_window_wayland_reparent(GdkWindow * window,GdkWindow * new_parent,gint x,gint y)3631 gdk_window_wayland_reparent (GdkWindow *window,
3632 GdkWindow *new_parent,
3633 gint x,
3634 gint y)
3635 {
3636 return FALSE;
3637 }
3638
3639 static void
gdk_window_wayland_set_device_cursor(GdkWindow * window,GdkDevice * device,GdkCursor * cursor)3640 gdk_window_wayland_set_device_cursor (GdkWindow *window,
3641 GdkDevice *device,
3642 GdkCursor *cursor)
3643 {
3644 g_return_if_fail (GDK_IS_WINDOW (window));
3645 g_return_if_fail (GDK_IS_DEVICE (device));
3646
3647 if (!GDK_WINDOW_DESTROYED (window))
3648 GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, window, cursor);
3649 }
3650
3651 static void
gdk_window_wayland_get_geometry(GdkWindow * window,gint * x,gint * y,gint * width,gint * height)3652 gdk_window_wayland_get_geometry (GdkWindow *window,
3653 gint *x,
3654 gint *y,
3655 gint *width,
3656 gint *height)
3657 {
3658 if (!GDK_WINDOW_DESTROYED (window))
3659 {
3660 if (x)
3661 *x = window->x;
3662 if (y)
3663 *y = window->y;
3664 if (width)
3665 *width = window->width;
3666 if (height)
3667 *height = window->height;
3668 }
3669 }
3670
3671 static void
gdk_window_wayland_get_root_coords(GdkWindow * window,gint x,gint y,gint * root_x,gint * root_y)3672 gdk_window_wayland_get_root_coords (GdkWindow *window,
3673 gint x,
3674 gint y,
3675 gint *root_x,
3676 gint *root_y)
3677 {
3678 /*
3679 * Wayland does not have a global coordinate space shared between surfaces. In
3680 * fact, for regular toplevels, we have no idea where our surfaces are
3681 * positioned, relatively.
3682 *
3683 * However, there are some cases like popups and subsurfaces where we do have
3684 * some amount of control over the placement of our window, and we can
3685 * semi-accurately control the x/y position of these windows, if they are
3686 * relative to another surface.
3687 *
3688 * To pretend we have something called a root coordinate space, assume all
3689 * parent-less windows are positioned in (0, 0), and all relative positioned
3690 * popups and subsurfaces are placed within this fake root coordinate space.
3691 *
3692 * For example a 200x200 large toplevel window will have the position (0, 0).
3693 * If a popup positioned in the middle of the toplevel will have the fake
3694 * position (100,100). Furthermore, if a positioned is placed in the middle
3695 * that popup, will have the fake position (150,150), even though it has the
3696 * relative position (50,50). These three windows would make up one single
3697 * fake root coordinate space.
3698 */
3699
3700 if (root_x)
3701 *root_x = window->x + x;
3702
3703 if (root_y)
3704 *root_y = window->y + y;
3705 }
3706
3707 static gboolean
gdk_window_wayland_get_device_state(GdkWindow * window,GdkDevice * device,gdouble * x,gdouble * y,GdkModifierType * mask)3708 gdk_window_wayland_get_device_state (GdkWindow *window,
3709 GdkDevice *device,
3710 gdouble *x,
3711 gdouble *y,
3712 GdkModifierType *mask)
3713 {
3714 gboolean return_val;
3715
3716 g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), FALSE);
3717
3718 return_val = TRUE;
3719
3720 if (!GDK_WINDOW_DESTROYED (window))
3721 {
3722 GdkWindow *child;
3723
3724 GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
3725 NULL, &child,
3726 NULL, NULL,
3727 x, y, mask);
3728 return_val = (child != NULL);
3729 }
3730
3731 return return_val;
3732 }
3733
3734 static void
gdk_window_wayland_shape_combine_region(GdkWindow * window,const cairo_region_t * shape_region,gint offset_x,gint offset_y)3735 gdk_window_wayland_shape_combine_region (GdkWindow *window,
3736 const cairo_region_t *shape_region,
3737 gint offset_x,
3738 gint offset_y)
3739 {
3740 }
3741
3742 static void
gdk_window_wayland_input_shape_combine_region(GdkWindow * window,const cairo_region_t * shape_region,gint offset_x,gint offset_y)3743 gdk_window_wayland_input_shape_combine_region (GdkWindow *window,
3744 const cairo_region_t *shape_region,
3745 gint offset_x,
3746 gint offset_y)
3747 {
3748 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3749
3750 if (GDK_WINDOW_DESTROYED (window))
3751 return;
3752
3753 g_clear_pointer (&impl->input_region, cairo_region_destroy);
3754
3755 if (shape_region)
3756 {
3757 impl->input_region = cairo_region_copy (shape_region);
3758 cairo_region_translate (impl->input_region, offset_x, offset_y);
3759 }
3760
3761 impl->input_region_dirty = TRUE;
3762 }
3763
3764 static void
gdk_wayland_window_destroy(GdkWindow * window,gboolean recursing,gboolean foreign_destroy)3765 gdk_wayland_window_destroy (GdkWindow *window,
3766 gboolean recursing,
3767 gboolean foreign_destroy)
3768 {
3769 g_return_if_fail (GDK_IS_WINDOW (window));
3770
3771 /* Wayland windows can't be externally destroyed; we may possibly
3772 * eventually want to use this path at display close-down
3773 */
3774 g_return_if_fail (!foreign_destroy);
3775
3776 gdk_wayland_window_hide_surface (window);
3777 }
3778
3779 static void
gdk_window_wayland_destroy_foreign(GdkWindow * window)3780 gdk_window_wayland_destroy_foreign (GdkWindow *window)
3781 {
3782 }
3783
3784 static cairo_region_t *
gdk_wayland_window_get_shape(GdkWindow * window)3785 gdk_wayland_window_get_shape (GdkWindow *window)
3786 {
3787 return NULL;
3788 }
3789
3790 static cairo_region_t *
gdk_wayland_window_get_input_shape(GdkWindow * window)3791 gdk_wayland_window_get_input_shape (GdkWindow *window)
3792 {
3793 return NULL;
3794 }
3795
3796 static void
gdk_wayland_window_focus(GdkWindow * window,guint32 timestamp)3797 gdk_wayland_window_focus (GdkWindow *window,
3798 guint32 timestamp)
3799 {
3800 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3801
3802 if (!impl->display_server.gtk_surface)
3803 return;
3804
3805 if (timestamp == GDK_CURRENT_TIME)
3806 {
3807 GdkWaylandDisplay *display_wayland =
3808 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
3809
3810 if (display_wayland->gtk_shell_version >= 3)
3811 {
3812 gtk_surface1_request_focus (impl->display_server.gtk_surface,
3813 display_wayland->startup_notification_id);
3814 g_clear_pointer (&display_wayland->startup_notification_id, g_free);
3815 }
3816 }
3817 else
3818 gtk_surface1_present (impl->display_server.gtk_surface, timestamp);
3819 }
3820
3821 static void
gdk_wayland_window_set_type_hint(GdkWindow * window,GdkWindowTypeHint hint)3822 gdk_wayland_window_set_type_hint (GdkWindow *window,
3823 GdkWindowTypeHint hint)
3824 {
3825 GdkWindowImplWayland *impl;
3826
3827 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3828
3829 if (GDK_WINDOW_DESTROYED (window))
3830 return;
3831
3832 impl->hint = hint;
3833 }
3834
3835 static GdkWindowTypeHint
gdk_wayland_window_get_type_hint(GdkWindow * window)3836 gdk_wayland_window_get_type_hint (GdkWindow *window)
3837 {
3838 GdkWindowImplWayland *impl;
3839
3840 if (GDK_WINDOW_DESTROYED (window))
3841 return GDK_WINDOW_TYPE_HINT_NORMAL;
3842
3843 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3844
3845 return impl->hint;
3846 }
3847
3848 static void
gtk_surface_configure(void * data,struct gtk_surface1 * gtk_surface,struct wl_array * states)3849 gtk_surface_configure (void *data,
3850 struct gtk_surface1 *gtk_surface,
3851 struct wl_array *states)
3852 {
3853 GdkWindow *window = GDK_WINDOW (data);
3854 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3855 GdkWindowState new_state = 0;
3856 uint32_t *p;
3857
3858 wl_array_for_each (p, states)
3859 {
3860 uint32_t state = *p;
3861
3862 switch (state)
3863 {
3864 case GTK_SURFACE1_STATE_TILED:
3865 new_state |= GDK_WINDOW_STATE_TILED;
3866 break;
3867
3868 /* Since v2 */
3869 case GTK_SURFACE1_STATE_TILED_TOP:
3870 new_state |= (GDK_WINDOW_STATE_TILED | GDK_WINDOW_STATE_TOP_TILED);
3871 break;
3872 case GTK_SURFACE1_STATE_TILED_RIGHT:
3873 new_state |= (GDK_WINDOW_STATE_TILED | GDK_WINDOW_STATE_RIGHT_TILED);
3874 break;
3875 case GTK_SURFACE1_STATE_TILED_BOTTOM:
3876 new_state |= (GDK_WINDOW_STATE_TILED | GDK_WINDOW_STATE_BOTTOM_TILED);
3877 break;
3878 case GTK_SURFACE1_STATE_TILED_LEFT:
3879 new_state |= (GDK_WINDOW_STATE_TILED | GDK_WINDOW_STATE_LEFT_TILED);
3880 break;
3881 default:
3882 /* Unknown state */
3883 break;
3884 }
3885 }
3886
3887 impl->pending.state |= new_state;
3888 }
3889
3890 static void
gtk_surface_configure_edges(void * data,struct gtk_surface1 * gtk_surface,struct wl_array * edge_constraints)3891 gtk_surface_configure_edges (void *data,
3892 struct gtk_surface1 *gtk_surface,
3893 struct wl_array *edge_constraints)
3894 {
3895 GdkWindow *window = GDK_WINDOW (data);
3896 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3897 GdkWindowState new_state = 0;
3898 uint32_t *p;
3899
3900 wl_array_for_each (p, edge_constraints)
3901 {
3902 uint32_t constraint = *p;
3903
3904 switch (constraint)
3905 {
3906 case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_TOP:
3907 new_state |= GDK_WINDOW_STATE_TOP_RESIZABLE;
3908 break;
3909 case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_RIGHT:
3910 new_state |= GDK_WINDOW_STATE_RIGHT_RESIZABLE;
3911 break;
3912 case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_BOTTOM:
3913 new_state |= GDK_WINDOW_STATE_BOTTOM_RESIZABLE;
3914 break;
3915 case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_LEFT:
3916 new_state |= GDK_WINDOW_STATE_LEFT_RESIZABLE;
3917 break;
3918 default:
3919 /* Unknown state */
3920 break;
3921 }
3922 }
3923
3924 impl->pending.state |= new_state;
3925 }
3926
3927 static const struct gtk_surface1_listener gtk_surface_listener = {
3928 gtk_surface_configure,
3929 gtk_surface_configure_edges
3930 };
3931
3932 static void
gdk_wayland_window_init_gtk_surface(GdkWindow * window)3933 gdk_wayland_window_init_gtk_surface (GdkWindow *window)
3934 {
3935 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3936 GdkWaylandDisplay *display =
3937 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
3938
3939 if (impl->display_server.gtk_surface != NULL)
3940 return;
3941 if (!is_realized_toplevel (window))
3942 return;
3943 if (display->gtk_shell == NULL)
3944 return;
3945
3946 impl->display_server.gtk_surface =
3947 gtk_shell1_get_gtk_surface (display->gtk_shell,
3948 impl->display_server.wl_surface);
3949 gdk_window_set_geometry_hints (window,
3950 &impl->geometry_hints,
3951 impl->geometry_mask);
3952 gtk_surface1_add_listener (impl->display_server.gtk_surface,
3953 >k_surface_listener,
3954 window);
3955 }
3956
3957 static void
maybe_set_gtk_surface_modal(GdkWindow * window)3958 maybe_set_gtk_surface_modal (GdkWindow *window)
3959 {
3960 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
3961
3962 gdk_wayland_window_init_gtk_surface (window);
3963 if (impl->display_server.gtk_surface == NULL)
3964 return;
3965
3966 if (window->modal_hint)
3967 gtk_surface1_set_modal (impl->display_server.gtk_surface);
3968 else
3969 gtk_surface1_unset_modal (impl->display_server.gtk_surface);
3970
3971 }
3972
3973 static void
gdk_wayland_window_set_modal_hint(GdkWindow * window,gboolean modal)3974 gdk_wayland_window_set_modal_hint (GdkWindow *window,
3975 gboolean modal)
3976 {
3977 window->modal_hint = modal;
3978 maybe_set_gtk_surface_modal (window);
3979 }
3980
3981 static void
gdk_wayland_window_set_skip_taskbar_hint(GdkWindow * window,gboolean skips_taskbar)3982 gdk_wayland_window_set_skip_taskbar_hint (GdkWindow *window,
3983 gboolean skips_taskbar)
3984 {
3985 }
3986
3987 static void
gdk_wayland_window_set_skip_pager_hint(GdkWindow * window,gboolean skips_pager)3988 gdk_wayland_window_set_skip_pager_hint (GdkWindow *window,
3989 gboolean skips_pager)
3990 {
3991 }
3992
3993 static void
gdk_wayland_window_set_urgency_hint(GdkWindow * window,gboolean urgent)3994 gdk_wayland_window_set_urgency_hint (GdkWindow *window,
3995 gboolean urgent)
3996 {
3997 }
3998
3999 static void
gdk_wayland_window_set_geometry_hints(GdkWindow * window,const GdkGeometry * geometry,GdkWindowHints geom_mask)4000 gdk_wayland_window_set_geometry_hints (GdkWindow *window,
4001 const GdkGeometry *geometry,
4002 GdkWindowHints geom_mask)
4003 {
4004 GdkWaylandDisplay *display_wayland;
4005 GdkWindowImplWayland *impl;
4006 int min_width = 0, min_height = 0, max_width = 0, max_height = 0;
4007
4008 if (GDK_WINDOW_DESTROYED (window) ||
4009 !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4010 return;
4011
4012 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4013 display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
4014
4015 impl->geometry_hints = *geometry;
4016 impl->geometry_mask = geom_mask;
4017
4018 if (!is_realized_toplevel (window))
4019 return;
4020
4021 if (geom_mask & GDK_HINT_MIN_SIZE)
4022 {
4023 min_width =
4024 MAX (0, calculate_width_without_margin (window, geometry->min_width));
4025 min_height =
4026 MAX (0, calculate_height_without_margin (window, geometry->min_height));
4027 }
4028
4029 if (geom_mask & GDK_HINT_MAX_SIZE)
4030 {
4031 max_width =
4032 MAX (0, calculate_width_without_margin (window, geometry->max_width));
4033 max_height =
4034 MAX (0, calculate_height_without_margin (window, geometry->max_height));
4035 }
4036
4037 switch (display_wayland->shell_variant)
4038 {
4039 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4040 xdg_toplevel_set_min_size (impl->display_server.xdg_toplevel,
4041 min_width, min_height);
4042 xdg_toplevel_set_max_size (impl->display_server.xdg_toplevel,
4043 max_width, max_height);
4044 break;
4045 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4046 zxdg_toplevel_v6_set_min_size (impl->display_server.zxdg_toplevel_v6,
4047 min_width, min_height);
4048 zxdg_toplevel_v6_set_max_size (impl->display_server.zxdg_toplevel_v6,
4049 max_width, max_height);
4050 break;
4051 }
4052 }
4053
4054 static void
gdk_wayland_window_set_title(GdkWindow * window,const gchar * title)4055 gdk_wayland_window_set_title (GdkWindow *window,
4056 const gchar *title)
4057 {
4058 GdkWindowImplWayland *impl;
4059 const char *end;
4060 g_return_if_fail (title != NULL);
4061
4062 if (GDK_WINDOW_DESTROYED (window))
4063 return;
4064
4065 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4066
4067 if (g_strcmp0 (impl->title, title) == 0)
4068 return;
4069
4070 g_free (impl->title);
4071
4072 g_utf8_validate (title, MAX_WL_BUFFER_SIZE, &end);
4073 impl->title = g_malloc (end - title + 1);
4074 memcpy (impl->title, title, end - title);
4075 impl->title[end - title] = '\0';
4076
4077 gdk_wayland_window_sync_title (window);
4078 }
4079
4080 static void
gdk_wayland_window_set_role(GdkWindow * window,const gchar * role)4081 gdk_wayland_window_set_role (GdkWindow *window,
4082 const gchar *role)
4083 {
4084 }
4085
4086 static void
gdk_wayland_window_set_startup_id(GdkWindow * window,const gchar * startup_id)4087 gdk_wayland_window_set_startup_id (GdkWindow *window,
4088 const gchar *startup_id)
4089 {
4090 }
4091
4092 static gboolean
check_transient_for_loop(GdkWindow * window,GdkWindow * parent)4093 check_transient_for_loop (GdkWindow *window,
4094 GdkWindow *parent)
4095 {
4096 while (parent)
4097 {
4098 GdkWindowImplWayland *impl;
4099
4100 if (!GDK_IS_WINDOW_IMPL_WAYLAND(parent->impl))
4101 return FALSE;
4102
4103 impl = GDK_WINDOW_IMPL_WAYLAND (parent->impl);
4104 if (impl->transient_for == window)
4105 return TRUE;
4106 parent = impl->transient_for;
4107 }
4108 return FALSE;
4109 }
4110
4111 static void
gdk_wayland_window_set_transient_for(GdkWindow * window,GdkWindow * parent)4112 gdk_wayland_window_set_transient_for (GdkWindow *window,
4113 GdkWindow *parent)
4114 {
4115 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4116 GdkWaylandDisplay *display_wayland =
4117 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
4118 GdkWindow *previous_parent;
4119 gboolean was_subsurface = FALSE;
4120
4121 g_assert (parent == NULL ||
4122 gdk_window_get_display (window) == gdk_window_get_display (parent));
4123
4124 if (check_transient_for_loop (window, parent))
4125 {
4126 g_warning ("Setting %p transient for %p would create a loop", window, parent);
4127 return;
4128 }
4129
4130 unset_transient_for_exported (window);
4131
4132 if (impl->display_server.wl_subsurface)
4133 {
4134 was_subsurface = TRUE;
4135 unmap_subsurface (window);
4136 }
4137
4138 previous_parent = impl->transient_for;
4139 impl->transient_for = parent;
4140
4141 if (impl->hint == GDK_WINDOW_TYPE_HINT_DIALOG)
4142 {
4143 if (!parent)
4144 _gdk_wayland_screen_add_orphan_dialog (window);
4145 else if (!previous_parent)
4146 display_wayland->orphan_dialogs =
4147 g_list_remove (display_wayland->orphan_dialogs, window);
4148 }
4149
4150 gdk_wayland_window_sync_parent (window, NULL);
4151
4152 if (was_subsurface && parent)
4153 gdk_wayland_window_create_subsurface (window);
4154 }
4155
4156 static void
gdk_wayland_window_get_frame_extents(GdkWindow * window,GdkRectangle * rect)4157 gdk_wayland_window_get_frame_extents (GdkWindow *window,
4158 GdkRectangle *rect)
4159 {
4160 *rect = (GdkRectangle) {
4161 .x = window->x,
4162 .y = window->y,
4163 .width = window->width,
4164 .height = window->height
4165 };
4166 }
4167
4168 static void
gdk_wayland_window_set_override_redirect(GdkWindow * window,gboolean override_redirect)4169 gdk_wayland_window_set_override_redirect (GdkWindow *window,
4170 gboolean override_redirect)
4171 {
4172 }
4173
4174 static void
gdk_wayland_window_set_accept_focus(GdkWindow * window,gboolean accept_focus)4175 gdk_wayland_window_set_accept_focus (GdkWindow *window,
4176 gboolean accept_focus)
4177 {
4178 }
4179
4180 static void
gdk_wayland_window_set_focus_on_map(GdkWindow * window,gboolean focus_on_map)4181 gdk_wayland_window_set_focus_on_map (GdkWindow *window,
4182 gboolean focus_on_map)
4183 {
4184 }
4185
4186 static void
gdk_wayland_window_set_icon_list(GdkWindow * window,GList * pixbufs)4187 gdk_wayland_window_set_icon_list (GdkWindow *window,
4188 GList *pixbufs)
4189 {
4190 }
4191
4192 static void
gdk_wayland_window_set_icon_name(GdkWindow * window,const gchar * name)4193 gdk_wayland_window_set_icon_name (GdkWindow *window,
4194 const gchar *name)
4195 {
4196 if (GDK_WINDOW_DESTROYED (window))
4197 return;
4198 }
4199
4200 static void
gdk_wayland_window_iconify(GdkWindow * window)4201 gdk_wayland_window_iconify (GdkWindow *window)
4202 {
4203 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4204 GdkWaylandDisplay *display_wayland;
4205
4206 if (GDK_WINDOW_DESTROYED (window) ||
4207 !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4208 return;
4209
4210 if (!is_realized_toplevel (window))
4211 return;
4212
4213 display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
4214 switch (display_wayland->shell_variant)
4215 {
4216 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4217 xdg_toplevel_set_minimized (impl->display_server.xdg_toplevel);
4218 break;
4219 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4220 zxdg_toplevel_v6_set_minimized (impl->display_server.zxdg_toplevel_v6);
4221 break;
4222 }
4223 }
4224
4225 static void
gdk_wayland_window_deiconify(GdkWindow * window)4226 gdk_wayland_window_deiconify (GdkWindow *window)
4227 {
4228 if (GDK_WINDOW_DESTROYED (window) ||
4229 !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4230 return;
4231
4232 if (GDK_WINDOW_IS_MAPPED (window))
4233 gdk_window_show (window);
4234 else
4235 /* Flip our client side flag, the real work happens on map. */
4236 gdk_synthesize_window_state (window, GDK_WINDOW_STATE_ICONIFIED, 0);
4237 }
4238
4239 static void
gdk_wayland_window_stick(GdkWindow * window)4240 gdk_wayland_window_stick (GdkWindow *window)
4241 {
4242 }
4243
4244 static void
gdk_wayland_window_unstick(GdkWindow * window)4245 gdk_wayland_window_unstick (GdkWindow *window)
4246 {
4247 }
4248
4249 static void
gdk_wayland_window_maximize(GdkWindow * window)4250 gdk_wayland_window_maximize (GdkWindow *window)
4251 {
4252 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4253
4254 if (GDK_WINDOW_DESTROYED (window))
4255 return;
4256
4257 _gdk_wayland_window_save_size (window);
4258 if (is_realized_toplevel (window))
4259 {
4260 GdkWaylandDisplay *display_wayland =
4261 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
4262
4263 switch (display_wayland->shell_variant)
4264 {
4265 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4266 xdg_toplevel_set_maximized (impl->display_server.xdg_toplevel);
4267 break;
4268 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4269 zxdg_toplevel_v6_set_maximized (impl->display_server.zxdg_toplevel_v6);
4270 break;
4271 }
4272 }
4273 else
4274 {
4275 gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_MAXIMIZED);
4276 }
4277 }
4278
4279 static void
gdk_wayland_window_unmaximize(GdkWindow * window)4280 gdk_wayland_window_unmaximize (GdkWindow *window)
4281 {
4282 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4283
4284 if (GDK_WINDOW_DESTROYED (window))
4285 return;
4286
4287 if (is_realized_toplevel (window))
4288 {
4289 GdkWaylandDisplay *display_wayland =
4290 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
4291
4292 switch (display_wayland->shell_variant)
4293 {
4294 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4295 xdg_toplevel_unset_maximized (impl->display_server.xdg_toplevel);
4296 break;
4297 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4298 zxdg_toplevel_v6_unset_maximized (impl->display_server.zxdg_toplevel_v6);
4299 break;
4300 }
4301 }
4302 else
4303 {
4304 gdk_synthesize_window_state (window, GDK_WINDOW_STATE_MAXIMIZED, 0);
4305 }
4306 }
4307
4308 static void
gdk_wayland_window_fullscreen_on_monitor(GdkWindow * window,gint monitor)4309 gdk_wayland_window_fullscreen_on_monitor (GdkWindow *window, gint monitor)
4310 {
4311 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4312 GdkScreen *screen = gdk_window_get_screen (window);
4313 struct wl_output *fullscreen_output =
4314 _gdk_wayland_screen_get_wl_output (screen, monitor);
4315
4316 if (GDK_WINDOW_DESTROYED (window))
4317 return;
4318
4319 _gdk_wayland_window_save_size (window);
4320 if (is_realized_toplevel (window))
4321 {
4322 GdkWaylandDisplay *display_wayland =
4323 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
4324
4325 switch (display_wayland->shell_variant)
4326 {
4327 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4328 xdg_toplevel_set_fullscreen (impl->display_server.xdg_toplevel,
4329 fullscreen_output);
4330 break;
4331 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4332 zxdg_toplevel_v6_set_fullscreen (impl->display_server.zxdg_toplevel_v6,
4333 fullscreen_output);
4334 break;
4335 }
4336 }
4337 else
4338 {
4339 gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FULLSCREEN);
4340 impl->initial_fullscreen_monitor = monitor;
4341 }
4342 }
4343
4344 static void
gdk_wayland_window_fullscreen(GdkWindow * window)4345 gdk_wayland_window_fullscreen (GdkWindow *window)
4346 {
4347 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4348
4349 if (GDK_WINDOW_DESTROYED (window))
4350 return;
4351
4352 impl->initial_fullscreen_monitor = -1;
4353
4354 _gdk_wayland_window_save_size (window);
4355 if (is_realized_toplevel (window))
4356 {
4357 GdkWaylandDisplay *display_wayland =
4358 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
4359
4360 switch (display_wayland->shell_variant)
4361 {
4362 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4363 xdg_toplevel_set_fullscreen (impl->display_server.xdg_toplevel,
4364 NULL);
4365 break;
4366 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4367 zxdg_toplevel_v6_set_fullscreen (impl->display_server.zxdg_toplevel_v6,
4368 NULL);
4369 break;
4370 }
4371 }
4372 else
4373 {
4374 gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FULLSCREEN);
4375 }
4376 }
4377
4378 static void
gdk_wayland_window_unfullscreen(GdkWindow * window)4379 gdk_wayland_window_unfullscreen (GdkWindow *window)
4380 {
4381 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4382
4383 if (GDK_WINDOW_DESTROYED (window))
4384 return;
4385
4386 impl->initial_fullscreen_monitor = -1;
4387
4388 if (is_realized_toplevel (window))
4389 {
4390 GdkWaylandDisplay *display_wayland =
4391 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
4392
4393 switch (display_wayland->shell_variant)
4394 {
4395 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4396 xdg_toplevel_unset_fullscreen (impl->display_server.xdg_toplevel);
4397 break;
4398 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4399 zxdg_toplevel_v6_unset_fullscreen (impl->display_server.zxdg_toplevel_v6);
4400 break;
4401 }
4402 }
4403 else
4404 {
4405 gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FULLSCREEN, 0);
4406 }
4407 }
4408
4409 static void
gdk_wayland_window_set_keep_above(GdkWindow * window,gboolean setting)4410 gdk_wayland_window_set_keep_above (GdkWindow *window, gboolean setting)
4411 {
4412 }
4413
4414 static void
gdk_wayland_window_set_keep_below(GdkWindow * window,gboolean setting)4415 gdk_wayland_window_set_keep_below (GdkWindow *window, gboolean setting)
4416 {
4417 }
4418
4419 static GdkWindow *
gdk_wayland_window_get_group(GdkWindow * window)4420 gdk_wayland_window_get_group (GdkWindow *window)
4421 {
4422 return NULL;
4423 }
4424
4425 static void
gdk_wayland_window_set_group(GdkWindow * window,GdkWindow * leader)4426 gdk_wayland_window_set_group (GdkWindow *window,
4427 GdkWindow *leader)
4428 {
4429 }
4430
4431 static void
gdk_wayland_window_set_decorations(GdkWindow * window,GdkWMDecoration decorations)4432 gdk_wayland_window_set_decorations (GdkWindow *window,
4433 GdkWMDecoration decorations)
4434 {
4435 }
4436
4437 static gboolean
gdk_wayland_window_get_decorations(GdkWindow * window,GdkWMDecoration * decorations)4438 gdk_wayland_window_get_decorations (GdkWindow *window,
4439 GdkWMDecoration *decorations)
4440 {
4441 return FALSE;
4442 }
4443
4444 static void
gdk_wayland_window_set_functions(GdkWindow * window,GdkWMFunction functions)4445 gdk_wayland_window_set_functions (GdkWindow *window,
4446 GdkWMFunction functions)
4447 {
4448 }
4449
4450 static void
gdk_wayland_window_begin_resize_drag(GdkWindow * window,GdkWindowEdge edge,GdkDevice * device,gint button,gint root_x,gint root_y,guint32 timestamp)4451 gdk_wayland_window_begin_resize_drag (GdkWindow *window,
4452 GdkWindowEdge edge,
4453 GdkDevice *device,
4454 gint button,
4455 gint root_x,
4456 gint root_y,
4457 guint32 timestamp)
4458 {
4459 GdkWindowImplWayland *impl;
4460 GdkWaylandDisplay *display_wayland;
4461 GdkEventSequence *sequence;
4462 uint32_t resize_edges, serial;
4463
4464 if (GDK_WINDOW_DESTROYED (window) ||
4465 !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4466 return;
4467
4468 switch (edge)
4469 {
4470 case GDK_WINDOW_EDGE_NORTH_WEST:
4471 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT;
4472 break;
4473
4474 case GDK_WINDOW_EDGE_NORTH:
4475 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP;
4476 break;
4477
4478 case GDK_WINDOW_EDGE_NORTH_EAST:
4479 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT;
4480 break;
4481
4482 case GDK_WINDOW_EDGE_WEST:
4483 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT;
4484 break;
4485
4486 case GDK_WINDOW_EDGE_EAST:
4487 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT;
4488 break;
4489
4490 case GDK_WINDOW_EDGE_SOUTH_WEST:
4491 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT;
4492 break;
4493
4494 case GDK_WINDOW_EDGE_SOUTH:
4495 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM;
4496 break;
4497
4498 case GDK_WINDOW_EDGE_SOUTH_EAST:
4499 resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT;
4500 break;
4501
4502 default:
4503 g_warning ("gdk_window_begin_resize_drag: bad resize edge %d!", edge);
4504 return;
4505 }
4506
4507 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4508 display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
4509
4510 if (!is_realized_toplevel (window))
4511 return;
4512
4513 serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_device_get_seat (device),
4514 &sequence);
4515
4516 switch (display_wayland->shell_variant)
4517 {
4518 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4519 xdg_toplevel_resize (impl->display_server.xdg_toplevel,
4520 gdk_wayland_device_get_wl_seat (device),
4521 serial, resize_edges);
4522 break;
4523 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4524 zxdg_toplevel_v6_resize (impl->display_server.zxdg_toplevel_v6,
4525 gdk_wayland_device_get_wl_seat (device),
4526 serial, resize_edges);
4527 break;
4528 }
4529
4530 if (sequence)
4531 gdk_wayland_device_unset_touch_grab (device, sequence);
4532
4533 /* This is needed since Wayland will absorb all the pointer events after the
4534 * above function - FIXME: Is this always safe..?
4535 */
4536 gdk_seat_ungrab (gdk_device_get_seat (device));
4537 }
4538
4539 static void
gdk_wayland_window_begin_move_drag(GdkWindow * window,GdkDevice * device,gint button,gint root_x,gint root_y,guint32 timestamp)4540 gdk_wayland_window_begin_move_drag (GdkWindow *window,
4541 GdkDevice *device,
4542 gint button,
4543 gint root_x,
4544 gint root_y,
4545 guint32 timestamp)
4546 {
4547 GdkWindowImplWayland *impl;
4548 GdkWaylandDisplay *display_wayland;
4549 GdkEventSequence *sequence;
4550 uint32_t serial;
4551
4552 if (GDK_WINDOW_DESTROYED (window) ||
4553 !WINDOW_IS_TOPLEVEL (window))
4554 return;
4555
4556 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4557 display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
4558
4559 if (!is_realized_toplevel (window))
4560 return;
4561
4562 serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_device_get_seat (device),
4563 &sequence);
4564 switch (display_wayland->shell_variant)
4565 {
4566 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4567 xdg_toplevel_move (impl->display_server.xdg_toplevel,
4568 gdk_wayland_device_get_wl_seat (device),
4569 serial);
4570 break;
4571 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4572 zxdg_toplevel_v6_move (impl->display_server.zxdg_toplevel_v6,
4573 gdk_wayland_device_get_wl_seat (device),
4574 serial);
4575 break;
4576 }
4577
4578 if (sequence)
4579 gdk_wayland_device_unset_touch_grab (device, sequence);
4580
4581 /* This is needed since Wayland will absorb all the pointer events after the
4582 * above function - FIXME: Is this always safe..?
4583 */
4584 gdk_seat_ungrab (gdk_device_get_seat (device));
4585 }
4586
4587 static void
gdk_wayland_window_set_opacity(GdkWindow * window,gdouble opacity)4588 gdk_wayland_window_set_opacity (GdkWindow *window,
4589 gdouble opacity)
4590 {
4591 }
4592
4593 static void
gdk_wayland_window_set_composited(GdkWindow * window,gboolean composited)4594 gdk_wayland_window_set_composited (GdkWindow *window,
4595 gboolean composited)
4596 {
4597 }
4598
4599 static void
gdk_wayland_window_destroy_notify(GdkWindow * window)4600 gdk_wayland_window_destroy_notify (GdkWindow *window)
4601 {
4602 if (!GDK_WINDOW_DESTROYED (window))
4603 {
4604 if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
4605 g_warning ("GdkWindow %p unexpectedly destroyed", window);
4606
4607 _gdk_window_destroy (window, TRUE);
4608 }
4609
4610 g_object_unref (window);
4611 }
4612
4613 static void
gdk_wayland_window_sync_rendering(GdkWindow * window)4614 gdk_wayland_window_sync_rendering (GdkWindow *window)
4615 {
4616 }
4617
4618 static gboolean
gdk_wayland_window_simulate_key(GdkWindow * window,gint x,gint y,guint keyval,GdkModifierType modifiers,GdkEventType key_pressrelease)4619 gdk_wayland_window_simulate_key (GdkWindow *window,
4620 gint x,
4621 gint y,
4622 guint keyval,
4623 GdkModifierType modifiers,
4624 GdkEventType key_pressrelease)
4625 {
4626 return FALSE;
4627 }
4628
4629 static gboolean
gdk_wayland_window_simulate_button(GdkWindow * window,gint x,gint y,guint button,GdkModifierType modifiers,GdkEventType button_pressrelease)4630 gdk_wayland_window_simulate_button (GdkWindow *window,
4631 gint x,
4632 gint y,
4633 guint button,
4634 GdkModifierType modifiers,
4635 GdkEventType button_pressrelease)
4636 {
4637 return FALSE;
4638 }
4639
4640 static gboolean
gdk_wayland_window_get_property(GdkWindow * window,GdkAtom property,GdkAtom type,gulong offset,gulong length,gint pdelete,GdkAtom * actual_property_type,gint * actual_format_type,gint * actual_length,guchar ** data)4641 gdk_wayland_window_get_property (GdkWindow *window,
4642 GdkAtom property,
4643 GdkAtom type,
4644 gulong offset,
4645 gulong length,
4646 gint pdelete,
4647 GdkAtom *actual_property_type,
4648 gint *actual_format_type,
4649 gint *actual_length,
4650 guchar **data)
4651 {
4652 return FALSE;
4653 }
4654
4655 static void
gdk_wayland_window_change_property(GdkWindow * window,GdkAtom property,GdkAtom type,gint format,GdkPropMode mode,const guchar * data,gint nelements)4656 gdk_wayland_window_change_property (GdkWindow *window,
4657 GdkAtom property,
4658 GdkAtom type,
4659 gint format,
4660 GdkPropMode mode,
4661 const guchar *data,
4662 gint nelements)
4663 {
4664 if (property == gdk_atom_intern_static_string ("GDK_SELECTION"))
4665 gdk_wayland_selection_store (window, type, mode, data, nelements * (format / 8));
4666 }
4667
4668 static void
gdk_wayland_window_delete_property(GdkWindow * window,GdkAtom property)4669 gdk_wayland_window_delete_property (GdkWindow *window,
4670 GdkAtom property)
4671 {
4672 }
4673
4674 static gint
gdk_wayland_window_get_scale_factor(GdkWindow * window)4675 gdk_wayland_window_get_scale_factor (GdkWindow *window)
4676 {
4677 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4678
4679 if (GDK_WINDOW_DESTROYED (window))
4680 return 1;
4681
4682 return impl->scale;
4683 }
4684
4685 static void
gdk_wayland_window_set_opaque_region(GdkWindow * window,cairo_region_t * region)4686 gdk_wayland_window_set_opaque_region (GdkWindow *window,
4687 cairo_region_t *region)
4688 {
4689 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4690
4691 if (GDK_WINDOW_DESTROYED (window))
4692 return;
4693
4694 g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
4695 impl->opaque_region = cairo_region_reference (region);
4696 impl->opaque_region_dirty = TRUE;
4697 }
4698
4699 static void
gdk_wayland_window_set_shadow_width(GdkWindow * window,int left,int right,int top,int bottom)4700 gdk_wayland_window_set_shadow_width (GdkWindow *window,
4701 int left,
4702 int right,
4703 int top,
4704 int bottom)
4705 {
4706 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4707 gint new_width, new_height;
4708
4709 if (GDK_WINDOW_DESTROYED (window))
4710 return;
4711
4712 /* Reconfigure window to keep the same window geometry */
4713 new_width = (calculate_width_without_margin (window, window->width) +
4714 (left + right));
4715 new_height = (calculate_height_without_margin (window, window->height) +
4716 (top + bottom));
4717 gdk_wayland_window_maybe_configure (window, new_width, new_height, impl->scale);
4718
4719 impl->margin_left = left;
4720 impl->margin_right = right;
4721 impl->margin_top = top;
4722 impl->margin_bottom = bottom;
4723 }
4724
4725 static gboolean
gdk_wayland_window_show_window_menu(GdkWindow * window,GdkEvent * event)4726 gdk_wayland_window_show_window_menu (GdkWindow *window,
4727 GdkEvent *event)
4728 {
4729 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4730 GdkWaylandDisplay *display_wayland =
4731 GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
4732 struct wl_seat *seat;
4733 GdkWaylandDevice *device;
4734 GdkWindow *event_window;
4735 double x, y;
4736 uint32_t serial;
4737
4738 switch (event->type)
4739 {
4740 case GDK_BUTTON_PRESS:
4741 case GDK_BUTTON_RELEASE:
4742 case GDK_TOUCH_BEGIN:
4743 case GDK_TOUCH_END:
4744 break;
4745 default:
4746 return FALSE;
4747 }
4748
4749 if (!is_realized_toplevel (window))
4750 return FALSE;
4751
4752 device = GDK_WAYLAND_DEVICE (gdk_event_get_device (event));
4753 seat = gdk_wayland_device_get_wl_seat (GDK_DEVICE (device));
4754
4755 gdk_event_get_coords (event, &x, &y);
4756 event_window = gdk_event_get_window (event);
4757 while (gdk_window_get_window_type (event_window) != GDK_WINDOW_TOPLEVEL)
4758 {
4759 gdk_window_coords_to_parent (event_window, x, y, &x, &y);
4760 event_window = gdk_window_get_effective_parent (event_window);
4761 }
4762
4763 serial = _gdk_wayland_device_get_implicit_grab_serial (device, event);
4764
4765 switch (display_wayland->shell_variant)
4766 {
4767 case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
4768 xdg_toplevel_show_window_menu (impl->display_server.xdg_toplevel,
4769 seat, serial, x, y);
4770 break;
4771 case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
4772 zxdg_toplevel_v6_show_window_menu (impl->display_server.zxdg_toplevel_v6,
4773 seat, serial, x, y);
4774 break;
4775 }
4776
4777 return TRUE;
4778 }
4779
4780 static void
_gdk_window_impl_wayland_class_init(GdkWindowImplWaylandClass * klass)4781 _gdk_window_impl_wayland_class_init (GdkWindowImplWaylandClass *klass)
4782 {
4783 GObjectClass *object_class = G_OBJECT_CLASS (klass);
4784 GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass);
4785
4786 object_class->finalize = gdk_window_impl_wayland_finalize;
4787
4788 impl_class->ref_cairo_surface = gdk_wayland_window_ref_cairo_surface;
4789 impl_class->create_similar_image_surface = gdk_wayland_window_create_similar_image_surface;
4790 impl_class->show = gdk_wayland_window_show;
4791 impl_class->hide = gdk_wayland_window_hide;
4792 impl_class->withdraw = gdk_window_wayland_withdraw;
4793 impl_class->set_events = gdk_window_wayland_set_events;
4794 impl_class->get_events = gdk_window_wayland_get_events;
4795 impl_class->raise = gdk_window_wayland_raise;
4796 impl_class->lower = gdk_window_wayland_lower;
4797 impl_class->restack_under = gdk_window_wayland_restack_under;
4798 impl_class->restack_toplevel = gdk_window_wayland_restack_toplevel;
4799 impl_class->move_resize = gdk_window_wayland_move_resize;
4800 impl_class->move_to_rect = gdk_window_wayland_move_to_rect;
4801 impl_class->set_background = gdk_window_wayland_set_background;
4802 impl_class->reparent = gdk_window_wayland_reparent;
4803 impl_class->set_device_cursor = gdk_window_wayland_set_device_cursor;
4804 impl_class->get_geometry = gdk_window_wayland_get_geometry;
4805 impl_class->get_root_coords = gdk_window_wayland_get_root_coords;
4806 impl_class->get_device_state = gdk_window_wayland_get_device_state;
4807 impl_class->shape_combine_region = gdk_window_wayland_shape_combine_region;
4808 impl_class->input_shape_combine_region = gdk_window_wayland_input_shape_combine_region;
4809 impl_class->destroy = gdk_wayland_window_destroy;
4810 impl_class->destroy_foreign = gdk_window_wayland_destroy_foreign;
4811 impl_class->get_shape = gdk_wayland_window_get_shape;
4812 impl_class->get_input_shape = gdk_wayland_window_get_input_shape;
4813 impl_class->begin_paint = gdk_window_impl_wayland_begin_paint;
4814 impl_class->end_paint = gdk_window_impl_wayland_end_paint;
4815 impl_class->beep = gdk_window_impl_wayland_beep;
4816
4817 impl_class->focus = gdk_wayland_window_focus;
4818 impl_class->set_type_hint = gdk_wayland_window_set_type_hint;
4819 impl_class->get_type_hint = gdk_wayland_window_get_type_hint;
4820 impl_class->set_modal_hint = gdk_wayland_window_set_modal_hint;
4821 impl_class->set_skip_taskbar_hint = gdk_wayland_window_set_skip_taskbar_hint;
4822 impl_class->set_skip_pager_hint = gdk_wayland_window_set_skip_pager_hint;
4823 impl_class->set_urgency_hint = gdk_wayland_window_set_urgency_hint;
4824 impl_class->set_geometry_hints = gdk_wayland_window_set_geometry_hints;
4825 impl_class->set_title = gdk_wayland_window_set_title;
4826 impl_class->set_role = gdk_wayland_window_set_role;
4827 impl_class->set_startup_id = gdk_wayland_window_set_startup_id;
4828 impl_class->set_transient_for = gdk_wayland_window_set_transient_for;
4829 impl_class->get_frame_extents = gdk_wayland_window_get_frame_extents;
4830 impl_class->set_override_redirect = gdk_wayland_window_set_override_redirect;
4831 impl_class->set_accept_focus = gdk_wayland_window_set_accept_focus;
4832 impl_class->set_focus_on_map = gdk_wayland_window_set_focus_on_map;
4833 impl_class->set_icon_list = gdk_wayland_window_set_icon_list;
4834 impl_class->set_icon_name = gdk_wayland_window_set_icon_name;
4835 impl_class->iconify = gdk_wayland_window_iconify;
4836 impl_class->deiconify = gdk_wayland_window_deiconify;
4837 impl_class->stick = gdk_wayland_window_stick;
4838 impl_class->unstick = gdk_wayland_window_unstick;
4839 impl_class->maximize = gdk_wayland_window_maximize;
4840 impl_class->unmaximize = gdk_wayland_window_unmaximize;
4841 impl_class->fullscreen = gdk_wayland_window_fullscreen;
4842 impl_class->fullscreen_on_monitor = gdk_wayland_window_fullscreen_on_monitor;
4843 impl_class->unfullscreen = gdk_wayland_window_unfullscreen;
4844 impl_class->set_keep_above = gdk_wayland_window_set_keep_above;
4845 impl_class->set_keep_below = gdk_wayland_window_set_keep_below;
4846 impl_class->get_group = gdk_wayland_window_get_group;
4847 impl_class->set_group = gdk_wayland_window_set_group;
4848 impl_class->set_decorations = gdk_wayland_window_set_decorations;
4849 impl_class->get_decorations = gdk_wayland_window_get_decorations;
4850 impl_class->set_functions = gdk_wayland_window_set_functions;
4851 impl_class->begin_resize_drag = gdk_wayland_window_begin_resize_drag;
4852 impl_class->begin_move_drag = gdk_wayland_window_begin_move_drag;
4853 impl_class->set_opacity = gdk_wayland_window_set_opacity;
4854 impl_class->set_composited = gdk_wayland_window_set_composited;
4855 impl_class->destroy_notify = gdk_wayland_window_destroy_notify;
4856 impl_class->get_drag_protocol = _gdk_wayland_window_get_drag_protocol;
4857 impl_class->register_dnd = _gdk_wayland_window_register_dnd;
4858 impl_class->drag_begin = _gdk_wayland_window_drag_begin;
4859 impl_class->sync_rendering = gdk_wayland_window_sync_rendering;
4860 impl_class->simulate_key = gdk_wayland_window_simulate_key;
4861 impl_class->simulate_button = gdk_wayland_window_simulate_button;
4862 impl_class->get_property = gdk_wayland_window_get_property;
4863 impl_class->change_property = gdk_wayland_window_change_property;
4864 impl_class->delete_property = gdk_wayland_window_delete_property;
4865 impl_class->get_scale_factor = gdk_wayland_window_get_scale_factor;
4866 impl_class->set_opaque_region = gdk_wayland_window_set_opaque_region;
4867 impl_class->set_shadow_width = gdk_wayland_window_set_shadow_width;
4868 impl_class->show_window_menu = gdk_wayland_window_show_window_menu;
4869 impl_class->create_gl_context = gdk_wayland_window_create_gl_context;
4870 impl_class->invalidate_for_new_frame = gdk_wayland_window_invalidate_for_new_frame;
4871
4872 signals[COMMITTED] = g_signal_new ("committed",
4873 G_TYPE_FROM_CLASS (object_class),
4874 G_SIGNAL_RUN_LAST,
4875 0,
4876 NULL, NULL, NULL,
4877 G_TYPE_NONE, 0);
4878 }
4879
4880 void
_gdk_wayland_window_set_grab_seat(GdkWindow * window,GdkSeat * seat)4881 _gdk_wayland_window_set_grab_seat (GdkWindow *window,
4882 GdkSeat *seat)
4883 {
4884 GdkWindowImplWayland *impl;
4885
4886 g_return_if_fail (window != NULL);
4887
4888 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4889 impl->grab_input_seat = seat;
4890 }
4891
4892 /**
4893 * gdk_wayland_window_get_wl_surface:
4894 * @window: (type GdkWaylandWindow): a #GdkWindow
4895 *
4896 * Returns the Wayland surface of a #GdkWindow.
4897 *
4898 * Returns: (transfer none): a Wayland wl_surface
4899 *
4900 * Since: 3.8
4901 */
4902 struct wl_surface *
gdk_wayland_window_get_wl_surface(GdkWindow * window)4903 gdk_wayland_window_get_wl_surface (GdkWindow *window)
4904 {
4905 g_return_val_if_fail (GDK_IS_WAYLAND_WINDOW (window), NULL);
4906
4907 return GDK_WINDOW_IMPL_WAYLAND (window->impl)->display_server.wl_surface;
4908 }
4909
4910 struct wl_output *
gdk_wayland_window_get_wl_output(GdkWindow * window)4911 gdk_wayland_window_get_wl_output (GdkWindow *window)
4912 {
4913 GdkWindowImplWayland *impl;
4914
4915 g_return_val_if_fail (GDK_IS_WAYLAND_WINDOW (window), NULL);
4916
4917 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4918 /* We pick the head of the list as this is the last entered output */
4919 if (impl->display_server.outputs)
4920 return (struct wl_output *) impl->display_server.outputs->data;
4921
4922 return NULL;
4923 }
4924
4925 static struct wl_egl_window *
gdk_wayland_window_get_wl_egl_window(GdkWindow * window)4926 gdk_wayland_window_get_wl_egl_window (GdkWindow *window)
4927 {
4928 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4929
4930 if (impl->display_server.egl_window == NULL)
4931 {
4932 impl->display_server.egl_window =
4933 wl_egl_window_create (impl->display_server.wl_surface,
4934 impl->wrapper->width * impl->scale,
4935 impl->wrapper->height * impl->scale);
4936 wl_surface_set_buffer_scale (impl->display_server.wl_surface, impl->scale);
4937 }
4938
4939 return impl->display_server.egl_window;
4940 }
4941
4942 EGLSurface
gdk_wayland_window_get_egl_surface(GdkWindow * window,EGLConfig config)4943 gdk_wayland_window_get_egl_surface (GdkWindow *window,
4944 EGLConfig config)
4945 {
4946 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
4947 GdkWindowImplWayland *impl;
4948 struct wl_egl_window *egl_window;
4949
4950 g_return_val_if_fail (GDK_IS_WAYLAND_WINDOW (window), NULL);
4951
4952 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4953
4954 if (impl->egl_surface == NULL)
4955 {
4956 egl_window = gdk_wayland_window_get_wl_egl_window (window);
4957
4958 impl->egl_surface =
4959 eglCreateWindowSurface (display->egl_display, config, egl_window, NULL);
4960 }
4961
4962 return impl->egl_surface;
4963 }
4964
4965 EGLSurface
gdk_wayland_window_get_dummy_egl_surface(GdkWindow * window,EGLConfig config)4966 gdk_wayland_window_get_dummy_egl_surface (GdkWindow *window,
4967 EGLConfig config)
4968 {
4969 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
4970 GdkWindowImplWayland *impl;
4971
4972 g_return_val_if_fail (GDK_IS_WAYLAND_WINDOW (window), NULL);
4973
4974 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
4975
4976 if (impl->dummy_egl_surface == NULL)
4977 {
4978 impl->display_server.dummy_egl_window =
4979 wl_egl_window_create (impl->display_server.wl_surface, 1, 1);
4980
4981 impl->dummy_egl_surface =
4982 eglCreateWindowSurface (display->egl_display, config, impl->display_server.dummy_egl_window, NULL);
4983 }
4984
4985 return impl->dummy_egl_surface;
4986 }
4987
4988 struct gtk_surface1 *
gdk_wayland_window_get_gtk_surface(GdkWindow * window)4989 gdk_wayland_window_get_gtk_surface (GdkWindow *window)
4990 {
4991 g_return_val_if_fail (GDK_IS_WAYLAND_WINDOW (window), NULL);
4992
4993 return GDK_WINDOW_IMPL_WAYLAND (window->impl)->display_server.gtk_surface;
4994 }
4995
4996 /**
4997 * gdk_wayland_window_set_use_custom_surface:
4998 * @window: (type GdkWaylandWindow): a #GdkWindow
4999 *
5000 * Marks a #GdkWindow as a custom Wayland surface. The application is
5001 * expected to register the surface as some type of surface using
5002 * some Wayland interface.
5003 *
5004 * A good example would be writing a panel or on-screen-keyboard as an
5005 * out-of-process helper - as opposed to having those in the compositor
5006 * process. In this case the underlying surface isn’t an xdg_shell
5007 * surface and the panel or OSK client need to identify the wl_surface
5008 * as a panel or OSK to the compositor. The assumption is that the
5009 * compositor will expose a private interface to the special client
5010 * that lets the client identify the wl_surface as a panel or such.
5011 *
5012 * This function should be called before a #GdkWindow is shown. This is
5013 * best done by connecting to the #GtkWidget::realize signal:
5014 *
5015 * |[<!-- language="C" -->
5016 * static void
5017 * widget_realize_cb (GtkWidget *widget)
5018 * {
5019 * GdkWindow *window;
5020 * struct wl_surface *surface;
5021 * struct input_panel_surface *ip_surface;
5022 *
5023 * window = gtk_widget_get_window (widget);
5024 * gdk_wayland_window_set_custom_surface (window);
5025 *
5026 * surface = gdk_wayland_window_get_wl_surface (window);
5027 * ip_surface = input_panel_get_input_panel_surface (input_panel, surface);
5028 * input_panel_surface_set_panel (ip_surface);
5029 * }
5030 *
5031 * static void
5032 * setup_window (GtkWindow *window)
5033 * {
5034 * g_signal_connect (window, "realize", G_CALLBACK (widget_realize_cb), NULL);
5035 * }
5036 * ]|
5037 *
5038 * Since: 3.10
5039 */
5040 void
gdk_wayland_window_set_use_custom_surface(GdkWindow * window)5041 gdk_wayland_window_set_use_custom_surface (GdkWindow *window)
5042 {
5043 GdkWindowImplWayland *impl;
5044
5045 g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window));
5046
5047 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5048
5049 if (!impl->display_server.wl_surface)
5050 gdk_wayland_window_create_surface (window);
5051
5052 impl->use_custom_surface = TRUE;
5053 }
5054
5055 static void
maybe_set_gtk_surface_dbus_properties(GdkWindow * window)5056 maybe_set_gtk_surface_dbus_properties (GdkWindow *window)
5057 {
5058 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5059
5060 if (impl->application.was_set)
5061 return;
5062
5063 if (impl->application.application_id == NULL &&
5064 impl->application.app_menu_path == NULL &&
5065 impl->application.menubar_path == NULL &&
5066 impl->application.window_object_path == NULL &&
5067 impl->application.application_object_path == NULL &&
5068 impl->application.unique_bus_name == NULL)
5069 return;
5070
5071 gdk_wayland_window_init_gtk_surface (window);
5072 if (impl->display_server.gtk_surface == NULL)
5073 return;
5074
5075 gtk_surface1_set_dbus_properties (impl->display_server.gtk_surface,
5076 impl->application.application_id,
5077 impl->application.app_menu_path,
5078 impl->application.menubar_path,
5079 impl->application.window_object_path,
5080 impl->application.application_object_path,
5081 impl->application.unique_bus_name);
5082 impl->application.was_set = TRUE;
5083 }
5084
5085 void
gdk_wayland_window_set_dbus_properties_libgtk_only(GdkWindow * window,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)5086 gdk_wayland_window_set_dbus_properties_libgtk_only (GdkWindow *window,
5087 const char *application_id,
5088 const char *app_menu_path,
5089 const char *menubar_path,
5090 const char *window_object_path,
5091 const char *application_object_path,
5092 const char *unique_bus_name)
5093 {
5094 GdkWindowImplWayland *impl;
5095
5096 g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window));
5097
5098 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5099
5100 impl->application.application_id = g_strdup (application_id);
5101 impl->application.app_menu_path = g_strdup (app_menu_path);
5102 impl->application.menubar_path = g_strdup (menubar_path);
5103 impl->application.window_object_path = g_strdup (window_object_path);
5104 impl->application.application_object_path =
5105 g_strdup (application_object_path);
5106 impl->application.unique_bus_name = g_strdup (unique_bus_name);
5107
5108 maybe_set_gtk_surface_dbus_properties (window);
5109 }
5110
5111 void
_gdk_wayland_window_offset_next_wl_buffer(GdkWindow * window,int x,int y)5112 _gdk_wayland_window_offset_next_wl_buffer (GdkWindow *window,
5113 int x,
5114 int y)
5115 {
5116 GdkWindowImplWayland *impl;
5117
5118 g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window));
5119
5120 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5121
5122 impl->pending_buffer_offset_x = x;
5123 impl->pending_buffer_offset_y = y;
5124 }
5125
5126 static void
invoke_exported_closures(GdkWindow * window)5127 invoke_exported_closures (GdkWindow *window)
5128 {
5129 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5130 GList *l;
5131
5132 for (l = impl->exported.closures; l; l = l->next)
5133 {
5134 ExportedClosure *closure = l->data;
5135
5136 closure->callback (window, impl->exported.handle, closure->user_data);
5137
5138 if (closure->destroy_func)
5139 closure->destroy_func (closure->user_data);
5140 }
5141
5142 g_list_free_full (impl->exported.closures, g_free);
5143 impl->exported.closures = NULL;
5144 }
5145
5146 static void
xdg_exported_handle(void * data,struct zxdg_exported_v1 * zxdg_exported_v1,const char * handle)5147 xdg_exported_handle (void *data,
5148 struct zxdg_exported_v1 *zxdg_exported_v1,
5149 const char *handle)
5150 {
5151 GdkWindow *window = data;
5152 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5153
5154 impl->exported.handle = g_strdup (handle);
5155
5156 invoke_exported_closures (window);
5157 }
5158
5159 static const struct zxdg_exported_v1_listener xdg_exported_listener = {
5160 xdg_exported_handle
5161 };
5162
5163 /**
5164 * GdkWaylandWindowExported:
5165 * @window: the #GdkWindow that is exported
5166 * @handle: the handle
5167 * @user_data: user data that was passed to gdk_wayland_window_export_handle()
5168 *
5169 * Callback that gets called when the handle for a window has been
5170 * obtained from the Wayland compositor. The handle can be passed
5171 * to other processes, for the purpose of marking windows as transient
5172 * for out-of-process surfaces.
5173 *
5174 * Since: 3.22
5175 */
5176
5177 static gboolean
gdk_wayland_window_is_exported(GdkWindow * window)5178 gdk_wayland_window_is_exported (GdkWindow *window)
5179 {
5180 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5181
5182 return !!impl->display_server.xdg_exported;
5183 }
5184
5185 static gboolean
exported_idle(gpointer user_data)5186 exported_idle (gpointer user_data)
5187 {
5188 GdkWindow *window = user_data;
5189 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5190
5191 invoke_exported_closures (window);
5192
5193 impl->exported.idle_source_id = 0;
5194
5195 return G_SOURCE_REMOVE;
5196 }
5197
5198 /**
5199 * gdk_wayland_window_export_handle:
5200 * @window: the #GdkWindow to obtain a handle for
5201 * @callback: callback to call with the handle
5202 * @user_data: user data for @callback
5203 * @destroy_func: destroy notify for @user_data
5204 *
5205 * Asynchronously obtains a handle for a surface that can be passed
5206 * to other processes. When the handle has been obtained, @callback
5207 * will be called.
5208 *
5209 * Up until 3.22.15 it was an error to call this function on a window that is
5210 * already exported. When the handle is no longer needed,
5211 * gdk_wayland_window_unexport_handle() should be called to clean up resources.
5212 *
5213 * Starting with 3.22.16, calling this function on an already exported window
5214 * will cause the callback to be invoked with the same handle as was already
5215 * invoked, from an idle callback. To unexport the window,
5216 * gdk_wayland_window_unexport_handle() must be called the same number of times
5217 * as gdk_wayland_window_export_handle() was called. Any 'exported' callback
5218 * may still be invoked until the window is unexported or destroyed.
5219 *
5220 * The main purpose for obtaining a handle is to mark a surface
5221 * from another window as transient for this one, see
5222 * gdk_wayland_window_set_transient_for_exported().
5223 *
5224 * Note that this API depends on an unstable Wayland protocol,
5225 * and thus may require changes in the future.
5226 *
5227 * Return value: %TRUE if the handle has been requested, %FALSE if
5228 * an error occurred.
5229 *
5230 * Since: 3.22
5231 */
5232 gboolean
gdk_wayland_window_export_handle(GdkWindow * window,GdkWaylandWindowExported callback,gpointer user_data,GDestroyNotify destroy_func)5233 gdk_wayland_window_export_handle (GdkWindow *window,
5234 GdkWaylandWindowExported callback,
5235 gpointer user_data,
5236 GDestroyNotify destroy_func)
5237 {
5238 GdkWindowImplWayland *impl;
5239 GdkWaylandDisplay *display_wayland;
5240 GdkDisplay *display = gdk_window_get_display (window);
5241 ExportedClosure *closure;
5242
5243 g_return_val_if_fail (GDK_IS_WAYLAND_WINDOW (window), FALSE);
5244 g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
5245
5246 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5247 display_wayland = GDK_WAYLAND_DISPLAY (display);
5248
5249 if (!display_wayland->xdg_exporter)
5250 {
5251 g_warning ("Server is missing xdg_foreign support");
5252 return FALSE;
5253 }
5254
5255 if (!impl->display_server.xdg_exported)
5256 {
5257 struct zxdg_exported_v1 *xdg_exported;
5258
5259 xdg_exported = zxdg_exporter_v1_export (display_wayland->xdg_exporter,
5260 impl->display_server.wl_surface);
5261 zxdg_exported_v1_add_listener (xdg_exported,
5262 &xdg_exported_listener,
5263 window);
5264
5265 impl->display_server.xdg_exported = xdg_exported;
5266 }
5267
5268 closure = g_new0 (ExportedClosure, 1);
5269 closure->callback = callback;
5270 closure->user_data = user_data;
5271 closure->destroy_func = destroy_func;
5272
5273 impl->exported.closures = g_list_append (impl->exported.closures, closure);
5274 impl->exported.export_count++;
5275
5276 if (impl->exported.handle && !impl->exported.idle_source_id)
5277 impl->exported.idle_source_id = g_idle_add (exported_idle, window);
5278
5279 return TRUE;
5280 }
5281
5282 static void
gdk_wayland_window_unexport(GdkWindow * window)5283 gdk_wayland_window_unexport (GdkWindow *window)
5284 {
5285 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5286 GList *l;
5287
5288 g_clear_pointer (&impl->display_server.xdg_exported,
5289 zxdg_exported_v1_destroy);
5290
5291 for (l = impl->exported.closures; l; l = l->next)
5292 {
5293 ExportedClosure *closure = l->data;
5294
5295 if (closure->destroy_func)
5296 closure->destroy_func (closure->user_data);
5297 }
5298
5299 g_list_free_full (impl->exported.closures, g_free);
5300 impl->exported.closures = NULL;
5301 g_clear_pointer (&impl->exported.handle, g_free);
5302
5303 if (impl->exported.idle_source_id)
5304 {
5305 g_source_remove (impl->exported.idle_source_id);
5306 impl->exported.idle_source_id = 0;
5307 }
5308 }
5309
5310 /**
5311 * gdk_wayland_window_unexport_handle:
5312 * @window: the #GdkWindow to unexport
5313 *
5314 * Destroys the handle that was obtained with
5315 * gdk_wayland_window_export_handle().
5316 *
5317 * It is an error to call this function on a window that
5318 * does not have a handle.
5319 *
5320 * Note that this API depends on an unstable Wayland protocol,
5321 * and thus may require changes in the future.
5322 *
5323 * Since: 3.22
5324 */
5325 void
gdk_wayland_window_unexport_handle(GdkWindow * window)5326 gdk_wayland_window_unexport_handle (GdkWindow *window)
5327 {
5328 GdkWindowImplWayland *impl;
5329
5330 g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window));
5331
5332 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5333
5334 g_return_if_fail (impl->display_server.xdg_exported);
5335
5336 impl->exported.export_count--;
5337 if (impl->exported.export_count == 0)
5338 gdk_wayland_window_unexport (window);
5339 }
5340
5341 static void
unset_transient_for_exported(GdkWindow * window)5342 unset_transient_for_exported (GdkWindow *window)
5343 {
5344 GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5345
5346 g_clear_pointer (&impl->imported_transient_for, zxdg_imported_v1_destroy);
5347 }
5348
5349 static void
xdg_imported_destroyed(void * data,struct zxdg_imported_v1 * zxdg_imported_v1)5350 xdg_imported_destroyed (void *data,
5351 struct zxdg_imported_v1 *zxdg_imported_v1)
5352 {
5353 GdkWindow *window = data;
5354
5355 unset_transient_for_exported (window);
5356 }
5357
5358 static const struct zxdg_imported_v1_listener xdg_imported_listener = {
5359 xdg_imported_destroyed,
5360 };
5361
5362 /**
5363 * gdk_wayland_window_set_transient_for_exported:
5364 * @window: the #GdkWindow to make as transient
5365 * @parent_handle_str: an exported handle for a surface
5366 *
5367 * Marks @window as transient for the surface to which the given
5368 * @parent_handle_str refers. Typically, the handle will originate
5369 * from a gdk_wayland_window_export_handle() call in another process.
5370 *
5371 * Note that this API depends on an unstable Wayland protocol,
5372 * and thus may require changes in the future.
5373 *
5374 * Return value: %TRUE if the window has been marked as transient,
5375 * %FALSE if an error occurred.
5376 *
5377 * Since: 3.22
5378 */
5379 gboolean
gdk_wayland_window_set_transient_for_exported(GdkWindow * window,char * parent_handle_str)5380 gdk_wayland_window_set_transient_for_exported (GdkWindow *window,
5381 char *parent_handle_str)
5382 {
5383 GdkWindowImplWayland *impl;
5384 GdkWaylandDisplay *display_wayland;
5385 GdkDisplay *display = gdk_window_get_display (window);
5386
5387 g_return_val_if_fail (GDK_IS_WAYLAND_WINDOW (window), FALSE);
5388 g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
5389 g_return_val_if_fail (!should_map_as_subsurface (window) &&
5390 !should_map_as_popup (window), FALSE);
5391
5392 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5393 display_wayland = GDK_WAYLAND_DISPLAY (display);
5394
5395 if (!display_wayland->xdg_importer)
5396 {
5397 g_warning ("Server is missing xdg_foreign support");
5398 return FALSE;
5399 }
5400
5401 gdk_window_set_transient_for (window, NULL);
5402
5403 impl->imported_transient_for =
5404 zxdg_importer_v1_import (display_wayland->xdg_importer, parent_handle_str);
5405 zxdg_imported_v1_add_listener (impl->imported_transient_for,
5406 &xdg_imported_listener,
5407 window);
5408
5409 gdk_wayland_window_sync_parent_of_imported (window);
5410
5411 return TRUE;
5412 }
5413
5414 static struct zwp_keyboard_shortcuts_inhibitor_v1 *
gdk_wayland_window_get_inhibitor(GdkWindowImplWayland * impl,struct wl_seat * seat)5415 gdk_wayland_window_get_inhibitor (GdkWindowImplWayland *impl,
5416 struct wl_seat *seat)
5417 {
5418 return g_hash_table_lookup (impl->shortcuts_inhibitors, seat);
5419 }
5420
5421 void
gdk_wayland_window_inhibit_shortcuts(GdkWindow * window,GdkSeat * gdk_seat)5422 gdk_wayland_window_inhibit_shortcuts (GdkWindow *window,
5423 GdkSeat *gdk_seat)
5424 {
5425 GdkWindowImplWayland *impl= GDK_WINDOW_IMPL_WAYLAND (window->impl);
5426 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
5427 struct wl_surface *surface = impl->display_server.wl_surface;
5428 struct wl_seat *seat = gdk_wayland_seat_get_wl_seat (gdk_seat);
5429 struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
5430
5431 if (display->keyboard_shortcuts_inhibit == NULL)
5432 return;
5433
5434 if (gdk_wayland_window_get_inhibitor (impl, seat))
5435 return; /* Already inhibitted */
5436
5437 inhibitor =
5438 zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts (
5439 display->keyboard_shortcuts_inhibit, surface, seat);
5440
5441 g_hash_table_insert (impl->shortcuts_inhibitors, seat, inhibitor);
5442 }
5443
5444 void
gdk_wayland_window_restore_shortcuts(GdkWindow * window,GdkSeat * gdk_seat)5445 gdk_wayland_window_restore_shortcuts (GdkWindow *window,
5446 GdkSeat *gdk_seat)
5447 {
5448 GdkWindowImplWayland *impl;
5449 struct wl_seat *seat;
5450 struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
5451
5452 g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window));
5453 g_return_if_fail (GDK_IS_WINDOW_IMPL_WAYLAND (window->impl));
5454
5455 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5456 seat = gdk_wayland_seat_get_wl_seat (gdk_seat);
5457
5458 inhibitor = gdk_wayland_window_get_inhibitor (impl, seat);
5459 if (inhibitor == NULL)
5460 return; /* Not inhibitted */
5461
5462 zwp_keyboard_shortcuts_inhibitor_v1_destroy (inhibitor);
5463 g_hash_table_remove (impl->shortcuts_inhibitors, seat);
5464 }
5465
5466 /**
5467 * gdk_wayland_window_add_frame_callback_surface:
5468 * @window: the #GdkWindow requesting callbacks
5469 * @surface: the wl_surface to add
5470 *
5471 * Add @surface to a list of surfaces for which frame callback
5472 * listeners will get set up, additionally to the one of @window.
5473 *
5474 * This is useful when clients use subsurfaces independently of GDK.
5475 * For example if a client creates a subsurface that covers @window
5476 * entirely. If this subsurface is opaque, Wayland compositors may not
5477 * emit callbacks for the surface of @window any more.
5478 * Adding the covering subsurface via this function ensures the
5479 * @window will continue to update.
5480 *
5481 * A single callback is sufficient to trigger the next update. If more
5482 * than one are triggered, the later ones will get ignored.
5483 *
5484 * Before @surface gets destroyed it must get removed again using
5485 * gdk_wayland_window_remove_frame_callback_surface().
5486 *
5487 * Note that the client is responsible to commit the @surface.
5488 * One way to archive this is to always commit after the
5489 * #GdkSurface::after-paint signal was triggered.
5490 *
5491 * Since: 3.24.25
5492 */
5493 void
gdk_wayland_window_add_frame_callback_surface(GdkWindow * window,struct wl_surface * surface)5494 gdk_wayland_window_add_frame_callback_surface (GdkWindow *window,
5495 struct wl_surface *surface)
5496 {
5497 GdkWindowImplWayland *impl;
5498
5499 g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window));
5500 g_return_if_fail (GDK_IS_WINDOW_IMPL_WAYLAND (window->impl));
5501 g_return_if_fail (surface != NULL);
5502
5503 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5504
5505 g_hash_table_insert (impl->frame_callback_surfaces, surface, NULL);
5506 }
5507
5508 /**
5509 * gdk_wayland_window_remove_frame_callback_surface:
5510 * @window: the #GdkWindow requesting callbacks
5511 * @surface: the surface to remove
5512 *
5513 * Remove @surface from the list of surfaces again that got added via
5514 * gdk_wayland_window_add_frame_callback_surface().
5515 *
5516 * This function must be called before @surface gets destroyed.
5517 *
5518 * Since: 3.24.25
5519 */
5520 void
gdk_wayland_window_remove_frame_callback_surface(GdkWindow * window,struct wl_surface * surface)5521 gdk_wayland_window_remove_frame_callback_surface (GdkWindow *window,
5522 struct wl_surface *surface)
5523 {
5524 GdkWindowImplWayland *impl;
5525
5526 g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window));
5527 g_return_if_fail (GDK_IS_WINDOW_IMPL_WAYLAND (window->impl));
5528 g_return_if_fail (surface != NULL);
5529
5530 impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
5531
5532 g_hash_table_remove (impl->frame_callback_surfaces, surface);
5533 }
5534