gdkwindow.c 319 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
16 17 18
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
19
 */
20

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

28 29
#include "config.h"

30 31
#include <cairo-gobject.h>

32 33
#include "gdkwindow.h"

34
#include "gdkrectangle.h"
35 36
#include "gdkinternals.h"
#include "gdkintl.h"
Matthias Clasen's avatar
Matthias Clasen committed
37 38
#include "gdkscreenprivate.h"
#include "gdkdisplayprivate.h"
39
#include "gdkdeviceprivate.h"
40
#include "gdkvisualprivate.h"
41 42 43
#include "gdkmarshalers.h"
#include "gdkwindowimpl.h"

44 45
#include <math.h>

46 47 48
#undef DEBUG_WINDOW_PRINTING


49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
/**
 * SECTION:windows
 * @Short_description: Onscreen display areas in the target window system
 * @Title: Windows
 *
 * A #GdkWindow is a rectangular region on the screen. It's a low-level object,
 * used to implement high-level objects such as #GtkWidget and #GtkWindow on the
 * GTK+ level. A #GtkWindow is a toplevel window, the thing a user might think
 * of as a "window" with a titlebar and so on; a #GtkWindow may contain many
 * #GdkWindow<!-- -->s. For example, each #GtkButton has a #GdkWindow associated
 * with it.
 *
 * <refsect2 id="COMPOSITED-WINDOWS">
 * <title>Composited Windows</title>
 * <para>
 * Normally, the windowing system takes care of rendering the contents of a
 * child window onto its parent window. This mechanism can be intercepted by
 * calling gdk_window_set_composited() on the child window. For a
 * <firstterm>composited</firstterm> window it is the responsibility of the
 * application to render the window contents at the right spot.
 * </para>
 * <example id="composited-window-example">
 * <title>Composited windows</title>
 * <programlisting>
 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../examples/gdk/composited-window-example.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include>
 * </programlisting></example>
 * <para>
 * In the example <xref linkend="composited-window-example"/>, a button is
 * placed inside of an event box inside of a window. The event box is set as
 * composited and therefore is no longer automatically drawn to the screen.
 *
 * When the contents of the event box change, an expose event is generated on
 * it's parent window (which, in this case, belongs to the toplevel #GtkWindow).
 * The expose handler for this widget is responsible for merging the changes
 * back on the screen in the way that it wishes.
 *
 * In our case, we merge the contents with a 50% transparency. We also set the
 * background colour of the window to red. The effect is that the background
 * shows through the button.
 * </para>
 * </refsect2>
 * <refsect2 id="OFFSCREEN-WINDOWS">
 * <title>Offscreen Windows</title>
 * <para>
 * Offscreen windows are more general than composited windows, since they allow
 * not only to modify the rendering of the child window onto its parent, but
 * also to apply coordinate transformations.
 *
 * 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
106 107
 * offscreen window are available as a surface, via
 * gdk_offscreen_window_get_surface().
108 109 110 111
 * </para>
 * </refsect2>
 */

112

113 114 115 116 117
/* 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
 * object availible as "impl" in the window object.
118
 *
119 120 121 122 123 124 125 126 127 128 129 130 131 132
 * 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
 * window. Instead windows that are "client side" are emulated by the gdk
 * code such that clipping, drawing, moving, events etc work as expected.
 *
 * For GdkWindows that have a native window the "impl" object is the
 * 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
133 134
 * windows). Such windows work by allocating a #cairo_surface_t as the backing
 * store for drawing operations, which is resized with the window.
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
 *
 * 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
 * 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
 * region of the window wrt parent windows and siblings, in window-relative
 * coordinates with and without child windows included (clip_region,
 * clip_region_with_children).
 *
 * 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.
 *
 * In order to minimize flicker and for performance we use a couple of cacheing
 * tricks. First of all, every time we do a window to window copy area, for instance
 * when moving a client side window or when scrolling/moving a region in a window
 * we store this in outstanding_moves instead of applying immediately. We then
 * delay this move until we really need it (because something depends on being
 * able to read it), or until we're handing a redraw from an expose/invalidation
162
 * (actually we delay it past redraw, but before blitting the double buffer
163 164 165 166 167 168 169 170 171 172
 * to the window). This gives us two advantages. First of all it minimizes the time
 * from the window is moved to the exposes related to that move, secondly it allows
 * us to be smart about how to do the copy. We combine multiple moves into one (when
 * possible) and we don't actually do copies to anything that is or will be
 * invalidated and exposed anyway.
 *
 * Secondly, we use something called a "implicit paint" during repaint handling.
 * An implicit paint is similar to a regular paint for the paint stack, but it is
 * not put on the stack. Instead, it is set on the impl window, and later when
 * regular gdk_window_begin_paint_region()  happen on a window of this impl window
173
 * we reuse the surface from the implicit paint. During repaint we create and at the
174
 * end flush an implicit paint, which means we can collect all the paints on
175
 * multiple client side windows in the same backing store.
176
 */
