gdkwindow-wayland.c 158 KB
Newer Older
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * Copyright © 2010 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
Javier Jardon's avatar
Javier Jardon committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Kristian Høgsberg's avatar
Kristian Høgsberg committed
16 17 18 19 20 21 22 23 24 25 26 27 28
 */

#include "config.h"

#include <netinet/in.h>
#include <unistd.h>

#include "gdk.h"
#include "gdkwayland.h"

#include "gdkwindow.h"
#include "gdkwindowimpl.h"
#include "gdkdisplay-wayland.h"
29
#include "gdkglcontext-wayland.h"
30
#include "gdkframeclockprivate.h"
Kristian Høgsberg's avatar
Kristian Høgsberg committed
31 32 33
#include "gdkprivate-wayland.h"
#include "gdkinternals.h"
#include "gdkdeviceprivate.h"
34 35
#include "gdkprivate-wayland.h"
#include "xdg-shell-unstable-v6-client-protocol.h"
Kristian Høgsberg's avatar
Kristian Høgsberg committed
36 37 38 39

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
40
#include <errno.h>
Kristian Høgsberg's avatar
Kristian Høgsberg committed
41

42 43 44 45 46 47 48 49
enum {
  COMMITTED,

  LAST_SIGNAL
};

static guint signals[LAST_SIGNAL];

Kristian Høgsberg's avatar
Kristian Høgsberg committed
50 51 52 53
#define WINDOW_IS_TOPLEVEL_OR_FOREIGN(window) \
  (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&   \
   GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)

Matthias Clasen's avatar
Matthias Clasen committed
54
#define WINDOW_IS_TOPLEVEL(window)                   \
Kristian Høgsberg's avatar
Kristian Høgsberg committed
55 56 57 58
  (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&   \
   GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN && \
   GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)

59 60
#define MAX_WL_BUFFER_SIZE (4083) /* 4096 minus header, string argument length and NUL byte */

Kristian Høgsberg's avatar
Kristian Høgsberg committed
61 62 63
typedef struct _GdkWaylandWindow GdkWaylandWindow;
typedef struct _GdkWaylandWindowClass GdkWaylandWindowClass;

Matthias Clasen's avatar
Matthias Clasen committed
64 65
struct _GdkWaylandWindow
{
Kristian Høgsberg's avatar
Kristian Høgsberg committed
66 67 68
  GdkWindow parent;
};

Matthias Clasen's avatar
Matthias Clasen committed
69 70
struct _GdkWaylandWindowClass
{
Kristian Høgsberg's avatar
Kristian Høgsberg committed
71 72 73
  GdkWindowClass parent_class;
};

74
G_DEFINE_TYPE (GdkWaylandWindow, gdk_wayland_window, GDK_TYPE_WINDOW)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
75 76

static void
77
gdk_wayland_window_class_init (GdkWaylandWindowClass *wayland_window_class)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
78 79 80 81
{
}

static void
82
gdk_wayland_window_init (GdkWaylandWindow *wayland_window)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
83 84 85
{
}

86 87 88 89 90 91 92 93 94 95
#define GDK_TYPE_WINDOW_IMPL_WAYLAND              (_gdk_window_impl_wayland_get_type ())
#define GDK_WINDOW_IMPL_WAYLAND(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WINDOW_IMPL_WAYLAND, GdkWindowImplWayland))
#define GDK_WINDOW_IMPL_WAYLAND_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WINDOW_IMPL_WAYLAND, GdkWindowImplWaylandClass))
#define GDK_IS_WINDOW_IMPL_WAYLAND(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WINDOW_IMPL_WAYLAND))
#define GDK_IS_WINDOW_IMPL_WAYLAND_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WINDOW_IMPL_WAYLAND))
#define GDK_WINDOW_IMPL_WAYLAND_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WINDOW_IMPL_WAYLAND, GdkWindowImplWaylandClass))

typedef struct _GdkWindowImplWayland GdkWindowImplWayland;
typedef struct _GdkWindowImplWaylandClass GdkWindowImplWaylandClass;

96 97 98 99 100 101 102
typedef enum _PositionMethod
{
  POSITION_METHOD_NONE,
  POSITION_METHOD_MOVE_RESIZE,
  POSITION_METHOD_MOVE_TO_RECT
} PositionMethod;

103 104 105 106 107 108 109
typedef struct _ExportedClosure
{
  GdkWaylandWindowExported callback;
  gpointer user_data;
  GDestroyNotify destroy_func;
} ExportedClosure;

110 111 112 113 114 115
struct _GdkWindowImplWayland
{
  GdkWindowImpl parent_instance;

  GdkWindow *wrapper;

116 117 118 119 120
  struct {
    /* The wl_outputs that this window currently touches */
    GSList               *outputs;

    struct wl_surface    *wl_surface;
121 122 123 124 125 126 127 128 129 130

    struct xdg_surface *xdg_surface;
    struct xdg_toplevel *xdg_toplevel;
    struct xdg_popup *xdg_popup;

