gdkwindow.c 337 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 36
#include "gdkscreenprivate.h"
#include "gdkdisplayprivate.h"
37
#include "gdkdeviceprivate.h"
38
#include "gdkvisualprivate.h"
39
#include "gdkmarshalers.h"
Owen W. Taylor's avatar
Owen W. Taylor committed
40
#include "gdkframeclockidle.h"
41
#include "gdkwindowimpl.h"
42
#include "gdkglcontextprivate.h"
43
#include "gdk-private.h"
44

45 46
#include <math.h>

47 48
#include <epoxy/gl.h>

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

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

56 57 58
#undef DEBUG_WINDOW_PRINTING


59 60 61 62 63
/**
 * SECTION:windows
 * @Short_description: Onscreen display areas in the target window system
 * @Title: Windows
 *
64
 * A #GdkWindow is a (usually) rectangular region on the screen.
65
 * It’s a low-level object, used to implement high-level objects such as
66
 * #GtkWidget and #GtkWindow on the GTK+ level. A #GtkWindow is a toplevel
William Jon McCann's avatar
William Jon McCann committed
67
 * window, the thing a user might think of as a “window” with a titlebar
Matthias Clasen's avatar
Matthias Clasen committed
68 69
 * and so on; a #GtkWindow may contain many #GdkWindows. For example,
 * each #GtkButton has a #GdkWindow associated with it.
70
 *
71
 * # Composited Windows # {#COMPOSITED-WINDOWS}
72
 *
73
 * Normally, the windowing system takes care of rendering the contents
Matthias Clasen's avatar
Matthias Clasen committed
74 75
 * of a child window onto its parent window. This mechanism can be
 * intercepted by calling gdk_window_set_composited() on the child
76
 * window. For a “composited” window it is the
Matthias Clasen's avatar
Matthias Clasen committed
77
 * responsibility of the application to render the window contents at
78
 * the right spot.
79
 *
80
 * # Offscreen Windows # {#OFFSCREEN-WINDOWS}
Matthias Clasen's avatar
Matthias Clasen committed
81
 *
82
 * Offscreen windows are more general than composited windows, since
Matthias Clasen's avatar
Matthias Clasen committed
83
 * they allow not only to modify the rendering of the child window onto
84
 * its parent, but also to apply coordinate transformations.
Matthias Clasen's avatar
Matthias Clasen committed
85 86 87 88 89 90 91 92 93 94 95
 *
 * To integrate an offscreen window into a window hierarchy, one has
 * to call gdk_offscreen_window_set_embedder() and handle a number of
 * signals. The #GdkWindow::pick-embedded-child signal on the embedder
 * window is used to select an offscreen child at given coordinates,
 * and the #GdkWindow::to-embedder and #GdkWindow::from-embedder signals
 * on the offscreen window are used to translate coordinates between
 * the embedder and the offscreen window.
 *
 * For rendering an offscreen window onto its embedder, the contents
 * of the offscreen window are available as a surface, via
96
 * gdk_offscreen_window_get_surface().
97 98
 */

99

100 101 102 103
/* 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
104
 * object available as “impl” in the window object.
105
 *
106 107 108
 * With the addition of client side windows and offscreen windows this
 * changes a bit. The application-visible GdkWindow object behaves as
 * it did before, but not all such windows now have a corresponding native
William Jon McCann's avatar
William Jon McCann committed
109
 * window. Instead windows that are “client side” are emulated by the gdk
110 111
 * code such that clipping, drawing, moving, events etc work as expected.
 *
William Jon McCann's avatar
William Jon McCann committed
112
 * For GdkWindows that have a native window the “impl” object is the
113 114 115 116 117 118 119
 * same as before. However, for all client side windows the impl object
 * is shared with its parent (i.e. all client windows descendants of one
 * native window has the same impl.
 *
 * Additionally there is a new type of platform independent impl object,
 * GdkOffscreenWindow. All windows of type GDK_WINDOW_OFFSCREEN get an impl
 * of this type (while their children are generally GDK_WINDOW_CHILD virtual
120 121
 * windows). Such windows work by allocating a #cairo_surface_t as the backing
 * store for drawing operations, which is resized with the window.
122
 *
William Jon McCann's avatar
William Jon McCann committed
123 124
 * 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
125 126 127 128 129
 * 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
130
 * region of the window wrt parent windows, in window-relative coordinates (clip_region).
131 132 133 134 135 136 137 138 139
 *
 * All toplevel windows are native windows, but also child windows can be
 * native (although not children of offscreens). We always listen to
 * a basic set of events (see get_native_event_mask) for these windows
 * so that we can emulate events for any client side children.
 *
 * For native windows we apply the calculated clip region as a window shape
 * so that eg. client side siblings that overlap the native child properly
 * draws over the native child window.
140
 */