177

178
#define USE_BACKING_STORE	/* Appears to work on Win32, too, now. */
179

180 181 182
/* This adds a local value to the GdkVisibilityState enum */
#define GDK_VISIBILITY_NOT_VIEWABLE 3

183
enum {
Alexander Larsson's avatar
Alexander Larsson committed
184 185 186
  PICK_EMBEDDED_CHILD, /* only called if children are embedded */
  TO_EMBEDDER,
  FROM_EMBEDDER,
187
  CREATE_SURFACE,
188 189 190
  LAST_SIGNAL
};

Cody Russell's avatar
Cody Russell committed
191 192 193 194 195
enum {
  PROP_0,
  PROP_CURSOR
};

196 197 198 199 200 201
typedef enum {
  CLEAR_BG_NONE,
  CLEAR_BG_WINCLEARED, /* Clear backgrounds except those that the window system clears */
  CLEAR_BG_ALL
} ClearBg;

202 203
struct _GdkWindowPaint
{
204
  cairo_region_t *region;
205
  cairo_surface_t *surface;
206
  guint uses_implicit : 1;
207
  guint flushed : 1;
208
  guint32 region_tag;
209
};
210

211
typedef struct {
212
  cairo_region_t *dest_region; /* The destination region */
213
  int dx, dy; /* The amount that the source was moved to reach dest_region */
214 215
} GdkWindowRegionMove;

216
/* Global info */
217

218
static void             gdk_window_drop_cairo_surface (GdkWindow *private);
219

Owen Taylor's avatar
Owen Taylor committed
220
static void gdk_window_free_paint_stack (GdkWindow *window);
221

222
static void gdk_window_init       (GdkWindow            *window);
223
static void gdk_window_class_init (GdkWindowClass *klass);
224
static void gdk_window_finalize   (GObject              *object);
Cody Russell's avatar
Cody Russell committed
225 226 227 228 229 230 231 232 233 234

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

235
static void gdk_window_clear_backing_region (GdkWindow *window,
236
					     cairo_region_t *region);
237

238
static void recompute_visible_regions   (GdkWindow *private,
239 240
					 gboolean recalculate_siblings,
					 gboolean recalculate_children);
241
static void gdk_window_flush_outstanding_moves (GdkWindow *window);
242 243
static void gdk_window_flush_recursive  (GdkWindow *window);
static void do_move_region_bits_on_impl (GdkWindow *window,
244
					 cairo_region_t *region, /* In impl window coords */
245
					 int dx, int dy);
246 247
static void gdk_window_invalidate_in_parent (GdkWindow *private);
static void move_native_children        (GdkWindow *private);
248 249
static void update_cursor               (GdkDisplay *display,
                                         GdkDevice  *device);
250
static void impl_window_add_update_area (GdkWindow *impl_window,
251
					 cairo_region_t *region);
252
static void gdk_window_region_move_free (GdkWindowRegionMove *move);
253
static void gdk_window_invalidate_region_full (GdkWindow       *window,
254
					       const cairo_region_t *region,
255 256 257 258 259 260
					       gboolean         invalidate_children,
					       ClearBg          clear_bg);