    /* Legacy xdg-shell unstable v6 fallback support */
    struct zxdg_surface_v6 *zxdg_surface_v6;
    struct zxdg_toplevel_v6 *zxdg_toplevel_v6;
    struct zxdg_popup_v6 *zxdg_popup_v6;

131
    struct gtk_surface1  *gtk_surface;
132 133 134
    struct wl_subsurface *wl_subsurface;
    struct wl_egl_window *egl_window;
    struct wl_egl_window *dummy_egl_window;
135
    struct zxdg_exported_v1 *xdg_exported;
136
    struct org_kde_kwin_server_decoration *server_decoration;
137
  } display_server;
138

139
  EGLSurface egl_surface;
140 141
  EGLSurface dummy_egl_surface;

142
  unsigned int initial_configure_received : 1;
143
  unsigned int mapped : 1;
144
  unsigned int use_custom_surface : 1;
145
  unsigned int pending_buffer_attached : 1;
146
  unsigned int pending_commit : 1;
147
  unsigned int awaiting_frame : 1;
148
  GdkWindowTypeHint hint;
149
  GdkWindow *transient_for;
150
  GdkWindow *popup_parent;
151
  PositionMethod position_method;
152

153 154 155 156
  cairo_surface_t *staging_cairo_surface;
  cairo_surface_t *committed_cairo_surface;
  cairo_surface_t *backfill_cairo_surface;

157 158
  int pending_buffer_offset_x;
  int pending_buffer_offset_y;
159

160 161
  gchar *title;

162 163 164 165 166 167 168 169 170 171 172
  struct {
    gboolean was_set;

    gchar *application_id;
    gchar *app_menu_path;
    gchar *menubar_path;
    gchar *window_object_path;
    gchar *application_object_path;
    gchar *unique_bus_name;
  } application;

173 174
  GdkGeometry geometry_hints;
  GdkWindowHints geometry_mask;
175

176
  GdkSeat *grab_input_seat;
177

178
  gint64 pending_frame_counter;
179
  guint32 scale;
180 181 182 183 184

  int margin_left;
  int margin_right;
  int margin_top;
  int margin_bottom;
185
  gboolean margin_dirty;
186

187
  int initial_fullscreen_monitor;
188 189

  cairo_region_t *opaque_region;
190 191
  gboolean opaque_region_dirty;

192
  cairo_region_t *input_region;
193 194
  gboolean input_region_dirty;

195
  cairo_region_t *staged_updates_region;
196 197 198

  int saved_width;
  int saved_height;
199 200

  gulong parent_surface_committed_handler;
201 202 203 204 205 206 207 208 209

  struct {
    GdkRectangle rect;
    GdkGravity rect_anchor;
    GdkGravity window_anchor;
    GdkAnchorHints anchor_hints;
    gint rect_anchor_dx;
    gint rect_anchor_dy;
  } pending_move_to_rect;
210 211

  struct {
212 213
    int width;
    int height;
214 215
    GdkWindowState state;
  } pending;
216 217

  struct {
218 219 220 221
    char *handle;
    int export_count;
    GList *closures;
    guint idle_source_id;
222
  } exported;
223 224

  struct zxdg_imported_v1 *imported_transient_for;
225
  GHashTable *shortcuts_inhibitors;
226 227 228 229 230 231 232
};

struct _GdkWindowImplWaylandClass
{
  GdkWindowImplClass parent_class;
};

233 234 235 236
static void gdk_wayland_window_maybe_configure (GdkWindow *window,
                                                int        width,
                                                int        height,
                                                int        scale);
237

238
static void maybe_set_gtk_surface_dbus_properties (GdkWindow *window);
239
static void maybe_set_gtk_surface_modal (GdkWindow *window);
240

241 242
static void gdk_window_request_transient_parent_commit (GdkWindow *window);

243 244 245 246
static void gdk_wayland_window_sync_margin (GdkWindow *window);
static void gdk_wayland_window_sync_input_region (GdkWindow *window);
static void gdk_wayland_window_sync_opaque_region (GdkWindow *window);

247 248
static void unset_transient_for_exported (GdkWindow *window);

249 250 251 252 253 254 255 256 257 258
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);

259
static gboolean gdk_wayland_window_is_exported (GdkWindow *window);
260
static void gdk_wayland_window_unexport (GdkWindow *window);
261

262 263
GType _gdk_window_impl_wayland_get_type (void);

Kristian Høgsberg's avatar
Kristian Høgsberg committed
264 265 266 267
G_DEFINE_TYPE (GdkWindowImplWayland, _gdk_window_impl_wayland, GDK_TYPE_WINDOW_IMPL)

static void
_gdk_window_impl_wayland_init (GdkWindowImplWayland *impl)
268
{
269
  impl->scale = 1;
270
  impl->initial_fullscreen_monitor = -1;
271 272
  impl->saved_width = -1;
  impl->saved_height = -1;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
273 274
}

275 276 277
static void
_gdk_wayland_screen_add_orphan_dialog (GdkWindow *window)
{
278 279 280 281 282 283
  GdkWaylandDisplay *display_wayland =
    GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));

  if (!g_list_find (display_wayland->orphan_dialogs, window))
    display_wayland->orphan_dialogs =
      g_list_prepend (display_wayland->orphan_dialogs, window);
284 285
}

286 287 288 289 290 291 292 293 294 295 296 297 298 299
static void
drop_cairo_surfaces (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);

  g_clear_pointer (&impl->staging_cairo_surface, cairo_surface_destroy);
  g_clear_pointer (&impl->backfill_cairo_surface, cairo_surface_destroy);

  /* We nullify this so if a buffer release comes in later, we won't
   * try to reuse that buffer since it's no longer suitable
   */
  impl->committed_cairo_surface = NULL;
}

300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
static void
_gdk_wayland_window_save_size (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);

  if (window->state & (GDK_WINDOW_STATE_FULLSCREEN | GDK_WINDOW_STATE_MAXIMIZED))
    return;

  impl->saved_width = window->width - impl->margin_left - impl->margin_right;
  impl->saved_height = window->height - impl->margin_top - impl->margin_bottom;
}

static void
_gdk_wayland_window_clear_saved_size (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);

  if (window->state & (GDK_WINDOW_STATE_FULLSCREEN | GDK_WINDOW_STATE_MAXIMIZED))
    return;

  impl->saved_width = -1;
  impl->saved_height = -1;
}

