gdkwindow.c 346 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"
Emmanuele Bassi's avatar
Emmanuele Bassi committed
43
#include "gdkdrawingcontextprivate.h"
44
#include "gdk-private.h"
45

46 47
#include <math.h>

48 49
#include <epoxy/gl.h>

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

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

57 58 59
#undef DEBUG_WINDOW_PRINTING


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

100

101 102 103 104
/* 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
105
 * object available as “impl” in the window object.
106
 *
107 108 109
 * 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
110
 * window. Instead windows that are “client side” are emulated by the gdk
111 112
 * code such that clipping, drawing, moving, events etc work as expected.
 *
William Jon McCann's avatar
William Jon McCann committed
113
 * For GdkWindows that have a native window the “impl” object is the
114 115 116 117 118 119 120
 * 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
121 122
 * windows). Such windows work by allocating a #cairo_surface_t as the backing
 * store for drawing operations, which is resized with the window.
123
 *
William Jon McCann's avatar
William Jon McCann committed
124 125
 * 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
126 127 128 129 130
 * 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
131
 * region of the window wrt parent windows, in window-relative coordinates (clip_region).
132 133 134 135 136 137 138 139 140
 *
 * 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.
141
 */
142

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

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

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

160
/* Global info */
161

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

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

173
static void gdk_window_clear_backing_region (GdkWindow *window);
174

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

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

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


199
static guint signals[LAST_SIGNAL] = { 0 };
200
static GParamSpec *properties[LAST_PROP] = { NULL, };
201

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

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

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
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;

271 272 273
      if (link->prev)
        link->prev->next = link;

274 275 276 277
      return list;
    }
}

278
static void
279
gdk_window_init (GdkWindow *window)
280 281
{
  /* 0-initialization is good for all other fields. */
rhlabs's avatar
rhlabs committed
282

283
  window->window_type = GDK_WINDOW_CHILD;
Elliot Lee's avatar
Elliot Lee committed
284

Havoc Pennington's avatar
Havoc Pennington committed
285
  window->state = GDK_WINDOW_STATE_WITHDRAWN;
286
  window->fullscreen_mode = GDK_FULLSCREEN_ON_CURRENT_MONITOR;
287 288 289
  window->width = 1;
  window->height = 1;
  window->toplevel_window_type = -1;
290 291 292 293 294
  /* 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;
295
  window->children_list_node.data = window;
296 297 298

  window->device_cursor = g_hash_table_new_full (NULL, NULL,
                                                 NULL, g_object_unref);
299
}
300

301
/* Stop and return on the first non-NULL parent */
302
static gboolean
303 304 305 306
accumulate_get_window (GSignalInvocationHint *ihint,
		       GValue		       *return_accu,
		       const GValue	       *handler_return,
		       gpointer               data)
307 308 309
{
  g_value_copy (handler_return, return_accu);
  /* Continue while returning NULL */
310
  return g_value_get_object (handler_return) == NULL;
311 312
}

313 314 315 316 317 318 319 320 321 322 323 324
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;
}

325 326
static GQuark quark_pointer_window = 0;

327
static void
328
gdk_window_class_init (GdkWindowClass *klass)
329 330
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
331

332
  object_class->finalize = gdk_window_finalize;
Cody Russell's avatar
Cody Russell committed
333 334
  object_class->set_property = gdk_window_set_property;
  object_class->get_property = gdk_window_get_property;
335

336 337
  klass->create_surface = _gdk_offscreen_window_create_surface;

338
  quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window");
339 340


Cody Russell's avatar
Cody Russell committed
341
  /* Properties */
342 343 344 345 346 347 348 349 350

  /**
   * GdkWindow:cursor:
   *
   * The mouse pointer for a #GdkWindow. See gdk_window_set_cursor() and
   * gdk_window_get_cursor() for details.
   *
   * Since: 2.18
   */
351 352 353 354 355 356 357
  properties[PROP_CURSOR] =
      g_param_spec_object ("cursor",
                           P_("Cursor"),
                           P_("Cursor"),
                           GDK_TYPE_CURSOR,
                           G_PARAM_READWRITE);
  g_object_class_install_properties (object_class, LAST_PROP, properties);
Cody Russell's avatar
Cody Russell committed
358

Matthias Clasen's avatar
Matthias Clasen committed
359 360 361 362 363 364 365 366 367
  /**
   * 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.
   *
368 369
   * Returns: (nullable) (transfer none): the #GdkWindow of the
   *     embedded child at @x, @y, or %NULL
Matthias Clasen's avatar
Matthias Clasen committed
370 371 372
   *
   * Since: 2.18
   */