static void gdk_window_invalidate_rect_full (GdkWindow          *window,
					     const GdkRectangle *rect,
					     gboolean            invalidate_children,
					     ClearBg             clear_bg);
261

262 263
static guint signals[LAST_SIGNAL] = { 0 };

264 265
static gpointer parent_class = NULL;

266 267
static const cairo_user_data_key_t gdk_window_cairo_key;

268 269 270 271 272 273 274 275
static guint32
new_region_tag (void)
{
  static guint32 tag = 0;

  return ++tag;
}

276
GType
277
gdk_window_get_type (void)
278 279 280 281
{
  static GType object_type = 0;

  if (!object_type)
282
    object_type = g_type_register_static_simple (G_TYPE_OBJECT,
283
						 "GdkWindow",
284
						 sizeof (GdkWindowClass),
285
						 (GClassInitFunc) gdk_window_class_init,
286
						 sizeof (GdkWindow),
287 288
						 (GInstanceInitFunc) gdk_window_init,
						 0);
289

290 291
  return object_type;
}
292

293 294 295 296 297 298 299
GType
_gdk_paintable_get_type (void)
{
  static GType paintable_type = 0;

  if (!paintable_type)
    {
300
      const GTypeInfo paintable_info =
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
      {
	sizeof (GdkPaintableIface),  /* class_size */
	NULL,                        /* base_init */
	NULL,                        /* base_finalize */
      };

      paintable_type = g_type_register_static (G_TYPE_INTERFACE,
					       g_intern_static_string ("GdkPaintable"),
					       &paintable_info, 0);

      g_type_interface_add_prerequisite (paintable_type, G_TYPE_OBJECT);
    }

  return paintable_type;
}

317
static void
318
gdk_window_init (GdkWindow *window)
319 320
{
  /* 0-initialization is good for all other fields. */
rhlabs's avatar
rhlabs committed
321

322
  window->window_type = GDK_WINDOW_CHILD;
Elliot Lee's avatar
Elliot Lee committed
323

Havoc Pennington's avatar
Havoc Pennington committed
324
  window->state = GDK_WINDOW_STATE_WITHDRAWN;
325 326 327
  window->width = 1;
  window->height = 1;
  window->toplevel_window_type = -1;
328 329 330 331 332
  /* 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;
333
}
334

335
/* Stop and return on the first non-NULL parent */
336
static gboolean
337 338 339 340
accumulate_get_window (GSignalInvocationHint *ihint,
		       GValue		       *return_accu,
		       const GValue	       *handler_return,
		       gpointer               data)
341 342 343
{
  g_value_copy (handler_return, return_accu);
  /* Continue while returning NULL */
344
  return g_value_get_object (handler_return) == NULL;
345 346
}

347 348 349 350 351 352 353 354 355 356 357 358
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;
}

359 360
static GQuark quark_pointer_window = 0;

361
static void
362
gdk_window_class_init (GdkWindowClass *klass)
363 364
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
365

366 367
  parent_class = g_type_class_peek_parent (klass);

368
  object_class->finalize = gdk_window_finalize;
Cody Russell's avatar
Cody Russell committed
369 370
  object_class->set_property = gdk_window_set_property;
  object_class->get_property = gdk_window_get_property;
371

372 373
  klass->create_surface = _gdk_offscreen_window_create_surface;

374
  quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window");
375 376


Cody Russell's avatar
Cody Russell committed
377
  /* Properties */