141

142 143 144
/* This adds a local value to the GdkVisibilityState enum */
#define GDK_VISIBILITY_NOT_VIEWABLE 3

145
enum {
Alexander Larsson's avatar
Alexander Larsson committed
146 147 148
  PICK_EMBEDDED_CHILD, /* only called if children are embedded */
  TO_EMBEDDER,
  FROM_EMBEDDER,
149
  CREATE_SURFACE,
150 151 152
  LAST_SIGNAL
};

Cody Russell's avatar
Cody Russell committed
153 154
enum {
  PROP_0,
155
  PROP_CURSOR
Cody Russell's avatar
Cody Russell committed
156 157
};

158
/* Global info */
159

160
static void gdk_window_finalize   (GObject              *object);
Cody Russell's avatar
Cody Russell committed
161 162 163 164 165 166 167 168 169 170

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);

171
static void gdk_window_clear_backing_region (GdkWindow *window);
172

173
static void recompute_visible_regions   (GdkWindow *private,
174
					 gboolean recalculate_children);
175 176
static void gdk_window_invalidate_in_parent (GdkWindow *private);
static void move_native_children        (GdkWindow *private);
177 178
static void update_cursor               (GdkDisplay *display,
                                         GdkDevice  *device);
179
static void impl_window_add_update_area (GdkWindow *impl_window,
180
					 cairo_region_t *region);
181
static void gdk_window_invalidate_region_full (GdkWindow       *window,
182
					       const cairo_region_t *region,
183
					       gboolean         invalidate_children);
184 185
static void gdk_window_invalidate_rect_full (GdkWindow          *window,
					     const GdkRectangle *rect,
186
					     gboolean            invalidate_children);
187
static cairo_surface_t *gdk_window_ref_impl_surface (GdkWindow *window);
188

189 190
static void gdk_window_set_frame_clock (GdkWindow      *window,
                                        GdkFrameClock  *clock);
Owen W. Taylor's avatar
Owen W. Taylor committed
191

192 193 194 195 196
static void draw_ugly_color (GdkWindow       *window,
                             const cairo_region_t *region,
                             int color);


197 198
static guint signals[LAST_SIGNAL] = { 0 };

199 200
static gpointer parent_class = NULL;

Benjamin Otte's avatar
Benjamin Otte committed
201
G_DEFINE_ABSTRACT_TYPE (GdkWindow, gdk_window, G_TYPE_OBJECT)
202

203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
#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
	{
224
	  int i;
225 226
	  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);
227
	  for (i = 0; i < num; i++)