Alexander Larsson's avatar
Alexander Larsson committed
373 374
  signals[PICK_EMBEDDED_CHILD] =
    g_signal_new (g_intern_static_string ("pick-embedded-child"),
375 376
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
377
                  G_STRUCT_OFFSET (GdkWindowClass, pick_embedded_child),
378
		  accumulate_get_window, NULL,
Matthias Clasen's avatar
Matthias Clasen committed
379
		  _gdk_marshal_OBJECT__DOUBLE_DOUBLE,
380 381 382 383
		  GDK_TYPE_WINDOW,
		  2,
		  G_TYPE_DOUBLE,
		  G_TYPE_DOUBLE);
Matthias Clasen's avatar
Matthias Clasen committed
384 385 386 387

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

  /**
   * GdkWindow::from-embedder:
   * @window: the offscreen window on which the signal is emitted
419 420 421
   * @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
422
   *     coordinate in the offscreen window
423
   * @offscreen_y: (out) (type double): return location for the y
424
   *     coordinate in the offscreen window
Matthias Clasen's avatar
Matthias Clasen committed
425 426 427 428
   *
   * The ::from-embedder signal is emitted to translate coordinates
   * in the embedder of an offscreen window to the offscreen window.
   *
429
   * See also #GdkWindow::to-embedder.
Matthias Clasen's avatar
Matthias Clasen committed
430
   *
Matthias Clasen's avatar
Matthias Clasen committed
431 432
   * Since: 2.18
   */
Alexander Larsson's avatar
Alexander Larsson committed
433 434
  signals[FROM_EMBEDDER] =
    g_signal_new (g_intern_static_string ("from-embedder"),
435 436
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
437
                  G_STRUCT_OFFSET (GdkWindowClass, from_embedder),
438
		  NULL, NULL,
Matthias Clasen's avatar
Matthias Clasen committed
439
		  _gdk_marshal_VOID__DOUBLE_DOUBLE_POINTER_POINTER,
440 441 442 443 444 445
		  G_TYPE_NONE,
		  4,
		  G_TYPE_DOUBLE,
		  G_TYPE_DOUBLE,
		  G_TYPE_POINTER,
		  G_TYPE_POINTER);
446 447 448 449 450 451 452 453

  /**
   * 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
454
   * needs its surface (re)created, which happens either when the
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
   * 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,
472
                  G_STRUCT_OFFSET (GdkWindowClass, create_surface),
473 474 475 476 477 478
                  create_surface_accumulator, NULL,
                  _gdk_marshal_BOXED__INT_INT,
                  CAIRO_GOBJECT_TYPE_SURFACE,
                  2,
                  G_TYPE_INT,
                  G_TYPE_INT);
479
}
480

481
static void
482 483 484
seat_removed_cb (GdkDisplay *display,
                 GdkSeat    *seat,
                 GdkWindow  *window)
485
{
486 487
  GdkDevice *device = gdk_seat_get_pointer (seat);

488 489
  window->devices_inside = g_list_remove (window->devices_inside, device);
  g_hash_table_remove (window->device_cursor, device);
490

491 492
  if (window->device_events)
    g_hash_table_remove (window->device_events, device);
493 494
}

495 496 497 498
static void
gdk_window_finalize (GObject *object)
{
  GdkWindow *window = GDK_WINDOW (object);
499

500 501
  g_signal_handlers_disconnect_by_func (gdk_window_get_display (window),
                                        seat_removed_cb, window);
502

503 504 505 506
  if (!GDK_WINDOW_DESTROYED (window))
    {
      if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
	{
507
	  g_warning ("losing last reference to undestroyed window");
508 509 510 511 512 513 514 515
	  _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);
    }
516

517
  if (window->impl)
518
    {
519 520
      g_object_unref (window->impl);
      window->impl = NULL;
521 522
    }

523
  if (window->impl_window != window)
524
    {
525 526
      g_object_unref (window->impl_window);
      window->impl_window = NULL;
527
    }
528

529 530
  if (window->shape)
    cairo_region_destroy (window->shape);
Alexander Larsson's avatar
Alexander Larsson committed
531

532 533
  if (window->input_shape)
    cairo_region_destroy (window->input_shape);
Alexander Larsson's avatar
Alexander Larsson committed
534

535
  if (window->cursor)
536
    g_object_unref (window->cursor);
537

538 539
  if (window->device_cursor)
    g_hash_table_destroy (window->device_cursor);
540

541 542
  if (window->device_events)
    g_hash_table_destroy (window->device_events);
543

544 545 546
  if (window->source_event_masks)
    g_hash_table_destroy (window->source_event_masks);

547 548
  if (window->devices_inside)
    g_list_free (window->devices_inside);
549

550
  G_OBJECT_CLASS (gdk_window_parent_class)->finalize (object);
Elliot Lee's avatar
Elliot Lee committed
551 552
}

Cody Russell's avatar
Cody Russell committed
553 554 555 556 557 558 559 560 561 562 563
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
564
      gdk_window_set_cursor (window, g_value_get_object (value));
Cody Russell's avatar
Cody Russell committed
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
      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
584
      g_value_set_object (value, gdk_window_get_cursor (window));
Cody Russell's avatar
Cody Russell committed
585 586 587 588 589 590 591 592
      break;

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

593
static gboolean
594
gdk_window_is_offscreen (GdkWindow *window)
595
{
596
  return window->window_type == GDK_WINDOW_OFFSCREEN;
597 598
}

599 600
static GdkWindow *
gdk_window_get_impl_window (GdkWindow *window)
601
{
602
  return window->impl_window;
603 604 605 606 607
}

GdkWindow *
_gdk_window_get_impl_window (GdkWindow *window)
{
608
  return gdk_window_get_impl_window (window);
609 610 611
}

static gboolean
612
gdk_window_has_impl (GdkWindow *window)
613
{
614
  return window->impl_window == window;
615 616
}

617
static gboolean
618
gdk_window_is_toplevel (GdkWindow *window)
619 620 621 622 623 624
{
  return
    window->parent == NULL ||
    window->parent->window_type == GDK_WINDOW_ROOT;
}

625 626 627
gboolean
_gdk_window_has_impl (GdkWindow *window)
{
628
  return gdk_window_has_impl (window);
629 630 631
}

static gboolean
632
gdk_window_has_no_impl (GdkWindow *window)
633
{
634
  return window->impl_window != window;
635 636 637
}

static void
638 639
remove_sibling_overlapped_area (GdkWindow *window,
				cairo_region_t *region)
640
{
641 642
  GdkWindow *parent;
  GdkWindow *sibling;
643 644 645
  cairo_region_t *child_region;
  GdkRectangle r;
  GList *l;
646
  cairo_region_t *shape;
647

648 649
  parent = window->parent;

650
  if (gdk_window_is_toplevel (window))
651 652 653 654 655 656
    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)
657
    {
658
      sibling = l->data;
659

660
      if (sibling == window)
661 662
	break;

663
      if (!GDK_WINDOW_IS_MAPPED (sibling) || sibling->input_only || sibling->composited)
664 665 666 667
	continue;

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

671 672 673 674
      r.x = sibling->x;
      r.y = sibling->y;
      r.width = sibling->width;
      r.height = sibling->height;
675 676

      child_region = cairo_region_create_rectangle (&r);
677 678

      if (sibling->shape)
679 680
	{
	  /* Adjust shape region to parent window coords */
