gdkwindow.c 207 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GDK - The GIMP Drawing Kit
2 3
 * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
 * Josh MacDonald, Ryan Lortie
Elliot Lee's avatar
Elliot Lee committed
4 5
 *
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
7 8 9 10 11 12
 * 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
13
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
16
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
17
 */
18

19
/*
20
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
21 22
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
23
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
24 25
 */

26 27
#include "config.h"

28 29
#include <cairo-gobject.h>

30 31
#include "gdkwindow.h"

32
#include "gdkrectangle.h"
33 34
#include "gdkinternals.h"
#include "gdkintl.h"
Matthias Clasen's avatar
Matthias Clasen committed
35
#include "gdkdisplayprivate.h"
36
#include "gdkdeviceprivate.h"
37
#include "gdkmarshalers.h"
Owen W. Taylor's avatar
Owen W. Taylor committed
38
#include "gdkframeclockidle.h"
39
#include "gdkwindowimpl.h"
40
#include "gdkglcontextprivate.h"
Emmanuele Bassi's avatar
Emmanuele Bassi committed
41
#include "gdkdrawingcontextprivate.h"
42
#include "gdk-private.h"
43

44 45
#include <math.h>

46 47
#include <epoxy/gl.h>

48 49 50
/* for the use of round() */
#include "fallback-c89.c"

51 52 53 54
#ifdef GDK_WINDOWING_WAYLAND
#include "wayland/gdkwayland.h"
#endif

55 56 57
#undef DEBUG_WINDOW_PRINTING


58 59 60 61 62
/**
 * SECTION:windows
 * @Short_description: Onscreen display areas in the target window system
 * @Title: Windows
 *
63
 * A #GdkWindow is a (usually) rectangular region on the screen.
64
 * It’s a low-level object, used to implement high-level objects such as
65
 * #GtkWidget and #GtkWindow on the GTK+ level. A #GtkWindow is a toplevel
William Jon McCann's avatar
William Jon McCann committed
66
 * window, the thing a user might think of as a “window” with a titlebar
Matthias Clasen's avatar
Matthias Clasen committed
67 68
 * and so on; a #GtkWindow may contain many #GdkWindows. For example,
 * each #GtkButton has a #GdkWindow associated with it.
69 70
 */

71

72 73 74 75
/* Historically a GdkWindow always matches a platform native window,
 * be it a toplevel window or a child window. In this setup the
 * GdkWindow (and other GdkDrawables) were platform independent classes,
 * and the actual platform specific implementation was in a delegate
William Jon McCann's avatar
William Jon McCann committed
76
 * object available as “impl” in the window object.
77
 *
78 79
 * With the addition of client side windows this changes a bit. The
 * application-visible GdkWindow object behaves as it did before, but
80 81 82
 * such windows now don't a corresponding native window. Instead subwindows
 * windows are “client side”, i.e. emulated by the gdk code such
 * that clipping, drawing, moving, events etc work as expected.
83
 *
William Jon McCann's avatar
William Jon McCann committed
84 85
 * GdkWindows have a pointer to the “impl window” they are in, i.e.
 * the topmost GdkWindow which have the same “impl” value. This is stored
86 87 88 89 90
 * in impl_window, which is different from the window itself only for client
 * side windows.
 * All GdkWindows (native or not) track the position of the window in the parent
 * (x, y), the size of the window (width, height), the position of the window
 * with respect to the impl window (abs_x, abs_y). We also track the clip
91
 * region of the window wrt parent windows, in window-relative coordinates (clip_region).
92
 */
93

94
enum {
95
  MOVED_TO_RECT,
96 97 98
  LAST_SIGNAL
};

Cody Russell's avatar
Cody Russell committed
99 100
enum {
  PROP_0,
101
  PROP_CURSOR,
102
  PROP_DISPLAY,
103
  LAST_PROP
Cody Russell's avatar
Cody Russell committed
104 105
};

106
/* Global info */
107

108
static void gdk_window_finalize   (GObject              *object);
Cody Russell's avatar
Cody Russell committed
109 110 111 112 113 114 115 116 117 118

static void gdk_window_set_property (GObject      *object,
                                     guint         prop_id,
                                     const GValue *value,
                                     GParamSpec   *pspec);
static void gdk_window_get_property (GObject      *object,
                                     guint         prop_id,
                                     GValue       *value,
                                     GParamSpec   *pspec);

119
static void gdk_window_clear_backing_region (GdkWindow *window);
120

121
static void recompute_visible_regions   (GdkWindow *private,
122
					 gboolean recalculate_children);
123
static void gdk_window_invalidate_in_parent (GdkWindow *private);
124 125
static void update_cursor               (GdkDisplay *display,
                                         GdkDevice  *device);
126
static void impl_window_add_update_area (GdkWindow *impl_window,
127
					 cairo_region_t *region);
128
static void gdk_window_invalidate_region_full (GdkWindow       *window,
129
					       const cairo_region_t *region,
130
					       gboolean         invalidate_children);
