gdkwindow.c 355 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
  MOVED_TO_RECT,
152
153
154
  LAST_SIGNAL
};

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

161
/* Global info */
162

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

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

174
static void gdk_window_clear_backing_region (GdkWindow *window);
175

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

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

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


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

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

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

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

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

275
276
277
278
      return list;
    }
}

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

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

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

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

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

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

326
327
static GQuark quark_pointer_window = 0;

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

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

337
338
  klass->create_surface = _gdk_offscreen_window_create_surface;

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


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

  /**
   * GdkWindow:cursor:
   *
   * The mouse pointer for a #GdkWindow. See gdk_window_set_cursor() and
   * gdk_window_get_cursor() for details.
   *
   * Since: 2.18
   */
352
353
354
355
356
357
358
  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
359

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

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

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

  /**
   * 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
464
   * needs its surface (re)created, which happens either when the
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
   * 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,
482
                  G_STRUCT_OFFSET (GdkWindowClass, create_surface),
483
484
485
486
487
488
                  create_surface_accumulator, NULL,
                  _gdk_marshal_BOXED__INT_INT,
                  CAIRO_GOBJECT_TYPE_SURFACE,
                  2,
                  G_TYPE_INT,
                  G_TYPE_INT);
489
490
491
  g_signal_set_va_marshaller (signals[CREATE_SURFACE],
                              G_OBJECT_CLASS_TYPE (object_class),
                              _gdk_marshal_BOXED__INT_INTv);
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531

  /**
   * GdkWindow::moved-to-rect:
   * @window: the #GdkWindow that moved
   * @flipped_rect: (nullable): the position of @window after any possible
   *                flipping or %NULL if the backend can't obtain it
   * @final_rect: (nullable): the final position of @window or %NULL if the
   *              backend can't obtain it
   * @flipped_x: %TRUE if the anchors were flipped horizontally
   * @flipped_y: %TRUE if the anchors were flipped vertically
   *
   * Emitted when the position of @window is finalized after being moved to a
   * destination rectangle.
   *
   * @window might be flipped over the destination rectangle in order to keep
   * it on-screen, in which case @flipped_x and @flipped_y will be set to %TRUE
   * accordingly.
   *
   * @flipped_rect is the ideal position of @window after any possible
   * flipping, but before any possible sliding. @final_rect is @flipped_rect,
   * but possibly translated in the case that flipping is still ineffective in
   * keeping @window on-screen.
   *
   * Since: 3.22
   * Stability: Private
   */
  signals[MOVED_TO_RECT] =
    g_signal_new (g_intern_static_string ("moved-to-rect"),
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_FIRST,
                  0,
                  NULL,
                  NULL,
                  _gdk_marshal_VOID__POINTER_POINTER_BOOLEAN_BOOLEAN,
                  G_TYPE_NONE,
                  4,
                  G_TYPE_POINTER,
                  G_TYPE_POINTER,
                  G_TYPE_BOOLEAN,
                  G_TYPE_BOOLEAN);
532
533
534
  g_signal_set_va_marshaller (signals[MOVED_TO_RECT],
                              G_OBJECT_CLASS_TYPE (object_class),
                              _gdk_marshal_VOID__POINTER_POINTER_BOOLEAN_BOOLEANv);
535
}
536

537
static void
538
539
540
seat_removed_cb (GdkDisplay *display,
                 GdkSeat    *seat,
                 GdkWindow  *window)
541
{
542
543
  GdkDevice *device = gdk_seat_get_pointer (seat);

544
545
  window->devices_inside = g_list_remove (window->devices_inside, device);
  g_hash_table_remove (window->device_cursor, device);
546

547
548
  if (window->device_events)
    g_hash_table_remove (window->device_events, device);
549
550
}