681 682 683 684 685 686 687 688 689 690 691 692
	  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);
	    }
693 694 695 696 697
	}

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

699 700
  remove_sibling_overlapped_area (parent, region);

701 702
  /* Convert back to window coords */
  cairo_region_translate (region, -window->x, -window->y);
703 704 705 706
}

static void
remove_child_area (GdkWindow *window,
Alexander Larsson's avatar
Alexander Larsson committed
707
		   gboolean for_input,
708
		   cairo_region_t *region)
709
{
710
  GdkWindow *child;
711
  cairo_region_t *child_region;
712 713
  GdkRectangle r;
  GList *l;
714
  cairo_region_t *shape;
715

716
  for (l = window->children; l; l = l->next)
717 718 719
    {
      child = l->data;

720 721
      /* If region is empty already, no need to do
	 anything potentially costly */
Benjamin Otte's avatar
Benjamin Otte committed
722
      if (cairo_region_is_empty (region))
723 724
	break;

725
      if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
726 727 728 729 730 731 732 733 734 735 736
	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
737

738
      /* Bail early if child totally outside region */
Benjamin Otte's avatar
Benjamin Otte committed
739
      if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
740 741
	continue;

Benjamin Otte's avatar
Benjamin Otte committed
742
      child_region = cairo_region_create_rectangle (&r);
743

Alexander Larsson's avatar
Alexander Larsson committed
744
      if (child->shape)
745 746
	{
	  /* Adjust shape region to parent window coords */
Benjamin Otte's avatar
Benjamin Otte committed
747 748 749
	  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);
750
	}
751
      else if (window->window_type == GDK_WINDOW_FOREIGN)
Alexander Larsson's avatar
Alexander Larsson committed
752
	{
753
	  shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_shape (child);
Alexander Larsson's avatar
Alexander Larsson committed
754 755
	  if (shape)
	    {
Benjamin Otte's avatar
Benjamin Otte committed
756 757
	      cairo_region_intersect (child_region, shape);
	      cairo_region_destroy (shape);
Alexander Larsson's avatar
Alexander Larsson committed
758 759
	    }
	}
Alexander Larsson's avatar
Alexander Larsson committed
760 761 762 763

      if (for_input)
	{
	  if (child->input_shape)
Benjamin Otte's avatar
Benjamin Otte committed
764
	    cairo_region_intersect (child_region, child->input_shape);
765
	  else if (window->window_type == GDK_WINDOW_FOREIGN)
Alexander Larsson's avatar
Alexander Larsson committed
766
	    {
767
	      shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_input_shape (child);
Alexander Larsson's avatar
Alexander Larsson committed
768 769
	      if (shape)
		{
Benjamin Otte's avatar
Benjamin Otte committed
770 771
		  cairo_region_intersect (child_region, shape);
		  cairo_region_destroy (shape);
Alexander Larsson's avatar
Alexander Larsson committed
772 773 774
		}
	    }
	}
775

776
      cairo_region_subtract (region, child_region);
Benjamin Otte's avatar
Benjamin Otte committed
777
      cairo_region_destroy (child_region);
778 779 780
    }
}

