1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
3 * Josh MacDonald, Ryan Lortie
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
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /*
20 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
21 * file for a list of people on the GTK+ Team. See the ChangeLog
22 * files for a list of changes. These files are distributed with
23 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
24 */
25
26 #include "config.h"
27
28 #include <cairo-gobject.h>
29
30 #include "gdkwindow.h"
31
32 #include "gdkrectangle.h"
33 #include "gdkinternals.h"
34 #include "gdkintl.h"
35 #include "gdkscreenprivate.h"
36 #include "gdkdisplayprivate.h"
37 #include "gdkdeviceprivate.h"
38 #include "gdkvisualprivate.h"
39 #include "gdkmarshalers.h"
40 #include "gdkframeclockidle.h"
41 #include "gdkwindowimpl.h"
42 #include "gdkglcontextprivate.h"
43 #include "gdkdrawingcontextprivate.h"
44 #include "gdk-private.h"
45
46 #include <math.h>
47
48 #include <epoxy/gl.h>
49
50 /* for the use of round() */
51 #include "fallback-c89.c"
52
53 #ifdef GDK_WINDOWING_WAYLAND
54 #include "wayland/gdkwayland.h"
55 #endif
56
57 #undef DEBUG_WINDOW_PRINTING
58
59
60 /**
61 * SECTION:windows
62 * @Short_description: Onscreen display areas in the target window system
63 * @Title: Windows
64 *
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
68 * window, the thing a user might think of as a “window” with a titlebar
69 * and so on; a #GtkWindow may contain many #GdkWindows. For example,
70 * 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
75 * of a child window onto its parent window. This mechanism can be
76 * intercepted by calling gdk_window_set_composited() on the child
77 * window. For a “composited” window it is the
78 * responsibility of the application to render the window contents at
79 * the right spot.
80 *
81 * # Offscreen Windows # {#OFFSCREEN-WINDOWS}
82 *
83 * Offscreen windows are more general than composited windows, since
84 * they allow not only to modify the rendering of the child window onto
85 * its parent, but also to apply coordinate transformations.
86 *
87 * To integrate an offscreen window into a window hierarchy, one has
88 * to call gdk_offscreen_window_set_embedder() and handle a number of
89 * signals. The #GdkWindow::pick-embedded-child signal on the embedder
90 * window is used to select an offscreen child at given coordinates,
91 * and the #GdkWindow::to-embedder and #GdkWindow::from-embedder signals
92 * on the offscreen window are used to translate coordinates between
93 * the embedder and the offscreen window.
94 *
95 * For rendering an offscreen window onto its embedder, the contents
96 * of the offscreen window are available as a surface, via
97 * gdk_offscreen_window_get_surface().
98 */
99
100
101 /* Historically a GdkWindow always matches a platform native window,
102 * be it a toplevel window or a child window. In this setup the
103 * GdkWindow (and other GdkDrawables) were platform independent classes,
104 * and the actual platform specific implementation was in a delegate
105 * object available as “impl” in the window object.
106 *
107 * With the addition of client side windows and offscreen windows this
108 * changes a bit. The application-visible GdkWindow object behaves as
109 * it did before, but not all such windows now have a corresponding native
110 * window. Instead windows that are “client side” are emulated by the gdk
111 * code such that clipping, drawing, moving, events etc work as expected.
112 *
113 * For GdkWindows that have a native window the “impl” object is the
114 * same as before. However, for all client side windows the impl object
115 * is shared with its parent (i.e. all client windows descendants of one
116 * native window has the same impl.
117 *
118 * Additionally there is a new type of platform independent impl object,
119 * GdkOffscreenWindow. All windows of type GDK_WINDOW_OFFSCREEN get an impl
120 * of this type (while their children are generally GDK_WINDOW_CHILD virtual
121 * windows). Such windows work by allocating a #cairo_surface_t as the backing
122 * store for drawing operations, which is resized with the window.
123 *
124 * GdkWindows have a pointer to the “impl window” they are in, i.e.
125 * the topmost GdkWindow which have the same “impl” value. This is stored
126 * in impl_window, which is different from the window itself only for client
127 * side windows.
128 * All GdkWindows (native or not) track the position of the window in the parent
129 * (x, y), the size of the window (width, height), the position of the window
130 * 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 * All toplevel windows are native windows, but also child windows can be
134 * native (although not children of offscreens). We always listen to
135 * a basic set of events (see get_native_event_mask) for these windows
136 * so that we can emulate events for any client side children.
137 *
138 * For native windows we apply the calculated clip region as a window shape
139 * so that eg. client side siblings that overlap the native child properly
140 * draws over the native child window.
141 */
142
143 /* This adds a local value to the GdkVisibilityState enum */
144 #define GDK_VISIBILITY_NOT_VIEWABLE 3
145
146 enum {
147 PICK_EMBEDDED_CHILD, /* only called if children are embedded */
148 TO_EMBEDDER,
149 FROM_EMBEDDER,
150 CREATE_SURFACE,
151 MOVED_TO_RECT,
152 LAST_SIGNAL
153 };
154
155 enum {
156 PROP_0,
157 PROP_CURSOR,
158 LAST_PROP
159 };
160
161 /* Global info */
162
163 static void gdk_window_finalize (GObject *object);
164
165 static void gdk_window_set_property (GObject *object,
166 guint prop_id,
167 const GValue *value,
168 GParamSpec *pspec);
169 static void gdk_window_get_property (GObject *object,
170 guint prop_id,
171 GValue *value,
172 GParamSpec *pspec);
173
174 static void gdk_window_clear_backing_region (GdkWindow *window);
175
176 static void recompute_visible_regions (GdkWindow *private,
177 gboolean recalculate_children);
178 static void gdk_window_invalidate_in_parent (GdkWindow *private);
179 static void move_native_children (GdkWindow *private);
180 static void update_cursor (GdkDisplay *display,
181 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 static void gdk_window_invalidate_rect_full (GdkWindow *window,
188 const GdkRectangle *rect,
189 gboolean invalidate_children);
190 static cairo_surface_t *gdk_window_ref_impl_surface (GdkWindow *window);
191
192 static void gdk_window_set_frame_clock (GdkWindow *window,
193 GdkFrameClock *clock);
194
195 static void draw_ugly_color (GdkWindow *window,
196 const cairo_region_t *region,
197 int color);
198
199
200 static guint signals[LAST_SIGNAL] = { 0 };
201 static GParamSpec *properties[LAST_PROP] = { NULL, };
202
G_DEFINE_ABSTRACT_TYPE(GdkWindow,gdk_window,G_TYPE_OBJECT)203 G_DEFINE_ABSTRACT_TYPE (GdkWindow, gdk_window, G_TYPE_OBJECT)
204
205 #ifdef DEBUG_WINDOW_PRINTING
206 char *
207 print_region (cairo_region_t *region)
208 {
209 GString *s = g_string_new ("{");
210 if (cairo_region_is_empty (region))
211 {
212 g_string_append (s, "empty");
213 }
214 else
215 {
216 int num = cairo_region_num_rectangles (region);
217 cairo_rectangle_int_t r;
218
219 if (num == 1)
220 {
221 cairo_region_get_rectangle (region, 0, &r);
222 g_string_append_printf (s, "%dx%d @%d,%d", r.width, r.height, r.x, r.y);
223 }
224 else
225 {
226 int i;
227 cairo_region_get_extents (region, &r);
228 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 g_string_append_printf (s, "[%dx%d @%d,%d]", r.width, r.height, r.x, r.y);
233 if (i != num -1)
234 g_string_append (s, ", ");
235 }
236 }
237 }
238 g_string_append (s, "}");
239 return g_string_free (s, FALSE);
240 }
241 #endif
242
243 static GList *
list_insert_link_before(GList * list,GList * sibling,GList * link)244 list_insert_link_before (GList *list,
245 GList *sibling,
246 GList *link)
247 {
248 if (list == NULL || sibling == list)
249 {
250 link->prev = NULL;
251 link->next = list;
252 if (list)
253 list->prev = link;
254 return link;
255 }
256 else if (sibling == NULL)
257 {
258 GList *last = g_list_last (list);
259
260 last->next = link;
261 link->prev = last;
262 link->next = NULL;
263
264 return list;
265 }
266 else
267 {
268 link->next = sibling;
269 link->prev = sibling->prev;
270 sibling->prev = link;
271
272 if (link->prev)
273 link->prev->next = link;
274
275 return list;
276 }
277 }
278
279 static void
gdk_window_init(GdkWindow * window)280 gdk_window_init (GdkWindow *window)
281 {
282 /* 0-initialization is good for all other fields. */
283
284 window->window_type = GDK_WINDOW_CHILD;
285
286 window->state = GDK_WINDOW_STATE_WITHDRAWN;
287 window->fullscreen_mode = GDK_FULLSCREEN_ON_CURRENT_MONITOR;
288 window->width = 1;
289 window->height = 1;
290 window->toplevel_window_type = -1;
291 /* starts hidden */
292 window->effective_visibility = GDK_VISIBILITY_NOT_VIEWABLE;
293 window->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
294 /* Default to unobscured since some backends don't send visibility events */
295 window->native_visibility = GDK_VISIBILITY_UNOBSCURED;
296 window->children_list_node.data = window;
297
298 window->device_cursor = g_hash_table_new_full (NULL, NULL,
299 NULL, g_object_unref);
300 }
301
302 /* Stop and return on the first non-NULL parent */
303 static gboolean
accumulate_get_window(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer data)304 accumulate_get_window (GSignalInvocationHint *ihint,
305 GValue *return_accu,
306 const GValue *handler_return,
307 gpointer data)
308 {
309 g_value_copy (handler_return, return_accu);
310 /* Continue while returning NULL */
311 return g_value_get_object (handler_return) == NULL;
312 }
313
314 static gboolean
create_surface_accumulator(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer data)315 create_surface_accumulator (GSignalInvocationHint *ihint,
316 GValue *return_accu,
317 const GValue *handler_return,
318 gpointer data)
319 {
320 g_value_copy (handler_return, return_accu);
321
322 /* Stop on the first non-NULL return value */
323 return g_value_get_boxed (handler_return) == NULL;
324 }
325
326 static GQuark quark_pointer_window = 0;
327
328 static void
gdk_window_class_init(GdkWindowClass * klass)329 gdk_window_class_init (GdkWindowClass *klass)
330 {
331 GObjectClass *object_class = G_OBJECT_CLASS (klass);
332
333 object_class->finalize = gdk_window_finalize;
334 object_class->set_property = gdk_window_set_property;
335 object_class->get_property = gdk_window_get_property;
336
337 klass->create_surface = _gdk_offscreen_window_create_surface;
338
339 quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window");
340
341
342 /* Properties */
343
344 /**
345 * GdkWindow:cursor:
346 *
347 * The mouse pointer for a #GdkWindow. See gdk_window_set_cursor() and
348 * gdk_window_get_cursor() for details.
349 *
350 * Since: 2.18
351 */
352 properties[PROP_CURSOR] =
353 g_param_spec_object ("cursor",
354 P_("Cursor"),
355 P_("Cursor"),
356 GDK_TYPE_CURSOR,
357 G_PARAM_READWRITE);
358 g_object_class_install_properties (object_class, LAST_PROP, properties);
359
360 /**
361 * GdkWindow::pick-embedded-child:
362 * @window: the window on which the signal is emitted
363 * @x: x coordinate in the window
364 * @y: y coordinate in the window
365 *
366 * The ::pick-embedded-child signal is emitted to find an embedded
367 * child at the given position.
368 *
369 * Returns: (nullable) (transfer none): the #GdkWindow of the
370 * embedded child at @x, @y, or %NULL
371 *
372 * Since: 2.18
373 */
374 signals[PICK_EMBEDDED_CHILD] =
375 g_signal_new (g_intern_static_string ("pick-embedded-child"),
376 G_OBJECT_CLASS_TYPE (object_class),
377 G_SIGNAL_RUN_LAST,
378 G_STRUCT_OFFSET (GdkWindowClass, pick_embedded_child),
379 accumulate_get_window, NULL,
380 _gdk_marshal_OBJECT__DOUBLE_DOUBLE,
381 GDK_TYPE_WINDOW,
382 2,
383 G_TYPE_DOUBLE,
384 G_TYPE_DOUBLE);
385 g_signal_set_va_marshaller (signals[PICK_EMBEDDED_CHILD],
386 G_OBJECT_CLASS_TYPE (object_class),
387 _gdk_marshal_OBJECT__DOUBLE_DOUBLEv);
388
389 /**
390 * GdkWindow::to-embedder:
391 * @window: the offscreen window on which the signal is emitted
392 * @offscreen_x: x coordinate in the offscreen window
393 * @offscreen_y: y coordinate in the offscreen window
394 * @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
398 *
399 * The ::to-embedder signal is emitted to translate coordinates
400 * in an offscreen window to its embedder.
401 *
402 * See also #GdkWindow::from-embedder.
403 *
404 * Since: 2.18
405 */
406 signals[TO_EMBEDDER] =
407 g_signal_new (g_intern_static_string ("to-embedder"),
408 G_OBJECT_CLASS_TYPE (object_class),
409 G_SIGNAL_RUN_LAST,
410 G_STRUCT_OFFSET (GdkWindowClass, to_embedder),
411 NULL, NULL,
412 _gdk_marshal_VOID__DOUBLE_DOUBLE_POINTER_POINTER,
413 G_TYPE_NONE,
414 4,
415 G_TYPE_DOUBLE,
416 G_TYPE_DOUBLE,
417 G_TYPE_POINTER,
418 G_TYPE_POINTER);
419 g_signal_set_va_marshaller (signals[TO_EMBEDDER],
420 G_OBJECT_CLASS_TYPE (object_class),
421 _gdk_marshal_VOID__DOUBLE_DOUBLE_POINTER_POINTERv);
422
423 /**
424 * GdkWindow::from-embedder:
425 * @window: the offscreen window on which the signal is emitted
426 * @embedder_x: x coordinate in the embedder window
427 * @embedder_y: y coordinate in the embedder window
428 * @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
432 *
433 * The ::from-embedder signal is emitted to translate coordinates
434 * in the embedder of an offscreen window to the offscreen window.
435 *
436 * See also #GdkWindow::to-embedder.
437 *
438 * Since: 2.18
439 */
440 signals[FROM_EMBEDDER] =
441 g_signal_new (g_intern_static_string ("from-embedder"),
442 G_OBJECT_CLASS_TYPE (object_class),
443 G_SIGNAL_RUN_LAST,
444 G_STRUCT_OFFSET (GdkWindowClass, from_embedder),
445 NULL, NULL,
446 _gdk_marshal_VOID__DOUBLE_DOUBLE_POINTER_POINTER,
447 G_TYPE_NONE,
448 4,
449 G_TYPE_DOUBLE,
450 G_TYPE_DOUBLE,
451 G_TYPE_POINTER,
452 G_TYPE_POINTER);
453 g_signal_set_va_marshaller (signals[FROM_EMBEDDER],
454 G_OBJECT_CLASS_TYPE (object_class),
455 _gdk_marshal_VOID__DOUBLE_DOUBLE_POINTER_POINTERv);
456
457 /**
458 * GdkWindow::create-surface:
459 * @window: the offscreen window on which the signal is emitted
460 * @width: the width of the offscreen surface to create
461 * @height: the height of the offscreen surface to create
462 *
463 * The ::create-surface signal is emitted when an offscreen window
464 * needs its surface (re)created, which happens either when the
465 * window is first drawn to, or when the window is being
466 * resized. The first signal handler that returns a non-%NULL
467 * surface will stop any further signal emission, and its surface
468 * will be used.
469 *
470 * Note that it is not possible to access the window's previous
471 * surface from within any callback of this signal. Calling
472 * gdk_offscreen_window_get_surface() will lead to a crash.
473 *
474 * Returns: the newly created #cairo_surface_t for the offscreen window
475 *
476 * Since: 3.0
477 */
478 signals[CREATE_SURFACE] =
479 g_signal_new (g_intern_static_string ("create-surface"),
480 G_OBJECT_CLASS_TYPE (object_class),
481 G_SIGNAL_RUN_LAST,
482 G_STRUCT_OFFSET (GdkWindowClass, create_surface),
483 create_surface_accumulator, NULL,
484 _gdk_marshal_BOXED__INT_INT,
485 CAIRO_GOBJECT_TYPE_SURFACE,
486 2,
487 G_TYPE_INT,
488 G_TYPE_INT);
489 g_signal_set_va_marshaller (signals[CREATE_SURFACE],
490 G_OBJECT_CLASS_TYPE (object_class),
491 _gdk_marshal_BOXED__INT_INTv);
492
493 /**
494 * GdkWindow::moved-to-rect:
495 * @window: the #GdkWindow that moved
496 * @flipped_rect: (nullable): the position of @window after any possible
497 * flipping or %NULL if the backend can't obtain it
498 * @final_rect: (nullable): the final position of @window or %NULL if the
499 * backend can't obtain it
500 * @flipped_x: %TRUE if the anchors were flipped horizontally
501 * @flipped_y: %TRUE if the anchors were flipped vertically
502 *
503 * Emitted when the position of @window is finalized after being moved to a
504 * destination rectangle.
505 *
506 * @window might be flipped over the destination rectangle in order to keep
507 * it on-screen, in which case @flipped_x and @flipped_y will be set to %TRUE
508 * accordingly.
509 *
510 * @flipped_rect is the ideal position of @window after any possible
511 * flipping, but before any possible sliding. @final_rect is @flipped_rect,
512 * but possibly translated in the case that flipping is still ineffective in
513 * keeping @window on-screen.
514 *
515 * Since: 3.22
516 * Stability: Private
517 */
518 signals[MOVED_TO_RECT] =
519 g_signal_new (g_intern_static_string ("moved-to-rect"),
520 G_OBJECT_CLASS_TYPE (object_class),
521 G_SIGNAL_RUN_FIRST,
522 0,
523 NULL,
524 NULL,
525 _gdk_marshal_VOID__POINTER_POINTER_BOOLEAN_BOOLEAN,
526 G_TYPE_NONE,
527 4,
528 G_TYPE_POINTER,
529 G_TYPE_POINTER,
530 G_TYPE_BOOLEAN,
531 G_TYPE_BOOLEAN);
532 g_signal_set_va_marshaller (signals[MOVED_TO_RECT],
533 G_OBJECT_CLASS_TYPE (object_class),
534 _gdk_marshal_VOID__POINTER_POINTER_BOOLEAN_BOOLEANv);
535 }
536
537 static void
seat_removed_cb(GdkDisplay * display,GdkSeat * seat,GdkWindow * window)538 seat_removed_cb (GdkDisplay *display,
539 GdkSeat *seat,
540 GdkWindow *window)
541 {
542 GdkDevice *device = gdk_seat_get_pointer (seat);
543
544 window->devices_inside = g_list_remove (window->devices_inside, device);
545 g_hash_table_remove (window->device_cursor, device);
546
547 if (window->device_events)
548 g_hash_table_remove (window->device_events, device);
549 }
550
551 static void
gdk_window_finalize(GObject * object)552 gdk_window_finalize (GObject *object)
553 {
554 GdkWindow *window = GDK_WINDOW (object);
555
556 g_signal_handlers_disconnect_by_func (gdk_window_get_display (window),
557 seat_removed_cb, window);
558
559 if (!GDK_WINDOW_DESTROYED (window))
560 {
561 if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
562 {
563 g_warning ("losing last reference to undestroyed window");
564 _gdk_window_destroy (window, FALSE);
565 }
566 else
567 /* We use TRUE here, to keep us from actually calling
568 * XDestroyWindow() on the window
569 */
570 _gdk_window_destroy (window, TRUE);
571 }
572
573 if (window->synthesized_crossing_event_id)
574 {
575 g_source_remove (window->synthesized_crossing_event_id);
576 window->synthesized_crossing_event_id = 0;
577 }
578
579 if (window->impl)
580 {
581 g_object_unref (window->impl);
582 window->impl = NULL;
583 }
584
585 if (window->impl_window != window)
586 {
587 g_object_unref (window->impl_window);
588 window->impl_window = NULL;
589 }
590
591 if (window->shape)
592 cairo_region_destroy (window->shape);
593
594 if (window->input_shape)
595 cairo_region_destroy (window->input_shape);
596
597 if (window->cursor)
598 g_object_unref (window->cursor);
599
600 if (window->device_cursor)
601 g_hash_table_destroy (window->device_cursor);
602
603 if (window->device_events)
604 g_hash_table_destroy (window->device_events);
605
606 if (window->source_event_masks)
607 g_hash_table_destroy (window->source_event_masks);
608
609 if (window->devices_inside)
610 g_list_free (window->devices_inside);
611
612 if (window->opaque_region)
613 cairo_region_destroy (window->opaque_region);
614
615 G_OBJECT_CLASS (gdk_window_parent_class)->finalize (object);
616 }
617
618 static void
gdk_window_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)619 gdk_window_set_property (GObject *object,
620 guint prop_id,
621 const GValue *value,
622 GParamSpec *pspec)
623 {
624 GdkWindow *window = (GdkWindow *)object;
625
626 switch (prop_id)
627 {
628 case PROP_CURSOR:
629 gdk_window_set_cursor (window, g_value_get_object (value));
630 break;
631
632 default:
633 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
634 break;
635 }
636 }
637
638 static void
gdk_window_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)639 gdk_window_get_property (GObject *object,
640 guint prop_id,
641 GValue *value,
642 GParamSpec *pspec)
643 {
644 GdkWindow *window = (GdkWindow *) object;
645
646 switch (prop_id)
647 {
648 case PROP_CURSOR:
649 g_value_set_object (value, gdk_window_get_cursor (window));
650 break;
651
652 default:
653 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
654 break;
655 }
656 }
657
658 static gboolean
gdk_window_is_offscreen(GdkWindow * window)659 gdk_window_is_offscreen (GdkWindow *window)
660 {
661 return window->window_type == GDK_WINDOW_OFFSCREEN;
662 }
663
664 static gboolean
gdk_window_is_subsurface(GdkWindow * window)665 gdk_window_is_subsurface (GdkWindow *window)
666 {
667 return window->window_type == GDK_WINDOW_SUBSURFACE;
668 }
669
670 static GdkWindow *
gdk_window_get_impl_window(GdkWindow * window)671 gdk_window_get_impl_window (GdkWindow *window)
672 {
673 return window->impl_window;
674 }
675
676 GdkWindow *
_gdk_window_get_impl_window(GdkWindow * window)677 _gdk_window_get_impl_window (GdkWindow *window)
678 {
679 return gdk_window_get_impl_window (window);
680 }
681
682 static gboolean
gdk_window_has_impl(GdkWindow * window)683 gdk_window_has_impl (GdkWindow *window)
684 {
685 return window->impl_window == window;
686 }
687
688 static gboolean
gdk_window_is_toplevel(GdkWindow * window)689 gdk_window_is_toplevel (GdkWindow *window)
690 {
691 return
692 window->parent == NULL ||
693 window->parent->window_type == GDK_WINDOW_ROOT;
694 }
695
696 gboolean
_gdk_window_has_impl(GdkWindow * window)697 _gdk_window_has_impl (GdkWindow *window)
698 {
699 return gdk_window_has_impl (window);
700 }
701
702 static gboolean
gdk_window_has_no_impl(GdkWindow * window)703 gdk_window_has_no_impl (GdkWindow *window)
704 {
705 return window->impl_window != window;
706 }
707
708 static void
remove_sibling_overlapped_area(GdkWindow * window,cairo_region_t * region)709 remove_sibling_overlapped_area (GdkWindow *window,
710 cairo_region_t *region)
711 {
712 GdkWindow *parent;
713 GdkWindow *sibling;
714 cairo_region_t *child_region;
715 GdkRectangle r;
716 GList *l;
717 cairo_region_t *shape;
718
719 parent = window->parent;
720
721 if (gdk_window_is_toplevel (window))
722 return;
723
724 /* Convert from from window coords to parent coords */
725 cairo_region_translate (region, window->x, window->y);
726
727 for (l = parent->children; l; l = l->next)
728 {
729 sibling = l->data;
730
731 if (sibling == window)
732 break;
733
734 if (!GDK_WINDOW_IS_MAPPED (sibling) || sibling->input_only || sibling->composited)
735 continue;
736
737 /* Ignore offscreen children, as they don't draw in their parent and
738 * don't take part in the clipping */
739 if (gdk_window_is_offscreen (sibling))
740 continue;
741
742 r.x = sibling->x;
743 r.y = sibling->y;
744 r.width = sibling->width;
745 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 cairo_region_translate (sibling->shape, sibling->x, sibling->y);
753 cairo_region_intersect (child_region, sibling->shape);
754 cairo_region_translate (sibling->shape, -sibling->x, -sibling->y);
755 }
756 else if (window->window_type == GDK_WINDOW_FOREIGN)
757 {
758 shape = GDK_WINDOW_IMPL_GET_CLASS (sibling)->get_shape (sibling);
759 if (shape)
760 {
761 cairo_region_intersect (child_region, shape);
762 cairo_region_destroy (shape);
763 }
764 }
765
766 cairo_region_subtract (region, child_region);
767 cairo_region_destroy (child_region);
768 }
769
770 remove_sibling_overlapped_area (parent, region);
771
772 /* Convert back to window coords */
773 cairo_region_translate (region, -window->x, -window->y);
774 }
775
776 static void
remove_child_area(GdkWindow * window,gboolean for_input,cairo_region_t * region)777 remove_child_area (GdkWindow *window,
778 gboolean for_input,
779 cairo_region_t *region)
780 {
781 GdkWindow *child;
782 cairo_region_t *child_region;
783 GdkRectangle r;
784 GList *l;
785 cairo_region_t *shape;
786
787 for (l = window->children; l; l = l->next)
788 {
789 child = l->data;
790
791 /* If region is empty already, no need to do
792 anything potentially costly */
793 if (cairo_region_is_empty (region))
794 break;
795
796 if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
797 continue;
798
799 /* Ignore offscreen children, as they don't draw in their parent and
800 * don't take part in the clipping */
801 if (gdk_window_is_offscreen (child))
802 continue;
803
804 r.x = child->x;
805 r.y = child->y;
806 r.width = child->width;
807 r.height = child->height;
808
809 /* Bail early if child totally outside region */
810 if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
811 continue;
812
813 child_region = cairo_region_create_rectangle (&r);
814
815 if (child->shape)
816 {
817 /* Adjust shape region to parent window coords */
818 cairo_region_translate (child->shape, child->x, child->y);
819 cairo_region_intersect (child_region, child->shape);
820 cairo_region_translate (child->shape, -child->x, -child->y);
821 }
822 else if (window->window_type == GDK_WINDOW_FOREIGN)
823 {
824 shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_shape (child);
825 if (shape)
826 {
827 cairo_region_intersect (child_region, shape);
828 cairo_region_destroy (shape);
829 }
830 }
831
832 if (for_input)
833 {
834 if (child->input_shape)
835 cairo_region_intersect (child_region, child->input_shape);
836 else if (window->window_type == GDK_WINDOW_FOREIGN)
837 {
838 shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_input_shape (child);
839 if (shape)
840 {
841 cairo_region_intersect (child_region, shape);
842 cairo_region_destroy (shape);
843 }
844 }
845 }
846
847 cairo_region_subtract (region, child_region);
848 cairo_region_destroy (child_region);
849 }
850 }
851
852 static GdkVisibilityState
effective_visibility(GdkWindow * window)853 effective_visibility (GdkWindow *window)
854 {
855 GdkVisibilityState native;
856
857 if (!gdk_window_is_viewable (window))
858 return GDK_VISIBILITY_NOT_VIEWABLE;
859
860 native = window->impl_window->native_visibility;
861
862 if (native == GDK_VISIBILITY_FULLY_OBSCURED ||
863 window->visibility == GDK_VISIBILITY_FULLY_OBSCURED)
864 return GDK_VISIBILITY_FULLY_OBSCURED;
865 else if (native == GDK_VISIBILITY_UNOBSCURED)
866 return window->visibility;
867 else /* native PARTIAL, private partial or unobscured */
868 return GDK_VISIBILITY_PARTIAL;
869 }
870
871 static void
gdk_window_update_visibility(GdkWindow * window)872 gdk_window_update_visibility (GdkWindow *window)
873 {
874 GdkVisibilityState new_visibility;
875 GdkEvent *event;
876
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 NULL, FALSE);
888 event->visibility.state = new_visibility;
889 }
890 }
891 }
892
893 static void
gdk_window_update_visibility_recursively(GdkWindow * window,GdkWindow * only_for_impl)894 gdk_window_update_visibility_recursively (GdkWindow *window,
895 GdkWindow *only_for_impl)
896 {
897 GdkWindow *child;
898 GList *l;
899
900 gdk_window_update_visibility (window);
901 for (l = window->children; l != NULL; l = l->next)
902 {
903 child = l->data;
904 if ((only_for_impl == NULL) ||
905 (only_for_impl == child->impl_window))
906 gdk_window_update_visibility_recursively (child, only_for_impl);
907 }
908 }
909
910 static gboolean
should_apply_clip_as_shape(GdkWindow * window)911 should_apply_clip_as_shape (GdkWindow *window)
912 {
913 return
914 gdk_window_has_impl (window) &&
915 /* Not for offscreens */
916 !gdk_window_is_offscreen (window) &&
917 /* or for non-shaped toplevels */
918 (!gdk_window_is_toplevel (window) ||
919 window->shape != NULL || window->applied_shape) &&
920 /* or for foreign windows */
921 window->window_type != GDK_WINDOW_FOREIGN &&
922 /* or for the root window */
923 window->window_type != GDK_WINDOW_ROOT;
924 }
925
926 static void
apply_shape(GdkWindow * window,cairo_region_t * region)927 apply_shape (GdkWindow *window,
928 cairo_region_t *region)
929 {
930 GdkWindowImplClass *impl_class;
931
932 /* We trash whether we applied a shape so that
933 we can avoid unsetting it many times, which
934 could happen in e.g. apply_clip_as_shape as
935 windows get resized */
936 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
937 if (region)
938 impl_class->shape_combine_region (window,
939 region, 0, 0);
940 else if (window->applied_shape)
941 impl_class->shape_combine_region (window,
942 NULL, 0, 0);
943
944 window->applied_shape = region != NULL;
945 }
946
947 static gboolean
region_rect_equal(const cairo_region_t * region,const GdkRectangle * rect)948 region_rect_equal (const cairo_region_t *region,
949 const GdkRectangle *rect)
950 {
951 GdkRectangle extents;
952
953 if (cairo_region_num_rectangles (region) != 1)
954 return FALSE;
955
956 cairo_region_get_extents (region, &extents);
957
958 return extents.x == rect->x &&
959 extents.y == rect->y &&
960 extents.width == rect->width &&
961 extents.height == rect->height;
962 }
963
964 static void
apply_clip_as_shape(GdkWindow * window)965 apply_clip_as_shape (GdkWindow *window)
966 {
967 GdkRectangle r;
968 cairo_region_t *region;
969
970 r.x = r.y = 0;
971 r.width = window->width;
972 r.height = window->height;
973
974 region = cairo_region_copy (window->clip_region);
975 remove_sibling_overlapped_area (window, region);
976
977 /* We only apply the clip region if would differ
978 from the actual clip region implied by the size
979 of the window. This is to avoid unneccessarily
980 adding meaningless shapes to all native subwindows */
981 if (!region_rect_equal (region, &r))
982 apply_shape (window, region);
983 else
984 apply_shape (window, NULL);
985
986 cairo_region_destroy (region);
987 }
988
989 static void
recompute_visible_regions_internal(GdkWindow * private,gboolean recalculate_clip,gboolean recalculate_children)990 recompute_visible_regions_internal (GdkWindow *private,
991 gboolean recalculate_clip,
992 gboolean recalculate_children)
993 {
994 GdkRectangle r;
995 GList *l;
996 GdkWindow *child;
997 cairo_region_t *new_clip;
998 gboolean clip_region_changed;
999 gboolean abs_pos_changed;
1000 int old_abs_x, old_abs_y;
1001
1002 old_abs_x = private->abs_x;
1003 old_abs_y = private->abs_y;
1004
1005 /* Update absolute position */
1006 if ((gdk_window_has_impl (private) &&
1007 private->window_type != GDK_WINDOW_SUBSURFACE) ||
1008 (gdk_window_is_toplevel (private) &&
1009 private->window_type == GDK_WINDOW_SUBSURFACE))
1010 {
1011 /* Native windows and toplevel subsurfaces start here */
1012 private->abs_x = 0;
1013 private->abs_y = 0;
1014 }
1015 else
1016 {
1017 private->abs_x = private->parent->abs_x + private->x;
1018 private->abs_y = private->parent->abs_y + private->y;
1019 }
1020
1021 abs_pos_changed =
1022 private->abs_x != old_abs_x ||
1023 private->abs_y != old_abs_y;
1024
1025 /* Update clip region based on:
1026 * parent clip
1027 * window size/position
1028 */
1029 clip_region_changed = FALSE;
1030 if (recalculate_clip)
1031 {
1032 if (private->viewable)
1033 {
1034 /* Calculate visible region (sans children) in parent window coords */
1035 r.x = private->x;
1036 r.y = private->y;
1037 r.width = private->width;
1038 r.height = private->height;
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 */
1045 cairo_region_translate (new_clip, -private->x, -private->y);
1046
1047 if (should_apply_clip_as_shape (private) && private->shape)
1048 cairo_region_intersect (new_clip, private->shape);
1049 }
1050 else
1051 new_clip = cairo_region_create ();
1052
1053 if (private->clip_region == NULL ||
1054 !cairo_region_equal (private->clip_region, new_clip))
1055 clip_region_changed = TRUE;
1056
1057 if (private->clip_region)
1058 cairo_region_destroy (private->clip_region);
1059 private->clip_region = new_clip;
1060 }
1061
1062 if (clip_region_changed)
1063 {
1064 GdkVisibilityState visibility;
1065 gboolean fully_visible;
1066
1067 if (cairo_region_is_empty (private->clip_region))
1068 visibility = GDK_VISIBILITY_FULLY_OBSCURED;
1069 else
1070 {
1071 if (private->shape)
1072 {
1073 fully_visible = cairo_region_equal (private->clip_region,
1074 private->shape);
1075 }
1076 else
1077 {
1078 r.x = 0;
1079 r.y = 0;
1080 r.width = private->width;
1081 r.height = private->height;
1082 fully_visible = region_rect_equal (private->clip_region, &r);
1083 }
1084
1085 if (fully_visible)
1086 visibility = GDK_VISIBILITY_UNOBSCURED;
1087 else
1088 visibility = GDK_VISIBILITY_PARTIAL;
1089 }
1090
1091 if (private->visibility != visibility)
1092 {
1093 private->visibility = visibility;
1094 gdk_window_update_visibility (private);
1095 }
1096 }
1097
1098 /* Update all children, recursively (except for root, where children are not exact). */
1099 if ((abs_pos_changed || clip_region_changed || recalculate_children) &&
1100 private->window_type != GDK_WINDOW_ROOT)
1101 {
1102 for (l = private->children; l; l = l->next)
1103 {
1104 child = l->data;
1105 /* Only recalculate clip if the the clip region changed, otherwise
1106 * there is no way the child clip region could change (its has not e.g. moved)
1107 * Except if recalculate_children is set to force child updates
1108 */
1109 recompute_visible_regions_internal (child,
1110 recalculate_clip && (clip_region_changed || recalculate_children),
1111 FALSE);
1112 }
1113 }
1114 }
1115
1116 /* Call this when private has changed in one or more of these ways:
1117 * size changed
1118 * window moved
1119 * new window added
1120 * stacking order of window changed
1121 * child deleted
1122 *
1123 * It will recalculate abs_x/y and the clip regions
1124 *
1125 * Unless the window didn’t change stacking order or size/pos, pass in TRUE
1126 * for recalculate_siblings. (Mostly used internally for the recursion)
1127 *
1128 * If a child window was removed (and you can’t use that child for
1129 * recompute_visible_regions), pass in TRUE for recalculate_children on the parent
1130 */
1131 static void
recompute_visible_regions(GdkWindow * private,gboolean recalculate_children)1132 recompute_visible_regions (GdkWindow *private,
1133 gboolean recalculate_children)
1134 {
1135 GdkWindow *toplevel;
1136
1137 toplevel = gdk_window_get_toplevel (private);
1138 toplevel->geometry_dirty = TRUE;
1139
1140 recompute_visible_regions_internal (private,
1141 TRUE,
1142 recalculate_children);
1143 }
1144
1145 static void
gdk_window_clear_old_updated_area(GdkWindow * window)1146 gdk_window_clear_old_updated_area (GdkWindow *window)
1147 {
1148 int i;
1149
1150 for (i = 0; i < 2; i++)
1151 {
1152 if (window->old_updated_area[i])
1153 {
1154 cairo_region_destroy (window->old_updated_area[i]);
1155 window->old_updated_area[i] = NULL;
1156 }
1157 }
1158 }
1159
1160 static void
gdk_window_append_old_updated_area(GdkWindow * window,cairo_region_t * region)1161 gdk_window_append_old_updated_area (GdkWindow *window,
1162 cairo_region_t *region)
1163 {
1164 if (window->old_updated_area[1])
1165 cairo_region_destroy (window->old_updated_area[1]);
1166 window->old_updated_area[1] = window->old_updated_area[0];
1167 window->old_updated_area[0] = cairo_region_reference (region);
1168 }
1169
1170 void
_gdk_window_update_size(GdkWindow * window)1171 _gdk_window_update_size (GdkWindow *window)
1172 {
1173 gdk_window_clear_old_updated_area (window);
1174 recompute_visible_regions (window, FALSE);
1175 }
1176
1177 /* Find the native window that would be just above "child"
1178 * in the native stacking order if “child” was a native window
1179 * (it doesn’t have to be native). If there is no such native
1180 * window inside this native parent then NULL is returned.
1181 * If child is NULL, find lowest native window in parent.
1182 */
1183 static GdkWindow *
find_native_sibling_above_helper(GdkWindow * parent,GdkWindow * child)1184 find_native_sibling_above_helper (GdkWindow *parent,
1185 GdkWindow *child)
1186 {
1187 GdkWindow *w;
1188 GList *l;
1189
1190 if (child)
1191 {
1192 l = g_list_find (parent->children, child);
1193 g_assert (l != NULL); /* Better be a child of its parent... */
1194 l = l->prev; /* Start looking at the one above the child */
1195 }
1196 else
1197 l = g_list_last (parent->children);
1198
1199 for (; l != NULL; l = l->prev)
1200 {
1201 w = l->data;
1202
1203 if (gdk_window_has_impl (w))
1204 return w;
1205
1206 g_assert (parent != w);
1207 w = find_native_sibling_above_helper (w, NULL);
1208 if (w)
1209 return w;
1210 }
1211
1212 return NULL;
1213 }
1214
1215
1216 static GdkWindow *
find_native_sibling_above(GdkWindow * parent,GdkWindow * child)1217 find_native_sibling_above (GdkWindow *parent,
1218 GdkWindow *child)
1219 {
1220 GdkWindow *w;
1221
1222 if (!parent)
1223 return NULL;
1224
1225 w = find_native_sibling_above_helper (parent, child);
1226 if (w)
1227 return w;
1228
1229 if (gdk_window_has_impl (parent))
1230 return NULL;
1231 else
1232 return find_native_sibling_above (parent->parent, parent);
1233 }
1234
1235 static GdkEventMask
get_native_device_event_mask(GdkWindow * private,GdkDevice * device)1236 get_native_device_event_mask (GdkWindow *private,
1237 GdkDevice *device)
1238 {
1239 GdkEventMask event_mask;
1240
1241 if (device)
1242 event_mask = GPOINTER_TO_INT (g_hash_table_lookup (private->device_events, device));
1243 else
1244 event_mask = private->event_mask;
1245
1246 if (private->window_type == GDK_WINDOW_ROOT ||
1247 private->window_type == GDK_WINDOW_FOREIGN)
1248 return event_mask;
1249 else
1250 {
1251 GdkEventMask mask;
1252
1253 /* Do whatever the app asks to, since the app
1254 * may be asking for weird things for native windows,
1255 * but don't use motion hints as that may affect non-native
1256 * child windows that don't want it. Also, we need to
1257 * set all the app-specified masks since they will be picked
1258 * up by any implicit grabs (i.e. if they were not set as
1259 * native we would not get the events we need). */
1260 mask = private->event_mask & ~GDK_POINTER_MOTION_HINT_MASK;
1261
1262 /* We need thse for all native windows so we can
1263 emulate events on children: */
1264 mask |=
1265 GDK_EXPOSURE_MASK |
1266 GDK_VISIBILITY_NOTIFY_MASK |
1267 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK;
1268
1269 /* Additionally we select for pointer and button events
1270 * for toplevels as we need to get these to emulate
1271 * them for non-native subwindows. Even though we don't
1272 * select on them for all native windows we will get them
1273 * as the events are propagated out to the first window
1274 * that select for them.
1275 * Not selecting for button press on all windows is an
1276 * important thing, because in X only one client can do
1277 * so, and we don't want to unexpectedly prevent another
1278 * client from doing it.
1279 *
1280 * We also need to do the same if the app selects for button presses
1281 * because then we will get implicit grabs for this window, and the
1282 * event mask used for that grab is based on the rest of the mask
1283 * for the window, but we might need more events than this window
1284 * lists due to some non-native child window.
1285 */
1286 if (gdk_window_is_toplevel (private) ||
1287 mask & GDK_BUTTON_PRESS_MASK)
1288 mask |=
1289 GDK_TOUCH_MASK | GDK_TOUCHPAD_GESTURE_MASK |
1290 GDK_POINTER_MOTION_MASK |
1291 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1292 GDK_SCROLL_MASK;
1293
1294 return mask;
1295 }
1296 }
1297
1298 static GdkEventMask
get_native_grab_event_mask(GdkEventMask grab_mask)1299 get_native_grab_event_mask (GdkEventMask grab_mask)
1300 {
1301 /* Similar to the above but for pointer events only */
1302 return
1303 GDK_POINTER_MOTION_MASK |
1304 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1305 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
1306 GDK_SCROLL_MASK |
1307 (grab_mask &
1308 ~GDK_POINTER_MOTION_HINT_MASK);
1309 }
1310
1311 static GdkEventMask
get_native_event_mask(GdkWindow * private)1312 get_native_event_mask (GdkWindow *private)
1313 {
1314 return get_native_device_event_mask (private, NULL);
1315 }
1316
1317 /* Puts the native window in the right order wrt the other native windows
1318 * in the hierarchy, given the position it has in the client side data.
1319 * This is useful if some operation changed the stacking order.
1320 * This calls assumes the native window is now topmost in its native parent.
1321 */
1322 static void
sync_native_window_stack_position(GdkWindow * window)1323 sync_native_window_stack_position (GdkWindow *window)
1324 {
1325 GdkWindow *above;
1326 GdkWindowImplClass *impl_class;
1327 GList listhead = {0};
1328
1329 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
1330
1331 above = find_native_sibling_above (window->parent, window);
1332 if (above)
1333 {
1334 listhead.data = window;
1335 impl_class->restack_under (above, &listhead);
1336 }
1337 }
1338
1339 /**
1340 * gdk_window_new: (constructor)
1341 * @parent: (allow-none): a #GdkWindow, or %NULL to create the window as a child of
1342 * the default root window for the default display.
1343 * @attributes: attributes of the new window
1344 * @attributes_mask: (type GdkWindowAttributesType): mask indicating which
1345 * fields in @attributes are valid
1346 *
1347 * Creates a new #GdkWindow using the attributes from
1348 * @attributes. See #GdkWindowAttr and #GdkWindowAttributesType for
1349 * more details. Note: to use this on displays other than the default
1350 * display, @parent must be specified.
1351 *
1352 * Returns: (transfer full): the new #GdkWindow
1353 **/
1354 GdkWindow*
gdk_window_new(GdkWindow * parent,GdkWindowAttr * attributes,gint attributes_mask)1355 gdk_window_new (GdkWindow *parent,
1356 GdkWindowAttr *attributes,
1357 gint attributes_mask)
1358 {
1359 GdkWindow *window;
1360 GdkScreen *screen;
1361 GdkDisplay *display;
1362 int x, y;
1363 gboolean native;
1364 GdkEventMask event_mask;
1365 GdkWindow *real_parent;
1366
1367 g_return_val_if_fail (attributes != NULL, NULL);
1368
1369 if (!parent)
1370 {
1371 screen = gdk_screen_get_default ();
1372 parent = gdk_screen_get_root_window (screen);
1373 }
1374 else
1375 screen = gdk_window_get_screen (parent);
1376
1377 g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL);
1378
1379 if (GDK_WINDOW_DESTROYED (parent))
1380 {
1381 g_warning ("gdk_window_new(): parent is destroyed");
1382 return NULL;
1383 }
1384
1385 if (attributes_mask & GDK_WA_VISUAL)
1386 {
1387 g_return_val_if_fail (gdk_visual_get_screen (attributes->visual) == screen, NULL);
1388 }
1389
1390 display = gdk_screen_get_display (screen);
1391
1392 window = _gdk_display_create_window (display);
1393
1394 /* Windows with a foreign parent are treated as if they are children
1395 * of the root window, except for actual creation.
1396 */
1397 real_parent = parent;
1398 if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN)
1399 parent = gdk_screen_get_root_window (screen);
1400
1401 window->parent = parent;
1402
1403 window->accept_focus = TRUE;
1404 window->focus_on_map = TRUE;
1405 window->event_compression = TRUE;
1406
1407 if (attributes_mask & GDK_WA_X)
1408 x = attributes->x;
1409 else
1410 x = 0;
1411
1412 if (attributes_mask & GDK_WA_Y)
1413 y = attributes->y;
1414 else
1415 y = 0;
1416
1417 window->x = x;
1418 window->y = y;
1419 window->width = (attributes->width > 1) ? (attributes->width) : (1);
1420 window->height = (attributes->height > 1) ? (attributes->height) : (1);
1421 window->alpha = 255;
1422
1423 if (attributes->wclass == GDK_INPUT_ONLY)
1424 {
1425 /* Backwards compatiblity - we've always ignored
1426 * attributes->window_type for input-only windows
1427 * before
1428 */
1429 if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT)
1430 window->window_type = GDK_WINDOW_TEMP;
1431 else
1432 window->window_type = GDK_WINDOW_CHILD;
1433 }
1434 else
1435 window->window_type = attributes->window_type;
1436
1437 /* Sanity checks */
1438 switch (window->window_type)
1439 {
1440 case GDK_WINDOW_TOPLEVEL:
1441 case GDK_WINDOW_TEMP:
1442 case GDK_WINDOW_OFFSCREEN:
1443 if (GDK_WINDOW_TYPE (parent) != GDK_WINDOW_ROOT)
1444 g_warning (G_STRLOC "Toplevel windows must be created as children of\n"
1445 "of a window of type GDK_WINDOW_ROOT or GDK_WINDOW_FOREIGN");
1446 break;
1447 case GDK_WINDOW_SUBSURFACE:
1448 #ifdef GDK_WINDOWING_WAYLAND
1449 if (!GDK_IS_WAYLAND_DISPLAY (display))
1450 {
1451 g_warning (G_STRLOC "Subsurface windows can only be used on Wayland");
1452 return NULL;
1453 }
1454 #endif
1455 break;
1456 case GDK_WINDOW_CHILD:
1457 break;
1458 default:
1459 g_warning (G_STRLOC "cannot make windows of type %d", window->window_type);
1460 return NULL;
1461 }
1462
1463 if (attributes_mask & GDK_WA_VISUAL)
1464 window->visual = attributes->visual;
1465 else
1466 window->visual = gdk_screen_get_system_visual (screen);
1467
1468 window->event_mask = attributes->event_mask;
1469
1470 if (attributes->wclass == GDK_INPUT_OUTPUT)
1471 {
1472 window->input_only = FALSE;
1473 window->depth = window->visual->depth;
1474
1475 /* XXX: Cache this somehow? */
1476 window->background = cairo_pattern_create_rgba (0, 0, 0, 0);
1477 }
1478 else
1479 {
1480 window->depth = 0;
1481 window->input_only = TRUE;
1482 }
1483
1484 window->parent->children = g_list_concat (&window->children_list_node, window->parent->children);
1485
1486 if (window->parent->window_type == GDK_WINDOW_ROOT)
1487 {
1488 GdkFrameClock *frame_clock = g_object_new (GDK_TYPE_FRAME_CLOCK_IDLE, NULL);
1489 gdk_window_set_frame_clock (window, frame_clock);
1490 g_object_unref (frame_clock);
1491 }
1492
1493 native = FALSE;
1494 if (window->parent->window_type == GDK_WINDOW_ROOT)
1495 native = TRUE; /* Always use native windows for toplevels */
1496
1497 #ifdef GDK_WINDOWING_WAYLAND
1498 if (window->window_type == GDK_WINDOW_SUBSURFACE)
1499 native = TRUE; /* Always use native windows for subsurfaces as well */
1500 #endif
1501
1502 if (gdk_window_is_offscreen (window))
1503 {
1504 _gdk_offscreen_window_new (window, attributes, attributes_mask);
1505 window->impl_window = window;
1506 }
1507 else if (native)
1508 {
1509 event_mask = get_native_event_mask (window);
1510
1511 /* Create the impl */
1512 _gdk_display_create_window_impl (display, window, real_parent, screen, event_mask, attributes, attributes_mask);
1513 window->impl_window = window;
1514
1515 parent->impl_window->native_children = g_list_prepend (parent->impl_window->native_children, window);
1516
1517 /* This will put the native window topmost in the native parent, which may
1518 * be wrong wrt other native windows in the non-native hierarchy, so restack */
1519 if (!_gdk_window_has_impl (real_parent))
1520 sync_native_window_stack_position (window);
1521 }
1522 else
1523 {
1524 window->impl_window = g_object_ref (window->parent->impl_window);
1525 window->impl = g_object_ref (window->impl_window->impl);
1526 }
1527
1528 recompute_visible_regions (window, FALSE);
1529
1530 gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
1531 (attributes->cursor) :
1532 NULL));
1533
1534 g_signal_connect (gdk_window_get_display (parent), "seat-removed",
1535 G_CALLBACK (seat_removed_cb), window);
1536
1537 if ((_gdk_gl_flags & (GDK_GL_ALWAYS | GDK_GL_DISABLE)) == GDK_GL_ALWAYS)
1538 {
1539 GError *error = NULL;
1540
1541 if (gdk_window_get_paint_gl_context (window, &error) == NULL)
1542 {
1543 g_warning ("Unable to force GL enabled: %s", error->message);
1544 g_error_free (error);
1545 }
1546 }
1547
1548 return window;
1549 }
1550
1551 static gboolean
is_parent_of(GdkWindow * parent,GdkWindow * child)1552 is_parent_of (GdkWindow *parent,
1553 GdkWindow *child)
1554 {
1555 GdkWindow *w;
1556
1557 w = child;
1558 while (w != NULL)
1559 {
1560 if (w == parent)
1561 return TRUE;
1562
1563 w = gdk_window_get_parent (w);
1564 }
1565
1566 return FALSE;
1567 }
1568
1569 static void
change_impl(GdkWindow * private,GdkWindow * impl_window,GdkWindowImpl * new)1570 change_impl (GdkWindow *private,
1571 GdkWindow *impl_window,
1572 GdkWindowImpl *new)
1573 {
1574 GList *l;
1575 GdkWindow *child;
1576 GdkWindowImpl *old_impl;
1577 GdkWindow *old_impl_window;
1578
1579 old_impl = private->impl;
1580 old_impl_window = private->impl_window;
1581 if (private != impl_window)
1582 private->impl_window = g_object_ref (impl_window);
1583 else
1584 private->impl_window = private;
1585 private->impl = g_object_ref (new);
1586 if (old_impl_window != private)
1587 g_object_unref (old_impl_window);
1588 g_object_unref (old_impl);
1589
1590 for (l = private->children; l != NULL; l = l->next)
1591 {
1592 child = l->data;
1593
1594 if (child->impl == old_impl)
1595 change_impl (child, impl_window, new);
1596 else
1597 {
1598 /* The child is a native, update native_children */
1599 old_impl_window->native_children =
1600 g_list_remove (old_impl_window->native_children, child);
1601 impl_window->native_children =
1602 g_list_prepend (impl_window->native_children, child);
1603 }
1604 }
1605 }
1606
1607 static void
reparent_to_impl(GdkWindow * private)1608 reparent_to_impl (GdkWindow *private)
1609 {
1610 GList *l;
1611 GdkWindow *child;
1612 gboolean show;
1613 GdkWindowImplClass *impl_class;
1614
1615 impl_class = GDK_WINDOW_IMPL_GET_CLASS (private->impl);
1616
1617 /* Enumerate in reverse order so we get the right order for the native
1618 windows (first in childrens list is topmost, and reparent places on top) */
1619 for (l = g_list_last (private->children); l != NULL; l = l->prev)
1620 {
1621 child = l->data;
1622
1623 if (child->impl == private->impl)
1624 reparent_to_impl (child);
1625 else
1626 {
1627 show = impl_class->reparent ((GdkWindow *)child,
1628 (GdkWindow *)private,
1629 child->x, child->y);
1630 if (show)
1631 gdk_window_show_unraised ((GdkWindow *)child);
1632 }
1633 }
1634 }
1635
1636
1637 /**
1638 * gdk_window_reparent:
1639 * @window: a #GdkWindow
1640 * @new_parent: new parent to move @window into
1641 * @x: X location inside the new parent
1642 * @y: Y location inside the new parent
1643 *
1644 * Reparents @window into the given @new_parent. The window being
1645 * reparented will be unmapped as a side effect.
1646 *
1647 **/
1648 void
gdk_window_reparent(GdkWindow * window,GdkWindow * new_parent,gint x,gint y)1649 gdk_window_reparent (GdkWindow *window,
1650 GdkWindow *new_parent,
1651 gint x,
1652 gint y)
1653 {
1654 GdkWindow *old_parent;
1655 GdkScreen *screen;
1656 gboolean show, was_mapped;
1657 gboolean do_reparent_to_impl;
1658 GdkEventMask old_native_event_mask;
1659 GdkWindowImplClass *impl_class;
1660
1661 g_return_if_fail (GDK_IS_WINDOW (window));
1662 g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent));
1663 g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
1664
1665 if (GDK_WINDOW_DESTROYED (window) ||
1666 (new_parent && GDK_WINDOW_DESTROYED (new_parent)))
1667 return;
1668
1669 screen = gdk_window_get_screen (window);
1670 if (!new_parent)
1671 new_parent = gdk_screen_get_root_window (screen);
1672
1673 /* No input-output children of input-only windows */
1674 if (new_parent->input_only && !window->input_only)
1675 return;
1676
1677 /* Don't create loops in hierarchy */
1678 if (is_parent_of (window, new_parent))
1679 return;
1680
1681 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
1682 old_parent = window->parent;
1683
1684 was_mapped = GDK_WINDOW_IS_MAPPED (window);
1685
1686 /* Reparenting to toplevel. Ensure we have a native window so this can work */
1687 if (new_parent->window_type == GDK_WINDOW_ROOT ||
1688 new_parent->window_type == GDK_WINDOW_FOREIGN)
1689 gdk_window_ensure_native (window);
1690
1691 old_native_event_mask = 0;
1692 do_reparent_to_impl = FALSE;
1693 if (gdk_window_has_impl (window))
1694 {
1695 old_native_event_mask = get_native_event_mask (window);
1696 /* Native window */
1697 show = impl_class->reparent (window, new_parent, x, y);
1698 }
1699 else
1700 {
1701 /* This shouldn't happen, as we created a native in this case, check anyway to see if that ever fails */
1702 g_assert (new_parent->window_type != GDK_WINDOW_ROOT &&
1703 new_parent->window_type != GDK_WINDOW_FOREIGN);
1704
1705 show = was_mapped;
1706 gdk_window_hide (window);
1707
1708 do_reparent_to_impl = TRUE;
1709 change_impl (window,
1710 new_parent->impl_window,
1711 new_parent->impl);
1712 }
1713
1714 /* From here on, we treat parents of type GDK_WINDOW_FOREIGN like
1715 * the root window
1716 */
1717 if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
1718 {
1719 new_parent = gdk_screen_get_root_window (screen);
1720 }
1721
1722 if (old_parent)
1723 {
1724 old_parent->children = g_list_remove_link (old_parent->children, &window->children_list_node);
1725
1726 if (gdk_window_has_impl (window))
1727 old_parent->impl_window->native_children =
1728 g_list_remove (old_parent->impl_window->native_children, window);
1729 }
1730
1731 window->parent = new_parent;
1732 window->x = x;
1733 window->y = y;
1734
1735 new_parent->children = g_list_concat (&window->children_list_node, new_parent->children);
1736
1737 if (gdk_window_has_impl (window))
1738 new_parent->impl_window->native_children = g_list_prepend (new_parent->impl_window->native_children, window);
1739
1740 /* Switch the window type as appropriate */
1741
1742 switch (GDK_WINDOW_TYPE (new_parent))
1743 {
1744 case GDK_WINDOW_ROOT:
1745 case GDK_WINDOW_FOREIGN:
1746 if (window->toplevel_window_type != -1)
1747 GDK_WINDOW_TYPE (window) = window->toplevel_window_type;
1748 else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1749 GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL;
1750 break;
1751 case GDK_WINDOW_OFFSCREEN:
1752 case GDK_WINDOW_TOPLEVEL:
1753 case GDK_WINDOW_CHILD:
1754 case GDK_WINDOW_TEMP:
1755 if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \
1756 GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
1757 {
1758 /* Save the original window type so we can restore it if the
1759 * window is reparented back to be a toplevel
1760 */
1761 window->toplevel_window_type = GDK_WINDOW_TYPE (window);
1762 GDK_WINDOW_TYPE (window) = GDK_WINDOW_CHILD;
1763 }
1764 }
1765
1766 /* If we changed the window type, we might have to set or
1767 * unset the frame clock on the window
1768 */
1769 if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_ROOT &&
1770 GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
1771 {
1772 if (window->frame_clock == NULL)
1773 {
1774 GdkFrameClock *frame_clock = g_object_new (GDK_TYPE_FRAME_CLOCK_IDLE, NULL);
1775 gdk_window_set_frame_clock (window, frame_clock);
1776 g_object_unref (frame_clock);
1777 }
1778 }
1779 else
1780 {
1781 if (window->frame_clock != NULL)
1782 {
1783 g_object_run_dispose (G_OBJECT (window->frame_clock));
1784 gdk_window_set_frame_clock (window, NULL);
1785 }
1786 }
1787
1788 /* We might have changed window type for a native windows, so we
1789 need to change the event mask too. */
1790 if (gdk_window_has_impl (window))
1791 {
1792 GdkEventMask native_event_mask = get_native_event_mask (window);
1793
1794 if (native_event_mask != old_native_event_mask)
1795 impl_class->set_events (window, native_event_mask);
1796 }
1797
1798 _gdk_window_update_viewable (window);
1799
1800 recompute_visible_regions (window, FALSE);
1801
1802 if (do_reparent_to_impl)
1803 reparent_to_impl (window);
1804 else
1805 {
1806 /* The reparent will have put the native window topmost in the native parent,
1807 * which may be wrong wrt other native windows in the non-native hierarchy,
1808 * so restack */
1809 if (!gdk_window_has_impl (new_parent))
1810 sync_native_window_stack_position (window);
1811 }
1812
1813 if (show)
1814 gdk_window_show_unraised (window);
1815 else
1816 _gdk_synthesize_crossing_events_for_geometry_change (window);
1817 }
1818
1819 /**
1820 * gdk_window_ensure_native:
1821 * @window: a #GdkWindow
1822 *
1823 * Tries to ensure that there is a window-system native window for this
1824 * GdkWindow. This may fail in some situations, returning %FALSE.
1825 *
1826 * Offscreen window and children of them can never have native windows.
1827 *
1828 * Some backends may not support native child windows.
1829 *
1830 * Returns: %TRUE if the window has a native window, %FALSE otherwise
1831 *
1832 * Since: 2.18
1833 */
1834 gboolean
gdk_window_ensure_native(GdkWindow * window)1835 gdk_window_ensure_native (GdkWindow *window)
1836 {
1837 GdkWindow *impl_window;
1838 GdkWindowImpl *new_impl, *old_impl;
1839 GdkDisplay *display;
1840 GdkScreen *screen;
1841 GdkWindow *above, *parent;
1842 GList listhead;
1843 GdkWindowImplClass *impl_class;
1844
1845 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
1846
1847 if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT ||
1848 GDK_WINDOW_DESTROYED (window))
1849 return FALSE;
1850
1851 impl_window = gdk_window_get_impl_window (window);
1852
1853 if (gdk_window_is_offscreen (impl_window))
1854 return FALSE; /* native in offscreens not supported */
1855
1856 if (impl_window == window)
1857 /* Already has an impl, and its not offscreen . */
1858 return TRUE;
1859
1860 /* Need to create a native window */
1861
1862 screen = gdk_window_get_screen (window);
1863 display = gdk_screen_get_display (screen);
1864 parent = window->parent;
1865
1866 old_impl = window->impl;
1867 _gdk_display_create_window_impl (display,
1868 window, parent,
1869 screen,
1870 get_native_event_mask (window),
1871 NULL, 0);
1872 new_impl = window->impl;
1873
1874 parent->impl_window->native_children =
1875 g_list_prepend (parent->impl_window->native_children, window);
1876
1877 window->impl = old_impl;
1878 change_impl (window, window, new_impl);
1879
1880 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
1881
1882 /* Native window creation will put the native window topmost in the
1883 * native parent, which may be wrong wrt the position of the previous
1884 * non-native window wrt to the other non-native children, so correct this.
1885 */
1886 above = find_native_sibling_above (parent, window);
1887 if (above)
1888 {
1889 listhead.data = window;
1890 listhead.prev = NULL;
1891 listhead.next = NULL;
1892 impl_class->restack_under ((GdkWindow *)above, &listhead);
1893 }
1894
1895 recompute_visible_regions (window, FALSE);
1896
1897 reparent_to_impl (window);
1898
1899 if (!window->input_only)
1900 impl_class->set_background (window, window->background);
1901
1902 impl_class->input_shape_combine_region (window,
1903 window->input_shape,
1904 0, 0);
1905
1906 if (gdk_window_is_viewable (window))
1907 impl_class->show (window, FALSE);
1908
1909 gdk_window_invalidate_in_parent (window);
1910
1911 return TRUE;
1912 }
1913
1914 /**
1915 * _gdk_event_filter_unref:
1916 * @window: (allow-none): A #GdkWindow, or %NULL to be the global window
1917 * @filter: A window filter
1918 *
1919 * Release a reference to @filter. Note this function may
1920 * mutate the list storage, so you need to handle this
1921 * if iterating over a list of filters.
1922 */
1923 void
_gdk_event_filter_unref(GdkWindow * window,GdkEventFilter * filter)1924 _gdk_event_filter_unref (GdkWindow *window,
1925 GdkEventFilter *filter)
1926 {
1927 GList **filters;
1928 GList *tmp_list;
1929
1930 if (window == NULL)
1931 filters = &_gdk_default_filters;
1932 else
1933 filters = &window->filters;
1934
1935 tmp_list = *filters;
1936 while (tmp_list)
1937 {
1938 GdkEventFilter *iter_filter = tmp_list->data;
1939 GList *node;
1940
1941 node = tmp_list;
1942 tmp_list = tmp_list->next;
1943
1944 if (iter_filter != filter)
1945 continue;
1946
1947 g_assert (iter_filter->ref_count > 0);
1948
1949 filter->ref_count--;
1950 if (filter->ref_count != 0)
1951 continue;
1952
1953 *filters = g_list_remove_link (*filters, node);
1954 g_free (filter);
1955 g_list_free_1 (node);
1956 }
1957 }
1958
1959 static void
window_remove_filters(GdkWindow * window)1960 window_remove_filters (GdkWindow *window)
1961 {
1962 while (window->filters)
1963 _gdk_event_filter_unref (window, window->filters->data);
1964 }
1965
1966 static void
update_pointer_info_foreach(GdkDisplay * display,GdkDevice * device,GdkPointerWindowInfo * pointer_info,gpointer user_data)1967 update_pointer_info_foreach (GdkDisplay *display,
1968 GdkDevice *device,
1969 GdkPointerWindowInfo *pointer_info,
1970 gpointer user_data)
1971 {
1972 GdkWindow *window = user_data;
1973
1974 if (pointer_info->toplevel_under_pointer == window)
1975 {
1976 g_object_unref (pointer_info->toplevel_under_pointer);
1977 pointer_info->toplevel_under_pointer = NULL;
1978 }
1979 }
1980
1981 static void
window_remove_from_pointer_info(GdkWindow * window,GdkDisplay * display)1982 window_remove_from_pointer_info (GdkWindow *window,
1983 GdkDisplay *display)
1984 {
1985 _gdk_display_pointer_info_foreach (display,
1986 update_pointer_info_foreach,
1987 window);
1988 }
1989
1990 static void
gdk_window_free_current_paint(GdkWindow * window)1991 gdk_window_free_current_paint (GdkWindow *window)
1992 {
1993 cairo_surface_destroy (window->current_paint.surface);
1994 window->current_paint.surface = NULL;
1995
1996 cairo_region_destroy (window->current_paint.region);
1997 window->current_paint.region = NULL;
1998
1999 cairo_region_destroy (window->current_paint.flushed_region);
2000 window->current_paint.flushed_region = NULL;
2001
2002 cairo_region_destroy (window->current_paint.need_blend_region);
2003 window->current_paint.need_blend_region = NULL;
2004
2005 window->current_paint.surface_needs_composite = FALSE;
2006 }
2007
2008 /**
2009 * _gdk_window_destroy_hierarchy:
2010 * @window: a #GdkWindow
2011 * @recursing: If %TRUE, then this is being called because a parent
2012 * was destroyed.
2013 * @recursing_native: If %TRUE, then this is being called because a native parent
2014 * was destroyed. This generally means that the call to the
2015 * windowing system to destroy the window can be omitted, since
2016 * it will be destroyed as a result of the parent being destroyed.
2017 * Unless @foreign_destroy.
2018 * @foreign_destroy: If %TRUE, the window or a parent was destroyed by some
2019 * external agency. The window has already been destroyed and no
2020 * windowing system calls should be made. (This may never happen
2021 * for some windowing systems.)
2022 *
2023 * Internal function to destroy a window. Like gdk_window_destroy(),
2024 * but does not drop the reference count created by gdk_window_new().
2025 **/
2026 static void
_gdk_window_destroy_hierarchy(GdkWindow * window,gboolean recursing,gboolean recursing_native,gboolean foreign_destroy)2027 _gdk_window_destroy_hierarchy (GdkWindow *window,
2028 gboolean recursing,
2029 gboolean recursing_native,
2030 gboolean foreign_destroy)
2031 {
2032 GdkWindowImplClass *impl_class;
2033 GdkWindow *temp_window;
2034 GdkScreen *screen;
2035 GdkDisplay *display;
2036 GList *tmp;
2037
2038 g_return_if_fail (GDK_IS_WINDOW (window));
2039
2040 if (GDK_WINDOW_DESTROYED (window))
2041 return;
2042
2043 display = gdk_window_get_display (window);
2044 screen = gdk_window_get_screen (window);
2045 temp_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
2046 if (temp_window == window)
2047 g_object_set_qdata (G_OBJECT (screen), quark_pointer_window, NULL);
2048
2049 switch (window->window_type)
2050 {
2051 case GDK_WINDOW_ROOT:
2052 if (!screen->closed)
2053 {
2054 g_error ("attempted to destroy root window");
2055 break;
2056 }
2057 /* else fall thru */
2058 case GDK_WINDOW_TOPLEVEL:
2059 case GDK_WINDOW_CHILD:
2060 case GDK_WINDOW_TEMP:
2061 case GDK_WINDOW_FOREIGN:
2062 case GDK_WINDOW_OFFSCREEN:
2063 case GDK_WINDOW_SUBSURFACE:
2064 if (window->window_type == GDK_WINDOW_FOREIGN && !foreign_destroy)
2065 {
2066 /* Logically, it probably makes more sense to send
2067 * a "destroy yourself" message to the foreign window
2068 * whether or not it's in our hierarchy; but for historical
2069 * reasons, we only send "destroy yourself" messages to
2070 * foreign windows in our hierarchy.
2071 */
2072 if (window->parent)
2073 {
2074 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
2075
2076 if (gdk_window_has_impl (window))
2077 impl_class->destroy_foreign (window);
2078 }
2079
2080 /* Also for historical reasons, we remove any filters
2081 * on a foreign window when it or a parent is destroyed;
2082 * this likely causes problems if two separate portions
2083 * of code are maintaining filter lists on a foreign window.
2084 */
2085 window_remove_filters (window);
2086 }
2087 else
2088 {
2089 if (window->parent)
2090 {
2091 if (window->parent->children)
2092 window->parent->children = g_list_remove_link (window->parent->children, &window->children_list_node);
2093
2094 if (gdk_window_has_impl (window))
2095 window->parent->impl_window->native_children =
2096 g_list_remove (window->parent->impl_window->native_children, window);
2097
2098 if (!recursing &&
2099 GDK_WINDOW_IS_MAPPED (window))
2100 {
2101 recompute_visible_regions (window, FALSE);
2102 gdk_window_invalidate_in_parent (window);
2103 }
2104 }
2105
2106 if (window->gl_paint_context)
2107 {
2108 /* Make sure to destroy if current */
2109 g_object_run_dispose (G_OBJECT (window->gl_paint_context));
2110 g_object_unref (window->gl_paint_context);
2111 window->gl_paint_context = NULL;
2112 }
2113
2114 if (window->frame_clock)
2115 {
2116 g_object_run_dispose (G_OBJECT (window->frame_clock));
2117 gdk_window_set_frame_clock (window, NULL);
2118 }
2119
2120 gdk_window_free_current_paint (window);
2121
2122 if (window->background)
2123 {
2124 cairo_pattern_destroy (window->background);
2125 window->background = NULL;
2126 }
2127
2128 if (window->window_type == GDK_WINDOW_FOREIGN)
2129 g_assert (window->children == NULL);
2130 else
2131 {
2132 tmp = window->children;
2133 window->children = NULL;
2134 /* No need to free children list, its all made up of in-struct nodes */
2135
2136 while (tmp)
2137 {
2138 temp_window = tmp->data;
2139 tmp = tmp->next;
2140
2141 if (temp_window)
2142 _gdk_window_destroy_hierarchy (temp_window,
2143 TRUE,
2144 recursing_native || gdk_window_has_impl (window),
2145 foreign_destroy);
2146 }
2147
2148
2149 if (gdk_window_has_impl (window))
2150 g_assert (window->native_children == NULL);
2151 }
2152
2153 _gdk_window_clear_update_area (window);
2154
2155 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
2156
2157 if (gdk_window_has_impl (window))
2158 impl_class->destroy (window, recursing_native, foreign_destroy);
2159 else
2160 {
2161 /* hide to make sure we repaint and break grabs */
2162 gdk_window_hide (window);
2163 }
2164
2165 window->state |= GDK_WINDOW_STATE_WITHDRAWN;
2166 window->parent = NULL;
2167 window->destroyed = TRUE;
2168
2169 window_remove_filters (window);
2170
2171 window_remove_from_pointer_info (window, display);
2172
2173 if (window->clip_region)
2174 {
2175 cairo_region_destroy (window->clip_region);
2176 window->clip_region = NULL;
2177 }
2178 }
2179 break;
2180 }
2181 }
2182
2183 /**
2184 * _gdk_window_destroy:
2185 * @window: a #GdkWindow
2186 * @foreign_destroy: If %TRUE, the window or a parent was destroyed by some
2187 * external agency. The window has already been destroyed and no
2188 * windowing system calls should be made. (This may never happen
2189 * for some windowing systems.)
2190 *
2191 * Internal function to destroy a window. Like gdk_window_destroy(),
2192 * but does not drop the reference count created by gdk_window_new().
2193 **/
2194 void
_gdk_window_destroy(GdkWindow * window,gboolean foreign_destroy)2195 _gdk_window_destroy (GdkWindow *window,
2196 gboolean foreign_destroy)
2197 {
2198 _gdk_window_destroy_hierarchy (window, FALSE, FALSE, foreign_destroy);
2199 }
2200
2201 /**
2202 * gdk_window_destroy:
2203 * @window: a #GdkWindow
2204 *
2205 * Destroys the window system resources associated with @window and decrements @window's
2206 * reference count. The window system resources for all children of @window are also
2207 * destroyed, but the children’s reference counts are not decremented.
2208 *
2209 * Note that a window will not be destroyed automatically when its reference count
2210 * reaches zero. You must call this function yourself before that happens.
2211 *
2212 **/
2213 void
gdk_window_destroy(GdkWindow * window)2214 gdk_window_destroy (GdkWindow *window)
2215 {
2216 _gdk_window_destroy_hierarchy (window, FALSE, FALSE, FALSE);
2217 g_object_unref (window);
2218 }
2219
2220 /**
2221 * gdk_window_set_user_data:
2222 * @window: a #GdkWindow
2223 * @user_data: (allow-none) (type GObject.Object): user data
2224 *
2225 * For most purposes this function is deprecated in favor of
2226 * g_object_set_data(). However, for historical reasons GTK+ stores
2227 * the #GtkWidget that owns a #GdkWindow as user data on the
2228 * #GdkWindow. So, custom widget implementations should use
2229 * this function for that. If GTK+ receives an event for a #GdkWindow,
2230 * and the user data for the window is non-%NULL, GTK+ will assume the
2231 * user data is a #GtkWidget, and forward the event to that widget.
2232 *
2233 **/
2234 void
gdk_window_set_user_data(GdkWindow * window,gpointer user_data)2235 gdk_window_set_user_data (GdkWindow *window,
2236 gpointer user_data)
2237 {
2238 g_return_if_fail (GDK_IS_WINDOW (window));
2239
2240 window->user_data = user_data;
2241 }
2242
2243 /**
2244 * gdk_window_get_user_data:
2245 * @window: a #GdkWindow
2246 * @data: (out): return location for user data
2247 *
2248 * Retrieves the user data for @window, which is normally the widget
2249 * that @window belongs to. See gdk_window_set_user_data().
2250 *
2251 **/
2252 void
gdk_window_get_user_data(GdkWindow * window,gpointer * data)2253 gdk_window_get_user_data (GdkWindow *window,
2254 gpointer *data)
2255 {
2256 *data = window->user_data;
2257 }
2258
2259 /**
2260 * gdk_window_get_window_type:
2261 * @window: a #GdkWindow
2262 *
2263 * Gets the type of the window. See #GdkWindowType.
2264 *
2265 * Returns: type of window
2266 **/
2267 GdkWindowType
gdk_window_get_window_type(GdkWindow * window)2268 gdk_window_get_window_type (GdkWindow *window)
2269 {
2270 g_return_val_if_fail (GDK_IS_WINDOW (window), (GdkWindowType) -1);
2271
2272 return GDK_WINDOW_TYPE (window);
2273 }
2274
2275 /**
2276 * gdk_window_get_visual:
2277 * @window: a #GdkWindow
2278 *
2279 * Gets the #GdkVisual describing the pixel format of @window.
2280 *
2281 * Returns: (transfer none): a #GdkVisual
2282 *
2283 * Since: 2.24
2284 **/
2285 GdkVisual*
gdk_window_get_visual(GdkWindow * window)2286 gdk_window_get_visual (GdkWindow *window)
2287 {
2288 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2289
2290 return window->visual;
2291 }
2292
2293 /**
2294 * gdk_window_get_screen:
2295 * @window: a #GdkWindow
2296 *
2297 * Gets the #GdkScreen associated with a #GdkWindow.
2298 *
2299 * Returns: (transfer none): the #GdkScreen associated with @window
2300 *
2301 * Since: 2.24
2302 **/
2303 GdkScreen*
gdk_window_get_screen(GdkWindow * window)2304 gdk_window_get_screen (GdkWindow *window)
2305 {
2306 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2307
2308 return gdk_visual_get_screen (window->visual);
2309 }
2310
2311 /**
2312 * gdk_window_get_display:
2313 * @window: a #GdkWindow
2314 *
2315 * Gets the #GdkDisplay associated with a #GdkWindow.
2316 *
2317 * Returns: (transfer none): the #GdkDisplay associated with @window
2318 *
2319 * Since: 2.24
2320 **/
2321 GdkDisplay *
gdk_window_get_display(GdkWindow * window)2322 gdk_window_get_display (GdkWindow *window)
2323 {
2324 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2325
2326 return gdk_screen_get_display (gdk_visual_get_screen (window->visual));
2327 }
2328 /**
2329 * gdk_window_is_destroyed:
2330 * @window: a #GdkWindow
2331 *
2332 * Check to see if a window is destroyed..
2333 *
2334 * Returns: %TRUE if the window is destroyed
2335 *
2336 * Since: 2.18
2337 **/
2338 gboolean
gdk_window_is_destroyed(GdkWindow * window)2339 gdk_window_is_destroyed (GdkWindow *window)
2340 {
2341 return GDK_WINDOW_DESTROYED (window);
2342 }
2343
2344 static void
to_embedder(GdkWindow * window,gdouble offscreen_x,gdouble offscreen_y,gdouble * embedder_x,gdouble * embedder_y)2345 to_embedder (GdkWindow *window,
2346 gdouble offscreen_x,
2347 gdouble offscreen_y,
2348 gdouble *embedder_x,
2349 gdouble *embedder_y)
2350 {
2351 g_signal_emit (window, signals[TO_EMBEDDER], 0,
2352 offscreen_x, offscreen_y,
2353 embedder_x, embedder_y);
2354 }
2355
2356 static void
from_embedder(GdkWindow * window,gdouble embedder_x,gdouble embedder_y,gdouble * offscreen_x,gdouble * offscreen_y)2357 from_embedder (GdkWindow *window,
2358 gdouble embedder_x,
2359 gdouble embedder_y,
2360 gdouble *offscreen_x,
2361 gdouble *offscreen_y)
2362 {
2363 g_signal_emit (window, signals[FROM_EMBEDDER], 0,
2364 embedder_x, embedder_y,
2365 offscreen_x, offscreen_y);
2366 }
2367
2368 /**
2369 * gdk_window_has_native:
2370 * @window: a #GdkWindow
2371 *
2372 * Checks whether the window has a native window or not. Note that
2373 * you can use gdk_window_ensure_native() if a native window is needed.
2374 *
2375 * Returns: %TRUE if the @window has a native window, %FALSE otherwise.
2376 *
2377 * Since: 2.22
2378 */
2379 gboolean
gdk_window_has_native(GdkWindow * window)2380 gdk_window_has_native (GdkWindow *window)
2381 {
2382 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
2383
2384 return window->parent == NULL || window->parent->impl != window->impl;
2385 }
2386
2387 /**
2388 * gdk_window_get_position:
2389 * @window: a #GdkWindow
2390 * @x: (out) (allow-none): X coordinate of window
2391 * @y: (out) (allow-none): Y coordinate of window
2392 *
2393 * Obtains the position of the window as reported in the
2394 * most-recently-processed #GdkEventConfigure. Contrast with
2395 * gdk_window_get_geometry() which queries the X server for the
2396 * current window position, regardless of which events have been
2397 * received or processed.
2398 *
2399 * The position coordinates are relative to the window’s parent window.
2400 *
2401 **/
2402 void
gdk_window_get_position(GdkWindow * window,gint * x,gint * y)2403 gdk_window_get_position (GdkWindow *window,
2404 gint *x,
2405 gint *y)
2406 {
2407 g_return_if_fail (GDK_IS_WINDOW (window));
2408
2409 if (x)
2410 *x = window->x;
2411 if (y)
2412 *y = window->y;
2413 }
2414
2415 /**
2416 * gdk_window_get_parent:
2417 * @window: a #GdkWindow
2418 *
2419 * Obtains the parent of @window, as known to GDK. Does not query the
2420 * X server; thus this returns the parent as passed to gdk_window_new(),
2421 * not the actual parent. This should never matter unless you’re using
2422 * Xlib calls mixed with GDK calls on the X11 platform. It may also
2423 * matter for toplevel windows, because the window manager may choose
2424 * to reparent them.
2425 *
2426 * Note that you should use gdk_window_get_effective_parent() when
2427 * writing generic code that walks up a window hierarchy, because
2428 * gdk_window_get_parent() will most likely not do what you expect if
2429 * there are offscreen windows in the hierarchy.
2430 *
2431 * Returns: (transfer none): parent of @window
2432 **/
2433 GdkWindow*
gdk_window_get_parent(GdkWindow * window)2434 gdk_window_get_parent (GdkWindow *window)
2435 {
2436 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2437
2438 return window->parent;
2439 }
2440
2441 /**
2442 * gdk_window_get_effective_parent:
2443 * @window: a #GdkWindow
2444 *
2445 * Obtains the parent of @window, as known to GDK. Works like
2446 * gdk_window_get_parent() for normal windows, but returns the
2447 * window’s embedder for offscreen windows.
2448 *
2449 * See also: gdk_offscreen_window_get_embedder()
2450 *
2451 * Returns: (transfer none): effective parent of @window
2452 *
2453 * Since: 2.22
2454 **/
2455 GdkWindow *
gdk_window_get_effective_parent(GdkWindow * window)2456 gdk_window_get_effective_parent (GdkWindow *window)
2457 {
2458 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2459
2460 if (gdk_window_is_offscreen (window))
2461 return gdk_offscreen_window_get_embedder (window);
2462 else if (gdk_window_is_subsurface (window))
2463 return window->transient_for;
2464 else
2465 return window->parent;
2466 }
2467
2468 /**
2469 * gdk_window_get_toplevel:
2470 * @window: a #GdkWindow
2471 *
2472 * Gets the toplevel window that’s an ancestor of @window.
2473 *
2474 * Any window type but %GDK_WINDOW_CHILD is considered a
2475 * toplevel window, as is a %GDK_WINDOW_CHILD window that
2476 * has a root window as parent.
2477 *
2478 * Note that you should use gdk_window_get_effective_toplevel() when
2479 * you want to get to a window’s toplevel as seen on screen, because
2480 * gdk_window_get_toplevel() will most likely not do what you expect
2481 * if there are offscreen windows in the hierarchy.
2482 *
2483 * Returns: (transfer none): the toplevel window containing @window
2484 **/
2485 GdkWindow *
gdk_window_get_toplevel(GdkWindow * window)2486 gdk_window_get_toplevel (GdkWindow *window)
2487 {
2488 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2489
2490 while (window->window_type == GDK_WINDOW_CHILD ||
2491 window->window_type == GDK_WINDOW_SUBSURFACE)
2492 {
2493 if (gdk_window_is_toplevel (window))
2494 break;
2495 window = window->parent;
2496 }
2497
2498 return window;
2499 }
2500
2501 /**
2502 * gdk_window_get_effective_toplevel:
2503 * @window: a #GdkWindow
2504 *
2505 * Gets the toplevel window that’s an ancestor of @window.
2506 *
2507 * Works like gdk_window_get_toplevel(), but treats an offscreen window's
2508 * embedder as its parent, using gdk_window_get_effective_parent().
2509 *
2510 * See also: gdk_offscreen_window_get_embedder()
2511 *
2512 * Returns: (transfer none): the effective toplevel window containing @window
2513 *
2514 * Since: 2.22
2515 **/
2516 GdkWindow *
gdk_window_get_effective_toplevel(GdkWindow * window)2517 gdk_window_get_effective_toplevel (GdkWindow *window)
2518 {
2519 GdkWindow *parent;
2520
2521 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2522
2523 while ((parent = gdk_window_get_effective_parent (window)) != NULL &&
2524 (gdk_window_get_window_type (parent) != GDK_WINDOW_ROOT))
2525 window = parent;
2526
2527 return window;
2528 }
2529
2530 /**
2531 * gdk_window_get_children:
2532 * @window: a #GdkWindow
2533 *
2534 * Gets the list of children of @window known to GDK.
2535 * This function only returns children created via GDK,
2536 * so for example it’s useless when used with the root window;
2537 * it only returns windows an application created itself.
2538 *
2539 * The returned list must be freed, but the elements in the
2540 * list need not be.
2541 *
2542 * Returns: (transfer container) (element-type GdkWindow):
2543 * list of child windows inside @window
2544 **/
2545 GList*
gdk_window_get_children(GdkWindow * window)2546 gdk_window_get_children (GdkWindow *window)
2547 {
2548 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2549
2550 if (GDK_WINDOW_DESTROYED (window))
2551 return NULL;
2552
2553 return g_list_copy (window->children);
2554 }
2555
2556 /**
2557 * gdk_window_peek_children:
2558 * @window: a #GdkWindow
2559 *
2560 * Like gdk_window_get_children(), but does not copy the list of
2561 * children, so the list does not need to be freed.
2562 *
2563 * Returns: (transfer none) (element-type GdkWindow):
2564 * a reference to the list of child windows in @window
2565 **/
2566 GList *
gdk_window_peek_children(GdkWindow * window)2567 gdk_window_peek_children (GdkWindow *window)
2568 {
2569 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2570
2571 if (GDK_WINDOW_DESTROYED (window))
2572 return NULL;
2573
2574 return window->children;
2575 }
2576
2577
2578 /**
2579 * gdk_window_get_children_with_user_data:
2580 * @window: a #GdkWindow
2581 * @user_data: user data to look for
2582 *
2583 * Gets the list of children of @window known to GDK with a
2584 * particular @user_data set on it.
2585 *
2586 * The returned list must be freed, but the elements in the
2587 * list need not be.
2588 *
2589 * The list is returned in (relative) stacking order, i.e. the
2590 * lowest window is first.
2591 *
2592 * Returns: (transfer container) (element-type GdkWindow):
2593 * list of child windows inside @window
2594 *
2595 * Since: 3.10
2596 **/
2597 GList *
gdk_window_get_children_with_user_data(GdkWindow * window,gpointer user_data)2598 gdk_window_get_children_with_user_data (GdkWindow *window,
2599 gpointer user_data)
2600 {
2601 GdkWindow *child;
2602 GList *res, *l;
2603
2604 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2605
2606 if (GDK_WINDOW_DESTROYED (window))
2607 return NULL;
2608
2609 res = NULL;
2610 for (l = window->children; l != NULL; l = l->next)
2611 {
2612 child = l->data;
2613
2614 if (child->user_data == user_data)
2615 res = g_list_prepend (res, child);
2616 }
2617
2618 return res;
2619 }
2620
2621
2622 /**
2623 * gdk_window_add_filter: (skip)
2624 * @window: (allow-none): a #GdkWindow
2625 * @function: filter callback
2626 * @data: data to pass to filter callback
2627 *
2628 * Adds an event filter to @window, allowing you to intercept events
2629 * before they reach GDK. This is a low-level operation and makes it
2630 * easy to break GDK and/or GTK+, so you have to know what you're
2631 * doing. Pass %NULL for @window to get all events for all windows,
2632 * instead of events for a specific window.
2633 *
2634 * If you are interested in X GenericEvents, bear in mind that
2635 * XGetEventData() has been already called on the event, and
2636 * XFreeEventData() must not be called within @function.
2637 **/
2638 void
gdk_window_add_filter(GdkWindow * window,GdkFilterFunc function,gpointer data)2639 gdk_window_add_filter (GdkWindow *window,
2640 GdkFilterFunc function,
2641 gpointer data)
2642 {
2643 GList *tmp_list;
2644 GdkEventFilter *filter;
2645
2646 g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
2647
2648 if (window && GDK_WINDOW_DESTROYED (window))
2649 return;
2650
2651 /* Filters are for the native events on the native window, so
2652 ensure there is a native window. */
2653 if (window)
2654 gdk_window_ensure_native (window);
2655
2656 if (window)
2657 tmp_list = window->filters;
2658 else
2659 tmp_list = _gdk_default_filters;
2660
2661 while (tmp_list)
2662 {
2663 filter = (GdkEventFilter *)tmp_list->data;
2664 if ((filter->function == function) && (filter->data == data))
2665 {
2666 filter->ref_count++;
2667 filter->flags = 0;
2668 return;
2669 }
2670 tmp_list = tmp_list->next;
2671 }
2672
2673 filter = g_new (GdkEventFilter, 1);
2674 filter->function = function;
2675 filter->data = data;
2676 filter->ref_count = 1;
2677 filter->flags = 0;
2678
2679 if (window)
2680 window->filters = g_list_append (window->filters, filter);
2681 else
2682 _gdk_default_filters = g_list_append (_gdk_default_filters, filter);
2683 }
2684
2685 /**
2686 * gdk_window_remove_filter: (skip)
2687 * @window: a #GdkWindow
2688 * @function: previously-added filter function
2689 * @data: user data for previously-added filter function
2690 *
2691 * Remove a filter previously added with gdk_window_add_filter().
2692 */
2693 void
gdk_window_remove_filter(GdkWindow * window,GdkFilterFunc function,gpointer data)2694 gdk_window_remove_filter (GdkWindow *window,
2695 GdkFilterFunc function,
2696 gpointer data)
2697 {
2698 GList *tmp_list;
2699 GdkEventFilter *filter;
2700
2701 g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
2702
2703 if (window)
2704 tmp_list = window->filters;
2705 else
2706 tmp_list = _gdk_default_filters;
2707
2708 while (tmp_list)
2709 {
2710 filter = (GdkEventFilter *)tmp_list->data;
2711 tmp_list = tmp_list->next;
2712
2713 if ((filter->function == function) && (filter->data == data))
2714 {
2715 filter->flags |= GDK_EVENT_FILTER_REMOVED;
2716
2717 _gdk_event_filter_unref (window, filter);
2718
2719 return;
2720 }
2721 }
2722 }
2723
2724 /**
2725 * gdk_screen_get_toplevel_windows:
2726 * @screen: The #GdkScreen where the toplevels are located.
2727 *
2728 * Obtains a list of all toplevel windows known to GDK on the screen @screen.
2729 * A toplevel window is a child of the root window (see
2730 * gdk_get_default_root_window()).
2731 *
2732 * The returned list should be freed with g_list_free(), but
2733 * its elements need not be freed.
2734 *
2735 * Returns: (transfer container) (element-type GdkWindow):
2736 * list of toplevel windows, free with g_list_free()
2737 *
2738 * Since: 2.2
2739 **/
2740 GList *
gdk_screen_get_toplevel_windows(GdkScreen * screen)2741 gdk_screen_get_toplevel_windows (GdkScreen *screen)
2742 {
2743 GdkWindow * root_window;
2744 GList *new_list = NULL;
2745 GList *tmp_list;
2746
2747 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
2748
2749 root_window = gdk_screen_get_root_window (screen);
2750
2751 tmp_list = root_window->children;
2752 while (tmp_list)
2753 {
2754 GdkWindow *w = tmp_list->data;
2755
2756 if (w->window_type != GDK_WINDOW_FOREIGN)
2757 new_list = g_list_prepend (new_list, w);
2758 tmp_list = tmp_list->next;
2759 }
2760
2761 return new_list;
2762 }
2763
2764 /**
2765 * gdk_window_is_visible:
2766 * @window: a #GdkWindow
2767 *
2768 * Checks whether the window has been mapped (with gdk_window_show() or
2769 * gdk_window_show_unraised()).
2770 *
2771 * Returns: %TRUE if the window is mapped
2772 **/
2773 gboolean
gdk_window_is_visible(GdkWindow * window)2774 gdk_window_is_visible (GdkWindow *window)
2775 {
2776 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
2777
2778 return GDK_WINDOW_IS_MAPPED (window);
2779 }
2780
2781 /**
2782 * gdk_window_is_viewable:
2783 * @window: a #GdkWindow
2784 *
2785 * Check if the window and all ancestors of the window are
2786 * mapped. (This is not necessarily "viewable" in the X sense, since
2787 * we only check as far as we have GDK window parents, not to the root
2788 * window.)
2789 *
2790 * Returns: %TRUE if the window is viewable
2791 **/
2792 gboolean
gdk_window_is_viewable(GdkWindow * window)2793 gdk_window_is_viewable (GdkWindow *window)
2794 {
2795 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
2796
2797 if (window->destroyed)
2798 return FALSE;
2799
2800 return window->viewable;
2801 }
2802
2803 /**
2804 * gdk_window_get_state:
2805 * @window: a #GdkWindow
2806 *
2807 * Gets the bitwise OR of the currently active window state flags,
2808 * from the #GdkWindowState enumeration.
2809 *
2810 * Returns: window state bitfield
2811 **/
2812 GdkWindowState
gdk_window_get_state(GdkWindow * window)2813 gdk_window_get_state (GdkWindow *window)
2814 {
2815 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
2816
2817 return window->state;
2818 }
2819
2820 static cairo_content_t
gdk_window_get_content(GdkWindow * window)2821 gdk_window_get_content (GdkWindow *window)
2822 {
2823 cairo_surface_t *surface;
2824 cairo_content_t content;
2825
2826 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
2827
2828 surface = gdk_window_ref_impl_surface (window);
2829 content = cairo_surface_get_content (surface);
2830 cairo_surface_destroy (surface);
2831
2832 return content;
2833 }
2834
2835 static cairo_surface_t *
gdk_window_ref_impl_surface(GdkWindow * window)2836 gdk_window_ref_impl_surface (GdkWindow *window)
2837 {
2838 return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->ref_cairo_surface (gdk_window_get_impl_window (window));
2839 }
2840
2841 GdkGLContext *
gdk_window_get_paint_gl_context(GdkWindow * window,GError ** error)2842 gdk_window_get_paint_gl_context (GdkWindow *window,
2843 GError **error)
2844 {
2845 GError *internal_error = NULL;
2846
2847 if (_gdk_gl_flags & GDK_GL_DISABLE)
2848 {
2849 g_set_error_literal (error, GDK_GL_ERROR,
2850 GDK_GL_ERROR_NOT_AVAILABLE,
2851 _("GL support disabled via GDK_DEBUG"));
2852 return NULL;
2853 }
2854
2855 if (window->impl_window->gl_paint_context == NULL)
2856 {
2857 GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
2858
2859 if (impl_class->create_gl_context == NULL)
2860 {
2861 g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
2862 _("The current backend does not support OpenGL"));
2863 return NULL;
2864 }
2865
2866 window->impl_window->gl_paint_context =
2867 impl_class->create_gl_context (window->impl_window,
2868 TRUE,
2869 NULL,
2870 &internal_error);
2871 }
2872
2873 if (internal_error != NULL)
2874 {
2875 g_propagate_error (error, internal_error);
2876 g_clear_object (&(window->impl_window->gl_paint_context));
2877 return NULL;
2878 }
2879
2880 gdk_gl_context_realize (window->impl_window->gl_paint_context, &internal_error);
2881 if (internal_error != NULL)
2882 {
2883 g_propagate_error (error, internal_error);
2884 g_clear_object (&(window->impl_window->gl_paint_context));
2885 return NULL;
2886 }
2887
2888 return window->impl_window->gl_paint_context;
2889 }
2890
2891 /**
2892 * gdk_window_create_gl_context:
2893 * @window: a #GdkWindow
2894 * @error: return location for an error
2895 *
2896 * Creates a new #GdkGLContext matching the
2897 * framebuffer format to the visual of the #GdkWindow. The context
2898 * is disconnected from any particular window or surface.
2899 *
2900 * If the creation of the #GdkGLContext failed, @error will be set.
2901 *
2902 * Before using the returned #GdkGLContext, you will need to
2903 * call gdk_gl_context_make_current() or gdk_gl_context_realize().
2904 *
2905 * Returns: (transfer full): the newly created #GdkGLContext, or
2906 * %NULL on error
2907 *
2908 * Since: 3.16
2909 **/
2910 GdkGLContext *
gdk_window_create_gl_context(GdkWindow * window,GError ** error)2911 gdk_window_create_gl_context (GdkWindow *window,
2912 GError **error)
2913 {
2914 GdkGLContext *paint_context;
2915
2916 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2917 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2918
2919 paint_context = gdk_window_get_paint_gl_context (window, error);
2920 if (paint_context == NULL)
2921 return NULL;
2922
2923 return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->create_gl_context (window->impl_window,
2924 FALSE,
2925 paint_context,
2926 error);
2927 }
2928
2929 static void
gdk_window_begin_paint_internal(GdkWindow * window,const cairo_region_t * region)2930 gdk_window_begin_paint_internal (GdkWindow *window,
2931 const cairo_region_t *region)
2932 {
2933 GdkRectangle clip_box;
2934 GdkWindowImplClass *impl_class;
2935 double sx, sy;
2936 gboolean needs_surface;
2937 cairo_content_t surface_content;
2938
2939 if (GDK_WINDOW_DESTROYED (window) ||
2940 !gdk_window_has_impl (window))
2941 return;
2942
2943 if (window->current_paint.surface != NULL)
2944 {
2945 g_warning ("A paint operation on the window is alredy in progress. "
2946 "This is not allowed.");
2947 return;
2948 }
2949
2950 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
2951
2952 needs_surface = TRUE;
2953 if (impl_class->begin_paint)
2954 needs_surface = impl_class->begin_paint (window);
2955
2956 window->current_paint.region = cairo_region_copy (region);
2957 cairo_region_intersect (window->current_paint.region, window->clip_region);
2958 cairo_region_get_extents (window->current_paint.region, &clip_box);
2959
2960 window->current_paint.flushed_region = cairo_region_create ();
2961 window->current_paint.need_blend_region = cairo_region_create ();
2962
2963 surface_content = gdk_window_get_content (window);
2964
2965 window->current_paint.use_gl = window->impl_window->gl_paint_context != NULL;
2966
2967 if (window->current_paint.use_gl)
2968 {
2969 GdkGLContext *context;
2970
2971 int ww = gdk_window_get_width (window) * gdk_window_get_scale_factor (window);
2972 int wh = gdk_window_get_height (window) * gdk_window_get_scale_factor (window);
2973
2974 context = gdk_window_get_paint_gl_context (window, NULL);
2975 if (context == NULL)
2976 {
2977 g_warning ("gl rendering failed, context: %p", context);
2978 window->current_paint.use_gl = FALSE;
2979 }
2980 else
2981 {
2982 gdk_gl_context_make_current (context);
2983 /* With gl we always need a surface to combine the gl
2984 drawing with the native drawing. */
2985 needs_surface = TRUE;
2986 /* Also, we need the surface to include alpha */
2987 surface_content = CAIRO_CONTENT_COLOR_ALPHA;
2988
2989 /* Initial setup */
2990 glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
2991 glDisable (GL_DEPTH_TEST);
2992 glDisable(GL_BLEND);
2993 glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
2994
2995 glViewport (0, 0, ww, wh);
2996 }
2997 }
2998
2999 if (needs_surface)
3000 {
3001 window->current_paint.surface = gdk_window_create_similar_surface (window,
3002 surface_content,
3003 MAX (clip_box.width, 1),
3004 MAX (clip_box.height, 1));
3005 sx = sy = 1;
3006 cairo_surface_get_device_scale (window->current_paint.surface, &sx, &sy);
3007 cairo_surface_set_device_offset (window->current_paint.surface, -clip_box.x*sx, -clip_box.y*sy);
3008 gdk_cairo_surface_mark_as_direct (window->current_paint.surface, window);
3009
3010 window->current_paint.surface_needs_composite = TRUE;
3011 }
3012 else
3013 {
3014 window->current_paint.surface = gdk_window_ref_impl_surface (window);
3015 window->current_paint.surface_needs_composite = FALSE;
3016 }
3017
3018 if (!cairo_region_is_empty (window->current_paint.region))
3019 gdk_window_clear_backing_region (window);
3020 }
3021
3022 static void
gdk_window_end_paint_internal(GdkWindow * window)3023 gdk_window_end_paint_internal (GdkWindow *window)
3024 {
3025 GdkWindow *composited;
3026 GdkWindowImplClass *impl_class;
3027 GdkRectangle clip_box = { 0, };
3028 cairo_t *cr;
3029
3030 if (GDK_WINDOW_DESTROYED (window) ||
3031 !gdk_window_has_impl (window))
3032 return;
3033
3034 if (window->current_paint.surface == NULL)
3035 {
3036 g_warning (G_STRLOC": no preceding call to gdk_window_begin_draw_frame(), see documentation");
3037 return;
3038 }
3039
3040 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
3041
3042 if (impl_class->end_paint)
3043 impl_class->end_paint (window);
3044
3045 if (window->current_paint.surface_needs_composite)
3046 {
3047 cairo_surface_t *surface;
3048
3049 cairo_region_get_extents (window->current_paint.region, &clip_box);
3050
3051 if (window->current_paint.use_gl)
3052 {
3053 cairo_region_t *opaque_region = cairo_region_copy (window->current_paint.region);
3054 cairo_region_subtract (opaque_region, window->current_paint.flushed_region);
3055 cairo_region_subtract (opaque_region, window->current_paint.need_blend_region);
3056
3057 gdk_gl_context_make_current (window->gl_paint_context);
3058
3059 if (!cairo_region_is_empty (opaque_region))
3060 gdk_gl_texture_from_surface (window->current_paint.surface,
3061 opaque_region);
3062 if (!cairo_region_is_empty (window->current_paint.need_blend_region))
3063 {
3064 glEnable(GL_BLEND);
3065 gdk_gl_texture_from_surface (window->current_paint.surface,
3066 window->current_paint.need_blend_region);
3067 glDisable(GL_BLEND);
3068 }
3069
3070 cairo_region_destroy (opaque_region);
3071
3072 gdk_gl_context_end_frame (window->gl_paint_context,
3073 window->current_paint.region,
3074 window->active_update_area);
3075 }
3076 else
3077 {
3078 surface = gdk_window_ref_impl_surface (window);
3079 cr = cairo_create (surface);
3080
3081 cairo_set_source_surface (cr, window->current_paint.surface, 0, 0);
3082 gdk_cairo_region (cr, window->current_paint.region);
3083 cairo_clip (cr);
3084
3085 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3086 cairo_paint (cr);
3087
3088 cairo_destroy (cr);
3089
3090 cairo_surface_flush (surface);
3091 cairo_surface_destroy (surface);
3092 }
3093 }
3094
3095 gdk_window_free_current_paint (window);
3096
3097 /* find a composited window in our hierarchy to signal its
3098 * parent to redraw, calculating the clip box as we go...
3099 *
3100 * stop if parent becomes NULL since then we'd have nowhere
3101 * to draw (ie: 'composited' will always be non-NULL here).
3102 */
3103 for (composited = window;
3104 composited->parent;
3105 composited = composited->parent)
3106 {
3107 clip_box.x += composited->x;
3108 clip_box.y += composited->y;
3109 clip_box.width = MIN (clip_box.width, composited->parent->width - clip_box.x);
3110 clip_box.height = MIN (clip_box.height, composited->parent->height - clip_box.y);
3111
3112 if (composited->composited)
3113 {
3114 gdk_window_invalidate_rect (GDK_WINDOW (composited->parent),
3115 &clip_box, FALSE);
3116 break;
3117 }
3118 }
3119 }
3120
3121 /**
3122 * gdk_window_begin_paint_rect:
3123 * @window: a #GdkWindow
3124 * @rectangle: rectangle you intend to draw to
3125 *
3126 * A convenience wrapper around gdk_window_begin_paint_region() which
3127 * creates a rectangular region for you. See
3128 * gdk_window_begin_paint_region() for details.
3129 *
3130 * Deprecated: 3.22: Use gdk_window_begin_draw_frame() instead
3131 */
3132 void
gdk_window_begin_paint_rect(GdkWindow * window,const GdkRectangle * rectangle)3133 gdk_window_begin_paint_rect (GdkWindow *window,
3134 const GdkRectangle *rectangle)
3135 {
3136 cairo_region_t *region;
3137
3138 g_return_if_fail (GDK_IS_WINDOW (window));
3139
3140 region = cairo_region_create_rectangle (rectangle);
3141 gdk_window_begin_paint_internal (window, region);
3142 cairo_region_destroy (region);
3143 }
3144
3145 /**
3146 * gdk_window_begin_paint_region:
3147 * @window: a #GdkWindow
3148 * @region: region you intend to draw to
3149 *
3150 * Indicates that you are beginning the process of redrawing @region.
3151 * A backing store (offscreen buffer) large enough to contain @region
3152 * will be created. The backing store will be initialized with the
3153 * background color or background surface for @window. Then, all
3154 * drawing operations performed on @window will be diverted to the
3155 * backing store. When you call gdk_window_end_paint(), the backing
3156 * store will be copied to @window, making it visible onscreen. Only
3157 * the part of @window contained in @region will be modified; that is,
3158 * drawing operations are clipped to @region.
3159 *
3160 * The net result of all this is to remove flicker, because the user
3161 * sees the finished product appear all at once when you call
3162 * gdk_window_end_paint(). If you draw to @window directly without
3163 * calling gdk_window_begin_paint_region(), the user may see flicker
3164 * as individual drawing operations are performed in sequence. The
3165 * clipping and background-initializing features of
3166 * gdk_window_begin_paint_region() are conveniences for the
3167 * programmer, so you can avoid doing that work yourself.
3168 *
3169 * When using GTK+, the widget system automatically places calls to
3170 * gdk_window_begin_paint_region() and gdk_window_end_paint() around
3171 * emissions of the expose_event signal. That is, if you’re writing an
3172 * expose event handler, you can assume that the exposed area in
3173 * #GdkEventExpose has already been cleared to the window background,
3174 * is already set as the clip region, and already has a backing store.
3175 * Therefore in most cases, application code need not call
3176 * gdk_window_begin_paint_region(). (You can disable the automatic
3177 * calls around expose events on a widget-by-widget basis by calling
3178 * gtk_widget_set_double_buffered().)
3179 *
3180 * If you call this function multiple times before calling the
3181 * matching gdk_window_end_paint(), the backing stores are pushed onto
3182 * a stack. gdk_window_end_paint() copies the topmost backing store
3183 * onscreen, subtracts the topmost region from all other regions in
3184 * the stack, and pops the stack. All drawing operations affect only
3185 * the topmost backing store in the stack. One matching call to
3186 * gdk_window_end_paint() is required for each call to
3187 * gdk_window_begin_paint_region().
3188 *
3189 * Deprecated: 3.22: Use gdk_window_begin_draw_frame() instead
3190 */
3191 void
gdk_window_begin_paint_region(GdkWindow * window,const cairo_region_t * region)3192 gdk_window_begin_paint_region (GdkWindow *window,
3193 const cairo_region_t *region)
3194 {
3195 g_return_if_fail (GDK_IS_WINDOW (window));
3196
3197 gdk_window_begin_paint_internal (window, region);
3198 }
3199
3200 /**
3201 * gdk_window_begin_draw_frame:
3202 * @window: a #GdkWindow
3203 * @region: a Cairo region
3204 *
3205 * Indicates that you are beginning the process of redrawing @region
3206 * on @window, and provides you with a #GdkDrawingContext.
3207 *
3208 * If @window is a top level #GdkWindow, backed by a native window
3209 * implementation, a backing store (offscreen buffer) large enough to
3210 * contain @region will be created. The backing store will be initialized
3211 * with the background color or background surface for @window. Then, all
3212 * drawing operations performed on @window will be diverted to the
3213 * backing store. When you call gdk_window_end_frame(), the contents of
3214 * the backing store will be copied to @window, making it visible
3215 * on screen. Only the part of @window contained in @region will be
3216 * modified; that is, drawing operations are clipped to @region.
3217 *
3218 * The net result of all this is to remove flicker, because the user
3219 * sees the finished product appear all at once when you call
3220 * gdk_window_end_draw_frame(). If you draw to @window directly without
3221 * calling gdk_window_begin_draw_frame(), the user may see flicker
3222 * as individual drawing operations are performed in sequence.
3223 *
3224 * When using GTK+, the widget system automatically places calls to
3225 * gdk_window_begin_draw_frame() and gdk_window_end_draw_frame() around
3226 * emissions of the `GtkWidget::draw` signal. That is, if you’re
3227 * drawing the contents of the widget yourself, you can assume that the
3228 * widget has a cleared background, is already set as the clip region,
3229 * and already has a backing store. Therefore in most cases, application
3230 * code in GTK does not need to call gdk_window_begin_draw_frame()
3231 * explicitly.
3232 *
3233 * Returns: (transfer none): a #GdkDrawingContext context that should be
3234 * used to draw the contents of the window; the returned context is owned
3235 * by GDK.
3236 *
3237 * Since: 3.22
3238 */
3239 GdkDrawingContext *
gdk_window_begin_draw_frame(GdkWindow * window,const cairo_region_t * region)3240 gdk_window_begin_draw_frame (GdkWindow *window,
3241 const cairo_region_t *region)
3242 {
3243 GdkDrawingContext *context;
3244 GdkWindowImplClass *impl_class;
3245
3246 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
3247
3248 if (window->drawing_context != NULL)
3249 {
3250 g_critical ("The window %p already has a drawing context. You cannot "
3251 "call gdk_window_begin_draw_frame() without calling "
3252 "gdk_window_end_draw_frame() first.", window);
3253 return NULL;
3254 }
3255
3256 if (gdk_window_has_native (window) && gdk_window_is_toplevel (window))
3257 gdk_window_begin_paint_internal (window, region);
3258
3259 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
3260 if (impl_class->create_draw_context != NULL)
3261 {
3262 context = impl_class->create_draw_context (window, region);
3263 }
3264 else
3265 {
3266 context = g_object_new (GDK_TYPE_DRAWING_CONTEXT,
3267 "window", window,
3268 "clip", region,
3269 NULL);
3270 }
3271
3272 /* Do not take a reference, to avoid creating cycles */
3273 window->drawing_context = context;
3274
3275 return context;
3276 }
3277
3278 /**
3279 * gdk_window_end_draw_frame:
3280 * @window: a #GdkWindow
3281 * @context: the #GdkDrawingContext created by gdk_window_begin_draw_frame()
3282 *
3283 * Indicates that the drawing of the contents of @window started with
3284 * gdk_window_begin_frame() has been completed.
3285 *
3286 * This function will take care of destroying the #GdkDrawingContext.
3287 *
3288 * It is an error to call this function without a matching
3289 * gdk_window_begin_frame() first.
3290 *
3291 * Since: 3.22
3292 */
3293 void
gdk_window_end_draw_frame(GdkWindow * window,GdkDrawingContext * context)3294 gdk_window_end_draw_frame (GdkWindow *window,
3295 GdkDrawingContext *context)
3296 {
3297 GdkWindowImplClass *impl_class;
3298
3299 g_return_if_fail (GDK_IS_WINDOW (window));
3300 g_return_if_fail (GDK_IS_DRAWING_CONTEXT (context));
3301
3302 if (window->drawing_context == NULL)
3303 {
3304 g_critical ("The window %p has no drawing context. You must call "
3305 "gdk_window_begin_draw_frame() before calling "
3306 "gdk_window_end_draw_frame().", window);
3307 return;
3308 }
3309
3310 if (gdk_window_has_native (window) && gdk_window_is_toplevel (window))
3311 gdk_window_end_paint_internal (window);
3312
3313 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
3314 if (impl_class->destroy_draw_context != NULL)
3315 impl_class->destroy_draw_context (window, context);
3316 else
3317 g_object_unref (context);
3318
3319 window->drawing_context = NULL;
3320 }
3321
3322 /*< private >
3323 * gdk_window_get_current_paint_region:
3324 * @window: a #GdkWindow
3325 *
3326 * Retrieves a copy of the current paint region.
3327 *
3328 * Returns: (transfer full): a Cairo region
3329 */
3330 cairo_region_t *
gdk_window_get_current_paint_region(GdkWindow * window)3331 gdk_window_get_current_paint_region (GdkWindow *window)
3332 {
3333 cairo_region_t *region;
3334
3335 if (window->impl_window->current_paint.region != NULL)
3336 {
3337 region = cairo_region_copy (window->impl_window->current_paint.region);
3338 cairo_region_translate (region, -window->abs_x, -window->abs_y);
3339 }
3340 else
3341 {
3342 region = cairo_region_copy (window->clip_region);
3343 }
3344
3345 return region;
3346 }
3347
3348 /*< private >
3349 * gdk_window_get_drawing_context:
3350 * @window: a #GdkWindow
3351 *
3352 * Retrieves the #GdkDrawingContext associated to @window by
3353 * gdk_window_begin_draw_frame().
3354 *
3355 * Returns: (transfer none) (nullable): a #GdkDrawingContext, if any is set
3356 */
3357 GdkDrawingContext *
gdk_window_get_drawing_context(GdkWindow * window)3358 gdk_window_get_drawing_context (GdkWindow *window)
3359 {
3360 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
3361
3362 if (GDK_WINDOW_DESTROYED (window))
3363 return NULL;
3364
3365 return window->drawing_context;
3366 }
3367
3368 /**
3369 * gdk_window_mark_paint_from_clip:
3370 * @window: a #GdkWindow
3371 * @cr: a #cairo_t
3372 *
3373 * If you call this during a paint (e.g. between gdk_window_begin_paint_region()
3374 * and gdk_window_end_paint() then GDK will mark the current clip region of the
3375 * window as being drawn. This is required when mixing GL rendering via
3376 * gdk_cairo_draw_from_gl() and cairo rendering, as otherwise GDK has no way
3377 * of knowing when something paints over the GL-drawn regions.
3378 *
3379 * This is typically called automatically by GTK+ and you don't need
3380 * to care about this.
3381 *
3382 * Since: 3.16
3383 **/
3384 void
gdk_window_mark_paint_from_clip(GdkWindow * window,cairo_t * cr)3385 gdk_window_mark_paint_from_clip (GdkWindow *window,
3386 cairo_t *cr)
3387 {
3388 cairo_region_t *clip_region;
3389 GdkWindow *impl_window = window->impl_window;
3390
3391 if (impl_window->current_paint.surface == NULL ||
3392 cairo_get_target (cr) != impl_window->current_paint.surface)
3393 return;
3394
3395 if (cairo_region_is_empty (impl_window->current_paint.flushed_region))
3396 return;
3397
3398 /* This here seems a bit weird, but basically, we're taking the current
3399 clip and applying also the flushed region, and the result is that the
3400 new clip is the intersection of these. This is the area where the newly
3401 drawn region overlaps a previosly flushed area, which is an area of the
3402 double buffer surface that need to be blended OVER the back buffer rather
3403 than SRCed. */
3404 cairo_save (cr);
3405 /* We set the identity matrix here so we get and apply regions in native
3406 window coordinates. */
3407 cairo_identity_matrix (cr);
3408 gdk_cairo_region (cr, impl_window->current_paint.flushed_region);
3409 cairo_clip (cr);
3410
3411 clip_region = gdk_cairo_region_from_clip (cr);
3412 if (clip_region == NULL)
3413 {
3414 /* Failed to represent clip as region, mark all as requiring
3415 blend */
3416 cairo_region_union (impl_window->current_paint.need_blend_region,
3417 impl_window->current_paint.flushed_region);
3418 cairo_region_destroy (impl_window->current_paint.flushed_region);
3419 impl_window->current_paint.flushed_region = cairo_region_create ();
3420 }
3421 else
3422 {
3423 cairo_region_subtract (impl_window->current_paint.flushed_region, clip_region);
3424 cairo_region_union (impl_window->current_paint.need_blend_region, clip_region);
3425 }
3426 cairo_region_destroy (clip_region);
3427
3428 /* Clear the area on the double buffer surface to transparent so we
3429 can start drawing from scratch the area "above" the flushed
3430 region */
3431 cairo_set_source_rgba (cr, 0, 0, 0, 0);
3432 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3433 cairo_paint (cr);
3434
3435 cairo_restore (cr);
3436 }
3437
3438 /**
3439 * gdk_window_end_paint:
3440 * @window: a #GdkWindow
3441 *
3442 * Indicates that the backing store created by the most recent call
3443 * to gdk_window_begin_paint_region() should be copied onscreen and
3444 * deleted, leaving the next-most-recent backing store or no backing
3445 * store at all as the active paint region. See
3446 * gdk_window_begin_paint_region() for full details.
3447 *
3448 * It is an error to call this function without a matching
3449 * gdk_window_begin_paint_region() first.
3450 **/
3451 void
gdk_window_end_paint(GdkWindow * window)3452 gdk_window_end_paint (GdkWindow *window)
3453 {
3454 g_return_if_fail (GDK_IS_WINDOW (window));
3455
3456 gdk_window_end_paint_internal (window);
3457 }
3458
3459 /**
3460 * gdk_window_flush:
3461 * @window: a #GdkWindow
3462 *
3463 * This function does nothing.
3464 *
3465 * Since: 2.18
3466 *
3467 * Deprecated: 3.14
3468 **/
3469 void
gdk_window_flush(GdkWindow * window)3470 gdk_window_flush (GdkWindow *window)
3471 {
3472 }
3473
3474 /**
3475 * gdk_window_get_clip_region:
3476 * @window: a #GdkWindow
3477 *
3478 * Computes the region of a window that potentially can be written
3479 * to by drawing primitives. This region may not take into account
3480 * other factors such as if the window is obscured by other windows,
3481 * but no area outside of this region will be affected by drawing
3482 * primitives.
3483 *
3484 * Returns: a #cairo_region_t. This must be freed with cairo_region_destroy()
3485 * when you are done.
3486 **/
3487 cairo_region_t*
gdk_window_get_clip_region(GdkWindow * window)3488 gdk_window_get_clip_region (GdkWindow *window)
3489 {
3490 cairo_region_t *result;
3491
3492 g_return_val_if_fail (GDK_WINDOW (window), NULL);
3493
3494 result = cairo_region_copy (window->clip_region);
3495
3496 if (window->current_paint.region != NULL)
3497 cairo_region_intersect (result, window->current_paint.region);
3498
3499 return result;
3500 }
3501
3502 /**
3503 * gdk_window_get_visible_region:
3504 * @window: a #GdkWindow
3505 *
3506 * Computes the region of the @window that is potentially visible.
3507 * This does not necessarily take into account if the window is
3508 * obscured by other windows, but no area outside of this region
3509 * is visible.
3510 *
3511 * Returns: a #cairo_region_t. This must be freed with cairo_region_destroy()
3512 * when you are done.
3513 **/
3514 cairo_region_t *
gdk_window_get_visible_region(GdkWindow * window)3515 gdk_window_get_visible_region (GdkWindow *window)
3516 {
3517 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
3518
3519 return cairo_region_copy (window->clip_region);
3520 }
3521
3522 static void
gdk_window_clear_backing_region(GdkWindow * window)3523 gdk_window_clear_backing_region (GdkWindow *window)
3524 {
3525 GdkWindow *bg_window;
3526 cairo_pattern_t *pattern = NULL;
3527 int x_offset = 0, y_offset = 0;
3528 cairo_t *cr;
3529
3530 if (GDK_WINDOW_DESTROYED (window))
3531 return;
3532
3533 cr = cairo_create (window->current_paint.surface);
3534
3535 for (bg_window = window; bg_window; bg_window = bg_window->parent)
3536 {
3537 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
3538 pattern = gdk_window_get_background_pattern (bg_window);
3539 G_GNUC_END_IGNORE_DEPRECATIONS
3540 if (pattern)
3541 break;
3542
3543 x_offset += bg_window->x;
3544 y_offset += bg_window->y;
3545 }
3546
3547 if (pattern)
3548 {
3549 cairo_translate (cr, -x_offset, -y_offset);
3550 cairo_set_source (cr, pattern);
3551 cairo_translate (cr, x_offset, y_offset);
3552 }
3553 else
3554 cairo_set_source_rgb (cr, 0, 0, 0);
3555
3556 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3557 gdk_cairo_region (cr, window->current_paint.region);
3558 cairo_fill (cr);
3559
3560 cairo_destroy (cr);
3561 }
3562
3563 /* This returns either the current working surface on the paint stack
3564 * or the actual impl surface of the window. This should not be used
3565 * from very many places: be careful! */
3566 static cairo_surface_t *
ref_window_surface(GdkWindow * window)3567 ref_window_surface (GdkWindow *window)
3568 {
3569 if (window->impl_window->current_paint.surface)
3570 return cairo_surface_reference (window->impl_window->current_paint.surface);
3571 else
3572 return gdk_window_ref_impl_surface (window);
3573 }
3574
3575 /* This is used in places like gdk_cairo_set_source_window and
3576 * other places to take "screenshots" of windows. Thus, we allow
3577 * it to be used outside of a begin_paint / end_paint. */
3578 cairo_surface_t *
_gdk_window_ref_cairo_surface(GdkWindow * window)3579 _gdk_window_ref_cairo_surface (GdkWindow *window)
3580 {
3581 cairo_surface_t *surface;
3582
3583 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
3584
3585 surface = ref_window_surface (window);
3586
3587 if (gdk_window_has_impl (window))
3588 {
3589 return surface;
3590 }
3591 else
3592 {
3593 cairo_surface_t *subsurface;
3594 subsurface = cairo_surface_create_for_rectangle (surface,
3595 window->abs_x,
3596 window->abs_y,
3597 window->width,
3598 window->height);
3599 cairo_surface_destroy (surface);
3600 return subsurface;
3601 }
3602 }
3603
3604 /**
3605 * gdk_cairo_create:
3606 * @window: a #GdkWindow
3607 *
3608 * Creates a Cairo context for drawing to @window.
3609 *
3610 * Note that calling cairo_reset_clip() on the resulting #cairo_t will
3611 * produce undefined results, so avoid it at all costs.
3612 *
3613 * Typically, this function is used to draw on a #GdkWindow out of the paint
3614 * cycle of the toolkit; this should be avoided, as it breaks various assumptions
3615 * and optimizations.
3616 *
3617 * If you are drawing on a native #GdkWindow in response to a %GDK_EXPOSE event
3618 * you should use gdk_window_begin_draw_frame() and gdk_drawing_context_get_cairo_context()
3619 * instead. GTK will automatically do this for you when drawing a widget.
3620 *
3621 * Returns: A newly created Cairo context. Free with
3622 * cairo_destroy() when you are done drawing.
3623 *
3624 * Since: 2.8
3625 *
3626 * Deprecated: 3.22: Use gdk_window_begin_draw_frame() and
3627 * gdk_drawing_context_get_cairo_context() instead
3628 **/
3629 cairo_t *
gdk_cairo_create(GdkWindow * window)3630 gdk_cairo_create (GdkWindow *window)
3631 {
3632 cairo_region_t *region;
3633 cairo_surface_t *surface;
3634 cairo_t *cr;
3635
3636 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
3637
3638 surface = _gdk_window_ref_cairo_surface (window);
3639
3640 cr = cairo_create (surface);
3641
3642 region = gdk_window_get_current_paint_region (window);
3643 gdk_cairo_region (cr, region);
3644 cairo_region_destroy (region);
3645 cairo_clip (cr);
3646
3647 /* Assign a drawing context, if one is set; if gdk_cairo_create()
3648 * is called outside of a frame drawing then this is going to be
3649 * NULL.
3650 */
3651 gdk_cairo_set_drawing_context (cr, window->drawing_context);
3652
3653 cairo_surface_destroy (surface);
3654
3655 return cr;
3656 }
3657
3658 /* Code for dirty-region queueing
3659 */
3660 static GSList *update_windows = NULL;
3661 gboolean _gdk_debug_updates = FALSE;
3662
3663 static inline gboolean
gdk_window_is_ancestor(GdkWindow * window,GdkWindow * ancestor)3664 gdk_window_is_ancestor (GdkWindow *window,
3665 GdkWindow *ancestor)
3666 {
3667 while (window)
3668 {
3669 GdkWindow *parent = window->parent;
3670
3671 if (parent == ancestor)
3672 return TRUE;
3673
3674 window = parent;
3675 }
3676
3677 return FALSE;
3678 }
3679
3680 static void
gdk_window_add_update_window(GdkWindow * window)3681 gdk_window_add_update_window (GdkWindow *window)
3682 {
3683 GSList *tmp;
3684 GSList *prev = NULL;
3685 gboolean has_ancestor_in_list = FALSE;
3686
3687 /* Check whether "window" is already in "update_windows" list.
3688 * It could be added during execution of gtk_widget_destroy() when
3689 * setting focus widget to NULL and redrawing old focus widget.
3690 * See bug 711552.
3691 */
3692 tmp = g_slist_find (update_windows, window);
3693 if (tmp != NULL)
3694 return;
3695
3696 for (tmp = update_windows; tmp; tmp = tmp->next)
3697 {
3698 GdkWindow *parent = window->parent;
3699
3700 /* check if tmp is an ancestor of "window"; if it is, set a
3701 * flag indicating that all following windows are either
3702 * children of "window" or from a differen hierarchy
3703 */
3704 if (!has_ancestor_in_list && gdk_window_is_ancestor (window, tmp->data))
3705 has_ancestor_in_list = TRUE;
3706
3707 /* insert in reverse stacking order when adding around siblings,
3708 * so processing updates properly paints over lower stacked windows
3709 */
3710 if (parent == GDK_WINDOW (tmp->data)->parent)
3711 {
3712 gint index = g_list_index (parent->children, window);
3713 for (; tmp && parent == GDK_WINDOW (tmp->data)->parent; tmp = tmp->next)
3714 {
3715 gint sibling_index = g_list_index (parent->children, tmp->data);
3716 if (index > sibling_index)
3717 break;
3718 prev = tmp;
3719 }
3720 /* here, tmp got advanced past all lower stacked siblings */
3721 tmp = g_slist_prepend (tmp, g_object_ref (window));
3722 if (prev)
3723 prev->next = tmp;
3724 else
3725 update_windows = tmp;
3726 return;
3727 }
3728
3729 /* if "window" has an ancestor in the list and tmp is one of
3730 * "window's" children, insert "window" before tmp
3731 */
3732 if (has_ancestor_in_list && gdk_window_is_ancestor (tmp->data, window))
3733 {
3734 tmp = g_slist_prepend (tmp, g_object_ref (window));
3735
3736 if (prev)
3737 prev->next = tmp;
3738 else
3739 update_windows = tmp;
3740 return;
3741 }
3742
3743 /* if we're at the end of the list and had an ancestor it it,
3744 * append to the list
3745 */
3746 if (! tmp->next && has_ancestor_in_list)
3747 {
3748 tmp = g_slist_append (tmp, g_object_ref (window));
3749 return;
3750 }
3751
3752 prev = tmp;
3753 }
3754
3755 /* if all above checks failed ("window" is from a different
3756 * hierarchy than what is already in the list) or the list is
3757 * empty, prepend
3758 */
3759 update_windows = g_slist_prepend (update_windows, g_object_ref (window));
3760 }
3761
3762 static void
gdk_window_remove_update_window(GdkWindow * window)3763 gdk_window_remove_update_window (GdkWindow *window)
3764 {
3765 GSList *link;
3766
3767 link = g_slist_find (update_windows, window);
3768 if (link != NULL)
3769 {
3770 update_windows = g_slist_delete_link (update_windows, link);
3771 g_object_unref (window);
3772 }
3773 }
3774
3775 static gboolean
gdk_window_is_toplevel_frozen(GdkWindow * window)3776 gdk_window_is_toplevel_frozen (GdkWindow *window)
3777 {
3778 GdkWindow *toplevel;
3779
3780 toplevel = gdk_window_get_toplevel (window);
3781
3782 return toplevel->update_and_descendants_freeze_count > 0;
3783 }
3784
3785 static void
gdk_window_schedule_update(GdkWindow * window)3786 gdk_window_schedule_update (GdkWindow *window)
3787 {
3788 GdkFrameClock *frame_clock;
3789
3790 if (window &&
3791 (window->update_freeze_count ||
3792 gdk_window_is_toplevel_frozen (window)))
3793 return;
3794
3795 /* If there's no frame clock (a foreign window), then the invalid
3796 * region will just stick around unless gdk_window_process_updates()
3797 * is called. */
3798 frame_clock = gdk_window_get_frame_clock (window);
3799 if (frame_clock)
3800 gdk_frame_clock_request_phase (gdk_window_get_frame_clock (window),
3801 GDK_FRAME_CLOCK_PHASE_PAINT);
3802 }
3803
3804 static void
gdk_window_add_damage(GdkWindow * toplevel,cairo_region_t * damaged_region)3805 gdk_window_add_damage (GdkWindow *toplevel,
3806 cairo_region_t *damaged_region)
3807 {
3808 GdkDisplay *display;
3809 GdkEvent event = { 0, };
3810
3811 /* This function only makes sense for offscreen windows. */
3812 g_assert (gdk_window_is_offscreen (toplevel));
3813
3814 event.expose.type = GDK_DAMAGE;
3815 event.expose.window = toplevel;
3816 event.expose.send_event = FALSE;
3817 event.expose.region = damaged_region;
3818 cairo_region_get_extents (event.expose.region, &event.expose.area);
3819
3820 display = gdk_window_get_display (event.expose.window);
3821 _gdk_event_queue_append (display, gdk_event_copy (&event));
3822 }
3823
3824 static void
_gdk_window_process_updates_recurse_helper(GdkWindow * window,cairo_region_t * expose_region)3825 _gdk_window_process_updates_recurse_helper (GdkWindow *window,
3826 cairo_region_t *expose_region)
3827 {
3828 GdkWindow *child;
3829 cairo_region_t *clipped_expose_region;
3830 GdkWindow **children;
3831 GdkWindow **free_children = NULL;
3832 int i, n_children;
3833 GList *l;
3834 GList *last_link;
3835
3836 if (window->destroyed)
3837 return;
3838
3839 if (window->alpha == 0 && !gdk_window_has_impl (window))
3840 return;
3841
3842 clipped_expose_region = cairo_region_copy (expose_region);
3843
3844 if (!gdk_window_has_impl (window))
3845 cairo_region_translate (clipped_expose_region, -window->x, -window->y);
3846
3847 cairo_region_intersect (clipped_expose_region, window->clip_region);
3848
3849 if (cairo_region_is_empty (clipped_expose_region))
3850 goto out;
3851
3852 if (gdk_window_is_offscreen (window))
3853 gdk_window_add_damage (window, clipped_expose_region);
3854
3855 /* Paint the window before the children, clipped to the window region */
3856
3857 /* While gtk+ no longer handles exposes on anything but native
3858 window we still have to send them to all windows that have the
3859 event mask set for backwards compat. We also need to send
3860 it to all native windows, even if they don't specify the
3861 expose mask, because they may have non-native children that do. */
3862 if (gdk_window_has_impl (window) ||
3863 window->event_mask & GDK_EXPOSURE_MASK)
3864 {
3865 GdkEvent event;
3866
3867 event.expose.type = GDK_EXPOSE;
3868 event.expose.window = window; /* we already hold a ref */
3869 event.expose.send_event = FALSE;
3870 event.expose.count = 0;
3871 event.expose.region = clipped_expose_region;
3872 cairo_region_get_extents (clipped_expose_region, &event.expose.area);
3873
3874 _gdk_event_emit (&event);
3875 }
3876
3877 n_children = 0;
3878 last_link = NULL;
3879 /* Count n_children and fetch bottommost at same time */
3880 for (l = window->children; l != NULL; l = l->next)
3881 {
3882 last_link = l;
3883 n_children++;
3884 }
3885
3886 children = g_newa (GdkWindow *, n_children);
3887 if (children == NULL)
3888 children = free_children = g_new (GdkWindow *, n_children);
3889
3890 n_children = 0;
3891 /* Iterate over children, starting at bottommost */
3892 for (l = last_link; l != NULL; l = l->prev)
3893 {
3894 child = l->data;
3895
3896 if (child->destroyed || !GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
3897 continue;
3898
3899 /* Ignore offscreen children, as they don't draw in their parent and
3900 * don't take part in the clipping */
3901 if (gdk_window_is_offscreen (child))
3902 continue;
3903
3904 /* Client side child, expose */
3905 if (child->impl == window->impl)
3906 {
3907 /* ref the child to make this reentrancy safe for expose
3908 handlers freeing other windows */
3909 children[n_children++] = g_object_ref (child);
3910 }
3911 }
3912
3913 for (i = 0; i < n_children; i++)
3914 {
3915 _gdk_window_process_updates_recurse_helper ((GdkWindow *)children[i],
3916 clipped_expose_region);
3917 g_object_unref (children[i]);
3918 }
3919
3920
3921 g_free (free_children);
3922
3923 out:
3924 cairo_region_destroy (clipped_expose_region);
3925 }
3926
3927 void
_gdk_window_process_updates_recurse(GdkWindow * window,cairo_region_t * expose_region)3928 _gdk_window_process_updates_recurse (GdkWindow *window,
3929 cairo_region_t *expose_region)
3930 {
3931 _gdk_window_process_updates_recurse_helper (window, expose_region);
3932 }
3933
3934
3935 static void
gdk_window_update_native_shapes(GdkWindow * window)3936 gdk_window_update_native_shapes (GdkWindow *window)
3937 {
3938 GdkWindow *child;
3939 GList *l;
3940
3941 if (should_apply_clip_as_shape (window))
3942 apply_clip_as_shape (window);
3943
3944 for (l = window->native_children; l != NULL; l = l->next)
3945 {
3946 child = l->data;
3947
3948 gdk_window_update_native_shapes (child);
3949 }
3950 }
3951
3952 /* Process and remove any invalid area on the native window by creating
3953 * expose events for the window and all non-native descendants.
3954 */
3955 static void
gdk_window_process_updates_internal(GdkWindow * window)3956 gdk_window_process_updates_internal (GdkWindow *window)
3957 {
3958 GdkWindowImplClass *impl_class;
3959 GdkWindow *toplevel;
3960 GdkDisplay *display;
3961
3962 display = gdk_window_get_display (window);
3963 toplevel = gdk_window_get_toplevel (window);
3964 if (toplevel->geometry_dirty)
3965 {
3966 gdk_window_update_native_shapes (toplevel);
3967 toplevel->geometry_dirty = FALSE;
3968 }
3969
3970 /* Ensure the window lives while updating it */
3971 g_object_ref (window);
3972
3973 window->in_update = TRUE;
3974
3975 /* If an update got queued during update processing, we can get a
3976 * window in the update queue that has an empty update_area.
3977 * just ignore it.
3978 */
3979 if (window->update_area)
3980 {
3981 g_assert (window->active_update_area == NULL); /* No reentrancy */
3982
3983 window->active_update_area = window->update_area;
3984 window->update_area = NULL;
3985
3986 if (gdk_window_is_viewable (window))
3987 {
3988 cairo_region_t *expose_region;
3989
3990 expose_region = cairo_region_copy (window->active_update_area);
3991
3992 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
3993
3994 /* Sometimes we can't just paint only the new area, as the windowing system
3995 * requires more to be repainted. For instance, with OpenGL you typically
3996 * repaint all of each frame each time and then swap the buffer, although
3997 * there are extensions that allow us to reuse part of an old frame.
3998 */
3999 if (impl_class->invalidate_for_new_frame)
4000 impl_class->invalidate_for_new_frame (window, expose_region);
4001
4002 /* Clip to part visible in impl window */
4003 cairo_region_intersect (expose_region, window->clip_region);
4004
4005 if (gdk_display_get_debug_updates (display))
4006 {
4007 cairo_region_t *swap_region = cairo_region_copy (expose_region);
4008 cairo_region_subtract (swap_region, window->active_update_area);
4009 draw_ugly_color (window, swap_region, 1);
4010 cairo_region_destroy (swap_region);
4011
4012 /* Make sure we see the red invalid area before redrawing. */
4013 gdk_display_sync (gdk_window_get_display (window));
4014 g_usleep (70000);
4015 }
4016
4017 if (impl_class->queue_antiexpose)
4018 impl_class->queue_antiexpose (window, expose_region);
4019
4020 impl_class->process_updates_recurse (window, expose_region);
4021
4022 gdk_window_append_old_updated_area (window, window->active_update_area);
4023
4024 cairo_region_destroy (expose_region);
4025 }
4026
4027 cairo_region_destroy (window->active_update_area);
4028 window->active_update_area = NULL;
4029 }
4030
4031 window->in_update = FALSE;
4032
4033 g_object_unref (window);
4034 }
4035
4036 static void
flush_all_displays(void)4037 flush_all_displays (void)
4038 {
4039 GSList *displays, *l;
4040
4041 displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
4042 for (l = displays; l; l = l->next)
4043 gdk_display_flush (l->data);
4044
4045 g_slist_free (displays);
4046 }
4047
4048 static void
before_process_all_updates(void)4049 before_process_all_updates (void)
4050 {
4051 GSList *displays, *l;
4052
4053 displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
4054 for (l = displays; l; l = l->next)
4055 GDK_DISPLAY_GET_CLASS (l->data)->before_process_all_updates (l->data);
4056
4057 g_slist_free (displays);
4058 }
4059
4060 static void
after_process_all_updates(void)4061 after_process_all_updates (void)
4062 {
4063 GSList *displays, *l;
4064
4065 displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
4066 for (l = displays; l; l = l->next)
4067 GDK_DISPLAY_GET_CLASS (l->data)->after_process_all_updates (l->data);
4068
4069 g_slist_free (displays);
4070 }
4071
4072 /* Currently it is not possible to override
4073 * gdk_window_process_all_updates in the same manner as
4074 * gdk_window_process_updates and gdk_window_invalidate_maybe_recurse
4075 * by implementing the GdkPaintable interface. If in the future a
4076 * backend would need this, the right solution would be to add a
4077 * method to GdkDisplay that can be optionally
4078 * NULL. gdk_window_process_all_updates can then walk the list of open
4079 * displays and call the mehod.
4080 */
4081
4082 /**
4083 * gdk_window_process_all_updates:
4084 *
4085 * Calls gdk_window_process_updates() for all windows (see #GdkWindow)
4086 * in the application.
4087 *
4088 * Deprecated: 3.22
4089 **/
4090 void
gdk_window_process_all_updates(void)4091 gdk_window_process_all_updates (void)
4092 {
4093 GSList *old_update_windows = update_windows;
4094 GSList *tmp_list = update_windows;
4095 static gboolean in_process_all_updates = FALSE;
4096 static gboolean got_recursive_update = FALSE;
4097
4098 if (in_process_all_updates)
4099 {
4100 /* We can't do this now since that would recurse, so
4101 delay it until after the recursion is done. */
4102 got_recursive_update = TRUE;
4103 return;
4104 }
4105
4106 in_process_all_updates = TRUE;
4107 got_recursive_update = FALSE;
4108
4109 update_windows = NULL;
4110
4111 before_process_all_updates ();
4112
4113 while (tmp_list)
4114 {
4115 GdkWindow *window = tmp_list->data;
4116
4117 if (!GDK_WINDOW_DESTROYED (window))
4118 {
4119 if (window->update_freeze_count ||
4120 gdk_window_is_toplevel_frozen (window))
4121 gdk_window_add_update_window (window);
4122 else
4123 gdk_window_process_updates_internal (window);
4124 }
4125
4126 g_object_unref (window);
4127 tmp_list = tmp_list->next;
4128 }
4129
4130 g_slist_free (old_update_windows);
4131
4132 flush_all_displays ();
4133
4134 after_process_all_updates ();
4135
4136 in_process_all_updates = FALSE;
4137
4138 /* If we ignored a recursive call, schedule a
4139 redraw now so that it eventually happens,
4140 otherwise we could miss an update if nothing
4141 else schedules an update. */
4142 if (got_recursive_update)
4143 gdk_window_schedule_update (NULL);
4144 }
4145
4146
4147 enum {
4148 PROCESS_UPDATES_NO_RECURSE,
4149 PROCESS_UPDATES_WITH_ALL_CHILDREN,
4150 PROCESS_UPDATES_WITH_SAME_CLOCK_CHILDREN
4151 };
4152
4153 static void
find_impl_windows_to_update(GPtrArray * list,GdkWindow * window,gint recurse_mode)4154 find_impl_windows_to_update (GPtrArray *list,
4155 GdkWindow *window,
4156 gint recurse_mode)
4157 {
4158 GList *node;
4159
4160 /* Recurse first, so that we process updates in reverse stacking
4161 * order so composition or painting over achieves the desired effect
4162 * for offscreen windows
4163 */
4164 if (recurse_mode != PROCESS_UPDATES_NO_RECURSE)
4165 {
4166 for (node = window->children; node; node = node->next)
4167 {
4168 GdkWindow *child = node->data;
4169
4170 if (!GDK_WINDOW_DESTROYED (child) &&
4171 (recurse_mode == PROCESS_UPDATES_WITH_ALL_CHILDREN ||
4172 (recurse_mode == PROCESS_UPDATES_WITH_SAME_CLOCK_CHILDREN &&
4173 child->frame_clock == NULL)))
4174 {
4175 find_impl_windows_to_update (list, child, recurse_mode);
4176 }
4177 }
4178 }
4179
4180 /* add reference count so the window cannot be deleted in a callback */
4181 if (window->impl_window == window)
4182 g_ptr_array_add (list, g_object_ref (window));
4183 }
4184
4185 static void
gdk_window_process_updates_with_mode(GdkWindow * window,int recurse_mode)4186 gdk_window_process_updates_with_mode (GdkWindow *window,
4187 int recurse_mode)
4188 {
4189 GPtrArray *list;
4190 int i;
4191
4192 g_return_if_fail (GDK_IS_WINDOW (window));
4193
4194 if (GDK_WINDOW_DESTROYED (window))
4195 return;
4196
4197 list = g_ptr_array_new_with_free_func (g_object_unref);
4198 find_impl_windows_to_update (list, window, recurse_mode);
4199
4200 if (window->impl_window != window)
4201 g_ptr_array_add (list, g_object_ref (window->impl_window));
4202
4203 for (i = (int)list->len - 1; i >= 0; i --)
4204 {
4205 GdkWindow *impl_window = g_ptr_array_index (list, i);
4206
4207 if (impl_window->update_area &&
4208 !impl_window->update_freeze_count &&
4209 !gdk_window_is_toplevel_frozen (impl_window) &&
4210
4211 /* Don't recurse into process_updates_internal, we'll
4212 * do the update later when idle instead. */
4213 !impl_window->in_update)
4214 {
4215 gdk_window_process_updates_internal (impl_window);
4216 gdk_window_remove_update_window (impl_window);
4217 }
4218 }
4219
4220 g_ptr_array_free (list, TRUE);
4221 }
4222
4223 /**
4224 * gdk_window_process_updates:
4225 * @window: a #GdkWindow
4226 * @update_children: whether to also process updates for child windows
4227 *
4228 * Sends one or more expose events to @window. The areas in each
4229 * expose event will cover the entire update area for the window (see
4230 * gdk_window_invalidate_region() for details). Normally GDK calls
4231 * gdk_window_process_all_updates() on your behalf, so there’s no
4232 * need to call this function unless you want to force expose events
4233 * to be delivered immediately and synchronously (vs. the usual
4234 * case, where GDK delivers them in an idle handler). Occasionally
4235 * this is useful to produce nicer scrolling behavior, for example.
4236 *
4237 * Deprecated: 3.22
4238 **/
4239 void
gdk_window_process_updates(GdkWindow * window,gboolean update_children)4240 gdk_window_process_updates (GdkWindow *window,
4241 gboolean update_children)
4242 {
4243 g_return_if_fail (GDK_IS_WINDOW (window));
4244
4245 gdk_window_process_updates_with_mode (window,
4246 update_children ?
4247 PROCESS_UPDATES_WITH_ALL_CHILDREN :
4248 PROCESS_UPDATES_NO_RECURSE);
4249 }
4250
4251 static void
gdk_window_invalidate_rect_full(GdkWindow * window,const GdkRectangle * rect,gboolean invalidate_children)4252 gdk_window_invalidate_rect_full (GdkWindow *window,
4253 const GdkRectangle *rect,
4254 gboolean invalidate_children)
4255 {
4256 GdkRectangle window_rect;
4257 cairo_region_t *region;
4258
4259 g_return_if_fail (GDK_IS_WINDOW (window));
4260
4261 if (GDK_WINDOW_DESTROYED (window))
4262 return;
4263
4264 if (window->input_only || !window->viewable)
4265 return;
4266
4267 if (!rect)
4268 {
4269 window_rect.x = 0;
4270 window_rect.y = 0;
4271 window_rect.width = window->width;
4272 window_rect.height = window->height;
4273 rect = &window_rect;
4274 }
4275
4276 region = cairo_region_create_rectangle (rect);
4277 gdk_window_invalidate_region_full (window, region, invalidate_children);
4278 cairo_region_destroy (region);
4279 }
4280
4281 /**
4282 * gdk_window_invalidate_rect:
4283 * @window: a #GdkWindow
4284 * @rect: (allow-none): rectangle to invalidate or %NULL to invalidate the whole
4285 * window
4286 * @invalidate_children: whether to also invalidate child windows
4287 *
4288 * A convenience wrapper around gdk_window_invalidate_region() which
4289 * invalidates a rectangular region. See
4290 * gdk_window_invalidate_region() for details.
4291 **/
4292 void
gdk_window_invalidate_rect(GdkWindow * window,const GdkRectangle * rect,gboolean invalidate_children)4293 gdk_window_invalidate_rect (GdkWindow *window,
4294 const GdkRectangle *rect,
4295 gboolean invalidate_children)
4296 {
4297 gdk_window_invalidate_rect_full (window, rect, invalidate_children);
4298 }
4299
4300 /**
4301 * gdk_window_set_invalidate_handler: (skip)
4302 * @window: a #GdkWindow
4303 * @handler: a #GdkWindowInvalidateHandlerFunc callback function
4304 *
4305 * Registers an invalidate handler for a specific window. This
4306 * will get called whenever a region in the window or its children
4307 * is invalidated.
4308 *
4309 * This can be used to record the invalidated region, which is
4310 * useful if you are keeping an offscreen copy of some region
4311 * and want to keep it up to date. You can also modify the
4312 * invalidated region in case you’re doing some effect where
4313 * e.g. a child widget appears in multiple places.
4314 *
4315 * Since: 3.10
4316 **/
4317 void
gdk_window_set_invalidate_handler(GdkWindow * window,GdkWindowInvalidateHandlerFunc handler)4318 gdk_window_set_invalidate_handler (GdkWindow *window,
4319 GdkWindowInvalidateHandlerFunc handler)
4320 {
4321 window->invalidate_handler = handler;
4322 }
4323
4324 static void
draw_ugly_color(GdkWindow * window,const cairo_region_t * region,int color)4325 draw_ugly_color (GdkWindow *window,
4326 const cairo_region_t *region,
4327 int color)
4328 {
4329 cairo_t *cr;
4330
4331 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
4332 cr = gdk_cairo_create (window);
4333 G_GNUC_END_IGNORE_DEPRECATIONS
4334
4335 /* Draw ugly color all over the newly-invalid region */
4336 if (color == 0)
4337 cairo_set_source_rgb (cr, 50000/65535., 10000/65535., 10000/65535.);
4338 else
4339 cairo_set_source_rgb (cr, 10000/65535., 50000/65535., 10000/65535.);
4340
4341 gdk_cairo_region (cr, region);
4342 cairo_fill (cr);
4343
4344 cairo_destroy (cr);
4345 }
4346
4347 static void
impl_window_add_update_area(GdkWindow * impl_window,cairo_region_t * region)4348 impl_window_add_update_area (GdkWindow *impl_window,
4349 cairo_region_t *region)
4350 {
4351 if (impl_window->update_area)
4352 cairo_region_union (impl_window->update_area, region);
4353 else
4354 {
4355 gdk_window_add_update_window (impl_window);
4356 impl_window->update_area = cairo_region_copy (region);
4357 gdk_window_schedule_update (impl_window);
4358 }
4359 }
4360
4361 static void
4362 gdk_window_invalidate_maybe_recurse_full (GdkWindow *window,
4363 const cairo_region_t *region,
4364 GdkWindowChildFunc child_func,
4365 gpointer user_data);
4366
4367 /* Returns true if window is a decendant of parent, but stops looking
4368 * at the first native window. Also ensures that all parents match
4369 * child_func if non-null..
4370 *
4371 * This is useful in combination with
4372 * window->impl_window->native_children as it lets you find all native
4373 * decendants in an efficient way (assuming few children are native).
4374 */
4375 static gboolean
has_visible_ancestor_in_impl(GdkWindow * window,GdkWindow * ancestor,GdkWindowChildFunc child_func,gpointer user_data)4376 has_visible_ancestor_in_impl (GdkWindow *window,
4377 GdkWindow *ancestor,
4378 GdkWindowChildFunc child_func,
4379 gpointer user_data)
4380 {
4381 GdkWindow *p;
4382 GdkWindow *stop_at;
4383
4384 p = window->parent;
4385 stop_at = p->impl_window;
4386 while (p != NULL)
4387 {
4388 if (!p->viewable)
4389 return FALSE;
4390 if (child_func &&
4391 !(*child_func) ((GdkWindow *)p, user_data))
4392 return FALSE;
4393 if (p == ancestor)
4394 return TRUE;
4395 if (p == stop_at)
4396 return FALSE;
4397 p = p->parent;
4398 }
4399 return FALSE;
4400 }
4401
4402 static void
invalidate_impl_subwindows(GdkWindow * window,const cairo_region_t * region,GdkWindowChildFunc child_func,gpointer user_data)4403 invalidate_impl_subwindows (GdkWindow *window,
4404 const cairo_region_t *region,
4405 GdkWindowChildFunc child_func,
4406 gpointer user_data)
4407 {
4408 GList *l;
4409
4410 /* Iterate over all native children of the native window
4411 that window is in. */
4412 for (l = window->impl_window->native_children;
4413 l != NULL;
4414 l = l->next)
4415 {
4416 GdkWindow *native_child = l->data;
4417 cairo_region_t *tmp;
4418 int dx, dy;
4419
4420 if (native_child->input_only)
4421 continue;
4422
4423 /* Then skip any that does not have window as an ancestor,
4424 * also checking that the ancestors are visible and pass child_func
4425 * This is fast if we assume native children are rare */
4426 if (!has_visible_ancestor_in_impl (native_child, window,
4427 child_func, user_data))
4428 continue;
4429
4430 dx = native_child->parent->abs_x + native_child->x - window->abs_x;
4431 dy = native_child->parent->abs_y + native_child->y - window->abs_y;
4432
4433 tmp = cairo_region_copy (region);
4434 cairo_region_translate (tmp, -dx, -dy);
4435 gdk_window_invalidate_maybe_recurse_full (native_child,
4436 tmp, child_func, user_data);
4437 cairo_region_destroy (tmp);
4438 }
4439 }
4440
4441 static void
gdk_window_invalidate_maybe_recurse_full(GdkWindow * window,const cairo_region_t * region,GdkWindowChildFunc child_func,gpointer user_data)4442 gdk_window_invalidate_maybe_recurse_full (GdkWindow *window,
4443 const cairo_region_t *region,
4444 GdkWindowChildFunc child_func,
4445 gpointer user_data)
4446 {
4447 cairo_region_t *visible_region;
4448 cairo_rectangle_int_t r;
4449 GdkDisplay *display;
4450
4451 g_return_if_fail (GDK_IS_WINDOW (window));
4452
4453 if (GDK_WINDOW_DESTROYED (window))
4454 return;
4455
4456 if (window->input_only ||
4457 !window->viewable ||
4458 cairo_region_is_empty (region) ||
4459 window->window_type == GDK_WINDOW_ROOT)
4460 return;
4461
4462 r.x = 0;
4463 r.y = 0;
4464
4465 visible_region = cairo_region_copy (region);
4466
4467 if (child_func)
4468 invalidate_impl_subwindows (window, region, child_func, user_data);
4469
4470 display = gdk_window_get_display (window);
4471 if (gdk_display_get_debug_updates (display))
4472 draw_ugly_color (window, visible_region, 0);
4473
4474 while (window != NULL &&
4475 !cairo_region_is_empty (visible_region))
4476 {
4477 if (window->invalidate_handler)
4478 window->invalidate_handler (window, visible_region);
4479
4480 r.width = window->width;
4481 r.height = window->height;
4482 cairo_region_intersect_rectangle (visible_region, &r);
4483
4484 if (gdk_window_has_impl (window))
4485 {
4486 impl_window_add_update_area (window, visible_region);
4487 break;
4488 }
4489 else
4490 {
4491 cairo_region_translate (visible_region,
4492 window->x, window->y);
4493 window = window->parent;
4494 }
4495 }
4496
4497 cairo_region_destroy (visible_region);
4498 }
4499
4500 /**
4501 * gdk_window_invalidate_maybe_recurse:
4502 * @window: a #GdkWindow
4503 * @region: a #cairo_region_t
4504 * @child_func: (scope call) (allow-none): function to use to decide if to
4505 * recurse to a child, %NULL means never recurse.
4506 * @user_data: data passed to @child_func
4507 *
4508 * Adds @region to the update area for @window. The update area is the
4509 * region that needs to be redrawn, or “dirty region.” The call
4510 * gdk_window_process_updates() sends one or more expose events to the
4511 * window, which together cover the entire update area. An
4512 * application would normally redraw the contents of @window in
4513 * response to those expose events.
4514 *
4515 * GDK will call gdk_window_process_all_updates() on your behalf
4516 * whenever your program returns to the main loop and becomes idle, so
4517 * normally there’s no need to do that manually, you just need to
4518 * invalidate regions that you know should be redrawn.
4519 *
4520 * The @child_func parameter controls whether the region of
4521 * each child window that intersects @region will also be invalidated.
4522 * Only children for which @child_func returns #TRUE will have the area
4523 * invalidated.
4524 **/
4525 void
gdk_window_invalidate_maybe_recurse(GdkWindow * window,const cairo_region_t * region,GdkWindowChildFunc child_func,gpointer user_data)4526 gdk_window_invalidate_maybe_recurse (GdkWindow *window,
4527 const cairo_region_t *region,
4528 GdkWindowChildFunc child_func,
4529 gpointer user_data)
4530 {
4531 gdk_window_invalidate_maybe_recurse_full (window, region,
4532 child_func, user_data);
4533 }
4534
4535 static gboolean
true_predicate(GdkWindow * window,gpointer user_data)4536 true_predicate (GdkWindow *window,
4537 gpointer user_data)
4538 {
4539 return TRUE;
4540 }
4541
4542 static void
gdk_window_invalidate_region_full(GdkWindow * window,const cairo_region_t * region,gboolean invalidate_children)4543 gdk_window_invalidate_region_full (GdkWindow *window,
4544 const cairo_region_t *region,
4545 gboolean invalidate_children)
4546 {
4547 gdk_window_invalidate_maybe_recurse_full (window, region,
4548 invalidate_children ?
4549 true_predicate : (gboolean (*) (GdkWindow *, gpointer))NULL,
4550 NULL);
4551 }
4552
4553 /**
4554 * gdk_window_invalidate_region:
4555 * @window: a #GdkWindow
4556 * @region: a #cairo_region_t
4557 * @invalidate_children: %TRUE to also invalidate child windows
4558 *
4559 * Adds @region to the update area for @window. The update area is the
4560 * region that needs to be redrawn, or “dirty region.” The call
4561 * gdk_window_process_updates() sends one or more expose events to the
4562 * window, which together cover the entire update area. An
4563 * application would normally redraw the contents of @window in
4564 * response to those expose events.
4565 *
4566 * GDK will call gdk_window_process_all_updates() on your behalf
4567 * whenever your program returns to the main loop and becomes idle, so
4568 * normally there’s no need to do that manually, you just need to
4569 * invalidate regions that you know should be redrawn.
4570 *
4571 * The @invalidate_children parameter controls whether the region of
4572 * each child window that intersects @region will also be invalidated.
4573 * If %FALSE, then the update area for child windows will remain
4574 * unaffected. See gdk_window_invalidate_maybe_recurse if you need
4575 * fine grained control over which children are invalidated.
4576 **/
4577 void
gdk_window_invalidate_region(GdkWindow * window,const cairo_region_t * region,gboolean invalidate_children)4578 gdk_window_invalidate_region (GdkWindow *window,
4579 const cairo_region_t *region,
4580 gboolean invalidate_children)
4581 {
4582 gdk_window_invalidate_maybe_recurse (window, region,
4583 invalidate_children ?
4584 true_predicate : (gboolean (*) (GdkWindow *, gpointer))NULL,
4585 NULL);
4586 }
4587
4588 /**
4589 * _gdk_window_invalidate_for_expose:
4590 * @window: a #GdkWindow
4591 * @region: a #cairo_region_t
4592 *
4593 * Adds @region to the update area for @window. The update area is the
4594 * region that needs to be redrawn, or “dirty region.” The call
4595 * gdk_window_process_updates() sends one or more expose events to the
4596 * window, which together cover the entire update area. An
4597 * application would normally redraw the contents of @window in
4598 * response to those expose events.
4599 *
4600 * GDK will call gdk_window_process_all_updates() on your behalf
4601 * whenever your program returns to the main loop and becomes idle, so
4602 * normally there’s no need to do that manually, you just need to
4603 * invalidate regions that you know should be redrawn.
4604 *
4605 * This version of invalidation is used when you recieve expose events
4606 * from the native window system. It exposes the native window, plus
4607 * any non-native child windows (but not native child windows, as those would
4608 * have gotten their own expose events).
4609 **/
4610 void
_gdk_window_invalidate_for_expose(GdkWindow * window,cairo_region_t * region)4611 _gdk_window_invalidate_for_expose (GdkWindow *window,
4612 cairo_region_t *region)
4613 {
4614 gdk_window_invalidate_maybe_recurse_full (window, region,
4615 (gboolean (*) (GdkWindow *, gpointer))gdk_window_has_no_impl,
4616 NULL);
4617 }
4618
4619
4620 /**
4621 * gdk_window_get_update_area:
4622 * @window: a #GdkWindow
4623 *
4624 * Transfers ownership of the update area from @window to the caller
4625 * of the function. That is, after calling this function, @window will
4626 * no longer have an invalid/dirty region; the update area is removed
4627 * from @window and handed to you. If a window has no update area,
4628 * gdk_window_get_update_area() returns %NULL. You are responsible for
4629 * calling cairo_region_destroy() on the returned region if it’s non-%NULL.
4630 *
4631 * Returns: the update area for @window
4632 **/
4633 cairo_region_t *
gdk_window_get_update_area(GdkWindow * window)4634 gdk_window_get_update_area (GdkWindow *window)
4635 {
4636 GdkWindow *impl_window;
4637 cairo_region_t *tmp_region, *to_remove;
4638
4639 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
4640
4641 impl_window = gdk_window_get_impl_window (window);
4642
4643 if (impl_window->update_area)
4644 {
4645 tmp_region = cairo_region_copy (window->clip_region);
4646 /* Convert to impl coords */
4647 cairo_region_translate (tmp_region, window->abs_x, window->abs_y);
4648 cairo_region_intersect (tmp_region, impl_window->update_area);
4649
4650 if (cairo_region_is_empty (tmp_region))
4651 {
4652 cairo_region_destroy (tmp_region);
4653 return NULL;
4654 }
4655 else
4656 {
4657 /* Convert from impl coords */
4658 cairo_region_translate (tmp_region, -window->abs_x, -window->abs_y);
4659
4660 /* Don't remove any update area that is overlapped by sibling windows
4661 or child windows as these really need to be repainted independently of this window. */
4662 to_remove = cairo_region_copy (tmp_region);
4663
4664 remove_child_area (window, FALSE, to_remove);
4665 remove_sibling_overlapped_area (window, to_remove);
4666
4667 /* Remove from update_area */
4668 cairo_region_translate (to_remove, window->abs_x, window->abs_y);
4669 cairo_region_subtract (impl_window->update_area, to_remove);
4670
4671 cairo_region_destroy (to_remove);
4672
4673 if (cairo_region_is_empty (impl_window->update_area))
4674 {
4675 cairo_region_destroy (impl_window->update_area);
4676 impl_window->update_area = NULL;
4677
4678 gdk_window_remove_update_window ((GdkWindow *)impl_window);
4679 }
4680
4681 return tmp_region;
4682 }
4683 }
4684 else
4685 return NULL;
4686 }
4687
4688 /**
4689 * _gdk_window_clear_update_area:
4690 * @window: a #GdkWindow.
4691 *
4692 * Internal function to clear the update area for a window. This
4693 * is called when the window is hidden or destroyed.
4694 **/
4695 void
_gdk_window_clear_update_area(GdkWindow * window)4696 _gdk_window_clear_update_area (GdkWindow *window)
4697 {
4698 g_return_if_fail (GDK_IS_WINDOW (window));
4699
4700 if (window->update_area)
4701 {
4702 gdk_window_remove_update_window (window);
4703
4704 cairo_region_destroy (window->update_area);
4705 window->update_area = NULL;
4706 }
4707 }
4708
4709 /**
4710 * gdk_window_freeze_updates:
4711 * @window: a #GdkWindow
4712 *
4713 * Temporarily freezes a window such that it won’t receive expose
4714 * events. The window will begin receiving expose events again when
4715 * gdk_window_thaw_updates() is called. If gdk_window_freeze_updates()
4716 * has been called more than once, gdk_window_thaw_updates() must be called
4717 * an equal number of times to begin processing exposes.
4718 **/
4719 void
gdk_window_freeze_updates(GdkWindow * window)4720 gdk_window_freeze_updates (GdkWindow *window)
4721 {
4722 GdkWindow *impl_window;
4723
4724 g_return_if_fail (GDK_IS_WINDOW (window));
4725
4726 impl_window = gdk_window_get_impl_window (window);
4727 impl_window->update_freeze_count++;
4728 }
4729
4730 /**
4731 * gdk_window_thaw_updates:
4732 * @window: a #GdkWindow
4733 *
4734 * Thaws a window frozen with gdk_window_freeze_updates().
4735 **/
4736 void
gdk_window_thaw_updates(GdkWindow * window)4737 gdk_window_thaw_updates (GdkWindow *window)
4738 {
4739 GdkWindow *impl_window;
4740
4741 g_return_if_fail (GDK_IS_WINDOW (window));
4742
4743 impl_window = gdk_window_get_impl_window (window);
4744
4745 g_return_if_fail (impl_window->update_freeze_count > 0);
4746
4747 if (--impl_window->update_freeze_count == 0)
4748 gdk_window_schedule_update (GDK_WINDOW (impl_window));
4749 }
4750
4751 /**
4752 * gdk_window_freeze_toplevel_updates_libgtk_only:
4753 * @window: a #GdkWindow
4754 *
4755 * Temporarily freezes a window and all its descendants such that it won't
4756 * receive expose events. The window will begin receiving expose events
4757 * again when gdk_window_thaw_toplevel_updates_libgtk_only() is called. If
4758 * gdk_window_freeze_toplevel_updates_libgtk_only()
4759 * has been called more than once,
4760 * gdk_window_thaw_toplevel_updates_libgtk_only() must be called
4761 * an equal number of times to begin processing exposes.
4762 *
4763 * This function is not part of the GDK public API and is only
4764 * for use by GTK+.
4765 *
4766 * Deprecated: 3.16: This symbol was never meant to be used outside of GTK+
4767 */
4768 void
gdk_window_freeze_toplevel_updates_libgtk_only(GdkWindow * window)4769 gdk_window_freeze_toplevel_updates_libgtk_only (GdkWindow *window)
4770 {
4771 gdk_window_freeze_toplevel_updates (window);
4772 }
4773
4774 void
gdk_window_freeze_toplevel_updates(GdkWindow * window)4775 gdk_window_freeze_toplevel_updates (GdkWindow *window)
4776 {
4777 g_return_if_fail (GDK_IS_WINDOW (window));
4778 g_return_if_fail (window->window_type != GDK_WINDOW_CHILD);
4779
4780 window->update_and_descendants_freeze_count++;
4781 _gdk_frame_clock_freeze (gdk_window_get_frame_clock (window));
4782 }
4783
4784 /**
4785 * gdk_window_thaw_toplevel_updates_libgtk_only:
4786 * @window: a #GdkWindow
4787 *
4788 * Thaws a window frozen with
4789 * gdk_window_freeze_toplevel_updates_libgtk_only().
4790 *
4791 * This function is not part of the GDK public API and is only
4792 * for use by GTK+.
4793 *
4794 * Deprecated: 3.16: This symbol was never meant to be used outside of GTK+
4795 */
4796 void
gdk_window_thaw_toplevel_updates_libgtk_only(GdkWindow * window)4797 gdk_window_thaw_toplevel_updates_libgtk_only (GdkWindow *window)
4798 {
4799 gdk_window_thaw_toplevel_updates (window);
4800 }
4801
4802 void
gdk_window_thaw_toplevel_updates(GdkWindow * window)4803 gdk_window_thaw_toplevel_updates (GdkWindow *window)
4804 {
4805 g_return_if_fail (GDK_IS_WINDOW (window));
4806 g_return_if_fail (window->window_type != GDK_WINDOW_CHILD);
4807 g_return_if_fail (window->update_and_descendants_freeze_count > 0);
4808
4809 window->update_and_descendants_freeze_count--;
4810 _gdk_frame_clock_thaw (gdk_window_get_frame_clock (window));
4811
4812 gdk_window_schedule_update (window);
4813 }
4814
4815 /**
4816 * gdk_window_set_debug_updates:
4817 * @setting: %TRUE to turn on update debugging
4818 *
4819 * With update debugging enabled, calls to
4820 * gdk_window_invalidate_region() clear the invalidated region of the
4821 * screen to a noticeable color, and GDK pauses for a short time
4822 * before sending exposes to windows during
4823 * gdk_window_process_updates(). The net effect is that you can see
4824 * the invalid region for each window and watch redraws as they
4825 * occur. This allows you to diagnose inefficiencies in your application.
4826 *
4827 * In essence, because the GDK rendering model prevents all flicker,
4828 * if you are redrawing the same region 400 times you may never
4829 * notice, aside from noticing a speed problem. Enabling update
4830 * debugging causes GTK to flicker slowly and noticeably, so you can
4831 * see exactly what’s being redrawn when, in what order.
4832 *
4833 * The --gtk-debug=updates command line option passed to GTK+ programs
4834 * enables this debug option at application startup time. That's
4835 * usually more useful than calling gdk_window_set_debug_updates()
4836 * yourself, though you might want to use this function to enable
4837 * updates sometime after application startup time.
4838 *
4839 * Deprecated: 3.22
4840 */
4841 void
gdk_window_set_debug_updates(gboolean setting)4842 gdk_window_set_debug_updates (gboolean setting)
4843 {
4844 _gdk_debug_updates = setting;
4845 }
4846
4847 /**
4848 * gdk_window_constrain_size:
4849 * @geometry: a #GdkGeometry structure
4850 * @flags: a mask indicating what portions of @geometry are set
4851 * @width: desired width of window
4852 * @height: desired height of the window
4853 * @new_width: (out): location to store resulting width
4854 * @new_height: (out): location to store resulting height
4855 *
4856 * Constrains a desired width and height according to a
4857 * set of geometry hints (such as minimum and maximum size).
4858 */
4859 void
gdk_window_constrain_size(GdkGeometry * geometry,GdkWindowHints flags,gint width,gint height,gint * new_width,gint * new_height)4860 gdk_window_constrain_size (GdkGeometry *geometry,
4861 GdkWindowHints flags,
4862 gint width,
4863 gint height,
4864 gint *new_width,
4865 gint *new_height)
4866 {
4867 /* This routine is partially borrowed from fvwm.
4868 *
4869 * Copyright 1993, Robert Nation
4870 * You may use this code for any purpose, as long as the original
4871 * copyright remains in the source code and all documentation
4872 *
4873 * which in turn borrows parts of the algorithm from uwm
4874 */
4875 gint min_width = 0;
4876 gint min_height = 0;
4877 gint base_width = 0;
4878 gint base_height = 0;
4879 gint xinc = 1;
4880 gint yinc = 1;
4881 gint max_width = G_MAXINT;
4882 gint max_height = G_MAXINT;
4883
4884 #define FLOOR(value, base) ( ((gint) ((value) / (base))) * (base) )
4885
4886 if ((flags & GDK_HINT_BASE_SIZE) && (flags & GDK_HINT_MIN_SIZE))
4887 {
4888 base_width = geometry->base_width;
4889 base_height = geometry->base_height;
4890 min_width = geometry->min_width;
4891 min_height = geometry->min_height;
4892 }
4893 else if (flags & GDK_HINT_BASE_SIZE)
4894 {
4895 base_width = geometry->base_width;
4896 base_height = geometry->base_height;
4897 min_width = geometry->base_width;
4898 min_height = geometry->base_height;
4899 }
4900 else if (flags & GDK_HINT_MIN_SIZE)
4901 {
4902 base_width = geometry->min_width;
4903 base_height = geometry->min_height;
4904 min_width = geometry->min_width;
4905 min_height = geometry->min_height;
4906 }
4907
4908 if (flags & GDK_HINT_MAX_SIZE)
4909 {
4910 max_width = geometry->max_width ;
4911 max_height = geometry->max_height;
4912 }
4913
4914 if (flags & GDK_HINT_RESIZE_INC)
4915 {
4916 xinc = MAX (xinc, geometry->width_inc);
4917 yinc = MAX (yinc, geometry->height_inc);
4918 }
4919
4920 /* clamp width and height to min and max values
4921 */
4922 width = CLAMP (width, min_width, max_width);
4923 height = CLAMP (height, min_height, max_height);
4924
4925 /* shrink to base + N * inc
4926 */
4927 width = base_width + FLOOR (width - base_width, xinc);
4928 height = base_height + FLOOR (height - base_height, yinc);
4929
4930 /* constrain aspect ratio, according to:
4931 *
4932 * width
4933 * min_aspect <= -------- <= max_aspect
4934 * height
4935 */
4936
4937 if (flags & GDK_HINT_ASPECT &&
4938 geometry->min_aspect > 0 &&
4939 geometry->max_aspect > 0)
4940 {
4941 gint delta;
4942
4943 if (geometry->min_aspect * height > width)
4944 {
4945 delta = FLOOR (height - width / geometry->min_aspect, yinc);
4946 if (height - delta >= min_height)
4947 height -= delta;
4948 else
4949 {
4950 delta = FLOOR (height * geometry->min_aspect - width, xinc);
4951 if (width + delta <= max_width)
4952 width += delta;
4953 }
4954 }
4955
4956 if (geometry->max_aspect * height < width)
4957 {
4958 delta = FLOOR (width - height * geometry->max_aspect, xinc);
4959 if (width - delta >= min_width)
4960 width -= delta;
4961 else
4962 {
4963 delta = FLOOR (width / geometry->max_aspect - height, yinc);
4964 if (height + delta <= max_height)
4965 height += delta;
4966 }
4967 }
4968 }
4969
4970 #undef FLOOR
4971
4972 *new_width = width;
4973 *new_height = height;
4974 }
4975
4976 /**
4977 * gdk_window_get_pointer:
4978 * @window: a #GdkWindow
4979 * @x: (out) (allow-none): return location for X coordinate of pointer or %NULL to not
4980 * return the X coordinate
4981 * @y: (out) (allow-none): return location for Y coordinate of pointer or %NULL to not
4982 * return the Y coordinate
4983 * @mask: (out) (allow-none): return location for modifier mask or %NULL to not return the
4984 * modifier mask
4985 *
4986 * Obtains the current pointer position and modifier state.
4987 * The position is given in coordinates relative to the upper left
4988 * corner of @window.
4989 *
4990 * Returns: (nullable) (transfer none): the window containing the
4991 * pointer (as with gdk_window_at_pointer()), or %NULL if the window
4992 * containing the pointer isn’t known to GDK
4993 *
4994 * Deprecated: 3.0: Use gdk_window_get_device_position() instead.
4995 **/
4996 GdkWindow*
gdk_window_get_pointer(GdkWindow * window,gint * x,gint * y,GdkModifierType * mask)4997 gdk_window_get_pointer (GdkWindow *window,
4998 gint *x,
4999 gint *y,
5000 GdkModifierType *mask)
5001 {
5002 GdkDisplay *display;
5003 GdkDevice *pointer;
5004
5005 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
5006
5007 display = gdk_window_get_display (window);
5008 pointer = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
5009
5010 return gdk_window_get_device_position (window, pointer, x, y, mask);
5011 }
5012
5013 /**
5014 * gdk_window_get_device_position_double:
5015 * @window: a #GdkWindow.
5016 * @device: pointer #GdkDevice to query to.
5017 * @x: (out) (allow-none): return location for the X coordinate of @device, or %NULL.
5018 * @y: (out) (allow-none): return location for the Y coordinate of @device, or %NULL.
5019 * @mask: (out) (allow-none): return location for the modifier mask, or %NULL.
5020 *
5021 * Obtains the current device position in doubles and modifier state.
5022 * The position is given in coordinates relative to the upper left
5023 * corner of @window.
5024 *
5025 * Returns: (nullable) (transfer none): The window underneath @device
5026 * (as with gdk_device_get_window_at_position()), or %NULL if the
5027 * window is not known to GDK.
5028 *
5029 * Since: 3.10
5030 **/
5031 GdkWindow *
gdk_window_get_device_position_double(GdkWindow * window,GdkDevice * device,double * x,double * y,GdkModifierType * mask)5032 gdk_window_get_device_position_double (GdkWindow *window,
5033 GdkDevice *device,
5034 double *x,
5035 double *y,
5036 GdkModifierType *mask)
5037 {
5038 gdouble tmp_x, tmp_y;
5039 GdkModifierType tmp_mask;
5040 gboolean normal_child;
5041
5042 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
5043 g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
5044 g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
5045
5046 tmp_x = tmp_y = 0;
5047 tmp_mask = 0;
5048 normal_child = GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_device_state (window,
5049 device,
5050 &tmp_x, &tmp_y,
5051 &tmp_mask);
5052 /* We got the coords on the impl, convert to the window */
5053 tmp_x -= window->abs_x;
5054 tmp_y -= window->abs_y;
5055
5056 if (x)
5057 *x = tmp_x;
5058 if (y)
5059 *y = tmp_y;
5060 if (mask)
5061 *mask = tmp_mask;
5062
5063 _gdk_display_enable_motion_hints (gdk_window_get_display (window), device);
5064
5065 if (normal_child)
5066 return _gdk_window_find_child_at (window, tmp_x, tmp_y);
5067 return NULL;
5068 }
5069
5070 /**
5071 * gdk_window_get_device_position:
5072 * @window: a #GdkWindow.
5073 * @device: pointer #GdkDevice to query to.
5074 * @x: (out) (allow-none): return location for the X coordinate of @device, or %NULL.
5075 * @y: (out) (allow-none): return location for the Y coordinate of @device, or %NULL.
5076 * @mask: (out) (allow-none): return location for the modifier mask, or %NULL.
5077 *
5078 * Obtains the current device position and modifier state.
5079 * The position is given in coordinates relative to the upper left
5080 * corner of @window.
5081 *
5082 * Use gdk_window_get_device_position_double() if you need subpixel precision.
5083 *
5084 * Returns: (nullable) (transfer none): The window underneath @device
5085 * (as with gdk_device_get_window_at_position()), or %NULL if the
5086 * window is not known to GDK.
5087 *
5088 * Since: 3.0
5089 **/
5090 GdkWindow *
gdk_window_get_device_position(GdkWindow * window,GdkDevice * device,gint * x,gint * y,GdkModifierType * mask)5091 gdk_window_get_device_position (GdkWindow *window,
5092 GdkDevice *device,
5093 gint *x,
5094 gint *y,
5095 GdkModifierType *mask)
5096 {
5097 gdouble tmp_x, tmp_y;
5098
5099 window = gdk_window_get_device_position_double (window, device,
5100 &tmp_x, &tmp_y, mask);
5101 if (x)
5102 *x = round (tmp_x);
5103 if (y)
5104 *y = round (tmp_y);
5105
5106 return window;
5107 }
5108
5109 /**
5110 * gdk_get_default_root_window:
5111 *
5112 * Obtains the root window (parent all other windows are inside)
5113 * for the default display and screen.
5114 *
5115 * Returns: (transfer none): the default root window
5116 **/
5117 GdkWindow *
gdk_get_default_root_window(void)5118 gdk_get_default_root_window (void)
5119 {
5120 return gdk_screen_get_root_window (gdk_screen_get_default ());
5121 }
5122
5123 static void
get_all_native_children(GdkWindow * window,GList ** native)5124 get_all_native_children (GdkWindow *window,
5125 GList **native)
5126 {
5127 GdkWindow *child;
5128 GList *l;
5129
5130 for (l = window->children; l != NULL; l = l->next)
5131 {
5132 child = l->data;
5133
5134 if (gdk_window_has_impl (child))
5135 *native = g_list_prepend (*native, child);
5136 else
5137 get_all_native_children (child, native);
5138 }
5139 }
5140
5141
5142 static gboolean
gdk_window_raise_internal(GdkWindow * window)5143 gdk_window_raise_internal (GdkWindow *window)
5144 {
5145 GdkWindow *parent = window->parent;
5146 GdkWindow *above;
5147 GList *native_children;
5148 GList *l, listhead;
5149 GdkWindowImplClass *impl_class;
5150 gboolean did_raise = FALSE;
5151
5152 if (parent && parent->children->data != window)
5153 {
5154 parent->children = g_list_remove_link (parent->children, &window->children_list_node);
5155 parent->children = g_list_concat (&window->children_list_node, parent->children);
5156 did_raise = TRUE;
5157 }
5158
5159 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
5160 /* Just do native raise for toplevels */
5161 if (gdk_window_is_toplevel (window) ||
5162 /* The restack_under codepath should work correctly even if the parent
5163 is native, but it relies on the order of ->children to be correct,
5164 and some apps like SWT reorder the x windows without gdks knowledge,
5165 so we use raise directly in order to make these behave as before
5166 when using native windows */
5167 (gdk_window_has_impl (window) && gdk_window_has_impl (parent)))
5168 {
5169 impl_class->raise (window);
5170 }
5171 else if (gdk_window_has_impl (window))
5172 {
5173 above = find_native_sibling_above (parent, window);
5174 if (above)
5175 {
5176 listhead.data = window;
5177 listhead.next = NULL;
5178 listhead.prev = NULL;
5179 impl_class->restack_under ((GdkWindow *)above,
5180 &listhead);
5181 }
5182 else
5183 impl_class->raise (window);
5184 }
5185 else
5186 {
5187 native_children = NULL;
5188 get_all_native_children (window, &native_children);
5189 if (native_children != NULL)
5190 {
5191 above = find_native_sibling_above (parent, window);
5192
5193 if (above)
5194 impl_class->restack_under (above, native_children);
5195 else
5196 {
5197 /* Right order, since native_children is bottom-topmost first */
5198 for (l = native_children; l != NULL; l = l->next)
5199 impl_class->raise (l->data);
5200 }
5201
5202 g_list_free (native_children);
5203 }
5204 }
5205
5206 return did_raise;
5207 }
5208
5209 /* Returns TRUE If the native window was mapped or unmapped */
5210 static gboolean
set_viewable(GdkWindow * w,gboolean val)5211 set_viewable (GdkWindow *w,
5212 gboolean val)
5213 {
5214 GdkWindow *child;
5215 GdkWindowImplClass *impl_class;
5216 GList *l;
5217
5218 if (w->viewable == val)
5219 return FALSE;
5220
5221 w->viewable = val;
5222
5223 if (val)
5224 recompute_visible_regions (w, FALSE);
5225
5226 for (l = w->children; l != NULL; l = l->next)
5227 {
5228 child = l->data;
5229
5230 if (GDK_WINDOW_IS_MAPPED (child) &&
5231 child->window_type != GDK_WINDOW_FOREIGN)
5232 set_viewable (child, val);
5233 }
5234
5235 if (gdk_window_has_impl (w) &&
5236 w->window_type != GDK_WINDOW_FOREIGN &&
5237 !gdk_window_is_toplevel (w))
5238 {
5239 /* For most native windows we show/hide them not when they are
5240 * mapped/unmapped, because that may not produce the correct results.
5241 * For instance, if a native window have a non-native parent which is
5242 * hidden, but its native parent is viewable then showing the window
5243 * would make it viewable to X but its not viewable wrt the non-native
5244 * hierarchy. In order to handle this we track the gdk side viewability
5245 * and only map really viewable windows.
5246 *
5247 * There are two exceptions though:
5248 *
5249 * For foreign windows we don't want ever change the mapped state
5250 * except when explicitly done via gdk_window_show/hide, as this may
5251 * cause problems for client owning the foreign window when its window
5252 * is suddenly mapped or unmapped.
5253 *
5254 * For toplevel windows embedded in a foreign window (e.g. a plug)
5255 * we sometimes synthesize a map of a window, but the native
5256 * window is really shown by the embedder, so we don't want to
5257 * do the show ourselves. We can't really tell this case from the normal
5258 * toplevel show as such toplevels are seen by gdk as parents of the
5259 * root window, so we make an exception for all toplevels.
5260 */
5261
5262 impl_class = GDK_WINDOW_IMPL_GET_CLASS (w->impl);
5263 if (val)
5264 impl_class->show ((GdkWindow *)w, FALSE);
5265 else
5266 impl_class->hide ((GdkWindow *)w);
5267
5268 return TRUE;
5269 }
5270
5271 return FALSE;
5272 }
5273
5274 /* Returns TRUE If the native window was mapped or unmapped */
5275 gboolean
_gdk_window_update_viewable(GdkWindow * window)5276 _gdk_window_update_viewable (GdkWindow *window)
5277 {
5278 gboolean viewable;
5279
5280 if (window->window_type == GDK_WINDOW_FOREIGN ||
5281 window->window_type == GDK_WINDOW_ROOT)
5282 viewable = TRUE;
5283 else if (gdk_window_is_toplevel (window) ||
5284 window->parent->viewable)
5285 viewable = GDK_WINDOW_IS_MAPPED (window);
5286 else
5287 viewable = FALSE;
5288
5289 return set_viewable (window, viewable);
5290 }
5291
5292 static void
gdk_window_show_internal(GdkWindow * window,gboolean raise)5293 gdk_window_show_internal (GdkWindow *window, gboolean raise)
5294 {
5295 GdkWindowImplClass *impl_class;
5296 gboolean was_mapped, was_viewable;
5297 gboolean did_show, did_raise = FALSE;
5298
5299 g_return_if_fail (GDK_IS_WINDOW (window));
5300
5301 if (window->destroyed)
5302 return;
5303
5304 was_mapped = GDK_WINDOW_IS_MAPPED (window);
5305 was_viewable = window->viewable;
5306
5307 if (raise)
5308 {
5309 /* Keep children in (reverse) stacking order */
5310 did_raise = gdk_window_raise_internal (window);
5311 }
5312
5313 if (gdk_window_has_impl (window))
5314 {
5315 if (!was_mapped)
5316 gdk_synthesize_window_state (window,
5317 GDK_WINDOW_STATE_WITHDRAWN,
5318 GDK_WINDOW_STATE_FOCUSED);
5319 }
5320 else
5321 {
5322 window->state = 0;
5323 }
5324
5325 did_show = _gdk_window_update_viewable (window);
5326
5327 /* If it was already viewable the backend show op won't be called, call it
5328 again to ensure things happen right if the mapped tracking was not right
5329 for e.g. a foreign window.
5330 Dunno if this is strictly needed but its what happened pre-csw.
5331 Also show if not done by gdk_window_update_viewable. */
5332 if (gdk_window_has_impl (window) && (was_viewable || !did_show))
5333 {
5334 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
5335 impl_class->show (window, !did_show ? was_mapped : TRUE);
5336 }
5337
5338 if (!was_mapped && !gdk_window_has_impl (window))
5339 {
5340 if (window->event_mask & GDK_STRUCTURE_MASK)
5341 _gdk_make_event (window, GDK_MAP, NULL, FALSE);
5342
5343 if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
5344 _gdk_make_event (window, GDK_MAP, NULL, FALSE);
5345 }
5346
5347 if (!was_mapped || did_raise)
5348 {
5349 recompute_visible_regions (window, FALSE);
5350
5351 /* If any decendants became visible we need to send visibility notify */
5352 gdk_window_update_visibility_recursively (window, NULL);
5353
5354 if (gdk_window_is_viewable (window))
5355 {
5356 _gdk_synthesize_crossing_events_for_geometry_change (window);
5357 gdk_window_invalidate_rect_full (window, NULL, TRUE);
5358 }
5359 }
5360 }
5361
5362 /**
5363 * gdk_window_show_unraised:
5364 * @window: a #GdkWindow
5365 *
5366 * Shows a #GdkWindow onscreen, but does not modify its stacking
5367 * order. In contrast, gdk_window_show() will raise the window
5368 * to the top of the window stack.
5369 *
5370 * On the X11 platform, in Xlib terms, this function calls
5371 * XMapWindow() (it also updates some internal GDK state, which means
5372 * that you can’t really use XMapWindow() directly on a GDK window).
5373 */
5374 void
gdk_window_show_unraised(GdkWindow * window)5375 gdk_window_show_unraised (GdkWindow *window)
5376 {
5377 gdk_window_show_internal (window, FALSE);
5378 }
5379
5380 /**
5381 * gdk_window_raise:
5382 * @window: a #GdkWindow
5383 *
5384 * Raises @window to the top of the Z-order (stacking order), so that
5385 * other windows with the same parent window appear below @window.
5386 * This is true whether or not the windows are visible.
5387 *
5388 * If @window is a toplevel, the window manager may choose to deny the
5389 * request to move the window in the Z-order, gdk_window_raise() only
5390 * requests the restack, does not guarantee it.
5391 */
5392 void
gdk_window_raise(GdkWindow * window)5393 gdk_window_raise (GdkWindow *window)
5394 {
5395 gboolean did_raise;
5396
5397 g_return_if_fail (GDK_IS_WINDOW (window));
5398
5399 if (window->destroyed)
5400 return;
5401
5402 /* Keep children in (reverse) stacking order */
5403 did_raise = gdk_window_raise_internal (window);
5404
5405 if (did_raise &&
5406 !gdk_window_is_toplevel (window) &&
5407 gdk_window_is_viewable (window) &&
5408 !window->input_only)
5409 gdk_window_invalidate_region_full (window, window->clip_region, TRUE);
5410 }
5411
5412 static void
gdk_window_lower_internal(GdkWindow * window)5413 gdk_window_lower_internal (GdkWindow *window)
5414 {
5415 GdkWindow *parent = window->parent;
5416 GdkWindowImplClass *impl_class;
5417 GdkWindow *above;
5418 GList *native_children;
5419 GList *l, listhead;
5420
5421 if (parent)
5422 {
5423 parent->children = g_list_remove_link (parent->children, &window->children_list_node);
5424 parent->children = g_list_concat (parent->children, &window->children_list_node);
5425 }
5426
5427 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
5428 /* Just do native lower for toplevels */
5429 if (gdk_window_is_toplevel (window) ||
5430 /* The restack_under codepath should work correctly even if the parent
5431 is native, but it relies on the order of ->children to be correct,
5432 and some apps like SWT reorder the x windows without gdks knowledge,
5433 so we use lower directly in order to make these behave as before
5434 when using native windows */
5435 (gdk_window_has_impl (window) && gdk_window_has_impl (parent)))
5436 {
5437 impl_class->lower (window);
5438 }
5439 else if (gdk_window_has_impl (window))
5440 {
5441 above = find_native_sibling_above (parent, window);
5442 if (above)
5443 {
5444 listhead.data = window;
5445 listhead.next = NULL;
5446 listhead.prev = NULL;
5447 impl_class->restack_under ((GdkWindow *)above, &listhead);
5448 }
5449 else
5450 impl_class->raise (window);
5451 }
5452 else
5453 {
5454 native_children = NULL;
5455 get_all_native_children (window, &native_children);
5456 if (native_children != NULL)
5457 {
5458 above = find_native_sibling_above (parent, window);
5459
5460 if (above)
5461 impl_class->restack_under ((GdkWindow *)above,
5462 native_children);
5463 else
5464 {
5465 /* Right order, since native_children is bottom-topmost first */
5466 for (l = native_children; l != NULL; l = l->next)
5467 impl_class->raise (l->data);
5468 }
5469
5470 g_list_free (native_children);
5471 }
5472
5473 }
5474 }
5475
5476 static void
gdk_window_invalidate_in_parent(GdkWindow * private)5477 gdk_window_invalidate_in_parent (GdkWindow *private)
5478 {
5479 GdkRectangle r, child;
5480
5481 if (gdk_window_is_toplevel (private))
5482 return;
5483
5484 /* get the visible rectangle of the parent */
5485 r.x = r.y = 0;
5486 r.width = private->parent->width;
5487 r.height = private->parent->height;
5488
5489 child.x = private->x;
5490 child.y = private->y;
5491 child.width = private->width;
5492 child.height = private->height;
5493 gdk_rectangle_intersect (&r, &child, &r);
5494
5495 gdk_window_invalidate_rect_full (private->parent, &r, TRUE);
5496 }
5497
5498
5499 /**
5500 * gdk_window_lower:
5501 * @window: a #GdkWindow
5502 *
5503 * Lowers @window to the bottom of the Z-order (stacking order), so that
5504 * other windows with the same parent window appear above @window.
5505 * This is true whether or not the other windows are visible.
5506 *
5507 * If @window is a toplevel, the window manager may choose to deny the
5508 * request to move the window in the Z-order, gdk_window_lower() only
5509 * requests the restack, does not guarantee it.
5510 *
5511 * Note that gdk_window_show() raises the window again, so don’t call this
5512 * function before gdk_window_show(). (Try gdk_window_show_unraised().)
5513 */
5514 void
gdk_window_lower(GdkWindow * window)5515 gdk_window_lower (GdkWindow *window)
5516 {
5517 g_return_if_fail (GDK_IS_WINDOW (window));
5518
5519 if (window->destroyed)
5520 return;
5521
5522 /* Keep children in (reverse) stacking order */
5523 gdk_window_lower_internal (window);
5524
5525 _gdk_synthesize_crossing_events_for_geometry_change (window);
5526 gdk_window_invalidate_in_parent (window);
5527 }
5528
5529 /**
5530 * gdk_window_restack:
5531 * @window: a #GdkWindow
5532 * @sibling: (allow-none): a #GdkWindow that is a sibling of @window, or %NULL
5533 * @above: a boolean
5534 *
5535 * Changes the position of @window in the Z-order (stacking order), so that
5536 * it is above @sibling (if @above is %TRUE) or below @sibling (if @above is
5537 * %FALSE).
5538 *
5539 * If @sibling is %NULL, then this either raises (if @above is %TRUE) or
5540 * lowers the window.
5541 *
5542 * If @window is a toplevel, the window manager may choose to deny the
5543 * request to move the window in the Z-order, gdk_window_restack() only
5544 * requests the restack, does not guarantee it.
5545 *
5546 * Since: 2.18
5547 */
5548 void
gdk_window_restack(GdkWindow * window,GdkWindow * sibling,gboolean above)5549 gdk_window_restack (GdkWindow *window,
5550 GdkWindow *sibling,
5551 gboolean above)
5552 {
5553 GdkWindowImplClass *impl_class;
5554 GdkWindow *parent;
5555 GdkWindow *above_native;
5556 GList *sibling_link;
5557 GList *native_children;
5558 GList *l, listhead;
5559
5560 g_return_if_fail (GDK_IS_WINDOW (window));
5561 g_return_if_fail (sibling == NULL || GDK_IS_WINDOW (sibling));
5562
5563 if (window->destroyed)
5564 return;
5565
5566 if (sibling == NULL)
5567 {
5568 if (above)
5569 gdk_window_raise (window);
5570 else
5571 gdk_window_lower (window);
5572 return;
5573 }
5574
5575 if (gdk_window_is_toplevel (window))
5576 {
5577 g_return_if_fail (gdk_window_is_toplevel (sibling));
5578 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
5579 impl_class->restack_toplevel (window, sibling, above);
5580 return;
5581 }
5582
5583 parent = window->parent;
5584 if (parent)
5585 {
5586 sibling_link = g_list_find (parent->children, sibling);
5587 g_return_if_fail (sibling_link != NULL);
5588 if (sibling_link == NULL)
5589 return;
5590
5591 parent->children = g_list_remove_link (parent->children, &window->children_list_node);
5592 if (above)
5593 parent->children = list_insert_link_before (parent->children,
5594 sibling_link,
5595 &window->children_list_node);
5596 else
5597 parent->children = list_insert_link_before (parent->children,
5598 sibling_link->next,
5599 &window->children_list_node);
5600
5601 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
5602 if (gdk_window_has_impl (window))
5603 {
5604 above_native = find_native_sibling_above (parent, window);
5605 if (above_native)
5606 {
5607 listhead.data = window;
5608 listhead.next = NULL;
5609 listhead.prev = NULL;
5610 impl_class->restack_under (above_native, &listhead);
5611 }
5612 else
5613 impl_class->raise (window);
5614 }
5615 else
5616 {
5617 native_children = NULL;
5618 get_all_native_children (window, &native_children);
5619 if (native_children != NULL)
5620 {
5621 above_native = find_native_sibling_above (parent, window);
5622 if (above_native)
5623 impl_class->restack_under (above_native,
5624 native_children);
5625 else
5626 {
5627 /* Right order, since native_children is bottom-topmost first */
5628 for (l = native_children; l != NULL; l = l->next)
5629 impl_class->raise (l->data);
5630 }
5631
5632 g_list_free (native_children);
5633 }
5634 }
5635 }
5636
5637 _gdk_synthesize_crossing_events_for_geometry_change (window);
5638 gdk_window_invalidate_in_parent (window);
5639 }
5640
5641
5642 /**
5643 * gdk_window_show:
5644 * @window: a #GdkWindow
5645 *
5646 * Like gdk_window_show_unraised(), but also raises the window to the
5647 * top of the window stack (moves the window to the front of the
5648 * Z-order).
5649 *
5650 * This function maps a window so it’s visible onscreen. Its opposite
5651 * is gdk_window_hide().
5652 *
5653 * When implementing a #GtkWidget, you should call this function on the widget's
5654 * #GdkWindow as part of the “map” method.
5655 */
5656 void
gdk_window_show(GdkWindow * window)5657 gdk_window_show (GdkWindow *window)
5658 {
5659 gdk_window_show_internal (window, TRUE);
5660 }
5661
5662 /**
5663 * gdk_window_hide:
5664 * @window: a #GdkWindow
5665 *
5666 * For toplevel windows, withdraws them, so they will no longer be
5667 * known to the window manager; for all windows, unmaps them, so
5668 * they won’t be displayed. Normally done automatically as
5669 * part of gtk_widget_hide().
5670 */
5671 void
gdk_window_hide(GdkWindow * window)5672 gdk_window_hide (GdkWindow *window)
5673 {
5674 GdkWindowImplClass *impl_class;
5675 gboolean was_mapped, did_hide;
5676
5677 g_return_if_fail (GDK_IS_WINDOW (window));
5678
5679 if (window->destroyed)
5680 return;
5681
5682 was_mapped = GDK_WINDOW_IS_MAPPED (window);
5683
5684 if (gdk_window_has_impl (window))
5685 {
5686
5687 if (GDK_WINDOW_IS_MAPPED (window))
5688 gdk_synthesize_window_state (window,
5689 0,
5690 GDK_WINDOW_STATE_WITHDRAWN);
5691 }
5692 else if (was_mapped)
5693 {
5694 GdkDisplay *display;
5695 GdkDeviceManager *device_manager;
5696 GList *devices, *d;
5697
5698 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
5699
5700 /* May need to break grabs on children */
5701 display = gdk_window_get_display (window);
5702 device_manager = gdk_display_get_device_manager (display);
5703
5704 /* Get all devices */
5705 devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
5706 devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
5707 devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
5708
5709 for (d = devices; d; d = d->next)
5710 {
5711 GdkDevice *device = d->data;
5712
5713 if (_gdk_display_end_device_grab (display,
5714 device,
5715 _gdk_display_get_next_serial (display),
5716 window,
5717 TRUE))
5718 gdk_device_ungrab (device, GDK_CURRENT_TIME);
5719 }
5720
5721 window->state = GDK_WINDOW_STATE_WITHDRAWN;
5722 g_list_free (devices);
5723 G_GNUC_END_IGNORE_DEPRECATIONS;
5724 }
5725
5726 did_hide = _gdk_window_update_viewable (window);
5727
5728 /* Hide foreign window as those are not handled by update_viewable. */
5729 if (gdk_window_has_impl (window) && (!did_hide))
5730 {
5731 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
5732 impl_class->hide (window);
5733 }
5734
5735 gdk_window_clear_old_updated_area (window);
5736 recompute_visible_regions (window, FALSE);
5737
5738 /* all decendants became non-visible, we need to send visibility notify */
5739 gdk_window_update_visibility_recursively (window, NULL);
5740
5741 if (was_mapped && !gdk_window_has_impl (window))
5742 {
5743 if (window->event_mask & GDK_STRUCTURE_MASK)
5744 _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
5745
5746 if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
5747 _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
5748
5749 _gdk_synthesize_crossing_events_for_geometry_change (window->parent);
5750 }
5751
5752 /* Invalidate the rect */
5753 if (was_mapped)
5754 gdk_window_invalidate_in_parent (window);
5755 }
5756
5757 /**
5758 * gdk_window_withdraw:
5759 * @window: a toplevel #GdkWindow
5760 *
5761 * Withdraws a window (unmaps it and asks the window manager to forget about it).
5762 * This function is not really useful as gdk_window_hide() automatically
5763 * withdraws toplevel windows before hiding them.
5764 **/
5765 void
gdk_window_withdraw(GdkWindow * window)5766 gdk_window_withdraw (GdkWindow *window)
5767 {
5768 GdkWindowImplClass *impl_class;
5769 gboolean was_mapped;
5770 GdkGLContext *current_context;
5771
5772 g_return_if_fail (GDK_IS_WINDOW (window));
5773
5774 if (window->destroyed)
5775 return;
5776
5777 was_mapped = GDK_WINDOW_IS_MAPPED (window);
5778
5779 if (gdk_window_has_impl (window))
5780 {
5781 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
5782 impl_class->withdraw (window);
5783
5784 if (was_mapped)
5785 {
5786 if (window->event_mask & GDK_STRUCTURE_MASK)
5787 _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
5788
5789 if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
5790 _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
5791
5792 _gdk_synthesize_crossing_events_for_geometry_change (window->parent);
5793 }
5794
5795 current_context = gdk_gl_context_get_current ();
5796 if (current_context != NULL && gdk_gl_context_get_window (current_context) == window)
5797 gdk_gl_context_clear_current ();
5798
5799 recompute_visible_regions (window, FALSE);
5800 gdk_window_clear_old_updated_area (window);
5801 }
5802 }
5803
5804 /**
5805 * gdk_window_set_events:
5806 * @window: a #GdkWindow
5807 * @event_mask: event mask for @window
5808 *
5809 * The event mask for a window determines which events will be reported
5810 * for that window from all master input devices. For example, an event mask
5811 * including #GDK_BUTTON_PRESS_MASK means the window should report button
5812 * press events. The event mask is the bitwise OR of values from the
5813 * #GdkEventMask enumeration.
5814 *
5815 * See the [input handling overview][event-masks] for details.
5816 **/
5817 void
gdk_window_set_events(GdkWindow * window,GdkEventMask event_mask)5818 gdk_window_set_events (GdkWindow *window,
5819 GdkEventMask event_mask)
5820 {
5821 GdkWindowImplClass *impl_class;
5822 GdkDisplay *display;
5823
5824 g_return_if_fail (GDK_IS_WINDOW (window));
5825
5826 if (window->destroyed)
5827 return;
5828
5829 /* If motion hint is disabled, enable motion events again */
5830 display = gdk_window_get_display (window);
5831 if ((window->event_mask & GDK_POINTER_MOTION_HINT_MASK) &&
5832 !(event_mask & GDK_POINTER_MOTION_HINT_MASK))
5833 {
5834 GList *devices = window->devices_inside;
5835
5836 while (devices)
5837 {
5838 _gdk_display_enable_motion_hints (display, (GdkDevice *) devices->data);
5839 devices = devices->next;
5840 }
5841 }
5842
5843 window->event_mask = event_mask;
5844
5845 if (gdk_window_has_impl (window))
5846 {
5847 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
5848 impl_class->set_events (window,
5849 get_native_event_mask (window));
5850 }
5851
5852 }
5853
5854 /**
5855 * gdk_window_get_events:
5856 * @window: a #GdkWindow
5857 *
5858 * Gets the event mask for @window for all master input devices. See
5859 * gdk_window_set_events().
5860 *
5861 * Returns: event mask for @window
5862 **/
5863 GdkEventMask
gdk_window_get_events(GdkWindow * window)5864 gdk_window_get_events (GdkWindow *window)
5865 {
5866 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
5867
5868 if (window->destroyed)
5869 return 0;
5870
5871 return window->event_mask;
5872 }
5873
5874 /**
5875 * gdk_window_set_device_events:
5876 * @window: a #GdkWindow
5877 * @device: #GdkDevice to enable events for.
5878 * @event_mask: event mask for @window
5879 *
5880 * Sets the event mask for a given device (Normally a floating device, not
5881 * attached to any visible pointer) to @window. For example, an event mask
5882 * including #GDK_BUTTON_PRESS_MASK means the window should report button
5883 * press events. The event mask is the bitwise OR of values from the
5884 * #GdkEventMask enumeration.
5885 *
5886 * See the [input handling overview][event-masks] for details.
5887 *
5888 * Since: 3.0
5889 **/
5890 void
gdk_window_set_device_events(GdkWindow * window,GdkDevice * device,GdkEventMask event_mask)5891 gdk_window_set_device_events (GdkWindow *window,
5892 GdkDevice *device,
5893 GdkEventMask event_mask)
5894 {
5895 GdkEventMask device_mask;
5896 GdkDisplay *display;
5897 GdkWindow *native;
5898
5899 g_return_if_fail (GDK_IS_WINDOW (window));
5900 g_return_if_fail (GDK_IS_DEVICE (device));
5901
5902 if (GDK_WINDOW_DESTROYED (window))
5903 return;
5904
5905 /* If motion hint is disabled, enable motion events again */
5906 display = gdk_window_get_display (window);
5907 if ((window->event_mask & GDK_POINTER_MOTION_HINT_MASK) &&
5908 !(event_mask & GDK_POINTER_MOTION_HINT_MASK))
5909 _gdk_display_enable_motion_hints (display, device);
5910
5911 if (G_UNLIKELY (!window->device_events))
5912 window->device_events = g_hash_table_new (NULL, NULL);
5913
5914 if (event_mask == 0)
5915 {
5916 /* FIXME: unsetting events on a master device
5917 * would restore window->event_mask
5918 */
5919 g_hash_table_remove (window->device_events, device);
5920 }
5921 else
5922 g_hash_table_insert (window->device_events, device,
5923 GINT_TO_POINTER (event_mask));
5924
5925 native = gdk_window_get_toplevel (window);
5926
5927 while (gdk_window_is_offscreen (native))
5928 {
5929 native = gdk_offscreen_window_get_embedder (native);
5930
5931 if (native == NULL ||
5932 (!_gdk_window_has_impl (native) &&
5933 !gdk_window_is_viewable (native)))
5934 return;
5935
5936 native = gdk_window_get_toplevel (native);
5937 }
5938
5939 device_mask = get_native_device_event_mask (window, device);
5940 GDK_DEVICE_GET_CLASS (device)->select_window_events (device, native, device_mask);
5941 }
5942
5943 /**
5944 * gdk_window_get_device_events:
5945 * @window: a #GdkWindow.
5946 * @device: a #GdkDevice.
5947 *
5948 * Returns the event mask for @window corresponding to an specific device.
5949 *
5950 * Returns: device event mask for @window
5951 *
5952 * Since: 3.0
5953 **/
5954 GdkEventMask
gdk_window_get_device_events(GdkWindow * window,GdkDevice * device)5955 gdk_window_get_device_events (GdkWindow *window,
5956 GdkDevice *device)
5957 {
5958 GdkEventMask mask;
5959
5960 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
5961 g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
5962
5963 if (GDK_WINDOW_DESTROYED (window))
5964 return 0;
5965
5966 if (!window->device_events)
5967 return 0;
5968
5969 mask = GPOINTER_TO_INT (g_hash_table_lookup (window->device_events, device));
5970
5971 /* FIXME: device could be controlled by window->event_mask */
5972
5973 return mask;
5974 }
5975
5976 static void
gdk_window_move_resize_toplevel(GdkWindow * window,gboolean with_move,gint x,gint y,gint width,gint height)5977 gdk_window_move_resize_toplevel (GdkWindow *window,
5978 gboolean with_move,
5979 gint x,
5980 gint y,
5981 gint width,
5982 gint height)
5983 {
5984 cairo_region_t *old_region, *new_region;
5985 GdkWindowImplClass *impl_class;
5986 gboolean expose;
5987 gboolean is_resize;
5988
5989 expose = FALSE;
5990 old_region = NULL;
5991
5992 is_resize = (width != -1) || (height != -1);
5993
5994 if (gdk_window_is_viewable (window) &&
5995 !window->input_only)
5996 {
5997 expose = TRUE;
5998 old_region = cairo_region_copy (window->clip_region);
5999 }
6000
6001 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
6002 impl_class->move_resize (window, with_move, x, y, width, height);
6003
6004 /* Avoid recomputing for pure toplevel moves, for performance reasons */
6005 if (is_resize)
6006 recompute_visible_regions (window, FALSE);
6007
6008 if (expose)
6009 {
6010 new_region = cairo_region_copy (window->clip_region);
6011
6012 /* This is the newly exposed area (due to any resize),
6013 * X will expose it, but lets do that without the roundtrip
6014 */
6015 cairo_region_subtract (new_region, old_region);
6016 gdk_window_invalidate_region_full (window, new_region, TRUE);
6017
6018 cairo_region_destroy (old_region);
6019 cairo_region_destroy (new_region);
6020 }
6021
6022 _gdk_synthesize_crossing_events_for_geometry_change (window);
6023 }
6024
6025
6026 static void
move_native_children(GdkWindow * private)6027 move_native_children (GdkWindow *private)
6028 {
6029 GList *l;
6030 GdkWindow *child;
6031 GdkWindowImplClass *impl_class;
6032
6033 for (l = private->children; l; l = l->next)
6034 {
6035 child = l->data;
6036
6037 if (child->impl != private->impl)
6038 {
6039 impl_class = GDK_WINDOW_IMPL_GET_CLASS (child->impl);
6040 impl_class->move_resize (child, TRUE,
6041 child->x, child->y,
6042 child->width, child->height);
6043 }
6044 else
6045 move_native_children (child);
6046 }
6047 }
6048
6049 static void
gdk_window_move_resize_internal(GdkWindow * window,gboolean with_move,gint x,gint y,gint width,gint height)6050 gdk_window_move_resize_internal (GdkWindow *window,
6051 gboolean with_move,
6052 gint x,
6053 gint y,
6054 gint width,
6055 gint height)
6056 {
6057 cairo_region_t *old_region, *new_region;
6058 GdkWindowImplClass *impl_class;
6059 gboolean expose;
6060 int old_abs_x, old_abs_y;
6061
6062 g_return_if_fail (GDK_IS_WINDOW (window));
6063
6064 if (window->destroyed)
6065 return;
6066
6067 if (gdk_window_is_toplevel (window))
6068 {
6069 gdk_window_move_resize_toplevel (window, with_move, x, y, width, height);
6070 return;
6071 }
6072
6073 if (width == 0)
6074 width = 1;
6075 if (height == 0)
6076 height = 1;
6077
6078 /* Bail early if no change */
6079 if (window->width == width &&
6080 window->height == height &&
6081 (!with_move ||
6082 (window->x == x &&
6083 window->y == y)))
6084 return;
6085
6086 /* Handle child windows */
6087
6088 expose = FALSE;
6089 old_region = NULL;
6090
6091 if (gdk_window_is_viewable (window) &&
6092 !window->input_only)
6093 {
6094 GdkRectangle r;
6095
6096 expose = TRUE;
6097
6098 r.x = window->x;
6099 r.y = window->y;
6100 r.width = window->width;
6101 r.height = window->height;
6102
6103 old_region = cairo_region_create_rectangle (&r);
6104 }
6105
6106 /* Set the new position and size */
6107 if (with_move)
6108 {
6109 window->x = x;
6110 window->y = y;
6111 }
6112 if (!(width < 0 && height < 0))
6113 {
6114 window->width = width;
6115 window->height = height;
6116 }
6117
6118 old_abs_x = window->abs_x;
6119 old_abs_y = window->abs_y;
6120
6121 recompute_visible_regions (window, FALSE);
6122
6123 if (gdk_window_has_impl (window))
6124 {
6125 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
6126
6127 /* Do the actual move after recomputing things, as this will have set the shape to
6128 the now correct one, thus avoiding copying regions that should not be copied. */
6129 impl_class->move_resize (window, TRUE,
6130 window->x, window->y,
6131 window->width, window->height);
6132 }
6133 else if (old_abs_x != window->abs_x ||
6134 old_abs_y != window->abs_y)
6135 move_native_children (window);
6136
6137 if (expose)
6138 {
6139 GdkRectangle r;
6140
6141 r.x = window->x;
6142 r.y = window->y;
6143 r.width = window->width;
6144 r.height = window->height;
6145
6146 new_region = cairo_region_create_rectangle (&r);
6147
6148 cairo_region_union (new_region, old_region);
6149
6150 gdk_window_invalidate_region_full (window->parent, new_region, TRUE);
6151
6152 cairo_region_destroy (old_region);
6153 cairo_region_destroy (new_region);
6154 }
6155
6156 _gdk_synthesize_crossing_events_for_geometry_change (window);
6157 }
6158
6159
6160
6161 /**
6162 * gdk_window_move:
6163 * @window: a #GdkWindow
6164 * @x: X coordinate relative to window’s parent
6165 * @y: Y coordinate relative to window’s parent
6166 *
6167 * Repositions a window relative to its parent window.
6168 * For toplevel windows, window managers may ignore or modify the move;
6169 * you should probably use gtk_window_move() on a #GtkWindow widget
6170 * anyway, instead of using GDK functions. For child windows,
6171 * the move will reliably succeed.
6172 *
6173 * If you’re also planning to resize the window, use gdk_window_move_resize()
6174 * to both move and resize simultaneously, for a nicer visual effect.
6175 **/
6176 void
gdk_window_move(GdkWindow * window,gint x,gint y)6177 gdk_window_move (GdkWindow *window,
6178 gint x,
6179 gint y)
6180 {
6181 gdk_window_move_resize_internal (window, TRUE, x, y, -1, -1);
6182 }
6183
6184 /**
6185 * gdk_window_resize:
6186 * @window: a #GdkWindow
6187 * @width: new width of the window
6188 * @height: new height of the window
6189 *
6190 * Resizes @window; for toplevel windows, asks the window manager to resize
6191 * the window. The window manager may not allow the resize. When using GTK+,
6192 * use gtk_window_resize() instead of this low-level GDK function.
6193 *
6194 * Windows may not be resized below 1x1.
6195 *
6196 * If you’re also planning to move the window, use gdk_window_move_resize()
6197 * to both move and resize simultaneously, for a nicer visual effect.
6198 **/
6199 void
gdk_window_resize(GdkWindow * window,gint width,gint height)6200 gdk_window_resize (GdkWindow *window,
6201 gint width,
6202 gint height)
6203 {
6204 gdk_window_move_resize_internal (window, FALSE, 0, 0, width, height);
6205 }
6206
6207
6208 /**
6209 * gdk_window_move_resize:
6210 * @window: a #GdkWindow
6211 * @x: new X position relative to window’s parent
6212 * @y: new Y position relative to window’s parent
6213 * @width: new width
6214 * @height: new height
6215 *
6216 * Equivalent to calling gdk_window_move() and gdk_window_resize(),
6217 * except that both operations are performed at once, avoiding strange
6218 * visual effects. (i.e. the user may be able to see the window first
6219 * move, then resize, if you don’t use gdk_window_move_resize().)
6220 **/
6221 void
gdk_window_move_resize(GdkWindow * window,gint x,gint y,gint width,gint height)6222 gdk_window_move_resize (GdkWindow *window,
6223 gint x,
6224 gint y,
6225 gint width,
6226 gint height)
6227 {
6228 gdk_window_move_resize_internal (window, TRUE, x, y, width, height);
6229 }
6230
6231 /**
6232 * gdk_window_move_to_rect:
6233 * @window: the #GdkWindow to move
6234 * @rect: (not nullable): the destination #GdkRectangle to align @window with
6235 * @rect_anchor: the point on @rect to align with @window's anchor point
6236 * @window_anchor: the point on @window to align with @rect's anchor point
6237 * @anchor_hints: positioning hints to use when limited on space
6238 * @rect_anchor_dx: horizontal offset to shift @window, i.e. @rect's anchor
6239 * point
6240 * @rect_anchor_dy: vertical offset to shift @window, i.e. @rect's anchor point
6241 *
6242 * Moves @window to @rect, aligning their anchor points.
6243 *
6244 * @rect is relative to the top-left corner of the window that @window is
6245 * transient for. @rect_anchor and @window_anchor determine anchor points on
6246 * @rect and @window to pin together. @rect's anchor point can optionally be
6247 * offset by @rect_anchor_dx and @rect_anchor_dy, which is equivalent to
6248 * offsetting the position of @window.
6249 *
6250 * @anchor_hints determines how @window will be moved if the anchor points cause
6251 * it to move off-screen. For example, %GDK_ANCHOR_FLIP_X will replace
6252 * %GDK_GRAVITY_NORTH_WEST with %GDK_GRAVITY_NORTH_EAST and vice versa if
6253 * @window extends beyond the left or right edges of the monitor.
6254 *
6255 * Connect to the #GdkWindow::moved-to-rect signal to find out how it was
6256 * actually positioned.
6257 *
6258 * Since: 3.24
6259 */
6260 void
gdk_window_move_to_rect(GdkWindow * window,const GdkRectangle * rect,GdkGravity rect_anchor,GdkGravity window_anchor,GdkAnchorHints anchor_hints,gint rect_anchor_dx,gint rect_anchor_dy)6261 gdk_window_move_to_rect (GdkWindow *window,
6262 const GdkRectangle *rect,
6263 GdkGravity rect_anchor,
6264 GdkGravity window_anchor,
6265 GdkAnchorHints anchor_hints,
6266 gint rect_anchor_dx,
6267 gint rect_anchor_dy)
6268 {
6269 GdkWindowImplClass *impl_class;
6270
6271 g_return_if_fail (GDK_IS_WINDOW (window));
6272 g_return_if_fail (window->transient_for);
6273 g_return_if_fail (rect);
6274
6275 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
6276 impl_class->move_to_rect (window,
6277 rect,
6278 rect_anchor,
6279 window_anchor,
6280 anchor_hints,
6281 rect_anchor_dx,
6282 rect_anchor_dy);
6283 }
6284
6285 /**
6286 * gdk_window_scroll:
6287 * @window: a #GdkWindow
6288 * @dx: Amount to scroll in the X direction
6289 * @dy: Amount to scroll in the Y direction
6290 *
6291 * Scroll the contents of @window, both pixels and children, by the
6292 * given amount. @window itself does not move. Portions of the window
6293 * that the scroll operation brings in from offscreen areas are
6294 * invalidated. The invalidated region may be bigger than what would
6295 * strictly be necessary.
6296 *
6297 * For X11, a minimum area will be invalidated if the window has no
6298 * subwindows, or if the edges of the window’s parent do not extend
6299 * beyond the edges of the window. In other cases, a multi-step process
6300 * is used to scroll the window which may produce temporary visual
6301 * artifacts and unnecessary invalidations.
6302 **/
6303 void
gdk_window_scroll(GdkWindow * window,gint dx,gint dy)6304 gdk_window_scroll (GdkWindow *window,
6305 gint dx,
6306 gint dy)
6307 {
6308 GList *tmp_list;
6309
6310 g_return_if_fail (GDK_IS_WINDOW (window));
6311
6312 if (dx == 0 && dy == 0)
6313 return;
6314
6315 if (window->destroyed)
6316 return;
6317
6318 /* First move all child windows, without causing invalidation */
6319
6320 tmp_list = window->children;
6321 while (tmp_list)
6322 {
6323 GdkWindow *child = GDK_WINDOW (tmp_list->data);
6324
6325 /* Just update the positions, the bits will move with the copy */
6326 child->x += dx;
6327 child->y += dy;
6328
6329 tmp_list = tmp_list->next;
6330 }
6331
6332 recompute_visible_regions (window, TRUE);
6333
6334 move_native_children (window);
6335
6336 gdk_window_invalidate_rect_full (window, NULL, TRUE);
6337
6338 _gdk_synthesize_crossing_events_for_geometry_change (window);
6339 }
6340
6341 /**
6342 * gdk_window_move_region:
6343 * @window: a #GdkWindow
6344 * @region: The #cairo_region_t to move
6345 * @dx: Amount to move in the X direction
6346 * @dy: Amount to move in the Y direction
6347 *
6348 * Move the part of @window indicated by @region by @dy pixels in the Y
6349 * direction and @dx pixels in the X direction. The portions of @region
6350 * that not covered by the new position of @region are invalidated.
6351 *
6352 * Child windows are not moved.
6353 *
6354 * Since: 2.8
6355 */
6356 void
gdk_window_move_region(GdkWindow * window,const cairo_region_t * region,gint dx,gint dy)6357 gdk_window_move_region (GdkWindow *window,
6358 const cairo_region_t *region,
6359 gint dx,
6360 gint dy)
6361 {
6362 cairo_region_t *expose_area;
6363
6364 g_return_if_fail (GDK_IS_WINDOW (window));
6365 g_return_if_fail (region != NULL);
6366
6367 if (dx == 0 && dy == 0)
6368 return;
6369
6370 if (window->destroyed)
6371 return;
6372
6373 expose_area = cairo_region_copy (region);
6374 cairo_region_translate (expose_area, dx, dy);
6375 cairo_region_union (expose_area, region);
6376
6377 gdk_window_invalidate_region_full (window, expose_area, FALSE);
6378 cairo_region_destroy (expose_area);
6379 }
6380
6381 /**
6382 * gdk_window_set_background:
6383 * @window: a #GdkWindow
6384 * @color: a #GdkColor
6385 *
6386 * Sets the background color of @window.
6387 *
6388 * However, when using GTK+, influence the background of a widget
6389 * using a style class or CSS — if you’re an application — or with
6390 * gtk_style_context_set_background() — if you're implementing a
6391 * custom widget.
6392 *
6393 * Deprecated: 3.4: Don't use this function
6394 */
6395 void
gdk_window_set_background(GdkWindow * window,const GdkColor * color)6396 gdk_window_set_background (GdkWindow *window,
6397 const GdkColor *color)
6398 {
6399 cairo_pattern_t *pattern;
6400
6401 g_return_if_fail (GDK_IS_WINDOW (window));
6402
6403 pattern = cairo_pattern_create_rgb (color->red / 65535.,
6404 color->green / 65535.,
6405 color->blue / 65535.);
6406
6407 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
6408 gdk_window_set_background_pattern (window, pattern);
6409 G_GNUC_END_IGNORE_DEPRECATIONS
6410
6411 cairo_pattern_destroy (pattern);
6412 }
6413
6414 /**
6415 * gdk_window_set_background_rgba:
6416 * @window: a #GdkWindow
6417 * @rgba: a #GdkRGBA color
6418 *
6419 * Sets the background color of @window.
6420 *
6421 * See also gdk_window_set_background_pattern().
6422 *
6423 * Deprecated: 3.22: Don't use this function
6424 **/
6425 void
gdk_window_set_background_rgba(GdkWindow * window,const GdkRGBA * rgba)6426 gdk_window_set_background_rgba (GdkWindow *window,
6427 const GdkRGBA *rgba)
6428 {
6429 cairo_pattern_t *pattern;
6430 GdkRGBA prev_rgba;
6431
6432 g_return_if_fail (GDK_IS_WINDOW (window));
6433 g_return_if_fail (rgba != NULL);
6434
6435 /*
6436 * If the new RGBA matches the previous pattern, ignore the change so that
6437 * we do not invalidate the window contents.
6438 */
6439 if ((window->background != NULL) &&
6440 (cairo_pattern_get_type (window->background) == CAIRO_PATTERN_TYPE_SOLID) &&
6441 (cairo_pattern_get_rgba (window->background,
6442 &prev_rgba.red,
6443 &prev_rgba.green,
6444 &prev_rgba.blue,
6445 &prev_rgba.alpha) == CAIRO_STATUS_SUCCESS) &&
6446 gdk_rgba_equal (&prev_rgba, rgba))
6447 return;
6448
6449 pattern = cairo_pattern_create_rgba (rgba->red, rgba->green,
6450 rgba->blue, rgba->alpha);
6451
6452 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
6453 gdk_window_set_background_pattern (window, pattern);
6454 G_GNUC_END_IGNORE_DEPRECATIONS
6455
6456 cairo_pattern_destroy (pattern);
6457 }
6458
6459
6460 /**
6461 * gdk_window_set_background_pattern:
6462 * @window: a #GdkWindow
6463 * @pattern: (allow-none): a pattern to use, or %NULL
6464 *
6465 * Sets the background of @window.
6466 *
6467 * A background of %NULL means that the window won't have any background. On the
6468 * X11 backend it's also possible to inherit the background from the parent
6469 * window using gdk_x11_get_parent_relative_pattern().
6470 *
6471 * The windowing system will normally fill a window with its background
6472 * when the window is obscured then exposed.
6473 *
6474 * Deprecated: 3.22: Don't use this function
6475 */
6476 void
gdk_window_set_background_pattern(GdkWindow * window,cairo_pattern_t * pattern)6477 gdk_window_set_background_pattern (GdkWindow *window,
6478 cairo_pattern_t *pattern)
6479 {
6480 g_return_if_fail (GDK_IS_WINDOW (window));
6481
6482 if (window->input_only)
6483 return;
6484
6485 if (pattern)
6486 cairo_pattern_reference (pattern);
6487 if (window->background)
6488 cairo_pattern_destroy (window->background);
6489 window->background = pattern;
6490
6491 if (gdk_window_has_impl (window))
6492 {
6493 GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
6494 impl_class->set_background (window, pattern);
6495 }
6496 else
6497 gdk_window_invalidate_rect_full (window, NULL, TRUE);
6498 }
6499
6500 /**
6501 * gdk_window_get_background_pattern:
6502 * @window: a window
6503 *
6504 * Gets the pattern used to clear the background on @window.
6505 *
6506 * Returns: (nullable) (transfer none): The pattern to use for the
6507 * background or %NULL if there is no background.
6508 *
6509 * Since: 2.22
6510 *
6511 * Deprecated: 3.22: Don't use this function
6512 **/
6513 cairo_pattern_t *
gdk_window_get_background_pattern(GdkWindow * window)6514 gdk_window_get_background_pattern (GdkWindow *window)
6515 {
6516 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
6517
6518 return window->background;
6519 }
6520
6521 static void
gdk_window_set_cursor_internal(GdkWindow * window,GdkDevice * device,GdkCursor * cursor)6522 gdk_window_set_cursor_internal (GdkWindow *window,
6523 GdkDevice *device,
6524 GdkCursor *cursor)
6525 {
6526 if (GDK_WINDOW_DESTROYED (window))
6527 return;
6528
6529 g_assert (gdk_window_get_display (window) == gdk_device_get_display (device));
6530 g_assert (!cursor || gdk_window_get_display (window) == gdk_cursor_get_display (cursor));
6531
6532 if (window->window_type == GDK_WINDOW_ROOT ||
6533 window->window_type == GDK_WINDOW_FOREIGN)
6534 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_device_cursor (window, device, cursor);
6535 else
6536 {
6537 GdkPointerWindowInfo *pointer_info;
6538 GdkDisplay *display;
6539
6540 display = gdk_window_get_display (window);
6541 pointer_info = _gdk_display_get_pointer_info (display, device);
6542
6543 if (_gdk_window_event_parent_of (window, pointer_info->window_under_pointer))
6544 update_cursor (display, device);
6545 }
6546 }
6547
6548 /**
6549 * gdk_window_get_cursor:
6550 * @window: a #GdkWindow
6551 *
6552 * Retrieves a #GdkCursor pointer for the cursor currently set on the
6553 * specified #GdkWindow, or %NULL. If the return value is %NULL then
6554 * there is no custom cursor set on the specified window, and it is
6555 * using the cursor for its parent window.
6556 *
6557 * Returns: (nullable) (transfer none): a #GdkCursor, or %NULL. The
6558 * returned object is owned by the #GdkWindow and should not be
6559 * unreferenced directly. Use gdk_window_set_cursor() to unset the
6560 * cursor of the window
6561 *
6562 * Since: 2.18
6563 */
6564 GdkCursor *
gdk_window_get_cursor(GdkWindow * window)6565 gdk_window_get_cursor (GdkWindow *window)
6566 {
6567 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
6568
6569 return window->cursor;
6570 }
6571
6572 /**
6573 * gdk_window_set_cursor:
6574 * @window: a #GdkWindow
6575 * @cursor: (allow-none): a cursor
6576 *
6577 * Sets the default mouse pointer for a #GdkWindow.
6578 *
6579 * Note that @cursor must be for the same display as @window.
6580 *
6581 * Use gdk_cursor_new_for_display() or gdk_cursor_new_from_pixbuf() to
6582 * create the cursor. To make the cursor invisible, use %GDK_BLANK_CURSOR.
6583 * Passing %NULL for the @cursor argument to gdk_window_set_cursor() means
6584 * that @window will use the cursor of its parent window. Most windows
6585 * should use this default.
6586 */
6587 void
gdk_window_set_cursor(GdkWindow * window,GdkCursor * cursor)6588 gdk_window_set_cursor (GdkWindow *window,
6589 GdkCursor *cursor)
6590 {
6591 GdkDisplay *display;
6592
6593 g_return_if_fail (GDK_IS_WINDOW (window));
6594
6595 display = gdk_window_get_display (window);
6596
6597 if (window->cursor)
6598 {
6599 g_object_unref (window->cursor);
6600 window->cursor = NULL;
6601 }
6602
6603 if (!GDK_WINDOW_DESTROYED (window))
6604 {
6605 GdkDevice *device;
6606 GList *seats, *s;
6607
6608 if (cursor)
6609 window->cursor = g_object_ref (cursor);
6610
6611 seats = gdk_display_list_seats (display);
6612
6613 for (s = seats; s; s = s->next)
6614 {
6615 GList *devices, *d;
6616
6617 device = gdk_seat_get_pointer (s->data);
6618 gdk_window_set_cursor_internal (window, device, window->cursor);
6619
6620 devices = gdk_seat_get_slaves (s->data, GDK_SEAT_CAPABILITY_TABLET_STYLUS);
6621 for (d = devices; d; d = d->next)
6622 {
6623 device = gdk_device_get_associated_device (d->data);
6624 gdk_window_set_cursor_internal (window, device, window->cursor);
6625 }
6626 g_list_free (devices);
6627 }
6628
6629 g_list_free (seats);
6630 g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_CURSOR]);
6631 }
6632 }
6633
6634 /**
6635 * gdk_window_get_device_cursor:
6636 * @window: a #GdkWindow.
6637 * @device: a master, pointer #GdkDevice.
6638 *
6639 * Retrieves a #GdkCursor pointer for the @device currently set on the
6640 * specified #GdkWindow, or %NULL. If the return value is %NULL then
6641 * there is no custom cursor set on the specified window, and it is
6642 * using the cursor for its parent window.
6643 *
6644 * Returns: (nullable) (transfer none): a #GdkCursor, or %NULL. The
6645 * returned object is owned by the #GdkWindow and should not be
6646 * unreferenced directly. Use gdk_window_set_cursor() to unset the
6647 * cursor of the window
6648 *
6649 * Since: 3.0
6650 **/
6651 GdkCursor *
gdk_window_get_device_cursor(GdkWindow * window,GdkDevice * device)6652 gdk_window_get_device_cursor (GdkWindow *window,
6653 GdkDevice *device)
6654 {
6655 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
6656 g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
6657 g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
6658 g_return_val_if_fail (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER, NULL);
6659
6660 return g_hash_table_lookup (window->device_cursor, device);
6661 }
6662
6663 /**
6664 * gdk_window_set_device_cursor:
6665 * @window: a #GdkWindow
6666 * @device: a master, pointer #GdkDevice
6667 * @cursor: a #GdkCursor
6668 *
6669 * Sets a specific #GdkCursor for a given device when it gets inside @window.
6670 * Use gdk_cursor_new_for_display() or gdk_cursor_new_from_pixbuf() to create
6671 * the cursor. To make the cursor invisible, use %GDK_BLANK_CURSOR. Passing
6672 * %NULL for the @cursor argument to gdk_window_set_cursor() means that
6673 * @window will use the cursor of its parent window. Most windows should
6674 * use this default.
6675 *
6676 * Since: 3.0
6677 **/
6678 void
gdk_window_set_device_cursor(GdkWindow * window,GdkDevice * device,GdkCursor * cursor)6679 gdk_window_set_device_cursor (GdkWindow *window,
6680 GdkDevice *device,
6681 GdkCursor *cursor)
6682 {
6683 g_return_if_fail (GDK_IS_WINDOW (window));
6684 g_return_if_fail (GDK_IS_DEVICE (device));
6685 g_return_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD);
6686 g_return_if_fail (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER);
6687
6688 if (!cursor)
6689 g_hash_table_remove (window->device_cursor, device);
6690 else
6691 g_hash_table_replace (window->device_cursor, device, g_object_ref (cursor));
6692
6693 gdk_window_set_cursor_internal (window, device, cursor);
6694 }
6695
6696 /**
6697 * gdk_window_get_geometry:
6698 * @window: a #GdkWindow
6699 * @x: (out) (allow-none): return location for X coordinate of window (relative to its parent)
6700 * @y: (out) (allow-none): return location for Y coordinate of window (relative to its parent)
6701 * @width: (out) (allow-none): return location for width of window
6702 * @height: (out) (allow-none): return location for height of window
6703 *
6704 * Any of the return location arguments to this function may be %NULL,
6705 * if you aren’t interested in getting the value of that field.
6706 *
6707 * The X and Y coordinates returned are relative to the parent window
6708 * of @window, which for toplevels usually means relative to the
6709 * window decorations (titlebar, etc.) rather than relative to the
6710 * root window (screen-size background window).
6711 *
6712 * On the X11 platform, the geometry is obtained from the X server,
6713 * so reflects the latest position of @window; this may be out-of-sync
6714 * with the position of @window delivered in the most-recently-processed
6715 * #GdkEventConfigure. gdk_window_get_position() in contrast gets the
6716 * position from the most recent configure event.
6717 *
6718 * Note: If @window is not a toplevel, it is much better
6719 * to call gdk_window_get_position(), gdk_window_get_width() and
6720 * gdk_window_get_height() instead, because it avoids the roundtrip to
6721 * the X server and because these functions support the full 32-bit
6722 * coordinate space, whereas gdk_window_get_geometry() is restricted to
6723 * the 16-bit coordinates of X11.
6724 */
6725 void
gdk_window_get_geometry(GdkWindow * window,gint * x,gint * y,gint * width,gint * height)6726 gdk_window_get_geometry (GdkWindow *window,
6727 gint *x,
6728 gint *y,
6729 gint *width,
6730 gint *height)
6731 {
6732 GdkWindow *parent;
6733 GdkWindowImplClass *impl_class;
6734
6735 if (!window)
6736 window = gdk_screen_get_root_window ((gdk_screen_get_default ()));
6737
6738 g_return_if_fail (GDK_IS_WINDOW (window));
6739
6740 if (!GDK_WINDOW_DESTROYED (window))
6741 {
6742 if (gdk_window_has_impl (window))
6743 {
6744 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
6745 impl_class->get_geometry (window, x, y,
6746 width, height);
6747 /* This reports the position wrt to the native parent, we need to convert
6748 it to be relative to the client side parent */
6749 parent = window->parent;
6750 if (parent && !gdk_window_has_impl (parent))
6751 {
6752 if (x)
6753 *x -= parent->abs_x;
6754 if (y)
6755 *y -= parent->abs_y;
6756 }
6757 }
6758 else
6759 {
6760 if (x)
6761 *x = window->x;
6762 if (y)
6763 *y = window->y;
6764 if (width)
6765 *width = window->width;
6766 if (height)
6767 *height = window->height;
6768 }
6769 }
6770 }
6771
6772 /**
6773 * gdk_window_get_width:
6774 * @window: a #GdkWindow
6775 *
6776 * Returns the width of the given @window.
6777 *
6778 * On the X11 platform the returned size is the size reported in the
6779 * most-recently-processed configure event, rather than the current
6780 * size on the X server.
6781 *
6782 * Returns: The width of @window
6783 *
6784 * Since: 2.24
6785 */
6786 int
gdk_window_get_width(GdkWindow * window)6787 gdk_window_get_width (GdkWindow *window)
6788 {
6789 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
6790
6791 return window->width;
6792 }
6793
6794 /**
6795 * gdk_window_get_height:
6796 * @window: a #GdkWindow
6797 *
6798 * Returns the height of the given @window.
6799 *
6800 * On the X11 platform the returned size is the size reported in the
6801 * most-recently-processed configure event, rather than the current
6802 * size on the X server.
6803 *
6804 * Returns: The height of @window
6805 *
6806 * Since: 2.24
6807 */
6808 int
gdk_window_get_height(GdkWindow * window)6809 gdk_window_get_height (GdkWindow *window)
6810 {
6811 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
6812
6813 return window->height;
6814 }
6815
6816 /**
6817 * gdk_window_get_origin:
6818 * @window: a #GdkWindow
6819 * @x: (out) (allow-none): return location for X coordinate
6820 * @y: (out) (allow-none): return location for Y coordinate
6821 *
6822 * Obtains the position of a window in root window coordinates.
6823 * (Compare with gdk_window_get_position() and
6824 * gdk_window_get_geometry() which return the position of a window
6825 * relative to its parent window.)
6826 *
6827 * Returns: not meaningful, ignore
6828 */
6829 gint
gdk_window_get_origin(GdkWindow * window,gint * x,gint * y)6830 gdk_window_get_origin (GdkWindow *window,
6831 gint *x,
6832 gint *y)
6833 {
6834 gint dummy_x, dummy_y;
6835
6836 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
6837
6838 gdk_window_get_root_coords (window,
6839 0, 0,
6840 x ? x : &dummy_x,
6841 y ? y : &dummy_y);
6842
6843 return TRUE;
6844 }
6845
6846 /**
6847 * gdk_window_get_root_coords:
6848 * @window: a #GdkWindow
6849 * @x: X coordinate in window
6850 * @y: Y coordinate in window
6851 * @root_x: (out): return location for X coordinate
6852 * @root_y: (out): return location for Y coordinate
6853 *
6854 * Obtains the position of a window position in root
6855 * window coordinates. This is similar to
6856 * gdk_window_get_origin() but allows you to pass
6857 * in any position in the window, not just the origin.
6858 *
6859 * Since: 2.18
6860 */
6861 void
gdk_window_get_root_coords(GdkWindow * window,gint x,gint y,gint * root_x,gint * root_y)6862 gdk_window_get_root_coords (GdkWindow *window,
6863 gint x,
6864 gint y,
6865 gint *root_x,
6866 gint *root_y)
6867 {
6868 GdkWindowImplClass *impl_class;
6869
6870 g_return_if_fail (GDK_IS_WINDOW (window));
6871
6872 if (GDK_WINDOW_DESTROYED (window))
6873 {
6874 *root_x = 0;
6875 *root_y = 0;
6876 return;
6877 }
6878
6879 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
6880 impl_class->get_root_coords (window->impl_window,
6881 x + window->abs_x,
6882 y + window->abs_y,
6883 root_x, root_y);
6884 }
6885
6886 /**
6887 * gdk_window_coords_to_parent:
6888 * @window: a child window
6889 * @x: X coordinate in child’s coordinate system
6890 * @y: Y coordinate in child’s coordinate system
6891 * @parent_x: (out) (allow-none): return location for X coordinate
6892 * in parent’s coordinate system, or %NULL
6893 * @parent_y: (out) (allow-none): return location for Y coordinate
6894 * in parent’s coordinate system, or %NULL
6895 *
6896 * Transforms window coordinates from a child window to its parent
6897 * window, where the parent window is the normal parent as returned by
6898 * gdk_window_get_parent() for normal windows, and the window's
6899 * embedder as returned by gdk_offscreen_window_get_embedder() for
6900 * offscreen windows.
6901 *
6902 * For normal windows, calling this function is equivalent to adding
6903 * the return values of gdk_window_get_position() to the child coordinates.
6904 * For offscreen windows however (which can be arbitrarily transformed),
6905 * this function calls the GdkWindow::to-embedder: signal to translate
6906 * the coordinates.
6907 *
6908 * You should always use this function when writing generic code that
6909 * walks up a window hierarchy.
6910 *
6911 * See also: gdk_window_coords_from_parent()
6912 *
6913 * Since: 2.22
6914 **/
6915 void
gdk_window_coords_to_parent(GdkWindow * window,gdouble x,gdouble y,gdouble * parent_x,gdouble * parent_y)6916 gdk_window_coords_to_parent (GdkWindow *window,
6917 gdouble x,
6918 gdouble y,
6919 gdouble *parent_x,
6920 gdouble *parent_y)
6921 {
6922 g_return_if_fail (GDK_IS_WINDOW (window));
6923
6924 if (gdk_window_is_offscreen (window))
6925 {
6926 gdouble px, py;
6927
6928 to_embedder (window, x, y, &px, &py);
6929
6930 if (parent_x)
6931 *parent_x = px;
6932
6933 if (parent_y)
6934 *parent_y = py;
6935 }
6936 else
6937 {
6938 if (parent_x)
6939 *parent_x = x + window->x;
6940
6941 if (parent_y)
6942 *parent_y = y + window->y;
6943 }
6944 }
6945
6946 /**
6947 * gdk_window_coords_from_parent:
6948 * @window: a child window
6949 * @parent_x: X coordinate in parent’s coordinate system
6950 * @parent_y: Y coordinate in parent’s coordinate system
6951 * @x: (out) (allow-none): return location for X coordinate in child’s coordinate system
6952 * @y: (out) (allow-none): return location for Y coordinate in child’s coordinate system
6953 *
6954 * Transforms window coordinates from a parent window to a child
6955 * window, where the parent window is the normal parent as returned by
6956 * gdk_window_get_parent() for normal windows, and the window's
6957 * embedder as returned by gdk_offscreen_window_get_embedder() for
6958 * offscreen windows.
6959 *
6960 * For normal windows, calling this function is equivalent to subtracting
6961 * the return values of gdk_window_get_position() from the parent coordinates.
6962 * For offscreen windows however (which can be arbitrarily transformed),
6963 * this function calls the GdkWindow::from-embedder: signal to translate
6964 * the coordinates.
6965 *
6966 * You should always use this function when writing generic code that
6967 * walks down a window hierarchy.
6968 *
6969 * See also: gdk_window_coords_to_parent()
6970 *
6971 * Since: 2.22
6972 **/
6973 void
gdk_window_coords_from_parent(GdkWindow * window,gdouble parent_x,gdouble parent_y,gdouble * x,gdouble * y)6974 gdk_window_coords_from_parent (GdkWindow *window,
6975 gdouble parent_x,
6976 gdouble parent_y,
6977 gdouble *x,
6978 gdouble *y)
6979 {
6980 g_return_if_fail (GDK_IS_WINDOW (window));
6981
6982 if (gdk_window_is_offscreen (window))
6983 {
6984 gdouble cx, cy;
6985
6986 from_embedder (window, parent_x, parent_y, &cx, &cy);
6987
6988 if (x)
6989 *x = cx;
6990
6991 if (y)
6992 *y = cy;
6993 }
6994 else
6995 {
6996 if (x)
6997 *x = parent_x - window->x;
6998
6999 if (y)
7000 *y = parent_y - window->y;
7001 }
7002 }
7003
7004 /**
7005 * gdk_window_shape_combine_region:
7006 * @window: a #GdkWindow
7007 * @shape_region: (allow-none): region of window to be non-transparent
7008 * @offset_x: X position of @shape_region in @window coordinates
7009 * @offset_y: Y position of @shape_region in @window coordinates
7010 *
7011 * Makes pixels in @window outside @shape_region be transparent,
7012 * so that the window may be nonrectangular.
7013 *
7014 * If @shape_region is %NULL, the shape will be unset, so the whole
7015 * window will be opaque again. @offset_x and @offset_y are ignored
7016 * if @shape_region is %NULL.
7017 *
7018 * On the X11 platform, this uses an X server extension which is
7019 * widely available on most common platforms, but not available on
7020 * very old X servers, and occasionally the implementation will be
7021 * buggy. On servers without the shape extension, this function
7022 * will do nothing.
7023 *
7024 * This function works on both toplevel and child windows.
7025 */
7026 void
gdk_window_shape_combine_region(GdkWindow * window,const cairo_region_t * shape_region,gint offset_x,gint offset_y)7027 gdk_window_shape_combine_region (GdkWindow *window,
7028 const cairo_region_t *shape_region,
7029 gint offset_x,
7030 gint offset_y)
7031 {
7032 cairo_region_t *old_region, *new_region, *diff;
7033
7034 g_return_if_fail (GDK_IS_WINDOW (window));
7035
7036 if (GDK_WINDOW_DESTROYED (window))
7037 return;
7038
7039 if (!window->shape && shape_region == NULL)
7040 return;
7041
7042 window->shaped = (shape_region != NULL);
7043
7044 if (window->shape)
7045 cairo_region_destroy (window->shape);
7046
7047 old_region = NULL;
7048 if (GDK_WINDOW_IS_MAPPED (window))
7049 old_region = cairo_region_copy (window->clip_region);
7050
7051 if (shape_region)
7052 {
7053 window->shape = cairo_region_copy (shape_region);
7054 cairo_region_translate (window->shape, offset_x, offset_y);
7055 }
7056 else
7057 window->shape = NULL;
7058
7059 recompute_visible_regions (window, FALSE);
7060
7061 if (old_region)
7062 {
7063 new_region = cairo_region_copy (window->clip_region);
7064
7065 /* New area in the window, needs invalidation */
7066 diff = cairo_region_copy (new_region);
7067 cairo_region_subtract (diff, old_region);
7068
7069 gdk_window_invalidate_region_full (window, diff, TRUE);
7070
7071 cairo_region_destroy (diff);
7072
7073 if (!gdk_window_is_toplevel (window))
7074 {
7075 /* New area in the non-root parent window, needs invalidation */
7076 diff = cairo_region_copy (old_region);
7077 cairo_region_subtract (diff, new_region);
7078
7079 /* Adjust region to parent window coords */
7080 cairo_region_translate (diff, window->x, window->y);
7081
7082 gdk_window_invalidate_region_full (window->parent, diff, TRUE);
7083
7084 cairo_region_destroy (diff);
7085 }
7086
7087 cairo_region_destroy (new_region);
7088 cairo_region_destroy (old_region);
7089 }
7090 }
7091
7092 static void
do_child_shapes(GdkWindow * window,gboolean merge)7093 do_child_shapes (GdkWindow *window,
7094 gboolean merge)
7095 {
7096 GdkRectangle r;
7097 cairo_region_t *region;
7098
7099 r.x = 0;
7100 r.y = 0;
7101 r.width = window->width;
7102 r.height = window->height;
7103
7104 region = cairo_region_create_rectangle (&r);
7105 remove_child_area (window, FALSE, region);
7106
7107 if (merge && window->shape)
7108 cairo_region_subtract (region, window->shape);
7109
7110 cairo_region_xor_rectangle (region, &r);
7111
7112 gdk_window_shape_combine_region (window, region, 0, 0);
7113
7114 cairo_region_destroy (region);
7115 }
7116
7117 /**
7118 * gdk_window_set_child_shapes:
7119 * @window: a #GdkWindow
7120 *
7121 * Sets the shape mask of @window to the union of shape masks
7122 * for all children of @window, ignoring the shape mask of @window
7123 * itself. Contrast with gdk_window_merge_child_shapes() which includes
7124 * the shape mask of @window in the masks to be merged.
7125 **/
7126 void
gdk_window_set_child_shapes(GdkWindow * window)7127 gdk_window_set_child_shapes (GdkWindow *window)
7128 {
7129 g_return_if_fail (GDK_IS_WINDOW (window));
7130
7131 do_child_shapes (window, FALSE);
7132 }
7133
7134 /**
7135 * gdk_window_merge_child_shapes:
7136 * @window: a #GdkWindow
7137 *
7138 * Merges the shape masks for any child windows into the
7139 * shape mask for @window. i.e. the union of all masks
7140 * for @window and its children will become the new mask
7141 * for @window. See gdk_window_shape_combine_region().
7142 *
7143 * This function is distinct from gdk_window_set_child_shapes()
7144 * because it includes @window’s shape mask in the set of shapes to
7145 * be merged.
7146 */
7147 void
gdk_window_merge_child_shapes(GdkWindow * window)7148 gdk_window_merge_child_shapes (GdkWindow *window)
7149 {
7150 g_return_if_fail (GDK_IS_WINDOW (window));
7151
7152 do_child_shapes (window, TRUE);
7153 }
7154
7155 /**
7156 * gdk_window_input_shape_combine_region:
7157 * @window: a #GdkWindow
7158 * @shape_region: region of window to be non-transparent
7159 * @offset_x: X position of @shape_region in @window coordinates
7160 * @offset_y: Y position of @shape_region in @window coordinates
7161 *
7162 * Like gdk_window_shape_combine_region(), but the shape applies
7163 * only to event handling. Mouse events which happen while
7164 * the pointer position corresponds to an unset bit in the
7165 * mask will be passed on the window below @window.
7166 *
7167 * An input shape is typically used with RGBA windows.
7168 * The alpha channel of the window defines which pixels are
7169 * invisible and allows for nicely antialiased borders,
7170 * and the input shape controls where the window is
7171 * “clickable”.
7172 *
7173 * On the X11 platform, this requires version 1.1 of the
7174 * shape extension.
7175 *
7176 * On the Win32 platform, this functionality is not present and the
7177 * function does nothing.
7178 *
7179 * Since: 2.10
7180 */
7181 void
gdk_window_input_shape_combine_region(GdkWindow * window,const cairo_region_t * shape_region,gint offset_x,gint offset_y)7182 gdk_window_input_shape_combine_region (GdkWindow *window,
7183 const cairo_region_t *shape_region,
7184 gint offset_x,
7185 gint offset_y)
7186 {
7187 GdkWindowImplClass *impl_class;
7188
7189 g_return_if_fail (GDK_IS_WINDOW (window));
7190
7191 if (GDK_WINDOW_DESTROYED (window))
7192 return;
7193
7194 if (window->input_shape)
7195 cairo_region_destroy (window->input_shape);
7196
7197 if (shape_region)
7198 {
7199 window->input_shape = cairo_region_copy (shape_region);
7200 cairo_region_translate (window->input_shape, offset_x, offset_y);
7201 }
7202 else
7203 window->input_shape = NULL;
7204
7205 if (gdk_window_has_impl (window))
7206 {
7207 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
7208 impl_class->input_shape_combine_region (window, window->input_shape, 0, 0);
7209 }
7210
7211 /* Pointer may have e.g. moved outside window due to the input mask change */
7212 _gdk_synthesize_crossing_events_for_geometry_change (window);
7213 }
7214
7215 static void
do_child_input_shapes(GdkWindow * window,gboolean merge)7216 do_child_input_shapes (GdkWindow *window,
7217 gboolean merge)
7218 {
7219 GdkRectangle r;
7220 cairo_region_t *region;
7221
7222 r.x = 0;
7223 r.y = 0;
7224 r.width = window->width;
7225 r.height = window->height;
7226
7227 region = cairo_region_create_rectangle (&r);
7228 remove_child_area (window, TRUE, region);
7229
7230 if (merge && window->shape)
7231 cairo_region_subtract (region, window->shape);
7232 if (merge && window->input_shape)
7233 cairo_region_subtract (region, window->input_shape);
7234
7235 cairo_region_xor_rectangle (region, &r);
7236
7237 gdk_window_input_shape_combine_region (window, region, 0, 0);
7238 }
7239
7240
7241 /**
7242 * gdk_window_set_child_input_shapes:
7243 * @window: a #GdkWindow
7244 *
7245 * Sets the input shape mask of @window to the union of input shape masks
7246 * for all children of @window, ignoring the input shape mask of @window
7247 * itself. Contrast with gdk_window_merge_child_input_shapes() which includes
7248 * the input shape mask of @window in the masks to be merged.
7249 *
7250 * Since: 2.10
7251 **/
7252 void
gdk_window_set_child_input_shapes(GdkWindow * window)7253 gdk_window_set_child_input_shapes (GdkWindow *window)
7254 {
7255 g_return_if_fail (GDK_IS_WINDOW (window));
7256
7257 do_child_input_shapes (window, FALSE);
7258 }
7259
7260 /**
7261 * gdk_window_set_pass_through:
7262 * @window: a #GdkWindow
7263 * @pass_through: a boolean
7264 *
7265 * Sets whether input to the window is passed through to the window
7266 * below.
7267 *
7268 * The default value of this is %FALSE, which means that pointer
7269 * events that happen inside the window are send first to the window,
7270 * but if the event is not selected by the event mask then the event
7271 * is sent to the parent window, and so on up the hierarchy.
7272 *
7273 * If @pass_through is %TRUE then such pointer events happen as if the
7274 * window wasn't there at all, and thus will be sent first to any
7275 * windows below @window. This is useful if the window is used in a
7276 * transparent fashion. In the terminology of the web this would be called
7277 * "pointer-events: none".
7278 *
7279 * Note that a window with @pass_through %TRUE can still have a subwindow
7280 * without pass through, so you can get events on a subset of a window. And in
7281 * that cases you would get the in-between related events such as the pointer
7282 * enter/leave events on its way to the destination window.
7283 *
7284 * Since: 3.18
7285 **/
7286 void
gdk_window_set_pass_through(GdkWindow * window,gboolean pass_through)7287 gdk_window_set_pass_through (GdkWindow *window,
7288 gboolean pass_through)
7289 {
7290 g_return_if_fail (GDK_IS_WINDOW (window));
7291
7292 window->pass_through = !!pass_through;
7293
7294 /* Pointer may have e.g. moved outside window due to the input region change */
7295 _gdk_synthesize_crossing_events_for_geometry_change (window);
7296 }
7297
7298 /**
7299 * gdk_window_get_pass_through:
7300 * @window: a #GdkWindow
7301 *
7302 * Returns whether input to the window is passed through to the window
7303 * below.
7304 *
7305 * See gdk_window_set_pass_through() for details
7306 *
7307 * Since: 3.18
7308 **/
7309 gboolean
gdk_window_get_pass_through(GdkWindow * window)7310 gdk_window_get_pass_through (GdkWindow *window)
7311 {
7312 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
7313
7314 return window->pass_through;
7315 }
7316
7317 /**
7318 * gdk_window_merge_child_input_shapes:
7319 * @window: a #GdkWindow
7320 *
7321 * Merges the input shape masks for any child windows into the
7322 * input shape mask for @window. i.e. the union of all input masks
7323 * for @window and its children will become the new input mask
7324 * for @window. See gdk_window_input_shape_combine_region().
7325 *
7326 * This function is distinct from gdk_window_set_child_input_shapes()
7327 * because it includes @window’s input shape mask in the set of
7328 * shapes to be merged.
7329 *
7330 * Since: 2.10
7331 **/
7332 void
gdk_window_merge_child_input_shapes(GdkWindow * window)7333 gdk_window_merge_child_input_shapes (GdkWindow *window)
7334 {
7335 g_return_if_fail (GDK_IS_WINDOW (window));
7336
7337 do_child_input_shapes (window, TRUE);
7338 }
7339
7340
7341 /**
7342 * gdk_window_set_static_gravities:
7343 * @window: a #GdkWindow
7344 * @use_static: %TRUE to turn on static gravity
7345 *
7346 * Used to set the bit gravity of the given window to static, and flag
7347 * it so all children get static subwindow gravity. This is used if you
7348 * are implementing scary features that involve deep knowledge of the
7349 * windowing system. Don’t worry about it.
7350 *
7351 * Returns: %FALSE
7352 *
7353 * Deprecated: 3.16: static gravities haven't worked on anything but X11
7354 * for a long time.
7355 */
7356 gboolean
gdk_window_set_static_gravities(GdkWindow * window,gboolean use_static)7357 gdk_window_set_static_gravities (GdkWindow *window,
7358 gboolean use_static)
7359 {
7360 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
7361
7362 return FALSE;
7363 }
7364
7365 /**
7366 * gdk_window_get_composited:
7367 * @window: a #GdkWindow
7368 *
7369 * Determines whether @window is composited.
7370 *
7371 * See gdk_window_set_composited().
7372 *
7373 * Returns: %TRUE if the window is composited.
7374 *
7375 * Since: 2.22
7376 *
7377 * Deprecated: 3.16: Compositing is an outdated technology that
7378 * only ever worked on X11.
7379 **/
7380 gboolean
gdk_window_get_composited(GdkWindow * window)7381 gdk_window_get_composited (GdkWindow *window)
7382 {
7383 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
7384
7385 return window->composited;
7386 }
7387
7388 /**
7389 * gdk_window_set_composited:
7390 * @window: a #GdkWindow
7391 * @composited: %TRUE to set the window as composited
7392 *
7393 * Sets a #GdkWindow as composited, or unsets it. Composited
7394 * windows do not automatically have their contents drawn to
7395 * the screen. Drawing is redirected to an offscreen buffer
7396 * and an expose event is emitted on the parent of the composited
7397 * window. It is the responsibility of the parent’s expose handler
7398 * to manually merge the off-screen content onto the screen in
7399 * whatever way it sees fit.
7400 *
7401 * It only makes sense for child windows to be composited; see
7402 * gdk_window_set_opacity() if you need translucent toplevel
7403 * windows.
7404 *
7405 * An additional effect of this call is that the area of this
7406 * window is no longer clipped from regions marked for
7407 * invalidation on its parent. Draws done on the parent
7408 * window are also no longer clipped by the child.
7409 *
7410 * This call is only supported on some systems (currently,
7411 * only X11 with new enough Xcomposite and Xdamage extensions).
7412 * You must call gdk_display_supports_composite() to check if
7413 * setting a window as composited is supported before
7414 * attempting to do so.
7415 *
7416 * Since: 2.12
7417 *
7418 * Deprecated: 3.16: Compositing is an outdated technology that
7419 * only ever worked on X11.
7420 */
7421 void
gdk_window_set_composited(GdkWindow * window,gboolean composited)7422 gdk_window_set_composited (GdkWindow *window,
7423 gboolean composited)
7424 {
7425 GdkDisplay *display;
7426 GdkWindowImplClass *impl_class;
7427
7428 g_return_if_fail (GDK_IS_WINDOW (window));
7429
7430 composited = composited != FALSE;
7431
7432 if (window->composited == composited)
7433 return;
7434
7435 if (composited)
7436 gdk_window_ensure_native (window);
7437
7438 display = gdk_window_get_display (window);
7439
7440 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
7441
7442 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
7443 if (composited && (!gdk_display_supports_composite (display) || !impl_class->set_composited))
7444 {
7445 g_warning ("gdk_window_set_composited called but "
7446 "compositing is not supported");
7447 return;
7448 }
7449 G_GNUC_END_IGNORE_DEPRECATIONS
7450
7451 impl_class->set_composited (window, composited);
7452
7453 recompute_visible_regions (window, FALSE);
7454
7455 if (GDK_WINDOW_IS_MAPPED (window))
7456 gdk_window_invalidate_in_parent (window);
7457
7458 window->composited = composited;
7459 }
7460
7461 /**
7462 * gdk_window_get_modal_hint:
7463 * @window: A toplevel #GdkWindow.
7464 *
7465 * Determines whether or not the window manager is hinted that @window
7466 * has modal behaviour.
7467 *
7468 * Returns: whether or not the window has the modal hint set.
7469 *
7470 * Since: 2.22
7471 */
7472 gboolean
gdk_window_get_modal_hint(GdkWindow * window)7473 gdk_window_get_modal_hint (GdkWindow *window)
7474 {
7475 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
7476
7477 return window->modal_hint;
7478 }
7479
7480 /**
7481 * gdk_window_get_accept_focus:
7482 * @window: a toplevel #GdkWindow.
7483 *
7484 * Determines whether or not the desktop environment shuld be hinted that
7485 * the window does not want to receive input focus.
7486 *
7487 * Returns: whether or not the window should receive input focus.
7488 *
7489 * Since: 2.22
7490 */
7491 gboolean
gdk_window_get_accept_focus(GdkWindow * window)7492 gdk_window_get_accept_focus (GdkWindow *window)
7493 {
7494 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
7495
7496 return window->accept_focus;
7497 }
7498
7499 /**
7500 * gdk_window_get_focus_on_map:
7501 * @window: a toplevel #GdkWindow.
7502 *
7503 * Determines whether or not the desktop environment should be hinted that the
7504 * window does not want to receive input focus when it is mapped.
7505 *
7506 * Returns: whether or not the window wants to receive input focus when
7507 * it is mapped.
7508 *
7509 * Since: 2.22
7510 */
7511 gboolean
gdk_window_get_focus_on_map(GdkWindow * window)7512 gdk_window_get_focus_on_map (GdkWindow *window)
7513 {
7514 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
7515
7516 return window->focus_on_map;
7517 }
7518
7519 /**
7520 * gdk_window_is_input_only:
7521 * @window: a toplevel #GdkWindow
7522 *
7523 * Determines whether or not the window is an input only window.
7524 *
7525 * Returns: %TRUE if @window is input only
7526 *
7527 * Since: 2.22
7528 */
7529 gboolean
gdk_window_is_input_only(GdkWindow * window)7530 gdk_window_is_input_only (GdkWindow *window)
7531 {
7532 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
7533
7534 return window->input_only;
7535 }
7536
7537 /**
7538 * gdk_window_is_shaped:
7539 * @window: a toplevel #GdkWindow
7540 *
7541 * Determines whether or not the window is shaped.
7542 *
7543 * Returns: %TRUE if @window is shaped
7544 *
7545 * Since: 2.22
7546 */
7547 gboolean
gdk_window_is_shaped(GdkWindow * window)7548 gdk_window_is_shaped (GdkWindow *window)
7549 {
7550 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
7551
7552 return window->shaped;
7553 }
7554
7555 /* Gets the toplevel for a window as used for events,
7556 i.e. including offscreen parents */
7557 static GdkWindow *
get_event_parent(GdkWindow * window)7558 get_event_parent (GdkWindow *window)
7559 {
7560 if (gdk_window_is_offscreen (window))
7561 return gdk_offscreen_window_get_embedder ((GdkWindow *)window);
7562 else
7563 return window->parent;
7564 }
7565
7566 /* Gets the toplevel for a window as used for events,
7567 i.e. including offscreen parents going up to the native
7568 toplevel */
7569 static GdkWindow *
get_event_toplevel(GdkWindow * window)7570 get_event_toplevel (GdkWindow *window)
7571 {
7572 GdkWindow *parent;
7573
7574 while ((parent = get_event_parent (window)) != NULL &&
7575 (parent->window_type != GDK_WINDOW_ROOT))
7576 window = parent;
7577
7578 return window;
7579 }
7580
7581 gboolean
_gdk_window_event_parent_of(GdkWindow * parent,GdkWindow * child)7582 _gdk_window_event_parent_of (GdkWindow *parent,
7583 GdkWindow *child)
7584 {
7585 GdkWindow *w;
7586
7587 w = child;
7588 while (w != NULL)
7589 {
7590 if (w == parent)
7591 return TRUE;
7592
7593 w = get_event_parent (w);
7594 }
7595
7596 return FALSE;
7597 }
7598
7599 static void
update_cursor(GdkDisplay * display,GdkDevice * device)7600 update_cursor (GdkDisplay *display,
7601 GdkDevice *device)
7602 {
7603 GdkWindow *cursor_window, *parent, *toplevel;
7604 GdkWindow *pointer_window;
7605 GdkWindowImplClass *impl_class;
7606 GdkPointerWindowInfo *pointer_info;
7607 GdkDeviceGrabInfo *grab;
7608 GdkCursor *cursor;
7609
7610 pointer_info = _gdk_display_get_pointer_info (display, device);
7611 pointer_window = pointer_info->window_under_pointer;
7612
7613 /* We ignore the serials here and just pick the last grab
7614 we've sent, as that would shortly be used anyway. */
7615 grab = _gdk_display_get_last_device_grab (display, device);
7616 if (/* have grab */
7617 grab != NULL &&
7618 /* the pointer is not in a descendant of the grab window */
7619 !_gdk_window_event_parent_of (grab->window, pointer_window))
7620 {
7621 /* use the cursor from the grab window */
7622 cursor_window = grab->window;
7623 }
7624 else
7625 {
7626 /* otherwise use the cursor from the pointer window */
7627 cursor_window = pointer_window;
7628 }
7629
7630 /* Find the first window with the cursor actually set, as
7631 the cursor is inherited from the parent */
7632 while (cursor_window->cursor == NULL &&
7633 !g_hash_table_contains (cursor_window->device_cursor, device) &&
7634 (parent = get_event_parent (cursor_window)) != NULL &&
7635 parent->window_type != GDK_WINDOW_ROOT)
7636 cursor_window = parent;
7637
7638 cursor = g_hash_table_lookup (cursor_window->device_cursor, device);
7639
7640 if (!cursor)
7641 cursor = cursor_window->cursor;
7642
7643 /* Set all cursors on toplevel, otherwise its tricky to keep track of
7644 * which native window has what cursor set. */
7645 toplevel = get_event_toplevel (pointer_window);
7646 impl_class = GDK_WINDOW_IMPL_GET_CLASS (toplevel->impl);
7647 impl_class->set_device_cursor (toplevel, device, cursor);
7648 }
7649
7650 static gboolean
point_in_window(GdkWindow * window,gdouble x,gdouble y)7651 point_in_window (GdkWindow *window,
7652 gdouble x,
7653 gdouble y)
7654 {
7655 return
7656 x >= 0 && x < window->width &&
7657 y >= 0 && y < window->height &&
7658 (window->shape == NULL ||
7659 cairo_region_contains_point (window->shape,
7660 x, y)) &&
7661 (window->input_shape == NULL ||
7662 cairo_region_contains_point (window->input_shape,
7663 x, y));
7664 }
7665
7666 /* Same as point_in_window, except it also takes pass_through and its
7667 interaction with child windows into account */
7668 static gboolean
point_in_input_window(GdkWindow * window,gdouble x,gdouble y,GdkWindow ** input_window,gdouble * input_window_x,gdouble * input_window_y)7669 point_in_input_window (GdkWindow *window,
7670 gdouble x,
7671 gdouble y,
7672 GdkWindow **input_window,
7673 gdouble *input_window_x,
7674 gdouble *input_window_y)
7675 {
7676 GdkWindow *sub;
7677 double child_x, child_y;
7678 GList *l;
7679
7680 if (!point_in_window (window, x, y))
7681 return FALSE;
7682
7683 if (!window->pass_through)
7684 {
7685 if (input_window)
7686 {
7687 *input_window = window;
7688 *input_window_x = x;
7689 *input_window_y = y;
7690 }
7691 return TRUE;
7692 }
7693
7694 /* For pass-through, must be over a child input window */
7695
7696 /* Children is ordered in reverse stack order, i.e. first is topmost */
7697 for (l = window->children; l != NULL; l = l->next)
7698 {
7699 sub = l->data;
7700
7701 if (!GDK_WINDOW_IS_MAPPED (sub))
7702 continue;
7703
7704 gdk_window_coords_from_parent ((GdkWindow *)sub,
7705 x, y,
7706 &child_x, &child_y);
7707 if (point_in_input_window (sub, child_x, child_y,
7708 input_window, input_window_x, input_window_y))
7709 {
7710 if (input_window)
7711 gdk_window_coords_to_parent (sub,
7712 *input_window_x,
7713 *input_window_y,
7714 input_window_x,
7715 input_window_y);
7716 return TRUE;
7717 }
7718 }
7719
7720 return FALSE;
7721 }
7722
7723 static GdkWindow *
convert_native_coords_to_toplevel(GdkWindow * window,gdouble child_x,gdouble child_y,gdouble * toplevel_x,gdouble * toplevel_y)7724 convert_native_coords_to_toplevel (GdkWindow *window,
7725 gdouble child_x,
7726 gdouble child_y,
7727 gdouble *toplevel_x,
7728 gdouble *toplevel_y)
7729 {
7730 gdouble x, y;
7731
7732 x = child_x;
7733 y = child_y;
7734
7735 while (!gdk_window_is_toplevel (window))
7736 {
7737 x += window->x;
7738 y += window->y;
7739 window = window->parent;
7740 }
7741
7742 *toplevel_x = x;
7743 *toplevel_y = y;
7744
7745 return window;
7746 }
7747
7748 static void
convert_toplevel_coords_to_window(GdkWindow * window,gdouble toplevel_x,gdouble toplevel_y,gdouble * window_x,gdouble * window_y)7749 convert_toplevel_coords_to_window (GdkWindow *window,
7750 gdouble toplevel_x,
7751 gdouble toplevel_y,
7752 gdouble *window_x,
7753 gdouble *window_y)
7754 {
7755 GdkWindow *parent;
7756 gdouble x, y;
7757 GList *children, *l;
7758
7759 x = toplevel_x;
7760 y = toplevel_y;
7761
7762 children = NULL;
7763 while ((parent = get_event_parent (window)) != NULL &&
7764 (parent->window_type != GDK_WINDOW_ROOT))
7765 {
7766 children = g_list_prepend (children, window);
7767 window = parent;
7768 }
7769
7770 for (l = children; l != NULL; l = l->next)
7771 gdk_window_coords_from_parent (l->data, x, y, &x, &y);
7772
7773 g_list_free (children);
7774
7775 *window_x = x;
7776 *window_y = y;
7777 }
7778
7779 static GdkWindow *
pick_embedded_child(GdkWindow * window,gdouble x,gdouble y)7780 pick_embedded_child (GdkWindow *window,
7781 gdouble x,
7782 gdouble y)
7783 {
7784 GdkWindow *res;
7785
7786 res = NULL;
7787 g_signal_emit (window,
7788 signals[PICK_EMBEDDED_CHILD], 0,
7789 x, y, &res);
7790
7791 return res;
7792 }
7793
7794 GdkWindow *
_gdk_window_find_child_at(GdkWindow * window,double x,double y)7795 _gdk_window_find_child_at (GdkWindow *window,
7796 double x,
7797 double y)
7798 {
7799 GdkWindow *sub;
7800 double child_x, child_y;
7801 GList *l;
7802
7803 if (point_in_window (window, x, y))
7804 {
7805 /* Children is ordered in reverse stack order, i.e. first is topmost */
7806 for (l = window->children; l != NULL; l = l->next)
7807 {
7808 sub = l->data;
7809
7810 if (!GDK_WINDOW_IS_MAPPED (sub))
7811 continue;
7812
7813 gdk_window_coords_from_parent ((GdkWindow *)sub,
7814 x, y,
7815 &child_x, &child_y);
7816 if (point_in_input_window (sub, child_x, child_y,
7817 NULL, NULL, NULL))
7818 return (GdkWindow *)sub;
7819 }
7820
7821 if (window->num_offscreen_children > 0)
7822 {
7823 sub = pick_embedded_child (window,
7824 x, y);
7825 if (sub)
7826 return (GdkWindow *)sub;
7827 }
7828 }
7829
7830 return NULL;
7831 }
7832
7833 GdkWindow *
_gdk_window_find_descendant_at(GdkWindow * window,gdouble x,gdouble y,gdouble * found_x,gdouble * found_y)7834 _gdk_window_find_descendant_at (GdkWindow *window,
7835 gdouble x,
7836 gdouble y,
7837 gdouble *found_x,
7838 gdouble *found_y)
7839 {
7840 GdkWindow *sub, *input_window;
7841 gdouble child_x, child_y;
7842 GList *l;
7843 gboolean found;
7844
7845 if (point_in_window (window, x, y))
7846 {
7847 do
7848 {
7849 found = FALSE;
7850 /* Children is ordered in reverse stack order, i.e. first is topmost */
7851 for (l = window->children; l != NULL; l = l->next)
7852 {
7853 sub = l->data;
7854
7855 if (!GDK_WINDOW_IS_MAPPED (sub))
7856 continue;
7857
7858 gdk_window_coords_from_parent ((GdkWindow *)sub,
7859 x, y,
7860 &child_x, &child_y);
7861 if (point_in_input_window (sub, child_x, child_y,
7862 &input_window, &child_x, &child_y))
7863 {
7864 x = child_x;
7865 y = child_y;
7866 window = input_window;
7867 found = TRUE;
7868 break;
7869 }
7870 }
7871 if (!found &&
7872 window->num_offscreen_children > 0)
7873 {
7874 sub = pick_embedded_child (window,
7875 x, y);
7876 if (sub)
7877 {
7878 found = TRUE;
7879 window = sub;
7880 from_embedder (sub, x, y, &x, &y);
7881 }
7882 }
7883 }
7884 while (found);
7885 }
7886 else
7887 {
7888 /* Not in window at all */
7889 window = NULL;
7890 }
7891
7892 if (found_x)
7893 *found_x = x;
7894 if (found_y)
7895 *found_y = y;
7896
7897 return window;
7898 }
7899
7900 /**
7901 * gdk_window_beep:
7902 * @window: a toplevel #GdkWindow
7903 *
7904 * Emits a short beep associated to @window in the appropriate
7905 * display, if supported. Otherwise, emits a short beep on
7906 * the display just as gdk_display_beep().
7907 *
7908 * Since: 2.12
7909 **/
7910 void
gdk_window_beep(GdkWindow * window)7911 gdk_window_beep (GdkWindow *window)
7912 {
7913 GdkDisplay *display;
7914 GdkWindow *toplevel;
7915
7916 g_return_if_fail (GDK_IS_WINDOW (window));
7917
7918 if (GDK_WINDOW_DESTROYED (window))
7919 return;
7920
7921 toplevel = get_event_toplevel (window);
7922 display = gdk_window_get_display (window);
7923
7924 if (toplevel)
7925 {
7926 if (GDK_WINDOW_IMPL_GET_CLASS (toplevel->impl)->beep (toplevel))
7927 return;
7928 }
7929
7930 /* If windows fail to beep, we beep the display. */
7931 gdk_display_beep (display);
7932 }
7933
7934 /**
7935 * gdk_window_set_support_multidevice:
7936 * @window: a #GdkWindow.
7937 * @support_multidevice: %TRUE to enable multidevice support in @window.
7938 *
7939 * This function will enable multidevice features in @window.
7940 *
7941 * Multidevice aware windows will need to handle properly multiple,
7942 * per device enter/leave events, device grabs and grab ownerships.
7943 *
7944 * Since: 3.0
7945 **/
7946 void
gdk_window_set_support_multidevice(GdkWindow * window,gboolean support_multidevice)7947 gdk_window_set_support_multidevice (GdkWindow *window,
7948 gboolean support_multidevice)
7949 {
7950 g_return_if_fail (GDK_IS_WINDOW (window));
7951
7952 if (GDK_WINDOW_DESTROYED (window))
7953 return;
7954
7955 if (window->support_multidevice == support_multidevice)
7956 return;
7957
7958 window->support_multidevice = support_multidevice;
7959
7960 /* FIXME: What to do if called when some pointers are inside the window ? */
7961 }
7962
7963 /**
7964 * gdk_window_get_support_multidevice:
7965 * @window: a #GdkWindow.
7966 *
7967 * Returns %TRUE if the window is aware of the existence of multiple
7968 * devices.
7969 *
7970 * Returns: %TRUE if the window handles multidevice features.
7971 *
7972 * Since: 3.0
7973 **/
7974 gboolean
gdk_window_get_support_multidevice(GdkWindow * window)7975 gdk_window_get_support_multidevice (GdkWindow *window)
7976 {
7977 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
7978
7979 if (GDK_WINDOW_DESTROYED (window))
7980 return FALSE;
7981
7982 return window->support_multidevice;
7983 }
7984
7985 static const guint type_masks[] = {
7986 GDK_SUBSTRUCTURE_MASK, /* GDK_DELETE = 0 */
7987 GDK_STRUCTURE_MASK, /* GDK_DESTROY = 1 */
7988 GDK_EXPOSURE_MASK, /* GDK_EXPOSE = 2 */
7989 GDK_POINTER_MOTION_MASK, /* GDK_MOTION_NOTIFY = 3 */
7990 GDK_BUTTON_PRESS_MASK, /* GDK_BUTTON_PRESS = 4 */
7991 GDK_BUTTON_PRESS_MASK, /* GDK_2BUTTON_PRESS = 5 */
7992 GDK_BUTTON_PRESS_MASK, /* GDK_3BUTTON_PRESS = 6 */
7993 GDK_BUTTON_RELEASE_MASK, /* GDK_BUTTON_RELEASE = 7 */
7994 GDK_KEY_PRESS_MASK, /* GDK_KEY_PRESS = 8 */
7995 GDK_KEY_RELEASE_MASK, /* GDK_KEY_RELEASE = 9 */
7996 GDK_ENTER_NOTIFY_MASK, /* GDK_ENTER_NOTIFY = 10 */
7997 GDK_LEAVE_NOTIFY_MASK, /* GDK_LEAVE_NOTIFY = 11 */
7998 GDK_FOCUS_CHANGE_MASK, /* GDK_FOCUS_CHANGE = 12 */
7999 GDK_STRUCTURE_MASK, /* GDK_CONFIGURE = 13 */
8000 GDK_VISIBILITY_NOTIFY_MASK, /* GDK_MAP = 14 */
8001 GDK_VISIBILITY_NOTIFY_MASK, /* GDK_UNMAP = 15 */
8002 GDK_PROPERTY_CHANGE_MASK, /* GDK_PROPERTY_NOTIFY = 16 */
8003 GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_CLEAR = 17 */
8004 GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_REQUEST = 18 */
8005 GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_NOTIFY = 19 */
8006 GDK_PROXIMITY_IN_MASK, /* GDK_PROXIMITY_IN = 20 */
8007 GDK_PROXIMITY_OUT_MASK, /* GDK_PROXIMITY_OUT = 21 */
8008 GDK_ALL_EVENTS_MASK, /* GDK_DRAG_ENTER = 22 */
8009 GDK_ALL_EVENTS_MASK, /* GDK_DRAG_LEAVE = 23 */
8010 GDK_ALL_EVENTS_MASK, /* GDK_DRAG_MOTION = 24 */
8011 GDK_ALL_EVENTS_MASK, /* GDK_DRAG_STATUS = 25 */
8012 GDK_ALL_EVENTS_MASK, /* GDK_DROP_START = 26 */
8013 GDK_ALL_EVENTS_MASK, /* GDK_DROP_FINISHED = 27 */
8014 GDK_ALL_EVENTS_MASK, /* GDK_CLIENT_EVENT = 28 */
8015 GDK_VISIBILITY_NOTIFY_MASK, /* GDK_VISIBILITY_NOTIFY = 29 */
8016 GDK_EXPOSURE_MASK, /* GDK_NO_EXPOSE = 30 */
8017 GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK,/* GDK_SCROLL= 31 */
8018 0, /* GDK_WINDOW_STATE = 32 */
8019 0, /* GDK_SETTING = 33 */
8020 0, /* GDK_OWNER_CHANGE = 34 */
8021 0, /* GDK_GRAB_BROKEN = 35 */
8022 0, /* GDK_DAMAGE = 36 */
8023 GDK_TOUCH_MASK, /* GDK_TOUCH_BEGIN = 37 */
8024 GDK_TOUCH_MASK, /* GDK_TOUCH_UPDATE = 38 */
8025 GDK_TOUCH_MASK, /* GDK_TOUCH_END = 39 */
8026 GDK_TOUCH_MASK, /* GDK_TOUCH_CANCEL = 40 */
8027 GDK_TOUCHPAD_GESTURE_MASK, /* GDK_TOUCHPAD_SWIPE = 41 */
8028 GDK_TOUCHPAD_GESTURE_MASK, /* GDK_TOUCHPAD_PINCH = 42 */
8029 GDK_TABLET_PAD_MASK, /* GDK_PAD_BUTTON_PRESS = 43 */
8030 GDK_TABLET_PAD_MASK, /* GDK_PAD_BUTTON_RELEASE = 44 */
8031 GDK_TABLET_PAD_MASK, /* GDK_PAD_RING = 45 */
8032 GDK_TABLET_PAD_MASK, /* GDK_PAD_STRIP = 46 */
8033 GDK_TABLET_PAD_MASK, /* GDK_PAD_GROUP_MODE = 47 */
8034 };
8035 G_STATIC_ASSERT (G_N_ELEMENTS (type_masks) == GDK_EVENT_LAST);
8036
8037 /* send motion events if the right buttons are down */
8038 static guint
update_evmask_for_button_motion(guint evmask,GdkModifierType mask)8039 update_evmask_for_button_motion (guint evmask,
8040 GdkModifierType mask)
8041 {
8042 if (evmask & GDK_BUTTON_MOTION_MASK &&
8043 mask & (GDK_BUTTON1_MASK |
8044 GDK_BUTTON2_MASK |
8045 GDK_BUTTON3_MASK |
8046 GDK_BUTTON4_MASK |
8047 GDK_BUTTON5_MASK))
8048 evmask |= GDK_POINTER_MOTION_MASK;
8049
8050 if ((evmask & GDK_BUTTON1_MOTION_MASK && mask & GDK_BUTTON1_MASK) ||
8051 (evmask & GDK_BUTTON2_MOTION_MASK && mask & GDK_BUTTON2_MASK) ||
8052 (evmask & GDK_BUTTON3_MOTION_MASK && mask & GDK_BUTTON3_MASK))
8053 evmask |= GDK_POINTER_MOTION_MASK;
8054
8055 return evmask;
8056 }
8057
8058 static gboolean
is_button_type(GdkEventType type)8059 is_button_type (GdkEventType type)
8060 {
8061 return type == GDK_BUTTON_PRESS ||
8062 type == GDK_2BUTTON_PRESS ||
8063 type == GDK_3BUTTON_PRESS ||
8064 type == GDK_BUTTON_RELEASE ||
8065 type == GDK_TOUCH_BEGIN ||
8066 type == GDK_TOUCH_END ||
8067 type == GDK_TOUCH_CANCEL ||
8068 type == GDK_SCROLL;
8069 }
8070
8071 static gboolean
is_gesture_type(GdkEventType type)8072 is_gesture_type (GdkEventType type)
8073 {
8074 return (type == GDK_TOUCHPAD_SWIPE ||
8075 type == GDK_TOUCHPAD_PINCH);
8076 }
8077
8078 static gboolean
is_motion_type(GdkEventType type)8079 is_motion_type (GdkEventType type)
8080 {
8081 return type == GDK_MOTION_NOTIFY ||
8082 type == GDK_TOUCH_UPDATE ||
8083 type == GDK_ENTER_NOTIFY ||
8084 type == GDK_LEAVE_NOTIFY;
8085 }
8086
8087 static gboolean
is_touch_type(GdkEventType type)8088 is_touch_type (GdkEventType type)
8089 {
8090 return type == GDK_TOUCH_BEGIN ||
8091 type == GDK_TOUCH_UPDATE ||
8092 type == GDK_TOUCH_END ||
8093 type == GDK_TOUCH_CANCEL;
8094 }
8095
8096 static GdkWindow *
find_common_ancestor(GdkWindow * win1,GdkWindow * win2)8097 find_common_ancestor (GdkWindow *win1,
8098 GdkWindow *win2)
8099 {
8100 GdkWindow *tmp;
8101 GList *path1 = NULL, *path2 = NULL;
8102 GList *list1, *list2;
8103
8104 tmp = win1;
8105 while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
8106 {
8107 path1 = g_list_prepend (path1, tmp);
8108 tmp = get_event_parent (tmp);
8109 }
8110
8111 tmp = win2;
8112 while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
8113 {
8114 path2 = g_list_prepend (path2, tmp);
8115 tmp = get_event_parent (tmp);
8116 }
8117
8118 list1 = path1;
8119 list2 = path2;
8120 tmp = NULL;
8121 while (list1 && list2 && (list1->data == list2->data))
8122 {
8123 tmp = list1->data;
8124 list1 = list1->next;
8125 list2 = list2->next;
8126 }
8127 g_list_free (path1);
8128 g_list_free (path2);
8129
8130 return tmp;
8131 }
8132
8133 GdkEvent *
_gdk_make_event(GdkWindow * window,GdkEventType type,GdkEvent * event_in_queue,gboolean before_event)8134 _gdk_make_event (GdkWindow *window,
8135 GdkEventType type,
8136 GdkEvent *event_in_queue,
8137 gboolean before_event)
8138 {
8139 GdkEvent *event = gdk_event_new (type);
8140 guint32 the_time;
8141 GdkModifierType the_state;
8142
8143 the_time = gdk_event_get_time (event_in_queue);
8144 gdk_event_get_state (event_in_queue, &the_state);
8145
8146 event->any.window = g_object_ref (window);
8147 event->any.send_event = FALSE;
8148 if (event_in_queue && event_in_queue->any.send_event)
8149 event->any.send_event = TRUE;
8150
8151 switch (type)
8152 {
8153 case GDK_MOTION_NOTIFY:
8154 event->motion.time = the_time;
8155 event->motion.axes = NULL;
8156 event->motion.state = the_state;
8157 break;
8158
8159 case GDK_BUTTON_PRESS:
8160 case GDK_2BUTTON_PRESS:
8161 case GDK_3BUTTON_PRESS:
8162 case GDK_BUTTON_RELEASE:
8163 event->button.time = the_time;
8164 event->button.axes = NULL;
8165 event->button.state = the_state;
8166 break;
8167
8168 case GDK_TOUCH_BEGIN:
8169 case GDK_TOUCH_UPDATE:
8170 case GDK_TOUCH_END:
8171 case GDK_TOUCH_CANCEL:
8172 event->touch.time = the_time;
8173 event->touch.axes = NULL;
8174 event->touch.state = the_state;
8175 break;
8176
8177 case GDK_SCROLL:
8178 event->scroll.time = the_time;
8179 event->scroll.state = the_state;
8180 break;
8181
8182 case GDK_KEY_PRESS:
8183 case GDK_KEY_RELEASE:
8184 event->key.time = the_time;
8185 event->key.state = the_state;
8186 break;
8187
8188 case GDK_ENTER_NOTIFY:
8189 case GDK_LEAVE_NOTIFY:
8190 event->crossing.time = the_time;
8191 event->crossing.state = the_state;
8192 break;
8193
8194 case GDK_PROPERTY_NOTIFY:
8195 event->property.time = the_time;
8196 event->property.state = the_state;
8197 break;
8198
8199 case GDK_SELECTION_CLEAR:
8200 case GDK_SELECTION_REQUEST:
8201 case GDK_SELECTION_NOTIFY:
8202 event->selection.time = the_time;
8203 break;
8204
8205 case GDK_PROXIMITY_IN:
8206 case GDK_PROXIMITY_OUT:
8207 event->proximity.time = the_time;
8208 break;
8209
8210 case GDK_DRAG_ENTER:
8211 case GDK_DRAG_LEAVE:
8212 case GDK_DRAG_MOTION:
8213 case GDK_DRAG_STATUS:
8214 case GDK_DROP_START:
8215 case GDK_DROP_FINISHED:
8216 event->dnd.time = the_time;
8217 break;
8218
8219 case GDK_TOUCHPAD_SWIPE:
8220 event->touchpad_swipe.time = the_time;
8221 event->touchpad_swipe.state = the_state;
8222 break;
8223
8224 case GDK_TOUCHPAD_PINCH:
8225 event->touchpad_pinch.time = the_time;
8226 event->touchpad_pinch.state = the_state;
8227 break;
8228
8229 case GDK_FOCUS_CHANGE:
8230 case GDK_CONFIGURE:
8231 case GDK_MAP:
8232 case GDK_UNMAP:
8233 case GDK_CLIENT_EVENT:
8234 case GDK_VISIBILITY_NOTIFY:
8235 case GDK_DELETE:
8236 case GDK_DESTROY:
8237 case GDK_EXPOSE:
8238 default:
8239 break;
8240 }
8241
8242 if (event_in_queue)
8243 {
8244 if (before_event)
8245 _gdk_event_queue_insert_before (gdk_window_get_display (window), event_in_queue, event);
8246 else
8247 _gdk_event_queue_insert_after (gdk_window_get_display (window), event_in_queue, event);
8248 }
8249 else
8250 _gdk_event_queue_append (gdk_window_get_display (window), event);
8251
8252 return event;
8253 }
8254
8255 static void
send_crossing_event(GdkDisplay * display,GdkWindow * toplevel,GdkWindow * window,GdkEventType type,GdkCrossingMode mode,GdkNotifyType notify_type,GdkWindow * subwindow,GdkDevice * device,GdkDevice * source_device,gdouble toplevel_x,gdouble toplevel_y,GdkModifierType mask,guint32 time_,GdkEvent * event_in_queue,gulong serial)8256 send_crossing_event (GdkDisplay *display,
8257 GdkWindow *toplevel,
8258 GdkWindow *window,
8259 GdkEventType type,
8260 GdkCrossingMode mode,
8261 GdkNotifyType notify_type,
8262 GdkWindow *subwindow,
8263 GdkDevice *device,
8264 GdkDevice *source_device,
8265 gdouble toplevel_x,
8266 gdouble toplevel_y,
8267 GdkModifierType mask,
8268 guint32 time_,
8269 GdkEvent *event_in_queue,
8270 gulong serial)
8271 {
8272 GdkEvent *event;
8273 guint32 window_event_mask, type_event_mask;
8274 GdkDeviceGrabInfo *grab;
8275 GdkTouchGrabInfo *touch_grab = NULL;
8276 GdkPointerWindowInfo *pointer_info;
8277 gboolean block_event = FALSE;
8278 GdkEventSequence *sequence;
8279
8280 grab = _gdk_display_has_device_grab (display, device, serial);
8281 pointer_info = _gdk_display_get_pointer_info (display, device);
8282
8283 sequence = gdk_event_get_event_sequence (event_in_queue);
8284 if (sequence)
8285 touch_grab = _gdk_display_has_touch_grab (display, device, sequence, serial);
8286
8287 if (touch_grab)
8288 {
8289 if (window != touch_grab->window)
8290 return;
8291
8292 window_event_mask = touch_grab->event_mask;
8293 }
8294 else if (grab != NULL &&
8295 !grab->owner_events)
8296 {
8297 /* !owner_event => only report events wrt grab window, ignore rest */
8298 if ((GdkWindow *)window != grab->window)
8299 return;
8300 window_event_mask = grab->event_mask;
8301 }
8302 else
8303 window_event_mask = window->event_mask;
8304
8305 if (type == GDK_ENTER_NOTIFY &&
8306 (pointer_info->need_touch_press_enter ||
8307 (source_device &&
8308 gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)) &&
8309 mode != GDK_CROSSING_TOUCH_BEGIN &&
8310 mode != GDK_CROSSING_TOUCH_END)
8311 {
8312 pointer_info->need_touch_press_enter = TRUE;
8313 block_event = TRUE;
8314 }
8315 else if (type == GDK_LEAVE_NOTIFY)
8316 {
8317 type_event_mask = GDK_LEAVE_NOTIFY_MASK;
8318 window->devices_inside = g_list_remove (window->devices_inside, device);
8319
8320 if (!window->support_multidevice && window->devices_inside)
8321 {
8322 /* Block leave events unless it's the last pointer */
8323 block_event = TRUE;
8324 }
8325 }
8326 else
8327 {
8328 type_event_mask = GDK_ENTER_NOTIFY_MASK;
8329
8330 if (!window->support_multidevice && window->devices_inside)
8331 {
8332 /* Only emit enter events for the first device */
8333 block_event = TRUE;
8334 }
8335
8336 if (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER &&
8337 gdk_device_get_mode (device) != GDK_MODE_DISABLED &&
8338 !g_list_find (window->devices_inside, device))
8339 window->devices_inside = g_list_prepend (window->devices_inside, device);
8340 }
8341
8342 if (block_event)
8343 return;
8344
8345 if (window_event_mask & type_event_mask)
8346 {
8347 event = _gdk_make_event ((GdkWindow *)window, type, event_in_queue, TRUE);
8348 gdk_event_set_device (event, device);
8349 gdk_event_set_seat (event, gdk_device_get_seat (device));
8350
8351 if (source_device)
8352 gdk_event_set_source_device (event, source_device);
8353
8354 event->crossing.time = time_;
8355 event->crossing.subwindow = subwindow;
8356 if (subwindow)
8357 g_object_ref (subwindow);
8358 convert_toplevel_coords_to_window ((GdkWindow *)window,
8359 toplevel_x, toplevel_y,
8360 &event->crossing.x, &event->crossing.y);
8361 event->crossing.x_root = toplevel_x + toplevel->x;
8362 event->crossing.y_root = toplevel_y + toplevel->y;
8363 event->crossing.mode = mode;
8364 event->crossing.detail = notify_type;
8365 event->crossing.focus = FALSE;
8366 event->crossing.state = mask;
8367 }
8368 }
8369
8370
8371 /* The coordinates are in the toplevel window that src/dest are in.
8372 * src and dest are always (if != NULL) in the same toplevel, as
8373 * we get a leave-notify and set the window_under_pointer to null
8374 * before crossing to another toplevel.
8375 */
8376 void
_gdk_synthesize_crossing_events(GdkDisplay * display,GdkWindow * src,GdkWindow * dest,GdkDevice * device,GdkDevice * source_device,GdkCrossingMode mode,double toplevel_x,double toplevel_y,GdkModifierType mask,guint32 time_,GdkEvent * event_in_queue,gulong serial,gboolean non_linear)8377 _gdk_synthesize_crossing_events (GdkDisplay *display,
8378 GdkWindow *src,
8379 GdkWindow *dest,
8380 GdkDevice *device,
8381 GdkDevice *source_device,
8382 GdkCrossingMode mode,
8383 double toplevel_x,
8384 double toplevel_y,
8385 GdkModifierType mask,
8386 guint32 time_,
8387 GdkEvent *event_in_queue,
8388 gulong serial,
8389 gboolean non_linear)
8390 {
8391 GdkWindow *c;
8392 GdkWindow *win, *last, *next;
8393 GList *path, *list;
8394 GdkWindow *a;
8395 GdkWindow *b;
8396 GdkWindow *toplevel;
8397 GdkNotifyType notify_type;
8398
8399 /* TODO: Don't send events to toplevel, as we get those from the windowing system */
8400
8401 a = (src && GDK_IS_WINDOW (src)) ? src : NULL;
8402 b = (dest && GDK_IS_WINDOW (dest)) ? dest : NULL;
8403
8404 if (src == dest)
8405 return; /* No crossings generated between src and dest */
8406
8407 if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
8408 {
8409 if (a && gdk_window_get_device_events (src, device) == 0)
8410 a = NULL;
8411
8412 if (b && gdk_window_get_device_events (dest, device) == 0)
8413 b = NULL;
8414 }
8415
8416 if (!a && !b)
8417 return;
8418
8419 c = find_common_ancestor (a, b);
8420
8421 non_linear |= (c != a) && (c != b);
8422
8423 if (a) /* There might not be a source (i.e. if no previous pointer_in_window) */
8424 {
8425 toplevel = gdk_window_get_toplevel (a);
8426
8427 /* Traverse up from a to (excluding) c sending leave events */
8428 if (non_linear)
8429 notify_type = GDK_NOTIFY_NONLINEAR;
8430 else if (c == a)
8431 notify_type = GDK_NOTIFY_INFERIOR;
8432 else
8433 notify_type = GDK_NOTIFY_ANCESTOR;
8434 send_crossing_event (display, toplevel,
8435 a, GDK_LEAVE_NOTIFY,
8436 mode,
8437 notify_type,
8438 NULL, device, source_device,
8439 toplevel_x, toplevel_y,
8440 mask, time_,
8441 event_in_queue,
8442 serial);
8443
8444 if (c != a)
8445 {
8446 if (non_linear)
8447 notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
8448 else
8449 notify_type = GDK_NOTIFY_VIRTUAL;
8450
8451 last = a;
8452 win = get_event_parent (a);
8453 while (win != c && win->window_type != GDK_WINDOW_ROOT)
8454 {
8455 send_crossing_event (display, toplevel,
8456 win, GDK_LEAVE_NOTIFY,
8457 mode,
8458 notify_type,
8459 (GdkWindow *)last,
8460 device, source_device,
8461 toplevel_x, toplevel_y,
8462 mask, time_,
8463 event_in_queue,
8464 serial);
8465
8466 last = win;
8467 win = get_event_parent (win);
8468 }
8469 }
8470 }
8471
8472 if (b) /* Might not be a dest, e.g. if we're moving out of the window */
8473 {
8474 toplevel = gdk_window_get_toplevel ((GdkWindow *)b);
8475
8476 /* Traverse down from c to b */
8477 if (c != b)
8478 {
8479 path = NULL;
8480 win = get_event_parent (b);
8481 while (win != c && win->window_type != GDK_WINDOW_ROOT)
8482 {
8483 path = g_list_prepend (path, win);
8484 win = get_event_parent (win);
8485 }
8486
8487 if (non_linear)
8488 notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
8489 else
8490 notify_type = GDK_NOTIFY_VIRTUAL;
8491
8492 list = path;
8493 while (list)
8494 {
8495 win = list->data;
8496 list = list->next;
8497 if (list)
8498 next = list->data;
8499 else
8500 next = b;
8501
8502 send_crossing_event (display, toplevel,
8503 win, GDK_ENTER_NOTIFY,
8504 mode,
8505 notify_type,
8506 (GdkWindow *)next,
8507 device, source_device,
8508 toplevel_x, toplevel_y,
8509 mask, time_,
8510 event_in_queue,
8511 serial);
8512 }
8513 g_list_free (path);
8514 }
8515
8516
8517 if (non_linear)
8518 notify_type = GDK_NOTIFY_NONLINEAR;
8519 else if (c == a)
8520 notify_type = GDK_NOTIFY_ANCESTOR;
8521 else
8522 notify_type = GDK_NOTIFY_INFERIOR;
8523
8524 send_crossing_event (display, toplevel,
8525 b, GDK_ENTER_NOTIFY,
8526 mode,
8527 notify_type,
8528 NULL,
8529 device, source_device,
8530 toplevel_x, toplevel_y,
8531 mask, time_,
8532 event_in_queue,
8533 serial);
8534 }
8535 }
8536
8537 /* Returns the window inside the event window with the pointer in it
8538 * at the specified coordinates, or NULL if its not in any child of
8539 * the toplevel. It also takes into account !owner_events grabs.
8540 */
8541 static GdkWindow *
get_pointer_window(GdkDisplay * display,GdkWindow * event_window,GdkDevice * device,gdouble toplevel_x,gdouble toplevel_y,gulong serial)8542 get_pointer_window (GdkDisplay *display,
8543 GdkWindow *event_window,
8544 GdkDevice *device,
8545 gdouble toplevel_x,
8546 gdouble toplevel_y,
8547 gulong serial)
8548 {
8549 GdkWindow *pointer_window;
8550 GdkDeviceGrabInfo *grab;
8551 GdkPointerWindowInfo *pointer_info;
8552
8553 pointer_info = _gdk_display_get_pointer_info (display, device);
8554
8555 if (event_window == pointer_info->toplevel_under_pointer)
8556 pointer_window =
8557 _gdk_window_find_descendant_at (event_window,
8558 toplevel_x, toplevel_y,
8559 NULL, NULL);
8560 else
8561 pointer_window = NULL;
8562
8563 grab = _gdk_display_has_device_grab (display, device, serial);
8564 if (grab != NULL &&
8565 !grab->owner_events &&
8566 pointer_window != grab->window &&
8567 !gdk_window_is_ancestor (pointer_window, grab->window))
8568 pointer_window = NULL;
8569
8570 return pointer_window;
8571 }
8572
8573 void
_gdk_display_set_window_under_pointer(GdkDisplay * display,GdkDevice * device,GdkWindow * window)8574 _gdk_display_set_window_under_pointer (GdkDisplay *display,
8575 GdkDevice *device,
8576 GdkWindow *window)
8577 {
8578 GdkPointerWindowInfo *device_info;
8579
8580 device_info = _gdk_display_get_pointer_info (display, device);
8581
8582 if (device_info->window_under_pointer)
8583 g_object_unref (device_info->window_under_pointer);
8584 device_info->window_under_pointer = window;
8585
8586 if (window)
8587 {
8588 g_object_ref (window);
8589 update_cursor (display, device);
8590 }
8591
8592 _gdk_display_enable_motion_hints (display, device);
8593 }
8594
8595 /**
8596 * gdk_pointer_grab:
8597 * @window: the #GdkWindow which will own the grab (the grab window).
8598 * @owner_events: if %FALSE then all pointer events are reported with respect to
8599 * @window and are only reported if selected by @event_mask. If %TRUE then pointer
8600 * events for this application are reported as normal, but pointer events outside
8601 * this application are reported with respect to @window and only if selected by
8602 * @event_mask. In either mode, unreported events are discarded.
8603 * @event_mask: specifies the event mask, which is used in accordance with
8604 * @owner_events. Note that only pointer events (i.e. button and motion events)
8605 * may be selected.
8606 * @confine_to: (allow-none): If non-%NULL, the pointer will be confined to this
8607 * window during the grab. If the pointer is outside @confine_to, it will
8608 * automatically be moved to the closest edge of @confine_to and enter
8609 * and leave events will be generated as necessary.
8610 * @cursor: (allow-none): the cursor to display while the grab is active. If this is %NULL then
8611 * the normal cursors are used for @window and its descendants, and the cursor
8612 * for @window is used for all other windows.
8613 * @time_: the timestamp of the event which led to this pointer grab. This usually
8614 * comes from a #GdkEventButton struct, though %GDK_CURRENT_TIME can be used if
8615 * the time isn’t known.
8616 *
8617 * Grabs the pointer (usually a mouse) so that all events are passed to this
8618 * application until the pointer is ungrabbed with gdk_pointer_ungrab(), or
8619 * the grab window becomes unviewable.
8620 * This overrides any previous pointer grab by this client.
8621 *
8622 * Pointer grabs are used for operations which need complete control over mouse
8623 * events, even if the mouse leaves the application.
8624 * For example in GTK+ it is used for Drag and Drop, for dragging the handle in
8625 * the #GtkHPaned and #GtkVPaned widgets.
8626 *
8627 * Note that if the event mask of an X window has selected both button press and
8628 * button release events, then a button press event will cause an automatic
8629 * pointer grab until the button is released.
8630 * X does this automatically since most applications expect to receive button
8631 * press and release events in pairs.
8632 * It is equivalent to a pointer grab on the window with @owner_events set to
8633 * %TRUE.
8634 *
8635 * If you set up anything at the time you take the grab that needs to be cleaned
8636 * up when the grab ends, you should handle the #GdkEventGrabBroken events that
8637 * are emitted when the grab ends unvoluntarily.
8638 *
8639 * Returns: %GDK_GRAB_SUCCESS if the grab was successful.
8640 *
8641 * Deprecated: 3.0: Use gdk_device_grab() instead.
8642 **/
8643 GdkGrabStatus
gdk_pointer_grab(GdkWindow * window,gboolean owner_events,GdkEventMask event_mask,GdkWindow * confine_to,GdkCursor * cursor,guint32 time)8644 gdk_pointer_grab (GdkWindow * window,
8645 gboolean owner_events,
8646 GdkEventMask event_mask,
8647 GdkWindow * confine_to,
8648 GdkCursor * cursor,
8649 guint32 time)
8650 {
8651 GdkWindow *native;
8652 GdkDisplay *display;
8653 GdkDevice *device;
8654 GdkGrabStatus res = 0;
8655 gulong serial;
8656 GList *seats, *s;
8657
8658 g_return_val_if_fail (window != NULL, GDK_GRAB_FAILED);
8659 g_return_val_if_fail (GDK_IS_WINDOW (window), GDK_GRAB_FAILED);
8660 g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), GDK_GRAB_FAILED);
8661
8662 /* We need a native window for confine to to work, ensure we have one */
8663 if (confine_to)
8664 {
8665 if (!gdk_window_ensure_native (confine_to))
8666 {
8667 g_warning ("Can't confine to grabbed window, not native");
8668 confine_to = NULL;
8669 }
8670 }
8671
8672 /* Non-viewable client side window => fail */
8673 if (!_gdk_window_has_impl (window) &&
8674 !gdk_window_is_viewable (window))
8675 return GDK_GRAB_NOT_VIEWABLE;
8676
8677 native = gdk_window_get_toplevel (window);
8678 while (gdk_window_is_offscreen (native))
8679 {
8680 native = gdk_offscreen_window_get_embedder (native);
8681
8682 if (native == NULL ||
8683 (!_gdk_window_has_impl (native) &&
8684 !gdk_window_is_viewable (native)))
8685 return GDK_GRAB_NOT_VIEWABLE;
8686
8687 native = gdk_window_get_toplevel (native);
8688 }
8689
8690 display = gdk_window_get_display (window);
8691
8692 serial = _gdk_display_get_next_serial (display);
8693 seats = gdk_display_list_seats (display);
8694
8695 for (s = seats; s; s = s->next)
8696 {
8697 device = gdk_seat_get_pointer (s->data);
8698
8699 res = GDK_DEVICE_GET_CLASS (device)->grab (device,
8700 native,
8701 owner_events,
8702 get_native_grab_event_mask (event_mask),
8703 confine_to,
8704 cursor,
8705 time);
8706
8707 if (res == GDK_GRAB_SUCCESS)
8708 _gdk_display_add_device_grab (display,
8709 device,
8710 window,
8711 native,
8712 GDK_OWNERSHIP_NONE,
8713 owner_events,
8714 event_mask,
8715 serial,
8716 time,
8717 FALSE);
8718 }
8719
8720 /* FIXME: handle errors when grabbing */
8721
8722 g_list_free (seats);
8723
8724 return res;
8725 }
8726
8727 /**
8728 * gdk_keyboard_grab:
8729 * @window: the #GdkWindow which will own the grab (the grab window).
8730 * @owner_events: if %FALSE then all keyboard events are reported with respect to
8731 * @window. If %TRUE then keyboard events for this application are
8732 * reported as normal, but keyboard events outside this application
8733 * are reported with respect to @window. Both key press and key
8734 * release events are always reported, independant of the event mask
8735 * set by the application.
8736 * @time_: a timestamp from a #GdkEvent, or %GDK_CURRENT_TIME if no timestamp is
8737 * available.
8738 *
8739 * Grabs the keyboard so that all events are passed to this
8740 * application until the keyboard is ungrabbed with gdk_keyboard_ungrab().
8741 * This overrides any previous keyboard grab by this client.
8742 *
8743 * If you set up anything at the time you take the grab that needs to be cleaned
8744 * up when the grab ends, you should handle the #GdkEventGrabBroken events that
8745 * are emitted when the grab ends unvoluntarily.
8746 *
8747 * Returns: %GDK_GRAB_SUCCESS if the grab was successful.
8748 *
8749 * Deprecated: 3.0: Use gdk_device_grab() instead.
8750 **/
8751 GdkGrabStatus
gdk_keyboard_grab(GdkWindow * window,gboolean owner_events,guint32 time)8752 gdk_keyboard_grab (GdkWindow *window,
8753 gboolean owner_events,
8754 guint32 time)
8755 {
8756 GdkWindow *native;
8757 GdkDisplay *display;
8758 GdkDevice *device;
8759 GdkGrabStatus res = 0;
8760 gulong serial;
8761 GList *seats, *s;
8762
8763 g_return_val_if_fail (GDK_IS_WINDOW (window), GDK_GRAB_FAILED);
8764
8765 /* Non-viewable client side window => fail */
8766 if (!_gdk_window_has_impl (window) &&
8767 !gdk_window_is_viewable (window))
8768 return GDK_GRAB_NOT_VIEWABLE;
8769
8770 native = gdk_window_get_toplevel (window);
8771
8772 while (gdk_window_is_offscreen (native))
8773 {
8774 native = gdk_offscreen_window_get_embedder (native);
8775
8776 if (native == NULL ||
8777 (!_gdk_window_has_impl (native) &&
8778 !gdk_window_is_viewable (native)))
8779 return GDK_GRAB_NOT_VIEWABLE;
8780
8781 native = gdk_window_get_toplevel (native);
8782 }
8783
8784 display = gdk_window_get_display (window);
8785 serial = _gdk_display_get_next_serial (display);
8786 seats = gdk_display_list_seats (display);
8787
8788 for (s = seats; s; s = s->next)
8789 {
8790 device = gdk_seat_get_keyboard (s->data);
8791
8792 res = GDK_DEVICE_GET_CLASS (device)->grab (device,
8793 native,
8794 owner_events,
8795 GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
8796 NULL,
8797 NULL,
8798 time);
8799
8800 if (res == GDK_GRAB_SUCCESS)
8801 _gdk_display_add_device_grab (display,
8802 device,
8803 window,
8804 native,
8805 GDK_OWNERSHIP_NONE,
8806 owner_events, 0,
8807 serial,
8808 time,
8809 FALSE);
8810 }
8811
8812 /* FIXME: handle errors when grabbing */
8813
8814 g_list_free (seats);
8815
8816 return res;
8817 }
8818
8819 /**
8820 * gdk_window_geometry_changed:
8821 * @window: an embedded offscreen #GdkWindow
8822 *
8823 * This function informs GDK that the geometry of an embedded
8824 * offscreen window has changed. This is necessary for GDK to keep
8825 * track of which offscreen window the pointer is in.
8826 *
8827 * Since: 2.18
8828 */
8829 void
gdk_window_geometry_changed(GdkWindow * window)8830 gdk_window_geometry_changed (GdkWindow *window)
8831 {
8832 _gdk_synthesize_crossing_events_for_geometry_change (window);
8833 }
8834
8835 static void
source_events_device_added(GdkDeviceManager * device_manager,GdkDevice * device,gpointer user_data)8836 source_events_device_added (GdkDeviceManager *device_manager,
8837 GdkDevice *device,
8838 gpointer user_data)
8839 {
8840 GdkWindow *window;
8841 GdkEventMask event_mask;
8842 GdkInputSource source;
8843
8844 if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_FLOATING)
8845 return;
8846
8847 window = user_data;
8848 source = gdk_device_get_source (device);
8849
8850 event_mask = GPOINTER_TO_INT (g_hash_table_lookup (window->source_event_masks,
8851 GINT_TO_POINTER (source)));
8852 if (event_mask)
8853 gdk_window_set_device_events (window, device, event_mask);
8854 }
8855
8856 static void
source_events_device_changed(GdkDeviceManager * device_manager,GdkDevice * device,gpointer user_data)8857 source_events_device_changed (GdkDeviceManager *device_manager,
8858 GdkDevice *device,
8859 gpointer user_data)
8860 {
8861 GdkDeviceType type;
8862 GdkInputSource source;
8863 GdkEventMask event_mask;
8864 GdkWindow *window;
8865
8866 window = user_data;
8867 type = gdk_device_get_device_type (device);
8868 source = gdk_device_get_source (device);
8869
8870 event_mask = GPOINTER_TO_INT (g_hash_table_lookup (window->source_event_masks,
8871 GINT_TO_POINTER (source)));
8872
8873 if (!event_mask)
8874 return;
8875
8876 if (type == GDK_DEVICE_TYPE_FLOATING)
8877 {
8878 /* The device was just floated, enable its event mask */
8879 gdk_window_set_device_events (window, device, event_mask);
8880 }
8881 else if (type == GDK_DEVICE_TYPE_SLAVE)
8882 gdk_window_set_device_events (window, device, 0);
8883 }
8884
8885 /**
8886 * gdk_window_set_source_events:
8887 * @window: a #GdkWindow
8888 * @source: a #GdkInputSource to define the source class.
8889 * @event_mask: event mask for @window
8890 *
8891 * Sets the event mask for any floating device (i.e. not attached to any
8892 * visible pointer) that has the source defined as @source. This event
8893 * mask will be applied both to currently existing, newly added devices
8894 * after this call, and devices being attached/detached.
8895 *
8896 * Since: 3.0
8897 **/
8898 void
gdk_window_set_source_events(GdkWindow * window,GdkInputSource source,GdkEventMask event_mask)8899 gdk_window_set_source_events (GdkWindow *window,
8900 GdkInputSource source,
8901 GdkEventMask event_mask)
8902 {
8903 GdkDeviceManager *device_manager;
8904 GdkDisplay *display;
8905 GList *devices, *d;
8906 guint size;
8907
8908 g_return_if_fail (GDK_IS_WINDOW (window));
8909
8910 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
8911 display = gdk_window_get_display (window);
8912 device_manager = gdk_display_get_device_manager (display);
8913
8914 devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING);
8915
8916 /* Set event mask for existing devices */
8917 for (d = devices; d; d = d->next)
8918 {
8919 GdkDevice *device = d->data;
8920
8921 if (source == gdk_device_get_source (device))
8922 gdk_window_set_device_events (window, device, event_mask);
8923 }
8924
8925 g_list_free (devices);
8926 G_GNUC_END_IGNORE_DEPRECATIONS;
8927
8928 /* Update accounting */
8929 if (G_UNLIKELY (!window->source_event_masks))
8930 window->source_event_masks = g_hash_table_new (NULL, NULL);
8931
8932 if (event_mask)
8933 g_hash_table_insert (window->source_event_masks,
8934 GUINT_TO_POINTER (source),
8935 GUINT_TO_POINTER (event_mask));
8936 else
8937 g_hash_table_remove (window->source_event_masks,
8938 GUINT_TO_POINTER (source));
8939
8940 size = g_hash_table_size (window->source_event_masks);
8941
8942 /* Update handler if needed */
8943 if (!window->device_added_handler_id && size > 0)
8944 {
8945 window->device_added_handler_id =
8946 g_signal_connect (device_manager, "device-added",
8947 G_CALLBACK (source_events_device_added), window);
8948 window->device_changed_handler_id =
8949 g_signal_connect (device_manager, "device-changed",
8950 G_CALLBACK (source_events_device_changed), window);
8951 }
8952 else if (window->device_added_handler_id && size == 0)
8953 g_signal_handler_disconnect (device_manager, window->device_added_handler_id);
8954 }
8955
8956 /**
8957 * gdk_window_get_source_events:
8958 * @window: a #GdkWindow
8959 * @source: a #GdkInputSource to define the source class.
8960 *
8961 * Returns the event mask for @window corresponding to the device class specified
8962 * by @source.
8963 *
8964 * Returns: source event mask for @window
8965 **/
8966 GdkEventMask
gdk_window_get_source_events(GdkWindow * window,GdkInputSource source)8967 gdk_window_get_source_events (GdkWindow *window,
8968 GdkInputSource source)
8969 {
8970 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
8971
8972 return GPOINTER_TO_UINT (g_hash_table_lookup (window->source_event_masks,
8973 GUINT_TO_POINTER (source)));
8974 }
8975
8976 static gboolean
do_synthesize_crossing_event(gpointer data)8977 do_synthesize_crossing_event (gpointer data)
8978 {
8979 GdkDisplay *display;
8980 GdkWindow *changed_toplevel;
8981 GHashTableIter iter;
8982 gpointer key, value;
8983 gulong serial;
8984
8985 changed_toplevel = data;
8986
8987 changed_toplevel->synthesized_crossing_event_id = 0;
8988
8989 if (GDK_WINDOW_DESTROYED (changed_toplevel))
8990 return FALSE;
8991
8992 display = gdk_window_get_display (changed_toplevel);
8993 serial = _gdk_display_get_next_serial (display);
8994 g_hash_table_iter_init (&iter, display->pointers_info);
8995
8996 while (g_hash_table_iter_next (&iter, &key, &value))
8997 {
8998 GdkWindow *new_window_under_pointer;
8999 GdkPointerWindowInfo *pointer_info = value;
9000 GdkDevice *device = key;
9001
9002 if (changed_toplevel == pointer_info->toplevel_under_pointer)
9003 {
9004 new_window_under_pointer =
9005 get_pointer_window (display, changed_toplevel,
9006 device,
9007 pointer_info->toplevel_x,
9008 pointer_info->toplevel_y,
9009 serial);
9010 if (new_window_under_pointer != pointer_info->window_under_pointer)
9011 {
9012 GdkDevice *source_device;
9013
9014 if (pointer_info->last_slave)
9015 source_device = pointer_info->last_slave;
9016 else
9017 source_device = device;
9018
9019 _gdk_synthesize_crossing_events (display,
9020 pointer_info->window_under_pointer,
9021 new_window_under_pointer,
9022 device, source_device,
9023 GDK_CROSSING_NORMAL,
9024 pointer_info->toplevel_x,
9025 pointer_info->toplevel_y,
9026 pointer_info->state,
9027 GDK_CURRENT_TIME,
9028 NULL,
9029 serial,
9030 FALSE);
9031 _gdk_display_set_window_under_pointer (display, device, new_window_under_pointer);
9032 }
9033 }
9034 }
9035
9036 return FALSE;
9037 }
9038
9039 void
_gdk_synthesize_crossing_events_for_geometry_change(GdkWindow * changed_window)9040 _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
9041 {
9042 GdkWindow *toplevel;
9043
9044 toplevel = get_event_toplevel (changed_window);
9045
9046 if (toplevel->synthesized_crossing_event_id == 0)
9047 {
9048 toplevel->synthesized_crossing_event_id =
9049 gdk_threads_add_idle_full (GDK_PRIORITY_EVENTS - 1,
9050 do_synthesize_crossing_event,
9051 toplevel, NULL);
9052 g_source_set_name_by_id (toplevel->synthesized_crossing_event_id,
9053 "[gtk+] do_synthesize_crossing_event");
9054 }
9055 }
9056
9057 /* Don't use for crossing events */
9058 static GdkWindow *
get_event_window(GdkDisplay * display,GdkDevice * device,GdkEventSequence * sequence,GdkWindow * pointer_window,GdkEventType type,GdkModifierType mask,guint * evmask_out,gboolean pointer_emulated,gulong serial)9059 get_event_window (GdkDisplay *display,
9060 GdkDevice *device,
9061 GdkEventSequence *sequence,
9062 GdkWindow *pointer_window,
9063 GdkEventType type,
9064 GdkModifierType mask,
9065 guint *evmask_out,
9066 gboolean pointer_emulated,
9067 gulong serial)
9068 {
9069 guint evmask, emulated_mask = 0;
9070 GdkWindow *grab_window;
9071 GdkDeviceGrabInfo *grab;
9072 GdkTouchGrabInfo *touch_grab;
9073
9074 touch_grab = _gdk_display_has_touch_grab (display, device, sequence, serial);
9075 grab = _gdk_display_get_last_device_grab (display, device);
9076
9077 /* Default value. */
9078 if (evmask_out)
9079 *evmask_out = 0;
9080
9081 if (is_touch_type (type) && pointer_emulated)
9082 {
9083 switch (type)
9084 {
9085 case GDK_TOUCH_BEGIN:
9086 emulated_mask |= GDK_BUTTON_PRESS_MASK;
9087 break;
9088 case GDK_TOUCH_UPDATE:
9089 emulated_mask |= GDK_POINTER_MOTION_MASK;
9090 break;
9091 case GDK_TOUCH_END:
9092 emulated_mask |= GDK_BUTTON_RELEASE_MASK;
9093 default:
9094 break;
9095 }
9096 }
9097
9098 if (touch_grab != NULL &&
9099 (!grab || grab->implicit || touch_grab->serial >= grab->serial_start))
9100 {
9101 evmask = touch_grab->event_mask;
9102 evmask = update_evmask_for_button_motion (evmask, mask);
9103
9104 if (evmask & (type_masks[type] | emulated_mask))
9105 {
9106 if (evmask_out)
9107 *evmask_out = evmask;
9108 return touch_grab->window;
9109 }
9110 else
9111 return NULL;
9112 }
9113
9114 if (grab != NULL && !grab->owner_events)
9115 {
9116 evmask = grab->event_mask;
9117 evmask = update_evmask_for_button_motion (evmask, mask);
9118
9119 grab_window = grab->window;
9120
9121 if (evmask & (type_masks[type] | emulated_mask))
9122 {
9123 if (evmask_out)
9124 *evmask_out = evmask;
9125 return grab_window;
9126 }
9127 else
9128 return NULL;
9129 }
9130
9131 while (pointer_window != NULL)
9132 {
9133 evmask = pointer_window->event_mask;
9134 evmask = update_evmask_for_button_motion (evmask, mask);
9135
9136 if (evmask & (type_masks[type] | emulated_mask))
9137 {
9138 if (evmask_out)
9139 *evmask_out = evmask;
9140 return pointer_window;
9141 }
9142
9143 pointer_window = get_event_parent (pointer_window);
9144 }
9145
9146 if (grab != NULL &&
9147 grab->owner_events)
9148 {
9149 evmask = grab->event_mask;
9150 evmask = update_evmask_for_button_motion (evmask, mask);
9151
9152 if (evmask & (type_masks[type] | emulated_mask))
9153 {
9154 if (evmask_out)
9155 *evmask_out = evmask;
9156 return grab->window;
9157 }
9158 else
9159 return NULL;
9160 }
9161
9162 return NULL;
9163 }
9164
9165 static gboolean
proxy_pointer_event(GdkDisplay * display,GdkEvent * source_event,gulong serial)9166 proxy_pointer_event (GdkDisplay *display,
9167 GdkEvent *source_event,
9168 gulong serial)
9169 {
9170 GdkWindow *toplevel_window, *event_window;
9171 GdkWindow *pointer_window;
9172 GdkPointerWindowInfo *pointer_info;
9173 GdkDevice *device, *source_device;
9174 GdkEvent *event;
9175 guint state;
9176 gdouble toplevel_x, toplevel_y;
9177 guint32 time_;
9178 gboolean non_linear, need_synthetic_enter = FALSE;
9179 gint event_type;
9180
9181 event_type = source_event->type;
9182 event_window = source_event->any.window;
9183 gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
9184 gdk_event_get_state (source_event, &state);
9185 time_ = gdk_event_get_time (source_event);
9186 device = gdk_event_get_device (source_event);
9187 source_device = gdk_event_get_source_device (source_event);
9188 pointer_info = _gdk_display_get_pointer_info (display, device);
9189 toplevel_window = convert_native_coords_to_toplevel (event_window,
9190 toplevel_x, toplevel_y,
9191 &toplevel_x, &toplevel_y);
9192
9193 non_linear = FALSE;
9194 if ((source_event->type == GDK_LEAVE_NOTIFY ||
9195 source_event->type == GDK_ENTER_NOTIFY) &&
9196 (source_event->crossing.detail == GDK_NOTIFY_NONLINEAR ||
9197 source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))
9198 non_linear = TRUE;
9199
9200 if (pointer_info->need_touch_press_enter &&
9201 gdk_device_get_source (pointer_info->last_slave) != GDK_SOURCE_TOUCHSCREEN &&
9202 (source_event->type != GDK_TOUCH_UPDATE ||
9203 gdk_event_get_pointer_emulated (source_event)))
9204 {
9205 pointer_info->need_touch_press_enter = FALSE;
9206 need_synthetic_enter = TRUE;
9207 }
9208
9209 /* If we get crossing events with subwindow unexpectedly being NULL
9210 that means there is a native subwindow that gdk doesn't know about.
9211 We track these and forward them, with the correct virtual window
9212 events inbetween.
9213 This is important to get right, as metacity uses gdk for the frame
9214 windows, but gdk doesn't know about the client windows reparented
9215 into the frame. */
9216 if (((source_event->type == GDK_LEAVE_NOTIFY &&
9217 source_event->crossing.detail == GDK_NOTIFY_INFERIOR) ||
9218 (source_event->type == GDK_ENTER_NOTIFY &&
9219 (source_event->crossing.detail == GDK_NOTIFY_VIRTUAL ||
9220 source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))) &&
9221 source_event->crossing.subwindow == NULL)
9222 {
9223 /* Left for an unknown (to gdk) subwindow */
9224
9225 /* Send leave events from window under pointer to event window
9226 that will get the subwindow == NULL window */
9227 _gdk_synthesize_crossing_events (display,
9228 pointer_info->window_under_pointer,
9229 event_window,
9230 device, source_device,
9231 source_event->crossing.mode,
9232 toplevel_x, toplevel_y,
9233 state, time_,
9234 source_event,
9235 serial,
9236 non_linear);
9237
9238 /* Send subwindow == NULL event */
9239 send_crossing_event (display,
9240 toplevel_window,
9241 event_window,
9242 source_event->type,
9243 source_event->crossing.mode,
9244 source_event->crossing.detail,
9245 NULL,
9246 device, source_device,
9247 toplevel_x, toplevel_y,
9248 state, time_,
9249 source_event,
9250 serial);
9251
9252 _gdk_display_set_window_under_pointer (display, device, NULL);
9253 return TRUE;
9254 }
9255
9256 pointer_window = get_pointer_window (display, toplevel_window, device,
9257 toplevel_x, toplevel_y, serial);
9258
9259 if (((source_event->type == GDK_ENTER_NOTIFY &&
9260 source_event->crossing.detail == GDK_NOTIFY_INFERIOR) ||
9261 (source_event->type == GDK_LEAVE_NOTIFY &&
9262 (source_event->crossing.detail == GDK_NOTIFY_VIRTUAL ||
9263 source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))) &&
9264 source_event->crossing.subwindow == NULL)
9265 {
9266 /* Entered from an unknown (to gdk) subwindow */
9267
9268 /* Send subwindow == NULL event */
9269 send_crossing_event (display,
9270 toplevel_window,
9271 event_window,
9272 source_event->type,
9273 source_event->crossing.mode,
9274 source_event->crossing.detail,
9275 NULL,
9276 device, source_device,
9277 toplevel_x, toplevel_y,
9278 state, time_,
9279 source_event,
9280 serial);
9281
9282 /* Send enter events from event window to pointer_window */
9283 _gdk_synthesize_crossing_events (display,
9284 event_window,
9285 pointer_window,
9286 device, source_device,
9287 source_event->crossing.mode,
9288 toplevel_x, toplevel_y,
9289 state, time_,
9290 source_event,
9291 serial, non_linear);
9292 _gdk_display_set_window_under_pointer (display, device, pointer_window);
9293 return TRUE;
9294 }
9295
9296 if ((source_event->type != GDK_TOUCH_UPDATE ||
9297 gdk_event_get_pointer_emulated (source_event)) &&
9298 pointer_info->window_under_pointer != pointer_window)
9299 {
9300 /* Either a toplevel crossing notify that ended up inside a child window,
9301 or a motion notify that got into another child window */
9302
9303 /* Different than last time, send crossing events */
9304 _gdk_synthesize_crossing_events (display,
9305 pointer_info->window_under_pointer,
9306 pointer_window,
9307 device, source_device,
9308 GDK_CROSSING_NORMAL,
9309 toplevel_x, toplevel_y,
9310 state, time_,
9311 source_event,
9312 serial, non_linear);
9313 _gdk_display_set_window_under_pointer (display, device, pointer_window);
9314 }
9315
9316 if (source_event->type == GDK_MOTION_NOTIFY ||
9317 source_event->type == GDK_TOUCH_UPDATE)
9318 {
9319 GdkWindow *event_win;
9320 guint evmask;
9321 gboolean is_hint;
9322 GdkEventSequence *sequence;
9323
9324 sequence = gdk_event_get_event_sequence (source_event);
9325
9326 event_win = get_event_window (display,
9327 device,
9328 sequence,
9329 pointer_window,
9330 source_event->type,
9331 state,
9332 &evmask,
9333 gdk_event_get_pointer_emulated (source_event),
9334 serial);
9335
9336 if (event_type == GDK_TOUCH_UPDATE)
9337 {
9338 if (gdk_event_get_pointer_emulated (source_event))
9339 {
9340 /* Touch events emulating pointer events are transformed back
9341 * to pointer events if:
9342 * 1 - The event window doesn't select for touch events
9343 * 2 - There's no touch grab for this sequence, which means
9344 * it was started as a pointer sequence, but a device
9345 * grab added touch events afterwards, the sequence must
9346 * not mutate in this case.
9347 */
9348 if ((evmask & GDK_TOUCH_MASK) == 0 ||
9349 !_gdk_display_has_touch_grab (display, device, sequence, serial))
9350 event_type = GDK_MOTION_NOTIFY;
9351 }
9352 else if ((evmask & GDK_TOUCH_MASK) == 0)
9353 return TRUE;
9354 }
9355
9356 if (is_touch_type (source_event->type) && !is_touch_type (event_type))
9357 state |= GDK_BUTTON1_MASK;
9358
9359 if (event_win &&
9360 gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER &&
9361 gdk_window_get_device_events (event_win, device) == 0)
9362 return TRUE;
9363
9364 /* The last device to interact with the window was a touch device,
9365 * which synthesized a leave notify event, so synthesize another enter
9366 * notify to tell the pointer is on the window.
9367 */
9368 if (need_synthetic_enter)
9369 _gdk_synthesize_crossing_events (display,
9370 NULL, pointer_window,
9371 device, source_device,
9372 GDK_CROSSING_DEVICE_SWITCH,
9373 toplevel_x, toplevel_y,
9374 state, time_, NULL,
9375 serial, FALSE);
9376
9377 is_hint = FALSE;
9378
9379 if (event_win &&
9380 event_type == GDK_MOTION_NOTIFY &&
9381 (evmask & GDK_POINTER_MOTION_HINT_MASK))
9382 {
9383 gulong *device_serial;
9384
9385 device_serial = g_hash_table_lookup (display->motion_hint_info, device);
9386
9387 if (!device_serial ||
9388 (*device_serial != 0 &&
9389 serial < *device_serial))
9390 event_win = NULL; /* Ignore event */
9391 else
9392 {
9393 is_hint = TRUE;
9394 *device_serial = G_MAXULONG;
9395 }
9396 }
9397
9398 if (!event_win)
9399 return TRUE;
9400
9401 event = gdk_event_new (event_type);
9402 event->any.window = g_object_ref (event_win);
9403 event->any.send_event = source_event->any.send_event;
9404
9405 gdk_event_set_device (event, gdk_event_get_device (source_event));
9406 gdk_event_set_source_device (event, source_device);
9407 gdk_event_set_seat (event, gdk_device_get_seat (device));
9408 gdk_event_set_device_tool (event, gdk_event_get_device_tool (source_event));
9409
9410 if (event_type == GDK_TOUCH_UPDATE)
9411 {
9412 event->touch.time = time_;
9413 event->touch.state = state | GDK_BUTTON1_MASK;
9414 event->touch.sequence = source_event->touch.sequence;
9415 event->touch.emulating_pointer = source_event->touch.emulating_pointer;
9416 convert_toplevel_coords_to_window (event_win,
9417 toplevel_x, toplevel_y,
9418 &event->touch.x, &event->touch.y);
9419 gdk_event_get_root_coords (source_event,
9420 &event->touch.x_root,
9421 &event->touch.y_root);
9422
9423 event->touch.axes = g_memdup (source_event->touch.axes,
9424 sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
9425 }
9426 else
9427 {
9428 event->motion.time = time_;
9429 event->motion.state = state;
9430 event->motion.is_hint = is_hint;
9431
9432 convert_toplevel_coords_to_window (event_win,
9433 toplevel_x, toplevel_y,
9434 &event->motion.x, &event->motion.y);
9435 gdk_event_get_root_coords (source_event,
9436 &event->motion.x_root,
9437 &event->motion.y_root);
9438
9439 if (is_touch_type (source_event->type))
9440 event->motion.axes = g_memdup (source_event->touch.axes,
9441 sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
9442 else
9443 event->motion.axes = g_memdup (source_event->motion.axes,
9444 sizeof (gdouble) * gdk_device_get_n_axes (source_event->motion.device));
9445 }
9446
9447 /* Just insert the event */
9448 _gdk_event_queue_insert_after (gdk_window_get_display (event_win),
9449 source_event, event);
9450 }
9451
9452 /* unlink all move events from queue.
9453 We handle our own, including our emulated masks. */
9454 return TRUE;
9455 }
9456
9457 #define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \
9458 GDK_BUTTON2_MASK | \
9459 GDK_BUTTON3_MASK | \
9460 GDK_BUTTON4_MASK | \
9461 GDK_BUTTON5_MASK)
9462
9463 static gboolean
proxy_button_event(GdkEvent * source_event,gulong serial)9464 proxy_button_event (GdkEvent *source_event,
9465 gulong serial)
9466 {
9467 GdkWindow *toplevel_window, *event_window;
9468 GdkWindow *event_win;
9469 GdkWindow *pointer_window;
9470 GdkWindow *parent;
9471 GdkEvent *event;
9472 GdkPointerWindowInfo *pointer_info;
9473 GdkDeviceGrabInfo *pointer_grab;
9474 guint state;
9475 guint32 time_;
9476 GdkEventType type;
9477 gdouble toplevel_x, toplevel_y;
9478 GdkDisplay *display;
9479 GdkWindow *w;
9480 GdkDevice *device, *source_device;
9481 GdkEventMask evmask;
9482 GdkEventSequence *sequence;
9483
9484 type = source_event->any.type;
9485 event_window = source_event->any.window;
9486 gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
9487 gdk_event_get_state (source_event, &state);
9488 time_ = gdk_event_get_time (source_event);
9489 device = gdk_event_get_device (source_event);
9490 source_device = gdk_event_get_source_device (source_event);
9491 display = gdk_window_get_display (source_event->any.window);
9492 toplevel_window = convert_native_coords_to_toplevel (event_window,
9493 toplevel_x, toplevel_y,
9494 &toplevel_x, &toplevel_y);
9495
9496 sequence = gdk_event_get_event_sequence (source_event);
9497
9498 pointer_info = _gdk_display_get_pointer_info (display, device);
9499 pointer_grab = _gdk_display_has_device_grab (display, device, serial);
9500
9501 if ((type == GDK_BUTTON_PRESS ||
9502 type == GDK_TOUCH_BEGIN) &&
9503 !source_event->any.send_event &&
9504 (!pointer_grab ||
9505 (type == GDK_TOUCH_BEGIN && pointer_grab->implicit &&
9506 !gdk_event_get_pointer_emulated (source_event))))
9507 {
9508 pointer_window =
9509 _gdk_window_find_descendant_at (toplevel_window,
9510 toplevel_x, toplevel_y,
9511 NULL, NULL);
9512
9513 /* Find the event window, that gets the grab */
9514 w = pointer_window;
9515 while (w != NULL &&
9516 (parent = get_event_parent (w)) != NULL &&
9517 parent->window_type != GDK_WINDOW_ROOT)
9518 {
9519 if (w->event_mask & GDK_BUTTON_PRESS_MASK &&
9520 (type == GDK_BUTTON_PRESS ||
9521 gdk_event_get_pointer_emulated (source_event)))
9522 break;
9523
9524 if (type == GDK_TOUCH_BEGIN &&
9525 w->event_mask & GDK_TOUCH_MASK)
9526 break;
9527
9528 w = parent;
9529 }
9530 pointer_window = w;
9531
9532 if (pointer_window)
9533 {
9534 if (type == GDK_TOUCH_BEGIN &&
9535 pointer_window->event_mask & GDK_TOUCH_MASK)
9536 {
9537 _gdk_display_add_touch_grab (display, device, sequence,
9538 pointer_window, event_window,
9539 gdk_window_get_events (pointer_window),
9540 serial, time_);
9541 }
9542 else if (type == GDK_BUTTON_PRESS ||
9543 gdk_event_get_pointer_emulated (source_event))
9544 {
9545 _gdk_display_add_device_grab (display,
9546 device,
9547 pointer_window,
9548 event_window,
9549 GDK_OWNERSHIP_NONE,
9550 FALSE,
9551 gdk_window_get_events (pointer_window),
9552 serial,
9553 time_,
9554 TRUE);
9555 _gdk_display_device_grab_update (display, device,
9556 source_device, serial);
9557 }
9558 }
9559 }
9560
9561 pointer_window = get_pointer_window (display, toplevel_window, device,
9562 toplevel_x, toplevel_y,
9563 serial);
9564
9565 event_win = get_event_window (display,
9566 device,
9567 sequence,
9568 pointer_window,
9569 type, state,
9570 &evmask,
9571 gdk_event_get_pointer_emulated (source_event),
9572 serial);
9573
9574 if (type == GDK_TOUCH_BEGIN || type == GDK_TOUCH_END)
9575 {
9576 if (gdk_event_get_pointer_emulated (source_event))
9577 {
9578 if ((evmask & GDK_TOUCH_MASK) == 0 ||
9579 !_gdk_display_has_touch_grab (display, device, sequence, serial))
9580 {
9581 if (type == GDK_TOUCH_BEGIN)
9582 type = GDK_BUTTON_PRESS;
9583 else if (type == GDK_TOUCH_END)
9584 type = GDK_BUTTON_RELEASE;
9585 }
9586 }
9587 else if ((evmask & GDK_TOUCH_MASK) == 0)
9588 return TRUE;
9589 }
9590
9591 if (source_event->type == GDK_TOUCH_END && !is_touch_type (type))
9592 state |= GDK_BUTTON1_MASK;
9593
9594 if (event_win == NULL)
9595 return TRUE;
9596
9597 if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER &&
9598 gdk_window_get_device_events (event_win, device) == 0)
9599 return TRUE;
9600
9601 if ((type == GDK_BUTTON_PRESS ||
9602 (type == GDK_TOUCH_BEGIN &&
9603 gdk_event_get_pointer_emulated (source_event))) &&
9604 pointer_info->need_touch_press_enter)
9605 {
9606 GdkCrossingMode mode;
9607
9608 /* The last device to interact with the window was a touch device,
9609 * which synthesized a leave notify event, so synthesize another enter
9610 * notify to tell the pointer is on the window.
9611 */
9612 if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
9613 mode = GDK_CROSSING_TOUCH_BEGIN;
9614 else
9615 mode = GDK_CROSSING_DEVICE_SWITCH;
9616
9617 pointer_info->need_touch_press_enter = FALSE;
9618 _gdk_synthesize_crossing_events (display,
9619 NULL,
9620 pointer_info->window_under_pointer,
9621 device, source_device, mode,
9622 toplevel_x, toplevel_y,
9623 state, time_, source_event,
9624 serial, FALSE);
9625 }
9626 else if (type == GDK_SCROLL &&
9627 (((evmask & GDK_SMOOTH_SCROLL_MASK) == 0 &&
9628 source_event->scroll.direction == GDK_SCROLL_SMOOTH) ||
9629 ((evmask & GDK_SMOOTH_SCROLL_MASK) != 0 &&
9630 source_event->scroll.direction != GDK_SCROLL_SMOOTH &&
9631 gdk_event_get_pointer_emulated (source_event))))
9632 return FALSE;
9633
9634 event = _gdk_make_event (event_win, type, source_event, FALSE);
9635
9636 switch (type)
9637 {
9638 case GDK_BUTTON_PRESS:
9639 case GDK_BUTTON_RELEASE:
9640 event->button.button = source_event->button.button;
9641 convert_toplevel_coords_to_window (event_win,
9642 toplevel_x, toplevel_y,
9643 &event->button.x, &event->button.y);
9644 gdk_event_get_root_coords (source_event,
9645 &event->button.x_root,
9646 &event->button.y_root);
9647 gdk_event_set_device (event, gdk_event_get_device (source_event));
9648 gdk_event_set_source_device (event, source_device);
9649 gdk_event_set_seat (event, gdk_device_get_seat (device));
9650 gdk_event_set_device_tool (event, gdk_event_get_device_tool (source_event));
9651
9652 if (is_touch_type (source_event->type))
9653 {
9654 if (type == GDK_BUTTON_RELEASE)
9655 event->button.state |= GDK_BUTTON1_MASK;
9656 event->button.button = 1;
9657 event->button.axes = g_memdup (source_event->touch.axes,
9658 sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
9659 }
9660 else
9661 {
9662 event->button.button = source_event->button.button;
9663 event->button.axes = g_memdup (source_event->button.axes,
9664 sizeof (gdouble) * gdk_device_get_n_axes (source_event->button.device));
9665 }
9666
9667 if (type == GDK_BUTTON_PRESS)
9668 _gdk_event_button_generate (display, event);
9669 else if ((type == GDK_BUTTON_RELEASE ||
9670 (type == GDK_TOUCH_END &&
9671 gdk_event_get_pointer_emulated (source_event))) &&
9672 pointer_window == pointer_info->window_under_pointer &&
9673 gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
9674 {
9675 /* Synthesize a leave notify event
9676 * whenever a touch device is released
9677 */
9678 pointer_info->need_touch_press_enter = TRUE;
9679 _gdk_synthesize_crossing_events (display,
9680 pointer_window, NULL,
9681 device, source_device,
9682 GDK_CROSSING_TOUCH_END,
9683 toplevel_x, toplevel_y,
9684 state, time_, NULL,
9685 serial, FALSE);
9686 }
9687 return TRUE;
9688
9689 case GDK_TOUCH_BEGIN:
9690 case GDK_TOUCH_END:
9691 case GDK_TOUCH_CANCEL:
9692 convert_toplevel_coords_to_window (event_win,
9693 toplevel_x, toplevel_y,
9694 &event->button.x, &event->button.y);
9695 gdk_event_get_root_coords (source_event,
9696 &event->touch.x_root,
9697 &event->touch.y_root);
9698 event->touch.state = state;
9699 event->touch.device = source_event->touch.device;
9700 event->touch.axes = g_memdup (source_event->touch.axes,
9701 sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
9702 event->touch.sequence = source_event->touch.sequence;
9703 event->touch.emulating_pointer = source_event->touch.emulating_pointer;
9704
9705 gdk_event_set_source_device (event, source_device);
9706
9707 if (((type == GDK_TOUCH_END || type == GDK_TOUCH_CANCEL) &&
9708 gdk_event_get_pointer_emulated (source_event)) &&
9709 pointer_window == pointer_info->window_under_pointer &&
9710 gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
9711 {
9712 /* Synthesize a leave notify event
9713 * whenever a touch device is released
9714 */
9715 pointer_info->need_touch_press_enter = TRUE;
9716 _gdk_synthesize_crossing_events (display,
9717 pointer_window, NULL,
9718 device, source_device,
9719 GDK_CROSSING_TOUCH_END,
9720 toplevel_x, toplevel_y,
9721 state, time_, NULL,
9722 serial, FALSE);
9723 }
9724 return TRUE;
9725
9726 case GDK_SCROLL:
9727 event->scroll.direction = source_event->scroll.direction;
9728 convert_toplevel_coords_to_window (event_win,
9729 toplevel_x, toplevel_y,
9730 &event->scroll.x, &event->scroll.y);
9731 event->scroll.x_root = source_event->scroll.x_root;
9732 event->scroll.y_root = source_event->scroll.y_root;
9733 event->scroll.state = state;
9734 event->scroll.device = source_event->scroll.device;
9735 event->scroll.delta_x = source_event->scroll.delta_x;
9736 event->scroll.delta_y = source_event->scroll.delta_y;
9737 event->scroll.is_stop = source_event->scroll.is_stop;
9738 gdk_event_set_source_device (event, source_device);
9739 return TRUE;
9740
9741 default:
9742 return FALSE;
9743 }
9744
9745 return TRUE; /* Always unlink original, we want to obey the emulated event mask */
9746 }
9747
9748 static gboolean
proxy_gesture_event(GdkEvent * source_event,gulong serial)9749 proxy_gesture_event (GdkEvent *source_event,
9750 gulong serial)
9751 {
9752 GdkWindow *toplevel_window, *pointer_window, *event_win;
9753 GdkDevice *device, *source_device;
9754 gdouble toplevel_x, toplevel_y;
9755 GdkDisplay *display;
9756 GdkEventMask evmask;
9757 GdkEventType evtype;
9758 GdkEvent *event;
9759 guint state;
9760
9761 evtype = source_event->any.type;
9762 gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
9763 gdk_event_get_state (source_event, &state);
9764 device = gdk_event_get_device (source_event);
9765 source_device = gdk_event_get_source_device (source_event);
9766 display = gdk_window_get_display (source_event->any.window);
9767 toplevel_window = convert_native_coords_to_toplevel (source_event->any.window,
9768 toplevel_x, toplevel_y,
9769 &toplevel_x, &toplevel_y);
9770
9771 pointer_window = get_pointer_window (display, toplevel_window, device,
9772 toplevel_x, toplevel_y,
9773 serial);
9774
9775 event_win = get_event_window (display, device, NULL,
9776 pointer_window, evtype, state,
9777 &evmask, FALSE, serial);
9778 if (!event_win)
9779 return TRUE;
9780
9781 if ((evmask & GDK_TOUCHPAD_GESTURE_MASK) == 0)
9782 return TRUE;
9783
9784 event = _gdk_make_event (event_win, evtype, source_event, FALSE);
9785 gdk_event_set_device (event, device);
9786 gdk_event_set_source_device (event, source_device);
9787 gdk_event_set_seat (event, gdk_device_get_seat (device));
9788
9789 switch (evtype)
9790 {
9791 case GDK_TOUCHPAD_SWIPE:
9792 convert_toplevel_coords_to_window (event_win,
9793 toplevel_x, toplevel_y,
9794 &event->touchpad_swipe.x,
9795 &event->touchpad_swipe.y);
9796 gdk_event_get_root_coords (source_event,
9797 &event->touchpad_swipe.x_root,
9798 &event->touchpad_swipe.y_root);
9799 event->touchpad_swipe.dx = source_event->touchpad_swipe.dx;
9800 event->touchpad_swipe.dy = source_event->touchpad_swipe.dy;
9801 event->touchpad_swipe.n_fingers = source_event->touchpad_swipe.n_fingers;
9802 event->touchpad_swipe.phase = source_event->touchpad_swipe.phase;
9803 break;
9804
9805 case GDK_TOUCHPAD_PINCH:
9806 convert_toplevel_coords_to_window (event_win,
9807 toplevel_x, toplevel_y,
9808 &event->touchpad_pinch.x,
9809 &event->touchpad_pinch.y);
9810 gdk_event_get_root_coords (source_event,
9811 &event->touchpad_pinch.x_root,
9812 &event->touchpad_pinch.y_root);
9813 event->touchpad_pinch.dx = source_event->touchpad_pinch.dx;
9814 event->touchpad_pinch.dy = source_event->touchpad_pinch.dy;
9815 event->touchpad_pinch.scale = source_event->touchpad_pinch.scale;
9816 event->touchpad_pinch.angle_delta = source_event->touchpad_pinch.angle_delta;
9817 event->touchpad_pinch.n_fingers = source_event->touchpad_pinch.n_fingers;
9818 event->touchpad_pinch.phase = source_event->touchpad_pinch.phase;
9819 break;
9820
9821 default:
9822 break;
9823 }
9824
9825 return TRUE;
9826 }
9827
9828 #ifdef DEBUG_WINDOW_PRINTING
9829
9830 #ifdef GDK_WINDOWING_X11
9831 #include "x11/gdkx.h"
9832 #endif
9833
9834 static void
gdk_window_print(GdkWindow * window,int indent)9835 gdk_window_print (GdkWindow *window,
9836 int indent)
9837 {
9838 char *s;
9839 const char *window_types[] = {
9840 "root",
9841 "toplevel",
9842 "child",
9843 "dialog",
9844 "temp",
9845 "foreign",
9846 "offscreen"
9847 };
9848
9849 g_print ("%*s%p: [%s] %d,%d %dx%d", indent, "", window,
9850 window->user_data ? g_type_name_from_instance (window->user_data) : "no widget",
9851 window->x, window->y,
9852 window->width, window->height
9853 );
9854
9855 if (gdk_window_has_impl (window))
9856 {
9857 #ifdef GDK_WINDOWING_X11
9858 g_print (" impl(0x%lx)", gdk_x11_window_get_xid (window));
9859 #endif
9860 }
9861
9862 if (window->window_type != GDK_WINDOW_CHILD)
9863 g_print (" %s", window_types[window->window_type]);
9864
9865 if (window->input_only)
9866 g_print (" input-only");
9867
9868 if (window->shaped)
9869 g_print (" shaped");
9870
9871 if (!gdk_window_is_visible ((GdkWindow *)window))
9872 g_print (" hidden");
9873
9874 g_print (" abs[%d,%d]",
9875 window->abs_x, window->abs_y);
9876
9877 if (window->alpha != 255)
9878 g_print (" alpha[%d]",
9879 window->alpha);
9880
9881 s = print_region (window->clip_region);
9882 g_print (" clipbox[%s]", s);
9883
9884 g_print ("\n");
9885 }
9886
9887
9888 static void
gdk_window_print_tree(GdkWindow * window,int indent,gboolean include_input_only)9889 gdk_window_print_tree (GdkWindow *window,
9890 int indent,
9891 gboolean include_input_only)
9892 {
9893 GList *l;
9894
9895 if (window->input_only && !include_input_only)
9896 return;
9897
9898 gdk_window_print (window, indent);
9899
9900 for (l = window->children; l != NULL; l = l->next)
9901 gdk_window_print_tree (l->data, indent + 4, include_input_only);
9902 }
9903
9904 #endif /* DEBUG_WINDOW_PRINTING */
9905
9906 void
_gdk_windowing_got_event(GdkDisplay * display,GList * event_link,GdkEvent * event,gulong serial)9907 _gdk_windowing_got_event (GdkDisplay *display,
9908 GList *event_link,
9909 GdkEvent *event,
9910 gulong serial)
9911 {
9912 GdkWindow *event_window;
9913 gdouble x, y;
9914 gboolean unlink_event = FALSE;
9915 GdkDeviceGrabInfo *button_release_grab;
9916 GdkPointerWindowInfo *pointer_info = NULL;
9917 GdkDevice *device, *source_device;
9918 gboolean is_toplevel;
9919
9920 _gdk_display_update_last_event (display, event);
9921
9922 device = gdk_event_get_device (event);
9923 source_device = gdk_event_get_source_device (event);
9924
9925 if (device)
9926 {
9927 if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD &&
9928 gdk_device_get_source (device) != GDK_SOURCE_TABLET_PAD)
9929 {
9930 pointer_info = _gdk_display_get_pointer_info (display, device);
9931
9932 if (source_device != pointer_info->last_slave &&
9933 gdk_device_get_device_type (source_device) == GDK_DEVICE_TYPE_SLAVE)
9934 g_set_object (&pointer_info->last_slave, source_device);
9935 else if (pointer_info->last_slave)
9936 source_device = pointer_info->last_slave;
9937 }
9938
9939 _gdk_display_device_grab_update (display, device, source_device, serial);
9940
9941 if (gdk_device_get_input_mode (device) == GDK_MODE_DISABLED ||
9942 !_gdk_display_check_grab_ownership (display, device, serial))
9943 {
9944 /* Device events are blocked by another
9945 * device grab, or the device is disabled
9946 */
9947 unlink_event = TRUE;
9948 goto out;
9949 }
9950 }
9951
9952 event_window = event->any.window;
9953 if (!event_window)
9954 goto out;
9955
9956 #ifdef DEBUG_WINDOW_PRINTING
9957 if (event->type == GDK_KEY_PRESS &&
9958 (event->key.keyval == 0xa7 ||
9959 event->key.keyval == 0xbd))
9960 {
9961 gdk_window_print_tree (event_window, 0, event->key.keyval == 0xbd);
9962 }
9963 #endif
9964
9965 if (event->type == GDK_VISIBILITY_NOTIFY)
9966 {
9967 event_window->native_visibility = event->visibility.state;
9968 gdk_window_update_visibility_recursively (event_window, event_window);
9969 goto out;
9970 }
9971
9972 if (!(event->type == GDK_TOUCH_CANCEL ||
9973 is_button_type (event->type) ||
9974 is_motion_type (event->type) ||
9975 is_gesture_type (event->type)) ||
9976 event_window->window_type == GDK_WINDOW_ROOT)
9977 goto out;
9978
9979 is_toplevel = gdk_window_is_toplevel (event_window);
9980
9981 if ((event->type == GDK_ENTER_NOTIFY ||
9982 event->type == GDK_LEAVE_NOTIFY) &&
9983 (event->crossing.mode == GDK_CROSSING_GRAB ||
9984 event->crossing.mode == GDK_CROSSING_UNGRAB) &&
9985 (_gdk_display_has_device_grab (display, device, serial) ||
9986 event->crossing.detail == GDK_NOTIFY_INFERIOR))
9987 {
9988 /* We synthesize all crossing events due to grabs ourselves,
9989 * so we ignore the native ones caused by our native pointer_grab
9990 * calls. Otherwise we would proxy these crossing event and cause
9991 * multiple copies of crossing events for grabs.
9992 *
9993 * We do want to handle grabs from other clients though, as for
9994 * instance alt-tab in metacity causes grabs like these and
9995 * we want to handle those. Thus the has_pointer_grab check.
9996 *
9997 * Implicit grabs on child windows create some grabbing events
9998 * that are sent before the button press. This means we can't
9999 * detect these with the has_pointer_grab check (as the implicit
10000 * grab is only noticed when we get button press event), so we
10001 * detect these events by checking for INFERIOR enter or leave
10002 * events. These should never be a problem to filter out.
10003 */
10004
10005 /* We ended up in this window after some (perhaps other clients)
10006 * grab, so update the toplevel_under_window state
10007 */
10008 if (pointer_info && is_toplevel &&
10009 event->type == GDK_ENTER_NOTIFY &&
10010 event->crossing.mode == GDK_CROSSING_UNGRAB)
10011 {
10012 if (pointer_info->toplevel_under_pointer)
10013 g_object_unref (pointer_info->toplevel_under_pointer);
10014 pointer_info->toplevel_under_pointer = g_object_ref (event_window);
10015 }
10016
10017 unlink_event = TRUE;
10018 goto out;
10019 }
10020
10021 /* Track toplevel_under_pointer */
10022 if (pointer_info && is_toplevel)
10023 {
10024 if (event->type == GDK_ENTER_NOTIFY &&
10025 event->crossing.detail != GDK_NOTIFY_INFERIOR)
10026 {
10027 if (pointer_info->toplevel_under_pointer)
10028 g_object_unref (pointer_info->toplevel_under_pointer);
10029 pointer_info->toplevel_under_pointer = g_object_ref (event_window);
10030 }
10031 else if (event->type == GDK_LEAVE_NOTIFY &&
10032 event->crossing.detail != GDK_NOTIFY_INFERIOR &&
10033 pointer_info->toplevel_under_pointer == event_window)
10034 {
10035 if (pointer_info->toplevel_under_pointer)
10036 g_object_unref (pointer_info->toplevel_under_pointer);
10037 pointer_info->toplevel_under_pointer = NULL;
10038 }
10039 }
10040
10041 if (pointer_info &&
10042 (!is_touch_type (event->type) ||
10043 gdk_event_get_pointer_emulated (event)))
10044 {
10045 guint old_state, old_button;
10046
10047 /* Store last pointer window and position/state */
10048 old_state = pointer_info->state;
10049 old_button = pointer_info->button;
10050
10051 gdk_event_get_coords (event, &x, &y);
10052 convert_native_coords_to_toplevel (event_window, x, y, &x, &y);
10053 pointer_info->toplevel_x = x;
10054 pointer_info->toplevel_y = y;
10055 gdk_event_get_state (event, &pointer_info->state);
10056
10057 if (event->type == GDK_BUTTON_PRESS ||
10058 event->type == GDK_BUTTON_RELEASE)
10059 pointer_info->button = event->button.button;
10060 else if (event->type == GDK_TOUCH_BEGIN ||
10061 event->type == GDK_TOUCH_END)
10062 pointer_info->button = 1;
10063
10064 if (device &&
10065 (pointer_info->state != old_state ||
10066 pointer_info->button != old_button))
10067 _gdk_display_enable_motion_hints (display, device);
10068 }
10069
10070 if (is_motion_type (event->type))
10071 unlink_event = proxy_pointer_event (display, event, serial);
10072 else if (is_button_type (event->type))
10073 unlink_event = proxy_button_event (event, serial);
10074 else if (is_gesture_type (event->type))
10075 unlink_event = proxy_gesture_event (event, serial);
10076
10077 if ((event->type == GDK_BUTTON_RELEASE ||
10078 event->type == GDK_TOUCH_CANCEL ||
10079 event->type == GDK_TOUCH_END) &&
10080 !event->any.send_event)
10081 {
10082 GdkEventSequence *sequence;
10083
10084 sequence = gdk_event_get_event_sequence (event);
10085 if (sequence)
10086 {
10087 _gdk_display_end_touch_grab (display, device, sequence);
10088 }
10089
10090 if (event->type == GDK_BUTTON_RELEASE ||
10091 gdk_event_get_pointer_emulated (event))
10092 {
10093 button_release_grab =
10094 _gdk_display_has_device_grab (display, device, serial);
10095
10096 if (button_release_grab &&
10097 button_release_grab->implicit &&
10098 (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
10099 {
10100 button_release_grab->serial_end = serial;
10101 button_release_grab->implicit_ungrab = FALSE;
10102 _gdk_display_device_grab_update (display, device, source_device, serial);
10103 }
10104 }
10105 }
10106
10107 out:
10108 if (unlink_event)
10109 {
10110 _gdk_event_queue_remove_link (display, event_link);
10111 g_list_free_1 (event_link);
10112 gdk_event_free (event);
10113 }
10114
10115 /* This does two things - first it sees if there are motions at the
10116 * end of the queue that can be compressed. Second, if there is just
10117 * a single motion that won't be dispatched because it is a compression
10118 * candidate it queues up flushing the event queue.
10119 */
10120 _gdk_event_queue_handle_motion_compression (display);
10121 }
10122
10123 /**
10124 * gdk_window_create_similar_surface:
10125 * @window: window to make new surface similar to
10126 * @content: the content for the new surface
10127 * @width: width of the new surface
10128 * @height: height of the new surface
10129 *
10130 * Create a new surface that is as compatible as possible with the
10131 * given @window. For example the new surface will have the same
10132 * fallback resolution and font options as @window. Generally, the new
10133 * surface will also use the same backend as @window, unless that is
10134 * not possible for some reason. The type of the returned surface may
10135 * be examined with cairo_surface_get_type().
10136 *
10137 * Initially the surface contents are all 0 (transparent if contents
10138 * have transparency, black otherwise.)
10139 *
10140 * Returns: a pointer to the newly allocated surface. The caller
10141 * owns the surface and should call cairo_surface_destroy() when done
10142 * with it.
10143 *
10144 * This function always returns a valid pointer, but it will return a
10145 * pointer to a “nil” surface if @other is already in an error state
10146 * or any other error occurs.
10147 *
10148 * Since: 2.22
10149 **/
10150 cairo_surface_t *
gdk_window_create_similar_surface(GdkWindow * window,cairo_content_t content,int width,int height)10151 gdk_window_create_similar_surface (GdkWindow * window,
10152 cairo_content_t content,
10153 int width,
10154 int height)
10155 {
10156 GdkDisplay *display;
10157 GdkRenderingMode rendering_mode;
10158 cairo_surface_t *window_surface, *surface;
10159 double sx, sy;
10160
10161 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
10162
10163 window_surface = gdk_window_ref_impl_surface (window);
10164 sx = sy = 1;
10165 cairo_surface_get_device_scale (window_surface, &sx, &sy);
10166
10167 display = gdk_window_get_display (window);
10168 rendering_mode = gdk_display_get_rendering_mode (display);
10169
10170 switch (rendering_mode)
10171 {
10172 case GDK_RENDERING_MODE_RECORDING:
10173 {
10174 cairo_rectangle_t rect = { 0, 0, width * sx, height *sy };
10175 surface = cairo_recording_surface_create (content, &rect);
10176 cairo_surface_set_device_scale (surface, sx, sy);
10177 }
10178 break;
10179 case GDK_RENDERING_MODE_IMAGE:
10180 surface = cairo_image_surface_create (content == CAIRO_CONTENT_COLOR ? CAIRO_FORMAT_RGB24 :
10181 content == CAIRO_CONTENT_ALPHA ? CAIRO_FORMAT_A8 : CAIRO_FORMAT_ARGB32,
10182 width * sx, height * sy);
10183 cairo_surface_set_device_scale (surface, sx, sy);
10184 break;
10185 case GDK_RENDERING_MODE_SIMILAR:
10186 default:
10187 surface = cairo_surface_create_similar (window_surface,
10188 content,
10189 width, height);
10190 break;
10191 }
10192
10193 cairo_surface_destroy (window_surface);
10194
10195 return surface;
10196 }
10197
10198
10199 /**
10200 * gdk_window_create_similar_image_surface:
10201 * @window: (nullable): window to make new surface similar to, or
10202 * %NULL if none
10203 * @format: the format for the new surface
10204 * @width: width of the new surface
10205 * @height: height of the new surface
10206 * @scale: the scale of the new surface, or 0 to use same as @window
10207 *
10208 * Create a new image surface that is efficient to draw on the
10209 * given @window.
10210 *
10211 * Initially the surface contents are all 0 (transparent if contents
10212 * have transparency, black otherwise.)
10213 *
10214 * The @width and @height of the new surface are not affected by
10215 * the scaling factor of the @window, or by the @scale argument; they
10216 * are the size of the surface in device pixels. If you wish to create
10217 * an image surface capable of holding the contents of @window you can
10218 * use:
10219 *
10220 * |[<!-- language="C" -->
10221 * int scale = gdk_window_get_scale_factor (window);
10222 * int width = gdk_window_get_width (window) * scale;
10223 * int height = gdk_window_get_height (window) * scale;
10224 *
10225 * // format is set elsewhere
10226 * cairo_surface_t *surface =
10227 * gdk_window_create_similar_image_surface (window,
10228 * format,
10229 * width, height,
10230 * scale);
10231 * ]|
10232 *
10233 * Note that unlike cairo_surface_create_similar_image(), the new
10234 * surface's device scale is set to @scale, or to the scale factor of
10235 * @window if @scale is 0.
10236 *
10237 * Returns: a pointer to the newly allocated surface. The caller
10238 * owns the surface and should call cairo_surface_destroy() when done
10239 * with it.
10240 *
10241 * This function always returns a valid pointer, but it will return a
10242 * pointer to a “nil” surface if @other is already in an error state
10243 * or any other error occurs.
10244 *
10245 * Since: 3.10
10246 **/
10247 cairo_surface_t *
gdk_window_create_similar_image_surface(GdkWindow * window,cairo_format_t format,int width,int height,int scale)10248 gdk_window_create_similar_image_surface (GdkWindow * window,
10249 cairo_format_t format,
10250 int width,
10251 int height,
10252 int scale)
10253 {
10254 GdkWindowImplClass *impl_class;
10255 cairo_surface_t *window_surface, *surface;
10256 GdkDisplay *display;
10257 GdkScreen *screen;
10258
10259 g_return_val_if_fail (window ==NULL || GDK_IS_WINDOW (window), NULL);
10260
10261 if (window == NULL)
10262 {
10263 display = gdk_display_get_default ();
10264 screen = gdk_display_get_default_screen (display);
10265 window = gdk_screen_get_root_window (screen);
10266 }
10267
10268 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
10269
10270 if (impl_class->create_similar_image_surface)
10271 surface = impl_class->create_similar_image_surface (window, format, width, height);
10272 else
10273 {
10274 window_surface = gdk_window_ref_impl_surface (window);
10275 surface =
10276 cairo_surface_create_similar_image (window_surface,
10277 format,
10278 width,
10279 height);
10280 cairo_surface_destroy (window_surface);
10281 }
10282
10283 if (scale == 0)
10284 scale = gdk_window_get_scale_factor (window);
10285
10286 cairo_surface_set_device_scale (surface, scale, scale);
10287
10288 return surface;
10289 }
10290
10291
10292 /**
10293 * gdk_window_focus:
10294 * @window: a #GdkWindow
10295 * @timestamp: timestamp of the event triggering the window focus
10296 *
10297 * Sets keyboard focus to @window. In most cases, gtk_window_present_with_time()
10298 * should be used on a #GtkWindow, rather than calling this function.
10299 *
10300 **/
10301 void
gdk_window_focus(GdkWindow * window,guint32 timestamp)10302 gdk_window_focus (GdkWindow *window,
10303 guint32 timestamp)
10304 {
10305 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->focus (window, timestamp);
10306 }
10307
10308 /**
10309 * gdk_window_set_type_hint:
10310 * @window: A toplevel #GdkWindow
10311 * @hint: A hint of the function this window will have
10312 *
10313 * The application can use this call to provide a hint to the window
10314 * manager about the functionality of a window. The window manager
10315 * can use this information when determining the decoration and behaviour
10316 * of the window.
10317 *
10318 * The hint must be set before the window is mapped.
10319 **/
10320 void
gdk_window_set_type_hint(GdkWindow * window,GdkWindowTypeHint hint)10321 gdk_window_set_type_hint (GdkWindow *window,
10322 GdkWindowTypeHint hint)
10323 {
10324 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_type_hint (window, hint);
10325 }
10326
10327 /**
10328 * gdk_window_get_type_hint:
10329 * @window: A toplevel #GdkWindow
10330 *
10331 * This function returns the type hint set for a window.
10332 *
10333 * Returns: The type hint set for @window
10334 *
10335 * Since: 2.10
10336 **/
10337 GdkWindowTypeHint
gdk_window_get_type_hint(GdkWindow * window)10338 gdk_window_get_type_hint (GdkWindow *window)
10339 {
10340 return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_type_hint (window);
10341 }
10342
10343 /**
10344 * gdk_window_set_modal_hint:
10345 * @window: A toplevel #GdkWindow
10346 * @modal: %TRUE if the window is modal, %FALSE otherwise.
10347 *
10348 * The application can use this hint to tell the window manager
10349 * that a certain window has modal behaviour. The window manager
10350 * can use this information to handle modal windows in a special
10351 * way.
10352 *
10353 * You should only use this on windows for which you have
10354 * previously called gdk_window_set_transient_for()
10355 **/
10356 void
gdk_window_set_modal_hint(GdkWindow * window,gboolean modal)10357 gdk_window_set_modal_hint (GdkWindow *window,
10358 gboolean modal)
10359 {
10360 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_modal_hint (window, modal);
10361 }
10362
10363 /**
10364 * gdk_window_set_skip_taskbar_hint:
10365 * @window: a toplevel #GdkWindow
10366 * @skips_taskbar: %TRUE to skip the taskbar
10367 *
10368 * Toggles whether a window should appear in a task list or window
10369 * list. If a window’s semantic type as specified with
10370 * gdk_window_set_type_hint() already fully describes the window, this
10371 * function should not be called in addition,
10372 * instead you should allow the window to be treated according to
10373 * standard policy for its semantic type.
10374 *
10375 * Since: 2.2
10376 **/
10377 void
gdk_window_set_skip_taskbar_hint(GdkWindow * window,gboolean skips_taskbar)10378 gdk_window_set_skip_taskbar_hint (GdkWindow *window,
10379 gboolean skips_taskbar)
10380 {
10381 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_skip_taskbar_hint (window, skips_taskbar);
10382 }
10383
10384 /**
10385 * gdk_window_set_skip_pager_hint:
10386 * @window: a toplevel #GdkWindow
10387 * @skips_pager: %TRUE to skip the pager
10388 *
10389 * Toggles whether a window should appear in a pager (workspace
10390 * switcher, or other desktop utility program that displays a small
10391 * thumbnail representation of the windows on the desktop). If a
10392 * window’s semantic type as specified with gdk_window_set_type_hint()
10393 * already fully describes the window, this function should
10394 * not be called in addition, instead you should
10395 * allow the window to be treated according to standard policy for
10396 * its semantic type.
10397 *
10398 * Since: 2.2
10399 **/
10400 void
gdk_window_set_skip_pager_hint(GdkWindow * window,gboolean skips_pager)10401 gdk_window_set_skip_pager_hint (GdkWindow *window,
10402 gboolean skips_pager)
10403 {
10404 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_skip_pager_hint (window, skips_pager);
10405 }
10406
10407 /**
10408 * gdk_window_set_urgency_hint:
10409 * @window: a toplevel #GdkWindow
10410 * @urgent: %TRUE if the window is urgent
10411 *
10412 * Toggles whether a window needs the user's
10413 * urgent attention.
10414 *
10415 * Since: 2.8
10416 **/
10417 void
gdk_window_set_urgency_hint(GdkWindow * window,gboolean urgent)10418 gdk_window_set_urgency_hint (GdkWindow *window,
10419 gboolean urgent)
10420 {
10421 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_urgency_hint (window, urgent);
10422 }
10423
10424 /**
10425 * gdk_window_set_geometry_hints:
10426 * @window: a toplevel #GdkWindow
10427 * @geometry: geometry hints
10428 * @geom_mask: bitmask indicating fields of @geometry to pay attention to
10429 *
10430 * Sets the geometry hints for @window. Hints flagged in @geom_mask
10431 * are set, hints not flagged in @geom_mask are unset.
10432 * To unset all hints, use a @geom_mask of 0 and a @geometry of %NULL.
10433 *
10434 * This function provides hints to the windowing system about
10435 * acceptable sizes for a toplevel window. The purpose of
10436 * this is to constrain user resizing, but the windowing system
10437 * will typically (but is not required to) also constrain the
10438 * current size of the window to the provided values and
10439 * constrain programatic resizing via gdk_window_resize() or
10440 * gdk_window_move_resize().
10441 *
10442 * Note that on X11, this effect has no effect on windows
10443 * of type %GDK_WINDOW_TEMP or windows where override redirect
10444 * has been turned on via gdk_window_set_override_redirect()
10445 * since these windows are not resizable by the user.
10446 *
10447 * Since you can’t count on the windowing system doing the
10448 * constraints for programmatic resizes, you should generally
10449 * call gdk_window_constrain_size() yourself to determine
10450 * appropriate sizes.
10451 *
10452 **/
10453 void
gdk_window_set_geometry_hints(GdkWindow * window,const GdkGeometry * geometry,GdkWindowHints geom_mask)10454 gdk_window_set_geometry_hints (GdkWindow *window,
10455 const GdkGeometry *geometry,
10456 GdkWindowHints geom_mask)
10457 {
10458 g_return_if_fail (geometry != NULL || geom_mask == 0);
10459
10460 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_geometry_hints (window, geometry, geom_mask);
10461 }
10462
10463 /**
10464 * gdk_window_set_title:
10465 * @window: a toplevel #GdkWindow
10466 * @title: title of @window
10467 *
10468 * Sets the title of a toplevel window, to be displayed in the titlebar.
10469 * If you haven’t explicitly set the icon name for the window
10470 * (using gdk_window_set_icon_name()), the icon name will be set to
10471 * @title as well. @title must be in UTF-8 encoding (as with all
10472 * user-readable strings in GDK/GTK+). @title may not be %NULL.
10473 **/
10474 void
gdk_window_set_title(GdkWindow * window,const gchar * title)10475 gdk_window_set_title (GdkWindow *window,
10476 const gchar *title)
10477 {
10478 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_title (window, title);
10479 }
10480
10481 /**
10482 * gdk_window_set_role:
10483 * @window: a toplevel #GdkWindow
10484 * @role: a string indicating its role
10485 *
10486 * When using GTK+, typically you should use gtk_window_set_role() instead
10487 * of this low-level function.
10488 *
10489 * The window manager and session manager use a window’s role to
10490 * distinguish it from other kinds of window in the same application.
10491 * When an application is restarted after being saved in a previous
10492 * session, all windows with the same title and role are treated as
10493 * interchangeable. So if you have two windows with the same title
10494 * that should be distinguished for session management purposes, you
10495 * should set the role on those windows. It doesn’t matter what string
10496 * you use for the role, as long as you have a different role for each
10497 * non-interchangeable kind of window.
10498 *
10499 **/
10500 void
gdk_window_set_role(GdkWindow * window,const gchar * role)10501 gdk_window_set_role (GdkWindow *window,
10502 const gchar *role)
10503 {
10504 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_role (window, role);
10505 }
10506
10507 /**
10508 * gdk_window_set_startup_id:
10509 * @window: a toplevel #GdkWindow
10510 * @startup_id: a string with startup-notification identifier
10511 *
10512 * When using GTK+, typically you should use gtk_window_set_startup_id()
10513 * instead of this low-level function.
10514 *
10515 * Since: 2.12
10516 *
10517 **/
10518 void
gdk_window_set_startup_id(GdkWindow * window,const gchar * startup_id)10519 gdk_window_set_startup_id (GdkWindow *window,
10520 const gchar *startup_id)
10521 {
10522 GdkWindowImplClass *klass = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
10523
10524 if (klass->set_startup_id)
10525 klass->set_startup_id (window, startup_id);
10526 }
10527
10528 /**
10529 * gdk_window_set_transient_for:
10530 * @window: a toplevel #GdkWindow
10531 * @parent: another toplevel #GdkWindow
10532 *
10533 * Indicates to the window manager that @window is a transient dialog
10534 * associated with the application window @parent. This allows the
10535 * window manager to do things like center @window on @parent and
10536 * keep @window above @parent.
10537 *
10538 * See gtk_window_set_transient_for() if you’re using #GtkWindow or
10539 * #GtkDialog.
10540 **/
10541 void
gdk_window_set_transient_for(GdkWindow * window,GdkWindow * parent)10542 gdk_window_set_transient_for (GdkWindow *window,
10543 GdkWindow *parent)
10544 {
10545 window->transient_for = parent;
10546
10547 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_transient_for (window, parent);
10548 }
10549
10550 /**
10551 * gdk_window_get_root_origin:
10552 * @window: a toplevel #GdkWindow
10553 * @x: (out): return location for X position of window frame
10554 * @y: (out): return location for Y position of window frame
10555 *
10556 * Obtains the top-left corner of the window manager frame in root
10557 * window coordinates.
10558 *
10559 **/
10560 void
gdk_window_get_root_origin(GdkWindow * window,gint * x,gint * y)10561 gdk_window_get_root_origin (GdkWindow *window,
10562 gint *x,
10563 gint *y)
10564 {
10565 GdkRectangle rect;
10566
10567 gdk_window_get_frame_extents (window, &rect);
10568
10569 if (x)
10570 *x = rect.x;
10571
10572 if (y)
10573 *y = rect.y;
10574 }
10575
10576 /**
10577 * gdk_window_get_frame_extents:
10578 * @window: a toplevel #GdkWindow
10579 * @rect: (out): rectangle to fill with bounding box of the window frame
10580 *
10581 * Obtains the bounding box of the window, including window manager
10582 * titlebar/borders if any. The frame position is given in root window
10583 * coordinates. To get the position of the window itself (rather than
10584 * the frame) in root window coordinates, use gdk_window_get_origin().
10585 *
10586 **/
10587 void
gdk_window_get_frame_extents(GdkWindow * window,GdkRectangle * rect)10588 gdk_window_get_frame_extents (GdkWindow *window,
10589 GdkRectangle *rect)
10590 {
10591 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_frame_extents (window, rect);
10592 }
10593
10594 /**
10595 * gdk_window_set_override_redirect:
10596 * @window: a toplevel #GdkWindow
10597 * @override_redirect: %TRUE if window should be override redirect
10598 *
10599 * An override redirect window is not under the control of the window manager.
10600 * This means it won’t have a titlebar, won’t be minimizable, etc. - it will
10601 * be entirely under the control of the application. The window manager
10602 * can’t see the override redirect window at all.
10603 *
10604 * Override redirect should only be used for short-lived temporary
10605 * windows, such as popup menus. #GtkMenu uses an override redirect
10606 * window in its implementation, for example.
10607 *
10608 **/
10609 void
gdk_window_set_override_redirect(GdkWindow * window,gboolean override_redirect)10610 gdk_window_set_override_redirect (GdkWindow *window,
10611 gboolean override_redirect)
10612 {
10613 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_override_redirect (window, override_redirect);
10614 }
10615
10616 /**
10617 * gdk_window_set_accept_focus:
10618 * @window: a toplevel #GdkWindow
10619 * @accept_focus: %TRUE if the window should receive input focus
10620 *
10621 * Setting @accept_focus to %FALSE hints the desktop environment that the
10622 * window doesn’t want to receive input focus.
10623 *
10624 * On X, it is the responsibility of the window manager to interpret this
10625 * hint. ICCCM-compliant window manager usually respect it.
10626 *
10627 * Since: 2.4
10628 **/
10629 void
gdk_window_set_accept_focus(GdkWindow * window,gboolean accept_focus)10630 gdk_window_set_accept_focus (GdkWindow *window,
10631 gboolean accept_focus)
10632 {
10633 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_accept_focus (window, accept_focus);
10634 }
10635
10636 /**
10637 * gdk_window_set_focus_on_map:
10638 * @window: a toplevel #GdkWindow
10639 * @focus_on_map: %TRUE if the window should receive input focus when mapped
10640 *
10641 * Setting @focus_on_map to %FALSE hints the desktop environment that the
10642 * window doesn’t want to receive input focus when it is mapped.
10643 * focus_on_map should be turned off for windows that aren’t triggered
10644 * interactively (such as popups from network activity).
10645 *
10646 * On X, it is the responsibility of the window manager to interpret
10647 * this hint. Window managers following the freedesktop.org window
10648 * manager extension specification should respect it.
10649 *
10650 * Since: 2.6
10651 **/
10652 void
gdk_window_set_focus_on_map(GdkWindow * window,gboolean focus_on_map)10653 gdk_window_set_focus_on_map (GdkWindow *window,
10654 gboolean focus_on_map)
10655 {
10656 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_focus_on_map (window, focus_on_map);
10657 }
10658
10659 /**
10660 * gdk_window_set_event_compression:
10661 * @window: a #GdkWindow
10662 * @event_compression: %TRUE if motion events should be compressed
10663 *
10664 * Determines whether or not extra unprocessed motion events in
10665 * the event queue can be discarded. If %TRUE only the most recent
10666 * event will be delivered.
10667 *
10668 * Some types of applications, e.g. paint programs, need to see all
10669 * motion events and will benefit from turning off event compression.
10670 *
10671 * By default, event compression is enabled.
10672 *
10673 * Since: 3.12
10674 **/
10675 void
gdk_window_set_event_compression(GdkWindow * window,gboolean event_compression)10676 gdk_window_set_event_compression (GdkWindow *window,
10677 gboolean event_compression)
10678 {
10679 g_return_if_fail (GDK_IS_WINDOW (window));
10680
10681 window->event_compression = !!event_compression;
10682 }
10683
10684 /**
10685 * gdk_window_get_event_compression:
10686 * @window: a #GdkWindow
10687 *
10688 * Get the current event compression setting for this window.
10689 *
10690 * Returns: %TRUE if motion events will be compressed
10691 *
10692 * Since: 3.12
10693 **/
10694 gboolean
gdk_window_get_event_compression(GdkWindow * window)10695 gdk_window_get_event_compression (GdkWindow *window)
10696 {
10697 g_return_val_if_fail (GDK_IS_WINDOW (window), TRUE);
10698
10699 return window->event_compression;
10700 }
10701
10702 /**
10703 * gdk_window_set_icon_list:
10704 * @window: The #GdkWindow toplevel window to set the icon of.
10705 * @pixbufs: (transfer none) (element-type GdkPixbuf):
10706 * A list of pixbufs, of different sizes.
10707 *
10708 * Sets a list of icons for the window. One of these will be used
10709 * to represent the window when it has been iconified. The icon is
10710 * usually shown in an icon box or some sort of task bar. Which icon
10711 * size is shown depends on the window manager. The window manager
10712 * can scale the icon but setting several size icons can give better
10713 * image quality since the window manager may only need to scale the
10714 * icon by a small amount or not at all.
10715 *
10716 * Note that some platforms don't support window icons.
10717 */
10718 void
gdk_window_set_icon_list(GdkWindow * window,GList * pixbufs)10719 gdk_window_set_icon_list (GdkWindow *window,
10720 GList *pixbufs)
10721 {
10722 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_icon_list (window, pixbufs);
10723 }
10724
10725 /**
10726 * gdk_window_set_icon_name:
10727 * @window: a toplevel #GdkWindow
10728 * @name: (allow-none): name of window while iconified (minimized)
10729 *
10730 * Windows may have a name used while minimized, distinct from the
10731 * name they display in their titlebar. Most of the time this is a bad
10732 * idea from a user interface standpoint. But you can set such a name
10733 * with this function, if you like.
10734 *
10735 * After calling this with a non-%NULL @name, calls to gdk_window_set_title()
10736 * will not update the icon title.
10737 *
10738 * Using %NULL for @name unsets the icon title; further calls to
10739 * gdk_window_set_title() will again update the icon title as well.
10740 *
10741 * Note that some platforms don't support window icons.
10742 **/
10743 void
gdk_window_set_icon_name(GdkWindow * window,const gchar * name)10744 gdk_window_set_icon_name (GdkWindow *window,
10745 const gchar *name)
10746 {
10747 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_icon_name (window, name);
10748 }
10749
10750 /**
10751 * gdk_window_iconify:
10752 * @window: a toplevel #GdkWindow
10753 *
10754 * Asks to iconify (minimize) @window. The window manager may choose
10755 * to ignore the request, but normally will honor it. Using
10756 * gtk_window_iconify() is preferred, if you have a #GtkWindow widget.
10757 *
10758 * This function only makes sense when @window is a toplevel window.
10759 *
10760 **/
10761 void
gdk_window_iconify(GdkWindow * window)10762 gdk_window_iconify (GdkWindow *window)
10763 {
10764 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->iconify (window);
10765 }
10766
10767 /**
10768 * gdk_window_deiconify:
10769 * @window: a toplevel #GdkWindow
10770 *
10771 * Attempt to deiconify (unminimize) @window. On X11 the window manager may
10772 * choose to ignore the request to deiconify. When using GTK+,
10773 * use gtk_window_deiconify() instead of the #GdkWindow variant. Or better yet,
10774 * you probably want to use gtk_window_present_with_time(), which raises the window, focuses it,
10775 * unminimizes it, and puts it on the current desktop.
10776 *
10777 **/
10778 void
gdk_window_deiconify(GdkWindow * window)10779 gdk_window_deiconify (GdkWindow *window)
10780 {
10781 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->deiconify (window);
10782 }
10783
10784 /**
10785 * gdk_window_stick:
10786 * @window: a toplevel #GdkWindow
10787 *
10788 * “Pins” a window such that it’s on all workspaces and does not scroll
10789 * with viewports, for window managers that have scrollable viewports.
10790 * (When using #GtkWindow, gtk_window_stick() may be more useful.)
10791 *
10792 * On the X11 platform, this function depends on window manager
10793 * support, so may have no effect with many window managers. However,
10794 * GDK will do the best it can to convince the window manager to stick
10795 * the window. For window managers that don’t support this operation,
10796 * there’s nothing you can do to force it to happen.
10797 *
10798 **/
10799 void
gdk_window_stick(GdkWindow * window)10800 gdk_window_stick (GdkWindow *window)
10801 {
10802 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->stick (window);
10803 }
10804
10805 /**
10806 * gdk_window_unstick:
10807 * @window: a toplevel #GdkWindow
10808 *
10809 * Reverse operation for gdk_window_stick(); see gdk_window_stick(),
10810 * and gtk_window_unstick().
10811 *
10812 **/
10813 void
gdk_window_unstick(GdkWindow * window)10814 gdk_window_unstick (GdkWindow *window)
10815 {
10816 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->unstick (window);
10817 }
10818
10819 /**
10820 * gdk_window_maximize:
10821 * @window: a toplevel #GdkWindow
10822 *
10823 * Maximizes the window. If the window was already maximized, then
10824 * this function does nothing.
10825 *
10826 * On X11, asks the window manager to maximize @window, if the window
10827 * manager supports this operation. Not all window managers support
10828 * this, and some deliberately ignore it or don’t have a concept of
10829 * “maximized”; so you can’t rely on the maximization actually
10830 * happening. But it will happen with most standard window managers,
10831 * and GDK makes a best effort to get it to happen.
10832 *
10833 * On Windows, reliably maximizes the window.
10834 *
10835 **/
10836 void
gdk_window_maximize(GdkWindow * window)10837 gdk_window_maximize (GdkWindow *window)
10838 {
10839 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->maximize (window);
10840 }
10841
10842 /**
10843 * gdk_window_unmaximize:
10844 * @window: a toplevel #GdkWindow
10845 *
10846 * Unmaximizes the window. If the window wasn’t maximized, then this
10847 * function does nothing.
10848 *
10849 * On X11, asks the window manager to unmaximize @window, if the
10850 * window manager supports this operation. Not all window managers
10851 * support this, and some deliberately ignore it or don’t have a
10852 * concept of “maximized”; so you can’t rely on the unmaximization
10853 * actually happening. But it will happen with most standard window
10854 * managers, and GDK makes a best effort to get it to happen.
10855 *
10856 * On Windows, reliably unmaximizes the window.
10857 *
10858 **/
10859 void
gdk_window_unmaximize(GdkWindow * window)10860 gdk_window_unmaximize (GdkWindow *window)
10861 {
10862 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->unmaximize (window);
10863 }
10864
10865 /**
10866 * gdk_window_fullscreen:
10867 * @window: a toplevel #GdkWindow
10868 *
10869 * Moves the window into fullscreen mode. This means the
10870 * window covers the entire screen and is above any panels
10871 * or task bars.
10872 *
10873 * If the window was already fullscreen, then this function does nothing.
10874 *
10875 * On X11, asks the window manager to put @window in a fullscreen
10876 * state, if the window manager supports this operation. Not all
10877 * window managers support this, and some deliberately ignore it or
10878 * don’t have a concept of “fullscreen”; so you can’t rely on the
10879 * fullscreenification actually happening. But it will happen with
10880 * most standard window managers, and GDK makes a best effort to get
10881 * it to happen.
10882 *
10883 * Since: 2.2
10884 **/
10885 void
gdk_window_fullscreen(GdkWindow * window)10886 gdk_window_fullscreen (GdkWindow *window)
10887 {
10888 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->fullscreen (window);
10889 }
10890
10891 /**
10892 * gdk_window_fullscreen_on_monitor:
10893 * @window: a toplevel #GdkWindow
10894 * @monitor: Which monitor to display fullscreen on.
10895 *
10896 * Moves the window into fullscreen mode on the given monitor. This means
10897 * the window covers the entire screen and is above any panels or task bars.
10898 *
10899 * If the window was already fullscreen, then this function does nothing.
10900 * Since: UNRELEASED
10901 **/
10902 void
gdk_window_fullscreen_on_monitor(GdkWindow * window,gint monitor)10903 gdk_window_fullscreen_on_monitor (GdkWindow *window,
10904 gint monitor)
10905 {
10906 GdkDisplay *display = gdk_window_get_display (window);
10907
10908 g_return_if_fail (monitor >= 0);
10909 g_return_if_fail (monitor < gdk_display_get_n_monitors (display));
10910
10911 if (GDK_WINDOW_IMPL_GET_CLASS (window->impl)->fullscreen_on_monitor != NULL)
10912 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->fullscreen_on_monitor (window, monitor);
10913 else
10914 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->fullscreen (window);
10915 }
10916
10917 /**
10918 * gdk_window_set_fullscreen_mode:
10919 * @window: a toplevel #GdkWindow
10920 * @mode: fullscreen mode
10921 *
10922 * Specifies whether the @window should span over all monitors (in a multi-head
10923 * setup) or only the current monitor when in fullscreen mode.
10924 *
10925 * The @mode argument is from the #GdkFullscreenMode enumeration.
10926 * If #GDK_FULLSCREEN_ON_ALL_MONITORS is specified, the fullscreen @window will
10927 * span over all monitors from the #GdkScreen.
10928 *
10929 * On X11, searches through the list of monitors from the #GdkScreen the ones
10930 * which delimit the 4 edges of the entire #GdkScreen and will ask the window
10931 * manager to span the @window over these monitors.
10932 *
10933 * If the XINERAMA extension is not available or not usable, this function
10934 * has no effect.
10935 *
10936 * Not all window managers support this, so you can’t rely on the fullscreen
10937 * window to span over the multiple monitors when #GDK_FULLSCREEN_ON_ALL_MONITORS
10938 * is specified.
10939 *
10940 * Since: 3.8
10941 **/
10942 void
gdk_window_set_fullscreen_mode(GdkWindow * window,GdkFullscreenMode mode)10943 gdk_window_set_fullscreen_mode (GdkWindow *window,
10944 GdkFullscreenMode mode)
10945 {
10946 GdkWindowImplClass *impl_class;
10947
10948 g_return_if_fail (GDK_IS_WINDOW (window));
10949
10950 if (window->fullscreen_mode != mode)
10951 {
10952 window->fullscreen_mode = mode;
10953
10954 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
10955 if (impl_class->apply_fullscreen_mode != NULL)
10956 impl_class->apply_fullscreen_mode (window);
10957 }
10958 }
10959
10960 /**
10961 * gdk_window_get_fullscreen_mode:
10962 * @window: a toplevel #GdkWindow
10963 *
10964 * Obtains the #GdkFullscreenMode of the @window.
10965 *
10966 * Returns: The #GdkFullscreenMode applied to the window when fullscreen.
10967 *
10968 * Since: 3.8
10969 **/
10970 GdkFullscreenMode
gdk_window_get_fullscreen_mode(GdkWindow * window)10971 gdk_window_get_fullscreen_mode (GdkWindow *window)
10972 {
10973 g_return_val_if_fail (GDK_IS_WINDOW (window), GDK_FULLSCREEN_ON_CURRENT_MONITOR);
10974
10975 return window->fullscreen_mode;
10976 }
10977
10978 /**
10979 * gdk_window_unfullscreen:
10980 * @window: a toplevel #GdkWindow
10981 *
10982 * Moves the window out of fullscreen mode. If the window was not
10983 * fullscreen, does nothing.
10984 *
10985 * On X11, asks the window manager to move @window out of the fullscreen
10986 * state, if the window manager supports this operation. Not all
10987 * window managers support this, and some deliberately ignore it or
10988 * don’t have a concept of “fullscreen”; so you can’t rely on the
10989 * unfullscreenification actually happening. But it will happen with
10990 * most standard window managers, and GDK makes a best effort to get
10991 * it to happen.
10992 *
10993 * Since: 2.2
10994 **/
10995 void
gdk_window_unfullscreen(GdkWindow * window)10996 gdk_window_unfullscreen (GdkWindow *window)
10997 {
10998 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->unfullscreen (window);
10999 }
11000
11001 /**
11002 * gdk_window_set_keep_above:
11003 * @window: a toplevel #GdkWindow
11004 * @setting: whether to keep @window above other windows
11005 *
11006 * Set if @window must be kept above other windows. If the
11007 * window was already above, then this function does nothing.
11008 *
11009 * On X11, asks the window manager to keep @window above, if the window
11010 * manager supports this operation. Not all window managers support
11011 * this, and some deliberately ignore it or don’t have a concept of
11012 * “keep above”; so you can’t rely on the window being kept above.
11013 * But it will happen with most standard window managers,
11014 * and GDK makes a best effort to get it to happen.
11015 *
11016 * Since: 2.4
11017 **/
11018 void
gdk_window_set_keep_above(GdkWindow * window,gboolean setting)11019 gdk_window_set_keep_above (GdkWindow *window,
11020 gboolean setting)
11021 {
11022 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_keep_above (window, setting);
11023 }
11024
11025 /**
11026 * gdk_window_set_keep_below:
11027 * @window: a toplevel #GdkWindow
11028 * @setting: whether to keep @window below other windows
11029 *
11030 * Set if @window must be kept below other windows. If the
11031 * window was already below, then this function does nothing.
11032 *
11033 * On X11, asks the window manager to keep @window below, if the window
11034 * manager supports this operation. Not all window managers support
11035 * this, and some deliberately ignore it or don’t have a concept of
11036 * “keep below”; so you can’t rely on the window being kept below.
11037 * But it will happen with most standard window managers,
11038 * and GDK makes a best effort to get it to happen.
11039 *
11040 * Since: 2.4
11041 **/
11042 void
gdk_window_set_keep_below(GdkWindow * window,gboolean setting)11043 gdk_window_set_keep_below (GdkWindow *window, gboolean setting)
11044 {
11045 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_keep_below (window, setting);
11046 }
11047
11048 /**
11049 * gdk_window_get_group:
11050 * @window: a toplevel #GdkWindow
11051 *
11052 * Returns the group leader window for @window. See gdk_window_set_group().
11053 *
11054 * Returns: (transfer none): the group leader window for @window
11055 *
11056 * Since: 2.4
11057 **/
11058 GdkWindow *
gdk_window_get_group(GdkWindow * window)11059 gdk_window_get_group (GdkWindow *window)
11060 {
11061 return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_group (window);
11062 }
11063
11064 /**
11065 * gdk_window_set_group:
11066 * @window: a toplevel #GdkWindow
11067 * @leader: (allow-none): group leader window, or %NULL to restore the default group leader window
11068 *
11069 * Sets the group leader window for @window. By default,
11070 * GDK sets the group leader for all toplevel windows
11071 * to a global window implicitly created by GDK. With this function
11072 * you can override this default.
11073 *
11074 * The group leader window allows the window manager to distinguish
11075 * all windows that belong to a single application. It may for example
11076 * allow users to minimize/unminimize all windows belonging to an
11077 * application at once. You should only set a non-default group window
11078 * if your application pretends to be multiple applications.
11079 **/
11080 void
gdk_window_set_group(GdkWindow * window,GdkWindow * leader)11081 gdk_window_set_group (GdkWindow *window,
11082 GdkWindow *leader)
11083 {
11084 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_group (window, leader);
11085 }
11086
11087 /**
11088 * gdk_window_set_decorations:
11089 * @window: a toplevel #GdkWindow
11090 * @decorations: decoration hint mask
11091 *
11092 * “Decorations” are the features the window manager adds to a toplevel #GdkWindow.
11093 * This function sets the traditional Motif window manager hints that tell the
11094 * window manager which decorations you would like your window to have.
11095 * Usually you should use gtk_window_set_decorated() on a #GtkWindow instead of
11096 * using the GDK function directly.
11097 *
11098 * The @decorations argument is the logical OR of the fields in
11099 * the #GdkWMDecoration enumeration. If #GDK_DECOR_ALL is included in the
11100 * mask, the other bits indicate which decorations should be turned off.
11101 * If #GDK_DECOR_ALL is not included, then the other bits indicate
11102 * which decorations should be turned on.
11103 *
11104 * Most window managers honor a decorations hint of 0 to disable all decorations,
11105 * but very few honor all possible combinations of bits.
11106 *
11107 **/
11108 void
gdk_window_set_decorations(GdkWindow * window,GdkWMDecoration decorations)11109 gdk_window_set_decorations (GdkWindow *window,
11110 GdkWMDecoration decorations)
11111 {
11112 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_decorations (window, decorations);
11113 }
11114
11115 /**
11116 * gdk_window_get_decorations:
11117 * @window: The toplevel #GdkWindow to get the decorations from
11118 * @decorations: (out): The window decorations will be written here
11119 *
11120 * Returns the decorations set on the GdkWindow with
11121 * gdk_window_set_decorations().
11122 *
11123 * Returns: %TRUE if the window has decorations set, %FALSE otherwise.
11124 **/
11125 gboolean
gdk_window_get_decorations(GdkWindow * window,GdkWMDecoration * decorations)11126 gdk_window_get_decorations(GdkWindow *window,
11127 GdkWMDecoration *decorations)
11128 {
11129 return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_decorations (window, decorations);
11130 }
11131
11132 /**
11133 * gdk_window_set_functions:
11134 * @window: a toplevel #GdkWindow
11135 * @functions: bitmask of operations to allow on @window
11136 *
11137 * Sets hints about the window management functions to make available
11138 * via buttons on the window frame.
11139 *
11140 * On the X backend, this function sets the traditional Motif window
11141 * manager hint for this purpose. However, few window managers do
11142 * anything reliable or interesting with this hint. Many ignore it
11143 * entirely.
11144 *
11145 * The @functions argument is the logical OR of values from the
11146 * #GdkWMFunction enumeration. If the bitmask includes #GDK_FUNC_ALL,
11147 * then the other bits indicate which functions to disable; if
11148 * it doesn’t include #GDK_FUNC_ALL, it indicates which functions to
11149 * enable.
11150 *
11151 **/
11152 void
gdk_window_set_functions(GdkWindow * window,GdkWMFunction functions)11153 gdk_window_set_functions (GdkWindow *window,
11154 GdkWMFunction functions)
11155 {
11156 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_functions (window, functions);
11157 }
11158
11159 /**
11160 * gdk_window_begin_resize_drag_for_device:
11161 * @window: a toplevel #GdkWindow
11162 * @edge: the edge or corner from which the drag is started
11163 * @device: the device used for the operation
11164 * @button: the button being used to drag, or 0 for a keyboard-initiated drag
11165 * @root_x: root window X coordinate of mouse click that began the drag
11166 * @root_y: root window Y coordinate of mouse click that began the drag
11167 * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
11168 *
11169 * Begins a window resize operation (for a toplevel window).
11170 * You might use this function to implement a “window resize grip,” for
11171 * example; in fact #GtkStatusbar uses it. The function works best
11172 * with window managers that support the
11173 * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec)
11174 * but has a fallback implementation for other window managers.
11175 *
11176 * Since: 3.4
11177 */
11178 void
gdk_window_begin_resize_drag_for_device(GdkWindow * window,GdkWindowEdge edge,GdkDevice * device,gint button,gint root_x,gint root_y,guint32 timestamp)11179 gdk_window_begin_resize_drag_for_device (GdkWindow *window,
11180 GdkWindowEdge edge,
11181 GdkDevice *device,
11182 gint button,
11183 gint root_x,
11184 gint root_y,
11185 guint32 timestamp)
11186 {
11187 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->begin_resize_drag (window, edge, device, button, root_x, root_y, timestamp);
11188 }
11189
11190 /**
11191 * gdk_window_begin_resize_drag:
11192 * @window: a toplevel #GdkWindow
11193 * @edge: the edge or corner from which the drag is started
11194 * @button: the button being used to drag, or 0 for a keyboard-initiated drag
11195 * @root_x: root window X coordinate of mouse click that began the drag
11196 * @root_y: root window Y coordinate of mouse click that began the drag
11197 * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
11198 *
11199 * Begins a window resize operation (for a toplevel window).
11200 *
11201 * This function assumes that the drag is controlled by the
11202 * client pointer device, use gdk_window_begin_resize_drag_for_device()
11203 * to begin a drag with a different device.
11204 */
11205 void
gdk_window_begin_resize_drag(GdkWindow * window,GdkWindowEdge edge,gint button,gint root_x,gint root_y,guint32 timestamp)11206 gdk_window_begin_resize_drag (GdkWindow *window,
11207 GdkWindowEdge edge,
11208 gint button,
11209 gint root_x,
11210 gint root_y,
11211 guint32 timestamp)
11212 {
11213 GdkDisplay *display;
11214 GdkDevice *device;
11215
11216 display = gdk_window_get_display (window);
11217 device = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
11218 gdk_window_begin_resize_drag_for_device (window, edge,
11219 device, button, root_x, root_y, timestamp);
11220 }
11221
11222 /**
11223 * gdk_window_begin_move_drag_for_device:
11224 * @window: a toplevel #GdkWindow
11225 * @device: the device used for the operation
11226 * @button: the button being used to drag, or 0 for a keyboard-initiated drag
11227 * @root_x: root window X coordinate of mouse click that began the drag
11228 * @root_y: root window Y coordinate of mouse click that began the drag
11229 * @timestamp: timestamp of mouse click that began the drag
11230 *
11231 * Begins a window move operation (for a toplevel window).
11232 * You might use this function to implement a “window move grip,” for
11233 * example. The function works best with window managers that support the
11234 * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec)
11235 * but has a fallback implementation for other window managers.
11236 *
11237 * Since: 3.4
11238 */
11239 void
gdk_window_begin_move_drag_for_device(GdkWindow * window,GdkDevice * device,gint button,gint root_x,gint root_y,guint32 timestamp)11240 gdk_window_begin_move_drag_for_device (GdkWindow *window,
11241 GdkDevice *device,
11242 gint button,
11243 gint root_x,
11244 gint root_y,
11245 guint32 timestamp)
11246 {
11247 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->begin_move_drag (window,
11248 device, button, root_x, root_y, timestamp);
11249 }
11250
11251 /**
11252 * gdk_window_begin_move_drag:
11253 * @window: a toplevel #GdkWindow
11254 * @button: the button being used to drag, or 0 for a keyboard-initiated drag
11255 * @root_x: root window X coordinate of mouse click that began the drag
11256 * @root_y: root window Y coordinate of mouse click that began the drag
11257 * @timestamp: timestamp of mouse click that began the drag
11258 *
11259 * Begins a window move operation (for a toplevel window).
11260 *
11261 * This function assumes that the drag is controlled by the
11262 * client pointer device, use gdk_window_begin_move_drag_for_device()
11263 * to begin a drag with a different device.
11264 */
11265 void
gdk_window_begin_move_drag(GdkWindow * window,gint button,gint root_x,gint root_y,guint32 timestamp)11266 gdk_window_begin_move_drag (GdkWindow *window,
11267 gint button,
11268 gint root_x,
11269 gint root_y,
11270 guint32 timestamp)
11271 {
11272 GdkDisplay *display;
11273 GdkDevice *device;
11274
11275 display = gdk_window_get_display (window);
11276 device = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
11277 gdk_window_begin_move_drag_for_device (window, device, button, root_x, root_y, timestamp);
11278 }
11279
11280 /**
11281 * gdk_window_enable_synchronized_configure:
11282 * @window: a toplevel #GdkWindow
11283 *
11284 * Does nothing, present only for compatiblity.
11285 *
11286 * Since: 2.6
11287 * Deprecated: 3.8: this function is no longer needed
11288 **/
11289 void
gdk_window_enable_synchronized_configure(GdkWindow * window)11290 gdk_window_enable_synchronized_configure (GdkWindow *window)
11291 {
11292 }
11293
11294 /**
11295 * gdk_window_configure_finished:
11296 * @window: a toplevel #GdkWindow
11297 *
11298 * Does nothing, present only for compatiblity.
11299 *
11300 * Since: 2.6
11301 * Deprecated: 3.8: this function is no longer needed
11302 **/
11303 void
gdk_window_configure_finished(GdkWindow * window)11304 gdk_window_configure_finished (GdkWindow *window)
11305 {
11306 }
11307
11308 /**
11309 * gdk_window_set_opacity:
11310 * @window: a top-level or non-native #GdkWindow
11311 * @opacity: opacity
11312 *
11313 * Set @window to render as partially transparent,
11314 * with opacity 0 being fully transparent and 1 fully opaque. (Values
11315 * of the opacity parameter are clamped to the [0,1] range.)
11316 *
11317 * For toplevel windows this depends on support from the windowing system
11318 * that may not always be there. For instance, On X11, this works only on
11319 * X screens with a compositing manager running. On Wayland, there is no
11320 * per-window opacity value that the compositor would apply. Instead, use
11321 * `gdk_window_set_opaque_region (window, NULL)` to tell the compositor
11322 * that the entire window is (potentially) non-opaque, and draw your content
11323 * with alpha, or use gtk_widget_set_opacity() to set an overall opacity
11324 * for your widgets.
11325 *
11326 * For child windows this function only works for non-native windows.
11327 *
11328 * For setting up per-pixel alpha topelevels, see gdk_screen_get_rgba_visual(),
11329 * and for non-toplevels, see gdk_window_set_composited().
11330 *
11331 * Support for non-toplevel windows was added in 3.8.
11332 *
11333 * Since: 2.12
11334 */
11335 void
gdk_window_set_opacity(GdkWindow * window,gdouble opacity)11336 gdk_window_set_opacity (GdkWindow *window,
11337 gdouble opacity)
11338 {
11339 if (opacity < 0)
11340 opacity = 0;
11341 else if (opacity > 1)
11342 opacity = 1;
11343
11344 window->alpha = round (opacity * 255);
11345
11346 if (window->destroyed)
11347 return;
11348
11349 if (gdk_window_has_impl (window))
11350 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_opacity (window, opacity);
11351 else
11352 {
11353 recompute_visible_regions (window, FALSE);
11354 gdk_window_invalidate_rect_full (window, NULL, TRUE);
11355 }
11356 }
11357
11358 /* This function is called when the XWindow is really gone.
11359 */
11360 void
gdk_window_destroy_notify(GdkWindow * window)11361 gdk_window_destroy_notify (GdkWindow *window)
11362 {
11363 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->destroy_notify (window);
11364 }
11365
11366 /**
11367 * gdk_window_register_dnd:
11368 * @window: a #GdkWindow.
11369 *
11370 * Registers a window as a potential drop destination.
11371 */
11372 void
gdk_window_register_dnd(GdkWindow * window)11373 gdk_window_register_dnd (GdkWindow *window)
11374 {
11375 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->register_dnd (window);
11376 }
11377
11378 /**
11379 * gdk_window_get_drag_protocol:
11380 * @window: the destination window
11381 * @target: (out) (allow-none) (transfer full): location of the window
11382 * where the drop should happen. This may be @window or a proxy window,
11383 * or %NULL if @window does not support Drag and Drop.
11384 *
11385 * Finds out the DND protocol supported by a window.
11386 *
11387 * Returns: the supported DND protocol.
11388 *
11389 * Since: 3.0
11390 */
11391 GdkDragProtocol
gdk_window_get_drag_protocol(GdkWindow * window,GdkWindow ** target)11392 gdk_window_get_drag_protocol (GdkWindow *window,
11393 GdkWindow **target)
11394 {
11395 g_return_val_if_fail (GDK_IS_WINDOW (window), GDK_DRAG_PROTO_NONE);
11396
11397 return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_drag_protocol (window, target);
11398 }
11399
11400 /**
11401 * gdk_drag_begin:
11402 * @window: the source window for this drag.
11403 * @targets: (transfer none) (element-type GdkAtom): the offered targets,
11404 * as list of #GdkAtoms
11405 *
11406 * Starts a drag and creates a new drag context for it.
11407 * This function assumes that the drag is controlled by the
11408 * client pointer device, use gdk_drag_begin_for_device() to
11409 * begin a drag with a different device.
11410 *
11411 * This function is called by the drag source.
11412 *
11413 * Returns: (transfer full): a newly created #GdkDragContext
11414 */
11415 GdkDragContext *
gdk_drag_begin(GdkWindow * window,GList * targets)11416 gdk_drag_begin (GdkWindow *window,
11417 GList *targets)
11418 {
11419 GdkDisplay *display;
11420 GdkDevice *device;
11421
11422 display = gdk_window_get_display (window);
11423 device = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
11424
11425 return gdk_drag_begin_for_device (window, device, targets);
11426 }
11427
11428 /**
11429 * gdk_drag_begin_for_device:
11430 * @window: the source window for this drag
11431 * @device: the device that controls this drag
11432 * @targets: (transfer none) (element-type GdkAtom): the offered targets,
11433 * as list of #GdkAtoms
11434 *
11435 * Starts a drag and creates a new drag context for it.
11436 *
11437 * This function is called by the drag source.
11438 *
11439 * Returns: (transfer full): a newly created #GdkDragContext
11440 */
11441 GdkDragContext *
gdk_drag_begin_for_device(GdkWindow * window,GdkDevice * device,GList * targets)11442 gdk_drag_begin_for_device (GdkWindow *window,
11443 GdkDevice *device,
11444 GList *targets)
11445 {
11446 gint x, y;
11447
11448 gdk_device_get_position (device, NULL, &x, &y);
11449
11450 return gdk_drag_begin_from_point (window, device, targets, x, y);
11451 }
11452
11453 /**
11454 * gdk_drag_begin_from_point:
11455 * @window: the source window for this drag
11456 * @device: the device that controls this drag
11457 * @targets: (transfer none) (element-type GdkAtom): the offered targets,
11458 * as list of #GdkAtoms
11459 * @x_root: the x coordinate where the drag nominally started
11460 * @y_root: the y coordinate where the drag nominally started
11461 *
11462 * Starts a drag and creates a new drag context for it.
11463 *
11464 * This function is called by the drag source.
11465 *
11466 * Returns: (transfer full): a newly created #GdkDragContext
11467 *
11468 * Since: 3.20
11469 */
11470 GdkDragContext *
gdk_drag_begin_from_point(GdkWindow * window,GdkDevice * device,GList * targets,gint x_root,gint y_root)11471 gdk_drag_begin_from_point (GdkWindow *window,
11472 GdkDevice *device,
11473 GList *targets,
11474 gint x_root,
11475 gint y_root)
11476 {
11477 return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->drag_begin (window, device, targets, x_root, y_root);
11478 }
11479
11480 /**
11481 * gdk_test_render_sync:
11482 * @window: a mapped #GdkWindow
11483 *
11484 * Retrieves a pixel from @window to force the windowing
11485 * system to carry out any pending rendering commands.
11486 *
11487 * This function is intended to be used to synchronize with rendering
11488 * pipelines, to benchmark windowing system rendering operations.
11489 *
11490 * Since: 2.14
11491 **/
11492 void
gdk_test_render_sync(GdkWindow * window)11493 gdk_test_render_sync (GdkWindow *window)
11494 {
11495 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->sync_rendering (window);
11496 }
11497
11498 /**
11499 * gdk_test_simulate_key:
11500 * @window: a #GdkWindow to simulate a key event for
11501 * @x: x coordinate within @window for the key event
11502 * @y: y coordinate within @window for the key event
11503 * @keyval: A GDK keyboard value
11504 * @modifiers: Keyboard modifiers the event is setup with
11505 * @key_pressrelease: either %GDK_KEY_PRESS or %GDK_KEY_RELEASE
11506 *
11507 * This function is intended to be used in GTK+ test programs.
11508 * If (@x,@y) are > (-1,-1), it will warp the mouse pointer to
11509 * the given (@x,@y) coordinates within @window and simulate a
11510 * key press or release event.
11511 *
11512 * When the mouse pointer is warped to the target location, use
11513 * of this function outside of test programs that run in their
11514 * own virtual windowing system (e.g. Xvfb) is not recommended.
11515 * If (@x,@y) are passed as (-1,-1), the mouse pointer will not
11516 * be warped and @window origin will be used as mouse pointer
11517 * location for the event.
11518 *
11519 * Also, gdk_test_simulate_key() is a fairly low level function,
11520 * for most testing purposes, gtk_test_widget_send_key() is the
11521 * right function to call which will generate a key press event
11522 * followed by its accompanying key release event.
11523 *
11524 * Returns: whether all actions necessary for a key event simulation
11525 * were carried out successfully
11526 *
11527 * Since: 2.14
11528 */
11529 gboolean
gdk_test_simulate_key(GdkWindow * window,gint x,gint y,guint keyval,GdkModifierType modifiers,GdkEventType key_pressrelease)11530 gdk_test_simulate_key (GdkWindow *window,
11531 gint x,
11532 gint y,
11533 guint keyval,
11534 GdkModifierType modifiers,
11535 GdkEventType key_pressrelease)
11536 {
11537 return GDK_WINDOW_IMPL_GET_CLASS (window->impl)
11538 ->simulate_key (window, x, y, keyval, modifiers, key_pressrelease);
11539 }
11540
11541 /**
11542 * gdk_test_simulate_button:
11543 * @window: a #GdkWindow to simulate a button event for
11544 * @x: x coordinate within @window for the button event
11545 * @y: y coordinate within @window for the button event
11546 * @button: Number of the pointer button for the event, usually 1, 2 or 3
11547 * @modifiers: Keyboard modifiers the event is setup with
11548 * @button_pressrelease: either %GDK_BUTTON_PRESS or %GDK_BUTTON_RELEASE
11549 *
11550 * This function is intended to be used in GTK+ test programs.
11551 * It will warp the mouse pointer to the given (@x,@y) coordinates
11552 * within @window and simulate a button press or release event.
11553 * Because the mouse pointer needs to be warped to the target
11554 * location, use of this function outside of test programs that
11555 * run in their own virtual windowing system (e.g. Xvfb) is not
11556 * recommended.
11557 *
11558 * Also, gdk_test_simulate_button() is a fairly low level function,
11559 * for most testing purposes, gtk_test_widget_click() is the right
11560 * function to call which will generate a button press event followed
11561 * by its accompanying button release event.
11562 *
11563 * Returns: whether all actions necessary for a button event simulation
11564 * were carried out successfully
11565 *
11566 * Since: 2.14
11567 */
11568 gboolean
gdk_test_simulate_button(GdkWindow * window,gint x,gint y,guint button,GdkModifierType modifiers,GdkEventType button_pressrelease)11569 gdk_test_simulate_button (GdkWindow *window,
11570 gint x,
11571 gint y,
11572 guint button, /*1..3*/
11573 GdkModifierType modifiers,
11574 GdkEventType button_pressrelease)
11575 {
11576 return GDK_WINDOW_IMPL_GET_CLASS (window->impl)
11577 ->simulate_button (window, x, y, button, modifiers, button_pressrelease);
11578 }
11579
11580 /**
11581 * gdk_property_get:
11582 * @window: a #GdkWindow
11583 * @property: the property to retrieve
11584 * @type: the desired property type, or %GDK_NONE, if any type of data
11585 * is acceptable. If this does not match the actual
11586 * type, then @actual_format and @actual_length will
11587 * be filled in, a warning will be printed to stderr
11588 * and no data will be returned.
11589 * @offset: the offset into the property at which to begin
11590 * retrieving data, in 4 byte units.
11591 * @length: the length of the data to retrieve in bytes. Data is
11592 * considered to be retrieved in 4 byte chunks, so @length
11593 * will be rounded up to the next highest 4 byte boundary
11594 * (so be careful not to pass a value that might overflow
11595 * when rounded up).
11596 * @pdelete: if %TRUE, delete the property after retrieving the
11597 * data.
11598 * @actual_property_type: (out) (transfer none): location to store the
11599 * actual type of the property.
11600 * @actual_format: (out): location to store the actual return format of the
11601 * data; either 8, 16 or 32 bits.
11602 * @actual_length: location to store the length of the retrieved data, in
11603 * bytes. Data returned in the 32 bit format is stored
11604 * in a long variable, so the actual number of 32 bit
11605 * elements should be be calculated via
11606 * @actual_length / sizeof(glong) to ensure portability to
11607 * 64 bit systems.
11608 * @data: (out) (array length=actual_length) (transfer full): location
11609 * to store a pointer to the data. The retrieved data should be
11610 * freed with g_free() when you are finished using it.
11611 *
11612 * Retrieves a portion of the contents of a property. If the
11613 * property does not exist, then the function returns %FALSE,
11614 * and %GDK_NONE will be stored in @actual_property_type.
11615 *
11616 * The XGetWindowProperty() function that gdk_property_get()
11617 * uses has a very confusing and complicated set of semantics.
11618 * Unfortunately, gdk_property_get() makes the situation
11619 * worse instead of better (the semantics should be considered
11620 * undefined), and also prints warnings to stderr in cases where it
11621 * should return a useful error to the program. You are advised to use
11622 * XGetWindowProperty() directly until a replacement function for
11623 * gdk_property_get() is provided.
11624 *
11625 * Returns: %TRUE if data was successfully received and stored
11626 * in @data, otherwise %FALSE.
11627 */
11628 gboolean
gdk_property_get(GdkWindow * window,GdkAtom property,GdkAtom type,gulong offset,gulong length,gint pdelete,GdkAtom * actual_property_type,gint * actual_format_type,gint * actual_length,guchar ** data)11629 gdk_property_get (GdkWindow *window,
11630 GdkAtom property,
11631 GdkAtom type,
11632 gulong offset,
11633 gulong length,
11634 gint pdelete,
11635 GdkAtom *actual_property_type,
11636 gint *actual_format_type,
11637 gint *actual_length,
11638 guchar **data)
11639 {
11640 return GDK_WINDOW_IMPL_GET_CLASS (window->impl)
11641 ->get_property (window, property, type, offset, length, pdelete,
11642 actual_property_type, actual_format_type,
11643 actual_length, data);
11644 }
11645
11646 /**
11647 * gdk_property_change: (skip)
11648 * @window: a #GdkWindow
11649 * @property: the property to change
11650 * @type: the new type for the property. If @mode is
11651 * %GDK_PROP_MODE_PREPEND or %GDK_PROP_MODE_APPEND, then this
11652 * must match the existing type or an error will occur.
11653 * @format: the new format for the property. If @mode is
11654 * %GDK_PROP_MODE_PREPEND or %GDK_PROP_MODE_APPEND, then this
11655 * must match the existing format or an error will occur.
11656 * @mode: a value describing how the new data is to be combined
11657 * with the current data.
11658 * @data: the data (a `guchar *`
11659 * `gushort *`, or `gulong *`,
11660 * depending on @format), cast to a `guchar *`.
11661 * @nelements: the number of elements of size determined by the format,
11662 * contained in @data.
11663 *
11664 * Changes the contents of a property on a window.
11665 */
11666 void
gdk_property_change(GdkWindow * window,GdkAtom property,GdkAtom type,gint format,GdkPropMode mode,const guchar * data,gint nelements)11667 gdk_property_change (GdkWindow *window,
11668 GdkAtom property,
11669 GdkAtom type,
11670 gint format,
11671 GdkPropMode mode,
11672 const guchar *data,
11673 gint nelements)
11674 {
11675 GDK_WINDOW_IMPL_GET_CLASS (window->impl)
11676 ->change_property (window, property, type, format, mode, data, nelements);
11677 }
11678
11679 /**
11680 * gdk_property_delete:
11681 * @window: a #GdkWindow
11682 * @property: the property to delete
11683 *
11684 * Deletes a property from a window.
11685 */
11686 void
gdk_property_delete(GdkWindow * window,GdkAtom property)11687 gdk_property_delete (GdkWindow *window,
11688 GdkAtom property)
11689 {
11690 GDK_WINDOW_IMPL_GET_CLASS (window->impl)->delete_property (window, property);
11691 }
11692
11693 static void
gdk_window_flush_events(GdkFrameClock * clock,void * data)11694 gdk_window_flush_events (GdkFrameClock *clock,
11695 void *data)
11696 {
11697 GdkWindow *window;
11698 GdkDisplay *display;
11699
11700 window = GDK_WINDOW (data);
11701
11702 display = gdk_window_get_display (window);
11703 _gdk_event_queue_flush (display);
11704 _gdk_display_pause_events (display);
11705
11706 gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS);
11707
11708 window->frame_clock_events_paused = TRUE;
11709 }
11710
11711 static void
gdk_window_paint_on_clock(GdkFrameClock * clock,void * data)11712 gdk_window_paint_on_clock (GdkFrameClock *clock,
11713 void *data)
11714 {
11715 GdkWindow *window;
11716
11717 window = GDK_WINDOW (data);
11718
11719 /* Update window and any children on the same clock.
11720 */
11721 gdk_window_process_updates_with_mode (window, PROCESS_UPDATES_WITH_SAME_CLOCK_CHILDREN);
11722 }
11723
11724 static void
gdk_window_resume_events(GdkFrameClock * clock,void * data)11725 gdk_window_resume_events (GdkFrameClock *clock,
11726 void *data)
11727 {
11728 GdkWindow *window;
11729 GdkDisplay *display;
11730
11731 window = GDK_WINDOW (data);
11732
11733 display = gdk_window_get_display (window);
11734 _gdk_display_unpause_events (display);
11735
11736 window->frame_clock_events_paused = FALSE;
11737 }
11738
11739 static void
gdk_window_set_frame_clock(GdkWindow * window,GdkFrameClock * clock)11740 gdk_window_set_frame_clock (GdkWindow *window,
11741 GdkFrameClock *clock)
11742 {
11743 g_return_if_fail (GDK_IS_WINDOW (window));
11744 g_return_if_fail (clock == NULL || GDK_IS_FRAME_CLOCK (clock));
11745 g_return_if_fail (clock == NULL || gdk_window_is_toplevel (window));
11746
11747 if (clock == window->frame_clock)
11748 return;
11749
11750 if (clock)
11751 {
11752 g_object_ref (clock);
11753 g_signal_connect (G_OBJECT (clock),
11754 "flush-events",
11755 G_CALLBACK (gdk_window_flush_events),
11756 window);
11757 g_signal_connect (G_OBJECT (clock),
11758 "paint",
11759 G_CALLBACK (gdk_window_paint_on_clock),
11760 window);
11761 g_signal_connect (G_OBJECT (clock),
11762 "resume-events",
11763 G_CALLBACK (gdk_window_resume_events),
11764 window);
11765 }
11766
11767 if (window->frame_clock)
11768 {
11769 if (window->frame_clock_events_paused)
11770 gdk_window_resume_events (window->frame_clock, G_OBJECT (window));
11771
11772 g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock),
11773 G_CALLBACK (gdk_window_flush_events),
11774 window);
11775 g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock),
11776 G_CALLBACK (gdk_window_paint_on_clock),
11777 window);
11778 g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock),
11779 G_CALLBACK (gdk_window_resume_events),
11780 window);
11781 g_object_unref (window->frame_clock);
11782 }
11783
11784 window->frame_clock = clock;
11785 }
11786
11787 /**
11788 * gdk_window_get_frame_clock:
11789 * @window: window to get frame clock for
11790 *
11791 * Gets the frame clock for the window. The frame clock for a window
11792 * never changes unless the window is reparented to a new toplevel
11793 * window.
11794 *
11795 * Since: 3.8
11796 * Returns: (transfer none): the frame clock
11797 */
11798 GdkFrameClock*
gdk_window_get_frame_clock(GdkWindow * window)11799 gdk_window_get_frame_clock (GdkWindow *window)
11800 {
11801 GdkWindow *toplevel;
11802
11803 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
11804
11805 toplevel = gdk_window_get_toplevel (window);
11806
11807 return toplevel->frame_clock;
11808 }
11809
11810 /**
11811 * gdk_window_get_scale_factor:
11812 * @window: window to get scale factor for
11813 *
11814 * Returns the internal scale factor that maps from window coordiantes
11815 * to the actual device pixels. On traditional systems this is 1, but
11816 * on very high density outputs this can be a higher value (often 2).
11817 *
11818 * A higher value means that drawing is automatically scaled up to
11819 * a higher resolution, so any code doing drawing will automatically look
11820 * nicer. However, if you are supplying pixel-based data the scale
11821 * value can be used to determine whether to use a pixel resource
11822 * with higher resolution data.
11823 *
11824 * The scale of a window may change during runtime, if this happens
11825 * a configure event will be sent to the toplevel window.
11826 *
11827 * Since: 3.10
11828 * Returns: the scale factor
11829 */
11830 gint
gdk_window_get_scale_factor(GdkWindow * window)11831 gdk_window_get_scale_factor (GdkWindow *window)
11832 {
11833 GdkWindowImplClass *impl_class;
11834
11835 g_return_val_if_fail (GDK_IS_WINDOW (window), 1);
11836
11837 if (GDK_WINDOW_DESTROYED (window))
11838 return 1;
11839
11840 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
11841
11842 if (impl_class->get_scale_factor)
11843 return impl_class->get_scale_factor (window);
11844
11845 return 1;
11846 }
11847
11848 /* Returns the *real* unscaled size, which may be a fractional size
11849 in window scale coordinates. We need this to properly handle GL
11850 coordinates which are y-flipped in the real coordinates. */
11851 void
gdk_window_get_unscaled_size(GdkWindow * window,int * unscaled_width,int * unscaled_height)11852 gdk_window_get_unscaled_size (GdkWindow *window,
11853 int *unscaled_width,
11854 int *unscaled_height)
11855 {
11856 GdkWindowImplClass *impl_class;
11857 gint scale;
11858
11859 g_return_if_fail (GDK_IS_WINDOW (window));
11860
11861 if (window->impl_window == window)
11862 {
11863 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
11864
11865 if (impl_class->get_unscaled_size)
11866 {
11867 impl_class->get_unscaled_size (window, unscaled_width, unscaled_height);
11868 return;
11869 }
11870 }
11871
11872 scale = gdk_window_get_scale_factor (window);
11873
11874 if (unscaled_width)
11875 *unscaled_width = window->width * scale;
11876
11877 if (unscaled_height)
11878 *unscaled_height = window->height * scale;
11879 }
11880
11881
11882 /**
11883 * gdk_window_set_opaque_region:
11884 * @window: a top-level or non-native #GdkWindow
11885 * @region: (allow-none): a region, or %NULL
11886 *
11887 * For optimisation purposes, compositing window managers may
11888 * like to not draw obscured regions of windows, or turn off blending
11889 * during for these regions. With RGB windows with no transparency,
11890 * this is just the shape of the window, but with ARGB32 windows, the
11891 * compositor does not know what regions of the window are transparent
11892 * or not.
11893 *
11894 * This function only works for toplevel windows.
11895 *
11896 * GTK+ will update this property automatically if
11897 * the @window background is opaque, as we know where the opaque regions
11898 * are. If your window background is not opaque, please update this
11899 * property in your #GtkWidget::style-updated handler.
11900 *
11901 * Since: 3.10
11902 */
11903 void
gdk_window_set_opaque_region(GdkWindow * window,cairo_region_t * region)11904 gdk_window_set_opaque_region (GdkWindow *window,
11905 cairo_region_t *region)
11906 {
11907 GdkWindowImplClass *impl_class;
11908
11909 g_return_if_fail (GDK_IS_WINDOW (window));
11910 g_return_if_fail (!GDK_WINDOW_DESTROYED (window));
11911
11912 if (cairo_region_equal (window->opaque_region, region))
11913 return;
11914
11915 g_clear_pointer (&window->opaque_region, cairo_region_destroy);
11916
11917 if (region != NULL)
11918 window->opaque_region = cairo_region_reference (region);
11919
11920 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
11921
11922 if (impl_class->set_opaque_region)
11923 impl_class->set_opaque_region (window, region);
11924 }
11925
11926 /**
11927 * gdk_window_set_shadow_width:
11928 * @window: a #GdkWindow
11929 * @left: The left extent
11930 * @right: The right extent
11931 * @top: The top extent
11932 * @bottom: The bottom extent
11933 *
11934 * Newer GTK+ windows using client-side decorations use extra geometry
11935 * around their frames for effects like shadows and invisible borders.
11936 * Window managers that want to maximize windows or snap to edges need
11937 * to know where the extents of the actual frame lie, so that users
11938 * don’t feel like windows are snapping against random invisible edges.
11939 *
11940 * Note that this property is automatically updated by GTK+, so this
11941 * function should only be used by applications which do not use GTK+
11942 * to create toplevel windows.
11943 *
11944 * Since: 3.12
11945 */
11946 void
gdk_window_set_shadow_width(GdkWindow * window,gint left,gint right,gint top,gint bottom)11947 gdk_window_set_shadow_width (GdkWindow *window,
11948 gint left,
11949 gint right,
11950 gint top,
11951 gint bottom)
11952 {
11953 GdkWindowImplClass *impl_class;
11954
11955 g_return_if_fail (GDK_IS_WINDOW (window));
11956 g_return_if_fail (!GDK_WINDOW_DESTROYED (window));
11957 g_return_if_fail (left >= 0 && right >= 0 && top >= 0 && bottom >= 0);
11958
11959 window->shadow_top = top;
11960 window->shadow_left = left;
11961 window->shadow_right = right;
11962 window->shadow_bottom = bottom;
11963
11964 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
11965
11966 if (impl_class->set_shadow_width)
11967 impl_class->set_shadow_width (window, left, right, top, bottom);
11968 }
11969
11970 /**
11971 * gdk_window_show_window_menu:
11972 * @window: a #GdkWindow
11973 * @event: a #GdkEvent to show the menu for
11974 *
11975 * Asks the windowing system to show the window menu. The window menu
11976 * is the menu shown when right-clicking the titlebar on traditional
11977 * windows managed by the window manager. This is useful for windows
11978 * using client-side decorations, activating it with a right-click
11979 * on the window decorations.
11980 *
11981 * Returns: %TRUE if the window menu was shown and %FALSE otherwise.
11982 *
11983 * Since: 3.14
11984 */
11985 gboolean
gdk_window_show_window_menu(GdkWindow * window,GdkEvent * event)11986 gdk_window_show_window_menu (GdkWindow *window,
11987 GdkEvent *event)
11988 {
11989 GdkWindowImplClass *impl_class;
11990
11991 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
11992 g_return_val_if_fail (!GDK_WINDOW_DESTROYED (window), FALSE);
11993
11994 impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
11995
11996 if (impl_class->show_window_menu)
11997 return impl_class->show_window_menu (window, event);
11998 else
11999 return FALSE;
12000 }
12001