324
/*
325
 * gdk_wayland_window_update_size:
Kristian Høgsberg's avatar
Kristian Høgsberg committed
326
 * @drawable: a #GdkDrawableImplWayland.
Matthias Clasen's avatar
Matthias Clasen committed
327
 *
Kristian Høgsberg's avatar
Kristian Høgsberg committed
328 329
 * Updates the state of the drawable (in particular the drawable's
 * cairo surface) when its size has changed.
Matthias Clasen's avatar
Matthias Clasen committed
330
 */
331 332
static void
gdk_wayland_window_update_size (GdkWindow *window,
Matthias Clasen's avatar
Matthias Clasen committed
333
                                int32_t    width,
334 335
                                int32_t    height,
                                int        scale)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
336
{
337
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
338 339
  GdkRectangle area;
  cairo_region_t *region;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
340

341 342 343 344 345
  if ((window->width == width) &&
      (window->height == height) &&
      (impl->scale == scale))
    return;

346
  drop_cairo_surfaces (window);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
347

348 349
  window->width = width;
  window->height = height;
350
  impl->scale = scale;
351

352
  if (impl->display_server.egl_window)
353 354 355
    wl_egl_window_resize (impl->display_server.egl_window, width * scale, height * scale, 0, 0);
  if (impl->display_server.wl_surface)
    wl_surface_set_buffer_scale (impl->display_server.wl_surface, scale);
356

357 358 359 360 361 362 363 364
  area.x = 0;
  area.y = 0;
  area.width = window->width;
  area.height = window->height;

  region = cairo_region_create_rectangle (&area);
  _gdk_window_invalidate_for_expose (window, region);
  cairo_region_destroy (region);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
365 366 367 368
}

GdkWindow *
_gdk_wayland_screen_create_root_window (GdkScreen *screen,
Matthias Clasen's avatar
Matthias Clasen committed
369 370
                                        int        width,
                                        int        height)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
371
{
372
  GdkWaylandDisplay *display_wayland =
373
    GDK_WAYLAND_DISPLAY (gdk_screen_get_display (screen));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
374 375 376
  GdkWindow *window;
  GdkWindowImplWayland *impl;

377
  window = _gdk_display_create_window (GDK_DISPLAY (display_wayland));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
378 379 380 381 382 383 384
  window->impl = g_object_new (GDK_TYPE_WINDOW_IMPL_WAYLAND, NULL);
  window->impl_window = window;
  window->visual = gdk_screen_get_system_visual (screen);

  impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);

  impl->wrapper = GDK_WINDOW (window);
385
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
386
  if (display_wayland->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE &&
Matthias Clasen's avatar
Matthias Clasen committed
387
      gdk_screen_get_n_monitors (screen) > 0)
388
    impl->scale = gdk_screen_get_monitor_scale_factor (screen, 0);
389
G_GNUC_END_IGNORE_DEPRECATIONS
390 391

  /* logical 1x1 fake buffer */
392 393 394
  impl->staging_cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                                            impl->scale,
                                                            impl->scale);
395

396
  cairo_surface_set_device_scale (impl->staging_cairo_surface, impl->scale, impl->scale);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428

  window->window_type = GDK_WINDOW_ROOT;
  window->depth = 32;

  window->x = 0;
  window->y = 0;
  window->abs_x = 0;
  window->abs_y = 0;
  window->width = width;
  window->height = height;
  window->viewable = TRUE;

  /* see init_randr_support() in gdkscreen-wayland.c */
  window->event_mask = GDK_STRUCTURE_MASK;

  return window;
}

static const gchar *
get_default_title (void)
{
  const char *title;

  title = g_get_application_name ();
  if (!title)
    title = g_get_prgname ();
  if (!title)
    title = "";

  return title;
}

429 430 431 432 433 434 435 436 437 438
static void
fill_presentation_time_from_frame_time (GdkFrameTimings *timings,
                                        guint32          frame_time)
{
  /* The timestamp in a wayland frame is a msec time value that in some
   * way reflects the time at which the server started drawing the frame.
   * This is not useful from our perspective.
   *
   * However, for the DRM backend of Weston, on reasonably recent
   * Linux, we know that the time is the
Matthias Clasen's avatar
Matthias Clasen committed
439
   * clock_gettime (CLOCK_MONOTONIC) value at the vblank, and that
440 441 442 443
   * backend starts drawing immediately after receiving the vblank
   * notification. If we detect this, and make the assumption that the
   * compositor will finish drawing before the next vblank, we can
   * then determine the presentation time as the frame time we
Matthias Clasen's avatar
Matthias Clasen committed
444
   * received plus one refresh interval.
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
   *
   * If a backend is using clock_gettime(CLOCK_MONOTONIC), but not
   * picking values right at the vblank, then the presentation times
   * we compute won't be accurate, but not really worse than then
   * the alternative of not providing presentation times at all.
   *
   * The complexity here is dealing with the fact that we receive
   * only the low 32 bits of the CLOCK_MONOTONIC value in milliseconds.
   */
  gint64 now_monotonic = g_get_monotonic_time ();
  gint64 now_monotonic_msec = now_monotonic / 1000;
  uint32_t now_monotonic_low = (uint32_t)now_monotonic_msec;

  if (frame_time - now_monotonic_low < 1000 ||
      frame_time - now_monotonic_low > (uint32_t)-1000)
    {
      /* Timestamp we received is within one second of the current time.
       */
      gint64 last_frame_time = now_monotonic + (gint64)1000 * (gint32)(frame_time - now_monotonic_low);
      if ((gint32)now_monotonic_low < 0 && (gint32)frame_time > 0)
        last_frame_time += (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
      else if ((gint32)now_monotonic_low > 0 && (gint32)frame_time < 0)
        last_frame_time -= (gint64)1000 * G_GINT64_CONSTANT(0x100000000);

      timings->presentation_time = last_frame_time + timings->refresh_interval;
    }
}

473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
static void
read_back_cairo_surface (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
  cairo_t *cr;
  cairo_region_t *paint_region = NULL;

  if (!impl->backfill_cairo_surface)
    goto out;

  paint_region = cairo_region_copy (window->clip_region);
  cairo_region_subtract (paint_region, impl->staged_updates_region);

  if (cairo_region_is_empty (paint_region))
    goto out;

  cr = cairo_create (impl->staging_cairo_surface);
  cairo_set_source_surface (cr, impl->backfill_cairo_surface, 0, 0);
  gdk_cairo_region (cr, paint_region);
  cairo_clip (cr);
  cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
  cairo_paint (cr);
  cairo_destroy (cr);
  cairo_surface_flush (impl->staging_cairo_surface);

out:
  g_clear_pointer (&paint_region, cairo_region_destroy);
  g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy);
  g_clear_pointer (&impl->backfill_cairo_surface, cairo_surface_destroy);
}