378 379 380 381 382 383 384 385 386

  /**
   * 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
387 388
  g_object_class_install_property (object_class,
                                   PROP_CURSOR,
Benjamin Otte's avatar
Benjamin Otte committed
389 390 391 392 393
                                   g_param_spec_object ("cursor",
                                                        P_("Cursor"),
                                                        P_("Cursor"),
                                                        GDK_TYPE_CURSOR,
                                                        G_PARAM_READWRITE));
Cody Russell's avatar
Cody Russell committed
394

Matthias Clasen's avatar
Matthias Clasen committed
395 396 397 398 399 400 401 402 403
  /**
   * 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.
   *
Matthias Clasen's avatar
Matthias Clasen committed
404
   * Returns: the #GdkWindow of the embedded child at @x, @y, or %NULL
Matthias Clasen's avatar
Matthias Clasen committed
405 406 407
   *
   * Since: 2.18
   */
Alexander Larsson's avatar
Alexander Larsson committed
408 409
  signals[PICK_EMBEDDED_CHILD] =
    g_signal_new (g_intern_static_string ("pick-embedded-child"),
410 411
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
412
                  G_STRUCT_OFFSET (GdkWindowClass, pick_embedded_child),
413
		  accumulate_get_window, NULL,
Matthias Clasen's avatar
Matthias Clasen committed
414
		  _gdk_marshal_OBJECT__DOUBLE_DOUBLE,
415 416 417 418
		  GDK_TYPE_WINDOW,
		  2,
		  G_TYPE_DOUBLE,
		  G_TYPE_DOUBLE);
Matthias Clasen's avatar
Matthias Clasen committed
419 420 421 422 423 424 425 426 427 428 429 430

  /**
   * GdkWindow::to-embedder:
   * @window: the offscreen window on which the signal is emitted
   * @offscreen-x: x coordinate in the offscreen window
   * @offscreen-y: y coordinate in the offscreen window
   * @embedder-x: return location for the x coordinate in the embedder window
   * @embedder-y: return location for the y coordinate in the embedder window
   *
   * The ::to-embedder signal is emitted to translate coordinates
   * in an offscreen window to its embedder.
   *
Matthias Clasen's avatar
Matthias Clasen committed
431 432
   * See also #GtkWindow::from-embedder.
   *
Matthias Clasen's avatar
Matthias Clasen committed
433 434
   * Since: 2.18
   */
Alexander Larsson's avatar
Alexander Larsson committed
435 436
  signals[TO_EMBEDDER] =
    g_signal_new (g_intern_static_string ("to-embedder"),
437 438
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
439
                  G_STRUCT_OFFSET (GdkWindowClass, to_embedder),
440
		  NULL, NULL,
Matthias Clasen's avatar
Matthias Clasen committed
441
		  _gdk_marshal_VOID__DOUBLE_DOUBLE_POINTER_POINTER,
442 443 444 445 446 447
		  G_TYPE_NONE,
		  4,
		  G_TYPE_DOUBLE,
		  G_TYPE_DOUBLE,
		  G_TYPE_POINTER,
		  G_TYPE_POINTER);
Matthias Clasen's avatar
Matthias Clasen committed
448 449 450 451 452 453 454 455 456 457 458 459

  /**
   * GdkWindow::from-embedder:
   * @window: the offscreen window on which the signal is emitted
   * @embedder-x: x coordinate in the embedder window
   * @embedder-y: y coordinate in the embedder window
   * @offscreen-x: return location for the x coordinate in the offscreen window
   * @offscreen-y: return location for the y coordinate in the offscreen window
   *
   * The ::from-embedder signal is emitted to translate coordinates
   * in the embedder of an offscreen window to the offscreen window.
   *
Matthias Clasen's avatar
Matthias Clasen committed
460 461
   * See also #GtkWindow::to-embedder.
   *
Matthias Clasen's avatar
Matthias Clasen committed
462 463
   * Since: 2.18
   */