551
552
553
554
static void
gdk_window_finalize (GObject *object)
{
  GdkWindow *window = GDK_WINDOW (object);
555

556
557
  g_signal_handlers_disconnect_by_func (gdk_window_get_display (window),
                                        seat_removed_cb, window);
558

559
560
561
562
  if (!GDK_WINDOW_DESTROYED (window))
    {
      if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
	{
563
	  g_warning ("losing last reference to undestroyed window");
564
565
566
567
568
569
570
571
	  _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);
    }
572

573
574
575
576
577
578
  if (window->synthesized_crossing_event_id)
    {
      g_source_remove (window->synthesized_crossing_event_id);
      window->synthesized_crossing_event_id = 0;
    }

579
  if (window->impl)
580
    {
581
582
      g_object_unref (window->impl);
      window->impl = NULL;
583
584
    }

585
  if (window->impl_window != window)
586
    {
587
588
      g_object_unref (window->impl_window);
      window->impl_window = NULL;
589
    }
590

591
592
  if (window->shape)
    cairo_region_destroy (window->shape);
Alexander Larsson's avatar
Alexander Larsson committed
593

594
595
  if (window->input_shape)
    cairo_region_destroy (window->input_shape);
Alexander Larsson's avatar
Alexander Larsson committed
596

597
  if (window->cursor)
598
    g_object_unref (window->cursor);
599

600
601
  if (window->device_cursor)
    g_hash_table_destroy (window->device_cursor);
602

603
604
  if (window->device_events)
    g_hash_table_destroy (window->device_events);
605

606
607
608
  if (window->source_event_masks)
    g_hash_table_destroy (window->source_event_masks);

609
610
  if (window->devices_inside)
    g_list_free (window->devices_inside);
611

612
613
614
  if (window->opaque_region)
    cairo_region_destroy (window->opaque_region);

615
  G_OBJECT_CLASS (gdk_window_parent_class)->finalize (object);
Elliot Lee's avatar
Elliot Lee committed
616
617
}

Cody Russell's avatar
Cody Russell committed
618
619
620
621
622
623
624
625
626
627
628
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
629
      gdk_window_set_cursor (window, g_value_get_object (value));
Cody Russell's avatar
Cody Russell committed
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
      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
649
      g_value_set_object (value, gdk_window_get_cursor (window));
Cody Russell's avatar
Cody Russell committed
650
651
652
653
654
655
656
657
      break;

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

658
static gboolean
659
gdk_window_is_offscreen (GdkWindow *window)
660
{
661
  return window->window_type == GDK_WINDOW_OFFSCREEN;
662
663
}

664
665
666
667
668
669
static gboolean
gdk_window_is_subsurface (GdkWindow *window)
{
   return window->window_type == GDK_WINDOW_SUBSURFACE;
}

670
671
static GdkWindow *
gdk_window_get_impl_window (GdkWindow *window)
672
{
673
  return window->impl_window;
674
675
676
677
678
}

GdkWindow *
_gdk_window_get_impl_window (GdkWindow *window)
{
679
  return gdk_window_get_impl_window (window);
680
681
682
}

static gboolean
683
gdk_window_has_impl (GdkWindow *window)
684
{
685
  return window->impl_window == window;
686
687
}

688
static gboolean
689
gdk_window_is_toplevel (GdkWindow *window)
690
691
692
693
694
695
{
  return
    window->parent == NULL ||
    window->parent->window_type == GDK_WINDOW_ROOT;
}

696
697
698
gboolean
_gdk_window_has_impl (GdkWindow *window)
{
699
  return gdk_window_has_impl (window);
700
701
702
}

static gboolean
703
gdk_window_has_no_impl (GdkWindow *window)
704
{
705
  return window->impl_window != window;
706
707
708
}

static void
709
710
remove_sibling_overlapped_area (GdkWindow *window,
				cairo_region_t *region)
711
{
712
713
  GdkWindow *parent;
  GdkWindow *sibling;
714
715
716
  cairo_region_t *child_region;
  GdkRectangle r;
  GList *l;
717
  cairo_region_t *shape;
718

719
720
  parent = window->parent;

721
  if (gdk_window_is_toplevel (window))
722
723
724
725
726
727
    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)
728
    {
729
      sibling = l->data;
730

731
      if (sibling == window)
732
733
	break;

734
      if (!GDK_WINDOW_IS_MAPPED (sibling) || sibling->input_only || sibling->composited)
735
736
737
738
	continue;

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

742
743
744
745
      r.x = sibling->x;
      r.y = sibling->y;
      r.width = sibling->width;
      r.height = sibling->height;
746
747

      child_region = cairo_region_create_rectangle (&r);
748
749

      if (sibling->shape)
750
751
	{
	  /* Adjust shape region to parent window coords */
752
753
754
755
756
757
758
759
760
761
762
763
	  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);
	    }
764
765
766
767
768
	}

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

770
771
  remove_sibling_overlapped_area (parent, region);

772
773
  /* Convert back to window coords */
  cairo_region_translate (region, -window->x, -window->y);
774
775
776
777
}

static void
remove_child_area (GdkWindow *window,
Alexander Larsson's avatar
Alexander Larsson committed
778
		   gboolean for_input,
779
		   cairo_region_t *region)