504 505 506 507 508 509 510
static void
frame_callback (void               *data,
                struct wl_callback *callback,
                uint32_t            time)
{
  GdkWindow *window = data;
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
511 512
  GdkWaylandDisplay *display_wayland =
    GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
513 514 515
  GdkFrameClock *clock = gdk_window_get_frame_clock (window);
  GdkFrameTimings *timings;

Matthias Clasen's avatar
Matthias Clasen committed
516 517 518
  GDK_NOTE (EVENTS,
            g_message ("frame %p", window));

519
  wl_callback_destroy (callback);
520 521 522 523

  if (GDK_WINDOW_DESTROYED (window))
    return;

524 525 526 527
  if (!impl->awaiting_frame)
    return;

  impl->awaiting_frame = FALSE;
528 529 530 531 532 533 534 535
  _gdk_frame_clock_thaw (clock);

  timings = gdk_frame_clock_get_timings (clock, impl->pending_frame_counter);
  impl->pending_frame_counter = 0;

  if (timings == NULL)
    return;

536
  timings->refresh_interval = 16667; /* default to 1/60th of a second */
537
  if (impl->display_server.outputs)
538 539 540
    {
      /* We pick a random output out of the outputs that the window touches
       * The rate here is in milli-hertz */
541 542 543
      int refresh_rate =
        _gdk_wayland_screen_get_output_refresh_rate (display_wayland->screen,
                                                     impl->display_server.outputs->data);
544 545 546 547
      if (refresh_rate != 0)
        timings->refresh_interval = G_GINT64_CONSTANT(1000000000) / refresh_rate;
    }

548 549
  fill_presentation_time_from_frame_time (timings, time);

550 551 552 553 554 555 556 557
  timings->complete = TRUE;

#ifdef G_ENABLE_DEBUG
  if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0)
    _gdk_frame_clock_debug_print_timings (clock, timings);
#endif
}

558
static const struct wl_callback_listener frame_listener = {
559 560 561 562 563 564 565
  frame_callback
};

static void
on_frame_clock_before_paint (GdkFrameClock *clock,
                             GdkWindow     *window)
{
566 567 568 569
  GdkFrameTimings *timings = gdk_frame_clock_get_current_timings (clock);
  gint64 presentation_time;
  gint64 refresh_interval;

570 571 572
  if (window->update_freeze_count > 0)
    return;

573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
  gdk_frame_clock_get_refresh_info (clock,
                                    timings->frame_time,
                                    &refresh_interval, &presentation_time);

  if (presentation_time != 0)
    {
      /* Assume the algorithm used by the DRM backend of Weston - it
       * starts drawing at the next vblank after receiving the commit
       * for this frame, and presentation occurs at the vblank
       * after that.
       */
      timings->predicted_presentation_time = presentation_time + refresh_interval;
    }
  else
    {
      /* As above, but we don't actually know the phase of the vblank,
       * so just assume that we're half way through a refresh cycle.
       */
      timings->predicted_presentation_time = timings->frame_time + refresh_interval / 2 + refresh_interval;
    }
593 594 595 596 597 598 599 600 601 602 603 604
}

static void
on_frame_clock_after_paint (GdkFrameClock *clock,
                            GdkWindow     *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
  struct wl_callback *callback;

  if (!impl->pending_commit)
    return;

605 606 607
  if (window->update_freeze_count > 0)
    return;

608
  callback = wl_surface_frame (impl->display_server.wl_surface);
609
  wl_callback_add_listener (callback, &frame_listener, window);
610 611
  _gdk_frame_clock_freeze (clock);

612 613 614
  /* Before we commit a new buffer, make sure we've backfilled
   * undrawn parts from any old committed buffer
   */
615 616
  if (impl->pending_buffer_attached)
    read_back_cairo_surface (window);
617 618 619 620 621 622 623 624 625

  /* From this commit forward, we can't write to the buffer,
   * it's "live".  In the future, if we need to stage more changes
   * we have to allocate a new staging buffer and draw to it instead.
   *
   * Our one saving grace is if the compositor releases the buffer
   * before we need to stage any changes, then we can take it back and
   * use it again.
   */
626
  wl_surface_commit (impl->display_server.wl_surface);
627 628 629 630 631 632 633 634

  if (impl->pending_buffer_attached)
    impl->committed_cairo_surface = g_steal_pointer (&impl->staging_cairo_surface);

  impl->pending_buffer_attached = FALSE;
  impl->pending_commit = FALSE;
  impl->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock);
  impl->awaiting_frame = TRUE;
635 636

  g_signal_emit (impl, signals[COMMITTED], 0);
637 638
}