Alexander Larsson's avatar
Alexander Larsson committed
464 465
  signals[FROM_EMBEDDER] =
    g_signal_new (g_intern_static_string ("from-embedder"),
466 467
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
468
                  G_STRUCT_OFFSET (GdkWindowClass, from_embedder),
469
		  NULL, NULL,
Matthias Clasen's avatar
Matthias Clasen committed
470
		  _gdk_marshal_VOID__DOUBLE_DOUBLE_POINTER_POINTER,
471 472 473 474 475 476
		  G_TYPE_NONE,
		  4,
		  G_TYPE_DOUBLE,
		  G_TYPE_DOUBLE,
		  G_TYPE_POINTER,
		  G_TYPE_POINTER);
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502

  /**
   * 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
   * needs its surface (re)created, which happens either when the the
   * 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,
503
                  G_STRUCT_OFFSET (GdkWindowClass, create_surface),
504 505 506 507 508 509
                  create_surface_accumulator, NULL,
                  _gdk_marshal_BOXED__INT_INT,
                  CAIRO_GOBJECT_TYPE_SURFACE,
                  2,
                  G_TYPE_INT,
                  G_TYPE_INT);
510
}
511

512 513 514 515 516
static void
device_removed_cb (GdkDeviceManager *device_manager,
                   GdkDevice        *device,
                   GdkWindow        *window)
{
517 518
  window->devices_inside = g_list_remove (window->devices_inside, device);
  g_hash_table_remove (window->device_cursor, device);
519

520 521
  if (window->device_events)
    g_hash_table_remove (window->device_events, device);
522 523
}

524 525 526 527
static void
gdk_window_finalize (GObject *object)
{
  GdkWindow *window = GDK_WINDOW (object);
528 529
  GdkDeviceManager *device_manager;

530
  device_manager = gdk_display_get_device_manager (gdk_window_get_display (window));
531
  g_signal_handlers_disconnect_by_func (device_manager, device_removed_cb, window);
532

533 534 535 536 537 538 539 540 541 542 543 544 545
  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);
    }
546

547
  gdk_window_drop_cairo_surface (window);
548

549
  if (window->impl)
550
    {
551 552
      g_object_unref (window->impl);
      window->impl = NULL;
553 554
    }

555
  if (window->impl_window != window)
556
    {
557 558
      g_object_unref (window->impl_window);
      window->impl_window = NULL;
559
    }
560

561 562
  if (window->shape)
    cairo_region_destroy (window->shape);
Alexander Larsson's avatar
Alexander Larsson committed
563

564 565
  if (window->input_shape)
    cairo_region_destroy (window->input_shape);
Alexander Larsson's avatar
Alexander Larsson committed
566

567
  if (window->cursor)
568
    g_object_unref (window->cursor);
569

570 571
  if (window->device_cursor)
    g_hash_table_destroy (window->device_cursor);
572

573 574
  if (window->device_events)
    g_hash_table_destroy (window->device_events);
575

576 577 578
  if (window->source_event_masks)
    g_hash_table_destroy (window->source_event_masks);

579 580
  if (window->devices_inside)
    g_list_free (window->devices_inside);
581

582
  G_OBJECT_CLASS (parent_class)->finalize (object);
Elliot Lee's avatar
Elliot Lee committed
583 584
}

Cody Russell's avatar
Cody Russell committed
585 586 587 588 589 590 591 592 593 594 595
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
596
      gdk_window_set_cursor (window, g_value_get_object (value));
Cody Russell's avatar
Cody Russell committed
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
      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
616
      g_value_set_object (value, gdk_window_get_cursor (window));
Cody Russell's avatar
Cody Russell committed
617 618 619 620 621 622 623 624
      break;

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

625
static gboolean
626
gdk_window_is_offscreen (GdkWindow *window)
627
{
628
  return window->window_type == GDK_WINDOW_OFFSCREEN;
629 630
}

631 632
static GdkWindow *
gdk_window_get_impl_window (GdkWindow *window)
633
{
634
  return window->impl_window;
635 636 637 638 639
}

GdkWindow *
_gdk_window_get_impl_window (GdkWindow *window)
{
640
  return gdk_window_get_impl_window (window);
641 642 643
}

static gboolean
644
gdk_window_has_impl (GdkWindow *window)
645
{
646
  return window->impl_window == window;
647 648
}

649
static gboolean
650
gdk_window_is_toplevel (GdkWindow *window)
651 652 653 654 655 656
{
  return
    window->parent == NULL ||
    window->parent->window_type == GDK_WINDOW_ROOT;
}

657 658 659
gboolean
_gdk_window_has_impl (GdkWindow *window)
{
660
  return gdk_window_has_impl (window);
661 662 663
}

static gboolean
664
gdk_window_has_no_impl (GdkWindow *window)
665
{
666
  return window->impl_window != window;
667 668 669
}

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

681 682 683 684 685 686
  for (l = private->children; l; l = l->next)
    {
      child = l->data;

      if (child == until)
	break;
687

688 689
      /* If region is empty already, no need to do
	 anything potentially costly */