780
{
781
  GdkWindow *child;
782
  cairo_region_t *child_region;
783
784
  GdkRectangle r;
  GList *l;
785
  cairo_region_t *shape;
786

787
  for (l = window->children; l; l = l->next)
788
789
790
    {
      child = l->data;

791
792
      /* If region is empty already, no need to do
	 anything potentially costly */
Benjamin Otte's avatar
Benjamin Otte committed
793
      if (cairo_region_is_empty (region))
794
795
	break;

796
      if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
797
798
799
800
801
802
803
804
805
806
807
	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
808

809
      /* Bail early if child totally outside region */
Benjamin Otte's avatar
Benjamin Otte committed
810
      if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
811
812
	continue;

Benjamin Otte's avatar
Benjamin Otte committed
813
      child_region = cairo_region_create_rectangle (&r);
814

Alexander Larsson's avatar
Alexander Larsson committed
815
      if (child->shape)
816
817
	{
	  /* Adjust shape region to parent window coords */
Benjamin Otte's avatar
Benjamin Otte committed
818
819
820
	  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);
821
	}
822
      else if (window->window_type == GDK_WINDOW_FOREIGN)
Alexander Larsson's avatar
Alexander Larsson committed
823
	{
824
	  shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_shape (child);
Alexander Larsson's avatar
Alexander Larsson committed
825
826
	  if (shape)
	    {
Benjamin Otte's avatar
Benjamin Otte committed
827
828
	      cairo_region_intersect (child_region, shape);
	      cairo_region_destroy (shape);
Alexander Larsson's avatar
Alexander Larsson committed
829
830
	    }
	}
Alexander Larsson's avatar
Alexander Larsson committed
831
832
833
834

      if (for_input)
	{
	  if (child->input_shape)
Benjamin Otte's avatar
Benjamin Otte committed
835
	    cairo_region_intersect (child_region, child->input_shape);
836
	  else if (window->window_type == GDK_WINDOW_FOREIGN)
Alexander Larsson's avatar
Alexander Larsson committed
837
	    {
838
	      shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_input_shape (child);
Alexander Larsson's avatar
Alexander Larsson committed
839
840
	      if (shape)
		{
Benjamin Otte's avatar
Benjamin Otte committed
841
842
		  cairo_region_intersect (child_region, shape);
		  cairo_region_destroy (shape);
Alexander Larsson's avatar
Alexander Larsson committed
843
844
845
		}
	    }
	}
846

847
      cairo_region_subtract (region, child_region);
Benjamin Otte's avatar
Benjamin Otte committed
848
      cairo_region_destroy (child_region);
849
850
851
    }
}

852
static GdkVisibilityState
853
effective_visibility (GdkWindow *window)
854
855
856
{
  GdkVisibilityState native;

857
  if (!gdk_window_is_viewable (window))
858
859
    return GDK_VISIBILITY_NOT_VIEWABLE;

860
  native = window->impl_window->native_visibility;
861
862

  if (native == GDK_VISIBILITY_FULLY_OBSCURED ||
863
      window->visibility == GDK_VISIBILITY_FULLY_OBSCURED)
864
865
    return GDK_VISIBILITY_FULLY_OBSCURED;
  else if (native == GDK_VISIBILITY_UNOBSCURED)
866
    return window->visibility;
867
868
869
870
871
  else /* native PARTIAL, private partial or unobscured  */
    return GDK_VISIBILITY_PARTIAL;
}

static void
872
gdk_window_update_visibility (GdkWindow *window)
873
874
875
876
{
  GdkVisibilityState new_visibility;
  GdkEvent *event;

877
  new_visibility = effective_visibility (window);
878

879
  if (new_visibility != window->effective_visibility)
880
    {
881
      window->effective_visibility = new_visibility;
882
883

      if (new_visibility != GDK_VISIBILITY_NOT_VIEWABLE &&
884
	  window->event_mask & GDK_VISIBILITY_NOTIFY_MASK)
885
	{
886
	  event = _gdk_make_event (window, GDK_VISIBILITY_NOTIFY,
887
888
889
890
891
892
893
				   NULL, FALSE);
	  event->visibility.state = new_visibility;
	}
    }
}

static void
894
895
gdk_window_update_visibility_recursively (GdkWindow *window,
					  GdkWindow *only_for_impl)