639 640 641 642
static void
window_update_scale (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
643 644
  GdkWaylandDisplay *display_wayland =
    GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
645 646 647
  guint32 scale;
  GSList *l;

648
  if (display_wayland->compositor_version < WL_SURFACE_HAS_BUFFER_SCALE)
649 650 651 652 653
    {
      /* We can't set the scale on this surface */
      return;
    }

654
  scale = 1;
655
  for (l = impl->display_server.outputs; l != NULL; l = l->next)
656 657
    {
      guint32 output_scale =
658
        _gdk_wayland_screen_get_output_scale (display_wayland->screen, l->data);
659 660 661
      scale = MAX (scale, output_scale);
    }

662
  /* Notify app that scale changed */
663
  gdk_wayland_window_maybe_configure (window, window->width, window->height, scale);
664 665 666 667
}

static void
on_monitors_changed (GdkScreen *screen,
Matthias Clasen's avatar
Matthias Clasen committed
668
                     GdkWindow *window)
669 670 671 672
{
  window_update_scale (window);
}

673

Matthias Clasen's avatar
Matthias Clasen committed
674
static void gdk_wayland_window_create_surface (GdkWindow *window);
675

Kristian Høgsberg's avatar
Kristian Høgsberg committed
676 677
void
_gdk_wayland_display_create_window_impl (GdkDisplay    *display,
Matthias Clasen's avatar
Matthias Clasen committed
678 679 680 681 682 683
                                         GdkWindow     *window,
                                         GdkWindow     *real_parent,
                                         GdkScreen     *screen,
                                         GdkEventMask   event_mask,
                                         GdkWindowAttr *attributes,
                                         gint           attributes_mask)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
684
{
685
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
686
  GdkWindowImplWayland *impl;
687
  GdkFrameClock *frame_clock;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
688 689 690 691 692
  const char *title;

  impl = g_object_new (GDK_TYPE_WINDOW_IMPL_WAYLAND, NULL);
  window->impl = GDK_WINDOW_IMPL (impl);
  impl->wrapper = GDK_WINDOW (window);
693
  impl->shortcuts_inhibitors = g_hash_table_new (NULL, NULL);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
694

Matthias Clasen's avatar
Matthias Clasen committed
695
  if (window->width > 65535)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
696
    {
Matthias Clasen's avatar
Matthias Clasen committed
697 698 699 700 701 702 703
      g_warning ("Native Windows wider than 65535 pixels are not supported");
      window->width = 65535;
    }
  if (window->height > 65535)
    {
      g_warning ("Native Windows taller than 65535 pixels are not supported");
      window->height = 65535;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
704
    }
705

Kristian Høgsberg's avatar
Kristian Høgsberg committed
706 707
  g_object_ref (window);

708
  /* More likely to be right than just assuming 1 */
709
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
710
  if (display_wayland->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE &&
711
      gdk_screen_get_n_monitors (screen) > 0)
712
    impl->scale = gdk_screen_get_monitor_scale_factor (screen, 0);
713
G_GNUC_END_IGNORE_DEPRECATIONS
714

715 716
  impl->title = NULL;

Kristian Høgsberg's avatar
Kristian Høgsberg committed
717 718 719 720 721
  switch (GDK_WINDOW_TYPE (window))
    {
    case GDK_WINDOW_TOPLEVEL:
    case GDK_WINDOW_TEMP:
      if (attributes_mask & GDK_WA_TITLE)
Matthias Clasen's avatar
Matthias Clasen committed
722
        title = attributes->title;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
723
      else
Matthias Clasen's avatar
Matthias Clasen committed
724
        title = get_default_title ();
Kristian Høgsberg's avatar
Kristian Høgsberg committed
725 726 727 728 729 730 731 732 733

      gdk_window_set_title (window, title);
      break;

    case GDK_WINDOW_CHILD:
    default:
      break;
    }

734 735
  gdk_wayland_window_create_surface (window);

Kristian Høgsberg's avatar
Kristian Høgsberg committed
736 737
  if (attributes_mask & GDK_WA_TYPE_HINT)
    gdk_window_set_type_hint (window, attributes->type_hint);
738 739 740 741 742 743 744

  frame_clock = gdk_window_get_frame_clock (window);

  g_signal_connect (frame_clock, "before-paint",
                    G_CALLBACK (on_frame_clock_before_paint), window);
  g_signal_connect (frame_clock, "after-paint",
                    G_CALLBACK (on_frame_clock_after_paint), window);
745 746 747

  g_signal_connect (screen, "monitors-changed",
                    G_CALLBACK (on_monitors_changed), window);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
748 749
}

750 751 752
static void
gdk_wayland_window_attach_image (GdkWindow *window)
{
753
  GdkWaylandDisplay *display;
754
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
755

756 757 758
  if (GDK_WINDOW_DESTROYED (window))
    return;

759
  g_assert (_gdk_wayland_is_shm_surface (impl->staging_cairo_surface));
760

761
  /* Attach this new buffer to the surface */
762
  wl_surface_attach (impl->display_server.wl_surface,
763
                     _gdk_wayland_shm_surface_get_wl_buffer (impl->staging_cairo_surface),
764 765 766 767
                     impl->pending_buffer_offset_x,
                     impl->pending_buffer_offset_y);
  impl->pending_buffer_offset_x = 0;
  impl->pending_buffer_offset_y = 0;
768 769 770 771

  /* Only set the buffer scale if supported by the compositor */
  display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
  if (display->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE)
772
    wl_surface_set_buffer_scale (impl->display_server.wl_surface, impl->scale);
773

774
  impl->pending_buffer_attached = TRUE;
775
  impl->pending_commit = TRUE;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
776 777
}

778 779
static const cairo_user_data_key_t gdk_wayland_window_cairo_key;

780 781 782 783 784
static void
buffer_release_callback (void             *_data,
                         struct wl_buffer *wl_buffer)
{
  cairo_surface_t *cairo_surface = _data;
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
  GdkWindowImplWayland *impl = cairo_surface_get_user_data (cairo_surface, &gdk_wayland_window_cairo_key);