228
	    {
229
              cairo_region_get_rectangle (region, i, &r);
230 231 232 233 234 235 236 237 238 239 240
	      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

241
static void
242
gdk_window_init (GdkWindow *window)
243 244
{
  /* 0-initialization is good for all other fields. */
rhlabs's avatar
rhlabs committed
245

246
  window->window_type = GDK_WINDOW_CHILD;
Elliot Lee's avatar
Elliot Lee committed
247

Havoc Pennington's avatar
Havoc Pennington committed
248
  window->state = GDK_WINDOW_STATE_WITHDRAWN;
249
  window->fullscreen_mode = GDK_FULLSCREEN_ON_CURRENT_MONITOR;
250 251 252
  window->width = 1;
  window->height = 1;
  window->toplevel_window_type = -1;
253 254 255 256 257
  /* starts hidden */
  window->effective_visibility = GDK_VISIBILITY_NOT_VIEWABLE;
  window->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
  /* Default to unobscured since some backends don't send visibility events */
  window->native_visibility = GDK_VISIBILITY_UNOBSCURED;
258 259 260

  window->device_cursor = g_hash_table_new_full (NULL, NULL,
                                                 NULL, g_object_unref);
261
}
262

263
/* Stop and return on the first non-NULL parent */
264
static gboolean
265 266 267 268
accumulate_get_window (GSignalInvocationHint *ihint,
		       GValue		       *return_accu,
		       const GValue	       *handler_return,
		       gpointer               data)
269 270 271
{
  g_value_copy (handler_return, return_accu);
  /* Continue while returning NULL */
272
  return g_value_get_object (handler_return) == NULL;
273 274
}

275 276 277 278 279 280 281 282 283 284 285 286
static gboolean
create_surface_accumulator (GSignalInvocationHint *ihint,
                            GValue                *return_accu,
                            const GValue          *handler_return,
                            gpointer               data)
{
  g_value_copy (handler_return, return_accu);

  /* Stop on the first non-NULL return value */
  return g_value_get_boxed (handler_return) == NULL;
}

287 288
static GQuark quark_pointer_window = 0;

289
static void
290
gdk_window_class_init (GdkWindowClass *klass)
291 292
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
293

294 295
  parent_class = g_type_class_peek_parent (klass);

296
  object_class->finalize = gdk_window_finalize;
Cody Russell's avatar
Cody Russell committed
297 298
  object_class->set_property = gdk_window_set_property;
  object_class->get_property = gdk_window_get_property;
299

300 301
  klass->create_surface = _gdk_offscreen_window_create_surface;

302
  quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window");
303 304


Cody Russell's avatar
Cody Russell committed
305
  /* Properties */
306 307 308 309 310 311 312 313 314

  /**
   * GdkWindow:cursor:
   *
   * The mouse pointer for a #GdkWindow. See gdk_window_set_cursor() and
   * gdk_window_get_cursor() for details.
   *
   * Since: 2.18
   */
Cody Russell's avatar
Cody Russell committed
315 316
  g_object_class_install_property (object_class,
                                   PROP_CURSOR,
Benjamin Otte's avatar
Benjamin Otte committed
317 318 319 320 321
                                   g_param_spec_object ("cursor",
                                                        P_("Cursor"),
                                                        P_("Cursor"),
                                                        GDK_TYPE_CURSOR,
                                                        G_PARAM_READWRITE));
Cody Russell's avatar
Cody Russell committed
322

Matthias Clasen's avatar
Matthias Clasen committed
323 324 325 326 327 328 329 330 331
  /**
   * GdkWindow::pick-embedded-child:
   * @window: the window on which the signal is emitted
   * @x: x coordinate in the window
   * @y: y coordinate in the window
   *
   * The ::pick-embedded-child signal is emitted to find an embedded
   * child at the given position.
   *
332 333
   * Returns: (nullable) (transfer none): the #GdkWindow of the
   *     embedded child at @x, @y, or %NULL
Matthias Clasen's avatar
Matthias Clasen committed
334 335 336
   *
   * Since: 2.18
   */
Alexander Larsson's avatar
Alexander Larsson committed
337 338
  signals[PICK_EMBEDDED_CHILD] =
    g_signal_new (g_intern_static_string ("pick-embedded-child"),
339 340
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
341
                  G_STRUCT_OFFSET (GdkWindowClass, pick_embedded_child),
342
		  accumulate_get_window, NULL,
Matthias Clasen's avatar
Matthias Clasen committed
343
		  _gdk_marshal_OBJECT__DOUBLE_DOUBLE,
344 345 346 347
		  GDK_TYPE_WINDOW,
		  2,
		  G_TYPE_DOUBLE,
		  G_TYPE_DOUBLE);
Matthias Clasen's avatar
Matthias Clasen committed
348 349 350 351

  /**
   * GdkWindow::to-embedder:
   * @window: the offscreen window on which the signal is emitted
352 353 354
   * @offscreen_x: x coordinate in the offscreen window
   * @offscreen_y: y coordinate in the offscreen window
   * @embedder_x: (out) (type double): return location for the x
355
   *     coordinate in the embedder window
356
   * @embedder_y: (out) (type double): return location for the y
357
   *     coordinate in the embedder window
Matthias Clasen's avatar
Matthias Clasen committed
358 359 360 361
   *
   * The ::to-embedder signal is emitted to translate coordinates
   * in an offscreen window to its embedder.
   *
362
   * See also #GdkWindow::from-embedder.
Matthias Clasen's avatar
Matthias Clasen committed
363
   *
Matthias Clasen's avatar
Matthias Clasen committed
364 365
   * Since: 2.18
   */
Alexander Larsson's avatar
Alexander Larsson committed
366 367
  signals[TO_EMBEDDER] =
    g_signal_new (g_intern_static_string ("to-embedder"),
368 369
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
370
                  G_STRUCT_OFFSET (GdkWindowClass, to_embedder),
371
		  NULL, NULL,
Matthias Clasen's avatar
Matthias Clasen committed
372
		  _gdk_marshal_VOID__DOUBLE_DOUBLE_POINTER_POINTER,
373 374 375 376 377 378
		  G_TYPE_NONE,
		  4,
		  G_TYPE_DOUBLE,
		  G_TYPE_DOUBLE,
		  G_TYPE_POINTER,
		  G_TYPE_POINTER);
Matthias Clasen's avatar
Matthias Clasen committed
379 380 381 382

  /**
   * GdkWindow::from-embedder:
   * @window: the offscreen window on which the signal is emitted
383 384 385
   * @embedder_x: x coordinate in the embedder window
   * @embedder_y: y coordinate in the embedder window
   * @offscreen_x: (out) (type double): return location for the x
386
   *     coordinate in the offscreen window
387
   * @offscreen_y: (out) (type double): return location for the y
388
   *     coordinate in the offscreen window
Matthias Clasen's avatar
Matthias Clasen committed
389 390 391 392
   *
   * The ::from-embedder signal is emitted to translate coordinates
   * in the embedder of an offscreen window to the offscreen window.
   *
393
   * See also #GdkWindow::to-embedder.
Matthias Clasen's avatar
Matthias Clasen committed
394
   *
Matthias Clasen's avatar
Matthias Clasen committed
395 396
   * Since: 2.18
   */
Alexander Larsson's avatar
Alexander Larsson committed
397 398
  signals[FROM_EMBEDDER] =
    g_signal_new (g_intern_static_string ("from-embedder"),
399 400
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
401
                  G_STRUCT_OFFSET (GdkWindowClass, from_embedder),
402
		  NULL, NULL,
Matthias Clasen's avatar
Matthias Clasen committed
403
		  _gdk_marshal_VOID__DOUBLE_DOUBLE_POINTER_POINTER,
404 405 406 407 408 409
		  G_TYPE_NONE,
		  4,
		  G_TYPE_DOUBLE,
		  G_TYPE_DOUBLE,
		  G_TYPE_POINTER,
		  G_TYPE_POINTER);
410 411 412 413 414 415 416 417

  /**
   * GdkWindow::create-surface:
   * @window: the offscreen window on which the signal is emitted
   * @width: the width of the offscreen surface to create
   * @height: the height of the offscreen surface to create
   *
   * The ::create-surface signal is emitted when an offscreen window
418
   * needs its surface (re)created, which happens either when the
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
   * window is first drawn to, or when the window is being
   * resized. The first signal handler that returns a non-%NULL
   * surface will stop any further signal emission, and its surface
   * will be used.
   *
   * Note that it is not possible to access the window's previous
   * surface from within any callback of this signal. Calling
   * gdk_offscreen_window_get_surface() will lead to a crash.
   *
   * Returns: the newly created #cairo_surface_t for the offscreen window
   *
   * Since: 3.0
   */
  signals[CREATE_SURFACE] =
    g_signal_new (g_intern_static_string ("create-surface"),
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_LAST,
436
                  G_STRUCT_OFFSET (GdkWindowClass, create_surface),
437 438 439 440 441 442
                  create_surface_accumulator, NULL,
                  _gdk_marshal_BOXED__INT_INT,
                  CAIRO_GOBJECT_TYPE_SURFACE,
                  2,
                  G_TYPE_INT,
                  G_TYPE_INT);
443
}
444