896
{
897
  GdkWindow *child;
898
899
  GList *l;

900
901
  gdk_window_update_visibility (window);
  for (l = window->children; l != NULL; l = l->next)
902
903
904
905
906
907
908
909
    {
      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
910
static gboolean
911
should_apply_clip_as_shape (GdkWindow *window)
Alexander Larsson's avatar
Alexander Larsson committed
912
913
{
  return
914
    gdk_window_has_impl (window) &&
Alexander Larsson's avatar
Alexander Larsson committed
915
    /* Not for offscreens */
916
    !gdk_window_is_offscreen (window) &&
Alexander Larsson's avatar
Alexander Larsson committed
917
918
919
    /* or for non-shaped toplevels */
    (!gdk_window_is_toplevel (window) ||
     window->shape != NULL || window->applied_shape) &&
Alexander Larsson's avatar
Alexander Larsson committed
920
    /* or for foreign windows */
921
    window->window_type != GDK_WINDOW_FOREIGN &&
Alexander Larsson's avatar
Alexander Larsson committed
922
    /* or for the root window */
923
    window->window_type != GDK_WINDOW_ROOT;
Alexander Larsson's avatar
Alexander Larsson committed
924
925
926
}

static void
927
apply_shape (GdkWindow *window,
928
	     cairo_region_t *region)
Alexander Larsson's avatar
Alexander Larsson committed
929
{
930
  GdkWindowImplClass *impl_class;
Alexander Larsson's avatar
Alexander Larsson committed
931
932
933
934
935

  /* 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 */
936
  impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
Alexander Larsson's avatar
Alexander Larsson committed
937
  if (region)
938
    impl_class->shape_combine_region (window,
Alexander Larsson's avatar
Alexander Larsson committed
939
				      region, 0, 0);
940
941
  else if (window->applied_shape)
    impl_class->shape_combine_region (window,
Alexander Larsson's avatar
Alexander Larsson committed
942
943
				      NULL, 0, 0);

944
  window->applied_shape = region != NULL;
Alexander Larsson's avatar
Alexander Larsson committed
945
946
}

Benjamin Otte's avatar
Benjamin Otte committed
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
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
964
static void
965
apply_clip_as_shape (GdkWindow *window)
Alexander Larsson's avatar
Alexander Larsson committed
966
967
{
  GdkRectangle r;
968
  cairo_region_t *region;
Alexander Larsson's avatar
Alexander Larsson committed
969
970

  r.x = r.y = 0;
971
972
  r.width = window->width;
  r.height = window->height;
Alexander Larsson's avatar
Alexander Larsson committed
973

974
  region = cairo_region_copy (window->clip_region);
975
  remove_sibling_overlapped_area (window, region);
976

Alexander Larsson's avatar
Alexander Larsson committed
977
978
979
980
  /* 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 */
981
982
  if (!region_rect_equal (region, &r))
    apply_shape (window, region);
Alexander Larsson's avatar
Alexander Larsson committed
983
  else
984
    apply_shape (window, NULL);
985
986

  cairo_region_destroy (region);
Alexander Larsson's avatar
Alexander Larsson committed
987
988
}

989
static void
990
991
992
recompute_visible_regions_internal (GdkWindow *private,
				    gboolean   recalculate_clip,
				    gboolean   recalculate_children)
993
994
995
{
  GdkRectangle r;
  GList *l;
996
  GdkWindow *child;
997
  cairo_region_t *new_clip;
998
999
1000
1001
1002
1003
  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;
1004

1005
  /* Update absolute position */
1006
1007
1008
1009
  if ((gdk_window_has_impl (private) &&
       private->window_type != GDK_WINDOW_SUBSURFACE) ||
      (gdk_window_is_toplevel (private) &&
       private->window_type == GDK_WINDOW_SUBSURFACE))
1010
    {
1011
      /* Native windows and toplevel subsurfaces start here */
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
      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
1027
   * window size/position
1028
1029
   */
  clip_region_changed = FALSE;
1030
  if (recalculate_clip)
1031
    {
1032
      if (private->viewable)
1033
	{
1034
1035
1036
1037
1038
	  /* 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
1039
	  new_clip = cairo_region_create_rectangle (&r);
1040

1041
	  if (!gdk_window_is_toplevel (private))
1042
	    cairo_region_intersect (new_clip, private->parent->clip_region);
1043

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

1047
	  if (should_apply_clip_as_shape (private) && private->shape)
Benjamin Otte's avatar
Benjamin Otte committed
1048
	    cairo_region_intersect (new_clip, private->shape);
1049
1050
	}
      else
1051
	  new_clip = cairo_region_create ();
Alexander Larsson's avatar
Alexander Larsson committed
1052