  g_return_if_fail (GDK_IS_WINDOW_IMPL_WAYLAND (impl));

  /* The released buffer isn't the latest committed one, we have no further
   * use for it, so clean it up.
   */
  if (impl->committed_cairo_surface != cairo_surface)
    {
      /* If this fails, then the surface buffer got reused before it was
       * released from the compositor
       */
      g_warn_if_fail (impl->staging_cairo_surface != cairo_surface);

      cairo_surface_destroy (cairo_surface);
      return;
    }

803
  if (impl->staged_updates_region != NULL)
804
    {
805 806
      /* If this fails, then we're tracking staged updates on a staging surface
       * that doesn't exist.
807
       */
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
      g_warn_if_fail (impl->staging_cairo_surface != NULL);

      /* If we've staged updates into a new buffer before the release for this
       * buffer came in, then we can't reuse this buffer, so unref it. It may still
       * be alive as a readback buffer though (via impl->backfill_cairo_surface).
       *
       * It's possible a staging surface was allocated but no updates were staged.
       * If that happened, clean up that staging surface now, since the old commit
       * buffer is available again, and reusing the old commit buffer for future
       * updates will save having to do a read back later.
       */
      if (!cairo_region_is_empty (impl->staged_updates_region))
        {
          g_clear_pointer (&impl->committed_cairo_surface, cairo_surface_destroy);
          return;
        }
      else
        {
          g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy);
          g_clear_pointer (&impl->staging_cairo_surface, cairo_surface_destroy);
        }
829
    }
830

831 832 833 834
  /* Release came in, we haven't done any interim updates, so we can just use
   * the old committed buffer again.
   */
  impl->staging_cairo_surface = g_steal_pointer (&impl->committed_cairo_surface);
835 836 837 838 839 840
}

static const struct wl_buffer_listener buffer_listener = {
  buffer_release_callback
};

841 842
static void
gdk_wayland_window_ensure_cairo_surface (GdkWindow *window)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
843 844
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
845 846

  /* If we are drawing using OpenGL then we only need a logical 1x1 surface. */
847
  if (impl->display_server.egl_window)
848
    {
849 850
      if (impl->staging_cairo_surface &&
          _gdk_wayland_is_shm_surface (impl->staging_cairo_surface))
851
        g_clear_pointer (&impl->staging_cairo_surface, cairo_surface_destroy);
852

853 854 855 856 857 858 859 860
      if (!impl->staging_cairo_surface)
        {
          impl->staging_cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                                                    impl->scale,
                                                                    impl->scale);
          cairo_surface_set_device_scale (impl->staging_cairo_surface,
                                          impl->scale, impl->scale);
        }
861
    }
862
  else if (!impl->staging_cairo_surface)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
863
    {
864
      GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (impl->wrapper));
865
      struct wl_buffer *buffer;
866

867 868 869 870 871 872 873 874 875 876 877
      impl->staging_cairo_surface = _gdk_wayland_display_create_shm_surface (display_wayland,
                                                                             impl->wrapper->width,
                                                                             impl->wrapper->height,
                                                                             impl->scale);
      cairo_surface_set_user_data (impl->staging_cairo_surface,
                                   &gdk_wayland_window_cairo_key,
                                   g_object_ref (impl),
                                   (cairo_destroy_func_t)
                                   g_object_unref);
      buffer = _gdk_wayland_shm_surface_get_wl_buffer (impl->staging_cairo_surface);
      wl_buffer_add_listener (buffer, &buffer_listener, impl->staging_cairo_surface);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
878
    }
879 880
}

881 882 883 884 885 886
/* The cairo surface returned here uses a memory segment that's shared
 * with the display server.  This is not a temporary buffer that gets
 * copied to the display server, but the actual buffer the display server
 * will ultimately end up sending to the GPU. At the time this happens
 * impl->committed_cairo_surface gets set to impl->staging_cairo_surface, and
 * impl->staging_cairo_surface gets nullified.
887 888 889 890 891 892 893 894 895 896
 */
static cairo_surface_t *
gdk_wayland_window_ref_cairo_surface (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);

  if (GDK_WINDOW_DESTROYED (impl->wrapper))
    return NULL;

  gdk_wayland_window_ensure_cairo_surface (window);
897

898
  cairo_surface_reference (impl->staging_cairo_surface);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
899

900
  return impl->staging_cairo_surface;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
901 902
}

903 904 905 906 907 908 909 910
static cairo_surface_t *
gdk_wayland_window_create_similar_image_surface (GdkWindow *     window,
                                                 cairo_format_t  format,
                                                 int             width,
                                                 int             height)
{
  return cairo_image_surface_create (format, width, height);
}
911

912
static gboolean
913
gdk_window_impl_wayland_begin_paint (GdkWindow *window)
914 915
{
  gdk_wayland_window_ensure_cairo_surface (window);
Matthias Clasen's avatar
Matthias Clasen committed
916

917
  return FALSE;
918 919
}