445 446 447 448 449
static void
device_removed_cb (GdkDeviceManager *device_manager,
                   GdkDevice        *device,
                   GdkWindow        *window)
{
450 451
  window->devices_inside = g_list_remove (window->devices_inside, device);
  g_hash_table_remove (window->device_cursor, device);
452

453 454
  if (window->device_events)
    g_hash_table_remove (window->device_events, device);
455 456
}

457 458 459 460
static void
gdk_window_finalize (GObject *object)
{
  GdkWindow *window = GDK_WINDOW (object);
461 462
  GdkDeviceManager *device_manager;

463
  device_manager = gdk_display_get_device_manager (gdk_window_get_display (window));
464
  g_signal_handlers_disconnect_by_func (device_manager, device_removed_cb, window);
465

466 467 468 469 470 471 472 473 474 475 476 477 478
  if (!GDK_WINDOW_DESTROYED (window))
    {
      if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
	{
	  g_warning ("losing last reference to undestroyed window\n");
	  _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);
    }
479

480
  if (window->impl)
481
    {
482 483
      g_object_unref (window->impl);
      window->impl = NULL;
484 485
    }

486
  if (window->impl_window != window)
487
    {
488 489
      g_object_unref (window->impl_window);
      window->impl_window = NULL;
490
    }
491

492 493
  if (window->shape)
    cairo_region_destroy (window->shape);
Alexander Larsson's avatar
Alexander Larsson committed
494

495 496
  if (window->input_shape)
    cairo_region_destroy (window->input_shape);
Alexander Larsson's avatar
Alexander Larsson committed
497

498
  if (window->cursor)
499
    g_object_unref (window->cursor);
500

501 502
  if (window->device_cursor)
    g_hash_table_destroy (window->device_cursor);
503

504 505
  if (window->device_events)
    g_hash_table_destroy (window->device_events);
506

507 508 509
  if (window->source_event_masks)
    g_hash_table_destroy (window->source_event_masks);

510 511
  if (window->devices_inside)
    g_list_free (window->devices_inside);
512

513
  G_OBJECT_CLASS (parent_class)->finalize (object);
Elliot Lee's avatar
Elliot Lee committed
514 515
}