781
static GdkVisibilityState
782
effective_visibility (GdkWindow *window)
783 784 785
{
  GdkVisibilityState native;

786
  if (!gdk_window_is_viewable (window))
787 788
    return GDK_VISIBILITY_NOT_VIEWABLE;

789
  native = window->impl_window->native_visibility;
790 791

  if (native == GDK_VISIBILITY_FULLY_OBSCURED ||
792
      window->visibility == GDK_VISIBILITY_FULLY_OBSCURED)
793 794
    return GDK_VISIBILITY_FULLY_OBSCURED;
  else if (native == GDK_VISIBILITY_UNOBSCURED)
795
    return window->visibility;
796 797 798 799 800
  else /* native PARTIAL, private partial or unobscured  */
    return GDK_VISIBILITY_PARTIAL;
}

static void
801
gdk_window_update_visibility (GdkWindow *window)
802 803 804 805
{
  GdkVisibilityState new_visibility;
  GdkEvent *event;

806
  new_visibility = effective_visibility (window);
807

808
  if (new_visibility != window->effective_visibility)
809
    {
810
      window->effective_visibility = new_visibility;
811 812

      if (new_visibility != GDK_VISIBILITY_NOT_VIEWABLE &&
813
	  window->event_mask & GDK_VISIBILITY_NOTIFY_MASK)
814
	{
815
	  event = _gdk_make_event (window, GDK_VISIBILITY_NOTIFY,
816 817 818 819 820 821 822
				   NULL, FALSE);
	  event->visibility.state = new_visibility;
	}
    }
}

static void
823 824
gdk_window_update_visibility_recursively (GdkWindow *window,
					  GdkWindow *only_for_impl)
825
{
826
  GdkWindow *child;
827 828
  GList *l;

829 830
  gdk_window_update_visibility (window);
  for (l = window->children; l != NULL; l = l->next)
831 832 833 834 835 836 837 838
    {
      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
839
static gboolean
840
should_apply_clip_as_shape (GdkWindow *window)
Alexander Larsson's avatar
Alexander Larsson committed
841 842
{
  return
843
    gdk_window_has_impl (window) &&
Alexander Larsson's avatar
Alexander Larsson committed
844
    /* Not for offscreens */
845
    !gdk_window_is_offscreen (window) &&
Alexander Larsson's avatar
Alexander Larsson committed
846 847 848
    /* or for non-shaped toplevels */
    (!gdk_window_is_toplevel (window) ||
     window->shape != NULL || window->applied_shape) &&
Alexander Larsson's avatar
Alexander Larsson committed
849
    /* or for foreign windows */
850
    window->window_type != GDK_WINDOW_FOREIGN &&
Alexander Larsson's avatar
Alexander Larsson committed
851
    /* or for the root window */
852
    window->window_type != GDK_WINDOW_ROOT;
Alexander Larsson's avatar
Alexander Larsson committed
853 854 855
}

static void
856
apply_shape (GdkWindow *window,
857
	     cairo_region_t *region)
Alexander Larsson's avatar
Alexander Larsson committed
858
{
859
  GdkWindowImplClass *impl_class;
Alexander Larsson's avatar
Alexander Larsson committed
860 861 862 863 864

  /* 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 */
865
  impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
Alexander Larsson's avatar
Alexander Larsson committed
866
  if (region)
867
    impl_class->shape_combine_region (window,
Alexander Larsson's avatar
Alexander Larsson committed
868
				      region, 0, 0);
869 870
  else if (window->applied_shape)
    impl_class->shape_combine_region (window,
Alexander Larsson's avatar
Alexander Larsson committed
871 872
				      NULL, 0, 0);

873
  window->applied_shape = region != NULL;
Alexander Larsson's avatar
Alexander Larsson committed
874 875
}

Benjamin Otte's avatar
Benjamin Otte committed
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
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;
}