920 921 922 923 924 925 926
static void
gdk_window_impl_wayland_end_paint (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
  cairo_rectangle_int_t rect;
  int i, n;

927 928 929
  if (impl->staging_cairo_surface &&
      _gdk_wayland_is_shm_surface (impl->staging_cairo_surface) &&
      !window->current_paint.use_gl &&
930
      !cairo_region_is_empty (window->current_paint.region))
931
    {
932 933
      gdk_wayland_window_attach_image (window);

934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951
      /* If there's a committed buffer pending, then track which
       * updates are staged until the next frame, so we can back
       * fill the unstaged parts of the staging buffer with the
       * last frame.
       */
      if (impl->committed_cairo_surface != NULL)
        {
          if (impl->staged_updates_region == NULL)
            {
              impl->staged_updates_region = cairo_region_copy (window->current_paint.region);
              impl->backfill_cairo_surface = cairo_surface_reference (impl->committed_cairo_surface);
            }
          else
            {
              cairo_region_union (impl->staged_updates_region, window->current_paint.region);
            }
        }

952 953 954 955
      n = cairo_region_num_rectangles (window->current_paint.region);
      for (i = 0; i < n; i++)
        {
          cairo_region_get_rectangle (window->current_paint.region, i, &rect);
956
          wl_surface_damage (impl->display_server.wl_surface, rect.x, rect.y, rect.width, rect.height);
957
        }
958 959

      impl->pending_commit = TRUE;
960
    }
961 962 963 964

  gdk_wayland_window_sync_margin (window);
  gdk_wayland_window_sync_opaque_region (window);
  gdk_wayland_window_sync_input_region (window);
965 966
}

967 968 969
static gboolean
gdk_window_impl_wayland_beep (GdkWindow *window)
{
970 971
  gdk_wayland_display_system_bell (gdk_window_get_display (window),
                                   window);
972 973 974 975

  return TRUE;
}

976 977 978
static void
gdk_window_impl_wayland_finalize (GObject *object)
{
979
  GdkWindow *window = GDK_WINDOW (object);
980 981 982 983 984 985
  GdkWindowImplWayland *impl;

  g_return_if_fail (GDK_IS_WINDOW_IMPL_WAYLAND (object));

  impl = GDK_WINDOW_IMPL_WAYLAND (object);

986 987 988
  if (gdk_wayland_window_is_exported (window))
    gdk_wayland_window_unexport_handle (window);

989 990
  g_free (impl->title);

991 992 993 994 995 996 997
  g_free (impl->application.application_id);
  g_free (impl->application.app_menu_path);
  g_free (impl->application.menubar_path);
  g_free (impl->application.window_object_path);
  g_free (impl->application.application_object_path);
  g_free (impl->application.unique_bus_name);

998
  g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
999
  g_clear_pointer (&impl->input_region, cairo_region_destroy);
1000
  g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy);
1001

1002 1003
  g_hash_table_destroy (impl->shortcuts_inhibitors);

1004 1005 1006
  G_OBJECT_CLASS (_gdk_window_impl_wayland_parent_class)->finalize (object);
}

1007
static void
1008
gdk_wayland_window_configure (GdkWindow *window,
Matthias Clasen's avatar
Matthias Clasen committed
1009
                              int        width,
1010 1011
                              int        height,
                              int        scale)
1012 1013 1014 1015 1016
{
  GdkDisplay *display;
  GdkEvent *event;

  event = gdk_event_new (GDK_CONFIGURE);
1017
  event->configure.window = g_object_ref (window);
1018 1019 1020 1021
  event->configure.send_event = FALSE;
  event->configure.width = width;
  event->configure.height = height;

1022
  gdk_wayland_window_update_size (window, width, height, scale);
1023
  _gdk_window_update_size (window);
1024

1025
  display = gdk_window_get_display (window);
1026 1027 1028
  _gdk_wayland_display_deliver_event (display, event);
}

1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
static gboolean
is_realized_shell_surface (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);

  return (impl->display_server.xdg_surface ||
          impl->display_server.zxdg_surface_v6);
}

static gboolean
is_realized_toplevel (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);

  return (impl->display_server.xdg_toplevel ||
          impl->display_server.zxdg_toplevel_v6);
}

static gboolean
is_realized_popup (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);

  return (impl->display_server.xdg_popup ||
          impl->display_server.zxdg_popup_v6);
}

1056 1057 1058 1059 1060 1061 1062
static void
gdk_wayland_window_maybe_configure (GdkWindow *window,
                                    int        width,
                                    int        height,
                                    int        scale)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1063 1064
  gboolean is_xdg_popup;
  gboolean is_visible;
1065 1066 1067 1068 1069 1070

  if (window->width == width &&
      window->height == height &&
      impl->scale == scale)
    return;

1071 1072 1073 1074 1075 1076
  /* For xdg_popup using an xdg_positioner, there is a race condition if
   * the application tries to change the size after it's mapped, but before
   * the initial configure is received, so hide and show the surface again
   * force the new size onto the compositor. See bug #772505.
   */

1077
  is_xdg_popup = is_realized_popup (window);
1078 1079 1080 1081 1082
  is_visible = gdk_window_is_visible (window);

  if (is_xdg_popup && is_visible && !impl->initial_configure_received)
    gdk_window_hide (window);

1083
  gdk_wayland_window_configure (window, width, height, scale);
1084 1085 1086

  if (is_xdg_popup && is_visible && !impl->initial_configure_received)
    gdk_window_show (window);
1087 1088
}

1089
static void
1090 1091
gdk_wayland_window_sync_parent (GdkWindow *window,
                                GdkWindow *parent)
1092
{
1093 1094
  GdkWaylandDisplay *display_wayland =
    GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1095
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1096
  GdkWindowImplWayland *impl_parent = NULL;
1097

1098 1099 1100
  g_assert (parent == NULL ||
            gdk_window_get_display (window) == gdk_window_get_display (parent));

1101
  if (!is_realized_toplevel (window))
1102
    return;
1103

1104
  if (impl->transient_for)
1105 1106 1107
    impl_parent = GDK_WINDOW_IMPL_WAYLAND (impl->transient_for->impl);
  else if (parent)
    impl_parent = GDK_WINDOW_IMPL_WAYLAND (parent->impl);
1108

1109 1110 1111 1112 1113
  /* XXX: Is this correct? */
  if (impl_parent && !impl_parent->display_server.wl_surface)
    return;

  switch (display_wayland->shell_variant)
1114
    {
1115 1116 1117
    case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
      {
        struct xdg_toplevel *parent_toplevel;
1118

1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
        if (impl_parent)
          parent_toplevel = impl_parent->display_server.xdg_toplevel;
        else
          parent_toplevel = NULL;

        xdg_toplevel_set_parent (impl->display_server.xdg_toplevel,
                                 parent_toplevel);
        break;
      }
      break;
    case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
      {
        struct zxdg_toplevel_v6 *parent_toplevel;
1132

1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
        if (impl_parent)
          parent_toplevel = impl_parent->display_server.zxdg_toplevel_v6;
        else
          parent_toplevel = NULL;

        zxdg_toplevel_v6_set_parent (impl->display_server.zxdg_toplevel_v6,
                                     parent_toplevel);
        break;
      }
    }
1143 1144
}