131 132
static void gdk_window_invalidate_rect_full (GdkWindow          *window,
					     const GdkRectangle *rect,
133
					     gboolean            invalidate_children);
134
static cairo_surface_t *gdk_window_ref_impl_surface (GdkWindow *window);
135

136 137
static void gdk_window_set_frame_clock (GdkWindow      *window,
                                        GdkFrameClock  *clock);
Owen W. Taylor's avatar
Owen W. Taylor committed
138

139

140
static guint signals[LAST_SIGNAL] = { 0 };
141
static GParamSpec *properties[LAST_PROP] = { NULL, };
142

Benjamin Otte's avatar
Benjamin Otte committed
143
G_DEFINE_ABSTRACT_TYPE (GdkWindow, gdk_window, G_TYPE_OBJECT)
144

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
#ifdef DEBUG_WINDOW_PRINTING
char *
print_region (cairo_region_t *region)
{
  GString *s = g_string_new ("{");
  if (cairo_region_is_empty (region))
    {
      g_string_append (s, "empty");
    }
  else
    {
      int num = cairo_region_num_rectangles (region);
      cairo_rectangle_int_t r;

      if (num == 1)
	{
	  cairo_region_get_rectangle (region, 0, &r);
	  g_string_append_printf (s, "%dx%d @%d,%d", r.width, r.height, r.x, r.y);
	}
      else
	{
166
	  int i;
167 168
	  cairo_region_get_extents (region, &r);
	  g_string_append_printf (s, "extent: %dx%d @%d,%d, details: ", r.width, r.height, r.x, r.y);
169
	  for (i = 0; i < num; i++)
170
	    {
171
              cairo_region_get_rectangle (region, i, &r);
172 173 174 175 176 177 178 179 180 181 182
	      g_string_append_printf (s, "[%dx%d @%d,%d]", r.width, r.height, r.x, r.y);
	      if (i != num -1)
		g_string_append (s, ", ");
	    }
	}
    }
  g_string_append (s, "}");
  return g_string_free (s, FALSE);
}
#endif

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
static GList *
list_insert_link_before (GList *list,
                         GList *sibling,
                         GList *link)
{
  if (list == NULL || sibling == list)
    {
      link->prev = NULL;
      link->next = list;
      if (list)
        list->prev = link;
      return link;
    }
  else if (sibling == NULL)
    {
      GList *last = g_list_last (list);

      last->next = link;
      link->prev = last;
      link->next = NULL;

      return list;
    }
  else
    {
      link->next = sibling;
      link->prev = sibling->prev;
      sibling->prev = link;

212 213 214
      if (link->prev)
        link->prev->next = link;

215 216 217 218
      return list;
    }
}

219
static void
220
gdk_window_init (GdkWindow *window)
221 222
{
  /* 0-initialization is good for all other fields. */
rhlabs's avatar
rhlabs committed
223

224
  window->window_type = GDK_WINDOW_CHILD;
Elliot Lee's avatar
Elliot Lee committed
225

Havoc Pennington's avatar
Havoc Pennington committed
226
  window->state = GDK_WINDOW_STATE_WITHDRAWN;
227
  window->fullscreen_mode = GDK_FULLSCREEN_ON_CURRENT_MONITOR;
228 229 230
  window->width = 1;
  window->height = 1;
  window->toplevel_window_type = -1;
231
  window->children_list_node.data = window;
232 233 234

  window->device_cursor = g_hash_table_new_full (NULL, NULL,
                                                 NULL, g_object_unref);
235
}
236

237
static void
238
gdk_window_class_init (GdkWindowClass *klass)
239 240
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
241

242
  object_class->finalize = gdk_window_finalize;
Cody Russell's avatar
Cody Russell committed
243 244
  object_class->set_property = gdk_window_set_property;
  object_class->get_property = gdk_window_get_property;
245

Cody Russell's avatar
Cody Russell committed
246
  /* Properties */
247 248 249 250 251 252 253 254 255

  /**
   * GdkWindow:cursor:
   *
   * The mouse pointer for a #GdkWindow. See gdk_window_set_cursor() and
   * gdk_window_get_cursor() for details.
   *
   * Since: 2.18
   */