Benjamin Otte's avatar
Benjamin Otte committed
690
      if (cairo_region_is_empty (region))
691 692
	break;

693
      if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
694 695 696 697 698 699 700 701 702 703 704
	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
705

706
      /* Bail early if child totally outside region */
Benjamin Otte's avatar
Benjamin Otte committed
707
      if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
708 709
	continue;

Benjamin Otte's avatar
Benjamin Otte committed
710
      child_region = cairo_region_create_rectangle (&r);
711

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

      if (for_input)
	{
	  if (child->input_shape)
Benjamin Otte's avatar
Benjamin Otte committed
732
	    cairo_region_intersect (child_region, child->input_shape);
Alexander Larsson's avatar
Alexander Larsson committed
733 734
	  else if (private->window_type == GDK_WINDOW_FOREIGN)
	    {
735
	      shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_input_shape (child);
Alexander Larsson's avatar
Alexander Larsson committed
736 737
	      if (shape)
		{
Benjamin Otte's avatar
Benjamin Otte committed
738 739
		  cairo_region_intersect (child_region, shape);
		  cairo_region_destroy (shape);
Alexander Larsson's avatar
Alexander Larsson committed
740 741 742
		}
	    }
	}
743

Benjamin Otte's avatar
Benjamin Otte committed
744 745
      cairo_region_subtract (region, child_region);
      cairo_region_destroy (child_region);
Alexander Larsson's avatar
Alexander Larsson committed
746

747 748 749
    }
}

750
static GdkVisibilityState
751
effective_visibility (GdkWindow *window)
752 753 754
{
  GdkVisibilityState native;

755
  if (!gdk_window_is_viewable (window))
756 757
    return GDK_VISIBILITY_NOT_VIEWABLE;

758
  native = window->impl_window->native_visibility;
759 760

  if (native == GDK_VISIBILITY_FULLY_OBSCURED ||
761
      window->visibility == GDK_VISIBILITY_FULLY_OBSCURED)
762 763
    return GDK_VISIBILITY_FULLY_OBSCURED;
  else if (native == GDK_VISIBILITY_UNOBSCURED)
764
    return window->visibility;
765 766 767 768 769
  else /* native PARTIAL, private partial or unobscured  */
    return GDK_VISIBILITY_PARTIAL;
}

static void
770
gdk_window_update_visibility (GdkWindow *window)
771 772 773 774
{
  GdkVisibilityState new_visibility;
  GdkEvent *event;

775
  new_visibility = effective_visibility (window);
776

777
  if (new_visibility != window->effective_visibility)
778
    {
779
      window->effective_visibility = new_visibility;
780 781

      if (new_visibility != GDK_VISIBILITY_NOT_VIEWABLE &&
782
	  window->event_mask & GDK_VISIBILITY_NOTIFY)
783
	{
784
	  event = _gdk_make_event (window, GDK_VISIBILITY_NOTIFY,
785 786 787 788 789 790 791
				   NULL, FALSE);
	  event->visibility.state = new_visibility;
	}
    }
}

static void
792 793
gdk_window_update_visibility_recursively (GdkWindow *window,
					  GdkWindow *only_for_impl)