Cody Russell's avatar
Cody Russell committed
516 517 518 519 520 521 522 523 524 525 526
static void
gdk_window_set_property (GObject      *object,
                         guint         prop_id,
                         const GValue *value,
                         GParamSpec   *pspec)
{
  GdkWindow *window = (GdkWindow *)object;

  switch (prop_id)
    {
    case PROP_CURSOR:
Benjamin Otte's avatar
Benjamin Otte committed
527
      gdk_window_set_cursor (window, g_value_get_object (value));
Cody Russell's avatar
Cody Russell committed
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
      break;

    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)
{
  GdkWindow *window = (GdkWindow *) object;

  switch (prop_id)
    {
    case PROP_CURSOR:
Benjamin Otte's avatar
Benjamin Otte committed
547
      g_value_set_object (value, gdk_window_get_cursor (window));
Cody Russell's avatar
Cody Russell committed
548 549 550 551 552 553 554 555
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

556
static gboolean
557
gdk_window_is_offscreen (GdkWindow *window)
558
{
559
  return window->window_type == GDK_WINDOW_OFFSCREEN;
560 561
}

562 563
static GdkWindow *
gdk_window_get_impl_window (GdkWindow *window)
564
{
565
  return window->impl_window;
566 567 568 569 570
}

GdkWindow *
_gdk_window_get_impl_window (GdkWindow *window)
{
571
  return gdk_window_get_impl_window (window);
572 573 574
}

static gboolean
575
gdk_window_has_impl (GdkWindow *window)
576
{
577
  return window->impl_window == window;
578 579
}

580
static gboolean
581
gdk_window_is_toplevel (GdkWindow *window)
582 583 584 585 586 587
{
  return
    window->parent == NULL ||
    window->parent->window_type == GDK_WINDOW_ROOT;
}

588 589 590
gboolean
_gdk_window_has_impl (GdkWindow *window)
{
591
  return gdk_window_has_impl (window);
592 593 594
}

static gboolean
595
gdk_window_has_no_impl (GdkWindow *window)
596
{
597
  return window->impl_window != window;
598 599 600
}

static void
601 602
remove_sibling_overlapped_area (GdkWindow *window,
				cairo_region_t *region)
603
{
604 605
  GdkWindow *parent;
  GdkWindow *sibling;
606 607 608
  cairo_region_t *child_region;
  GdkRectangle r;
  GList *l;
609
  cairo_region_t *shape;
610

611 612
  parent = window->parent;

613
  if (gdk_window_is_toplevel (window))
614 615 616 617 618 619
    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)
620
    {
621
      sibling = l->data;
622

623
      if (sibling == window)
624 625
	break;

626
      if (!GDK_WINDOW_IS_MAPPED (sibling) || sibling->input_only || sibling->composited)
627 628 629 630
	continue;

      /* Ignore offscreen children, as they don't draw in their parent and
       * don't take part in the clipping */
631
      if (gdk_window_is_offscreen (sibling))
632 633
	continue;

634 635 636 637
      r.x = sibling->x;
      r.y = sibling->y;
      r.width = sibling->width;
      r.height = sibling->height;
638 639

      child_region = cairo_region_create_rectangle (&r);
640 641

      if (sibling->shape)
642 643
	{
	  /* Adjust shape region to parent window coords */
644 645 646 647 648 649 650 651 652 653 654 655
	  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);
	}
      else if (window->window_type == GDK_WINDOW_FOREIGN)
	{
	  shape = GDK_WINDOW_IMPL_GET_CLASS (sibling)->get_shape (sibling);
	  if (shape)
	    {
	      cairo_region_intersect (child_region, shape);
	      cairo_region_destroy (shape);
	    }
656 657 658 659 660
	}

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

662 663
  remove_sibling_overlapped_area (parent, region);

664 665
  /* Convert back to window coords */
  cairo_region_translate (region, -window->x, -window->y);
666 667 668 669
}

static void
remove_child_area (GdkWindow *window,
Alexander Larsson's avatar
Alexander Larsson committed
670
		   gboolean for_input,
671
		   cairo_region_t *region)
672
{
673
  GdkWindow *child;
674
  cairo_region_t *child_region;
675 676
  GdkRectangle r;
  GList *l;
677
  cairo_region_t *shape;
678

679
  for (l = window->children; l; l = l->next)
680 681 682
    {
      child = l->data;

683 684
      /* If region is empty already, no need to do
	 anything potentially costly */
Benjamin Otte's avatar
Benjamin Otte committed
685
      if (cairo_region_is_empty (region))
686 687
	break;

688
      if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
689 690 691 692 693 694 695 696 697 698 699
	continue;

      /* Ignore offscreen children, as they don't draw in their parent and
       * don't take part in the clipping */
      if (gdk_window_is_offscreen (child))
	continue;

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

701
      /* Bail early if child totally outside region */
Benjamin Otte's avatar
Benjamin Otte committed
702
      if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
703 704
	continue;

Benjamin Otte's avatar
Benjamin Otte committed
705
      child_region = cairo_region_create_rectangle (&r);
706

Alexander Larsson's avatar
Alexander Larsson committed
707
      if (child->shape)
708 709
	{
	  /* Adjust shape region to parent window coords */
Benjamin Otte's avatar
Benjamin Otte committed
710 711 712
	  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);
713
	}
714
      else if (window->window_type == GDK_WINDOW_FOREIGN)
Alexander Larsson's avatar
Alexander Larsson committed
715
	{
716
	  shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_shape (child);
Alexander Larsson's avatar
Alexander Larsson committed
717 718
	  if (shape)
	    {
Benjamin Otte's avatar
Benjamin Otte committed
719 720
	      cairo_region_intersect (child_region, shape);
	      cairo_region_destroy (shape);
Alexander Larsson's avatar
Alexander Larsson committed
721 722
	    }
	}
Alexander Larsson's avatar
Alexander Larsson committed
723 724 725 726

      if (for_input)
	{
	  if (child->input_shape)
Benjamin Otte's avatar
Benjamin Otte committed
727
	    cairo_region_intersect (child_region, child->input_shape);
728
	  else if (window->window_type == GDK_WINDOW_FOREIGN)
Alexander Larsson's avatar
Alexander Larsson committed
729
	    {
730
	      shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_input_shape (child);
Alexander Larsson's avatar
Alexander Larsson committed
731 732
	      if (shape)
		{
Benjamin Otte's avatar
Benjamin Otte committed
733 734
		  cairo_region_intersect (child_region, shape);
		  cairo_region_destroy (shape);
Alexander Larsson's avatar
Alexander Larsson committed
735 736 737
		}
	    }
	}
738

739
      cairo_region_subtract (region, child_region);
Benjamin Otte's avatar
Benjamin Otte committed
740
      cairo_region_destroy (child_region);
741 742 743
    }
}

744
static GdkVisibilityState
745
effective_visibility (GdkWindow *window)
746 747 748
{
  GdkVisibilityState native;

749
  if (!gdk_window_is_viewable (window))
750 751
    return GDK_VISIBILITY_NOT_VIEWABLE;

752
  native = window->impl_window->native_visibility;
753 754

  if (native == GDK_VISIBILITY_FULLY_OBSCURED ||
755
      window->visibility == GDK_VISIBILITY_FULLY_OBSCURED)
756 757
    return GDK_VISIBILITY_FULLY_OBSCURED;
  else if (native == GDK_VISIBILITY_UNOBSCURED)
758
    return window->visibility;
759 760 761 762 763
  else /* native PARTIAL, private partial or unobscured  */
    return GDK_VISIBILITY_PARTIAL;
}

static void
764
gdk_window_update_visibility (GdkWindow *window)
765 766 767 768
{
  GdkVisibilityState new_visibility;
  GdkEvent *event;

769
  new_visibility = effective_visibility (window);
770

771
  if (new_visibility != window->effective_visibility)
772
    {
773
      window->effective_visibility = new_visibility;
774 775

      if (new_visibility != GDK_VISIBILITY_NOT_VIEWABLE &&
776
	  window->event_mask & GDK_VISIBILITY_NOTIFY_MASK)
777
	{
778
	  event = _gdk_make_event (window, GDK_VISIBILITY_NOTIFY,
779 780 781 782 783 784 785
				   NULL, FALSE);
	  event->visibility.state = new_visibility;
	}
    }
}

static void
786 787
gdk_window_update_visibility_recursively (GdkWindow *window,
					  GdkWindow *only_for_impl)
788
{
789
  GdkWindow *child;
790 791
  GList *l;

792 793
  gdk_window_update_visibility (window);
  for (l = window->children; l != NULL; l = l->next)
794 795 796 797 798 799 800 801
    {
      child = l->data;
      if ((only_for_impl == NULL) ||
	  (only_for_impl == child->impl_window))
	gdk_window_update_visibility_recursively (child, only_for_impl);
    }
}

Alexander Larsson's avatar
Alexander Larsson committed
802
static gboolean
803
should_apply_clip_as_shape (GdkWindow *window)
Alexander Larsson's avatar
Alexander Larsson committed
804 805
{
  return
806
    gdk_window_has_impl (window) &&
Alexander Larsson's avatar
Alexander Larsson committed
807
    /* Not for offscreens */
808
    !gdk_window_is_offscreen (window) &&
Alexander Larsson's avatar
Alexander Larsson committed
809 810 811
    /* or for non-shaped toplevels */
    (!gdk_window_is_toplevel (window) ||
     window->shape != NULL || window->applied_shape) &&
Alexander Larsson's avatar
Alexander Larsson committed
812
    /* or for foreign windows */
813
    window->window_type != GDK_WINDOW_FOREIGN &&
Alexander Larsson's avatar
Alexander Larsson committed
814
    /* or for the root window */
815
    window->window_type != GDK_WINDOW_ROOT;
Alexander Larsson's avatar
Alexander Larsson committed
816 817 818
}

static void
819
apply_shape (GdkWindow *window,
820
	     cairo_region_t *region)
Alexander Larsson's avatar
Alexander Larsson committed
821
{
822
  GdkWindowImplClass *impl_class;
Alexander Larsson's avatar
Alexander Larsson committed
823 824 825 826 827

  /* 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 */
828
  impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
Alexander Larsson's avatar
Alexander Larsson committed
829
  if (region)
830
    impl_class->shape_combine_region (window,
Alexander Larsson's avatar
Alexander Larsson committed
831
				      region, 0, 0);
832 833
  else if (window->applied_shape)
    impl_class->shape_combine_region (window,
Alexander Larsson's avatar
Alexander Larsson committed
834 835
				      NULL, 0, 0);

836
  window->applied_shape = region != NULL;
Alexander Larsson's avatar
Alexander Larsson committed
837 838
}

Benjamin Otte's avatar
Benjamin Otte committed
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
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
856
static void
857
apply_clip_as_shape (GdkWindow *window)
Alexander Larsson's avatar
Alexander Larsson committed
858 859
{
  GdkRectangle r;
860
  cairo_region_t *region;
Alexander Larsson's avatar
Alexander Larsson committed
861 862

  r.x = r.y = 0;
863 864
  r.width = window->width;
  r.height = window->height;
Alexander Larsson's avatar
Alexander Larsson committed
865

866
  region = cairo_region_copy (window->clip_region);
867
  remove_sibling_overlapped_area (window, region);
868

Alexander Larsson's avatar
Alexander Larsson committed
869 870 871 872
  /* 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 */
873 874
  if (!region_rect_equal (region, &r))
    apply_shape (window, region);
Alexander Larsson's avatar
Alexander Larsson committed
875
  else
876
    apply_shape (window, NULL);
877 878

  cairo_region_destroy (region);
Alexander Larsson's avatar
Alexander Larsson committed
879 880
}

881
static void
882 883 884
recompute_visible_regions_internal (GdkWindow *private,
				    gboolean   recalculate_clip,
				    gboolean   recalculate_children)
885 886 887
{
  GdkRectangle r;
  GList *l;
888
  GdkWindow *child;
889
  cairo_region_t *new_clip;
890 891 892 893 894 895
  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;
896

897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915
  /* Update absolute position */
  if (gdk_window_has_impl (private))
    {
      /* Native window starts here */
      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
916
   * window size/position
917 918
   */
  clip_region_changed = FALSE;
919
  if (recalculate_clip)
920
    {
921
      if (private->viewable)
922
	{
923 924 925 926 927
	  /* 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
928
	  new_clip = cairo_region_create_rectangle (&r);
929

930
	  if (!gdk_window_is_toplevel (private))
931
	    cairo_region_intersect (new_clip, private->parent->clip_region);
932

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

936
	  if (should_apply_clip_as_shape (private) && private->shape)
Benjamin Otte's avatar
Benjamin Otte committed
937
	    cairo_region_intersect (new_clip, private->shape);
938 939
	}
      else
940
	  new_clip = cairo_region_create ();
Alexander Larsson's avatar
Alexander Larsson committed
941

942
      if (private->clip_region == NULL ||
Benjamin Otte's avatar
Benjamin Otte committed
943
	  !cairo_region_equal (private->clip_region, new_clip))
944
	clip_region_changed = TRUE;
945

946
      if (private->clip_region)
Benjamin Otte's avatar
Benjamin Otte committed
947
	cairo_region_destroy (private->clip_region);
948 949 950
      private->clip_region = new_clip;
    }

951 952 953 954 955
  if (clip_region_changed)
    {
      GdkVisibilityState visibility;
      gboolean fully_visible;

Benjamin Otte's avatar
Benjamin Otte committed
956
      if (cairo_region_is_empty (private->clip_region))