1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
static void
gdk_wayland_window_sync_parent_of_imported (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);

  if (!impl->display_server.wl_surface)
    return;

  if (!impl->imported_transient_for)
    return;

1156
  if (!is_realized_toplevel (window))
1157 1158 1159 1160 1161 1162
    return;

  zxdg_imported_v1_set_parent_of (impl->imported_transient_for,
                                  impl->display_server.wl_surface);
}

1163 1164 1165
static void
gdk_wayland_window_update_dialogs (GdkWindow *window)
{
1166 1167
  GdkWaylandDisplay *display_wayland =
    GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1168 1169
  GList *l;

1170
  if (!display_wayland->orphan_dialogs)
1171 1172
    return;

1173
  for (l = display_wayland->orphan_dialogs; l; l = l->next)
1174 1175
    {
      GdkWindow *w = l->data;
1176 1177 1178 1179
      GdkWindowImplWayland *impl;

      if (!GDK_IS_WINDOW_IMPL_WAYLAND(w->impl))
        continue;
1180

1181
      impl = GDK_WINDOW_IMPL_WAYLAND (w->impl);
1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
      if (w == window)
	continue;
      if (impl->hint != GDK_WINDOW_TYPE_HINT_DIALOG)
        continue;
      if (impl->transient_for)
        continue;

      /* Update the parent relationship only for dialogs without transients */
      gdk_wayland_window_sync_parent (w, window);
    }
}

1194 1195 1196 1197
static void
gdk_wayland_window_sync_title (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1198 1199
  GdkWaylandDisplay *display_wayland =
    GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1200

1201
  if (!is_realized_toplevel (window))
1202 1203 1204 1205 1206
    return;

  if (!impl->title)
    return;

1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217
  switch (display_wayland->shell_variant)
    {
    case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
      xdg_toplevel_set_title (impl->display_server.xdg_toplevel,
                              impl->title);
      break;
    case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
      zxdg_toplevel_v6_set_title (impl->display_server.zxdg_toplevel_v6,
                                  impl->title);
      break;
    }
1218 1219
}

1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
static void
gdk_wayland_window_get_window_geometry (GdkWindow    *window,
                                        GdkRectangle *geometry)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);

  *geometry = (GdkRectangle) {
    .x = impl->margin_left,
    .y = impl->margin_top,
    .width = window->width - (impl->margin_left + impl->margin_right),
    .height = window->height - (impl->margin_top + impl->margin_bottom)
  };
}

1234 1235 1236 1237
static void
gdk_wayland_window_sync_margin (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
1238 1239
  GdkWaylandDisplay *display_wayland =
    GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
1240
  GdkRectangle geometry;
1241

1242
  if (!is_realized_shell_surface (window))
1243 1244
    return;

1245
  gdk_wayland_window_get_window_geometry (window, &geometry);
1246 1247 1248
  gdk_window_set_geometry_hints (window,
                                 &impl->geometry_hints,
                                 impl->geometry_mask);
1249 1250 1251 1252 1253

  switch (display_wayland->shell_variant)
    {
    case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
      xdg_surface_set_window_geometry (impl->display_server.xdg_surface,
1254 1255 1256 1257
                                       geometry.x,
                                       geometry.y,
                                       geometry.width,
                                       geometry.height);
1258 1259 1260 1261 1262 1263 1264 1265 1266
      break;
    case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
      zxdg_surface_v6_set_window_geometry (impl->display_server.zxdg_surface_v6,
                                           geometry.x,
                                           geometry.y,
                                           geometry.width,
                                           geometry.height);
      break;
    }
1267 1268
}

1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
static struct wl_region *
wl_region_from_cairo_region (GdkWaylandDisplay *display,
                             cairo_region_t    *region)
{
  struct wl_region *wl_region;
  int i, n_rects;

  wl_region = wl_compositor_create_region (display->compositor);
  if (wl_region == NULL)
    return NULL;

  n_rects = cairo_region_num_rectangles (region);
  for (i = 0; i < n_rects; i++)
    {
      cairo_rectangle_int_t rect;
      cairo_region_get_rectangle (region, i, &rect);
      wl_region_add (wl_region, rect.x, rect.y, rect.width, rect.height);
    }

  return wl_region;
}

static void
gdk_wayland_window_sync_opaque_region (GdkWindow *window)
{
  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
  struct wl_region *wl_region = NULL;

1297
  if (!impl->display_server.wl_surface)
1298 1299
    return;

1300 1301 1302
  if (!impl->opaque_region_dirty)
    return;

1303 1304 1305 1306
  if (impl->opaque_region != NULL)
    wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_window_get_display (window)),
                                             impl->opaque_region);

1307
  wl_surface_set_opaque_region (impl->display_server.wl_surface, wl_region);
1308 1309 1310

  if (wl_region != NULL)
    wl_region_destroy (wl_region);
1311 1312

  impl->opaque_region_dirty = FALSE;
1313 1314
}

Jasper St. Pierre's avatar