794
{
795
  GdkWindow *child;
796 797
  GList *l;

798 799
  gdk_window_update_visibility (window);
  for (l = window->children; l != NULL; l = l->next)
800 801 802 803 804 805 806 807
    {
      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
808
static gboolean
809
should_apply_clip_as_shape (GdkWindow *window)
Alexander Larsson's avatar
Alexander Larsson committed
810 811
{
  return
812
    gdk_window_has_impl (window) &&
Alexander Larsson's avatar
Alexander Larsson committed
813
    /* Not for offscreens */
814
    !gdk_window_is_offscreen (window) &&
Alexander Larsson's avatar
Alexander Larsson committed
815
    /* or for toplevels */
816
    !gdk_window_is_toplevel (window) &&
Alexander Larsson's avatar
Alexander Larsson committed
817
    /* or for foreign windows */
818
    window->window_type != GDK_WINDOW_FOREIGN &&
Alexander Larsson's avatar
Alexander Larsson committed
819
    /* or for the root window */
820
    window->window_type != GDK_WINDOW_ROOT;
Alexander Larsson's avatar
Alexander Larsson committed
821 822 823
}

static void
824
apply_shape (GdkWindow *window,
825
	     cairo_region_t *region)
Alexander Larsson's avatar
Alexander Larsson committed
826
{
827
  GdkWindowImplClass *impl_class;
Alexander Larsson's avatar
Alexander Larsson committed
828 829 830 831 832

  /* 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 */
833
  impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
Alexander Larsson's avatar
Alexander Larsson committed
834
  if (region)
835
    impl_class->shape_combine_region (window,
Alexander Larsson's avatar
Alexander Larsson committed
836
				      region, 0, 0);
837 838
  else if (window->applied_shape)
    impl_class->shape_combine_region (window,
Alexander Larsson's avatar
Alexander Larsson committed
839 840
				      NULL, 0, 0);

841
  window->applied_shape = region != NULL;
Alexander Larsson's avatar
Alexander Larsson committed
842 843
}

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

  r.x = r.y = 0;
867 868
  r.width = window->width;
  r.height = window->height;
Alexander Larsson's avatar
Alexander Larsson committed
869 870 871 872 873

  /* 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 */
874 875
  if (!region_rect_equal (window->clip_region, &r))
    apply_shape (window, window->clip_region);
Alexander Larsson's avatar
Alexander Larsson committed
876
  else
877
    apply_shape (window, NULL);
Alexander Larsson's avatar
Alexander Larsson committed
878 879
}

880
static void
881 882 883 884
recompute_visible_regions_internal (GdkWindow *private,
				    gboolean   recalculate_clip,
				    gboolean   recalculate_siblings,
				    gboolean   recalculate_children)
885 886 887
{
  GdkRectangle r;
  GList *l;
888
  GdkWindow *child;
889
  cairo_region_t *new_clip, *old_clip_region_with_children;
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 916 917 918 919
  /* 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
   * window size
   * siblings in parents above window
   */
  clip_region_changed = FALSE;
920
  if (recalculate_clip)
921
    {
922
      if (private->viewable)
923
	{
924 925 926 927 928
	  /* 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
929
	  new_clip = cairo_region_create_rectangle (&r);
930

931
	  if (!gdk_window_is_toplevel (private))
932
	    {
Benjamin Otte's avatar
Benjamin Otte committed
933
	      cairo_region_intersect (new_clip, private->parent->clip_region);
934

935 936 937 938 939 940 941 942
	      /* Remove all overlapping children from parent.
	       * Unless we're all native, because then we don't need to take
	       * siblings into account since X does that clipping for us.
	       * This makes things like SWT that modify the raw X stacking
	       * order without GDKs knowledge work.
	       */
	      if (!_gdk_native_windows)
		remove_child_area (private->parent, private, FALSE, new_clip);
943
	    }
944

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

948
	  if (private->shape)
Benjamin Otte's avatar
Benjamin Otte committed
949
	    cairo_region_intersect (new_clip, private->shape);
950 951
	}
      else
Benjamin Otte's avatar
Benjamin Otte committed
952
	new_clip = cairo_region_create ();
Alexander Larsson's avatar
Alexander Larsson committed
953

954
      if (private->clip_region == NULL ||