256 257 258 259 260
  properties[PROP_CURSOR] =
      g_param_spec_object ("cursor",
                           P_("Cursor"),
                           P_("Cursor"),
                           GDK_TYPE_CURSOR,
261
                           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
262 263 264 265 266 267 268 269 270 271 272 273 274 275

  /**
   * GdkWindow:display:
   *
   * The #GdkDisplay connection of the window. See gdk_window_get_display()
   * for details.
   *
   * Since: 3.90
   */
  properties[PROP_DISPLAY] =
      g_param_spec_object ("display",
                           P_("Display"),
                           P_("Display"),
                           GDK_TYPE_DISPLAY,
276
                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
277

278
  g_object_class_install_properties (object_class, LAST_PROP, properties);
Cody Russell's avatar
Cody Russell committed
279

280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
  /**
   * GdkWindow::moved-to-rect:
   * @window: the #GdkWindow that moved
   * @flipped_rect: (nullable): the position of @window after any possible
   *                flipping or %NULL if the backend can't obtain it
   * @final_rect: (nullable): the final position of @window or %NULL if the
   *              backend can't obtain it
   * @flipped_x: %TRUE if the anchors were flipped horizontally
   * @flipped_y: %TRUE if the anchors were flipped vertically
   *
   * Emitted when the position of @window is finalized after being moved to a
   * destination rectangle.
   *
   * @window might be flipped over the destination rectangle in order to keep
   * it on-screen, in which case @flipped_x and @flipped_y will be set to %TRUE
   * accordingly.
   *
   * @flipped_rect is the ideal position of @window after any possible
   * flipping, but before any possible sliding. @final_rect is @flipped_rect,
   * but possibly translated in the case that flipping is still ineffective in
   * keeping @window on-screen.
   *
   * Since: 3.22
   * Stability: Private
   */
  signals[MOVED_TO_RECT] =
    g_signal_new (g_intern_static_string ("moved-to-rect"),
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_FIRST,
                  0,
                  NULL,
                  NULL,
                  _gdk_marshal_VOID__POINTER_POINTER_BOOLEAN_BOOLEAN,
                  G_TYPE_NONE,
                  4,
                  G_TYPE_POINTER,
                  G_TYPE_POINTER,
                  G_TYPE_BOOLEAN,
                  G_TYPE_BOOLEAN);
319
}
320

321
static void
322 323 324
seat_removed_cb (GdkDisplay *display,
                 GdkSeat    *seat,
                 GdkWindow  *window)
325
{
326 327
  GdkDevice *device = gdk_seat_get_pointer (seat);

328 329
  window->devices_inside = g_list_remove (window->devices_inside, device);
  g_hash_table_remove (window->device_cursor, device);
330

331 332
  if (window->device_events)
    g_hash_table_remove (window->device_events, device);
333 334
}

335 336 337 338
static void
gdk_window_finalize (GObject *object)
{
  GdkWindow *window = GDK_WINDOW (object);
339

340 341
  g_signal_handlers_disconnect_by_func (gdk_window_get_display (window),
                                        seat_removed_cb, window);
342

343 344 345 346
  if (!GDK_WINDOW_DESTROYED (window))
    {
      if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
	{
347
	  g_warning ("losing last reference to undestroyed window");
348 349 350 351 352 353 354 355
	  _gdk_window_destroy (window, FALSE);
	}
      else
	/* We use TRUE here, to keep us from actually calling
	 * XDestroyWindow() on the window
	 */
	_gdk_window_destroy (window, TRUE);
    }
356

357
  if (window->impl)
358
    {
359 360
      g_object_unref (window->impl);
      window->impl = NULL;
361 362
    }

363
  if (window->impl_window != window)
364
    {
365 366
      g_object_unref (window->impl_window);
      window->impl_window = NULL;
367
    }
368

369 370
  if (window->shape)
    cairo_region_destroy (window->shape);
Alexander Larsson's avatar
Alexander Larsson committed
371

372 373
  if (window->input_shape)
    cairo_region_destroy (window->input_shape);
Alexander Larsson's avatar
Alexander Larsson committed
374

375
  if (window->cursor)
376
    g_object_unref (window->cursor);
377

378 379
  if (window->device_cursor)
    g_hash_table_destroy (window->device_cursor);
380

381 382
  if (window->device_events)
    g_hash_table_destroy (window->device_events);
383

384 385
  if (window->devices_inside)
    g_list_free (window->devices_inside);
386

387 388
  g_clear_object (&window->display);

389 390 391
  if (window->opaque_region)
    cairo_region_destroy (window->opaque_region);

392
  G_OBJECT_CLASS (gdk_window_parent_class)->finalize (object);
Elliot Lee's avatar
Elliot Lee committed
393 394
}

Cody Russell's avatar
Cody Russell committed
395 396 397 398 399 400
static void
gdk_window_set_property (GObject      *object,
                         guint         prop_id,
                         const GValue *value,
                         GParamSpec   *pspec)
{
401
  GdkWindow *window = GDK_WINDOW (object);
Cody Russell's avatar
Cody Russell committed
402 403 404 405

  switch (prop_id)
    {
    case PROP_CURSOR:
Benjamin Otte's avatar
Benjamin Otte committed
406
      gdk_window_set_cursor (window, g_value_get_object (value));
Cody Russell's avatar
Cody Russell committed
407 408
      break;

409 410 411 412 413
    case PROP_DISPLAY:
      window->display = g_value_dup_object (value);
      g_assert (window->display != NULL);
      break;

Cody Russell's avatar
Cody Russell committed
414 415 416 417 418 419 420 421 422 423 424 425
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gdk_window_get_property (GObject    *object,
                         guint       prop_id,
                         GValue     *value,
                         GParamSpec *pspec)
{
426
  GdkWindow *window = GDK_WINDOW (object);
Cody Russell's avatar
Cody Russell committed
427 428 429 430

  switch (prop_id)
    {
    case PROP_CURSOR:
Benjamin Otte's avatar
Benjamin Otte committed
431
      g_value_set_object (value, gdk_window_get_cursor (window));
Cody Russell's avatar
Cody Russell committed
432 433
      break;

434 435 436 437
    case PROP_DISPLAY:
      g_value_set_object (value, window->display);
      break;

Cody Russell's avatar
Cody Russell committed
438 439 440 441 442 443
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

444 445 446 447 448 449
static gboolean
gdk_window_is_subsurface (GdkWindow *window)
{
   return window->window_type == GDK_WINDOW_SUBSURFACE;
}

450 451
static GdkWindow *
gdk_window_get_impl_window (GdkWindow *window)
452
{
453
  return window->impl_window;
454 455 456 457 458
}

GdkWindow *
_gdk_window_get_impl_window (GdkWindow *window)
{
459
  return gdk_window_get_impl_window (window);
460 461 462
}

static gboolean
463
gdk_window_has_impl (GdkWindow *window)
464
{
465
  return window->impl_window == window;
466 467
}

468
static gboolean
469
gdk_window_is_toplevel (GdkWindow *window)
470 471 472 473 474 475
{
  return
    window->parent == NULL ||
    window->parent->window_type == GDK_WINDOW_ROOT;
}

476 477 478
gboolean
_gdk_window_has_impl (GdkWindow *window)
{
479
  return gdk_window_has_impl (window);
480 481 482
}

static gboolean
483
gdk_window_has_no_impl (GdkWindow *window)
484
{
485
  return window->impl_window != window;
486 487 488
}

static void
489 490
remove_sibling_overlapped_area (GdkWindow *window,
				cairo_region_t *region)
491
{
492 493
  GdkWindow *parent;
  GdkWindow *sibling;
494 495 496 497
  cairo_region_t *child_region;
  GdkRectangle r;
  GList *l;

498 499
  parent = window->parent;

500
  if (gdk_window_is_toplevel (window))
501 502 503 504 505 506
    return;

  /* Convert from from window coords to parent coords */
  cairo_region_translate (region, window->x, window->y);

  for (l = parent->children; l; l = l->next)
507
    {
508
      sibling = l->data;
509

510
      if (sibling == window)
511 512
	break;

513
      if (!GDK_WINDOW_IS_MAPPED (sibling) || sibling->input_only)
514 515
	continue;

516 517 518 519
      r.x = sibling->x;
      r.y = sibling->y;
      r.width = sibling->width;
      r.height = sibling->height;
520 521

      child_region = cairo_region_create_rectangle (&r);
522 523

      if (sibling->shape)
524 525
	{
	  /* Adjust shape region to parent window coords */
526 527 528 529
	  cairo_region_translate (sibling->shape, sibling->x, sibling->y);
	  cairo_region_intersect (child_region, sibling->shape);
	  cairo_region_translate (sibling->shape, -sibling->x, -sibling->y);
	}
530 531 532 533

      cairo_region_subtract (region, child_region);
      cairo_region_destroy (child_region);
    }
534

535 536
  remove_sibling_overlapped_area (parent, region);

537 538
  /* Convert back to window coords */
  cairo_region_translate (region, -window->x, -window->y);
539 540 541 542
}

static void
remove_child_area (GdkWindow *window,
Alexander Larsson's avatar
Alexander Larsson committed
543
		   gboolean for_input,
544
		   cairo_region_t *region)
545
{
546
  GdkWindow *child;
547
  cairo_region_t *child_region;
548 549
  GdkRectangle r;
  GList *l;
550

551
  for (l = window->children; l; l = l->next)
552 553 554
    {
      child = l->data;

555 556
      /* If region is empty already, no need to do
	 anything potentially costly */
Benjamin Otte's avatar
Benjamin Otte committed
557
      if (cairo_region_is_empty (region))
558 559
	break;

560
      if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only)
561 562 563 564 565 566
	continue;

      r.x = child->x;
      r.y = child->y;
      r.width = child->width;
      r.height = child->height;
Alexander Larsson's avatar
Alexander Larsson committed
567

568
      /* Bail early if child totally outside region */
Benjamin Otte's avatar
Benjamin Otte committed
569
      if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
570 571
	continue;

Benjamin Otte's avatar
Benjamin Otte committed
572
      child_region = cairo_region_create_rectangle (&r);
573

Alexander Larsson's avatar
Alexander Larsson committed
574
      if (child->shape)
575 576
	{
	  /* Adjust shape region to parent window coords */
Benjamin Otte's avatar
Benjamin Otte committed
577 578 579
	  cairo_region_translate (child->shape, child->x, child->y);
	  cairo_region_intersect (child_region, child->shape);
	  cairo_region_translate (child->shape, -child->x, -child->y);
580
	}
Alexander Larsson's avatar
Alexander Larsson committed
581 582 583 584

      if (for_input)
	{
	  if (child->input_shape)
Benjamin Otte's avatar
Benjamin Otte committed
585
	    cairo_region_intersect (child_region, child->input_shape);
Alexander Larsson's avatar
Alexander Larsson committed
586
	}
587

588
      cairo_region_subtract (region, child_region);
Benjamin Otte's avatar
Benjamin Otte committed
589
      cairo_region_destroy (child_region);
590 591 592
    }
}

Alexander Larsson's avatar
Alexander Larsson committed
593
static gboolean
594
should_apply_clip_as_shape (GdkWindow *window)
Alexander Larsson's avatar
Alexander Larsson committed
595 596
{
  return
597
    gdk_window_has_impl (window) &&
598
    /* Not for non-shaped toplevels */
599
    (window->shape != NULL || window->applied_shape) &&
Alexander Larsson's avatar
Alexander Larsson committed
600
    /* or for foreign windows */
601
    window->window_type != GDK_WINDOW_FOREIGN &&
Alexander Larsson's avatar
Alexander Larsson committed
602
    /* or for the root window */
603
    window->window_type != GDK_WINDOW_ROOT;
Alexander Larsson's avatar
Alexander Larsson committed
604 605 606
}

static void
607
apply_shape (GdkWindow *window,
608
	     cairo_region_t *region)
Alexander Larsson's avatar
Alexander Larsson committed
609
{
610
  GdkWindowImplClass *impl_class;
Alexander Larsson's avatar
Alexander Larsson committed
611 612 613 614 615

  /* We trash whether we applied a shape so that
     we can avoid unsetting it many times, which
     could happen in e.g. apply_clip_as_shape as
     windows get resized */
616
  impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
Alexander Larsson's avatar
Alexander Larsson committed
617
  if (region)
618
    impl_class->shape_combine_region (window,
Alexander Larsson's avatar
Alexander Larsson committed
619
				      region, 0, 0);
620 621
  else if (window->applied_shape)
    impl_class->shape_combine_region (window,
Alexander Larsson's avatar
Alexander Larsson committed
622 623
				      NULL, 0, 0);

624
  window->applied_shape = region != NULL;
Alexander Larsson's avatar
Alexander Larsson committed
625 626
}

Benjamin Otte's avatar
Benjamin Otte committed
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
static gboolean
region_rect_equal (const cairo_region_t *region,
                   const GdkRectangle *rect)
{
    GdkRectangle extents;

    if (cairo_region_num_rectangles (region) != 1)
        return FALSE;

    cairo_region_get_extents (region, &extents);

    return extents.x == rect->x &&
        extents.y == rect->y &&
        extents.width == rect->width &&
        extents.height == rect->height;
}

Alexander Larsson's avatar
Alexander Larsson committed
644
static void
645
apply_clip_as_shape (GdkWindow *window)
Alexander Larsson's avatar
Alexander Larsson committed
646 647
{
  GdkRectangle r;
648
  cairo_region_t *region;
Alexander Larsson's avatar
Alexander Larsson committed
649 650

  r.x = r.y = 0;
651 652
  r.width = window->width;
  r.height = window->height;
Alexander Larsson's avatar
Alexander Larsson committed
653

654
  region = cairo_region_copy (window->clip_region);
655
  remove_sibling_overlapped_area (window, region);
656

Alexander Larsson's avatar
Alexander Larsson committed
657 658 659 660
  /* We only apply the clip region if would differ
     from the actual clip region implied by the size
     of the window. This is to avoid unneccessarily
     adding meaningless shapes to all native subwindows */
661 662
  if (!region_rect_equal (region, &r))
    apply_shape (window, region);
Alexander Larsson's avatar
Alexander Larsson committed
663
  else
664
    apply_shape (window, NULL);
665 666

  cairo_region_destroy (region);
Alexander Larsson's avatar
Alexander Larsson committed
667 668
}

669
static void
670 671 672
recompute_visible_regions_internal (GdkWindow *private,
				    gboolean   recalculate_clip,
				    gboolean   recalculate_children)
673 674 675
{
  GdkRectangle r;
  GList *l;
676
  GdkWindow *child;
677
  cairo_region_t *new_clip;
678 679 680 681 682 683
  gboolean clip_region_changed;
  gboolean abs_pos_changed;
  int old_abs_x, old_abs_y;

  old_abs_x = private->abs_x;
  old_abs_y = private->abs_y;
684

685
  /* Update absolute position */
686 687 688 689
  if ((gdk_window_has_impl (private) &&
       private->window_type != GDK_WINDOW_SUBSURFACE) ||
      (gdk_window_is_toplevel (private) &&
       private->window_type == GDK_WINDOW_SUBSURFACE))
690
    {
691
      /* Native windows and toplevel subsurfaces start here */
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
      private->abs_x = 0;
      private->abs_y = 0;
    }
  else
    {
      private->abs_x = private->parent->abs_x + private->x;
      private->abs_y = private->parent->abs_y + private->y;
    }

  abs_pos_changed =
    private->abs_x != old_abs_x ||
    private->abs_y != old_abs_y;

  /* Update clip region based on:
   * parent clip
707
   * window size/position
708 709
   */
  clip_region_changed = FALSE;
710
  if (recalculate_clip)
711
    {
712
      if (private->viewable)
713
	{
714 715 716 717 718
	  /* Calculate visible region (sans children) in parent window coords */
	  r.x = private->x;
	  r.y = private->y;
	  r.width = private->width;
	  r.height = private->height;
Benjamin Otte's avatar
Benjamin Otte committed
719
	  new_clip = cairo_region_create_rectangle (&r);
720

721
	  if (!gdk_window_is_toplevel (private))
722
	    cairo_region_intersect (new_clip, private->parent->clip_region);
723

724
	  /* Convert from parent coords to window coords */
Benjamin Otte's avatar
Benjamin Otte committed
725
	  cairo_region_translate (new_clip, -private->x, -private->y);
726

727
	  if (should_apply_clip_as_shape (private) && private->shape)
Benjamin Otte's avatar
Benjamin Otte committed
728
	    cairo_region_intersect (new_clip, private->shape);
729 730
	}
      else
731
	  new_clip = cairo_region_create ();
Alexander Larsson's avatar
Alexander Larsson committed
732

733
      if (private->clip_region == NULL ||
Benjamin Otte's avatar
Benjamin Otte committed
734
	  !cairo_region_equal (private->clip_region, new_clip))
735
	clip_region_changed = TRUE;
736

737
      if (private->clip_region)
Benjamin Otte's avatar
Benjamin Otte committed
738
	cairo_region_destroy (private->clip_region);
739 740 741
      private->clip_region = new_clip;
    }

742 743
  /* Update all children, recursively (except for root, where children are not exact). */
  if ((abs_pos_changed || clip_region_changed || recalculate_children) &&
744
      private->window_type != GDK_WINDOW_ROOT)
745 746 747 748 749 750 751 752
    {
      for (l = private->children; l; l = l->next)
	{
	  child = l->data;
	  /* Only recalculate clip if the the clip region changed, otherwise
	   * there is no way the child clip region could change (its has not e.g. moved)
	   * Except if recalculate_children is set to force child updates
	   */
753 754
	  recompute_visible_regions_internal (child,
					      recalculate_clip && (clip_region_changed || recalculate_children),
755
					      FALSE);
756 757 758 759 760 761 762 763 764 765 766 767 768
	}
    }
}

/* Call this when private has changed in one or more of these ways:
 *  size changed
 *  window moved
 *  new window added
 *  stacking order of window changed
 *  child deleted
 *
 * It will recalculate abs_x/y and the clip regions
 *
769
 * Unless the window didn’t change stacking order or size/pos, pass in TRUE
770
 * for recalculate_siblings. (Mostly used internally for the recursion)
771
 *
772
 * If a child window was removed (and you can’t use that child for
773 774 775
 * recompute_visible_regions), pass in TRUE for recalculate_children on the parent
 */
static void
776
recompute_visible_regions (GdkWindow *private,
777 778
			   gboolean recalculate_children)
{
779 780 781 782 783
  GdkWindow *toplevel;

  toplevel = gdk_window_get_toplevel (private);
  toplevel->geometry_dirty = TRUE;

784 785 786 787 788
  recompute_visible_regions_internal (private,
				      TRUE,
				      recalculate_children);
}

789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
static void
gdk_window_clear_old_updated_area (GdkWindow *window)
{
  int i;

  for (i = 0; i < 2; i++)
    {
      if (window->old_updated_area[i])
        {
          cairo_region_destroy (window->old_updated_area[i]);
          window->old_updated_area[i] = NULL;
        }
    }
}

static void
gdk_window_append_old_updated_area (GdkWindow *window,
                                    cairo_region_t *region)
{
  if (window->old_updated_area[1])
    cairo_region_destroy (window->old_updated_area[1]);
  window->old_updated_area[1] = window->old_updated_area[0];
  window->old_updated_area[0] = cairo_region_reference (region);
}

814 815 816
void
_gdk_window_update_size (GdkWindow *window)
{
817
  gdk_window_clear_old_updated_area (window);
818
  recompute_visible_regions (window, FALSE);
819 820
}

821
static GdkEventMask
822 823
get_native_device_event_mask (GdkWindow *private,
                              GdkDevice *device)
824
{
825 826 827 828 829 830 831
  GdkEventMask event_mask;

  if (device)
    event_mask = GPOINTER_TO_INT (g_hash_table_lookup (private->device_events, device));
  else
    event_mask = private->event_mask;

832
  if (private->window_type == GDK_WINDOW_ROOT ||
833
      private->window_type == GDK_WINDOW_FOREIGN)
834
    return event_mask;
835
  else
836
    {
837 838
      GdkEventMask mask;

Carlos Garnacho's avatar
Carlos Garnacho committed
839
      mask = private->event_mask;
840 841 842 843

      /* We need thse for all native windows so we can
	 emulate events on children: */
      mask |=
844
	GDK_EXPOSURE_MASK |
845 846 847 848 849
	GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
        GDK_TOUCH_MASK |
        GDK_POINTER_MOTION_MASK |
        GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
        GDK_SCROLL_MASK;
850 851

      return mask;
852
    }
853 854
}

855
static GdkEventMask
856
get_native_event_mask (GdkWindow *private)
857 858 859 860
{
  return get_native_device_event_mask (private, NULL);
}

861
GdkWindow*
862 863
gdk_window_new (GdkDisplay    *display,
                GdkWindow     *parent,
864
		GdkWindowAttr *attributes)
865 866
{
  GdkWindow *window;
867 868
  gboolean native;
  GdkEventMask event_mask;
869

870
  g_return_val_if_fail (attributes != NULL, NULL);
871

872
  if (parent != NULL && GDK_WINDOW_DESTROYED (parent))
873
    {
874
      g_warning ("gdk_window_new(): parent is destroyed");
875 876
      return NULL;
    }
877

878
  window = _gdk_display_create_window (display);
879

880
  window->parent = parent;
881

882 883
  window->accept_focus = TRUE;
  window->focus_on_map = TRUE;
884
  window->event_compression = TRUE;
885

886 887
  window->x = attributes->x;
  window->y = attributes->y;
888 889
  window->width = (attributes->width > 1) ? (attributes->width) : (1);
  window->height = (attributes->height > 1) ? (attributes->height) : (1);
890
  window->alpha = 255;
891 892 893 894 895 896 897

  if (attributes->wclass == GDK_INPUT_ONLY)
    {
      /* Backwards compatiblity - we've always ignored
       * attributes->window_type for input-only windows
       * before
       */
898
      if (parent == NULL)
899
	window->window_type = GDK_WINDOW_TEMP;
900
      else
901
	window->window_type = GDK_WINDOW_CHILD;
902 903
    }
  else
904
    window->window_type = attributes->window_type;
905 906

  /* Sanity checks */
907
  switch (window->window_type)
908 909 910
    {
    case GDK_WINDOW_TOPLEVEL:
    case GDK_WINDOW_TEMP:
911
      if (parent != NULL && GDK_WINDOW_TYPE (parent) != GDK_WINDOW_ROOT)
912
	g_warning (G_STRLOC "Toplevel windows must be created as children of\n"
913
		   "a window of type GDK_WINDOW_ROOT");
914
      break;
915 916 917 918 919 920 921 922 923
    case GDK_WINDOW_SUBSURFACE:
#ifdef GDK_WINDOWING_WAYLAND
      if (!GDK_IS_WAYLAND_DISPLAY (display))
        {
          g_warning (G_STRLOC "Subsurface windows can only be used on Wayland");
          return NULL;
        }
#endif
      break;
924
    case GDK_WINDOW_CHILD:
925 926 927 928 929 930 931
      if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT ||
          GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN)
        {
          g_warning (G_STRLOC "Child windows must not be created as children of\n"
                     "a window of type GDK_WINDOW_ROOT or GDK_WINDOW_FOREIGN");
          return NULL;
        }
932 933
      break;
    default:
934
      g_warning (G_STRLOC "cannot make windows of type %d", window->window_type);
935 936
      return NULL;
    }
937

938
  window->event_mask = GDK_ALL_EVENTS_MASK;
939 940 941

  if (attributes->wclass == GDK_INPUT_OUTPUT)
    {
942
      window->input_only = FALSE;
943 944 945
    }
  else
    {
946
      window->input_only = TRUE;
947 948
    }

949
  native = FALSE;
950

951 952 953
  if (window->parent != NULL)
    window->parent->children = g_list_concat (&window->children_list_node, window->parent->children);
  else
954 955 956
    {
      GdkFrameClock *frame_clock = g_object_new (GDK_TYPE_FRAME_CLOCK_IDLE, NULL);
      gdk_window_set_frame_clock (window, frame_clock);
957
      g_object_unref (frame_clock);
958

959 960
      native = TRUE; /* Always use native windows for toplevels */
    }
961

962 963 964 965 966
#ifdef GDK_WINDOWING_WAYLAND
  if (window->window_type == GDK_WINDOW_SUBSURFACE)
    native = TRUE; /* Always use native windows for subsurfaces as well */
#endif

967
  if (native)
968
    {
969
      event_mask = get_native_event_mask (window);
970

971
      /* Create the impl */
Matthias Clasen's avatar
Matthias Clasen committed
972
      _gdk_display_create_window_impl (display, window, parent, event_mask, attributes);
973
      window->impl_window = window;
974 975
    }
  else
976
    {
977 978
      window->impl_window = g_object_ref (window->parent->impl_window);
      window->impl = g_object_ref (window->impl_window->impl);
979
    }
980

981
  recompute_visible_regions (window, FALSE);
982

983
  g_signal_connect (display, "seat-removed", G_CALLBACK (seat_removed_cb), window);
984

Matthias Clasen's avatar
Matthias Clasen committed
985
  if ((_gdk_gl_flags & (GDK_GL_ALWAYS | GDK_GL_DISABLE)) == GDK_GL_ALWAYS)
986 987 988 989 990
    {
      GError *error = NULL;

      if (gdk_window_get_paint_gl_context (window, &error) == NULL)
        {
991
          g_warning ("Unable to force GL enabled: %s", error->message);
992 993 994 995
          g_error_free (error);
        }
    }

996 997 998
  return window;
}

999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021
/**
 * gdk_window_new_toplevel: (constructor)
 * @display: the display to create the window on
 * @width: width of new window
 * @height: height of new window
 *
 * Creates a new toplevel window. The window will be managed by the window
 * manager.
 *
 * Returns: (transfer full): the new #GdkWindow
 *
 * Since: 3.90
 **/
GdkWindow *
gdk_window_new_toplevel (GdkDisplay *display,
                         gint        width,
                         gint        height)
{
  GdkWindowAttr attr;

  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  attr.wclass = GDK_INPUT_OUTPUT;
1022 1023
  attr.x = 0;
  attr.y = 0;
1024 1025 1026 1027
  attr.width = width;
  attr.height = height;
  attr.window_type = GDK_WINDOW_TOPLEVEL;

1028
  return gdk_window_new (display, NULL, &attr);
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 1056 1057 1058
/**
 * gdk_window_new_popup: (constructor)
 * @display: the display to create the window on
 * @position: position of the window on screen
 *
 * Creates a new toplevel popup window. The window will bypass window
 * management.
 *
 * Returns: (transfer full): the new #GdkWindow
 *
 * Since: 3.90
 **/
GdkWindow *
gdk_window_new_popup (GdkDisplay         *display,
                      const GdkRectangle *position)
{
  GdkWindowAttr attr;

  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
  g_return_val_if_fail (position != NULL, NULL);

  attr.wclass = GDK_INPUT_OUTPUT;
  attr.x = position->x;
  attr.y = position->y;
  attr.width = position->width;
  attr.height = position->height;
  attr.window_type = GDK_WINDOW_TEMP;

1059
  return gdk_window_new (display, NULL, &attr);
1060
}
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088

/**
 * gdk_window_new_temp: (constructor)
 * @display: the display to create the window on
 *
 * Creates a new toplevel temporary window. The window will be
 * situated off-screen and not handle output.
 *
 * You most likely do not want to use this function.
 *
 * Returns: (transfer full): the new #GdkWindow
 *
 * Since: 3.90
 **/
GdkWindow *
gdk_window_new_temp (GdkDisplay *display)
{
  GdkWindowAttr attr;

  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  attr.wclass = GDK_INPUT_ONLY;
  attr.x = -100;
  attr.y = -100;
  attr.width = 10;
  attr.height = 10;
  attr.window_type = GDK_WINDOW_TEMP;

1089
  return gdk_window_new (display, NULL, &attr);
1090 1091
}

1092 1093 1094 1095 1096 1097 1098 1099
/**
 * gdk_window_new_child: (constructor)
 * @parent: the parent window
 * @position: placement of the window inside @parent
 *
 * Creates a new client-side child window.
 *
 * Returns: (transfer full): the new #GdkWindow
1100 1101
 *
 * Since: 3.90
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
 **/
GdkWindow *
gdk_window_new_child (GdkWindow          *parent,
                      const GdkRectangle *position)
{
  GdkWindowAttr attr;

  g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL);

  attr.wclass = GDK_INPUT_OUTPUT;
  attr.x = position->x;
  attr.y = position->y;
  attr.width = position->width;
  attr.height = position->height;
  attr.window_type = GDK_WINDOW_CHILD;

1118
  return gdk_window_new (gdk_window_get_display (parent), parent, &attr);
1119 1120
}

1121 1122
/**
 * _gdk_event_filter_unref:
1123
 * @window: (allow-none): A #GdkWindow, or %NULL to be the global window
1124 1125 1126 1127 1128 1129 1130 1131 1132
 * @filter: A window filter
 *
 * Release a reference to @filter.  Note this function may
 * mutate the list storage, so you need to handle this
 * if iterating over a list of filters.
 */
void
_gdk_event_filter_unref (GdkWindow       *window,
			 GdkEventFilter  *filter)
1133
{
1134 1135 1136 1137 1138 1139 1140 1141
  GList **filters;
  GList *tmp_list;

  if (window == NULL)
    filters = &_g