 54dc823d67
			
		
	
	54dc823d67
	
	
	
		
			
			and gdk_window_get_fullscreen_mode() API to allow applications to specify if a fullscreen window should span across all monitors in a multi-monitor setup or remain on the current monitor where the window is placed. Fullscreen mode can be either GDK_FULLSCREEN_ON_ALL_MONITORS or GDK_FULLSCREEN_ON_CURRENT_MONITOR. https://bugzilla.gnome.org/show_bug.cgi?id=691856
		
			
				
	
	
		
			11435 lines
		
	
	
		
			340 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			11435 lines
		
	
	
		
			340 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* GDK - The GIMP Drawing Kit
 | |
|  * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
 | |
|  * Josh MacDonald, Ryan Lortie
 | |
|  *
 | |
|  * This library is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU Lesser General Public
 | |
|  * License as published by the Free Software Foundation; either
 | |
|  * version 2 of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This library is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * Lesser General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Lesser General Public
 | |
|  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
 | |
|  * file for a list of people on the GTK+ Team.  See the ChangeLog
 | |
|  * files for a list of changes.  These files are distributed with
 | |
|  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
 | |
|  */
 | |
| 
 | |
| #include "config.h"
 | |
| 
 | |
| #include <cairo-gobject.h>
 | |
| 
 | |
| #include "gdkwindow.h"
 | |
| 
 | |
| #include "gdkrectangle.h"
 | |
| #include "gdkinternals.h"
 | |
| #include "gdkintl.h"
 | |
| #include "gdkscreenprivate.h"
 | |
| #include "gdkdisplayprivate.h"
 | |
| #include "gdkdeviceprivate.h"
 | |
| #include "gdkvisualprivate.h"
 | |
| #include "gdkmarshalers.h"
 | |
| #include "gdkwindowimpl.h"
 | |
| 
 | |
| #include <math.h>
 | |
| 
 | |
| #undef DEBUG_WINDOW_PRINTING
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * SECTION:windows
 | |
|  * @Short_description: Onscreen display areas in the target window system
 | |
|  * @Title: Windows
 | |
|  *
 | |
|  * A #GdkWindow is a (usually) rectangular region on the screen.
 | |
|  * It's a low-level object, used to implement high-level objects such as
 | |
|  * #GtkWidget and #GtkWindow on the GTK+ level. A #GtkWindow is a toplevel
 | |
|  * window, the thing a user might think of as a "window" with a titlebar and
 | |
|  * so on; a #GtkWindow may contain many #GdkWindows. For example, each
 | |
|  * #GtkButton has a #GdkWindow associated with it.
 | |
|  *
 | |
|  * <refsect2 id="COMPOSITED-WINDOWS">
 | |
|  * <title>Composited Windows</title>
 | |
|  * <para>
 | |
|  * Normally, the windowing system takes care of rendering the contents of a
 | |
|  * child window onto its parent window. This mechanism can be intercepted by
 | |
|  * calling gdk_window_set_composited() on the child window. For a
 | |
|  * <firstterm>composited</firstterm> window it is the responsibility of the
 | |
|  * application to render the window contents at the right spot.
 | |
|  * </para>
 | |
|  * </refsect2>
 | |
|  * <refsect2 id="OFFSCREEN-WINDOWS">
 | |
|  * <title>Offscreen Windows</title>
 | |
|  * <para>
 | |
|  * Offscreen windows are more general than composited windows, since they allow
 | |
|  * not only to modify the rendering of the child window onto its parent, but
 | |
|  * also to apply coordinate transformations.
 | |
|  *
 | |
|  * To integrate an offscreen window into a window hierarchy, one has to call
 | |
|  * gdk_offscreen_window_set_embedder() and handle a number of signals. The
 | |
|  * #GdkWindow::pick-embedded-child signal on the embedder window is used to
 | |
|  * select an offscreen child at given coordinates, and the
 | |
|  * #GdkWindow::to-embedder and #GdkWindow::from-embedder signals on the
 | |
|  * offscreen window are used to translate coordinates between the embedder and
 | |
|  * the offscreen window.
 | |
|  *
 | |
|  * For rendering an offscreen window onto its embedder, the contents of the
 | |
|  * offscreen window are available as a surface, via
 | |
|  * gdk_offscreen_window_get_surface().
 | |
|  * </para>
 | |
|  * </refsect2>
 | |
|  */
 | |
| 
 | |
| 
 | |
| /* Historically a GdkWindow always matches a platform native window,
 | |
|  * be it a toplevel window or a child window. In this setup the
 | |
|  * GdkWindow (and other GdkDrawables) were platform independent classes,
 | |
|  * and the actual platform specific implementation was in a delegate
 | |
|  * object available as "impl" in the window object.
 | |
|  *
 | |
|  * With the addition of client side windows and offscreen windows this
 | |
|  * changes a bit. The application-visible GdkWindow object behaves as
 | |
|  * it did before, but not all such windows now have a corresponding native
 | |
|  * window. Instead windows that are "client side" are emulated by the gdk
 | |
|  * code such that clipping, drawing, moving, events etc work as expected.
 | |
|  *
 | |
|  * For GdkWindows that have a native window the "impl" object is the
 | |
|  * same as before. However, for all client side windows the impl object
 | |
|  * is shared with its parent (i.e. all client windows descendants of one
 | |
|  * native window has the same impl.
 | |
|  *
 | |
|  * Additionally there is a new type of platform independent impl object,
 | |
|  * GdkOffscreenWindow. All windows of type GDK_WINDOW_OFFSCREEN get an impl
 | |
|  * of this type (while their children are generally GDK_WINDOW_CHILD virtual
 | |
|  * windows). Such windows work by allocating a #cairo_surface_t as the backing
 | |
|  * store for drawing operations, which is resized with the window.
 | |
|  *
 | |
|  * GdkWindows have a pointer to the "impl window" they are in, i.e.
 | |
|  * the topmost GdkWindow which have the same "impl" value. This is stored
 | |
|  * in impl_window, which is different from the window itself only for client
 | |
|  * side windows.
 | |
|  * All GdkWindows (native or not) track the position of the window in the parent
 | |
|  * (x, y), the size of the window (width, height), the position of the window
 | |
|  * with respect to the impl window (abs_x, abs_y). We also track the clip
 | |
|  * region of the window wrt parent windows and siblings, in window-relative
 | |
|  * coordinates with and without child windows included (clip_region,
 | |
|  * clip_region_with_children).
 | |
|  *
 | |
|  * All toplevel windows are native windows, but also child windows can be
 | |
|  * native (although not children of offscreens). We always listen to
 | |
|  * a basic set of events (see get_native_event_mask) for these windows
 | |
|  * so that we can emulate events for any client side children.
 | |
|  *
 | |
|  * For native windows we apply the calculated clip region as a window shape
 | |
|  * so that eg. client side siblings that overlap the native child properly
 | |
|  * draws over the native child window.
 | |
|  *
 | |
|  * In order to minimize flicker and for performance we use a couple of cacheing
 | |
|  * tricks. First of all, every time we do a window to window copy area, for instance
 | |
|  * when moving a client side window or when scrolling/moving a region in a window
 | |
|  * we store this in outstanding_moves instead of applying immediately. We then
 | |
|  * delay this move until we really need it (because something depends on being
 | |
|  * able to read it), or until we're handing a redraw from an expose/invalidation
 | |
|  * (actually we delay it past redraw, but before blitting the double buffer
 | |
|  * to the window). This gives us two advantages. First of all it minimizes the time
 | |
|  * from the window is moved to the exposes related to that move, secondly it allows
 | |
|  * us to be smart about how to do the copy. We combine multiple moves into one (when
 | |
|  * possible) and we don't actually do copies to anything that is or will be
 | |
|  * invalidated and exposed anyway.
 | |
|  *
 | |
|  * Secondly, we use something called a "implicit paint" during repaint handling.
 | |
|  * An implicit paint is similar to a regular paint for the paint stack, but it is
 | |
|  * not put on the stack. Instead, it is set on the impl window, and later when
 | |
|  * regular gdk_window_begin_paint_region()  happen on a window of this impl window
 | |
|  * we reuse the surface from the implicit paint. During repaint we create and at the
 | |
|  * end flush an implicit paint, which means we can collect all the paints on
 | |
|  * multiple client side windows in the same backing store.
 | |
|  */
 | |
| 
 | |
| #define USE_BACKING_STORE	/* Appears to work on Win32, too, now. */
 | |
| 
 | |
| /* This adds a local value to the GdkVisibilityState enum */
 | |
| #define GDK_VISIBILITY_NOT_VIEWABLE 3
 | |
| 
 | |
| enum {
 | |
|   PICK_EMBEDDED_CHILD, /* only called if children are embedded */
 | |
|   TO_EMBEDDER,
 | |
|   FROM_EMBEDDER,
 | |
|   CREATE_SURFACE,
 | |
|   LAST_SIGNAL
 | |
| };
 | |
| 
 | |
| enum {
 | |
|   PROP_0,
 | |
|   PROP_CURSOR
 | |
| };
 | |
| 
 | |
| typedef enum {
 | |
|   CLEAR_BG_NONE,
 | |
|   CLEAR_BG_WINCLEARED, /* Clear backgrounds except those that the window system clears */
 | |
|   CLEAR_BG_ALL
 | |
| } ClearBg;
 | |
| 
 | |
| struct _GdkWindowPaint
 | |
| {
 | |
|   cairo_region_t *region;
 | |
|   cairo_surface_t *surface;
 | |
|   cairo_region_t *flushed;
 | |
|   guint uses_implicit : 1;
 | |
| };
 | |
| 
 | |
| typedef struct {
 | |
|   cairo_region_t *dest_region; /* The destination region */
 | |
|   int dx, dy; /* The amount that the source was moved to reach dest_region */
 | |
| } GdkWindowRegionMove;
 | |
| 
 | |
| /* Global info */
 | |
| 
 | |
| static void             gdk_window_drop_cairo_surface (GdkWindow *private);
 | |
| 
 | |
| static void gdk_window_free_paint_stack (GdkWindow *window);
 | |
| 
 | |
| static void gdk_window_finalize   (GObject              *object);
 | |
| 
 | |
| static void gdk_window_set_property (GObject      *object,
 | |
|                                      guint         prop_id,
 | |
|                                      const GValue *value,
 | |
|                                      GParamSpec   *pspec);
 | |
| static void gdk_window_get_property (GObject      *object,
 | |
|                                      guint         prop_id,
 | |
|                                      GValue       *value,
 | |
|                                      GParamSpec   *pspec);
 | |
| 
 | |
| static void gdk_window_clear_backing_region (GdkWindow *window,
 | |
| 					     cairo_region_t *region);
 | |
| 
 | |
| static void recompute_visible_regions   (GdkWindow *private,
 | |
| 					 gboolean recalculate_siblings,
 | |
| 					 gboolean recalculate_children);
 | |
| static void gdk_window_flush_outstanding_moves (GdkWindow *window);
 | |
| static void gdk_window_flush_recursive  (GdkWindow *window);
 | |
| static void do_move_region_bits_on_impl (GdkWindow *window,
 | |
| 					 cairo_region_t *region, /* In impl window coords */
 | |
| 					 int dx, int dy);
 | |
| static void gdk_window_invalidate_in_parent (GdkWindow *private);
 | |
| static void move_native_children        (GdkWindow *private);
 | |
| static void update_cursor               (GdkDisplay *display,
 | |
|                                          GdkDevice  *device);
 | |
| static void impl_window_add_update_area (GdkWindow *impl_window,
 | |
| 					 cairo_region_t *region);
 | |
| static void gdk_window_region_move_free (GdkWindowRegionMove *move);
 | |
| static void gdk_window_invalidate_region_full (GdkWindow       *window,
 | |
| 					       const cairo_region_t *region,
 | |
| 					       gboolean         invalidate_children,
 | |
| 					       ClearBg          clear_bg);
 | |
| static void gdk_window_invalidate_rect_full (GdkWindow          *window,
 | |
| 					     const GdkRectangle *rect,
 | |
| 					     gboolean            invalidate_children,
 | |
| 					     ClearBg             clear_bg);
 | |
| static void _gdk_window_propagate_has_alpha_background (GdkWindow *window);
 | |
| static cairo_surface_t *gdk_window_ref_impl_surface (GdkWindow *window);
 | |
| 
 | |
| static guint signals[LAST_SIGNAL] = { 0 };
 | |
| 
 | |
| static gpointer parent_class = NULL;
 | |
| 
 | |
| static const cairo_user_data_key_t gdk_window_cairo_key;
 | |
| 
 | |
| G_DEFINE_ABSTRACT_TYPE (GdkWindow, gdk_window, G_TYPE_OBJECT)
 | |
| 
 | |
| #ifdef DEBUG_WINDOW_PRINTING
 | |
| char *
 | |
| print_region (cairo_region_t *region)
 | |
| {
 | |
|   GString *s = g_string_new ("{");
 | |
|   if (cairo_region_is_empty (region))
 | |
|     {
 | |
|       g_string_append (s, "empty");
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       int num = cairo_region_num_rectangles (region);
 | |
|       cairo_rectangle_int_t r;
 | |
| 
 | |
|       if (num == 1)
 | |
| 	{
 | |
| 	  cairo_region_get_rectangle (region, 0, &r);
 | |
| 	  g_string_append_printf (s, "%dx%d @%d,%d", r.width, r.height, r.x, r.y);
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  cairo_region_get_extents (region, &r);
 | |
| 	  g_string_append_printf (s, "extent: %dx%d @%d,%d, details: ", r.width, r.height, r.x, r.y);
 | |
| 	  for (int i = 0; i < num; i++)
 | |
| 	    {
 | |
| 	      g_string_append_printf (s, "[%dx%d @%d,%d]", r.width, r.height, r.x, r.y);
 | |
| 	      if (i != num -1)
 | |
| 		g_string_append (s, ", ");
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|   g_string_append (s, "}");
 | |
|   return g_string_free (s, FALSE);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| GType
 | |
| _gdk_paintable_get_type (void)
 | |
| {
 | |
|   static GType paintable_type = 0;
 | |
| 
 | |
|   if (!paintable_type)
 | |
|     {
 | |
|       const GTypeInfo paintable_info =
 | |
|       {
 | |
| 	sizeof (GdkPaintableIface),  /* class_size */
 | |
| 	NULL,                        /* base_init */
 | |
| 	NULL,                        /* base_finalize */
 | |
|       };
 | |
| 
 | |
|       paintable_type = g_type_register_static (G_TYPE_INTERFACE,
 | |
| 					       g_intern_static_string ("GdkPaintable"),
 | |
| 					       &paintable_info, 0);
 | |
| 
 | |
|       g_type_interface_add_prerequisite (paintable_type, G_TYPE_OBJECT);
 | |
|     }
 | |
| 
 | |
|   return paintable_type;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_init (GdkWindow *window)
 | |
| {
 | |
|   /* 0-initialization is good for all other fields. */
 | |
| 
 | |
|   window->window_type = GDK_WINDOW_CHILD;
 | |
| 
 | |
|   window->state = GDK_WINDOW_STATE_WITHDRAWN;
 | |
|   window->fullscreen_mode = GDK_FULLSCREEN_ON_CURRENT_MONITOR;
 | |
|   window->width = 1;
 | |
|   window->height = 1;
 | |
|   window->toplevel_window_type = -1;
 | |
|   /* starts hidden */
 | |
|   window->effective_visibility = GDK_VISIBILITY_NOT_VIEWABLE;
 | |
|   window->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
 | |
|   /* Default to unobscured since some backends don't send visibility events */
 | |
|   window->native_visibility = GDK_VISIBILITY_UNOBSCURED;
 | |
| 
 | |
|   window->device_cursor = g_hash_table_new_full (NULL, NULL,
 | |
|                                                  NULL, g_object_unref);
 | |
| }
 | |
| 
 | |
| /* Stop and return on the first non-NULL parent */
 | |
| static gboolean
 | |
| accumulate_get_window (GSignalInvocationHint *ihint,
 | |
| 		       GValue		       *return_accu,
 | |
| 		       const GValue	       *handler_return,
 | |
| 		       gpointer               data)
 | |
| {
 | |
|   g_value_copy (handler_return, return_accu);
 | |
|   /* Continue while returning NULL */
 | |
|   return g_value_get_object (handler_return) == NULL;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| create_surface_accumulator (GSignalInvocationHint *ihint,
 | |
|                             GValue                *return_accu,
 | |
|                             const GValue          *handler_return,
 | |
|                             gpointer               data)
 | |
| {
 | |
|   g_value_copy (handler_return, return_accu);
 | |
| 
 | |
|   /* Stop on the first non-NULL return value */
 | |
|   return g_value_get_boxed (handler_return) == NULL;
 | |
| }
 | |
| 
 | |
| static GQuark quark_pointer_window = 0;
 | |
| 
 | |
| static void
 | |
| gdk_window_class_init (GdkWindowClass *klass)
 | |
| {
 | |
|   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | |
| 
 | |
|   parent_class = g_type_class_peek_parent (klass);
 | |
| 
 | |
|   object_class->finalize = gdk_window_finalize;
 | |
|   object_class->set_property = gdk_window_set_property;
 | |
|   object_class->get_property = gdk_window_get_property;
 | |
| 
 | |
|   klass->create_surface = _gdk_offscreen_window_create_surface;
 | |
| 
 | |
|   quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window");
 | |
| 
 | |
| 
 | |
|   /* Properties */
 | |
| 
 | |
|   /**
 | |
|    * GdkWindow:cursor:
 | |
|    *
 | |
|    * The mouse pointer for a #GdkWindow. See gdk_window_set_cursor() and
 | |
|    * gdk_window_get_cursor() for details.
 | |
|    *
 | |
|    * Since: 2.18
 | |
|    */
 | |
|   g_object_class_install_property (object_class,
 | |
|                                    PROP_CURSOR,
 | |
|                                    g_param_spec_object ("cursor",
 | |
|                                                         P_("Cursor"),
 | |
|                                                         P_("Cursor"),
 | |
|                                                         GDK_TYPE_CURSOR,
 | |
|                                                         G_PARAM_READWRITE));
 | |
| 
 | |
|   /**
 | |
|    * GdkWindow::pick-embedded-child:
 | |
|    * @window: the window on which the signal is emitted
 | |
|    * @x: x coordinate in the window
 | |
|    * @y: y coordinate in the window
 | |
|    *
 | |
|    * The ::pick-embedded-child signal is emitted to find an embedded
 | |
|    * child at the given position.
 | |
|    *
 | |
|    * Returns: (transfer none): the #GdkWindow of the embedded child at
 | |
|    *     @x, @y, or %NULL
 | |
|    *
 | |
|    * Since: 2.18
 | |
|    */
 | |
|   signals[PICK_EMBEDDED_CHILD] =
 | |
|     g_signal_new (g_intern_static_string ("pick-embedded-child"),
 | |
| 		  G_OBJECT_CLASS_TYPE (object_class),
 | |
| 		  G_SIGNAL_RUN_LAST,
 | |
|                   G_STRUCT_OFFSET (GdkWindowClass, pick_embedded_child),
 | |
| 		  accumulate_get_window, NULL,
 | |
| 		  _gdk_marshal_OBJECT__DOUBLE_DOUBLE,
 | |
| 		  GDK_TYPE_WINDOW,
 | |
| 		  2,
 | |
| 		  G_TYPE_DOUBLE,
 | |
| 		  G_TYPE_DOUBLE);
 | |
| 
 | |
|   /**
 | |
|    * GdkWindow::to-embedder:
 | |
|    * @window: the offscreen window on which the signal is emitted
 | |
|    * @offscreen_x: x coordinate in the offscreen window
 | |
|    * @offscreen_y: y coordinate in the offscreen window
 | |
|    * @embedder_x: (out) (type double): return location for the x
 | |
|    *     coordinate in the embedder window
 | |
|    * @embedder_y: (out) (type double): return location for the y
 | |
|    *     coordinate in the embedder window
 | |
|    *
 | |
|    * The ::to-embedder signal is emitted to translate coordinates
 | |
|    * in an offscreen window to its embedder.
 | |
|    *
 | |
|    * See also #GtkWindow::from-embedder.
 | |
|    *
 | |
|    * Since: 2.18
 | |
|    */
 | |
|   signals[TO_EMBEDDER] =
 | |
|     g_signal_new (g_intern_static_string ("to-embedder"),
 | |
| 		  G_OBJECT_CLASS_TYPE (object_class),
 | |
| 		  G_SIGNAL_RUN_LAST,
 | |
|                   G_STRUCT_OFFSET (GdkWindowClass, to_embedder),
 | |
| 		  NULL, NULL,
 | |
| 		  _gdk_marshal_VOID__DOUBLE_DOUBLE_POINTER_POINTER,
 | |
| 		  G_TYPE_NONE,
 | |
| 		  4,
 | |
| 		  G_TYPE_DOUBLE,
 | |
| 		  G_TYPE_DOUBLE,
 | |
| 		  G_TYPE_POINTER,
 | |
| 		  G_TYPE_POINTER);
 | |
| 
 | |
|   /**
 | |
|    * GdkWindow::from-embedder:
 | |
|    * @window: the offscreen window on which the signal is emitted
 | |
|    * @embedder_x: x coordinate in the embedder window
 | |
|    * @embedder_y: y coordinate in the embedder window
 | |
|    * @offscreen_x: (out) (type double): return location for the x
 | |
|    *     coordinate in the offscreen window
 | |
|    * @offscreen_y: (out) (type double): return location for the y
 | |
|    *     coordinate in the offscreen window
 | |
|    *
 | |
|    * The ::from-embedder signal is emitted to translate coordinates
 | |
|    * in the embedder of an offscreen window to the offscreen window.
 | |
|    *
 | |
|    * See also #GtkWindow::to-embedder.
 | |
|    *
 | |
|    * Since: 2.18
 | |
|    */
 | |
|   signals[FROM_EMBEDDER] =
 | |
|     g_signal_new (g_intern_static_string ("from-embedder"),
 | |
| 		  G_OBJECT_CLASS_TYPE (object_class),
 | |
| 		  G_SIGNAL_RUN_LAST,
 | |
|                   G_STRUCT_OFFSET (GdkWindowClass, from_embedder),
 | |
| 		  NULL, NULL,
 | |
| 		  _gdk_marshal_VOID__DOUBLE_DOUBLE_POINTER_POINTER,
 | |
| 		  G_TYPE_NONE,
 | |
| 		  4,
 | |
| 		  G_TYPE_DOUBLE,
 | |
| 		  G_TYPE_DOUBLE,
 | |
| 		  G_TYPE_POINTER,
 | |
| 		  G_TYPE_POINTER);
 | |
| 
 | |
|   /**
 | |
|    * GdkWindow::create-surface:
 | |
|    * @window: the offscreen window on which the signal is emitted
 | |
|    * @width: the width of the offscreen surface to create
 | |
|    * @height: the height of the offscreen surface to create
 | |
|    *
 | |
|    * The ::create-surface signal is emitted when an offscreen window
 | |
|    * needs its surface (re)created, which happens either when the the
 | |
|    * window is first drawn to, or when the window is being
 | |
|    * resized. The first signal handler that returns a non-%NULL
 | |
|    * surface will stop any further signal emission, and its surface
 | |
|    * will be used.
 | |
|    *
 | |
|    * Note that it is not possible to access the window's previous
 | |
|    * surface from within any callback of this signal. Calling
 | |
|    * gdk_offscreen_window_get_surface() will lead to a crash.
 | |
|    *
 | |
|    * Returns: the newly created #cairo_surface_t for the offscreen window
 | |
|    *
 | |
|    * Since: 3.0
 | |
|    */
 | |
|   signals[CREATE_SURFACE] =
 | |
|     g_signal_new (g_intern_static_string ("create-surface"),
 | |
|                   G_OBJECT_CLASS_TYPE (object_class),
 | |
|                   G_SIGNAL_RUN_LAST,
 | |
|                   G_STRUCT_OFFSET (GdkWindowClass, create_surface),
 | |
|                   create_surface_accumulator, NULL,
 | |
|                   _gdk_marshal_BOXED__INT_INT,
 | |
|                   CAIRO_GOBJECT_TYPE_SURFACE,
 | |
|                   2,
 | |
|                   G_TYPE_INT,
 | |
|                   G_TYPE_INT);
 | |
| }
 | |
| 
 | |
| static void
 | |
| device_removed_cb (GdkDeviceManager *device_manager,
 | |
|                    GdkDevice        *device,
 | |
|                    GdkWindow        *window)
 | |
| {
 | |
|   window->devices_inside = g_list_remove (window->devices_inside, device);
 | |
|   g_hash_table_remove (window->device_cursor, device);
 | |
| 
 | |
|   if (window->device_events)
 | |
|     g_hash_table_remove (window->device_events, device);
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_finalize (GObject *object)
 | |
| {
 | |
|   GdkWindow *window = GDK_WINDOW (object);
 | |
|   GdkDeviceManager *device_manager;
 | |
| 
 | |
|   device_manager = gdk_display_get_device_manager (gdk_window_get_display (window));
 | |
|   g_signal_handlers_disconnect_by_func (device_manager, device_removed_cb, window);
 | |
| 
 | |
|   if (!GDK_WINDOW_DESTROYED (window))
 | |
|     {
 | |
|       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
 | |
| 	{
 | |
| 	  g_warning ("losing last reference to undestroyed window\n");
 | |
| 	  _gdk_window_destroy (window, FALSE);
 | |
| 	}
 | |
|       else
 | |
| 	/* We use TRUE here, to keep us from actually calling
 | |
| 	 * XDestroyWindow() on the window
 | |
| 	 */
 | |
| 	_gdk_window_destroy (window, TRUE);
 | |
|     }
 | |
| 
 | |
|   gdk_window_drop_cairo_surface (window);
 | |
| 
 | |
|   if (window->impl)
 | |
|     {
 | |
|       g_object_unref (window->impl);
 | |
|       window->impl = NULL;
 | |
|     }
 | |
| 
 | |
|   if (window->impl_window != window)
 | |
|     {
 | |
|       g_object_unref (window->impl_window);
 | |
|       window->impl_window = NULL;
 | |
|     }
 | |
| 
 | |
|   if (window->shape)
 | |
|     cairo_region_destroy (window->shape);
 | |
| 
 | |
|   if (window->input_shape)
 | |
|     cairo_region_destroy (window->input_shape);
 | |
| 
 | |
|   if (window->cursor)
 | |
|     g_object_unref (window->cursor);
 | |
| 
 | |
|   if (window->device_cursor)
 | |
|     g_hash_table_destroy (window->device_cursor);
 | |
| 
 | |
|   if (window->device_events)
 | |
|     g_hash_table_destroy (window->device_events);
 | |
| 
 | |
|   if (window->source_event_masks)
 | |
|     g_hash_table_destroy (window->source_event_masks);
 | |
| 
 | |
|   if (window->devices_inside)
 | |
|     g_list_free (window->devices_inside);
 | |
| 
 | |
|   if (window->layered_region)
 | |
|       cairo_region_destroy (window->layered_region);
 | |
| 
 | |
|   G_OBJECT_CLASS (parent_class)->finalize (object);
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_set_property (GObject      *object,
 | |
|                          guint         prop_id,
 | |
|                          const GValue *value,
 | |
|                          GParamSpec   *pspec)
 | |
| {
 | |
|   GdkWindow *window = (GdkWindow *)object;
 | |
| 
 | |
|   switch (prop_id)
 | |
|     {
 | |
|     case PROP_CURSOR:
 | |
|       gdk_window_set_cursor (window, g_value_get_object (value));
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | |
|       break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_get_property (GObject    *object,
 | |
|                          guint       prop_id,
 | |
|                          GValue     *value,
 | |
|                          GParamSpec *pspec)
 | |
| {
 | |
|   GdkWindow *window = (GdkWindow *) object;
 | |
| 
 | |
|   switch (prop_id)
 | |
|     {
 | |
|     case PROP_CURSOR:
 | |
|       g_value_set_object (value, gdk_window_get_cursor (window));
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | |
|       break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_window_is_offscreen (GdkWindow *window)
 | |
| {
 | |
|   return window->window_type == GDK_WINDOW_OFFSCREEN;
 | |
| }
 | |
| 
 | |
| static GdkWindow *
 | |
| gdk_window_get_impl_window (GdkWindow *window)
 | |
| {
 | |
|   return window->impl_window;
 | |
| }
 | |
| 
 | |
| GdkWindow *
 | |
| _gdk_window_get_impl_window (GdkWindow *window)
 | |
| {
 | |
|   return gdk_window_get_impl_window (window);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_window_has_impl (GdkWindow *window)
 | |
| {
 | |
|   return window->impl_window == window;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_window_is_toplevel (GdkWindow *window)
 | |
| {
 | |
|   return
 | |
|     window->parent == NULL ||
 | |
|     window->parent->window_type == GDK_WINDOW_ROOT;
 | |
| }
 | |
| 
 | |
| gboolean
 | |
| _gdk_window_has_impl (GdkWindow *window)
 | |
| {
 | |
|   return gdk_window_has_impl (window);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_window_has_no_impl (GdkWindow *window)
 | |
| {
 | |
|   return window->impl_window != window;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_window_has_alpha (GdkWindow *window)
 | |
| {
 | |
|   return !gdk_window_has_impl (window) &&
 | |
|     window->has_alpha_background;
 | |
| }
 | |
| 
 | |
| static void
 | |
| remove_layered_child_area (GdkWindow *window,
 | |
| 			   cairo_region_t *region)
 | |
| {
 | |
|   GdkWindow *child;
 | |
|   cairo_region_t *child_region;
 | |
|   GdkRectangle r;
 | |
|   GList *l;
 | |
| 
 | |
|   for (l = window->children; l; l = l->next)
 | |
|     {
 | |
|       child = l->data;
 | |
| 
 | |
|       /* If region is empty already, no need to do
 | |
| 	 anything potentially costly */
 | |
|       if (cairo_region_is_empty (region))
 | |
| 	break;
 | |
| 
 | |
|       if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
 | |
| 	continue;
 | |
| 
 | |
|       /* Ignore offscreen children, as they don't draw in their parent and
 | |
|        * don't take part in the clipping */
 | |
|       if (gdk_window_is_offscreen (child))
 | |
| 	continue;
 | |
| 
 | |
|       /* Only non-impl children with alpha add to the layered region */
 | |
|       if (!gdk_window_has_alpha (child))
 | |
| 	continue;
 | |
| 
 | |
|       r.x = child->x;
 | |
|       r.y = child->y;
 | |
|       r.width = child->width;
 | |
|       r.height = child->height;
 | |
| 
 | |
|       /* Bail early if child totally outside region */
 | |
|       if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
 | |
| 	continue;
 | |
| 
 | |
|       child_region = cairo_region_create_rectangle (&r);
 | |
|       if (child->shape)
 | |
| 	{
 | |
| 	  /* Adjust shape region to parent window coords */
 | |
| 	  cairo_region_translate (child->shape, child->x, child->y);
 | |
| 	  cairo_region_intersect (child_region, child->shape);
 | |
| 	  cairo_region_translate (child->shape, -child->x, -child->y);
 | |
| 	}
 | |
| 
 | |
|       cairo_region_subtract (region, child_region);
 | |
|       cairo_region_destroy (child_region);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| remove_child_area (GdkWindow *window,
 | |
| 		   GdkWindow *until,
 | |
| 		   gboolean for_input,
 | |
| 		   cairo_region_t *region,
 | |
| 		   cairo_region_t *layered_region)
 | |
| {
 | |
|   GdkWindow *child;
 | |
|   cairo_region_t *child_region;
 | |
|   GdkRectangle r;
 | |
|   GList *l;
 | |
|   cairo_region_t *shape;
 | |
| 
 | |
|   for (l = window->children; l; l = l->next)
 | |
|     {
 | |
|       child = l->data;
 | |
| 
 | |
|       if (child == until)
 | |
| 	break;
 | |
| 
 | |
|       /* If region is empty already, no need to do
 | |
| 	 anything potentially costly */
 | |
|       if (cairo_region_is_empty (region))
 | |
| 	break;
 | |
| 
 | |
|       if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
 | |
| 	continue;
 | |
| 
 | |
|       /* Ignore offscreen children, as they don't draw in their parent and
 | |
|        * don't take part in the clipping */
 | |
|       if (gdk_window_is_offscreen (child))
 | |
| 	continue;
 | |
| 
 | |
|       r.x = child->x;
 | |
|       r.y = child->y;
 | |
|       r.width = child->width;
 | |
|       r.height = child->height;
 | |
| 
 | |
|       /* Bail early if child totally outside region */
 | |
|       if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
 | |
| 	continue;
 | |
| 
 | |
|       child_region = cairo_region_create_rectangle (&r);
 | |
| 
 | |
|       if (child->shape)
 | |
| 	{
 | |
| 	  /* Adjust shape region to parent window coords */
 | |
| 	  cairo_region_translate (child->shape, child->x, child->y);
 | |
| 	  cairo_region_intersect (child_region, child->shape);
 | |
| 	  cairo_region_translate (child->shape, -child->x, -child->y);
 | |
| 	}
 | |
|       else if (window->window_type == GDK_WINDOW_FOREIGN)
 | |
| 	{
 | |
| 	  shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_shape (child);
 | |
| 	  if (shape)
 | |
| 	    {
 | |
| 	      cairo_region_intersect (child_region, shape);
 | |
| 	      cairo_region_destroy (shape);
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|       if (for_input)
 | |
| 	{
 | |
| 	  if (child->input_shape)
 | |
| 	    cairo_region_intersect (child_region, child->input_shape);
 | |
| 	  else if (window->window_type == GDK_WINDOW_FOREIGN)
 | |
| 	    {
 | |
| 	      shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_input_shape (child);
 | |
| 	      if (shape)
 | |
| 		{
 | |
| 		  cairo_region_intersect (child_region, shape);
 | |
| 		  cairo_region_destroy (shape);
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|       if (gdk_window_has_alpha (child))
 | |
| 	{
 | |
| 	  if (layered_region != NULL)
 | |
| 	    cairo_region_union (layered_region, child_region);
 | |
| 	}
 | |
|       else
 | |
| 	cairo_region_subtract (region, child_region);
 | |
|       cairo_region_destroy (child_region);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static GdkVisibilityState
 | |
| effective_visibility (GdkWindow *window)
 | |
| {
 | |
|   GdkVisibilityState native;
 | |
| 
 | |
|   if (!gdk_window_is_viewable (window))
 | |
|     return GDK_VISIBILITY_NOT_VIEWABLE;
 | |
| 
 | |
|   native = window->impl_window->native_visibility;
 | |
| 
 | |
|   if (native == GDK_VISIBILITY_FULLY_OBSCURED ||
 | |
|       window->visibility == GDK_VISIBILITY_FULLY_OBSCURED)
 | |
|     return GDK_VISIBILITY_FULLY_OBSCURED;
 | |
|   else if (native == GDK_VISIBILITY_UNOBSCURED)
 | |
|     return window->visibility;
 | |
|   else /* native PARTIAL, private partial or unobscured  */
 | |
|     return GDK_VISIBILITY_PARTIAL;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_update_visibility (GdkWindow *window)
 | |
| {
 | |
|   GdkVisibilityState new_visibility;
 | |
|   GdkEvent *event;
 | |
| 
 | |
|   new_visibility = effective_visibility (window);
 | |
| 
 | |
|   if (new_visibility != window->effective_visibility)
 | |
|     {
 | |
|       window->effective_visibility = new_visibility;
 | |
| 
 | |
|       if (new_visibility != GDK_VISIBILITY_NOT_VIEWABLE &&
 | |
| 	  window->event_mask & GDK_VISIBILITY_NOTIFY_MASK)
 | |
| 	{
 | |
| 	  event = _gdk_make_event (window, GDK_VISIBILITY_NOTIFY,
 | |
| 				   NULL, FALSE);
 | |
| 	  event->visibility.state = new_visibility;
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_update_visibility_recursively (GdkWindow *window,
 | |
| 					  GdkWindow *only_for_impl)
 | |
| {
 | |
|   GdkWindow *child;
 | |
|   GList *l;
 | |
| 
 | |
|   gdk_window_update_visibility (window);
 | |
|   for (l = window->children; l != NULL; l = l->next)
 | |
|     {
 | |
|       child = l->data;
 | |
|       if ((only_for_impl == NULL) ||
 | |
| 	  (only_for_impl == child->impl_window))
 | |
| 	gdk_window_update_visibility_recursively (child, only_for_impl);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| should_apply_clip_as_shape (GdkWindow *window)
 | |
| {
 | |
|   return
 | |
|     gdk_window_has_impl (window) &&
 | |
|     /* Not for offscreens */
 | |
|     !gdk_window_is_offscreen (window) &&
 | |
|     /* or for toplevels */
 | |
|     !gdk_window_is_toplevel (window) &&
 | |
|     /* or for foreign windows */
 | |
|     window->window_type != GDK_WINDOW_FOREIGN &&
 | |
|     /* or for the root window */
 | |
|     window->window_type != GDK_WINDOW_ROOT;
 | |
| }
 | |
| 
 | |
| static void
 | |
| apply_shape (GdkWindow *window,
 | |
| 	     cairo_region_t *region)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   /* We trash whether we applied a shape so that
 | |
|      we can avoid unsetting it many times, which
 | |
|      could happen in e.g. apply_clip_as_shape as
 | |
|      windows get resized */
 | |
|   impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|   if (region)
 | |
|     impl_class->shape_combine_region (window,
 | |
| 				      region, 0, 0);
 | |
|   else if (window->applied_shape)
 | |
|     impl_class->shape_combine_region (window,
 | |
| 				      NULL, 0, 0);
 | |
| 
 | |
|   window->applied_shape = region != NULL;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| region_rect_equal (const cairo_region_t *region,
 | |
|                    const GdkRectangle *rect)
 | |
| {
 | |
|     GdkRectangle extents;
 | |
| 
 | |
|     if (cairo_region_num_rectangles (region) != 1)
 | |
|         return FALSE;
 | |
| 
 | |
|     cairo_region_get_extents (region, &extents);
 | |
| 
 | |
|     return extents.x == rect->x &&
 | |
|         extents.y == rect->y &&
 | |
|         extents.width == rect->width &&
 | |
|         extents.height == rect->height;
 | |
| }
 | |
| 
 | |
| static void
 | |
| apply_clip_as_shape (GdkWindow *window)
 | |
| {
 | |
|   GdkRectangle r;
 | |
| 
 | |
|   r.x = r.y = 0;
 | |
|   r.width = window->width;
 | |
|   r.height = window->height;
 | |
| 
 | |
|   /* We only apply the clip region if would differ
 | |
|      from the actual clip region implied by the size
 | |
|      of the window. This is to avoid unneccessarily
 | |
|      adding meaningless shapes to all native subwindows */
 | |
|   if (!region_rect_equal (window->clip_region, &r))
 | |
|     apply_shape (window, window->clip_region);
 | |
|   else
 | |
|     apply_shape (window, NULL);
 | |
| }
 | |
| 
 | |
| static void
 | |
| recompute_visible_regions_internal (GdkWindow *private,
 | |
| 				    gboolean   recalculate_clip,
 | |
| 				    gboolean   recalculate_siblings,
 | |
| 				    gboolean   recalculate_children)
 | |
| {
 | |
|   GdkRectangle r;
 | |
|   GList *l;
 | |
|   GdkWindow *child;
 | |
|   cairo_region_t *new_clip, *new_layered;
 | |
|   gboolean clip_region_changed;
 | |
|   gboolean abs_pos_changed;
 | |
|   int old_abs_x, old_abs_y;
 | |
| 
 | |
|   old_abs_x = private->abs_x;
 | |
|   old_abs_y = private->abs_y;
 | |
| 
 | |
|   /* Update absolute position */
 | |
|   if (gdk_window_has_impl (private))
 | |
|     {
 | |
|       /* Native window starts here */
 | |
|       private->abs_x = 0;
 | |
|       private->abs_y = 0;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       private->abs_x = private->parent->abs_x + private->x;
 | |
|       private->abs_y = private->parent->abs_y + private->y;
 | |
|     }
 | |
| 
 | |
|   abs_pos_changed =
 | |
|     private->abs_x != old_abs_x ||
 | |
|     private->abs_y != old_abs_y;
 | |
| 
 | |
|   /* Update clip region based on:
 | |
|    * parent clip
 | |
|    * window size
 | |
|    * siblings in parents above window
 | |
|    */
 | |
|   clip_region_changed = FALSE;
 | |
|   if (recalculate_clip)
 | |
|     {
 | |
|       new_layered = cairo_region_create ();
 | |
|       if (private->viewable)
 | |
| 	{
 | |
| 	  /* Calculate visible region (sans children) in parent window coords */
 | |
| 	  r.x = private->x;
 | |
| 	  r.y = private->y;
 | |
| 	  r.width = private->width;
 | |
| 	  r.height = private->height;
 | |
| 	  new_clip = cairo_region_create_rectangle (&r);
 | |
| 
 | |
| 	  if (!gdk_window_is_toplevel (private))
 | |
| 	    {
 | |
| 	      cairo_region_intersect (new_clip, private->parent->clip_region);
 | |
| 	      cairo_region_union (new_layered, private->parent->layered_region);
 | |
| 
 | |
| 	      /* Remove all overlapping children from parent. */
 | |
| 	      remove_child_area (private->parent, private, FALSE, new_clip, new_layered);
 | |
| 	    }
 | |
| 
 | |
| 	  /* Convert from parent coords to window coords */
 | |
| 	  cairo_region_translate (new_clip, -private->x, -private->y);
 | |
| 	  cairo_region_translate (new_layered, -private->x, -private->y);
 | |
| 
 | |
| 	  if (private->shape)
 | |
| 	    cairo_region_intersect (new_clip, private->shape);
 | |
| 	}
 | |
|       else
 | |
| 	  new_clip = cairo_region_create ();
 | |
| 
 | |
|       cairo_region_intersect (new_layered, new_clip);
 | |
|       
 | |
|       if (private->clip_region == NULL ||
 | |
| 	  !cairo_region_equal (private->clip_region, new_clip))
 | |
| 	clip_region_changed = TRUE;
 | |
| 
 | |
|       if (private->layered_region == NULL ||
 | |
| 	  !cairo_region_equal (private->layered_region, new_layered))
 | |
| 	clip_region_changed = TRUE;
 | |
|       
 | |
|       if (private->clip_region)
 | |
| 	cairo_region_destroy (private->clip_region);
 | |
|       private->clip_region = new_clip;
 | |
| 
 | |
|       if (private->layered_region != NULL)
 | |
| 	cairo_region_destroy (private->layered_region);
 | |
|       private->layered_region = new_layered;
 | |
| 
 | |
|       if (private->clip_region_with_children)
 | |
| 	cairo_region_destroy (private->clip_region_with_children);
 | |
|       private->clip_region_with_children = cairo_region_copy (private->clip_region);
 | |
|       if (private->window_type != GDK_WINDOW_ROOT)
 | |
| 	remove_child_area (private, NULL, FALSE, private->clip_region_with_children, NULL);
 | |
|     }
 | |
| 
 | |
|   if (clip_region_changed)
 | |
|     {
 | |
|       GdkVisibilityState visibility;
 | |
|       gboolean fully_visible;
 | |
| 
 | |
|       if (cairo_region_is_empty (private->clip_region))
 | |
| 	visibility = GDK_VISIBILITY_FULLY_OBSCURED;
 | |
|       else
 | |
|         {
 | |
|           if (private->shape)
 | |
|             {
 | |
| 	      fully_visible = cairo_region_equal (private->clip_region,
 | |
| 	                                        private->shape);
 | |
|             }
 | |
|           else
 | |
|             {
 | |
| 	      r.x = 0;
 | |
| 	      r.y = 0;
 | |
| 	      r.width = private->width;
 | |
| 	      r.height = private->height;
 | |
| 	      fully_visible = region_rect_equal (private->clip_region, &r);
 | |
| 	    }
 | |
| 
 | |
| 	  if (fully_visible)
 | |
| 	    visibility = GDK_VISIBILITY_UNOBSCURED;
 | |
| 	  else
 | |
| 	    visibility = GDK_VISIBILITY_PARTIAL;
 | |
| 	}
 | |
| 
 | |
|       if (private->visibility != visibility)
 | |
| 	{
 | |
| 	  private->visibility = visibility;
 | |
| 	  gdk_window_update_visibility (private);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   /* Update all children, recursively (except for root, where children are not exact). */
 | |
|   if ((abs_pos_changed || clip_region_changed || recalculate_children) &&
 | |
|       private->window_type != GDK_WINDOW_ROOT)
 | |
|     {
 | |
|       for (l = private->children; l; l = l->next)
 | |
| 	{
 | |
| 	  child = l->data;
 | |
| 	  /* Only recalculate clip if the the clip region changed, otherwise
 | |
| 	   * there is no way the child clip region could change (its has not e.g. moved)
 | |
| 	   * Except if recalculate_children is set to force child updates
 | |
| 	   */
 | |
| 	  recompute_visible_regions_internal (child,
 | |
| 					      recalculate_clip && (clip_region_changed || recalculate_children),
 | |
| 					      FALSE, FALSE);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   if (clip_region_changed &&
 | |
|       should_apply_clip_as_shape (private))
 | |
|     apply_clip_as_shape (private);
 | |
| 
 | |
|   if (recalculate_siblings &&
 | |
|       !gdk_window_is_toplevel (private))
 | |
|     {
 | |
|       /* If we moved a child window in parent or changed the stacking order, then we
 | |
|        * need to recompute the visible area of all the other children in the parent
 | |
|        */
 | |
|       for (l = private->parent->children; l; l = l->next)
 | |
| 	{
 | |
| 	  child = l->data;
 | |
| 
 | |
| 	  if (child != private)
 | |
| 	    recompute_visible_regions_internal (child, TRUE, FALSE, FALSE);
 | |
| 	}
 | |
| 
 | |
|       /* We also need to recompute the _with_children clip for the parent */
 | |
|       recompute_visible_regions_internal (private->parent, TRUE, FALSE, FALSE);
 | |
|     }
 | |
| 
 | |
|   if (private->cairo_surface && gdk_window_has_impl (private))
 | |
|     {
 | |
|       GdkWindowImplClass *iface = GDK_WINDOW_IMPL_GET_CLASS (private->impl);
 | |
| 
 | |
|       private->cairo_surface = iface->resize_cairo_surface (private,
 | |
|                                                             private->cairo_surface,
 | |
|                                                             private->width,
 | |
|                                                             private->height);
 | |
|     }
 | |
|   else if (private->cairo_surface)
 | |
|     gdk_window_drop_cairo_surface (private);
 | |
| }
 | |
| 
 | |
| /* Call this when private has changed in one or more of these ways:
 | |
|  *  size changed
 | |
|  *  window moved
 | |
|  *  new window added
 | |
|  *  stacking order of window changed
 | |
|  *  child deleted
 | |
|  *
 | |
|  * It will recalculate abs_x/y and the clip regions
 | |
|  *
 | |
|  * Unless the window didn't change stacking order or size/pos, pass in TRUE
 | |
|  * for recalculate_siblings. (Mostly used internally for the recursion)
 | |
|  *
 | |
|  * If a child window was removed (and you can't use that child for
 | |
|  * recompute_visible_regions), pass in TRUE for recalculate_children on the parent
 | |
|  */
 | |
| static void
 | |
| recompute_visible_regions (GdkWindow *private,
 | |
| 			   gboolean recalculate_siblings,
 | |
| 			   gboolean recalculate_children)
 | |
| {
 | |
|   recompute_visible_regions_internal (private,
 | |
| 				      TRUE,
 | |
| 				      recalculate_siblings,
 | |
| 				      recalculate_children);
 | |
| }
 | |
| 
 | |
| void
 | |
| _gdk_window_update_size (GdkWindow *window)
 | |
| {
 | |
|   recompute_visible_regions (window, TRUE, FALSE);
 | |
| }
 | |
| 
 | |
| /* Find the native window that would be just above "child"
 | |
|  * in the native stacking order if "child" was a native window
 | |
|  * (it doesn't have to be native). If there is no such native
 | |
|  * window inside this native parent then NULL is returned.
 | |
|  * If child is NULL, find lowest native window in parent.
 | |
|  */
 | |
| static GdkWindow *
 | |
| find_native_sibling_above_helper (GdkWindow *parent,
 | |
| 				  GdkWindow *child)
 | |
| {
 | |
|   GdkWindow *w;
 | |
|   GList *l;
 | |
| 
 | |
|   if (child)
 | |
|     {
 | |
|       l = g_list_find (parent->children, child);
 | |
|       g_assert (l != NULL); /* Better be a child of its parent... */
 | |
|       l = l->prev; /* Start looking at the one above the child */
 | |
|     }
 | |
|   else
 | |
|     l = g_list_last (parent->children);
 | |
| 
 | |
|   for (; l != NULL; l = l->prev)
 | |
|     {
 | |
|       w = l->data;
 | |
| 
 | |
|       if (gdk_window_has_impl (w))
 | |
| 	return w;
 | |
| 
 | |
|       g_assert (parent != w);
 | |
|       w = find_native_sibling_above_helper (w, NULL);
 | |
|       if (w)
 | |
| 	return w;
 | |
|     }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| static GdkWindow *
 | |
| find_native_sibling_above (GdkWindow *parent,
 | |
| 			   GdkWindow *child)
 | |
| {
 | |
|   GdkWindow *w;
 | |
| 
 | |
|   w = find_native_sibling_above_helper (parent, child);
 | |
|   if (w)
 | |
|     return w;
 | |
| 
 | |
|   if (gdk_window_has_impl (parent))
 | |
|     return NULL;
 | |
|   else
 | |
|     return find_native_sibling_above (parent->parent, parent);
 | |
| }
 | |
| 
 | |
| static GdkEventMask
 | |
| get_native_device_event_mask (GdkWindow *private,
 | |
|                               GdkDevice *device)
 | |
| {
 | |
|   GdkEventMask event_mask;
 | |
| 
 | |
|   if (device)
 | |
|     event_mask = GPOINTER_TO_INT (g_hash_table_lookup (private->device_events, device));
 | |
|   else
 | |
|     event_mask = private->event_mask;
 | |
| 
 | |
|   if (private->window_type == GDK_WINDOW_ROOT ||
 | |
|       private->window_type == GDK_WINDOW_FOREIGN)
 | |
|     return event_mask;
 | |
|   else
 | |
|     {
 | |
|       GdkEventMask mask;
 | |
| 
 | |
|       /* Do whatever the app asks to, since the app
 | |
|        * may be asking for weird things for native windows,
 | |
|        * but don't use motion hints as that may affect non-native
 | |
|        * child windows that don't want it. Also, we need to
 | |
|        * set all the app-specified masks since they will be picked
 | |
|        * up by any implicit grabs (i.e. if they were not set as
 | |
|        * native we would not get the events we need). */
 | |
|       mask = private->event_mask & ~GDK_POINTER_MOTION_HINT_MASK;
 | |
| 
 | |
|       /* We need thse for all native windows so we can
 | |
| 	 emulate events on children: */
 | |
|       mask |=
 | |
| 	GDK_EXPOSURE_MASK |
 | |
| 	GDK_VISIBILITY_NOTIFY_MASK |
 | |
| 	GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK;
 | |
| 
 | |
|       /* Additionally we select for pointer and button events
 | |
|        * for toplevels as we need to get these to emulate
 | |
|        * them for non-native subwindows. Even though we don't
 | |
|        * select on them for all native windows we will get them
 | |
|        * as the events are propagated out to the first window
 | |
|        * that select for them.
 | |
|        * Not selecting for button press on all windows is an
 | |
|        * important thing, because in X only one client can do
 | |
|        * so, and we don't want to unexpectedly prevent another
 | |
|        * client from doing it.
 | |
|        *
 | |
|        * We also need to do the same if the app selects for button presses
 | |
|        * because then we will get implicit grabs for this window, and the
 | |
|        * event mask used for that grab is based on the rest of the mask
 | |
|        * for the window, but we might need more events than this window
 | |
|        * lists due to some non-native child window.
 | |
|        */
 | |
|       if (gdk_window_is_toplevel (private) ||
 | |
|           mask & GDK_BUTTON_PRESS_MASK)
 | |
|         mask |=
 | |
|           GDK_TOUCH_MASK |
 | |
|           GDK_POINTER_MOTION_MASK |
 | |
|           GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
 | |
|           GDK_SCROLL_MASK;
 | |
| 
 | |
|       return mask;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static GdkEventMask
 | |
| get_native_grab_event_mask (GdkEventMask grab_mask)
 | |
| {
 | |
|   /* Similar to the above but for pointer events only */
 | |
|   return
 | |
|     GDK_POINTER_MOTION_MASK |
 | |
|     GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
 | |
|     GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
 | |
|     GDK_SCROLL_MASK |
 | |
|     (grab_mask &
 | |
|      ~GDK_POINTER_MOTION_HINT_MASK);
 | |
| }
 | |
| 
 | |
| static GdkEventMask
 | |
| get_native_event_mask (GdkWindow *private)
 | |
| {
 | |
|   return get_native_device_event_mask (private, NULL);
 | |
| }
 | |
| 
 | |
| /* Puts the native window in the right order wrt the other native windows
 | |
|  * in the hierarchy, given the position it has in the client side data.
 | |
|  * This is useful if some operation changed the stacking order.
 | |
|  * This calls assumes the native window is now topmost in its native parent.
 | |
|  */
 | |
| static void
 | |
| sync_native_window_stack_position (GdkWindow *window)
 | |
| {
 | |
|   GdkWindow *above;
 | |
|   GdkWindowImplClass *impl_class;
 | |
|   GList listhead = {0};
 | |
| 
 | |
|   impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
| 
 | |
|   above = find_native_sibling_above (window->parent, window);
 | |
|   if (above)
 | |
|     {
 | |
|       listhead.data = window;
 | |
|       impl_class->restack_under (above, &listhead);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_new: (constructor)
 | |
|  * @parent: (allow-none): a #GdkWindow, or %NULL to create the window as a child of
 | |
|  *   the default root window for the default display.
 | |
|  * @attributes: attributes of the new window
 | |
|  * @attributes_mask: (type GdkWindowAttributesType): mask indicating which
 | |
|  *   fields in @attributes are valid
 | |
|  *
 | |
|  * Creates a new #GdkWindow using the attributes from
 | |
|  * @attributes. See #GdkWindowAttr and #GdkWindowAttributesType for
 | |
|  * more details.  Note: to use this on displays other than the default
 | |
|  * display, @parent must be specified.
 | |
|  *
 | |
|  * Return value: (transfer full): the new #GdkWindow
 | |
|  **/
 | |
| GdkWindow*
 | |
| gdk_window_new (GdkWindow     *parent,
 | |
| 		GdkWindowAttr *attributes,
 | |
| 		gint           attributes_mask)
 | |
| {
 | |
|   GdkWindow *window;
 | |
|   GdkScreen *screen;
 | |
|   GdkDisplay *display;
 | |
|   int x, y;
 | |
|   gboolean native;
 | |
|   GdkEventMask event_mask;
 | |
|   GdkWindow *real_parent;
 | |
|   GdkDeviceManager *device_manager;
 | |
| 
 | |
|   g_return_val_if_fail (attributes != NULL, NULL);
 | |
| 
 | |
|   if (!parent)
 | |
|     {
 | |
|       GDK_NOTE (MULTIHEAD,
 | |
| 		g_warning ("gdk_window_new(): no parent specified reverting to parent = default root window"));
 | |
| 
 | |
|       screen = gdk_screen_get_default ();
 | |
|       parent = gdk_screen_get_root_window (screen);
 | |
|     }
 | |
|   else
 | |
|     screen = gdk_window_get_screen (parent);
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL);
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (parent))
 | |
|     {
 | |
|       g_warning ("gdk_window_new(): parent is destroyed\n");
 | |
|       return NULL;
 | |
|     }
 | |
| 
 | |
|   if (attributes_mask & GDK_WA_VISUAL)
 | |
|     {
 | |
|       g_return_val_if_fail (gdk_visual_get_screen (attributes->visual) == screen, NULL);
 | |
|     }
 | |
| 
 | |
|   display = gdk_screen_get_display (screen);
 | |
| 
 | |
|   window = _gdk_display_create_window (display);
 | |
| 
 | |
|   /* Windows with a foreign parent are treated as if they are children
 | |
|    * of the root window, except for actual creation.
 | |
|    */
 | |
|   real_parent = parent;
 | |
|   if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN)
 | |
|     parent = gdk_screen_get_root_window (screen);
 | |
| 
 | |
|   window->parent = parent;
 | |
| 
 | |
|   window->accept_focus = TRUE;
 | |
|   window->focus_on_map = TRUE;
 | |
| 
 | |
|   if (attributes_mask & GDK_WA_X)
 | |
|     x = attributes->x;
 | |
|   else
 | |
|     x = 0;
 | |
| 
 | |
|   if (attributes_mask & GDK_WA_Y)
 | |
|     y = attributes->y;
 | |
|   else
 | |
|     y = 0;
 | |
| 
 | |
|   window->x = x;
 | |
|   window->y = y;
 | |
|   window->width = (attributes->width > 1) ? (attributes->width) : (1);
 | |
|   window->height = (attributes->height > 1) ? (attributes->height) : (1);
 | |
| 
 | |
|   if (attributes->wclass == GDK_INPUT_ONLY)
 | |
|     {
 | |
|       /* Backwards compatiblity - we've always ignored
 | |
|        * attributes->window_type for input-only windows
 | |
|        * before
 | |
|        */
 | |
|       if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT)
 | |
| 	window->window_type = GDK_WINDOW_TEMP;
 | |
|       else
 | |
| 	window->window_type = GDK_WINDOW_CHILD;
 | |
|     }
 | |
|   else
 | |
|     window->window_type = attributes->window_type;
 | |
| 
 | |
|   /* Sanity checks */
 | |
|   switch (window->window_type)
 | |
|     {
 | |
|     case GDK_WINDOW_TOPLEVEL:
 | |
|     case GDK_WINDOW_TEMP:
 | |
|     case GDK_WINDOW_OFFSCREEN:
 | |
|       if (GDK_WINDOW_TYPE (parent) != GDK_WINDOW_ROOT)
 | |
| 	g_warning (G_STRLOC "Toplevel windows must be created as children of\n"
 | |
| 		   "of a window of type GDK_WINDOW_ROOT or GDK_WINDOW_FOREIGN");
 | |
|     case GDK_WINDOW_CHILD:
 | |
|       break;
 | |
|       break;
 | |
|     default:
 | |
|       g_warning (G_STRLOC "cannot make windows of type %d", window->window_type);
 | |
|       return NULL;
 | |
|     }
 | |
| 
 | |
|   if (attributes_mask & GDK_WA_VISUAL)
 | |
|     window->visual = attributes->visual;
 | |
|   else
 | |
|     window->visual = gdk_screen_get_system_visual (screen);
 | |
| 
 | |
|   window->event_mask = attributes->event_mask;
 | |
| 
 | |
|   if (attributes->wclass == GDK_INPUT_OUTPUT)
 | |
|     {
 | |
|       window->input_only = FALSE;
 | |
|       window->depth = window->visual->depth;
 | |
| 
 | |
|       /* XXX: Cache this somehow? */
 | |
|       window->background = cairo_pattern_create_rgba (0, 0, 0, 0);
 | |
|       window->has_alpha_background = TRUE;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       window->depth = 0;
 | |
|       window->input_only = TRUE;
 | |
|     }
 | |
| 
 | |
|   if (window->parent)
 | |
|     window->parent->children = g_list_prepend (window->parent->children, window);
 | |
| 
 | |
|   native = FALSE;
 | |
|   if (window->parent->window_type == GDK_WINDOW_ROOT)
 | |
|     native = TRUE; /* Always use native windows for toplevels */
 | |
|   else if (!window->input_only &&
 | |
| 	   (attributes_mask & GDK_WA_VISUAL &&
 | |
| 	    attributes->visual != gdk_window_get_visual (window->parent)))
 | |
|     native = TRUE; /* InputOutput window with different visual than parent, needs native window */
 | |
| 
 | |
|   if (gdk_window_is_offscreen (window))
 | |
|     {
 | |
|       _gdk_offscreen_window_new (window, attributes, attributes_mask);
 | |
|       window->impl_window = window;
 | |
|     }
 | |
|   else if (native)
 | |
|     {
 | |
|       event_mask = get_native_event_mask (window);
 | |
| 
 | |
|       /* Create the impl */
 | |
|       _gdk_display_create_window_impl (display, window, real_parent, screen, event_mask, attributes, attributes_mask);
 | |
|       window->impl_window = window;
 | |
| 
 | |
|       /* This will put the native window topmost in the native parent, which may
 | |
|        * be wrong wrt other native windows in the non-native hierarchy, so restack */
 | |
|       if (!_gdk_window_has_impl (real_parent))
 | |
| 	sync_native_window_stack_position (window);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       window->impl_window = g_object_ref (window->parent->impl_window);
 | |
|       window->impl = g_object_ref (window->impl_window->impl);
 | |
|     }
 | |
| 
 | |
|   recompute_visible_regions (window, TRUE, FALSE);
 | |
| 
 | |
|   gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
 | |
| 				  (attributes->cursor) :
 | |
| 				  NULL));
 | |
| 
 | |
|   device_manager = gdk_display_get_device_manager (gdk_window_get_display (parent));
 | |
|   g_signal_connect (device_manager, "device-removed",
 | |
|                     G_CALLBACK (device_removed_cb), window);
 | |
| 
 | |
|   return window;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| is_parent_of (GdkWindow *parent,
 | |
| 	      GdkWindow *child)
 | |
| {
 | |
|   GdkWindow *w;
 | |
| 
 | |
|   w = child;
 | |
|   while (w != NULL)
 | |
|     {
 | |
|       if (w == parent)
 | |
| 	return TRUE;
 | |
| 
 | |
|       w = gdk_window_get_parent (w);
 | |
|     }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| change_impl (GdkWindow *private,
 | |
| 	     GdkWindow *impl_window,
 | |
| 	     GdkWindowImpl *new)
 | |
| {
 | |
|   GList *l;
 | |
|   GdkWindow *child;
 | |
|   GdkWindowImpl *old_impl;
 | |
|   GdkWindow *old_impl_window;
 | |
| 
 | |
|   old_impl = private->impl;
 | |
|   old_impl_window = private->impl_window;
 | |
|   if (private != impl_window)
 | |
|     private->impl_window = g_object_ref (impl_window);
 | |
|   else
 | |
|     private->impl_window = private;
 | |
|   private->impl = g_object_ref (new);
 | |
|   if (old_impl_window != private)
 | |
|     g_object_unref (old_impl_window);
 | |
|   g_object_unref (old_impl);
 | |
| 
 | |
|   for (l = private->children; l != NULL; l = l->next)
 | |
|     {
 | |
|       child = l->data;
 | |
| 
 | |
|       if (child->impl == old_impl)
 | |
| 	change_impl (child, impl_window, new);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| reparent_to_impl (GdkWindow *private)
 | |
| {
 | |
|   GList *l;
 | |
|   GdkWindow *child;
 | |
|   gboolean show;
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   impl_class = GDK_WINDOW_IMPL_GET_CLASS (private->impl);
 | |
| 
 | |
|   /* Enumerate in reverse order so we get the right order for the native
 | |
|      windows (first in childrens list is topmost, and reparent places on top) */
 | |
|   for (l = g_list_last (private->children); l != NULL; l = l->prev)
 | |
|     {
 | |
|       child = l->data;
 | |
| 
 | |
|       if (child->impl == private->impl)
 | |
| 	reparent_to_impl (child);
 | |
|       else
 | |
| 	{
 | |
| 	  show = impl_class->reparent ((GdkWindow *)child,
 | |
| 				       (GdkWindow *)private,
 | |
| 				       child->x, child->y);
 | |
| 	  if (show)
 | |
| 	    gdk_window_show_unraised ((GdkWindow *)child);
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * gdk_window_reparent:
 | |
|  * @window: a #GdkWindow
 | |
|  * @new_parent: new parent to move @window into
 | |
|  * @x: X location inside the new parent
 | |
|  * @y: Y location inside the new parent
 | |
|  *
 | |
|  * Reparents @window into the given @new_parent. The window being
 | |
|  * reparented will be unmapped as a side effect.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_reparent (GdkWindow *window,
 | |
| 		     GdkWindow *new_parent,
 | |
| 		     gint       x,
 | |
| 		     gint       y)
 | |
| {
 | |
|   GdkWindow *old_parent;
 | |
|   GdkScreen *screen;
 | |
|   gboolean show, was_mapped, applied_clip_as_shape;
 | |
|   gboolean do_reparent_to_impl;
 | |
|   GdkEventMask old_native_event_mask;
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
|   g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent));
 | |
|   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window) ||
 | |
|       (new_parent && GDK_WINDOW_DESTROYED (new_parent)))
 | |
|     return;
 | |
| 
 | |
|   screen = gdk_window_get_screen (window);
 | |
|   if (!new_parent)
 | |
|     new_parent = gdk_screen_get_root_window (screen);
 | |
| 
 | |
|   /* No input-output children of input-only windows */
 | |
|   if (new_parent->input_only && !window->input_only)
 | |
|     return;
 | |
| 
 | |
|   /* Don't create loops in hierarchy */
 | |
|   if (is_parent_of (window, new_parent))
 | |
|     return;
 | |
| 
 | |
|   /* This might be wrong in the new parent, e.g. for non-native surfaces.
 | |
|      To make sure we're ok, just wipe it. */
 | |
|   gdk_window_drop_cairo_surface (window);
 | |
| 
 | |
|   impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|   old_parent = window->parent;
 | |
| 
 | |
|   was_mapped = GDK_WINDOW_IS_MAPPED (window);
 | |
|   show = FALSE;
 | |
| 
 | |
|   /* Reparenting to toplevel. Ensure we have a native window so this can work */
 | |
|   if (new_parent->window_type == GDK_WINDOW_ROOT ||
 | |
|       new_parent->window_type == GDK_WINDOW_FOREIGN)
 | |
|     gdk_window_ensure_native (window);
 | |
| 
 | |
|   applied_clip_as_shape = should_apply_clip_as_shape (window);
 | |
| 
 | |
|   old_native_event_mask = 0;
 | |
|   do_reparent_to_impl = FALSE;
 | |
|   if (gdk_window_has_impl (window))
 | |
|     {
 | |
|       old_native_event_mask = get_native_event_mask (window);
 | |
|       /* Native window */
 | |
|       show = impl_class->reparent (window, new_parent, x, y);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       /* This shouldn't happen, as we created a native in this case, check anyway to see if that ever fails */
 | |
|       g_assert (new_parent->window_type != GDK_WINDOW_ROOT &&
 | |
| 		new_parent->window_type != GDK_WINDOW_FOREIGN);
 | |
| 
 | |
|       show = was_mapped;
 | |
|       gdk_window_hide (window);
 | |
| 
 | |
|       do_reparent_to_impl = TRUE;
 | |
|       change_impl (window,
 | |
| 		   new_parent->impl_window,
 | |
| 		   new_parent->impl);
 | |
|     }
 | |
| 
 | |
|   /* From here on, we treat parents of type GDK_WINDOW_FOREIGN like
 | |
|    * the root window
 | |
|    */
 | |
|   if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
 | |
|     {
 | |
|       new_parent = gdk_screen_get_root_window (screen);
 | |
|     }
 | |
| 
 | |
|   if (old_parent)
 | |
|     old_parent->children = g_list_remove (old_parent->children, window);
 | |
| 
 | |
|   window->parent = new_parent;
 | |
|   window->x = x;
 | |
|   window->y = y;
 | |
| 
 | |
|   new_parent->children = g_list_prepend (new_parent->children, window);
 | |
| 
 | |
|   /* Switch the window type as appropriate */
 | |
| 
 | |
|   switch (GDK_WINDOW_TYPE (new_parent))
 | |
|     {
 | |
|     case GDK_WINDOW_ROOT:
 | |
|     case GDK_WINDOW_FOREIGN:
 | |
|       if (window->toplevel_window_type != -1)
 | |
| 	GDK_WINDOW_TYPE (window) = window->toplevel_window_type;
 | |
|       else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
 | |
| 	GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL;
 | |
|       break;
 | |
|     case GDK_WINDOW_OFFSCREEN:
 | |
|     case GDK_WINDOW_TOPLEVEL:
 | |
|     case GDK_WINDOW_CHILD:
 | |
|     case GDK_WINDOW_TEMP:
 | |
|       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \
 | |
| 	  GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
 | |
| 	{
 | |
| 	  /* Save the original window type so we can restore it if the
 | |
| 	   * window is reparented back to be a toplevel
 | |
| 	   */
 | |
| 	  window->toplevel_window_type = GDK_WINDOW_TYPE (window);
 | |
| 	  GDK_WINDOW_TYPE (window) = GDK_WINDOW_CHILD;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   /* We might have changed window type for a native windows, so we
 | |
|      need to change the event mask too. */
 | |
|   if (gdk_window_has_impl (window))
 | |
|     {
 | |
|       GdkEventMask native_event_mask = get_native_event_mask (window);
 | |
| 
 | |
|       if (native_event_mask != old_native_event_mask)
 | |
| 	impl_class->set_events (window,	native_event_mask);
 | |
|     }
 | |
| 
 | |
|   _gdk_window_update_viewable (window);
 | |
| 
 | |
|   if (window->background == NULL)
 | |
|     {
 | |
|       /* parent relative background, update has_alpha_background */
 | |
|       if (window->parent == NULL ||
 | |
| 	  window->parent->window_type == GDK_WINDOW_ROOT)
 | |
| 	window->has_alpha_background = FALSE;
 | |
|       else
 | |
| 	window->has_alpha_background = window->parent->has_alpha_background;
 | |
|     }
 | |
| 
 | |
|   recompute_visible_regions (window, TRUE, FALSE);
 | |
|   if (old_parent && GDK_WINDOW_TYPE (old_parent) != GDK_WINDOW_ROOT)
 | |
|     recompute_visible_regions (old_parent, FALSE, TRUE);
 | |
| 
 | |
|   _gdk_window_propagate_has_alpha_background (window);
 | |
| 
 | |
|   /* We used to apply the clip as the shape, but no more.
 | |
|      Reset this to the real shape */
 | |
|   if (gdk_window_has_impl (window) &&
 | |
|       applied_clip_as_shape &&
 | |
|       !should_apply_clip_as_shape (window))
 | |
|     apply_shape (window, window->shape);
 | |
| 
 | |
|   if (do_reparent_to_impl)
 | |
|     reparent_to_impl (window);
 | |
|   else
 | |
|     {
 | |
|       /* The reparent will have put the native window topmost in the native parent,
 | |
|        * which may be wrong wrt other native windows in the non-native hierarchy,
 | |
|        * so restack */
 | |
|       if (!gdk_window_has_impl (new_parent))
 | |
| 	sync_native_window_stack_position (window);
 | |
|     }
 | |
| 
 | |
|   if (show)
 | |
|     gdk_window_show_unraised (window);
 | |
|   else
 | |
|     _gdk_synthesize_crossing_events_for_geometry_change (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_ensure_native:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Tries to ensure that there is a window-system native window for this
 | |
|  * GdkWindow. This may fail in some situations, returning %FALSE.
 | |
|  *
 | |
|  * Offscreen window and children of them can never have native windows.
 | |
|  *
 | |
|  * Some backends may not support native child windows.
 | |
|  *
 | |
|  * Returns: %TRUE if the window has a native window, %FALSE otherwise
 | |
|  *
 | |
|  * Since: 2.18
 | |
|  */
 | |
| gboolean
 | |
| gdk_window_ensure_native (GdkWindow *window)
 | |
| {
 | |
|   GdkWindow *impl_window;
 | |
|   GdkWindowImpl *new_impl, *old_impl;
 | |
|   GdkDisplay *display;
 | |
|   GdkScreen *screen;
 | |
|   GdkWindow *above;
 | |
|   GList listhead;
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 | |
| 
 | |
|   if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT ||
 | |
|       GDK_WINDOW_DESTROYED (window))
 | |
|     return FALSE;
 | |
| 
 | |
|   impl_window = gdk_window_get_impl_window (window);
 | |
| 
 | |
|   if (gdk_window_is_offscreen (impl_window))
 | |
|     return FALSE; /* native in offscreens not supported */
 | |
| 
 | |
|   if (impl_window == window)
 | |
|     /* Already has an impl, and its not offscreen . */
 | |
|     return TRUE;
 | |
| 
 | |
|   /* Need to create a native window */
 | |
| 
 | |
|   gdk_window_drop_cairo_surface (window);
 | |
| 
 | |
|   screen = gdk_window_get_screen (window);
 | |
|   display = gdk_screen_get_display (screen);
 | |
| 
 | |
|   old_impl = window->impl;
 | |
|   _gdk_display_create_window_impl (display,
 | |
|                                    window, window->parent,
 | |
|                                    screen,
 | |
|                                    get_native_event_mask (window),
 | |
|                                    NULL, 0);
 | |
|   new_impl = window->impl;
 | |
| 
 | |
|   window->impl = old_impl;
 | |
|   change_impl (window, window, new_impl);
 | |
| 
 | |
|   impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
| 
 | |
|   /* Native window creation will put the native window topmost in the
 | |
|    * native parent, which may be wrong wrt the position of the previous
 | |
|    * non-native window wrt to the other non-native children, so correct this.
 | |
|    */
 | |
|   above = find_native_sibling_above (window->parent, window);
 | |
|   if (above)
 | |
|     {
 | |
|       listhead.data = window;
 | |
|       listhead.prev = NULL;
 | |
|       listhead.next = NULL;
 | |
|       impl_class->restack_under ((GdkWindow *)above, &listhead);
 | |
|     }
 | |
| 
 | |
|   recompute_visible_regions (window, FALSE, FALSE);
 | |
| 
 | |
|   /* The shape may not have been set, as the clip region doesn't actually
 | |
|      change, so do it here manually */
 | |
|   if (should_apply_clip_as_shape (window))
 | |
|     apply_clip_as_shape (window);
 | |
| 
 | |
|   reparent_to_impl (window);
 | |
| 
 | |
|   if (!window->input_only)
 | |
|     impl_class->set_background (window, window->background);
 | |
| 
 | |
|   impl_class->input_shape_combine_region (window,
 | |
|                                           window->input_shape,
 | |
|                                           0, 0);
 | |
| 
 | |
|   if (gdk_window_is_viewable (window))
 | |
|     impl_class->show (window, FALSE);
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * _gdk_event_filter_unref:
 | |
|  * @window: (allow-none): A #GdkWindow, or %NULL to be the global window
 | |
|  * @filter: A window filter
 | |
|  *
 | |
|  * Release a reference to @filter.  Note this function may
 | |
|  * mutate the list storage, so you need to handle this
 | |
|  * if iterating over a list of filters.
 | |
|  */
 | |
| void
 | |
| _gdk_event_filter_unref (GdkWindow       *window,
 | |
| 			 GdkEventFilter  *filter)
 | |
| {
 | |
|   GList **filters;
 | |
|   GList *tmp_list;
 | |
| 
 | |
|   if (window == NULL)
 | |
|     filters = &_gdk_default_filters;
 | |
|   else
 | |
|     filters = &window->filters;
 | |
| 
 | |
|   tmp_list = *filters;
 | |
|   while (tmp_list)
 | |
|     {
 | |
|       GdkEventFilter *iter_filter = tmp_list->data;
 | |
|       GList *node;
 | |
| 
 | |
|       node = tmp_list;
 | |
|       tmp_list = tmp_list->next;
 | |
| 
 | |
|       if (iter_filter != filter)
 | |
| 	continue;
 | |
| 
 | |
|       g_assert (iter_filter->ref_count > 0);
 | |
| 
 | |
|       filter->ref_count--;
 | |
|       if (filter->ref_count != 0)
 | |
| 	continue;
 | |
| 
 | |
|       *filters = g_list_remove_link (*filters, node);
 | |
|       g_free (filter);
 | |
|       g_list_free_1 (node);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| window_remove_filters (GdkWindow *window)
 | |
| {
 | |
|   while (window->filters)
 | |
|     _gdk_event_filter_unref (window, window->filters->data);
 | |
| }
 | |
| 
 | |
| static void
 | |
| update_pointer_info_foreach (GdkDisplay           *display,
 | |
|                              GdkDevice            *device,
 | |
|                              GdkPointerWindowInfo *pointer_info,
 | |
|                              gpointer              user_data)
 | |
| {
 | |
|   GdkWindow *window = user_data;
 | |
| 
 | |
|   if (pointer_info->toplevel_under_pointer == window)
 | |
|     {
 | |
|       g_object_unref (pointer_info->toplevel_under_pointer);
 | |
|       pointer_info->toplevel_under_pointer = NULL;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| window_remove_from_pointer_info (GdkWindow  *window,
 | |
|                                  GdkDisplay *display)
 | |
| {
 | |
|   _gdk_display_pointer_info_foreach (display,
 | |
|                                      update_pointer_info_foreach,
 | |
|                                      window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * _gdk_window_destroy_hierarchy:
 | |
|  * @window: a #GdkWindow
 | |
|  * @recursing: If TRUE, then this is being called because a parent
 | |
|  *            was destroyed.
 | |
|  * @recursing_native: If TRUE, then this is being called because a native parent
 | |
|  *            was destroyed. This generally means that the call to the
 | |
|  *            windowing system to destroy the window can be omitted, since
 | |
|  *            it will be destroyed as a result of the parent being destroyed.
 | |
|  *            Unless @foreign_destroy.
 | |
|  * @foreign_destroy: If TRUE, the window or a parent was destroyed by some
 | |
|  *            external agency. The window has already been destroyed and no
 | |
|  *            windowing system calls should be made. (This may never happen
 | |
|  *            for some windowing systems.)
 | |
|  *
 | |
|  * Internal function to destroy a window. Like gdk_window_destroy(),
 | |
|  * but does not drop the reference count created by gdk_window_new().
 | |
|  **/
 | |
| static void
 | |
| _gdk_window_destroy_hierarchy (GdkWindow *window,
 | |
| 			       gboolean   recursing,
 | |
| 			       gboolean   recursing_native,
 | |
| 			       gboolean   foreign_destroy)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
|   GdkWindow *temp_window;
 | |
|   GdkScreen *screen;
 | |
|   GdkDisplay *display;
 | |
|   GList *children;
 | |
|   GList *tmp;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   display = gdk_window_get_display (window);
 | |
|   screen = gdk_window_get_screen (window);
 | |
|   temp_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
 | |
|   if (temp_window == window)
 | |
|     g_object_set_qdata (G_OBJECT (screen), quark_pointer_window, NULL);
 | |
| 
 | |
| 
 | |
|   switch (window->window_type)
 | |
|     {
 | |
|     case GDK_WINDOW_ROOT:
 | |
|       if (!screen->closed)
 | |
| 	{
 | |
| 	  g_error ("attempted to destroy root window");
 | |
| 	  break;
 | |
| 	}
 | |
|       /* else fall thru */
 | |
|     case GDK_WINDOW_TOPLEVEL:
 | |
|     case GDK_WINDOW_CHILD:
 | |
|     case GDK_WINDOW_TEMP:
 | |
|     case GDK_WINDOW_FOREIGN:
 | |
|     case GDK_WINDOW_OFFSCREEN:
 | |
|       if (window->window_type == GDK_WINDOW_FOREIGN && !foreign_destroy)
 | |
| 	{
 | |
| 	  /* Logically, it probably makes more sense to send
 | |
| 	   * a "destroy yourself" message to the foreign window
 | |
| 	   * whether or not it's in our hierarchy; but for historical
 | |
| 	   * reasons, we only send "destroy yourself" messages to
 | |
| 	   * foreign windows in our hierarchy.
 | |
| 	   */
 | |
| 	  if (window->parent)
 | |
|             {
 | |
|               impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
| 
 | |
|               if (gdk_window_has_impl (window))
 | |
|                 impl_class->destroy_foreign (window);
 | |
|             }
 | |
| 
 | |
| 	  /* Also for historical reasons, we remove any filters
 | |
| 	   * on a foreign window when it or a parent is destroyed;
 | |
| 	   * this likely causes problems if two separate portions
 | |
| 	   * of code are maintaining filter lists on a foreign window.
 | |
| 	   */
 | |
| 	  window_remove_filters (window);
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  if (window->parent)
 | |
| 	    {
 | |
| 	      if (window->parent->children)
 | |
| 		window->parent->children = g_list_remove (window->parent->children, window);
 | |
| 
 | |
| 	      if (!recursing &&
 | |
| 		  GDK_WINDOW_IS_MAPPED (window))
 | |
| 		{
 | |
| 		  recompute_visible_regions (window, TRUE, FALSE);
 | |
| 		  gdk_window_invalidate_in_parent (window);
 | |
| 		}
 | |
| 	    }
 | |
| 
 | |
| 	  gdk_window_free_paint_stack (window);
 | |
| 
 | |
|           if (window->background)
 | |
|             {
 | |
|               cairo_pattern_destroy (window->background);
 | |
|               window->background = NULL;
 | |
|             }
 | |
| 
 | |
| 	  if (window->window_type == GDK_WINDOW_FOREIGN)
 | |
| 	    g_assert (window->children == NULL);
 | |
| 	  else
 | |
| 	    {
 | |
| 	      children = tmp = window->children;
 | |
| 	      window->children = NULL;
 | |
| 
 | |
| 	      while (tmp)
 | |
| 		{
 | |
| 		  temp_window = tmp->data;
 | |
| 		  tmp = tmp->next;
 | |
| 
 | |
| 		  if (temp_window)
 | |
| 		    _gdk_window_destroy_hierarchy (temp_window,
 | |
| 						   TRUE,
 | |
| 						   recursing_native || gdk_window_has_impl (window),
 | |
| 						   foreign_destroy);
 | |
| 		}
 | |
| 
 | |
| 	      g_list_free (children);
 | |
| 	    }
 | |
| 
 | |
| 	  _gdk_window_clear_update_area (window);
 | |
| 
 | |
| 	  gdk_window_drop_cairo_surface (window);
 | |
| 
 | |
| 	  impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
| 
 | |
| 	  if (gdk_window_has_impl (window))
 | |
| 	    impl_class->destroy (window, recursing_native,
 | |
| 				 foreign_destroy);
 | |
| 	  else
 | |
| 	    {
 | |
| 	      /* hide to make sure we repaint and break grabs */
 | |
| 	      gdk_window_hide (window);
 | |
| 	    }
 | |
| 
 | |
| 	  window->state |= GDK_WINDOW_STATE_WITHDRAWN;
 | |
| 	  window->parent = NULL;
 | |
| 	  window->destroyed = TRUE;
 | |
| 
 | |
| 	  window_remove_filters (window);
 | |
| 
 | |
| 	  window_remove_from_pointer_info (window, display);
 | |
| 
 | |
| 	  if (window->clip_region)
 | |
| 	    {
 | |
| 	      cairo_region_destroy (window->clip_region);
 | |
| 	      window->clip_region = NULL;
 | |
| 	    }
 | |
| 
 | |
| 	  if (window->clip_region_with_children)
 | |
| 	    {
 | |
| 	      cairo_region_destroy (window->clip_region_with_children);
 | |
| 	      window->clip_region_with_children = NULL;
 | |
| 	    }
 | |
| 
 | |
| 	  g_list_free_full (window->outstanding_moves, (GDestroyNotify) gdk_window_region_move_free);
 | |
| 	  window->outstanding_moves = NULL;
 | |
| 	}
 | |
|       break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * _gdk_window_destroy:
 | |
|  * @window: a #GdkWindow
 | |
|  * @foreign_destroy: If TRUE, the window or a parent was destroyed by some
 | |
|  *            external agency. The window has already been destroyed and no
 | |
|  *            windowing system calls should be made. (This may never happen
 | |
|  *            for some windowing systems.)
 | |
|  *
 | |
|  * Internal function to destroy a window. Like gdk_window_destroy(),
 | |
|  * but does not drop the reference count created by gdk_window_new().
 | |
|  **/
 | |
| void
 | |
| _gdk_window_destroy (GdkWindow *window,
 | |
| 		     gboolean   foreign_destroy)
 | |
| {
 | |
|   _gdk_window_destroy_hierarchy (window, FALSE, FALSE, foreign_destroy);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_destroy:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Destroys the window system resources associated with @window and decrements @window's
 | |
|  * reference count. The window system resources for all children of @window are also
 | |
|  * destroyed, but the children's reference counts are not decremented.
 | |
|  *
 | |
|  * Note that a window will not be destroyed automatically when its reference count
 | |
|  * reaches zero. You must call this function yourself before that happens.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_destroy (GdkWindow *window)
 | |
| {
 | |
|   _gdk_window_destroy_hierarchy (window, FALSE, FALSE, FALSE);
 | |
|   g_object_unref (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_user_data:
 | |
|  * @window: a #GdkWindow
 | |
|  * @user_data: (allow-none) (type GObject.Object): user data
 | |
|  *
 | |
|  * For most purposes this function is deprecated in favor of
 | |
|  * g_object_set_data(). However, for historical reasons GTK+ stores
 | |
|  * the #GtkWidget that owns a #GdkWindow as user data on the
 | |
|  * #GdkWindow. So, custom widget implementations should use
 | |
|  * this function for that. If GTK+ receives an event for a #GdkWindow,
 | |
|  * and the user data for the window is non-%NULL, GTK+ will assume the
 | |
|  * user data is a #GtkWidget, and forward the event to that widget.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_user_data (GdkWindow *window,
 | |
| 			  gpointer   user_data)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   window->user_data = user_data;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_user_data:
 | |
|  * @window: a #GdkWindow
 | |
|  * @data: (out): return location for user data
 | |
|  *
 | |
|  * Retrieves the user data for @window, which is normally the widget
 | |
|  * that @window belongs to. See gdk_window_set_user_data().
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_get_user_data (GdkWindow *window,
 | |
| 			  gpointer  *data)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   *data = window->user_data;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_window_type:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Gets the type of the window. See #GdkWindowType.
 | |
|  *
 | |
|  * Return value: type of window
 | |
|  **/
 | |
| GdkWindowType
 | |
| gdk_window_get_window_type (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), (GdkWindowType) -1);
 | |
| 
 | |
|   return GDK_WINDOW_TYPE (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_visual:
 | |
|  * @window: a #GdkWindow
 | |
|  * 
 | |
|  * Gets the #GdkVisual describing the pixel format of @window.
 | |
|  * 
 | |
|  * Return value: (transfer none): a #GdkVisual
 | |
|  *
 | |
|  * Since: 2.24
 | |
|  **/
 | |
| GdkVisual*
 | |
| gdk_window_get_visual (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
|   
 | |
|   return window->visual;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_screen:
 | |
|  * @window: a #GdkWindow
 | |
|  * 
 | |
|  * Gets the #GdkScreen associated with a #GdkWindow.
 | |
|  * 
 | |
|  * Return value: (transfer none): the #GdkScreen associated with @window
 | |
|  *
 | |
|  * Since: 2.24
 | |
|  **/
 | |
| GdkScreen*
 | |
| gdk_window_get_screen (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   return gdk_visual_get_screen (window->visual);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_display:
 | |
|  * @window: a #GdkWindow
 | |
|  * 
 | |
|  * Gets the #GdkDisplay associated with a #GdkWindow.
 | |
|  * 
 | |
|  * Return value: (transfer none): the #GdkDisplay associated with @window
 | |
|  *
 | |
|  * Since: 2.24
 | |
|  **/
 | |
| GdkDisplay *
 | |
| gdk_window_get_display (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   return gdk_screen_get_display (gdk_visual_get_screen (window->visual));
 | |
| }
 | |
| /**
 | |
|  * gdk_window_is_destroyed:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Check to see if a window is destroyed..
 | |
|  *
 | |
|  * Return value: %TRUE if the window is destroyed
 | |
|  *
 | |
|  * Since: 2.18
 | |
|  **/
 | |
| gboolean
 | |
| gdk_window_is_destroyed (GdkWindow *window)
 | |
| {
 | |
|   return GDK_WINDOW_DESTROYED (window);
 | |
| }
 | |
| 
 | |
| static void
 | |
| to_embedder (GdkWindow *window,
 | |
|              gdouble    offscreen_x,
 | |
|              gdouble    offscreen_y,
 | |
|              gdouble   *embedder_x,
 | |
|              gdouble   *embedder_y)
 | |
| {
 | |
|   g_signal_emit (window, signals[TO_EMBEDDER], 0,
 | |
|                  offscreen_x, offscreen_y,
 | |
|                  embedder_x, embedder_y);
 | |
| }
 | |
| 
 | |
| static void
 | |
| from_embedder (GdkWindow *window,
 | |
|                gdouble    embedder_x,
 | |
|                gdouble    embedder_y,
 | |
|                gdouble   *offscreen_x,
 | |
|                gdouble   *offscreen_y)
 | |
| {
 | |
|   g_signal_emit (window, signals[FROM_EMBEDDER], 0,
 | |
|                  embedder_x, embedder_y,
 | |
|                  offscreen_x, offscreen_y);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_has_native:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Checks whether the window has a native window or not. Note that
 | |
|  * you can use gdk_window_ensure_native() if a native window is needed.
 | |
|  *
 | |
|  * Returns: %TRUE if the %window has a native window, %FALSE otherwise.
 | |
|  *
 | |
|  * Since: 2.22
 | |
|  */
 | |
| gboolean
 | |
| gdk_window_has_native (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 | |
| 
 | |
|   return window->parent == NULL || window->parent->impl != window->impl;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_position:
 | |
|  * @window: a #GdkWindow
 | |
|  * @x: (out) (allow-none): X coordinate of window
 | |
|  * @y: (out) (allow-none): Y coordinate of window
 | |
|  *
 | |
|  * Obtains the position of the window as reported in the
 | |
|  * most-recently-processed #GdkEventConfigure. Contrast with
 | |
|  * gdk_window_get_geometry() which queries the X server for the
 | |
|  * current window position, regardless of which events have been
 | |
|  * received or processed.
 | |
|  *
 | |
|  * The position coordinates are relative to the window's parent window.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_get_position (GdkWindow *window,
 | |
| 			 gint      *x,
 | |
| 			 gint      *y)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (x)
 | |
|     *x = window->x;
 | |
|   if (y)
 | |
|     *y = window->y;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_parent:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Obtains the parent of @window, as known to GDK. Does not query the
 | |
|  * X server; thus this returns the parent as passed to gdk_window_new(),
 | |
|  * not the actual parent. This should never matter unless you're using
 | |
|  * Xlib calls mixed with GDK calls on the X11 platform. It may also
 | |
|  * matter for toplevel windows, because the window manager may choose
 | |
|  * to reparent them.
 | |
|  *
 | |
|  * Note that you should use gdk_window_get_effective_parent() when
 | |
|  * writing generic code that walks up a window hierarchy, because
 | |
|  * gdk_window_get_parent() will most likely not do what you expect if
 | |
|  * there are offscreen windows in the hierarchy.
 | |
|  *
 | |
|  * Return value: (transfer none): parent of @window
 | |
|  **/
 | |
| GdkWindow*
 | |
| gdk_window_get_parent (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   return window->parent;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_effective_parent:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Obtains the parent of @window, as known to GDK. Works like
 | |
|  * gdk_window_get_parent() for normal windows, but returns the
 | |
|  * window's embedder for offscreen windows.
 | |
|  *
 | |
|  * See also: gdk_offscreen_window_get_embedder()
 | |
|  *
 | |
|  * Return value: (transfer none): effective parent of @window
 | |
|  *
 | |
|  * Since: 2.22
 | |
|  **/
 | |
| GdkWindow *
 | |
| gdk_window_get_effective_parent (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   if (gdk_window_is_offscreen (window))
 | |
|     return gdk_offscreen_window_get_embedder (window);
 | |
|   else
 | |
|     return window->parent;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_toplevel:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Gets the toplevel window that's an ancestor of @window.
 | |
|  *
 | |
|  * Any window type but %GDK_WINDOW_CHILD is considered a
 | |
|  * toplevel window, as is a %GDK_WINDOW_CHILD window that
 | |
|  * has a root window as parent.
 | |
|  *
 | |
|  * Note that you should use gdk_window_get_effective_toplevel() when
 | |
|  * you want to get to a window's toplevel as seen on screen, because
 | |
|  * gdk_window_get_toplevel() will most likely not do what you expect
 | |
|  * if there are offscreen windows in the hierarchy.
 | |
|  *
 | |
|  * Return value: (transfer none): the toplevel window containing @window
 | |
|  **/
 | |
| GdkWindow *
 | |
| gdk_window_get_toplevel (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   while (window->window_type == GDK_WINDOW_CHILD)
 | |
|     {
 | |
|       if (gdk_window_is_toplevel (window))
 | |
| 	break;
 | |
|       window = window->parent;
 | |
|     }
 | |
| 
 | |
|   return window;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_effective_toplevel:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Gets the toplevel window that's an ancestor of @window.
 | |
|  *
 | |
|  * Works like gdk_window_get_toplevel(), but treats an offscreen window's
 | |
|  * embedder as its parent, using gdk_window_get_effective_parent().
 | |
|  *
 | |
|  * See also: gdk_offscreen_window_get_embedder()
 | |
|  *
 | |
|  * Return value: (transfer none): the effective toplevel window containing @window
 | |
|  *
 | |
|  * Since: 2.22
 | |
|  **/
 | |
| GdkWindow *
 | |
| gdk_window_get_effective_toplevel (GdkWindow *window)
 | |
| {
 | |
|   GdkWindow *parent;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   while ((parent = gdk_window_get_effective_parent (window)) != NULL &&
 | |
| 	 (gdk_window_get_window_type (parent) != GDK_WINDOW_ROOT))
 | |
|     window = parent;
 | |
| 
 | |
|   return window;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_children:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Gets the list of children of @window known to GDK.
 | |
|  * This function only returns children created via GDK,
 | |
|  * so for example it's useless when used with the root window;
 | |
|  * it only returns windows an application created itself.
 | |
|  *
 | |
|  * The returned list must be freed, but the elements in the
 | |
|  * list need not be.
 | |
|  *
 | |
|  * Return value: (transfer container) (element-type GdkWindow):
 | |
|  *     list of child windows inside @window
 | |
|  **/
 | |
| GList*
 | |
| gdk_window_get_children (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return NULL;
 | |
| 
 | |
|   return g_list_copy (window->children);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_peek_children:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Like gdk_window_get_children(), but does not copy the list of
 | |
|  * children, so the list does not need to be freed.
 | |
|  *
 | |
|  * Return value: (transfer none) (element-type GdkWindow):
 | |
|  *     a reference to the list of child windows in @window
 | |
|  **/
 | |
| GList *
 | |
| gdk_window_peek_children (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return NULL;
 | |
| 
 | |
|   return window->children;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_add_filter: (skip)
 | |
|  * @window: (allow-none): a #GdkWindow
 | |
|  * @function: filter callback
 | |
|  * @data: data to pass to filter callback
 | |
|  *
 | |
|  * Adds an event filter to @window, allowing you to intercept events
 | |
|  * before they reach GDK. This is a low-level operation and makes it
 | |
|  * easy to break GDK and/or GTK+, so you have to know what you're
 | |
|  * doing. Pass %NULL for @window to get all events for all windows,
 | |
|  * instead of events for a specific window.
 | |
|  *
 | |
|  * If you are interested in X GenericEvents, bear in mind that
 | |
|  * XGetEventData() has been already called on the event, and
 | |
|  * XFreeEventData() must not be called within @function.
 | |
|  **/
 | |
| void
 | |
| gdk_window_add_filter (GdkWindow     *window,
 | |
| 		       GdkFilterFunc  function,
 | |
| 		       gpointer       data)
 | |
| {
 | |
|   GList *tmp_list;
 | |
|   GdkEventFilter *filter;
 | |
| 
 | |
|   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (window && GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   /* Filters are for the native events on the native window, so
 | |
|      ensure there is a native window. */
 | |
|   if (window)
 | |
|     gdk_window_ensure_native (window);
 | |
| 
 | |
|   if (window)
 | |
|     tmp_list = window->filters;
 | |
|   else
 | |
|     tmp_list = _gdk_default_filters;
 | |
| 
 | |
|   while (tmp_list)
 | |
|     {
 | |
|       filter = (GdkEventFilter *)tmp_list->data;
 | |
|       if ((filter->function == function) && (filter->data == data))
 | |
|         {
 | |
|           filter->ref_count++;
 | |
|           return;
 | |
|         }
 | |
|       tmp_list = tmp_list->next;
 | |
|     }
 | |
| 
 | |
|   filter = g_new (GdkEventFilter, 1);
 | |
|   filter->function = function;
 | |
|   filter->data = data;
 | |
|   filter->ref_count = 1;
 | |
|   filter->flags = 0;
 | |
| 
 | |
|   if (window)
 | |
|     window->filters = g_list_append (window->filters, filter);
 | |
|   else
 | |
|     _gdk_default_filters = g_list_append (_gdk_default_filters, filter);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_remove_filter: (skip)
 | |
|  * @window: a #GdkWindow
 | |
|  * @function: previously-added filter function
 | |
|  * @data: user data for previously-added filter function
 | |
|  *
 | |
|  * Remove a filter previously added with gdk_window_add_filter().
 | |
|  */
 | |
| void
 | |
| gdk_window_remove_filter (GdkWindow     *window,
 | |
|                           GdkFilterFunc  function,
 | |
|                           gpointer       data)
 | |
| {
 | |
|   GList *tmp_list;
 | |
|   GdkEventFilter *filter;
 | |
| 
 | |
|   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (window)
 | |
|     tmp_list = window->filters;
 | |
|   else
 | |
|     tmp_list = _gdk_default_filters;
 | |
| 
 | |
|   while (tmp_list)
 | |
|     {
 | |
|       filter = (GdkEventFilter *)tmp_list->data;
 | |
|       tmp_list = tmp_list->next;
 | |
| 
 | |
|       if ((filter->function == function) && (filter->data == data))
 | |
|         {
 | |
|           filter->flags |= GDK_EVENT_FILTER_REMOVED;
 | |
| 
 | |
|           _gdk_event_filter_unref (window, filter);
 | |
| 
 | |
|           return;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_screen_get_toplevel_windows:
 | |
|  * @screen: The #GdkScreen where the toplevels are located.
 | |
|  *
 | |
|  * Obtains a list of all toplevel windows known to GDK on the screen @screen.
 | |
|  * A toplevel window is a child of the root window (see
 | |
|  * gdk_get_default_root_window()).
 | |
|  *
 | |
|  * The returned list should be freed with g_list_free(), but
 | |
|  * its elements need not be freed.
 | |
|  *
 | |
|  * Return value: (transfer container) (element-type GdkWindow):
 | |
|  *     list of toplevel windows, free with g_list_free()
 | |
|  *
 | |
|  * Since: 2.2
 | |
|  **/
 | |
| GList *
 | |
| gdk_screen_get_toplevel_windows (GdkScreen *screen)
 | |
| {
 | |
|   GdkWindow * root_window;
 | |
|   GList *new_list = NULL;
 | |
|   GList *tmp_list;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
 | |
| 
 | |
|   root_window = gdk_screen_get_root_window (screen);
 | |
| 
 | |
|   tmp_list = root_window->children;
 | |
|   while (tmp_list)
 | |
|     {
 | |
|       GdkWindow *w = tmp_list->data;
 | |
| 
 | |
|       if (w->window_type != GDK_WINDOW_FOREIGN)
 | |
| 	new_list = g_list_prepend (new_list, w);
 | |
|       tmp_list = tmp_list->next;
 | |
|     }
 | |
| 
 | |
|   return new_list;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_is_visible:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Checks whether the window has been mapped (with gdk_window_show() or
 | |
|  * gdk_window_show_unraised()).
 | |
|  *
 | |
|  * Return value: %TRUE if the window is mapped
 | |
|  **/
 | |
| gboolean
 | |
| gdk_window_is_visible (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 | |
| 
 | |
|   return GDK_WINDOW_IS_MAPPED (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_is_viewable:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Check if the window and all ancestors of the window are
 | |
|  * mapped. (This is not necessarily "viewable" in the X sense, since
 | |
|  * we only check as far as we have GDK window parents, not to the root
 | |
|  * window.)
 | |
|  *
 | |
|  * Return value: %TRUE if the window is viewable
 | |
|  **/
 | |
| gboolean
 | |
| gdk_window_is_viewable (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 | |
| 
 | |
|   if (window->destroyed)
 | |
|     return FALSE;
 | |
| 
 | |
|   return window->viewable;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_state:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Gets the bitwise OR of the currently active window state flags,
 | |
|  * from the #GdkWindowState enumeration.
 | |
|  *
 | |
|  * Return value: window state bitfield
 | |
|  **/
 | |
| GdkWindowState
 | |
| gdk_window_get_state (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 | |
| 
 | |
|   return window->state;
 | |
| }
 | |
| 
 | |
| static cairo_content_t
 | |
| gdk_window_get_content (GdkWindow *window)
 | |
| {
 | |
|   cairo_surface_t *surface;
 | |
|   cairo_content_t content;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 | |
| 
 | |
|   surface = gdk_window_ref_impl_surface (window);
 | |
|   content = cairo_surface_get_content (surface);
 | |
|   cairo_surface_destroy (surface);
 | |
| 
 | |
|   return content;
 | |
| }
 | |
| 
 | |
| /* This creates an empty "implicit" paint region for the impl window.
 | |
|  * By itself this does nothing, but real paints to this window
 | |
|  * or children of it can use this surface as backing to avoid allocating
 | |
|  * multiple surfaces for subwindow rendering. When doing so they
 | |
|  * add to the region of the implicit paint region, which will be
 | |
|  * pushed to the window when the implicit paint region is ended.
 | |
|  * Such paints should not copy anything to the window on paint end, but
 | |
|  * should rely on the implicit paint end.
 | |
|  * The implicit paint will be automatically ended if someone draws
 | |
|  * directly to the window or a child window.
 | |
|  */
 | |
| static gboolean
 | |
| gdk_window_begin_implicit_paint (GdkWindow *window, GdkRectangle *rect)
 | |
| {
 | |
|   GdkWindowPaint *paint;
 | |
| 
 | |
|   g_assert (gdk_window_has_impl (window));
 | |
| 
 | |
|   if (GDK_IS_PAINTABLE (window->impl))
 | |
|     return FALSE; /* Implementation does double buffering */
 | |
| 
 | |
|   if (window->paint_stack != NULL ||
 | |
|       window->implicit_paint != NULL)
 | |
|     return FALSE; /* Don't stack implicit paints */
 | |
| 
 | |
|   /* Never do implicit paints for foreign windows, they don't need
 | |
|    * double buffer combination since they have no client side children,
 | |
|    * and creating surfaces for them is risky since they could disappear
 | |
|    * at any time
 | |
|    */
 | |
|   if (window->window_type == GDK_WINDOW_FOREIGN)
 | |
|     return FALSE;
 | |
| 
 | |
|   paint = g_new (GdkWindowPaint, 1);
 | |
|   paint->region = cairo_region_create (); /* Empty */
 | |
|   paint->uses_implicit = FALSE;
 | |
|   paint->flushed = NULL;
 | |
|   paint->surface = gdk_window_create_similar_surface (window,
 | |
|                                                       gdk_window_get_content (window),
 | |
| 		                                      MAX (rect->width, 1),
 | |
|                                                       MAX (rect->height, 1));
 | |
|   cairo_surface_set_device_offset (paint->surface, -rect->x, -rect->y);
 | |
| 
 | |
|   window->implicit_paint = paint;
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| static cairo_surface_t *
 | |
| gdk_window_ref_impl_surface (GdkWindow *window)
 | |
| {
 | |
|   return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->ref_cairo_surface (gdk_window_get_impl_window (window));
 | |
| }
 | |
| 
 | |
| static cairo_t *
 | |
| gdk_cairo_create_for_impl (GdkWindow *window)
 | |
| {
 | |
|   cairo_surface_t *surface;
 | |
|   cairo_t *cr;
 | |
| 
 | |
|   surface = gdk_window_ref_impl_surface (window);
 | |
|   cr = cairo_create (surface);
 | |
| 
 | |
|   cairo_surface_destroy (surface);
 | |
| 
 | |
|   return cr;
 | |
| }
 | |
| 
 | |
| /* This is called whenever something is drawing directly to the
 | |
|  * window, bypassing the double buffering. When this happens we
 | |
|  * need to mark any the currently drawn data in the double buffer
 | |
|  * as invalid to avoid later drawing it back over the directly
 | |
|  * rendered pixels. We also need to mark this region as "flushed"
 | |
|  * so that if we later try to paint on it double-buffered we need
 | |
|  * to read back the on-window pixels rather than relying on what
 | |
|  * is in the current double-buffer pixmap.
 | |
|  *
 | |
|  * Note that this doesn't correctly handle the case where the
 | |
|  * non-double buffered drawing uses transparency and relies on
 | |
|  * what the windows below it draws. A fix for that would require
 | |
|  * drawing the existing double-buffered background to the window,
 | |
|  * but that causes ugly flashes. Non-double buffered drawing is
 | |
|  * typically only used in old code or when the drawed widget
 | |
|  * already has a double-buffering layer, and in these cases the
 | |
|  * pixels are opaque anyway. If you need transparency, don't
 | |
|  * disable double buffering.
 | |
|  */
 | |
| static void
 | |
| gdk_window_flush_implicit_paint (GdkWindow *window)
 | |
| {
 | |
|   GdkWindow *impl_window;
 | |
|   GdkWindowPaint *paint;
 | |
|   cairo_region_t *region;
 | |
| 
 | |
|   impl_window = gdk_window_get_impl_window (window);
 | |
|   if (impl_window->implicit_paint == NULL)
 | |
|     return;
 | |
| 
 | |
|   paint = impl_window->implicit_paint;
 | |
| 
 | |
|   region = cairo_region_copy (window->clip_region_with_children);
 | |
|   cairo_region_translate (region, window->abs_x, window->abs_y);
 | |
| 
 | |
|   /* Anything in the whole flushed window that was drawn is now
 | |
|      considered unpainted, so that we don't push it back at the
 | |
|      end of the implicit paint overwriting the directly rendered
 | |
|      pixels. */
 | |
|   cairo_region_subtract (paint->region, region);
 | |
| 
 | |
|   /* Save flushed area so we can read it back if we draw over it later */
 | |
|   if (paint->flushed == NULL)
 | |
|     paint->flushed = region;
 | |
|   else
 | |
|     {
 | |
|       cairo_region_union (paint->flushed, region);
 | |
|       cairo_region_destroy (region);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Ends an implicit paint, paired with gdk_window_begin_implicit_paint returning TRUE */
 | |
| static void
 | |
| gdk_window_end_implicit_paint (GdkWindow *window)
 | |
| {
 | |
|   GdkWindowPaint *paint;
 | |
| 
 | |
|   g_assert (gdk_window_has_impl (window));
 | |
| 
 | |
|   g_assert (window->implicit_paint != NULL);
 | |
| 
 | |
|   paint = window->implicit_paint;
 | |
| 
 | |
|   window->implicit_paint = NULL;
 | |
| 
 | |
|   if (!GDK_WINDOW_DESTROYED (window) && !cairo_region_is_empty (paint->region))
 | |
|     {
 | |
|       cairo_t *cr;
 | |
| 
 | |
|       /* Some regions are valid, push these to window now */
 | |
|       cr = gdk_cairo_create_for_impl (window);
 | |
|       gdk_cairo_region (cr, paint->region);
 | |
|       cairo_clip (cr);
 | |
|       cairo_set_source_surface (cr, paint->surface, 0, 0);
 | |
|       cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 | |
|       cairo_paint (cr);
 | |
|       cairo_destroy (cr);
 | |
|     }
 | |
|   
 | |
|   cairo_region_destroy (paint->region);
 | |
|   if (paint->flushed)
 | |
|     cairo_region_destroy (paint->flushed);
 | |
|   cairo_surface_destroy (paint->surface);
 | |
|   g_free (paint);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_begin_paint_rect:
 | |
|  * @window: a #GdkWindow
 | |
|  * @rectangle: rectangle you intend to draw to
 | |
|  *
 | |
|  * A convenience wrapper around gdk_window_begin_paint_region() which
 | |
|  * creates a rectangular region for you. See
 | |
|  * gdk_window_begin_paint_region() for details.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_begin_paint_rect (GdkWindow          *window,
 | |
| 			     const GdkRectangle *rectangle)
 | |
| {
 | |
|   cairo_region_t *region;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   region = cairo_region_create_rectangle (rectangle);
 | |
|   gdk_window_begin_paint_region (window, region);
 | |
|   cairo_region_destroy (region);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_begin_paint_region:
 | |
|  * @window: a #GdkWindow
 | |
|  * @region: region you intend to draw to
 | |
|  *
 | |
|  * Indicates that you are beginning the process of redrawing @region.
 | |
|  * A backing store (offscreen buffer) large enough to contain @region
 | |
|  * will be created. The backing store will be initialized with the
 | |
|  * background color or background surface for @window. Then, all
 | |
|  * drawing operations performed on @window will be diverted to the
 | |
|  * backing store.  When you call gdk_window_end_paint(), the backing
 | |
|  * store will be copied to @window, making it visible onscreen. Only
 | |
|  * the part of @window contained in @region will be modified; that is,
 | |
|  * drawing operations are clipped to @region.
 | |
|  *
 | |
|  * The net result of all this is to remove flicker, because the user
 | |
|  * sees the finished product appear all at once when you call
 | |
|  * gdk_window_end_paint(). If you draw to @window directly without
 | |
|  * calling gdk_window_begin_paint_region(), the user may see flicker
 | |
|  * as individual drawing operations are performed in sequence.  The
 | |
|  * clipping and background-initializing features of
 | |
|  * gdk_window_begin_paint_region() are conveniences for the
 | |
|  * programmer, so you can avoid doing that work yourself.
 | |
|  *
 | |
|  * When using GTK+, the widget system automatically places calls to
 | |
|  * gdk_window_begin_paint_region() and gdk_window_end_paint() around
 | |
|  * emissions of the expose_event signal. That is, if you're writing an
 | |
|  * expose event handler, you can assume that the exposed area in
 | |
|  * #GdkEventExpose has already been cleared to the window background,
 | |
|  * is already set as the clip region, and already has a backing store.
 | |
|  * Therefore in most cases, application code need not call
 | |
|  * gdk_window_begin_paint_region(). (You can disable the automatic
 | |
|  * calls around expose events on a widget-by-widget basis by calling
 | |
|  * gtk_widget_set_double_buffered().)
 | |
|  *
 | |
|  * If you call this function multiple times before calling the
 | |
|  * matching gdk_window_end_paint(), the backing stores are pushed onto
 | |
|  * a stack. gdk_window_end_paint() copies the topmost backing store
 | |
|  * onscreen, subtracts the topmost region from all other regions in
 | |
|  * the stack, and pops the stack. All drawing operations affect only
 | |
|  * the topmost backing store in the stack. One matching call to
 | |
|  * gdk_window_end_paint() is required for each call to
 | |
|  * gdk_window_begin_paint_region().
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_begin_paint_region (GdkWindow       *window,
 | |
| 			       const cairo_region_t *region)
 | |
| {
 | |
| #ifdef USE_BACKING_STORE
 | |
|   GdkRectangle clip_box;
 | |
|   GdkWindowPaint *paint, *implicit_paint;
 | |
|   GdkWindow *impl_window;
 | |
|   GSList *list;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   if (GDK_IS_PAINTABLE (window->impl))
 | |
|     {
 | |
|       GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (window->impl);
 | |
| 
 | |
|       if (iface->begin_paint_region)
 | |
| 	iface->begin_paint_region ((GdkPaintable*)window->impl, window, region);
 | |
| 
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   impl_window = gdk_window_get_impl_window (window);
 | |
|   implicit_paint = impl_window->implicit_paint;
 | |
| 
 | |
|   paint = g_new (GdkWindowPaint, 1);
 | |
|   paint->region = cairo_region_copy (region);
 | |
| 
 | |
|   cairo_region_intersect (paint->region, window->clip_region_with_children);
 | |
|   cairo_region_get_extents (paint->region, &clip_box);
 | |
| 
 | |
|   cairo_region_translate (paint->region, window->abs_x, window->abs_y);
 | |
| 
 | |
|   /* Mark the region as valid on the implicit paint */
 | |
| 
 | |
|   if (implicit_paint)
 | |
|     cairo_region_union (implicit_paint->region, paint->region);
 | |
| 
 | |
|   /* Convert back to normal coords */
 | |
|   cairo_region_translate (paint->region, -window->abs_x, -window->abs_y);
 | |
| 
 | |
|   if (implicit_paint)
 | |
|     {
 | |
|       paint->uses_implicit = TRUE;
 | |
|       paint->surface = cairo_surface_create_for_rectangle (implicit_paint->surface,
 | |
|                                                            window->abs_x + clip_box.x,
 | |
|                                                            window->abs_y + clip_box.y,
 | |
| 			                                   MAX (clip_box.width, 1),
 | |
|                                                            MAX (clip_box.height, 1));
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       paint->uses_implicit = FALSE;
 | |
|       paint->surface = gdk_window_create_similar_surface (window,
 | |
|                                                           gdk_window_get_content (window),
 | |
| 			                                  MAX (clip_box.width, 1),
 | |
|                                                           MAX (clip_box.height, 1));
 | |
|     }
 | |
| 
 | |
|   /* Normally alpha backgrounded client side windows are composited on the implicit paint
 | |
|      by being drawn in back to front order. However, if implicit paints are not used, for
 | |
|      instance if it was flushed due to a non-double-buffered paint in the middle of the
 | |
|      expose we need to copy in the existing data here. */
 | |
|   if (gdk_window_has_alpha (window) &&
 | |
|       (!implicit_paint ||
 | |
|        (implicit_paint && implicit_paint->flushed != NULL && !cairo_region_is_empty (implicit_paint->flushed))))
 | |
|     {
 | |
|       cairo_t *cr = cairo_create (paint->surface);
 | |
|       /* We can't use gdk_cairo_set_source_window here, as that might
 | |
| 	 flush the implicit paint at an unfortunate time, since this
 | |
| 	 would be detected as a draw during non-expose time */
 | |
|       cairo_surface_t *source_surface  = gdk_window_ref_impl_surface (impl_window);
 | |
|       cairo_set_source_surface (cr, source_surface,
 | |
| 				- (window->abs_x + clip_box.x),
 | |
| 				- (window->abs_y + clip_box.y));
 | |
|       cairo_surface_destroy (source_surface);
 | |
| 
 | |
|       /* Only read back the flushed area if any */
 | |
|       if (implicit_paint)
 | |
| 	{
 | |
| 	  cairo_region_t *flushed = cairo_region_copy (implicit_paint->flushed);
 | |
| 	  /* Convert from impl coords */
 | |
| 	  cairo_region_translate (flushed, -window->abs_x, -window->abs_y);
 | |
| 	  cairo_region_intersect (flushed, paint->region);
 | |
| 	  gdk_cairo_region (cr, flushed);
 | |
| 	  cairo_clip (cr);
 | |
| 
 | |
| 	  /* Convert to impl coords */
 | |
| 	  cairo_region_translate (flushed, window->abs_x, window->abs_y);
 | |
| 	  cairo_region_subtract (implicit_paint->flushed, flushed);
 | |
| 	  cairo_region_destroy (flushed);
 | |
| 	}
 | |
|       cairo_paint (cr);
 | |
|       cairo_destroy (cr);
 | |
|     }
 | |
| 
 | |
|   cairo_surface_set_device_offset (paint->surface, -clip_box.x, -clip_box.y);
 | |
| 
 | |
|   for (list = window->paint_stack; list != NULL; list = list->next)
 | |
|     {
 | |
|       GdkWindowPaint *tmp_paint = list->data;
 | |
| 
 | |
|       cairo_region_subtract (tmp_paint->region, paint->region);
 | |
|     }
 | |
| 
 | |
|   window->paint_stack = g_slist_prepend (window->paint_stack, paint);
 | |
| 
 | |
|   if (!cairo_region_is_empty (paint->region))
 | |
|     {
 | |
|       gdk_window_clear_backing_region (window,
 | |
| 				       paint->region);
 | |
|     }
 | |
| 
 | |
| #endif /* USE_BACKING_STORE */
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_end_paint:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Indicates that the backing store created by the most recent call to
 | |
|  * gdk_window_begin_paint_region() should be copied onscreen and
 | |
|  * deleted, leaving the next-most-recent backing store or no backing
 | |
|  * store at all as the active paint region. See
 | |
|  * gdk_window_begin_paint_region() for full details. It is an error to
 | |
|  * call this function without a matching
 | |
|  * gdk_window_begin_paint_region() first.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_end_paint (GdkWindow *window)
 | |
| {
 | |
| #ifdef USE_BACKING_STORE
 | |
|   GdkWindow *composited;
 | |
|   GdkWindowPaint *paint;
 | |
|   GdkRectangle clip_box;
 | |
|   cairo_region_t *full_clip;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   if (GDK_IS_PAINTABLE (window->impl))
 | |
|     {
 | |
|       GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (window->impl);
 | |
| 
 | |
|       if (iface->end_paint)
 | |
| 	iface->end_paint ((GdkPaintable*)window->impl);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   if (window->paint_stack == NULL)
 | |
|     {
 | |
|       g_warning (G_STRLOC": no preceding call to gdk_window_begin_paint_region(), see documentation");
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   paint = window->paint_stack->data;
 | |
| 
 | |
|   window->paint_stack = g_slist_delete_link (window->paint_stack,
 | |
| 					     window->paint_stack);
 | |
| 
 | |
|   cairo_region_get_extents (paint->region, &clip_box);
 | |
| 
 | |
|   if (!paint->uses_implicit)
 | |
|     {
 | |
|       cairo_t *cr;
 | |
| 
 | |
|       gdk_window_flush_outstanding_moves (window);
 | |
| 
 | |
|       full_clip = cairo_region_copy (window->clip_region_with_children);
 | |
|       cairo_region_intersect (full_clip, paint->region);
 | |
| 
 | |
|       cr = gdk_cairo_create (window);
 | |
|       cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 | |
|       cairo_set_source_surface (cr, paint->surface, 0, 0);
 | |
|       gdk_cairo_region (cr, full_clip);
 | |
|       cairo_fill (cr);
 | |
| 
 | |
|       cairo_destroy (cr);
 | |
|       cairo_region_destroy (full_clip);
 | |
|     }
 | |
| 
 | |
|   cairo_surface_destroy (paint->surface);
 | |
|   cairo_region_destroy (paint->region);
 | |
|   g_free (paint);
 | |
| 
 | |
|   /* find a composited window in our hierarchy to signal its
 | |
|    * parent to redraw, calculating the clip box as we go...
 | |
|    *
 | |
|    * stop if parent becomes NULL since then we'd have nowhere
 | |
|    * to draw (ie: 'composited' will always be non-NULL here).
 | |
|    */
 | |
|   for (composited = window;
 | |
|        composited->parent;
 | |
|        composited = composited->parent)
 | |
|     {
 | |
|       clip_box.x += composited->x;
 | |
|       clip_box.y += composited->y;
 | |
|       clip_box.width = MIN (clip_box.width, composited->parent->width - clip_box.x);
 | |
|       clip_box.height = MIN (clip_box.height, composited->parent->height - clip_box.y);
 | |
| 
 | |
|       if (composited->composited)
 | |
| 	{
 | |
| 	  gdk_window_invalidate_rect (GDK_WINDOW (composited->parent),
 | |
| 				      &clip_box, FALSE);
 | |
| 	  break;
 | |
| 	}
 | |
|     }
 | |
| #endif /* USE_BACKING_STORE */
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_free_paint_stack (GdkWindow *window)
 | |
| {
 | |
|   if (window->paint_stack)
 | |
|     {
 | |
|       GSList *tmp_list = window->paint_stack;
 | |
| 
 | |
|       while (tmp_list)
 | |
| 	{
 | |
| 	  GdkWindowPaint *paint = tmp_list->data;
 | |
| 
 | |
| 	  if (tmp_list == window->paint_stack)
 | |
| 	    cairo_surface_destroy (paint->surface);
 | |
| 
 | |
| 	  cairo_region_destroy (paint->region);
 | |
| 	  g_free (paint);
 | |
| 
 | |
| 	  tmp_list = tmp_list->next;
 | |
| 	}
 | |
| 
 | |
|       g_slist_free (window->paint_stack);
 | |
|       window->paint_stack = NULL;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| do_move_region_bits_on_impl (GdkWindow *impl_window,
 | |
| 			     cairo_region_t *dest_region, /* In impl window coords */
 | |
| 			     int dx, int dy)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   impl_class = GDK_WINDOW_IMPL_GET_CLASS (impl_window->impl);
 | |
| 
 | |
|   impl_class->translate (impl_window, dest_region, dx, dy);
 | |
| }
 | |
| 
 | |
| static GdkWindowRegionMove *
 | |
| gdk_window_region_move_new (cairo_region_t *region,
 | |
| 			    int dx, int dy)
 | |
| {
 | |
|   GdkWindowRegionMove *move;
 | |
| 
 | |
|   move = g_slice_new (GdkWindowRegionMove);
 | |
|   move->dest_region = cairo_region_copy (region);
 | |
|   move->dx = dx;
 | |
|   move->dy = dy;
 | |
| 
 | |
|   return move;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_region_move_free (GdkWindowRegionMove *move)
 | |
| {
 | |
|   cairo_region_destroy (move->dest_region);
 | |
|   g_slice_free (GdkWindowRegionMove, move);
 | |
| }
 | |
| 
 | |
| static void
 | |
| append_move_region (GdkWindow *impl_window,
 | |
| 		    cairo_region_t *new_dest_region,
 | |
| 		    int dx, int dy)
 | |
| {
 | |
|   GdkWindowRegionMove *move, *old_move;
 | |
|   cairo_region_t *new_total_region, *old_total_region;
 | |
|   cairo_region_t *source_overlaps_destination;
 | |
|   cairo_region_t *non_overwritten;
 | |
|   gboolean added_move;
 | |
|   GList *l, *prev;
 | |
| 
 | |
|   if (cairo_region_is_empty (new_dest_region))
 | |
|     return;
 | |
| 
 | |
|   /* In principle this could just append the move to the list of outstanding
 | |
|      moves that will be replayed before drawing anything when we're handling
 | |
|      exposes. However, we'd like to do a bit better since its commonly the case
 | |
|      that we get multiple copies where A is copied to B and then B is copied
 | |
|      to C, and we'd like to express this as a simple copy A to C operation. */
 | |
| 
 | |
|   /* We approach this by taking the new move and pushing it ahead of moves
 | |
|      starting at the end of the list and stopping when its not safe to do so.
 | |
|      It's not safe to push past a move if either the source of the new move
 | |
|      is in the destination of the old move, or if the destination of the new
 | |
|      move is in the source of the new move, or if the destination of the new
 | |
|      move overlaps the destination of the old move. We simplify this by
 | |
|      just comparing the total regions (src + dest) */
 | |
|   new_total_region = cairo_region_copy (new_dest_region);
 | |
|   cairo_region_translate (new_total_region, -dx, -dy);
 | |
|   cairo_region_union (new_total_region, new_dest_region);
 | |
| 
 | |
|   added_move = FALSE;
 | |
|   for (l = g_list_last (impl_window->outstanding_moves); l != NULL; l = prev)
 | |
|     {
 | |
|       prev = l->prev;
 | |
|       old_move = l->data;
 | |
| 
 | |
|       old_total_region = cairo_region_copy (old_move->dest_region);
 | |
|       cairo_region_translate (old_total_region, -old_move->dx, -old_move->dy);
 | |
|       cairo_region_union (old_total_region, old_move->dest_region);
 | |
| 
 | |
|       cairo_region_intersect (old_total_region, new_total_region);
 | |
|       /* If these regions intersect then its not safe to push the
 | |
| 	 new region before the old one */
 | |
|       if (!cairo_region_is_empty (old_total_region))
 | |
| 	{
 | |
| 	  /* The area where the new moves source overlaps the old ones
 | |
| 	     destination */
 | |
| 	  source_overlaps_destination = cairo_region_copy (new_dest_region);
 | |
| 	  cairo_region_translate (source_overlaps_destination, -dx, -dy);
 | |
| 	  cairo_region_intersect (source_overlaps_destination, old_move->dest_region);
 | |
| 	  cairo_region_translate (source_overlaps_destination, dx, dy);
 | |
| 
 | |
| 	  /* We can do all sort of optimizations here, but to do things safely it becomes
 | |
| 	     quite complicated. However, a very common case is that you copy something first,
 | |
| 	     then copy all that or a subset of it to a new location (i.e. if you scroll twice
 | |
| 	     in the same direction). We'd like to detect this case and optimize it to one
 | |
| 	     copy. */
 | |
| 	  if (cairo_region_equal (source_overlaps_destination, new_dest_region))
 | |
| 	    {
 | |
| 	      /* This means we might be able to replace the old move and the new one
 | |
| 		 with the new one read from the old ones source, and a second copy of
 | |
| 		 the non-overwritten parts of the old move. However, such a split
 | |
| 		 is only valid if the source in the old move isn't overwritten
 | |
| 		 by the destination of the new one */
 | |
| 
 | |
| 	      /* the new destination of old move if split is ok: */
 | |
| 	      non_overwritten = cairo_region_copy (old_move->dest_region);
 | |
| 	      cairo_region_subtract (non_overwritten, new_dest_region);
 | |
| 	      /* move to source region */
 | |
| 	      cairo_region_translate (non_overwritten, -old_move->dx, -old_move->dy);
 | |
| 
 | |
| 	      cairo_region_intersect (non_overwritten, new_dest_region);
 | |
| 	      if (cairo_region_is_empty (non_overwritten))
 | |
| 		{
 | |
| 		  added_move = TRUE;
 | |
| 		  move = gdk_window_region_move_new (new_dest_region,
 | |
| 						     dx + old_move->dx,
 | |
| 						     dy + old_move->dy);
 | |
| 
 | |
| 		  impl_window->outstanding_moves =
 | |
| 		    g_list_insert_before (impl_window->outstanding_moves,
 | |
| 					  l, move);
 | |
| 		  cairo_region_subtract (old_move->dest_region, new_dest_region);
 | |
| 		}
 | |
| 	      cairo_region_destroy (non_overwritten);
 | |
| 	    }
 | |
| 
 | |
| 	  cairo_region_destroy (source_overlaps_destination);
 | |
| 	  cairo_region_destroy (old_total_region);
 | |
| 	  break;
 | |
| 	}
 | |
|       cairo_region_destroy (old_total_region);
 | |
|     }
 | |
| 
 | |
|   cairo_region_destroy (new_total_region);
 | |
| 
 | |
|   if (!added_move)
 | |
|     {
 | |
|       move = gdk_window_region_move_new (new_dest_region, dx, dy);
 | |
| 
 | |
|       if (l == NULL)
 | |
| 	impl_window->outstanding_moves =
 | |
| 	  g_list_prepend (impl_window->outstanding_moves,
 | |
| 			  move);
 | |
|       else
 | |
| 	impl_window->outstanding_moves =
 | |
| 	  g_list_insert_before (impl_window->outstanding_moves,
 | |
| 				l->next, move);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Moves bits and update area by dx/dy in impl window.
 | |
|    Takes ownership of region to avoid copy (because we may change it) */
 | |
| static void
 | |
| move_region_on_impl (GdkWindow *impl_window,
 | |
| 		     cairo_region_t *region, /* In impl window coords */
 | |
| 		     int dx, int dy)
 | |
| {
 | |
|   if ((dx == 0 && dy == 0) ||
 | |
|       cairo_region_is_empty (region))
 | |
|     {
 | |
|       cairo_region_destroy (region);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   g_assert (impl_window == gdk_window_get_impl_window (impl_window));
 | |
| 
 | |
|   /* Move any old invalid regions in the copy source area by dx/dy */
 | |
|   if (impl_window->update_area)
 | |
|     {
 | |
|       cairo_region_t *update_area;
 | |
| 
 | |
|       update_area = cairo_region_copy (region);
 | |
| 
 | |
|       /* Convert from target to source */
 | |
|       cairo_region_translate (update_area, -dx, -dy);
 | |
|       cairo_region_intersect (update_area, impl_window->update_area);
 | |
|       /* We only copy the area, so keep the old update area invalid.
 | |
| 	 It would be safe to remove it too, as code that uses
 | |
| 	 move_region_on_impl generally also invalidate the source
 | |
| 	 area. However, it would just use waste cycles. */
 | |
| 
 | |
|       /* Convert back */
 | |
|       cairo_region_translate (update_area, dx, dy);
 | |
|       cairo_region_union (impl_window->update_area, update_area);
 | |
| 
 | |
|       /* This area of the destination is now invalid,
 | |
| 	 so no need to copy to it.  */
 | |
|       cairo_region_subtract (region, update_area);
 | |
| 
 | |
|       cairo_region_destroy (update_area);
 | |
|     }
 | |
| 
 | |
|   /* If we're currently exposing this window, don't copy to this
 | |
|      destination, as it will be overdrawn when the expose is done,
 | |
|      instead invalidate it and repaint later. */
 | |
|   if (impl_window->implicit_paint)
 | |
|     {
 | |
|       GdkWindowPaint *implicit_paint = impl_window->implicit_paint;
 | |
|       cairo_region_t *exposing;
 | |
| 
 | |
|       exposing = cairo_region_copy (implicit_paint->region);
 | |
|       cairo_region_intersect (exposing, region);
 | |
|       cairo_region_subtract (region, exposing);
 | |
| 
 | |
|       impl_window_add_update_area (impl_window, exposing);
 | |
|       cairo_region_destroy (exposing);
 | |
|     }
 | |
| 
 | |
|   append_move_region (impl_window, region, dx, dy);
 | |
| 
 | |
|   cairo_region_destroy (region);
 | |
| }
 | |
| 
 | |
| /* Flushes all outstanding changes to the window, call this
 | |
|  * before drawing directly to the window (i.e. outside a begin/end_paint pair).
 | |
|  */
 | |
| static void
 | |
| gdk_window_flush_outstanding_moves (GdkWindow *window)
 | |
| {
 | |
|   GdkWindow *impl_window;
 | |
|   GList *l, *outstanding;
 | |
|   GdkWindowRegionMove *move;
 | |
| 
 | |
|   impl_window = gdk_window_get_impl_window (window);
 | |
|   outstanding = impl_window->outstanding_moves;
 | |
|   impl_window->outstanding_moves = NULL;
 | |
| 
 | |
|   for (l = outstanding; l != NULL; l = l->next)
 | |
|     {
 | |
|       move = l->data;
 | |
| 
 | |
|       do_move_region_bits_on_impl (impl_window,
 | |
| 				   move->dest_region, move->dx, move->dy);
 | |
| 
 | |
|       gdk_window_region_move_free (move);
 | |
|     }
 | |
| 
 | |
|   g_list_free (outstanding);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_flush:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Flush all outstanding cached operations on a window, leaving the
 | |
|  * window in a state which reflects all that has been drawn before.
 | |
|  *
 | |
|  * Gdk uses multiple kinds of caching to get better performance and
 | |
|  * nicer drawing. For instance, during exposes all paints to a window
 | |
|  * using double buffered rendering are keep on a surface until the last
 | |
|  * window has been exposed. It also delays window moves/scrolls until
 | |
|  * as long as possible until next update to avoid tearing when moving
 | |
|  * windows.
 | |
|  *
 | |
|  * Normally this should be completely invisible to applications, as
 | |
|  * we automatically flush the windows when required, but this might
 | |
|  * be needed if you for instance mix direct native drawing with
 | |
|  * gdk drawing. For Gtk widgets that don't use double buffering this
 | |
|  * will be called automatically before sending the expose event.
 | |
|  *
 | |
|  * Since: 2.18
 | |
|  **/
 | |
| void
 | |
| gdk_window_flush (GdkWindow *window)
 | |
| {
 | |
|   gdk_window_flush_outstanding_moves (window);
 | |
|   gdk_window_flush_implicit_paint (window);
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_flush_recursive_helper (GdkWindow *window,
 | |
| 				   GdkWindowImpl *impl)
 | |
| {
 | |
|   GdkWindow *child;
 | |
|   GList *l;
 | |
| 
 | |
|   for (l = window->children; l != NULL; l = l->next)
 | |
|     {
 | |
|       child = l->data;
 | |
| 
 | |
|       if (child->impl == impl)
 | |
| 	/* Same impl, ignore */
 | |
| 	gdk_window_flush_recursive_helper (child, impl);
 | |
|       else
 | |
| 	gdk_window_flush_recursive (child);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_flush_recursive (GdkWindow *window)
 | |
| {
 | |
|   gdk_window_flush (window);
 | |
|   gdk_window_flush_recursive_helper (window, window->impl);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_clip_region:
 | |
|  * @window: a #GdkWindow
 | |
|  * 
 | |
|  * Computes the region of a window that potentially can be written
 | |
|  * to by drawing primitives. This region may not take into account
 | |
|  * other factors such as if the window is obscured by other windows,
 | |
|  * but no area outside of this region will be affected by drawing
 | |
|  * primitives.
 | |
|  * 
 | |
|  * Returns: a #cairo_region_t. This must be freed with cairo_region_destroy()
 | |
|  *          when you are done.
 | |
|  **/
 | |
| cairo_region_t*
 | |
| gdk_window_get_clip_region (GdkWindow *window)
 | |
| {
 | |
|   cairo_region_t *result;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_WINDOW (window), NULL);
 | |
| 
 | |
|   result = cairo_region_copy (window->clip_region);
 | |
| 
 | |
|   if (window->paint_stack)
 | |
|     {
 | |
|       cairo_region_t *paint_region = cairo_region_create ();
 | |
|       GSList *tmp_list = window->paint_stack;
 | |
| 
 | |
|       while (tmp_list)
 | |
| 	{
 | |
| 	  GdkWindowPaint *paint = tmp_list->data;
 | |
| 
 | |
| 	  cairo_region_union (paint_region, paint->region);
 | |
| 
 | |
| 	  tmp_list = tmp_list->next;
 | |
| 	}
 | |
| 
 | |
|       cairo_region_intersect (result, paint_region);
 | |
|       cairo_region_destroy (paint_region);
 | |
|     }
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_visible_region:
 | |
|  * @window: a #GdkWindow
 | |
|  * 
 | |
|  * Computes the region of the @window that is potentially visible.
 | |
|  * This does not necessarily take into account if the window is
 | |
|  * obscured by other windows, but no area outside of this region
 | |
|  * is visible.
 | |
|  * 
 | |
|  * Returns: a #cairo_region_t. This must be freed with cairo_region_destroy()
 | |
|  *          when you are done.
 | |
|  **/
 | |
| cairo_region_t *
 | |
| gdk_window_get_visible_region (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   return cairo_region_copy (window->clip_region);
 | |
| }
 | |
| 
 | |
| static cairo_t *
 | |
| setup_backing_rect (GdkWindow *window, GdkWindowPaint *paint)
 | |
| {
 | |
|   GdkWindow *bg_window;
 | |
|   cairo_pattern_t *pattern = NULL;
 | |
|   int x_offset = 0, y_offset = 0;
 | |
|   cairo_t *cr;
 | |
| 
 | |
|   cr = cairo_create (paint->surface);
 | |
| 
 | |
|   for (bg_window = window; bg_window; bg_window = bg_window->parent)
 | |
|     {
 | |
|       pattern = gdk_window_get_background_pattern (bg_window);
 | |
|       if (pattern)
 | |
|         break;
 | |
| 
 | |
|       x_offset += bg_window->x;
 | |
|       y_offset += bg_window->y;
 | |
|     }
 | |
| 
 | |
|   if (pattern)
 | |
|     {
 | |
|       cairo_translate (cr, -x_offset, -y_offset);
 | |
|       cairo_set_source (cr, pattern);
 | |
|       cairo_translate (cr, x_offset, y_offset);
 | |
|     }
 | |
|   else
 | |
|     cairo_set_source_rgb (cr, 0, 0, 0);
 | |
| 
 | |
|   return cr;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_clear_backing_region (GdkWindow *window,
 | |
| 				 cairo_region_t *region)
 | |
| {
 | |
|   GdkWindowPaint *paint = window->paint_stack->data;
 | |
|   cairo_region_t *clip;
 | |
|   cairo_t *cr;
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   cr = setup_backing_rect (window, paint);
 | |
| 
 | |
|   clip = cairo_region_copy (paint->region);
 | |
|   cairo_region_intersect (clip, region);
 | |
| 
 | |
|   gdk_cairo_region (cr, clip);
 | |
|   cairo_fill (cr);
 | |
| 
 | |
|   cairo_destroy (cr);
 | |
| 
 | |
|   cairo_region_destroy (clip);
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_drop_cairo_surface (GdkWindow *window)
 | |
| {
 | |
|   if (window->cairo_surface)
 | |
|     {
 | |
|       cairo_surface_finish (window->cairo_surface);
 | |
|       cairo_surface_set_user_data (window->cairo_surface, &gdk_window_cairo_key,
 | |
| 				   NULL, NULL);
 | |
|       window->cairo_surface = NULL;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_cairo_surface_destroy (void *data)
 | |
| {
 | |
|   GdkWindow *window = data;
 | |
| 
 | |
|   window->cairo_surface = NULL;
 | |
| }
 | |
| 
 | |
| static cairo_surface_t *
 | |
| gdk_window_create_cairo_surface (GdkWindow *window,
 | |
| 				 int width,
 | |
| 				 int height)
 | |
| {
 | |
|   cairo_surface_t *surface, *subsurface;
 | |
|   
 | |
|   surface = gdk_window_ref_impl_surface (window);
 | |
|   if (gdk_window_has_impl (window))
 | |
|     return surface;
 | |
| 
 | |
|   subsurface = cairo_surface_create_for_rectangle (surface,
 | |
|                                                    window->abs_x,
 | |
|                                                    window->abs_y,
 | |
|                                                    width,
 | |
|                                                    height);
 | |
|   cairo_surface_destroy (surface);
 | |
|   return subsurface;
 | |
| }
 | |
| 
 | |
| 
 | |
| cairo_surface_t *
 | |
| _gdk_window_ref_cairo_surface (GdkWindow *window)
 | |
| {
 | |
|   cairo_surface_t *surface;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   if (window->paint_stack)
 | |
|     {
 | |
|       GdkWindowPaint *paint = window->paint_stack->data;
 | |
| 
 | |
|       surface = paint->surface;
 | |
|       cairo_surface_reference (surface);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
| 
 | |
|       /* This will be drawing directly to the window, so flush implicit paint */
 | |
|       gdk_window_flush (window);
 | |
| 
 | |
|       if (!window->cairo_surface)
 | |
| 	{
 | |
| 	  window->cairo_surface = gdk_window_create_cairo_surface (window,
 | |
|                                                                    window->width,
 | |
|                                                                    window->height);
 | |
| 
 | |
| 	  if (window->cairo_surface)
 | |
| 	    {
 | |
| 	      cairo_surface_set_user_data (window->cairo_surface, &gdk_window_cairo_key,
 | |
| 					   window, gdk_window_cairo_surface_destroy);
 | |
| 	    }
 | |
| 	}
 | |
|       else
 | |
| 	cairo_surface_reference (window->cairo_surface);
 | |
| 
 | |
|       surface = window->cairo_surface;
 | |
|     }
 | |
| 
 | |
|   return surface;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_cairo_create:
 | |
|  * @window: a #GdkWindow
 | |
|  * 
 | |
|  * Creates a Cairo context for drawing to @window.
 | |
|  *
 | |
|  * <note><warning>
 | |
|  * Note that calling cairo_reset_clip() on the resulting #cairo_t will
 | |
|  * produce undefined results, so avoid it at all costs.
 | |
|  * </warning></note>
 | |
|  *
 | |
|  * Return value: A newly created Cairo context. Free with
 | |
|  *  cairo_destroy() when you are done drawing.
 | |
|  * 
 | |
|  * Since: 2.8
 | |
|  **/
 | |
| cairo_t *
 | |
| gdk_cairo_create (GdkWindow *window)
 | |
| {
 | |
|   cairo_surface_t *surface;
 | |
|   cairo_t *cr;
 | |
|     
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   surface = _gdk_window_ref_cairo_surface (window);
 | |
|   cr = cairo_create (surface);
 | |
| 
 | |
|   if (!window->paint_stack)
 | |
|     {
 | |
|       gdk_cairo_region (cr, window->clip_region_with_children);
 | |
|       cairo_clip (cr);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       GdkWindowPaint *paint = window->paint_stack->data;
 | |
| 
 | |
|       /* Only needs to clip to region if piggybacking
 | |
| 	 on an implicit paint */
 | |
|       if (paint->uses_implicit)
 | |
| 	{
 | |
| 	  gdk_cairo_region (cr, paint->region);
 | |
| 	  cairo_clip (cr);
 | |
| 	}
 | |
|     }
 | |
|     
 | |
|   cairo_surface_destroy (surface);
 | |
| 
 | |
|   return cr;
 | |
| }
 | |
| 
 | |
| /* Code for dirty-region queueing
 | |
|  */
 | |
| static GSList *update_windows = NULL;
 | |
| static guint update_idle = 0;
 | |
| static gboolean debug_updates = FALSE;
 | |
| 
 | |
| static inline gboolean
 | |
| gdk_window_is_ancestor (GdkWindow *window,
 | |
| 			GdkWindow *ancestor)
 | |
| {
 | |
|   while (window)
 | |
|     {
 | |
|       GdkWindow *parent = window->parent;
 | |
| 
 | |
|       if (parent == ancestor)
 | |
| 	return TRUE;
 | |
| 
 | |
|       window = parent;
 | |
|     }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_add_update_window (GdkWindow *window)
 | |
| {
 | |
|   GSList *tmp;
 | |
|   GSList *prev = NULL;
 | |
|   gboolean has_ancestor_in_list = FALSE;
 | |
| 
 | |
|   for (tmp = update_windows; tmp; tmp = tmp->next)
 | |
|     {
 | |
|       GdkWindow *parent = window->parent;
 | |
| 
 | |
|       /*  check if tmp is an ancestor of "window"; if it is, set a
 | |
|        *  flag indicating that all following windows are either
 | |
|        *  children of "window" or from a differen hierarchy
 | |
|        */
 | |
|       if (!has_ancestor_in_list && gdk_window_is_ancestor (window, tmp->data))
 | |
| 	has_ancestor_in_list = TRUE;
 | |
| 
 | |
|       /* insert in reverse stacking order when adding around siblings,
 | |
|        * so processing updates properly paints over lower stacked windows
 | |
|        */
 | |
|       if (parent == GDK_WINDOW (tmp->data)->parent)
 | |
| 	{
 | |
| 	  gint index = g_list_index (parent->children, window);
 | |
| 	  for (; tmp && parent == GDK_WINDOW (tmp->data)->parent; tmp = tmp->next)
 | |
| 	    {
 | |
| 	      gint sibling_index = g_list_index (parent->children, tmp->data);
 | |
| 	      if (index > sibling_index)
 | |
| 		break;
 | |
| 	      prev = tmp;
 | |
| 	    }
 | |
| 	  /* here, tmp got advanced past all lower stacked siblings */
 | |
| 	  tmp = g_slist_prepend (tmp, window);
 | |
| 	  if (prev)
 | |
| 	    prev->next = tmp;
 | |
| 	  else
 | |
| 	    update_windows = tmp;
 | |
| 	  return;
 | |
| 	}
 | |
| 
 | |
|       /*  if "window" has an ancestor in the list and tmp is one of
 | |
|        *  "window's" children, insert "window" before tmp
 | |
|        */
 | |
|       if (has_ancestor_in_list && gdk_window_is_ancestor (tmp->data, window))
 | |
| 	{
 | |
| 	  tmp = g_slist_prepend (tmp, window);
 | |
| 
 | |
| 	  if (prev)
 | |
| 	    prev->next = tmp;
 | |
| 	  else
 | |
| 	    update_windows = tmp;
 | |
| 	  return;
 | |
| 	}
 | |
| 
 | |
|       /*  if we're at the end of the list and had an ancestor it it,
 | |
|        *  append to the list
 | |
|        */
 | |
|       if (! tmp->next && has_ancestor_in_list)
 | |
| 	{
 | |
| 	  tmp = g_slist_append (tmp, window);
 | |
| 	  return;
 | |
| 	}
 | |
| 
 | |
|       prev = tmp;
 | |
|     }
 | |
| 
 | |
|   /*  if all above checks failed ("window" is from a different
 | |
|    *  hierarchy than what is already in the list) or the list is
 | |
|    *  empty, prepend
 | |
|    */
 | |
|   update_windows = g_slist_prepend (update_windows, window);
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_remove_update_window (GdkWindow *window)
 | |
| {
 | |
|   update_windows = g_slist_remove (update_windows, window);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_window_update_idle (gpointer data)
 | |
| {
 | |
|   gdk_window_process_all_updates ();
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_window_is_toplevel_frozen (GdkWindow *window)
 | |
| {
 | |
|   GdkWindow *toplevel;
 | |
| 
 | |
|   toplevel = gdk_window_get_toplevel (window);
 | |
| 
 | |
|   return toplevel->update_and_descendants_freeze_count > 0;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_schedule_update (GdkWindow *window)
 | |
| {
 | |
|   if (window &&
 | |
|       (window->update_freeze_count ||
 | |
|        gdk_window_is_toplevel_frozen (window)))
 | |
|     return;
 | |
| 
 | |
|   if (!update_idle)
 | |
|     update_idle =
 | |
|       gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW,
 | |
| 				 gdk_window_update_idle,
 | |
| 				 NULL, NULL);
 | |
| }
 | |
| 
 | |
| void
 | |
| _gdk_window_process_updates_recurse (GdkWindow *window,
 | |
| 				     cairo_region_t *expose_region)
 | |
| {
 | |
|   GdkWindow *child;
 | |
|   cairo_region_t *clipped_expose_region;
 | |
|   GList *l, *children;
 | |
| 
 | |
|   if (cairo_region_is_empty (expose_region))
 | |
|     return;
 | |
| 
 | |
|   if (gdk_window_is_offscreen (window->impl_window) &&
 | |
|       gdk_window_has_impl (window))
 | |
|     _gdk_window_add_damage ((GdkWindow *) window->impl_window, expose_region);
 | |
| 
 | |
| 
 | |
|   /* Paint the window before the children, clipped to the window region
 | |
|      with visible child windows removed */
 | |
|   clipped_expose_region = cairo_region_copy (expose_region);
 | |
|   cairo_region_intersect (clipped_expose_region, window->clip_region_with_children);
 | |
| 
 | |
|   if (!cairo_region_is_empty (clipped_expose_region) &&
 | |
|       !window->destroyed)
 | |
|     {
 | |
|       if (window->event_mask & GDK_EXPOSURE_MASK)
 | |
| 	{
 | |
| 	  GdkEvent event;
 | |
| 
 | |
| 	  event.expose.type = GDK_EXPOSE;
 | |
| 	  event.expose.window = g_object_ref (window);
 | |
| 	  event.expose.send_event = FALSE;
 | |
| 	  event.expose.count = 0;
 | |
| 	  event.expose.region = clipped_expose_region;
 | |
| 	  cairo_region_get_extents (clipped_expose_region, &event.expose.area);
 | |
| 
 | |
|           _gdk_event_emit (&event);
 | |
| 
 | |
| 	  g_object_unref (window);
 | |
| 	}
 | |
|       else if (window->window_type != GDK_WINDOW_FOREIGN)
 | |
| 	{
 | |
| 	  /* No exposure mask set, so nothing will be drawn, the
 | |
| 	   * app relies on the background being what it specified
 | |
| 	   * for the window. So, we need to clear this manually.
 | |
| 	   *
 | |
| 	   * For foreign windows if expose is not set that generally
 | |
| 	   * means some other client paints them, so don't clear
 | |
| 	   * there.
 | |
| 	   *
 | |
| 	   * We use begin/end_paint around the clear so that we can
 | |
| 	   * piggyback on the implicit paint */
 | |
| 
 | |
| 	  gdk_window_begin_paint_region (window, clipped_expose_region);
 | |
| 	  /* The actual clear happens in begin_paint_region */
 | |
| 	  gdk_window_end_paint (window);
 | |
| 	}
 | |
|     }
 | |
|   cairo_region_destroy (clipped_expose_region);
 | |
| 
 | |
|   /* Make this reentrancy safe for expose handlers freeing windows */
 | |
|   children = g_list_copy (window->children);
 | |
|   g_list_foreach (children, (GFunc)g_object_ref, NULL);
 | |
| 
 | |
|   /* Iterate over children, starting at bottommost */
 | |
|   for (l = g_list_last (children); l != NULL; l = l->prev)
 | |
|     {
 | |
|       child = l->data;
 | |
| 
 | |
|       if (child->destroyed || !GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
 | |
| 	continue;
 | |
| 
 | |
|       /* Ignore offscreen children, as they don't draw in their parent and
 | |
|        * don't take part in the clipping */
 | |
|       if (gdk_window_is_offscreen (child))
 | |
| 	continue;
 | |
| 
 | |
|       /* Client side child, expose */
 | |
|       if (child->impl == window->impl)
 | |
| 	{
 | |
| 	  cairo_region_translate (expose_region, -child->x, -child->y);
 | |
| 	  _gdk_window_process_updates_recurse ((GdkWindow *)child, expose_region);
 | |
| 	  cairo_region_translate (expose_region, child->x, child->y);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   g_list_free_full (children, g_object_unref);
 | |
| 
 | |
| }
 | |
| 
 | |
| /* Process and remove any invalid area on the native window by creating
 | |
|  * expose events for the window and all non-native descendants.
 | |
|  * Also processes any outstanding moves on the window before doing
 | |
|  * any drawing. Note that its possible to have outstanding moves without
 | |
|  * any invalid area as we use the update idle mechanism to coalesce
 | |
|  * multiple moves as well as multiple invalidations.
 | |
|  */
 | |
| static void
 | |
| gdk_window_process_updates_internal (GdkWindow *window)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
|   gboolean save_region = FALSE;
 | |
|   GdkRectangle clip_box;
 | |
| 
 | |
|   /* Ensure the window lives while updating it */
 | |
|   g_object_ref (window);
 | |
| 
 | |
|   /* If an update got queued during update processing, we can get a
 | |
|    * window in the update queue that has an empty update_area.
 | |
|    * just ignore it.
 | |
|    */
 | |
|   if (window->update_area)
 | |
|     {
 | |
|       cairo_region_t *update_area = window->update_area;
 | |
|       window->update_area = NULL;
 | |
| 
 | |
|       if (gdk_window_is_viewable (window))
 | |
| 	{
 | |
| 	  cairo_region_t *expose_region;
 | |
| 	  gboolean end_implicit;
 | |
| 
 | |
| 	  /* Clip to part visible in toplevel */
 | |
| 	  cairo_region_intersect (update_area, window->clip_region);
 | |
| 
 | |
| 	  if (debug_updates)
 | |
| 	    {
 | |
| 	      /* Make sure we see the red invalid area before redrawing. */
 | |
| 	      gdk_display_sync (gdk_window_get_display (window));
 | |
| 	      g_usleep (70000);
 | |
| 	    }
 | |
| 
 | |
| 	  /* At this point we will be completely redrawing all of update_area.
 | |
| 	   * If we have any outstanding moves that end up moving stuff inside
 | |
| 	   * this area we don't actually need to move that as that part would
 | |
| 	   * be overdrawn by the expose anyway. So, in order to copy less data
 | |
| 	   * we remove these areas from the outstanding moves.
 | |
| 	   */
 | |
| 	  if (window->outstanding_moves)
 | |
| 	    {
 | |
| 	      GdkWindowRegionMove *move;
 | |
| 	      cairo_region_t *remove;
 | |
| 	      GList *l, *prev;
 | |
| 
 | |
| 	      remove = cairo_region_copy (update_area);
 | |
| 	      /* We iterate backwards, starting from the state that would be
 | |
| 		 if we had applied all the moves. */
 | |
| 	      for (l = g_list_last (window->outstanding_moves); l != NULL; l = prev)
 | |
| 		{
 | |
| 		  prev = l->prev;
 | |
| 		  move = l->data;
 | |
| 
 | |
| 		  /* Don't need this area */
 | |
| 		  cairo_region_subtract (move->dest_region, remove);
 | |
| 
 | |
| 		  /* However if any of the destination we do need has a source
 | |
| 		     in the updated region we do need that as a destination for
 | |
| 		     the earlier moves */
 | |
| 		  cairo_region_translate (move->dest_region, -move->dx, -move->dy);
 | |
| 		  cairo_region_subtract (remove, move->dest_region);
 | |
| 
 | |
| 		  if (cairo_region_is_empty (move->dest_region))
 | |
| 		    {
 | |
| 		      gdk_window_region_move_free (move);
 | |
| 		      window->outstanding_moves =
 | |
| 			g_list_delete_link (window->outstanding_moves, l);
 | |
| 		    }
 | |
| 		  else /* move back */
 | |
| 		    cairo_region_translate (move->dest_region, move->dx, move->dy);
 | |
| 		}
 | |
| 	      cairo_region_destroy (remove);
 | |
| 	    }
 | |
| 
 | |
| 	  /* By now we a set of window moves that should be applied, and then
 | |
| 	   * an update region that should be repainted. A trivial implementation
 | |
| 	   * would just do that in order, however in order to get nicer drawing
 | |
| 	   * we do some tricks:
 | |
| 	   *
 | |
| 	   * First of all, each subwindow expose may be double buffered by
 | |
| 	   * itself (depending on widget setting) via
 | |
| 	   * gdk_window_begin/end_paint(). But we also do an "implicit" paint,
 | |
| 	   * creating a single surface the size of the invalid area on the
 | |
| 	   * native window which all the individual normal paints will draw
 | |
| 	   * into. This way in the normal case there will be only one surface
 | |
| 	   * allocated and only once surface draw done for all the windows
 | |
| 	   * in this native window.
 | |
| 	   * There are a couple of reasons this may fail, for instance, some
 | |
| 	   * backends (like quartz) do its own double buffering, so we disable
 | |
| 	   * gdk double buffering there. Secondly, some subwindow could be
 | |
| 	   * non-double buffered and draw directly to the window outside a
 | |
| 	   * begin/end_paint pair. That will be lead to a gdk_window_flush
 | |
| 	   * which immediately executes all outstanding moves and paints+removes
 | |
| 	   * the implicit paint (further paints will allocate their own surfaces).
 | |
| 	   *
 | |
| 	   * Secondly, in the case of implicit double buffering we expose all
 | |
| 	   * the child windows into the implicit surface before we execute
 | |
| 	   * the outstanding moves. This way we minimize the time between
 | |
| 	   * doing the moves and rendering the new update area, thus minimizing
 | |
| 	   * flashing. Of course, if any subwindow is non-double buffered we
 | |
| 	   * well flush earlier than that.
 | |
| 	   *
 | |
| 	   * Thirdly, after having done the outstanding moves we queue an
 | |
| 	   * "antiexpose" on the area that will be drawn by the expose, which
 | |
| 	   * means that any invalid region on the native window side before
 | |
| 	   * the first expose drawing operation will be discarded, as it
 | |
| 	   * has by then been overdrawn with valid data. This means we can
 | |
| 	   * avoid doing the unnecessary repaint any outstanding expose events.
 | |
| 	   */
 | |
| 
 | |
| 	  cairo_region_get_extents (update_area, &clip_box);
 | |
| 	  end_implicit = gdk_window_begin_implicit_paint (window, &clip_box);
 | |
| 	  expose_region = cairo_region_copy (update_area);
 | |
| 	  impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
| 	  if (!end_implicit)
 | |
| 	    {
 | |
| 	      /* Rendering is not double buffered by gdk, do outstanding
 | |
| 	       * moves and queue antiexposure immediately. No need to do
 | |
| 	       * any tricks */
 | |
| 	      gdk_window_flush_outstanding_moves (window);
 | |
| 	      save_region = impl_class->queue_antiexpose (window, update_area);
 | |
| 	    }
 | |
| 	  /* Render the invalid areas to the implicit paint, by sending exposes.
 | |
| 	   * May flush if non-double buffered widget draw. */
 | |
|           impl_class->process_updates_recurse (window, expose_region);
 | |
| 
 | |
| 	  if (end_implicit)
 | |
| 	    {
 | |
| 	      /* Do moves right before exposes are rendered to the window */
 | |
| 	      gdk_window_flush_outstanding_moves (window);
 | |
| 
 | |
| 	      /* By this time we know that any outstanding expose for this
 | |
| 	       * area is invalid and we can avoid it, so queue an antiexpose.
 | |
| 	       * we have already started drawing to the window, so it would
 | |
| 	       * be to late to anti-expose now. Since this is merely an
 | |
| 	       * optimization we just avoid doing it at all in that case.
 | |
| 	       */
 | |
| 	      if (window->implicit_paint != NULL && !window->implicit_paint->flushed)
 | |
|                 save_region = impl_class->queue_antiexpose (window, update_area);
 | |
| 
 | |
| 	      gdk_window_end_implicit_paint (window);
 | |
| 	    }
 | |
| 	  cairo_region_destroy (expose_region);
 | |
| 	}
 | |
|       if (!save_region)
 | |
| 	cairo_region_destroy (update_area);
 | |
|     }
 | |
| 
 | |
|   if (window->outstanding_moves)
 | |
|     {
 | |
|       /* Flush any outstanding moves, may happen if we moved a window but got
 | |
| 	 no actual invalid area */
 | |
|       gdk_window_flush_outstanding_moves (window);
 | |
|     }
 | |
| 
 | |
|   g_object_unref (window);
 | |
| }
 | |
| 
 | |
| static void
 | |
| flush_all_displays (void)
 | |
| {
 | |
|   GSList *displays, *l;
 | |
| 
 | |
|   displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
 | |
|   for (l = displays; l; l = l->next)
 | |
|     gdk_display_flush (l->data);
 | |
| 
 | |
|   g_slist_free (displays);
 | |
| }
 | |
| 
 | |
| static void
 | |
| before_process_all_updates (void)
 | |
| {
 | |
|   GSList *displays, *l;
 | |
|   GdkDisplayClass *display_class;
 | |
| 
 | |
|   displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
 | |
|   display_class = GDK_DISPLAY_GET_CLASS (displays->data);
 | |
|   for (l = displays; l; l = l->next)
 | |
|     display_class->before_process_all_updates (l->data);
 | |
| 
 | |
|   g_slist_free (displays);
 | |
| }
 | |
| 
 | |
| static void
 | |
| after_process_all_updates (void)
 | |
| {
 | |
|   GSList *displays, *l;
 | |
|   GdkDisplayClass *display_class;
 | |
| 
 | |
|   displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
 | |
|   display_class = GDK_DISPLAY_GET_CLASS (displays->data);
 | |
|   for (l = displays; l; l = l->next)
 | |
|     display_class->after_process_all_updates (l->data);
 | |
| 
 | |
|   g_slist_free (displays);
 | |
| }
 | |
| 
 | |
| /* Currently it is not possible to override
 | |
|  * gdk_window_process_all_updates in the same manner as
 | |
|  * gdk_window_process_updates and gdk_window_invalidate_maybe_recurse
 | |
|  * by implementing the GdkPaintable interface.  If in the future a
 | |
|  * backend would need this, the right solution would be to add a
 | |
|  * method to GdkDisplay that can be optionally
 | |
|  * NULL. gdk_window_process_all_updates can then walk the list of open
 | |
|  * displays and call the mehod.
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * gdk_window_process_all_updates:
 | |
|  *
 | |
|  * Calls gdk_window_process_updates() for all windows (see #GdkWindow)
 | |
|  * in the application.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_process_all_updates (void)
 | |
| {
 | |
|   GSList *old_update_windows = update_windows;
 | |
|   GSList *tmp_list = update_windows;
 | |
|   static gboolean in_process_all_updates = FALSE;
 | |
|   static gboolean got_recursive_update = FALSE;
 | |
| 
 | |
|   if (in_process_all_updates)
 | |
|     {
 | |
|       /* We can't do this now since that would recurse, so
 | |
| 	 delay it until after the recursion is done. */
 | |
|       got_recursive_update = TRUE;
 | |
|       update_idle = 0;
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   in_process_all_updates = TRUE;
 | |
|   got_recursive_update = FALSE;
 | |
| 
 | |
|   if (update_idle)
 | |
|     g_source_remove (update_idle);
 | |
| 
 | |
|   update_windows = NULL;
 | |
|   update_idle = 0;
 | |
| 
 | |
|   before_process_all_updates ();
 | |
| 
 | |
|   g_slist_foreach (old_update_windows, (GFunc)g_object_ref, NULL);
 | |
| 
 | |
|   while (tmp_list)
 | |
|     {
 | |
|       GdkWindow *window = tmp_list->data;
 | |
| 
 | |
|       if (!GDK_WINDOW_DESTROYED (window))
 | |
| 	{
 | |
| 	  if (window->update_freeze_count ||
 | |
| 	      gdk_window_is_toplevel_frozen (window))
 | |
| 	    gdk_window_add_update_window (window);
 | |
| 	  else
 | |
| 	    gdk_window_process_updates_internal (window);
 | |
| 	}
 | |
| 
 | |
|       g_object_unref (window);
 | |
|       tmp_list = tmp_list->next;
 | |
|     }
 | |
| 
 | |
|   g_slist_free (old_update_windows);
 | |
| 
 | |
|   flush_all_displays ();
 | |
| 
 | |
|   after_process_all_updates ();
 | |
| 
 | |
|   in_process_all_updates = FALSE;
 | |
| 
 | |
|   /* If we ignored a recursive call, schedule a
 | |
|      redraw now so that it eventually happens,
 | |
|      otherwise we could miss an update if nothing
 | |
|      else schedules an update. */
 | |
|   if (got_recursive_update && !update_idle)
 | |
|     update_idle =
 | |
|       gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW,
 | |
| 				 gdk_window_update_idle,
 | |
| 				 NULL, NULL);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_process_updates:
 | |
|  * @window: a #GdkWindow
 | |
|  * @update_children: whether to also process updates for child windows
 | |
|  *
 | |
|  * Sends one or more expose events to @window. The areas in each
 | |
|  * expose event will cover the entire update area for the window (see
 | |
|  * gdk_window_invalidate_region() for details). Normally GDK calls
 | |
|  * gdk_window_process_all_updates() on your behalf, so there's no
 | |
|  * need to call this function unless you want to force expose events
 | |
|  * to be delivered immediately and synchronously (vs. the usual
 | |
|  * case, where GDK delivers them in an idle handler). Occasionally
 | |
|  * this is useful to produce nicer scrolling behavior, for example.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_process_updates (GdkWindow *window,
 | |
| 			    gboolean   update_children)
 | |
| {
 | |
|   GdkWindow *impl_window;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   /* Make sure the window lives during the expose callouts */
 | |
|   g_object_ref (window);
 | |
| 
 | |
|   impl_window = gdk_window_get_impl_window (window);
 | |
|   if ((impl_window->update_area ||
 | |
|        impl_window->outstanding_moves) &&
 | |
|       !impl_window->update_freeze_count &&
 | |
|       !gdk_window_is_toplevel_frozen (window) &&
 | |
| 
 | |
|       /* Don't recurse into process_updates_internal, we'll
 | |
|        * do the update later when idle instead. */
 | |
|       impl_window->implicit_paint == NULL)
 | |
|     {
 | |
|       gdk_window_process_updates_internal ((GdkWindow *)impl_window);
 | |
|       gdk_window_remove_update_window ((GdkWindow *)impl_window);
 | |
|     }
 | |
| 
 | |
|   if (update_children)
 | |
|     {
 | |
|       /* process updates in reverse stacking order so composition or
 | |
|        * painting over achieves the desired effect for offscreen windows
 | |
|        */
 | |
|       GList *node, *children;
 | |
| 
 | |
|       children = g_list_copy (window->children);
 | |
|       g_list_foreach (children, (GFunc)g_object_ref, NULL);
 | |
| 
 | |
|       for (node = g_list_last (children); node; node = node->prev)
 | |
| 	{
 | |
| 	  gdk_window_process_updates (node->data, TRUE);
 | |
| 	  g_object_unref (node->data);
 | |
| 	}
 | |
| 
 | |
|       g_list_free (children);
 | |
|     }
 | |
| 
 | |
|   g_object_unref (window);
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_invalidate_rect_full (GdkWindow          *window,
 | |
| 				  const GdkRectangle *rect,
 | |
| 				  gboolean            invalidate_children,
 | |
| 				  ClearBg             clear_bg)
 | |
| {
 | |
|   GdkRectangle window_rect;
 | |
|   cairo_region_t *region;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   if (window->input_only || !window->viewable)
 | |
|     return;
 | |
| 
 | |
|   if (!rect)
 | |
|     {
 | |
|       window_rect.x = 0;
 | |
|       window_rect.y = 0;
 | |
|       window_rect.width = window->width;
 | |
|       window_rect.height = window->height;
 | |
|       rect = &window_rect;
 | |
|     }
 | |
| 
 | |
|   region = cairo_region_create_rectangle (rect);
 | |
|   gdk_window_invalidate_region_full (window, region, invalidate_children, clear_bg);
 | |
|   cairo_region_destroy (region);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_invalidate_rect:
 | |
|  * @window: a #GdkWindow
 | |
|  * @rect: (allow-none): rectangle to invalidate or %NULL to invalidate the whole
 | |
|  *      window
 | |
|  * @invalidate_children: whether to also invalidate child windows
 | |
|  *
 | |
|  * A convenience wrapper around gdk_window_invalidate_region() which
 | |
|  * invalidates a rectangular region. See
 | |
|  * gdk_window_invalidate_region() for details.
 | |
|  **/
 | |
| void
 | |
| gdk_window_invalidate_rect (GdkWindow          *window,
 | |
| 			    const GdkRectangle *rect,
 | |
| 			    gboolean            invalidate_children)
 | |
| {
 | |
|   gdk_window_invalidate_rect_full (window, rect, invalidate_children, CLEAR_BG_NONE);
 | |
| }
 | |
| 
 | |
| static void
 | |
| draw_ugly_color (GdkWindow       *window,
 | |
| 		 const cairo_region_t *region)
 | |
| {
 | |
|   cairo_t *cr;
 | |
| 
 | |
|   cr = gdk_cairo_create (window);
 | |
|   /* Draw ugly color all over the newly-invalid region */
 | |
|   cairo_set_source_rgb (cr, 50000/65535., 10000/65535., 10000/65535.);
 | |
|   gdk_cairo_region (cr, region);
 | |
|   cairo_fill (cr);
 | |
| 
 | |
|   cairo_destroy (cr);
 | |
| }
 | |
| 
 | |
| static void
 | |
| impl_window_add_update_area (GdkWindow *impl_window,
 | |
| 			     cairo_region_t *region)
 | |
| {
 | |
|   if (impl_window->update_area)
 | |
|     cairo_region_union (impl_window->update_area, region);
 | |
|   else
 | |
|     {
 | |
|       gdk_window_add_update_window (impl_window);
 | |
|       impl_window->update_area = cairo_region_copy (region);
 | |
|       gdk_window_schedule_update (impl_window);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* clear_bg controls if the region will be cleared to
 | |
|  * the background pattern if the exposure mask is not
 | |
|  * set for the window, whereas this might not otherwise be
 | |
|  * done (unless necessary to emulate background settings).
 | |
|  * Set this to CLEAR_BG_WINCLEARED or CLEAR_BG_ALL if you
 | |
|  * need to clear the background, such as when exposing the area beneath a
 | |
|  * hidden or moved window, but not when an app requests repaint or when the
 | |
|  * windowing system exposes a newly visible area (because then the windowing
 | |
|  * system has already cleared the area).
 | |
|  */
 | |
| static void
 | |
| gdk_window_invalidate_maybe_recurse_full (GdkWindow            *window,
 | |
| 					  const cairo_region_t *region,
 | |
| 					  ClearBg               clear_bg,
 | |
|                                           GdkWindowChildFunc    child_func,
 | |
| 					  gpointer              user_data)
 | |
| {
 | |
|   GdkWindow *impl_window;
 | |
|   cairo_region_t *visible_region;
 | |
|   GList *tmp_list;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   if (window->input_only ||
 | |
|       !window->viewable ||
 | |
|       cairo_region_is_empty (region) ||
 | |
|       window->window_type == GDK_WINDOW_ROOT)
 | |
|     return;
 | |
| 
 | |
|   visible_region = gdk_window_get_visible_region (window);
 | |
|   cairo_region_intersect (visible_region, region);
 | |
| 
 | |
|   tmp_list = window->children;
 | |
|   while (tmp_list)
 | |
|     {
 | |
|       GdkWindow *child = tmp_list->data;
 | |
| 
 | |
|       if (!child->input_only)
 | |
| 	{
 | |
| 	  cairo_region_t *child_region;
 | |
| 	  GdkRectangle child_rect;
 | |
| 
 | |
| 	  child_rect.x = child->x;
 | |
| 	  child_rect.y = child->y;
 | |
| 	  child_rect.width = child->width;
 | |
| 	  child_rect.height = child->height;
 | |
| 	  child_region = cairo_region_create_rectangle (&child_rect);
 | |
| 
 | |
| 	  /* remove child area from the invalid area of the parent */
 | |
| 	  if (GDK_WINDOW_IS_MAPPED (child) && !child->shaped &&
 | |
| 	      !child->composited &&
 | |
| 	      !gdk_window_is_offscreen (child))
 | |
| 	    cairo_region_subtract (visible_region, child_region);
 | |
| 
 | |
| 	  if (child_func && (*child_func) ((GdkWindow *)child, user_data))
 | |
| 	    {
 | |
| 	      cairo_region_t *tmp = cairo_region_copy (region);
 | |
| 
 | |
| 	      cairo_region_translate (tmp, - child_rect.x, - child_rect.y);
 | |
| 	      cairo_region_translate (child_region, - child_rect.x, - child_rect.y);
 | |
| 	      cairo_region_intersect (child_region, tmp);
 | |
| 
 | |
| 	      gdk_window_invalidate_maybe_recurse_full ((GdkWindow *)child,
 | |
| 							child_region, clear_bg, child_func, user_data);
 | |
| 
 | |
| 	      cairo_region_destroy (tmp);
 | |
| 	    }
 | |
| 
 | |
| 	  cairo_region_destroy (child_region);
 | |
| 	}
 | |
| 
 | |
|       tmp_list = tmp_list->next;
 | |
|     }
 | |
| 
 | |
|   impl_window = gdk_window_get_impl_window (window);
 | |
| 
 | |
|   if (!cairo_region_is_empty (visible_region)  ||
 | |
|       /* Even if we're not exposing anything, make sure we process
 | |
| 	 idles for windows with outstanding moves */
 | |
|       (impl_window->outstanding_moves != NULL &&
 | |
|        impl_window->update_area == NULL))
 | |
|     {
 | |
|       if (debug_updates)
 | |
| 	draw_ugly_color (window, region);
 | |
| 
 | |
|       /* Convert to impl coords */
 | |
|       cairo_region_translate (visible_region, window->abs_x, window->abs_y);
 | |
| 
 | |
|       /* Only invalidate area if app requested expose events or if
 | |
| 	 we need to clear the area (by request or to emulate background
 | |
| 	 clearing for non-native windows or native windows with no support
 | |
| 	 for window backgrounds */
 | |
|       if (window->event_mask & GDK_EXPOSURE_MASK ||
 | |
| 	  clear_bg == CLEAR_BG_ALL ||
 | |
| 	  clear_bg == CLEAR_BG_WINCLEARED)
 | |
| 	impl_window_add_update_area (impl_window, visible_region);
 | |
|     }
 | |
| 
 | |
|   cairo_region_destroy (visible_region);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_invalidate_maybe_recurse:
 | |
|  * @window: a #GdkWindow
 | |
|  * @region: a #cairo_region_t
 | |
|  * @child_func: (scope call) (allow-none): function to use to decide if to
 | |
|  *     recurse to a child, %NULL means never recurse.
 | |
|  * @user_data: data passed to @child_func
 | |
|  *
 | |
|  * Adds @region to the update area for @window. The update area is the
 | |
|  * region that needs to be redrawn, or "dirty region." The call
 | |
|  * gdk_window_process_updates() sends one or more expose events to the
 | |
|  * window, which together cover the entire update area. An
 | |
|  * application would normally redraw the contents of @window in
 | |
|  * response to those expose events.
 | |
|  *
 | |
|  * GDK will call gdk_window_process_all_updates() on your behalf
 | |
|  * whenever your program returns to the main loop and becomes idle, so
 | |
|  * normally there's no need to do that manually, you just need to
 | |
|  * invalidate regions that you know should be redrawn.
 | |
|  *
 | |
|  * The @child_func parameter controls whether the region of
 | |
|  * each child window that intersects @region will also be invalidated.
 | |
|  * Only children for which @child_func returns TRUE will have the area
 | |
|  * invalidated.
 | |
|  **/
 | |
| void
 | |
| gdk_window_invalidate_maybe_recurse (GdkWindow            *window,
 | |
| 				     const cairo_region_t *region,
 | |
|                                      GdkWindowChildFunc    child_func,
 | |
| 				     gpointer              user_data)
 | |
| {
 | |
|   gdk_window_invalidate_maybe_recurse_full (window, region, CLEAR_BG_NONE,
 | |
| 					    child_func, user_data);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| true_predicate (GdkWindow *window,
 | |
| 		gpointer   user_data)
 | |
| {
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_invalidate_region_full (GdkWindow       *window,
 | |
| 				    const cairo_region_t *region,
 | |
| 				    gboolean         invalidate_children,
 | |
| 				    ClearBg          clear_bg)
 | |
| {
 | |
|   gdk_window_invalidate_maybe_recurse_full (window, region, clear_bg,
 | |
| 					    invalidate_children ?
 | |
| 					    true_predicate : (gboolean (*) (GdkWindow *, gpointer))NULL,
 | |
| 				       NULL);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_invalidate_region:
 | |
|  * @window: a #GdkWindow
 | |
|  * @region: a #cairo_region_t
 | |
|  * @invalidate_children: %TRUE to also invalidate child windows
 | |
|  *
 | |
|  * Adds @region to the update area for @window. The update area is the
 | |
|  * region that needs to be redrawn, or "dirty region." The call
 | |
|  * gdk_window_process_updates() sends one or more expose events to the
 | |
|  * window, which together cover the entire update area. An
 | |
|  * application would normally redraw the contents of @window in
 | |
|  * response to those expose events.
 | |
|  *
 | |
|  * GDK will call gdk_window_process_all_updates() on your behalf
 | |
|  * whenever your program returns to the main loop and becomes idle, so
 | |
|  * normally there's no need to do that manually, you just need to
 | |
|  * invalidate regions that you know should be redrawn.
 | |
|  *
 | |
|  * The @invalidate_children parameter controls whether the region of
 | |
|  * each child window that intersects @region will also be invalidated.
 | |
|  * If %FALSE, then the update area for child windows will remain
 | |
|  * unaffected. See gdk_window_invalidate_maybe_recurse if you need
 | |
|  * fine grained control over which children are invalidated.
 | |
|  **/
 | |
| void
 | |
| gdk_window_invalidate_region (GdkWindow       *window,
 | |
| 			      const cairo_region_t *region,
 | |
| 			      gboolean         invalidate_children)
 | |
| {
 | |
|   gdk_window_invalidate_maybe_recurse (window, region,
 | |
| 				       invalidate_children ?
 | |
| 					 true_predicate : (gboolean (*) (GdkWindow *, gpointer))NULL,
 | |
| 				       NULL);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * _gdk_window_invalidate_for_expose:
 | |
|  * @window: a #GdkWindow
 | |
|  * @region: a #cairo_region_t
 | |
|  *
 | |
|  * Adds @region to the update area for @window. The update area is the
 | |
|  * region that needs to be redrawn, or "dirty region." The call
 | |
|  * gdk_window_process_updates() sends one or more expose events to the
 | |
|  * window, which together cover the entire update area. An
 | |
|  * application would normally redraw the contents of @window in
 | |
|  * response to those expose events.
 | |
|  *
 | |
|  * GDK will call gdk_window_process_all_updates() on your behalf
 | |
|  * whenever your program returns to the main loop and becomes idle, so
 | |
|  * normally there's no need to do that manually, you just need to
 | |
|  * invalidate regions that you know should be redrawn.
 | |
|  *
 | |
|  * This version of invalidation is used when you recieve expose events
 | |
|  * from the native window system. It exposes the native window, plus
 | |
|  * any non-native child windows (but not native child windows, as those would
 | |
|  * have gotten their own expose events).
 | |
|  **/
 | |
| void
 | |
| _gdk_window_invalidate_for_expose (GdkWindow       *window,
 | |
| 				   cairo_region_t       *region)
 | |
| {
 | |
|   GdkWindowRegionMove *move;
 | |
|   cairo_region_t *move_region;
 | |
|   GList *l;
 | |
| 
 | |
|   /* Any invalidations comming from the windowing system will
 | |
|      be in areas that may be moved by outstanding moves,
 | |
|      so we need to modify the expose region correspondingly,
 | |
|      otherwise we would expose in the wrong place, as the
 | |
|      outstanding moves will be copied before we draw the
 | |
|      exposes. */
 | |
|   for (l = window->outstanding_moves; l != NULL; l = l->next)
 | |
|     {
 | |
|       move = l->data;
 | |
| 
 | |
|       /* covert to move source region */
 | |
|       move_region = cairo_region_copy (move->dest_region);
 | |
|       cairo_region_translate (move_region, -move->dx, -move->dy);
 | |
| 
 | |
|       /* Move area of region that intersects with move source
 | |
| 	 by dx, dy of the move*/
 | |
|       cairo_region_intersect (move_region, region);
 | |
|       cairo_region_subtract (region, move_region);
 | |
|       cairo_region_translate (move_region, move->dx, move->dy);
 | |
|       cairo_region_union (region, move_region);
 | |
| 
 | |
|       cairo_region_destroy (move_region);
 | |
|     }
 | |
| 
 | |
|   gdk_window_invalidate_maybe_recurse_full (window, region, CLEAR_BG_WINCLEARED,
 | |
| 					    (gboolean (*) (GdkWindow *, gpointer))gdk_window_has_no_impl,
 | |
| 					    NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_update_area:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Transfers ownership of the update area from @window to the caller
 | |
|  * of the function. That is, after calling this function, @window will
 | |
|  * no longer have an invalid/dirty region; the update area is removed
 | |
|  * from @window and handed to you. If a window has no update area,
 | |
|  * gdk_window_get_update_area() returns %NULL. You are responsible for
 | |
|  * calling cairo_region_destroy() on the returned region if it's non-%NULL.
 | |
|  *
 | |
|  * Return value: the update area for @window
 | |
|  **/
 | |
| cairo_region_t *
 | |
| gdk_window_get_update_area (GdkWindow *window)
 | |
| {
 | |
|   GdkWindow *impl_window;
 | |
|   cairo_region_t *tmp_region, *to_remove;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   impl_window = gdk_window_get_impl_window (window);
 | |
| 
 | |
|   if (impl_window->update_area)
 | |
|     {
 | |
|       tmp_region = cairo_region_copy (window->clip_region_with_children);
 | |
|       /* Convert to impl coords */
 | |
|       cairo_region_translate (tmp_region, window->abs_x, window->abs_y);
 | |
|       cairo_region_intersect (tmp_region, impl_window->update_area);
 | |
| 
 | |
|       if (cairo_region_is_empty (tmp_region))
 | |
| 	{
 | |
| 	  cairo_region_destroy (tmp_region);
 | |
| 	  return NULL;
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  /* Convert from impl coords */
 | |
| 	  cairo_region_translate (tmp_region, -window->abs_x, -window->abs_y);
 | |
| 
 | |
| 	  /* Don't remove any update area that is overlapped by non-opaque windows
 | |
| 	     (children or siblings) with alpha, as these really need to be repainted
 | |
| 	     independently of this window. */
 | |
| 	  to_remove = cairo_region_copy (tmp_region);
 | |
| 	  cairo_region_subtract (to_remove, window->parent->layered_region);
 | |
| 	  remove_layered_child_area (window, to_remove);
 | |
| 
 | |
| 	  /* Remove from update_area */
 | |
| 	  cairo_region_translate (to_remove, window->abs_x, window->abs_y);
 | |
| 	  cairo_region_subtract (impl_window->update_area, to_remove);
 | |
| 
 | |
| 	  cairo_region_destroy (to_remove);
 | |
| 
 | |
| 	  if (cairo_region_is_empty (impl_window->update_area) &&
 | |
| 	      impl_window->outstanding_moves == NULL)
 | |
| 	    {
 | |
| 	      cairo_region_destroy (impl_window->update_area);
 | |
| 	      impl_window->update_area = NULL;
 | |
| 
 | |
| 	      gdk_window_remove_update_window ((GdkWindow *)impl_window);
 | |
| 	    }
 | |
| 
 | |
| 	  return tmp_region;
 | |
| 	}
 | |
|     }
 | |
|   else
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * _gdk_window_clear_update_area:
 | |
|  * @window: a #GdkWindow.
 | |
|  *
 | |
|  * Internal function to clear the update area for a window. This
 | |
|  * is called when the window is hidden or destroyed.
 | |
|  **/
 | |
| void
 | |
| _gdk_window_clear_update_area (GdkWindow *window)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (window->update_area)
 | |
|     {
 | |
|       gdk_window_remove_update_window (window);
 | |
| 
 | |
|       cairo_region_destroy (window->update_area);
 | |
|       window->update_area = NULL;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_freeze_updates:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Temporarily freezes a window such that it won't receive expose
 | |
|  * events.  The window will begin receiving expose events again when
 | |
|  * gdk_window_thaw_updates() is called. If gdk_window_freeze_updates()
 | |
|  * has been called more than once, gdk_window_thaw_updates() must be called
 | |
|  * an equal number of times to begin processing exposes.
 | |
|  **/
 | |
| void
 | |
| gdk_window_freeze_updates (GdkWindow *window)
 | |
| {
 | |
|   GdkWindow *impl_window;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   impl_window = gdk_window_get_impl_window (window);
 | |
|   impl_window->update_freeze_count++;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_thaw_updates:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Thaws a window frozen with gdk_window_freeze_updates().
 | |
|  **/
 | |
| void
 | |
| gdk_window_thaw_updates (GdkWindow *window)
 | |
| {
 | |
|   GdkWindow *impl_window;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   impl_window = gdk_window_get_impl_window (window);
 | |
| 
 | |
|   g_return_if_fail (impl_window->update_freeze_count > 0);
 | |
| 
 | |
|   if (--impl_window->update_freeze_count == 0)
 | |
|     gdk_window_schedule_update (GDK_WINDOW (impl_window));
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_freeze_toplevel_updates_libgtk_only:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Temporarily freezes a window and all its descendants such that it won't
 | |
|  * receive expose events.  The window will begin receiving expose events
 | |
|  * again when gdk_window_thaw_toplevel_updates_libgtk_only() is called. If
 | |
|  * gdk_window_freeze_toplevel_updates_libgtk_only()
 | |
|  * has been called more than once,
 | |
|  * gdk_window_thaw_toplevel_updates_libgtk_only() must be called
 | |
|  * an equal number of times to begin processing exposes.
 | |
|  *
 | |
|  * This function is not part of the GDK public API and is only
 | |
|  * for use by GTK+.
 | |
|  **/
 | |
| void
 | |
| gdk_window_freeze_toplevel_updates_libgtk_only (GdkWindow *window)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
|   g_return_if_fail (window->window_type != GDK_WINDOW_CHILD);
 | |
| 
 | |
|   window->update_and_descendants_freeze_count++;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_thaw_toplevel_updates_libgtk_only:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Thaws a window frozen with
 | |
|  * gdk_window_freeze_toplevel_updates_libgtk_only().
 | |
|  *
 | |
|  * This function is not part of the GDK public API and is only
 | |
|  * for use by GTK+.
 | |
|  **/
 | |
| void
 | |
| gdk_window_thaw_toplevel_updates_libgtk_only (GdkWindow *window)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
|   g_return_if_fail (window->window_type != GDK_WINDOW_CHILD);
 | |
|   g_return_if_fail (window->update_and_descendants_freeze_count > 0);
 | |
| 
 | |
|   window->update_and_descendants_freeze_count--;
 | |
| 
 | |
|   gdk_window_schedule_update (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_debug_updates:
 | |
|  * @setting: %TRUE to turn on update debugging
 | |
|  *
 | |
|  * With update debugging enabled, calls to
 | |
|  * gdk_window_invalidate_region() clear the invalidated region of the
 | |
|  * screen to a noticeable color, and GDK pauses for a short time
 | |
|  * before sending exposes to windows during
 | |
|  * gdk_window_process_updates().  The net effect is that you can see
 | |
|  * the invalid region for each window and watch redraws as they
 | |
|  * occur. This allows you to diagnose inefficiencies in your application.
 | |
|  *
 | |
|  * In essence, because the GDK rendering model prevents all flicker,
 | |
|  * if you are redrawing the same region 400 times you may never
 | |
|  * notice, aside from noticing a speed problem. Enabling update
 | |
|  * debugging causes GTK to flicker slowly and noticeably, so you can
 | |
|  * see exactly what's being redrawn when, in what order.
 | |
|  *
 | |
|  * The --gtk-debug=updates command line option passed to GTK+ programs
 | |
|  * enables this debug option at application startup time. That's
 | |
|  * usually more useful than calling gdk_window_set_debug_updates()
 | |
|  * yourself, though you might want to use this function to enable
 | |
|  * updates sometime after application startup time.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_debug_updates (gboolean setting)
 | |
| {
 | |
|   debug_updates = setting;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_constrain_size:
 | |
|  * @geometry: a #GdkGeometry structure
 | |
|  * @flags: a mask indicating what portions of @geometry are set
 | |
|  * @width: desired width of window
 | |
|  * @height: desired height of the window
 | |
|  * @new_width: (out): location to store resulting width
 | |
|  * @new_height: (out): location to store resulting height
 | |
|  *
 | |
|  * Constrains a desired width and height according to a
 | |
|  * set of geometry hints (such as minimum and maximum size).
 | |
|  */
 | |
| void
 | |
| gdk_window_constrain_size (GdkGeometry *geometry,
 | |
| 			   guint        flags,
 | |
| 			   gint         width,
 | |
| 			   gint         height,
 | |
| 			   gint        *new_width,
 | |
| 			   gint        *new_height)
 | |
| {
 | |
|   /* This routine is partially borrowed from fvwm.
 | |
|    *
 | |
|    * Copyright 1993, Robert Nation
 | |
|    *     You may use this code for any purpose, as long as the original
 | |
|    *     copyright remains in the source code and all documentation
 | |
|    *
 | |
|    * which in turn borrows parts of the algorithm from uwm
 | |
|    */
 | |
|   gint min_width = 0;
 | |
|   gint min_height = 0;
 | |
|   gint base_width = 0;
 | |
|   gint base_height = 0;
 | |
|   gint xinc = 1;
 | |
|   gint yinc = 1;
 | |
|   gint max_width = G_MAXINT;
 | |
|   gint max_height = G_MAXINT;
 | |
| 
 | |
| #define FLOOR(value, base)	( ((gint) ((value) / (base))) * (base) )
 | |
| 
 | |
|   if ((flags & GDK_HINT_BASE_SIZE) && (flags & GDK_HINT_MIN_SIZE))
 | |
|     {
 | |
|       base_width = geometry->base_width;
 | |
|       base_height = geometry->base_height;
 | |
|       min_width = geometry->min_width;
 | |
|       min_height = geometry->min_height;
 | |
|     }
 | |
|   else if (flags & GDK_HINT_BASE_SIZE)
 | |
|     {
 | |
|       base_width = geometry->base_width;
 | |
|       base_height = geometry->base_height;
 | |
|       min_width = geometry->base_width;
 | |
|       min_height = geometry->base_height;
 | |
|     }
 | |
|   else if (flags & GDK_HINT_MIN_SIZE)
 | |
|     {
 | |
|       base_width = geometry->min_width;
 | |
|       base_height = geometry->min_height;
 | |
|       min_width = geometry->min_width;
 | |
|       min_height = geometry->min_height;
 | |
|     }
 | |
| 
 | |
|   if (flags & GDK_HINT_MAX_SIZE)
 | |
|     {
 | |
|       max_width = geometry->max_width ;
 | |
|       max_height = geometry->max_height;
 | |
|     }
 | |
| 
 | |
|   if (flags & GDK_HINT_RESIZE_INC)
 | |
|     {
 | |
|       xinc = MAX (xinc, geometry->width_inc);
 | |
|       yinc = MAX (yinc, geometry->height_inc);
 | |
|     }
 | |
| 
 | |
|   /* clamp width and height to min and max values
 | |
|    */
 | |
|   width = CLAMP (width, min_width, max_width);
 | |
|   height = CLAMP (height, min_height, max_height);
 | |
| 
 | |
|   /* shrink to base + N * inc
 | |
|    */
 | |
|   width = base_width + FLOOR (width - base_width, xinc);
 | |
|   height = base_height + FLOOR (height - base_height, yinc);
 | |
| 
 | |
|   /* constrain aspect ratio, according to:
 | |
|    *
 | |
|    *                width
 | |
|    * min_aspect <= -------- <= max_aspect
 | |
|    *                height
 | |
|    */
 | |
| 
 | |
|   if (flags & GDK_HINT_ASPECT &&
 | |
|       geometry->min_aspect > 0 &&
 | |
|       geometry->max_aspect > 0)
 | |
|     {
 | |
|       gint delta;
 | |
| 
 | |
|       if (geometry->min_aspect * height > width)
 | |
| 	{
 | |
| 	  delta = FLOOR (height - width / geometry->min_aspect, yinc);
 | |
| 	  if (height - delta >= min_height)
 | |
| 	    height -= delta;
 | |
| 	  else
 | |
| 	    {
 | |
| 	      delta = FLOOR (height * geometry->min_aspect - width, xinc);
 | |
| 	      if (width + delta <= max_width)
 | |
| 		width += delta;
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|       if (geometry->max_aspect * height < width)
 | |
| 	{
 | |
| 	  delta = FLOOR (width - height * geometry->max_aspect, xinc);
 | |
| 	  if (width - delta >= min_width)
 | |
| 	    width -= delta;
 | |
| 	  else
 | |
| 	    {
 | |
| 	      delta = FLOOR (width / geometry->max_aspect - height, yinc);
 | |
| 	      if (height + delta <= max_height)
 | |
| 		height += delta;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
| #undef FLOOR
 | |
| 
 | |
|   *new_width = width;
 | |
|   *new_height = height;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_pointer:
 | |
|  * @window: a #GdkWindow
 | |
|  * @x: (out) (allow-none): return location for X coordinate of pointer or %NULL to not
 | |
|  *      return the X coordinate
 | |
|  * @y: (out) (allow-none):  return location for Y coordinate of pointer or %NULL to not
 | |
|  *      return the Y coordinate
 | |
|  * @mask: (out) (allow-none): return location for modifier mask or %NULL to not return the
 | |
|  *      modifier mask
 | |
|  *
 | |
|  * Obtains the current pointer position and modifier state.
 | |
|  * The position is given in coordinates relative to the upper left
 | |
|  * corner of @window.
 | |
|  *
 | |
|  * Return value: (transfer none): the window containing the pointer (as with
 | |
|  * gdk_window_at_pointer()), or %NULL if the window containing the
 | |
|  * pointer isn't known to GDK
 | |
|  *
 | |
|  * Deprecated: 3.0: Use gdk_window_get_device_position() instead.
 | |
|  **/
 | |
| GdkWindow*
 | |
| gdk_window_get_pointer (GdkWindow	  *window,
 | |
| 			gint		  *x,
 | |
| 			gint		  *y,
 | |
| 			GdkModifierType   *mask)
 | |
| {
 | |
|   GdkDisplay *display;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   display = gdk_window_get_display (window);
 | |
| 
 | |
|   return gdk_window_get_device_position (window, display->core_pointer, x, y, mask);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_device_position:
 | |
|  * @window: a #GdkWindow.
 | |
|  * @device: pointer #GdkDevice to query to.
 | |
|  * @x: (out) (allow-none): return location for the X coordinate of @device, or %NULL.
 | |
|  * @y: (out) (allow-none): return location for the Y coordinate of @device, or %NULL.
 | |
|  * @mask: (out) (allow-none): return location for the modifier mask, or %NULL.
 | |
|  *
 | |
|  * Obtains the current device position and modifier state.
 | |
|  * The position is given in coordinates relative to the upper left
 | |
|  * corner of @window.
 | |
|  *
 | |
|  * Return value: (transfer none): The window underneath @device (as with
 | |
|  * gdk_device_get_window_at_position()), or %NULL if the window is not known to GDK.
 | |
|  *
 | |
|  * Since: 3.0
 | |
|  **/
 | |
| GdkWindow *
 | |
| gdk_window_get_device_position (GdkWindow       *window,
 | |
|                                 GdkDevice       *device,
 | |
|                                 gint            *x,
 | |
|                                 gint            *y,
 | |
|                                 GdkModifierType *mask)
 | |
| {
 | |
|   gint tmp_x, tmp_y;
 | |
|   GdkModifierType tmp_mask;
 | |
|   gboolean normal_child;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
|   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
 | |
|   g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
 | |
| 
 | |
|   normal_child = GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_device_state (window,
 | |
|                                                                              device,
 | |
|                                                                              &tmp_x, &tmp_y,
 | |
|                                                                              &tmp_mask);
 | |
|   /* We got the coords on the impl, convert to the window */
 | |
|   tmp_x -= window->abs_x;
 | |
|   tmp_y -= window->abs_y;
 | |
| 
 | |
|   if (x)
 | |
|     *x = tmp_x;
 | |
|   if (y)
 | |
|     *y = tmp_y;
 | |
|   if (mask)
 | |
|     *mask = tmp_mask;
 | |
| 
 | |
|   _gdk_display_enable_motion_hints (gdk_window_get_display (window), device);
 | |
| 
 | |
|   if (normal_child)
 | |
|     return _gdk_window_find_child_at (window, tmp_x, tmp_y);
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_get_default_root_window:
 | |
|  *
 | |
|  * Obtains the root window (parent all other windows are inside)
 | |
|  * for the default display and screen.
 | |
|  *
 | |
|  * Return value: (transfer none): the default root window
 | |
|  **/
 | |
| GdkWindow *
 | |
| gdk_get_default_root_window (void)
 | |
| {
 | |
|   return gdk_screen_get_root_window (gdk_screen_get_default ());
 | |
| }
 | |
| 
 | |
| static void
 | |
| get_all_native_children (GdkWindow *window,
 | |
| 			 GList **native)
 | |
| {
 | |
|   GdkWindow *child;
 | |
|   GList *l;
 | |
| 
 | |
|   for (l = window->children; l != NULL; l = l->next)
 | |
|     {
 | |
|       child = l->data;
 | |
| 
 | |
|       if (gdk_window_has_impl (child))
 | |
| 	*native = g_list_prepend (*native, child);
 | |
|       else
 | |
| 	get_all_native_children (child, native);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| static inline void
 | |
| gdk_window_raise_internal (GdkWindow *window)
 | |
| {
 | |
|   GdkWindow *parent = window->parent;
 | |
|   GdkWindow *above;
 | |
|   GList *native_children;
 | |
|   GList *l, listhead;
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   if (parent)
 | |
|     {
 | |
|       parent->children = g_list_remove (parent->children, window);
 | |
|       parent->children = g_list_prepend (parent->children, window);
 | |
|     }
 | |
| 
 | |
|   impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|   /* Just do native raise for toplevels */
 | |
|   if (gdk_window_is_toplevel (window) ||
 | |
|       /* The restack_under codepath should work correctly even if the parent
 | |
| 	 is native, but it relies on the order of ->children to be correct,
 | |
| 	 and some apps like SWT reorder the x windows without gdks knowledge,
 | |
| 	 so we use raise directly in order to make these behave as before
 | |
| 	 when using native windows */
 | |
|       (gdk_window_has_impl (window) && gdk_window_has_impl (parent)))
 | |
|     {
 | |
|       impl_class->raise (window);
 | |
|     }
 | |
|   else if (gdk_window_has_impl (window))
 | |
|     {
 | |
|       above = find_native_sibling_above (parent, window);
 | |
|       if (above)
 | |
| 	{
 | |
| 	  listhead.data = window;
 | |
| 	  listhead.next = NULL;
 | |
| 	  listhead.prev = NULL;
 | |
| 	  impl_class->restack_under ((GdkWindow *)above,
 | |
| 				     &listhead);
 | |
| 	}
 | |
|       else
 | |
| 	impl_class->raise (window);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       native_children = NULL;
 | |
|       get_all_native_children (window, &native_children);
 | |
|       if (native_children != NULL)
 | |
| 	{
 | |
| 	  above = find_native_sibling_above (parent, window);
 | |
| 
 | |
| 	  if (above)
 | |
| 	    impl_class->restack_under (above, native_children);
 | |
| 	  else
 | |
| 	    {
 | |
| 	      /* Right order, since native_children is bottom-topmost first */
 | |
| 	      for (l = native_children; l != NULL; l = l->next)
 | |
| 		impl_class->raise (l->data);
 | |
| 	    }
 | |
| 
 | |
| 	  g_list_free (native_children);
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Returns TRUE If the native window was mapped or unmapped */
 | |
| static gboolean
 | |
| set_viewable (GdkWindow *w,
 | |
| 	      gboolean val)
 | |
| {
 | |
|   GdkWindow *child;
 | |
|   GdkWindowImplClass *impl_class;
 | |
|   GList *l;
 | |
| 
 | |
|   if (w->viewable == val)
 | |
|     return FALSE;
 | |
| 
 | |
|   w->viewable = val;
 | |
| 
 | |
|   if (val)
 | |
|     recompute_visible_regions (w, FALSE, FALSE);
 | |
| 
 | |
|   for (l = w->children; l != NULL; l = l->next)
 | |
|     {
 | |
|       child = l->data;
 | |
| 
 | |
|       if (GDK_WINDOW_IS_MAPPED (child) &&
 | |
| 	  child->window_type != GDK_WINDOW_FOREIGN)
 | |
| 	set_viewable (child, val);
 | |
|     }
 | |
| 
 | |
|   if (gdk_window_has_impl (w)  &&
 | |
|       w->window_type != GDK_WINDOW_FOREIGN &&
 | |
|       !gdk_window_is_toplevel (w))
 | |
|     {
 | |
|       /* For most native windows we show/hide them not when they are
 | |
|        * mapped/unmapped, because that may not produce the correct results.
 | |
|        * For instance, if a native window have a non-native parent which is
 | |
|        * hidden, but its native parent is viewable then showing the window
 | |
|        * would make it viewable to X but its not viewable wrt the non-native
 | |
|        * hierarchy. In order to handle this we track the gdk side viewability
 | |
|        * and only map really viewable windows.
 | |
|        *
 | |
|        * There are two exceptions though:
 | |
|        *
 | |
|        * For foreign windows we don't want ever change the mapped state
 | |
|        * except when explicitly done via gdk_window_show/hide, as this may
 | |
|        * cause problems for client owning the foreign window when its window
 | |
|        * is suddenly mapped or unmapped.
 | |
|        *
 | |
|        * For toplevel windows embedded in a foreign window (e.g. a plug)
 | |
|        * we sometimes synthesize a map of a window, but the native
 | |
|        * window is really shown by the embedder, so we don't want to
 | |
|        * do the show ourselves. We can't really tell this case from the normal
 | |
|        * toplevel show as such toplevels are seen by gdk as parents of the
 | |
|        * root window, so we make an exception for all toplevels.
 | |
|        */
 | |
| 
 | |
|       impl_class = GDK_WINDOW_IMPL_GET_CLASS (w->impl);
 | |
|       if (val)
 | |
| 	impl_class->show ((GdkWindow *)w, FALSE);
 | |
|       else
 | |
| 	impl_class->hide ((GdkWindow *)w);
 | |
| 
 | |
|       return TRUE;
 | |
|     }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* Returns TRUE If the native window was mapped or unmapped */
 | |
| gboolean
 | |
| _gdk_window_update_viewable (GdkWindow *window)
 | |
| {
 | |
|   gboolean viewable;
 | |
| 
 | |
|   if (window->window_type == GDK_WINDOW_FOREIGN ||
 | |
|       window->window_type == GDK_WINDOW_ROOT)
 | |
|     viewable = TRUE;
 | |
|   else if (gdk_window_is_toplevel (window) ||
 | |
| 	   window->parent->viewable)
 | |
|     viewable = GDK_WINDOW_IS_MAPPED (window);
 | |
|   else
 | |
|     viewable = FALSE;
 | |
| 
 | |
|   return set_viewable (window, viewable);
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_show_internal (GdkWindow *window, gboolean raise)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
|   gboolean was_mapped, was_viewable;
 | |
|   gboolean did_show;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (window->destroyed)
 | |
|     return;
 | |
| 
 | |
|   was_mapped = GDK_WINDOW_IS_MAPPED (window);
 | |
|   was_viewable = window->viewable;
 | |
| 
 | |
|   if (raise)
 | |
|     /* Keep children in (reverse) stacking order */
 | |
|     gdk_window_raise_internal (window);
 | |
| 
 | |
|   if (gdk_window_has_impl (window))
 | |
|     {
 | |
|       if (!was_mapped)
 | |
| 	gdk_synthesize_window_state (window,
 | |
| 				     GDK_WINDOW_STATE_WITHDRAWN,
 | |
| 				     GDK_WINDOW_STATE_FOCUSED);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       window->state = 0;
 | |
|     }
 | |
| 
 | |
|   did_show = _gdk_window_update_viewable (window);
 | |
| 
 | |
|   /* If it was already viewable the backend show op won't be called, call it
 | |
|      again to ensure things happen right if the mapped tracking was not right
 | |
|      for e.g. a foreign window.
 | |
|      Dunno if this is strictly needed but its what happened pre-csw.
 | |
|      Also show if not done by gdk_window_update_viewable. */
 | |
|   if (gdk_window_has_impl (window) && (was_viewable || !did_show))
 | |
|     {
 | |
|       impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|       impl_class->show (window, !did_show ? was_mapped : TRUE);
 | |
|     }
 | |
| 
 | |
|   if (!was_mapped && !gdk_window_has_impl (window))
 | |
|     {
 | |
|       if (window->event_mask & GDK_STRUCTURE_MASK)
 | |
| 	_gdk_make_event (window, GDK_MAP, NULL, FALSE);
 | |
| 
 | |
|       if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
 | |
| 	_gdk_make_event (window, GDK_MAP, NULL, FALSE);
 | |
|     }
 | |
| 
 | |
|   if (!was_mapped || raise)
 | |
|     {
 | |
|       recompute_visible_regions (window, TRUE, FALSE);
 | |
| 
 | |
|       /* If any decendants became visible we need to send visibility notify */
 | |
|       gdk_window_update_visibility_recursively (window, NULL);
 | |
| 
 | |
|       if (gdk_window_is_viewable (window))
 | |
| 	{
 | |
| 	  _gdk_synthesize_crossing_events_for_geometry_change (window);
 | |
| 	  gdk_window_invalidate_rect_full (window, NULL, TRUE, CLEAR_BG_ALL);
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_show_unraised:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Shows a #GdkWindow onscreen, but does not modify its stacking
 | |
|  * order. In contrast, gdk_window_show() will raise the window
 | |
|  * to the top of the window stack.
 | |
|  *
 | |
|  * On the X11 platform, in Xlib terms, this function calls
 | |
|  * XMapWindow() (it also updates some internal GDK state, which means
 | |
|  * that you can't really use XMapWindow() directly on a GDK window).
 | |
|  */
 | |
| void
 | |
| gdk_window_show_unraised (GdkWindow *window)
 | |
| {
 | |
|   gdk_window_show_internal (window, FALSE);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_raise:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Raises @window to the top of the Z-order (stacking order), so that
 | |
|  * other windows with the same parent window appear below @window.
 | |
|  * This is true whether or not the windows are visible.
 | |
|  *
 | |
|  * If @window is a toplevel, the window manager may choose to deny the
 | |
|  * request to move the window in the Z-order, gdk_window_raise() only
 | |
|  * requests the restack, does not guarantee it.
 | |
|  */
 | |
| void
 | |
| gdk_window_raise (GdkWindow *window)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (window->destroyed)
 | |
|     return;
 | |
| 
 | |
|   /* Keep children in (reverse) stacking order */
 | |
|   gdk_window_raise_internal (window);
 | |
| 
 | |
|   recompute_visible_regions (window, TRUE, FALSE);
 | |
| 
 | |
|   if (gdk_window_is_viewable (window) &&
 | |
|       !window->input_only)
 | |
|     gdk_window_invalidate_region_full (window, window->clip_region, TRUE, CLEAR_BG_ALL);
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_lower_internal (GdkWindow *window)
 | |
| {
 | |
|   GdkWindow *parent = window->parent;
 | |
|   GdkWindowImplClass *impl_class;
 | |
|   GdkWindow *above;
 | |
|   GList *native_children;
 | |
|   GList *l, listhead;
 | |
| 
 | |
|   if (parent)
 | |
|     {
 | |
|       parent->children = g_list_remove (parent->children, window);
 | |
|       parent->children = g_list_append (parent->children, window);
 | |
|     }
 | |
| 
 | |
|   impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|   /* Just do native lower for toplevels */
 | |
|   if (gdk_window_is_toplevel (window) ||
 | |
|       /* The restack_under codepath should work correctly even if the parent
 | |
| 	 is native, but it relies on the order of ->children to be correct,
 | |
| 	 and some apps like SWT reorder the x windows without gdks knowledge,
 | |
| 	 so we use lower directly in order to make these behave as before
 | |
| 	 when using native windows */
 | |
|       (gdk_window_has_impl (window) && gdk_window_has_impl (parent)))
 | |
|     {
 | |
|       impl_class->lower (window);
 | |
|     }
 | |
|   else if (gdk_window_has_impl (window))
 | |
|     {
 | |
|       above = find_native_sibling_above (parent, window);
 | |
|       if (above)
 | |
| 	{
 | |
| 	  listhead.data = window;
 | |
| 	  listhead.next = NULL;
 | |
| 	  listhead.prev = NULL;
 | |
| 	  impl_class->restack_under ((GdkWindow *)above, &listhead);
 | |
| 	}
 | |
|       else
 | |
| 	impl_class->raise (window);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       native_children = NULL;
 | |
|       get_all_native_children (window, &native_children);
 | |
|       if (native_children != NULL)
 | |
| 	{
 | |
| 	  above = find_native_sibling_above (parent, window);
 | |
| 
 | |
| 	  if (above)
 | |
| 	    impl_class->restack_under ((GdkWindow *)above,
 | |
| 				       native_children);
 | |
| 	  else
 | |
| 	    {
 | |
| 	      /* Right order, since native_children is bottom-topmost first */
 | |
| 	      for (l = native_children; l != NULL; l = l->next)
 | |
| 		impl_class->raise (l->data);
 | |
| 	    }
 | |
| 
 | |
| 	  g_list_free (native_children);
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_invalidate_in_parent (GdkWindow *private)
 | |
| {
 | |
|   GdkRectangle r, child;
 | |
| 
 | |
|   if (gdk_window_is_toplevel (private))
 | |
|     return;
 | |
| 
 | |
|   /* get the visible rectangle of the parent */
 | |
|   r.x = r.y = 0;
 | |
|   r.width = private->parent->width;
 | |
|   r.height = private->parent->height;
 | |
| 
 | |
|   child.x = private->x;
 | |
|   child.y = private->y;
 | |
|   child.width = private->width;
 | |
|   child.height = private->height;
 | |
|   gdk_rectangle_intersect (&r, &child, &r);
 | |
| 
 | |
|   gdk_window_invalidate_rect_full (private->parent, &r, TRUE, CLEAR_BG_ALL);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * gdk_window_lower:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Lowers @window to the bottom of the Z-order (stacking order), so that
 | |
|  * other windows with the same parent window appear above @window.
 | |
|  * This is true whether or not the other windows are visible.
 | |
|  *
 | |
|  * If @window is a toplevel, the window manager may choose to deny the
 | |
|  * request to move the window in the Z-order, gdk_window_lower() only
 | |
|  * requests the restack, does not guarantee it.
 | |
|  *
 | |
|  * Note that gdk_window_show() raises the window again, so don't call this
 | |
|  * function before gdk_window_show(). (Try gdk_window_show_unraised().)
 | |
|  */
 | |
| void
 | |
| gdk_window_lower (GdkWindow *window)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (window->destroyed)
 | |
|     return;
 | |
| 
 | |
|   /* Keep children in (reverse) stacking order */
 | |
|   gdk_window_lower_internal (window);
 | |
| 
 | |
|   recompute_visible_regions (window, TRUE, FALSE);
 | |
| 
 | |
|   _gdk_synthesize_crossing_events_for_geometry_change (window);
 | |
|   gdk_window_invalidate_in_parent (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_restack:
 | |
|  * @window: a #GdkWindow
 | |
|  * @sibling: (allow-none): a #GdkWindow that is a sibling of @window, or %NULL
 | |
|  * @above: a boolean
 | |
|  *
 | |
|  * Changes the position of  @window in the Z-order (stacking order), so that
 | |
|  * it is above @sibling (if @above is %TRUE) or below @sibling (if @above is
 | |
|  * %FALSE).
 | |
|  *
 | |
|  * If @sibling is %NULL, then this either raises (if @above is %TRUE) or
 | |
|  * lowers the window.
 | |
|  *
 | |
|  * If @window is a toplevel, the window manager may choose to deny the
 | |
|  * request to move the window in the Z-order, gdk_window_restack() only
 | |
|  * requests the restack, does not guarantee it.
 | |
|  *
 | |
|  * Since: 2.18
 | |
|  */
 | |
| void
 | |
| gdk_window_restack (GdkWindow     *window,
 | |
| 		    GdkWindow     *sibling,
 | |
| 		    gboolean       above)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
|   GdkWindow *parent;
 | |
|   GdkWindow *above_native;
 | |
|   GList *sibling_link;
 | |
|   GList *native_children;
 | |
|   GList *l, listhead;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
|   g_return_if_fail (sibling == NULL || GDK_IS_WINDOW (sibling));
 | |
| 
 | |
|   if (window->destroyed)
 | |
|     return;
 | |
| 
 | |
|   if (sibling == NULL)
 | |
|     {
 | |
|       if (above)
 | |
| 	gdk_window_raise (window);
 | |
|       else
 | |
| 	gdk_window_lower (window);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   if (gdk_window_is_toplevel (window))
 | |
|     {
 | |
|       g_return_if_fail (gdk_window_is_toplevel (sibling));
 | |
|       impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|       impl_class->restack_toplevel (window, sibling, above);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   parent = window->parent;
 | |
|   if (parent)
 | |
|     {
 | |
|       sibling_link = g_list_find (parent->children, sibling);
 | |
|       g_return_if_fail (sibling_link != NULL);
 | |
|       if (sibling_link == NULL)
 | |
| 	return;
 | |
| 
 | |
|       parent->children = g_list_remove (parent->children, window);
 | |
|       if (above)
 | |
| 	parent->children = g_list_insert_before (parent->children,
 | |
| 						 sibling_link,
 | |
| 						 window);
 | |
|       else
 | |
| 	parent->children = g_list_insert_before (parent->children,
 | |
| 						 sibling_link->next,
 | |
| 						 window);
 | |
| 
 | |
|       impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|       if (gdk_window_has_impl (window))
 | |
| 	{
 | |
| 	  above_native = find_native_sibling_above (parent, window);
 | |
| 	  if (above_native)
 | |
| 	    {
 | |
| 	      listhead.data = window;
 | |
| 	      listhead.next = NULL;
 | |
| 	      listhead.prev = NULL;
 | |
| 	      impl_class->restack_under (above_native, &listhead);
 | |
| 	    }
 | |
| 	  else
 | |
| 	    impl_class->raise (window);
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  native_children = NULL;
 | |
| 	  get_all_native_children (window, &native_children);
 | |
| 	  if (native_children != NULL)
 | |
| 	    {
 | |
| 	      above_native = find_native_sibling_above (parent, window);
 | |
| 	      if (above_native)
 | |
| 		impl_class->restack_under (above_native,
 | |
| 					   native_children);
 | |
| 	      else
 | |
| 		{
 | |
| 		  /* Right order, since native_children is bottom-topmost first */
 | |
| 		  for (l = native_children; l != NULL; l = l->next)
 | |
| 		    impl_class->raise (l->data);
 | |
| 		}
 | |
| 
 | |
| 	      g_list_free (native_children);
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   recompute_visible_regions (window, TRUE, FALSE);
 | |
| 
 | |
|   _gdk_synthesize_crossing_events_for_geometry_change (window);
 | |
|   gdk_window_invalidate_in_parent (window);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * gdk_window_show:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Like gdk_window_show_unraised(), but also raises the window to the
 | |
|  * top of the window stack (moves the window to the front of the
 | |
|  * Z-order).
 | |
|  *
 | |
|  * This function maps a window so it's visible onscreen. Its opposite
 | |
|  * is gdk_window_hide().
 | |
|  *
 | |
|  * When implementing a #GtkWidget, you should call this function on the widget's
 | |
|  * #GdkWindow as part of the "map" method.
 | |
|  */
 | |
| void
 | |
| gdk_window_show (GdkWindow *window)
 | |
| {
 | |
|   gdk_window_show_internal (window, TRUE);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_hide:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * For toplevel windows, withdraws them, so they will no longer be
 | |
|  * known to the window manager; for all windows, unmaps them, so
 | |
|  * they won't be displayed. Normally done automatically as
 | |
|  * part of gtk_widget_hide().
 | |
|  */
 | |
| void
 | |
| gdk_window_hide (GdkWindow *window)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
|   gboolean was_mapped, did_hide;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (window->destroyed)
 | |
|     return;
 | |
| 
 | |
|   was_mapped = GDK_WINDOW_IS_MAPPED (window);
 | |
| 
 | |
|   if (gdk_window_has_impl (window))
 | |
|     {
 | |
| 
 | |
|       if (GDK_WINDOW_IS_MAPPED (window))
 | |
| 	gdk_synthesize_window_state (window,
 | |
| 				     0,
 | |
| 				     GDK_WINDOW_STATE_WITHDRAWN);
 | |
|     }
 | |
|   else if (was_mapped)
 | |
|     {
 | |
|       GdkDisplay *display;
 | |
|       GdkDeviceManager *device_manager;
 | |
|       GList *devices, *d;
 | |
| 
 | |
|       /* May need to break grabs on children */
 | |
|       display = gdk_window_get_display (window);
 | |
|       device_manager = gdk_display_get_device_manager (display);
 | |
| 
 | |
|       /* Get all devices */
 | |
|       devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
 | |
|       devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
 | |
|       devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
 | |
| 
 | |
|       for (d = devices; d; d = d->next)
 | |
|         {
 | |
|           GdkDevice *device = d->data;
 | |
| 
 | |
|           if (_gdk_display_end_device_grab (display,
 | |
|                                             device,
 | |
|                                             _gdk_display_get_next_serial (display),
 | |
|                                             window,
 | |
|                                             TRUE))
 | |
|             gdk_device_ungrab (device, GDK_CURRENT_TIME);
 | |
|         }
 | |
| 
 | |
|       window->state = GDK_WINDOW_STATE_WITHDRAWN;
 | |
|       g_list_free (devices);
 | |
|     }
 | |
| 
 | |
|   did_hide = _gdk_window_update_viewable (window);
 | |
| 
 | |
|   /* Hide foreign window as those are not handled by update_viewable. */
 | |
|   if (gdk_window_has_impl (window) && (!did_hide))
 | |
|     {
 | |
|       impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|       impl_class->hide (window);
 | |
|     }
 | |
| 
 | |
|   recompute_visible_regions (window, TRUE, FALSE);
 | |
| 
 | |
|   /* all decendants became non-visible, we need to send visibility notify */
 | |
|   gdk_window_update_visibility_recursively (window, NULL);
 | |
| 
 | |
|   if (was_mapped && !gdk_window_has_impl (window))
 | |
|     {
 | |
|       if (window->event_mask & GDK_STRUCTURE_MASK)
 | |
| 	_gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
 | |
| 
 | |
|       if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
 | |
| 	_gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
 | |
| 
 | |
|       _gdk_synthesize_crossing_events_for_geometry_change (window->parent);
 | |
|     }
 | |
| 
 | |
|   /* Invalidate the rect */
 | |
|   if (was_mapped)
 | |
|     gdk_window_invalidate_in_parent (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_withdraw:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Withdraws a window (unmaps it and asks the window manager to forget about it).
 | |
|  * This function is not really useful as gdk_window_hide() automatically
 | |
|  * withdraws toplevel windows before hiding them.
 | |
|  **/
 | |
| void
 | |
| gdk_window_withdraw (GdkWindow *window)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
|   gboolean was_mapped;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (window->destroyed)
 | |
|     return;
 | |
| 
 | |
|   was_mapped = GDK_WINDOW_IS_MAPPED (window);
 | |
| 
 | |
|   if (gdk_window_has_impl (window))
 | |
|     {
 | |
|       impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|       impl_class->withdraw (window);
 | |
| 
 | |
|       if (was_mapped)
 | |
| 	{
 | |
| 	  if (window->event_mask & GDK_STRUCTURE_MASK)
 | |
| 	    _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
 | |
| 
 | |
| 	  if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
 | |
| 	    _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
 | |
| 
 | |
| 	  _gdk_synthesize_crossing_events_for_geometry_change (window->parent);
 | |
| 	}
 | |
| 
 | |
|       recompute_visible_regions (window, TRUE, FALSE);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_events:
 | |
|  * @window: a #GdkWindow
 | |
|  * @event_mask: event mask for @window
 | |
|  *
 | |
|  * The event mask for a window determines which events will be reported
 | |
|  * for that window from all master input devices. For example, an event mask
 | |
|  * including #GDK_BUTTON_PRESS_MASK means the window should report button
 | |
|  * press events. The event mask is the bitwise OR of values from the
 | |
|  * #GdkEventMask enumeration.
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_events (GdkWindow       *window,
 | |
| 		       GdkEventMask     event_mask)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
|   GdkDisplay *display;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (window->destroyed)
 | |
|     return;
 | |
| 
 | |
|   /* If motion hint is disabled, enable motion events again */
 | |
|   display = gdk_window_get_display (window);
 | |
|   if ((window->event_mask & GDK_POINTER_MOTION_HINT_MASK) &&
 | |
|       !(event_mask & GDK_POINTER_MOTION_HINT_MASK))
 | |
|     {
 | |
|       GList *devices = window->devices_inside;
 | |
| 
 | |
|       while (devices)
 | |
|         {
 | |
|           _gdk_display_enable_motion_hints (display, (GdkDevice *) devices->data);
 | |
|           devices = devices->next;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   window->event_mask = event_mask;
 | |
| 
 | |
|   if (gdk_window_has_impl (window))
 | |
|     {
 | |
|       impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|       impl_class->set_events (window,
 | |
| 			      get_native_event_mask (window));
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_events:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Gets the event mask for @window for all master input devices. See
 | |
|  * gdk_window_set_events().
 | |
|  *
 | |
|  * Return value: event mask for @window
 | |
|  **/
 | |
| GdkEventMask
 | |
| gdk_window_get_events (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 | |
| 
 | |
|   if (window->destroyed)
 | |
|     return 0;
 | |
| 
 | |
|   return window->event_mask;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_device_events:
 | |
|  * @window: a #GdkWindow
 | |
|  * @device: #GdkDevice to enable events for.
 | |
|  * @event_mask: event mask for @window
 | |
|  *
 | |
|  * Sets the event mask for a given device (Normally a floating device, not
 | |
|  * attached to any visible pointer) to @window. For example, an event mask
 | |
|  * including #GDK_BUTTON_PRESS_MASK means the window should report button
 | |
|  * press events. The event mask is the bitwise OR of values from the
 | |
|  * #GdkEventMask enumeration.
 | |
|  *
 | |
|  * Since: 3.0
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_device_events (GdkWindow    *window,
 | |
|                               GdkDevice    *device,
 | |
|                               GdkEventMask  event_mask)
 | |
| {
 | |
|   GdkEventMask device_mask;
 | |
|   GdkDisplay *display;
 | |
|   GdkWindow *native;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
|   g_return_if_fail (GDK_IS_DEVICE (device));
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   /* If motion hint is disabled, enable motion events again */
 | |
|   display = gdk_window_get_display (window);
 | |
|   if ((window->event_mask & GDK_POINTER_MOTION_HINT_MASK) &&
 | |
|       !(event_mask & GDK_POINTER_MOTION_HINT_MASK))
 | |
|     _gdk_display_enable_motion_hints (display, device);
 | |
| 
 | |
|   if (G_UNLIKELY (!window->device_events))
 | |
|     window->device_events = g_hash_table_new (NULL, NULL);
 | |
| 
 | |
|   if (event_mask == 0)
 | |
|     {
 | |
|       /* FIXME: unsetting events on a master device
 | |
|        * would restore window->event_mask
 | |
|        */
 | |
|       g_hash_table_remove (window->device_events, device);
 | |
|     }
 | |
|   else
 | |
|     g_hash_table_insert (window->device_events, device,
 | |
|                          GINT_TO_POINTER (event_mask));
 | |
| 
 | |
|   native = gdk_window_get_toplevel (window);
 | |
| 
 | |
|   while (gdk_window_is_offscreen (native))
 | |
|     {
 | |
|       native = gdk_offscreen_window_get_embedder (native);
 | |
| 
 | |
|       if (native == NULL ||
 | |
| 	  (!_gdk_window_has_impl (native) &&
 | |
| 	   !gdk_window_is_viewable (native)))
 | |
| 	return;
 | |
| 
 | |
|       native = gdk_window_get_toplevel (native);
 | |
|     }
 | |
| 
 | |
|   device_mask = get_native_device_event_mask (window, device);
 | |
|   GDK_DEVICE_GET_CLASS (device)->select_window_events (device, native, device_mask);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_device_events:
 | |
|  * @window: a #GdkWindow.
 | |
|  * @device: a #GdkDevice.
 | |
|  *
 | |
|  * Returns the event mask for @window corresponding to an specific device.
 | |
|  *
 | |
|  * Returns: device event mask for @window
 | |
|  *
 | |
|  * Since: 3.0
 | |
|  **/
 | |
| GdkEventMask
 | |
| gdk_window_get_device_events (GdkWindow *window,
 | |
|                               GdkDevice *device)
 | |
| {
 | |
|   GdkEventMask mask;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 | |
|   g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return 0;
 | |
| 
 | |
|   if (!window->device_events)
 | |
|     return 0;
 | |
| 
 | |
|   mask = GPOINTER_TO_INT (g_hash_table_lookup (window->device_events, device));
 | |
| 
 | |
|   /* FIXME: device could be controlled by window->event_mask */
 | |
| 
 | |
|   return mask;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_move_resize_toplevel (GdkWindow *window,
 | |
|                                  gboolean   with_move,
 | |
|                                  gint       x,
 | |
|                                  gint       y,
 | |
|                                  gint       width,
 | |
|                                  gint       height)
 | |
| {
 | |
|   cairo_region_t *old_region, *new_region;
 | |
|   GdkWindowImplClass *impl_class;
 | |
|   gboolean expose;
 | |
|   gboolean is_resize;
 | |
| 
 | |
|   expose = FALSE;
 | |
|   old_region = NULL;
 | |
| 
 | |
|   is_resize = (width != -1) || (height != -1);
 | |
| 
 | |
|   if (gdk_window_is_viewable (window) &&
 | |
|       !window->input_only)
 | |
|     {
 | |
|       expose = TRUE;
 | |
|       old_region = cairo_region_copy (window->clip_region);
 | |
|     }
 | |
| 
 | |
|   impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|   impl_class->move_resize (window, with_move, x, y, width, height);
 | |
| 
 | |
|   /* Avoid recomputing for pure toplevel moves, for performance reasons */
 | |
|   if (is_resize)
 | |
|     recompute_visible_regions (window, TRUE, FALSE);
 | |
| 
 | |
|   if (expose)
 | |
|     {
 | |
|       new_region = cairo_region_copy (window->clip_region);
 | |
| 
 | |
|       /* This is the newly exposed area (due to any resize),
 | |
|        * X will expose it, but lets do that without the roundtrip
 | |
|        */
 | |
|       cairo_region_subtract (new_region, old_region);
 | |
|       gdk_window_invalidate_region_full (window, new_region, TRUE, CLEAR_BG_WINCLEARED);
 | |
| 
 | |
|       cairo_region_destroy (old_region);
 | |
|       cairo_region_destroy (new_region);
 | |
|     }
 | |
| 
 | |
|   _gdk_synthesize_crossing_events_for_geometry_change (window);
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| move_native_children (GdkWindow *private)
 | |
| {
 | |
|   GList *l;
 | |
|   GdkWindow *child;
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   for (l = private->children; l; l = l->next)
 | |
|     {
 | |
|       child = l->data;
 | |
| 
 | |
|       if (child->impl != private->impl)
 | |
| 	{
 | |
| 	  impl_class = GDK_WINDOW_IMPL_GET_CLASS (child->impl);
 | |
| 	  impl_class->move_resize (child, TRUE,
 | |
| 				   child->x, child->y,
 | |
| 				   child->width, child->height);
 | |
| 	}
 | |
|       else
 | |
| 	move_native_children  (child);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| collect_native_child_region_helper (GdkWindow *window,
 | |
| 				    GdkWindowImpl *impl,
 | |
| 				    cairo_region_t **region,
 | |
| 				    int x_offset,
 | |
| 				    int y_offset)
 | |
| {
 | |
|   GdkWindow *child;
 | |
|   cairo_region_t *tmp;
 | |
|   GList *l;
 | |
| 
 | |
|   for (l = window->children; l != NULL; l = l->next)
 | |
|     {
 | |
|       child = l->data;
 | |
| 
 | |
|       if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only)
 | |
| 	continue;
 | |
| 
 | |
|       if (child->impl != impl)
 | |
| 	{
 | |
| 	  tmp = cairo_region_copy (child->clip_region);
 | |
| 	  cairo_region_translate (tmp,
 | |
| 			     x_offset + child->x,
 | |
| 			     y_offset + child->y);
 | |
| 	  if (*region == NULL)
 | |
| 	    *region = tmp;
 | |
| 	  else
 | |
| 	    {
 | |
| 	      cairo_region_union (*region, tmp);
 | |
| 	      cairo_region_destroy (tmp);
 | |
| 	    }
 | |
| 	}
 | |
|       else
 | |
| 	collect_native_child_region_helper (child, impl, region,
 | |
| 					    x_offset + child->x,
 | |
| 					    y_offset + child->y);
 | |
|     }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| static cairo_region_t *
 | |
| collect_native_child_region (GdkWindow *window,
 | |
| 			     gboolean include_this)
 | |
| {
 | |
|   cairo_region_t *region;
 | |
| 
 | |
|   if (include_this && gdk_window_has_impl (window) && window->viewable)
 | |
|     return cairo_region_copy (window->clip_region);
 | |
| 
 | |
|   region = NULL;
 | |
| 
 | |
|   collect_native_child_region_helper (window, window->impl, ®ion, 0, 0);
 | |
| 
 | |
|   return region;
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| gdk_window_move_resize_internal (GdkWindow *window,
 | |
| 				 gboolean   with_move,
 | |
| 				 gint       x,
 | |
| 				 gint       y,
 | |
| 				 gint       width,
 | |
| 				 gint       height)
 | |
| {
 | |
|   cairo_region_t *old_region, *old_layered, *new_region, *copy_area;
 | |
|   cairo_region_t *old_native_child_region, *new_native_child_region;
 | |
|   GdkWindow *impl_window;
 | |
|   GdkWindowImplClass *impl_class;
 | |
|   gboolean expose;
 | |
|   int old_x, old_y, old_abs_x, old_abs_y;
 | |
|   int dx, dy;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (window->destroyed)
 | |
|     return;
 | |
| 
 | |
|   if (gdk_window_is_toplevel (window))
 | |
|     {
 | |
|       gdk_window_move_resize_toplevel (window, with_move, x, y, width, height);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   /* Bail early if no change */
 | |
|   if (window->width == width &&
 | |
|       window->height == height &&
 | |
|       (!with_move ||
 | |
|        (window->x == x &&
 | |
| 	window->y == y)))
 | |
|     return;
 | |
| 
 | |
|   /* Handle child windows */
 | |
| 
 | |
|   expose = FALSE;
 | |
|   old_region = NULL;
 | |
|   old_layered = NULL;
 | |
| 
 | |
|   impl_window = gdk_window_get_impl_window (window);
 | |
| 
 | |
|   old_x = window->x;
 | |
|   old_y = window->y;
 | |
| 
 | |
|   old_native_child_region = NULL;
 | |
|   if (gdk_window_is_viewable (window) &&
 | |
|       !window->input_only)
 | |
|     {
 | |
|       expose = TRUE;
 | |
| 
 | |
|       old_region = cairo_region_copy (window->clip_region);
 | |
|       old_layered = cairo_region_copy (window->layered_region);
 | |
|       /* Adjust regions to parent window coords */
 | |
|       cairo_region_translate (old_region, window->x, window->y);
 | |
|       cairo_region_translate (old_layered, window->x, window->y);
 | |
| 
 | |
|       old_native_child_region = collect_native_child_region (window, TRUE);
 | |
|       if (old_native_child_region)
 | |
| 	{
 | |
| 	  /* Adjust region to parent window coords */
 | |
| 	  cairo_region_translate (old_native_child_region, window->x, window->y);
 | |
| 
 | |
| 	  /* Any native window move will immediately copy stuff to the destination, which may overwrite a
 | |
| 	   * source or destination for a delayed GdkWindowRegionMove. So, we need
 | |
| 	   * to flush those here for the parent window and all overlapped subwindows
 | |
| 	   * of it. And we need to do this before setting the new clips as those will be
 | |
| 	   * affecting this.
 | |
| 	   */
 | |
| 	  gdk_window_flush_recursive (window->parent);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   /* Set the new position and size */
 | |
|   if (with_move)
 | |
|     {
 | |
|       window->x = x;
 | |
|       window->y = y;
 | |
|     }
 | |
|   if (!(width < 0 && height < 0))
 | |
|     {
 | |
|       if (width < 1)
 | |
| 	width = 1;
 | |
|       window->width = width;
 | |
|       if (height < 1)
 | |
| 	height = 1;
 | |
|       window->height = height;
 | |
|     }
 | |
| 
 | |
|   dx = window->x - old_x;
 | |
|   dy = window->y - old_y;
 | |
| 
 | |
|   old_abs_x = window->abs_x;
 | |
|   old_abs_y = window->abs_y;
 | |
| 
 | |
|   recompute_visible_regions (window, TRUE, FALSE);
 | |
| 
 | |
|   new_native_child_region = NULL;
 | |
|   if (old_native_child_region)
 | |
|     {
 | |
|       new_native_child_region = collect_native_child_region (window, TRUE);
 | |
|       /* Adjust region to parent window coords */
 | |
|       cairo_region_translate (new_native_child_region, window->x, window->y);
 | |
|     }
 | |
| 
 | |
|   if (gdk_window_has_impl (window))
 | |
|     {
 | |
|       impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
| 
 | |
|       /* Do the actual move after recomputing things, as this will have set the shape to
 | |
| 	 the now correct one, thus avoiding copying regions that should not be copied. */
 | |
|       impl_class->move_resize (window, TRUE,
 | |
| 			       window->x, window->y,
 | |
| 			       window->width, window->height);
 | |
|     }
 | |
|   else if (old_abs_x != window->abs_x ||
 | |
| 	   old_abs_y != window->abs_y)
 | |
|     move_native_children (window);
 | |
| 
 | |
|   if (expose)
 | |
|     {
 | |
|       new_region = cairo_region_copy (window->clip_region);
 | |
|       /* Adjust region to parent window coords */
 | |
|       cairo_region_translate (new_region, window->x, window->y);
 | |
| 
 | |
|       /* copy_area:
 | |
|        * Part of the data at the new location can be copied from the
 | |
|        * old location, this area is the intersection of the old region
 | |
|        * moved as the copy will move it and then intersected with
 | |
|        * the new region.
 | |
|        *
 | |
|        * new_region:
 | |
|        * Everything in the old and new regions that is not copied must be
 | |
|        * invalidated (including children) as this is newly exposed
 | |
|        */
 | |
|       if (gdk_window_has_alpha (window))
 | |
| 	copy_area = cairo_region_create (); /* Copy nothing for alpha windows */
 | |
|       else
 | |
| 	copy_area = cairo_region_copy (new_region);
 | |
| 
 | |
|       /* Don't copy from a previously layered region */
 | |
|       cairo_region_translate (old_layered, dx, dy);
 | |
|       cairo_region_subtract (copy_area, old_layered);
 | |
| 
 | |
|       /* Don't copy into a layered region */
 | |
|       cairo_region_translate (copy_area, -window->x, -window->y);
 | |
|       cairo_region_subtract (copy_area, window->layered_region);
 | |
|       cairo_region_translate (copy_area, window->x, window->y);
 | |
| 
 | |
|       cairo_region_union (new_region, old_region);
 | |
| 
 | |
|       if (old_native_child_region)
 | |
| 	{
 | |
| 	  /* Don't copy from inside native children, as this is copied by
 | |
| 	   * the native window move.
 | |
| 	   */
 | |
| 	  cairo_region_subtract (old_region, old_native_child_region);
 | |
| 	}
 | |
|       cairo_region_translate (old_region, dx, dy);
 | |
| 
 | |
|       cairo_region_intersect (copy_area, old_region);
 | |
| 
 | |
|       if (new_native_child_region)
 | |
| 	{
 | |
| 	  /* Don't copy any bits that would cause a read from the moved
 | |
| 	     native windows, as we can't read that data */
 | |
| 	  cairo_region_translate (new_native_child_region, dx, dy);
 | |
| 	  cairo_region_subtract (copy_area, new_native_child_region);
 | |
| 	  cairo_region_translate (new_native_child_region, -dx, -dy);
 | |
| 	}
 | |
| 
 | |
|       cairo_region_subtract (new_region, copy_area);
 | |
| 
 | |
|       /* Convert old region to impl coords */
 | |
|       cairo_region_translate (old_region, -dx + window->abs_x - window->x, -dy + window->abs_y - window->y);
 | |
| 
 | |
|       /* convert from parent coords to impl */
 | |
|       cairo_region_translate (copy_area, window->abs_x - window->x, window->abs_y - window->y);
 | |
| 
 | |
|       move_region_on_impl (impl_window, copy_area, dx, dy); /* takes ownership of copy_area */
 | |
| 
 | |
|       /* Invalidate affected part in the parent window
 | |
|        *  (no higher window should be affected)
 | |
|        * We also invalidate any children in that area, which could include
 | |
|        * this window if it still overlaps that area.
 | |
|        */
 | |
|       if (old_native_child_region)
 | |
| 	{
 | |
| 	  /* No need to expose the region that the native window move copies */
 | |
| 	  cairo_region_translate (old_native_child_region, dx, dy);
 | |
| 	  cairo_region_intersect (old_native_child_region, new_native_child_region);
 | |
| 	  cairo_region_subtract (new_region, old_native_child_region);
 | |
| 	}
 | |
|       gdk_window_invalidate_region_full (window->parent, new_region, TRUE, CLEAR_BG_ALL);
 | |
| 
 | |
|       cairo_region_destroy (old_region);
 | |
|       cairo_region_destroy (old_layered);
 | |
|       cairo_region_destroy (new_region);
 | |
|     }
 | |
| 
 | |
|   if (old_native_child_region)
 | |
|     {
 | |
|       cairo_region_destroy (old_native_child_region);
 | |
|       cairo_region_destroy (new_native_child_region);
 | |
|     }
 | |
| 
 | |
|   _gdk_synthesize_crossing_events_for_geometry_change (window);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * gdk_window_move:
 | |
|  * @window: a #GdkWindow
 | |
|  * @x: X coordinate relative to window's parent
 | |
|  * @y: Y coordinate relative to window's parent
 | |
|  *
 | |
|  * Repositions a window relative to its parent window.
 | |
|  * For toplevel windows, window managers may ignore or modify the move;
 | |
|  * you should probably use gtk_window_move() on a #GtkWindow widget
 | |
|  * anyway, instead of using GDK functions. For child windows,
 | |
|  * the move will reliably succeed.
 | |
|  *
 | |
|  * If you're also planning to resize the window, use gdk_window_move_resize()
 | |
|  * to both move and resize simultaneously, for a nicer visual effect.
 | |
|  **/
 | |
| void
 | |
| gdk_window_move (GdkWindow *window,
 | |
| 		 gint       x,
 | |
| 		 gint       y)
 | |
| {
 | |
|   gdk_window_move_resize_internal (window, TRUE, x, y, -1, -1);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_resize:
 | |
|  * @window: a #GdkWindow
 | |
|  * @width: new width of the window
 | |
|  * @height: new height of the window
 | |
|  *
 | |
|  * Resizes @window; for toplevel windows, asks the window manager to resize
 | |
|  * the window. The window manager may not allow the resize. When using GTK+,
 | |
|  * use gtk_window_resize() instead of this low-level GDK function.
 | |
|  *
 | |
|  * Windows may not be resized below 1x1.
 | |
|  *
 | |
|  * If you're also planning to move the window, use gdk_window_move_resize()
 | |
|  * to both move and resize simultaneously, for a nicer visual effect.
 | |
|  **/
 | |
| void
 | |
| gdk_window_resize (GdkWindow *window,
 | |
| 		   gint       width,
 | |
| 		   gint       height)
 | |
| {
 | |
|   gdk_window_move_resize_internal (window, FALSE, 0, 0, width, height);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * gdk_window_move_resize:
 | |
|  * @window: a #GdkWindow
 | |
|  * @x: new X position relative to window's parent
 | |
|  * @y: new Y position relative to window's parent
 | |
|  * @width: new width
 | |
|  * @height: new height
 | |
|  *
 | |
|  * Equivalent to calling gdk_window_move() and gdk_window_resize(),
 | |
|  * except that both operations are performed at once, avoiding strange
 | |
|  * visual effects. (i.e. the user may be able to see the window first
 | |
|  * move, then resize, if you don't use gdk_window_move_resize().)
 | |
|  **/
 | |
| void
 | |
| gdk_window_move_resize (GdkWindow *window,
 | |
| 			gint       x,
 | |
| 			gint       y,
 | |
| 			gint       width,
 | |
| 			gint       height)
 | |
| {
 | |
|   gdk_window_move_resize_internal (window, TRUE, x, y, width, height);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * gdk_window_scroll:
 | |
|  * @window: a #GdkWindow
 | |
|  * @dx: Amount to scroll in the X direction
 | |
|  * @dy: Amount to scroll in the Y direction
 | |
|  *
 | |
|  * Scroll the contents of @window, both pixels and children, by the
 | |
|  * given amount. @window itself does not move. Portions of the window
 | |
|  * that the scroll operation brings in from offscreen areas are
 | |
|  * invalidated. The invalidated region may be bigger than what would
 | |
|  * strictly be necessary.
 | |
|  *
 | |
|  * For X11, a minimum area will be invalidated if the window has no
 | |
|  * subwindows, or if the edges of the window's parent do not extend
 | |
|  * beyond the edges of the window. In other cases, a multi-step process
 | |
|  * is used to scroll the window which may produce temporary visual
 | |
|  * artifacts and unnecessary invalidations.
 | |
|  **/
 | |
| void
 | |
| gdk_window_scroll (GdkWindow *window,
 | |
| 		   gint       dx,
 | |
| 		   gint       dy)
 | |
| {
 | |
|   GdkWindow *impl_window;
 | |
|   cairo_region_t *copy_area, *noncopy_area, *old_layered_area;
 | |
|   cairo_region_t *old_native_child_region, *new_native_child_region;
 | |
|   GList *tmp_list;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (dx == 0 && dy == 0)
 | |
|     return;
 | |
| 
 | |
|   if (window->destroyed)
 | |
|     return;
 | |
| 
 | |
|   old_layered_area = cairo_region_copy (window->layered_region);
 | |
|   old_native_child_region = collect_native_child_region (window, FALSE);
 | |
|   if (old_native_child_region)
 | |
|     {
 | |
|       /* Any native window move will immediately copy stuff to the destination, which may overwrite a
 | |
|        * source or destination for a delayed GdkWindowRegionMove. So, we need
 | |
|        * to flush those here for the window and all overlapped subwindows
 | |
|        * of it. And we need to do this before setting the new clips as those will be
 | |
|        * affecting this.
 | |
|        */
 | |
|       gdk_window_flush_recursive (window);
 | |
|     }
 | |
| 
 | |
| 
 | |
|   /* First move all child windows, without causing invalidation */
 | |
| 
 | |
|   tmp_list = window->children;
 | |
|   while (tmp_list)
 | |
|     {
 | |
|       GdkWindow *child = GDK_WINDOW (tmp_list->data);
 | |
| 
 | |
|       /* Just update the positions, the bits will move with the copy */
 | |
|       child->x += dx;
 | |
|       child->y += dy;
 | |
| 
 | |
|       tmp_list = tmp_list->next;
 | |
|     }
 | |
| 
 | |
|   recompute_visible_regions (window, FALSE, TRUE);
 | |
| 
 | |
|   new_native_child_region = NULL;
 | |
|   if (old_native_child_region)
 | |
|     new_native_child_region = collect_native_child_region (window, FALSE);
 | |
| 
 | |
|   move_native_children (window);
 | |
| 
 | |
|   /* Then copy the actual bits of the window w/ child windows */
 | |
| 
 | |
|   impl_window = gdk_window_get_impl_window (window);
 | |
| 
 | |
|   /* Calculate the area that can be gotten by copying the old area */
 | |
|   if (gdk_window_has_alpha (window))
 | |
|     copy_area = cairo_region_create (); /* Copy nothing for alpha windows */
 | |
|   else
 | |
|     copy_area = cairo_region_copy (window->clip_region);
 | |
|   cairo_region_subtract (copy_area, old_layered_area);
 | |
|   if (old_native_child_region)
 | |
|     {
 | |
|       /* Don't copy from inside native children, as this is copied by
 | |
|        * the native window move.
 | |
|        */
 | |
|       cairo_region_subtract (copy_area, old_native_child_region);
 | |
| 
 | |
|       /* Don't copy any bits that would cause a read from the moved
 | |
| 	 native windows, as we can't read that data */
 | |
|       cairo_region_subtract (copy_area, new_native_child_region);
 | |
|     }
 | |
|   cairo_region_translate (copy_area, dx, dy);
 | |
|   cairo_region_intersect (copy_area, window->clip_region);
 | |
|   cairo_region_subtract (copy_area, window->layered_region);
 | |
| 
 | |
|   /* And the rest need to be invalidated */
 | |
|   noncopy_area = cairo_region_copy (window->clip_region);
 | |
|   cairo_region_subtract (noncopy_area, copy_area);
 | |
| 
 | |
|   /* convert from window coords to impl */
 | |
|   cairo_region_translate (copy_area, window->abs_x, window->abs_y);
 | |
| 
 | |
|   move_region_on_impl (impl_window, copy_area, dx, dy); /* takes ownership of copy_area */
 | |
| 
 | |
|   /* Invalidate not copied regions */
 | |
|   if (old_native_child_region)
 | |
|     {
 | |
|       /* No need to expose the region that the native window move copies */
 | |
|       cairo_region_translate (old_native_child_region, dx, dy);
 | |
|       cairo_region_intersect (old_native_child_region, new_native_child_region);
 | |
|       cairo_region_subtract (noncopy_area, old_native_child_region);
 | |
|     }
 | |
|   gdk_window_invalidate_region_full (window, noncopy_area, TRUE, CLEAR_BG_ALL);
 | |
| 
 | |
|   cairo_region_destroy (noncopy_area);
 | |
|   cairo_region_destroy (old_layered_area);
 | |
| 
 | |
|   if (old_native_child_region)
 | |
|     {
 | |
|       cairo_region_destroy (old_native_child_region);
 | |
|       cairo_region_destroy (new_native_child_region);
 | |
|     }
 | |
| 
 | |
|   _gdk_synthesize_crossing_events_for_geometry_change (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_move_region:
 | |
|  * @window: a #GdkWindow
 | |
|  * @region: The #cairo_region_t to move
 | |
|  * @dx: Amount to move in the X direction
 | |
|  * @dy: Amount to move in the Y direction
 | |
|  *
 | |
|  * Move the part of @window indicated by @region by @dy pixels in the Y
 | |
|  * direction and @dx pixels in the X direction. The portions of @region
 | |
|  * that not covered by the new position of @region are invalidated.
 | |
|  *
 | |
|  * Child windows are not moved.
 | |
|  *
 | |
|  * Since: 2.8
 | |
|  */
 | |
| void
 | |
| gdk_window_move_region (GdkWindow       *window,
 | |
| 			const cairo_region_t *region,
 | |
| 			gint             dx,
 | |
| 			gint             dy)
 | |
| {
 | |
|   GdkWindow *impl_window;
 | |
|   cairo_region_t *nocopy_area;
 | |
|   cairo_region_t *copy_area;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
|   g_return_if_fail (region != NULL);
 | |
| 
 | |
|   if (dx == 0 && dy == 0)
 | |
|     return;
 | |
| 
 | |
|   if (window->destroyed)
 | |
|     return;
 | |
| 
 | |
|   impl_window = gdk_window_get_impl_window (window);
 | |
| 
 | |
|   /* compute source regions */
 | |
|   if (gdk_window_has_alpha (window))
 | |
|     copy_area = cairo_region_create (); /* Copy nothing for alpha windows */
 | |
|   else
 | |
|     copy_area = cairo_region_copy (region);
 | |
|   cairo_region_intersect (copy_area, window->clip_region_with_children);
 | |
|   cairo_region_subtract (copy_area, window->layered_region);
 | |
|   remove_layered_child_area (window, copy_area);
 | |
| 
 | |
|   /* compute destination regions */
 | |
|   cairo_region_translate (copy_area, dx, dy);
 | |
|   cairo_region_intersect (copy_area, window->clip_region_with_children);
 | |
|   cairo_region_subtract (copy_area, window->layered_region);
 | |
|   remove_layered_child_area (window, copy_area);
 | |
| 
 | |
|   /* Invalidate parts of the region (source and dest) not covered
 | |
|      by the copy */
 | |
|   nocopy_area = cairo_region_copy (region);
 | |
|   cairo_region_translate (nocopy_area, dx, dy);
 | |
|   cairo_region_union (nocopy_area, region);
 | |
|   cairo_region_subtract (nocopy_area, copy_area);
 | |
| 
 | |
|   /* convert from window coords to impl */
 | |
|   cairo_region_translate (copy_area, window->abs_x, window->abs_y);
 | |
|   move_region_on_impl (impl_window, copy_area, dx, dy); /* Takes ownership of copy_area */
 | |
| 
 | |
|   gdk_window_invalidate_region_full (window, nocopy_area, FALSE, CLEAR_BG_ALL);
 | |
|   cairo_region_destroy (nocopy_area);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_background:
 | |
|  * @window: a #GdkWindow
 | |
|  * @color: a #GdkColor
 | |
|  *
 | |
|  * Sets the background color of @window. (However, when using GTK+,
 | |
|  * set the background of a widget with gtk_widget_modify_bg() - if
 | |
|  * you're an application - or gtk_style_set_background() - if you're
 | |
|  * implementing a custom widget.)
 | |
|  *
 | |
|  * See also gdk_window_set_background_pattern().
 | |
|  *
 | |
|  * Deprecated: 3.4: Use gdk_window_set_background_rgba() instead.
 | |
|  */
 | |
| void
 | |
| gdk_window_set_background (GdkWindow      *window,
 | |
| 			   const GdkColor *color)
 | |
| {
 | |
|   cairo_pattern_t *pattern;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   pattern = cairo_pattern_create_rgb (color->red   / 65535.,
 | |
|                                       color->green / 65535.,
 | |
|                                       color->blue  / 65535.);
 | |
| 
 | |
|   gdk_window_set_background_pattern (window, pattern);
 | |
| 
 | |
|   cairo_pattern_destroy (pattern);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_background_rgba:
 | |
|  * @window: a #GdkWindow
 | |
|  * @rgba: a #GdkRGBA color
 | |
|  *
 | |
|  * Sets the background color of @window.
 | |
|  *
 | |
|  * See also gdk_window_set_background_pattern().
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_background_rgba (GdkWindow     *window,
 | |
|                                 const GdkRGBA *rgba)
 | |
| {
 | |
|   cairo_pattern_t *pattern;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
|   g_return_if_fail (rgba != NULL);
 | |
| 
 | |
|   pattern = cairo_pattern_create_rgba (rgba->red, rgba->green,
 | |
|                                        rgba->blue, rgba->alpha);
 | |
| 
 | |
|   gdk_window_set_background_pattern (window, pattern);
 | |
| 
 | |
|   cairo_pattern_destroy (pattern);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Updates has_alpha_background recursively for all child windows
 | |
|    that have parent-relative alpha */
 | |
| static void
 | |
| _gdk_window_propagate_has_alpha_background (GdkWindow *window)
 | |
| {
 | |
|   GdkWindow *child;
 | |
|   GList *l;
 | |
| 
 | |
|   for (l = window->children; l; l = l->next)
 | |
|     {
 | |
|       child = l->data;
 | |
| 
 | |
|       if (child->background == NULL &&
 | |
| 	  child->has_alpha_background != window->has_alpha_background)
 | |
| 	{
 | |
| 	  child->has_alpha_background = window->has_alpha_background;
 | |
| 	  recompute_visible_regions (child, TRUE, FALSE);
 | |
| 	  _gdk_window_propagate_has_alpha_background (child);
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_background_pattern:
 | |
|  * @window: a #GdkWindow
 | |
|  * @pattern: (allow-none): a pattern to use, or %NULL
 | |
|  *
 | |
|  * Sets the background of @window.
 | |
|  *
 | |
|  * A background of %NULL means that the window will inherit its
 | |
|  * background form its parent window.
 | |
|  *
 | |
|  * The windowing system will normally fill a window with its background
 | |
|  * when the window is obscured then exposed.
 | |
|  */
 | |
| void
 | |
| gdk_window_set_background_pattern (GdkWindow *window,
 | |
|                                    cairo_pattern_t *pattern)
 | |
| {
 | |
|   gboolean has_alpha;
 | |
|   cairo_pattern_type_t type;
 | |
|   
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (window->input_only)
 | |
|     return;
 | |
| 
 | |
|   if (pattern)
 | |
|     cairo_pattern_reference (pattern);
 | |
|   if (window->background)
 | |
|     cairo_pattern_destroy (window->background);
 | |
|   window->background = pattern;
 | |
| 
 | |
|   has_alpha = TRUE;
 | |
| 
 | |
|   if (pattern == NULL)
 | |
|     {
 | |
|       /* parent-relative, copy has_alpha from parent */
 | |
|       if (window->parent == NULL ||
 | |
| 	  window->parent->window_type == GDK_WINDOW_ROOT)
 | |
| 	has_alpha = FALSE;
 | |
|       else
 | |
| 	has_alpha = window->parent->has_alpha_background;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       type = cairo_pattern_get_type (pattern);
 | |
| 
 | |
|       if (type == CAIRO_PATTERN_TYPE_SOLID)
 | |
| 	{
 | |
| 	  double alpha;
 | |
| 	  cairo_pattern_get_rgba (pattern, NULL, NULL, NULL, &alpha);
 | |
| 	  if (alpha == 1.0)
 | |
| 	    has_alpha = FALSE;
 | |
| 	}
 | |
|       else if (type == CAIRO_PATTERN_TYPE_LINEAR ||
 | |
| 	       type == CAIRO_PATTERN_TYPE_RADIAL)
 | |
| 	{
 | |
| 	  int i, n;
 | |
| 	  double alpha;
 | |
| 
 | |
| 	  n = 0;
 | |
| 	  cairo_pattern_get_color_stop_count (pattern, &n);
 | |
| 	  has_alpha = FALSE;
 | |
| 	  for (i = 0; i < n; i++)
 | |
| 	    {
 | |
| 	      cairo_pattern_get_color_stop_rgba (pattern, i, NULL,
 | |
| 						 NULL, NULL, NULL, &alpha);
 | |
| 	      if (alpha != 1.0)
 | |
| 		{
 | |
| 		  has_alpha = TRUE;
 | |
| 		  break;
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|       else if (type == CAIRO_PATTERN_TYPE_SURFACE)
 | |
| 	{
 | |
| 	  cairo_surface_t *surface;
 | |
| 	  cairo_content_t content;
 | |
| 
 | |
| 	  cairo_pattern_get_surface (pattern, &surface);
 | |
| 	  content = cairo_surface_get_content (surface);
 | |
| 	  has_alpha =
 | |
| 	    (content == CAIRO_CONTENT_ALPHA) ||
 | |
| 	    (content == CAIRO_CONTENT_COLOR_ALPHA);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   if (has_alpha != window->has_alpha_background)
 | |
|     {
 | |
|       window->has_alpha_background = has_alpha;  
 | |
|       recompute_visible_regions (window, TRUE, FALSE);
 | |
| 
 | |
|       _gdk_window_propagate_has_alpha_background (window);
 | |
|     }
 | |
| 
 | |
|   if (gdk_window_has_impl (window))
 | |
|     {
 | |
|       GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|       impl_class->set_background (window, pattern);
 | |
|     }
 | |
|   else
 | |
|     gdk_window_invalidate_rect_full (window, NULL, TRUE, CLEAR_BG_ALL);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_background_pattern:
 | |
|  * @window: a window
 | |
|  *
 | |
|  * Gets the pattern used to clear the background on @window. If @window
 | |
|  * does not have its own background and reuses the parent's, %NULL is
 | |
|  * returned and you'll have to query it yourself.
 | |
|  *
 | |
|  * Returns: (transfer none): The pattern to use for the background or
 | |
|  *     %NULL to use the parent's background.
 | |
|  *
 | |
|  * Since: 2.22
 | |
|  **/
 | |
| cairo_pattern_t *
 | |
| gdk_window_get_background_pattern (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   return window->background;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_window_set_cursor_internal (GdkWindow *window,
 | |
|                                 GdkDevice *device,
 | |
|                                 GdkCursor *cursor)
 | |
| {
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   if (window->window_type == GDK_WINDOW_ROOT ||
 | |
|       window->window_type == GDK_WINDOW_FOREIGN)
 | |
|     GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_device_cursor (window, device, cursor);
 | |
|   else
 | |
|     {
 | |
|       GdkPointerWindowInfo *pointer_info;
 | |
|       GdkDisplay *display;
 | |
| 
 | |
|       display = gdk_window_get_display (window);
 | |
|       pointer_info = _gdk_display_get_pointer_info (display, device);
 | |
| 
 | |
|       if (_gdk_window_event_parent_of (window, pointer_info->window_under_pointer))
 | |
|         update_cursor (display, device);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_cursor:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Retrieves a #GdkCursor pointer for the cursor currently set on the
 | |
|  * specified #GdkWindow, or %NULL.  If the return value is %NULL then
 | |
|  * there is no custom cursor set on the specified window, and it is
 | |
|  * using the cursor for its parent window.
 | |
|  *
 | |
|  * Return value: (transfer none): a #GdkCursor, or %NULL. The returned
 | |
|  *   object is owned by the #GdkWindow and should not be unreferenced
 | |
|  *   directly. Use gdk_window_set_cursor() to unset the cursor of the
 | |
|  *   window
 | |
|  *
 | |
|  * Since: 2.18
 | |
|  */
 | |
| GdkCursor *
 | |
| gdk_window_get_cursor (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
| 
 | |
|   return window->cursor;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_cursor:
 | |
|  * @window: a #GdkWindow
 | |
|  * @cursor: (allow-none): a cursor
 | |
|  *
 | |
|  * Sets the default mouse pointer for a #GdkWindow. Use gdk_cursor_new_for_display()
 | |
|  * or gdk_cursor_new_from_pixbuf() to create the cursor. To make the cursor
 | |
|  * invisible, use %GDK_BLANK_CURSOR. Passing %NULL for the @cursor argument
 | |
|  * to gdk_window_set_cursor() means that @window will use the cursor of its
 | |
|  * parent window. Most windows should use this default.
 | |
|  */
 | |
| void
 | |
| gdk_window_set_cursor (GdkWindow *window,
 | |
| 		       GdkCursor *cursor)
 | |
| {
 | |
|   GdkDisplay *display;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   display = gdk_window_get_display (window);
 | |
| 
 | |
|   if (window->cursor)
 | |
|     {
 | |
|       g_object_unref (window->cursor);
 | |
|       window->cursor = NULL;
 | |
|     }
 | |
| 
 | |
|   if (!GDK_WINDOW_DESTROYED (window))
 | |
|     {
 | |
|       GdkDeviceManager *device_manager;
 | |
|       GList *devices, *d;
 | |
| 
 | |
|       if (cursor)
 | |
| 	window->cursor = g_object_ref (cursor);
 | |
| 
 | |
|       device_manager = gdk_display_get_device_manager (display);
 | |
|       devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
 | |
| 
 | |
|       for (d = devices; d; d = d->next)
 | |
|         {
 | |
|           GdkDevice *device;
 | |
| 
 | |
|           device = d->data;
 | |
| 
 | |
|           if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
 | |
|             continue;
 | |
| 
 | |
|           gdk_window_set_cursor_internal (window, device, window->cursor);
 | |
|         }
 | |
| 
 | |
|       g_list_free (devices);
 | |
|       g_object_notify (G_OBJECT (window), "cursor");
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_device_cursor:
 | |
|  * @window: a #GdkWindow.
 | |
|  * @device: a master, pointer #GdkDevice.
 | |
|  *
 | |
|  * Retrieves a #GdkCursor pointer for the @device currently set on the
 | |
|  * specified #GdkWindow, or %NULL.  If the return value is %NULL then
 | |
|  * there is no custom cursor set on the specified window, and it is
 | |
|  * using the cursor for its parent window.
 | |
|  *
 | |
|  * Returns: (transfer none): a #GdkCursor, or %NULL. The returned
 | |
|  *   object is owned by the #GdkWindow and should not be unreferenced
 | |
|  *   directly. Use gdk_window_set_cursor() to unset the cursor of the
 | |
|  *   window
 | |
|  *
 | |
|  * Since: 3.0
 | |
|  **/
 | |
| GdkCursor *
 | |
| gdk_window_get_device_cursor (GdkWindow *window,
 | |
|                               GdkDevice *device)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
|   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
 | |
|   g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
 | |
|   g_return_val_if_fail (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER, NULL);
 | |
| 
 | |
|   return g_hash_table_lookup (window->device_cursor, device);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_device_cursor:
 | |
|  * @window: a #Gdkwindow
 | |
|  * @device: a master, pointer #GdkDevice
 | |
|  * @cursor: a #GdkCursor
 | |
|  *
 | |
|  * Sets a specific #GdkCursor for a given device when it gets inside @window.
 | |
|  * Use gdk_cursor_new_for_display() or gdk_cursor_new_from_pixbuf() to create
 | |
|  * the cursor. To make the cursor invisible, use %GDK_BLANK_CURSOR. Passing
 | |
|  * %NULL for the @cursor argument to gdk_window_set_cursor() means that
 | |
|  * @window will use the cursor of its parent window. Most windows should
 | |
|  * use this default.
 | |
|  *
 | |
|  * Since: 3.0
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_device_cursor (GdkWindow *window,
 | |
|                               GdkDevice *device,
 | |
|                               GdkCursor *cursor)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
|   g_return_if_fail (GDK_IS_DEVICE (device));
 | |
|   g_return_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD);
 | |
|   g_return_if_fail (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER);
 | |
| 
 | |
|   if (!cursor)
 | |
|     g_hash_table_remove (window->device_cursor, device);
 | |
|   else
 | |
|     g_hash_table_replace (window->device_cursor, device, g_object_ref (cursor));
 | |
| 
 | |
|   gdk_window_set_cursor_internal (window, device, cursor);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_geometry:
 | |
|  * @window: a #GdkWindow
 | |
|  * @x: (out) (allow-none): return location for X coordinate of window (relative to its parent)
 | |
|  * @y: (out) (allow-none): return location for Y coordinate of window (relative to its parent)
 | |
|  * @width: (out) (allow-none): return location for width of window
 | |
|  * @height: (out) (allow-none): return location for height of window
 | |
|  *
 | |
|  * Any of the return location arguments to this function may be %NULL,
 | |
|  * if you aren't interested in getting the value of that field.
 | |
|  *
 | |
|  * The X and Y coordinates returned are relative to the parent window
 | |
|  * of @window, which for toplevels usually means relative to the
 | |
|  * window decorations (titlebar, etc.) rather than relative to the
 | |
|  * root window (screen-size background window).
 | |
|  *
 | |
|  * On the X11 platform, the geometry is obtained from the X server,
 | |
|  * so reflects the latest position of @window; this may be out-of-sync
 | |
|  * with the position of @window delivered in the most-recently-processed
 | |
|  * #GdkEventConfigure. gdk_window_get_position() in contrast gets the
 | |
|  * position from the most recent configure event.
 | |
|  *
 | |
|  * <note>
 | |
|  * If @window is not a toplevel, it is <emphasis>much</emphasis> better
 | |
|  * to call gdk_window_get_position(), gdk_window_get_width() and
 | |
|  * gdk_window_get_height() instead, because it avoids the roundtrip to
 | |
|  * the X server and because these functions support the full 32-bit
 | |
|  * coordinate space, whereas gdk_window_get_geometry() is restricted to
 | |
|  * the 16-bit coordinates of X11.
 | |
|  *</note>
 | |
|  **/
 | |
| void
 | |
| gdk_window_get_geometry (GdkWindow *window,
 | |
| 			 gint      *x,
 | |
| 			 gint      *y,
 | |
| 			 gint      *width,
 | |
| 			 gint      *height)
 | |
| {
 | |
|   GdkWindow *parent;
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   if (!window)
 | |
|     {
 | |
|       GDK_NOTE (MULTIHEAD,
 | |
| 		g_message ("gdk_window_get_geometry(): Window needs "
 | |
| 			   "to be non-NULL to be multi head safe"));
 | |
|       window = gdk_screen_get_root_window ((gdk_screen_get_default ()));
 | |
|     }
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (!GDK_WINDOW_DESTROYED (window))
 | |
|     {
 | |
|       if (gdk_window_has_impl (window))
 | |
| 	{
 | |
| 	  impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
| 	  impl_class->get_geometry (window, x, y,
 | |
| 				    width, height);
 | |
| 	  /* This reports the position wrt to the native parent, we need to convert
 | |
| 	     it to be relative to the client side parent */
 | |
| 	  parent = window->parent;
 | |
| 	  if (parent && !gdk_window_has_impl (parent))
 | |
| 	    {
 | |
| 	      if (x)
 | |
| 		*x -= parent->abs_x;
 | |
| 	      if (y)
 | |
| 		*y -= parent->abs_y;
 | |
| 	    }
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
|           if (x)
 | |
|             *x = window->x;
 | |
|           if (y)
 | |
|             *y = window->y;
 | |
| 	  if (width)
 | |
| 	    *width = window->width;
 | |
| 	  if (height)
 | |
| 	    *height = window->height;
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_width:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Returns the width of the given @window.
 | |
|  *
 | |
|  * On the X11 platform the returned size is the size reported in the
 | |
|  * most-recently-processed configure event, rather than the current
 | |
|  * size on the X server.
 | |
|  *
 | |
|  * Returns: The width of @window
 | |
|  *
 | |
|  * Since: 2.24
 | |
|  */
 | |
| int
 | |
| gdk_window_get_width (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 | |
| 
 | |
|   return window->width;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_height:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Returns the height of the given @window.
 | |
|  *
 | |
|  * On the X11 platform the returned size is the size reported in the
 | |
|  * most-recently-processed configure event, rather than the current
 | |
|  * size on the X server.
 | |
|  *
 | |
|  * Returns: The height of @window
 | |
|  *
 | |
|  * Since: 2.24
 | |
|  */
 | |
| int
 | |
| gdk_window_get_height (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 | |
| 
 | |
|   return window->height;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_origin:
 | |
|  * @window: a #GdkWindow
 | |
|  * @x: (out) (allow-none): return location for X coordinate
 | |
|  * @y: (out) (allow-none): return location for Y coordinate
 | |
|  *
 | |
|  * Obtains the position of a window in root window coordinates.
 | |
|  * (Compare with gdk_window_get_position() and
 | |
|  * gdk_window_get_geometry() which return the position of a window
 | |
|  * relative to its parent window.)
 | |
|  *
 | |
|  * Return value: not meaningful, ignore
 | |
|  */
 | |
| gint
 | |
| gdk_window_get_origin (GdkWindow *window,
 | |
| 		       gint      *x,
 | |
| 		       gint      *y)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     {
 | |
|       if (x)
 | |
| 	*x = 0;
 | |
|       if (y)
 | |
| 	*y = 0;
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|   impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|   impl_class->get_root_coords (window,
 | |
| 			       window->abs_x,
 | |
| 			       window->abs_y,
 | |
| 			       x, y);
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_root_coords:
 | |
|  * @window: a #GdkWindow
 | |
|  * @x: X coordinate in window
 | |
|  * @y: Y coordinate in window
 | |
|  * @root_x: (out): return location for X coordinate
 | |
|  * @root_y: (out): return location for Y coordinate
 | |
|  *
 | |
|  * Obtains the position of a window position in root
 | |
|  * window coordinates. This is similar to
 | |
|  * gdk_window_get_origin() but allows you go pass
 | |
|  * in any position in the window, not just the origin.
 | |
|  *
 | |
|  * Since: 2.18
 | |
|  */
 | |
| void
 | |
| gdk_window_get_root_coords (GdkWindow *window,
 | |
| 			    gint       x,
 | |
| 			    gint       y,
 | |
| 			    gint      *root_x,
 | |
| 			    gint      *root_y)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     {
 | |
|       *root_x = 0;
 | |
|       *root_y = 0;
 | |
|       return;
 | |
|     }
 | |
|   
 | |
|   impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|   impl_class->get_root_coords (window,
 | |
| 			       x + window->abs_x,
 | |
| 			       y + window->abs_y,
 | |
| 			       root_x, root_y);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_coords_to_parent:
 | |
|  * @window: a child window
 | |
|  * @x: X coordinate in child's coordinate system
 | |
|  * @y: Y coordinate in child's coordinate system
 | |
|  * @parent_x: (out) (allow-none): return location for X coordinate
 | |
|  * in parent's coordinate system, or %NULL
 | |
|  * @parent_y: (out) (allow-none): return location for Y coordinate
 | |
|  * in parent's coordinate system, or %NULL
 | |
|  *
 | |
|  * Transforms window coordinates from a child window to its parent
 | |
|  * window, where the parent window is the normal parent as returned by
 | |
|  * gdk_window_get_parent() for normal windows, and the window's
 | |
|  * embedder as returned by gdk_offscreen_window_get_embedder() for
 | |
|  * offscreen windows.
 | |
|  *
 | |
|  * For normal windows, calling this function is equivalent to adding
 | |
|  * the return values of gdk_window_get_position() to the child coordinates.
 | |
|  * For offscreen windows however (which can be arbitrarily transformed),
 | |
|  * this function calls the GdkWindow::to-embedder: signal to translate
 | |
|  * the coordinates.
 | |
|  *
 | |
|  * You should always use this function when writing generic code that
 | |
|  * walks up a window hierarchy.
 | |
|  *
 | |
|  * See also: gdk_window_coords_from_parent()
 | |
|  *
 | |
|  * Since: 2.22
 | |
|  **/
 | |
| void
 | |
| gdk_window_coords_to_parent (GdkWindow *window,
 | |
|                              gdouble    x,
 | |
|                              gdouble    y,
 | |
|                              gdouble   *parent_x,
 | |
|                              gdouble   *parent_y)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (gdk_window_is_offscreen (window))
 | |
|     {
 | |
|       gdouble px, py;
 | |
| 
 | |
|       to_embedder (window, x, y, &px, &py);
 | |
| 
 | |
|       if (parent_x)
 | |
|         *parent_x = px;
 | |
| 
 | |
|       if (parent_y)
 | |
|         *parent_y = py;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       if (parent_x)
 | |
|         *parent_x = x + window->x;
 | |
| 
 | |
|       if (parent_y)
 | |
|         *parent_y = y + window->y;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_coords_from_parent:
 | |
|  * @window: a child window
 | |
|  * @parent_x: X coordinate in parent's coordinate system
 | |
|  * @parent_y: Y coordinate in parent's coordinate system
 | |
|  * @x: (out) (allow-none): return location for X coordinate in child's coordinate system
 | |
|  * @y: (out) (allow-none): return location for Y coordinate in child's coordinate system
 | |
|  *
 | |
|  * Transforms window coordinates from a parent window to a child
 | |
|  * window, where the parent window is the normal parent as returned by
 | |
|  * gdk_window_get_parent() for normal windows, and the window's
 | |
|  * embedder as returned by gdk_offscreen_window_get_embedder() for
 | |
|  * offscreen windows.
 | |
|  *
 | |
|  * For normal windows, calling this function is equivalent to subtracting
 | |
|  * the return values of gdk_window_get_position() from the parent coordinates.
 | |
|  * For offscreen windows however (which can be arbitrarily transformed),
 | |
|  * this function calls the GdkWindow::from-embedder: signal to translate
 | |
|  * the coordinates.
 | |
|  *
 | |
|  * You should always use this function when writing generic code that
 | |
|  * walks down a window hierarchy.
 | |
|  *
 | |
|  * See also: gdk_window_coords_to_parent()
 | |
|  *
 | |
|  * Since: 2.22
 | |
|  **/
 | |
| void
 | |
| gdk_window_coords_from_parent (GdkWindow *window,
 | |
|                                gdouble    parent_x,
 | |
|                                gdouble    parent_y,
 | |
|                                gdouble   *x,
 | |
|                                gdouble   *y)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (gdk_window_is_offscreen (window))
 | |
|     {
 | |
|       gdouble cx, cy;
 | |
| 
 | |
|       from_embedder (window, parent_x, parent_y, &cx, &cy);
 | |
| 
 | |
|       if (x)
 | |
|         *x = cx;
 | |
| 
 | |
|       if (y)
 | |
|         *y = cy;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       if (x)
 | |
|         *x = parent_x - window->x;
 | |
| 
 | |
|       if (y)
 | |
|         *y = parent_y - window->y;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_shape_combine_region:
 | |
|  * @window: a #GdkWindow
 | |
|  * @shape_region: (allow-none): region of window to be non-transparent
 | |
|  * @offset_x: X position of @shape_region in @window coordinates
 | |
|  * @offset_y: Y position of @shape_region in @window coordinates
 | |
|  *
 | |
|  * Makes pixels in @window outside @shape_region be transparent,
 | |
|  * so that the window may be nonrectangular.
 | |
|  *
 | |
|  * If @shape_region is %NULL, the shape will be unset, so the whole
 | |
|  * window will be opaque again. @offset_x and @offset_y are ignored
 | |
|  * if @shape_region is %NULL.
 | |
|  *
 | |
|  * On the X11 platform, this uses an X server extension which is
 | |
|  * widely available on most common platforms, but not available on
 | |
|  * very old X servers, and occasionally the implementation will be
 | |
|  * buggy. On servers without the shape extension, this function
 | |
|  * will do nothing.
 | |
|  *
 | |
|  * This function works on both toplevel and child windows.
 | |
|  */
 | |
| void
 | |
| gdk_window_shape_combine_region (GdkWindow       *window,
 | |
| 				 const cairo_region_t *shape_region,
 | |
| 				 gint             offset_x,
 | |
| 				 gint             offset_y)
 | |
| {
 | |
|   cairo_region_t *old_region, *new_region, *diff;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   if (!window->shape && shape_region == NULL)
 | |
|     return;
 | |
| 
 | |
|   window->shaped = (shape_region != NULL);
 | |
| 
 | |
|   if (window->shape)
 | |
|     cairo_region_destroy (window->shape);
 | |
| 
 | |
|   old_region = NULL;
 | |
|   if (GDK_WINDOW_IS_MAPPED (window))
 | |
|     old_region = cairo_region_copy (window->clip_region);
 | |
| 
 | |
|   if (shape_region)
 | |
|     {
 | |
|       window->shape = cairo_region_copy (shape_region);
 | |
|       cairo_region_translate (window->shape, offset_x, offset_y);
 | |
|     }
 | |
|   else
 | |
|     window->shape = NULL;
 | |
| 
 | |
|   recompute_visible_regions (window, TRUE, FALSE);
 | |
| 
 | |
|   if (gdk_window_has_impl (window) &&
 | |
|       !should_apply_clip_as_shape (window))
 | |
|     apply_shape (window, window->shape);
 | |
| 
 | |
|   if (old_region)
 | |
|     {
 | |
|       new_region = cairo_region_copy (window->clip_region);
 | |
| 
 | |
|       /* New area in the window, needs invalidation */
 | |
|       diff = cairo_region_copy (new_region);
 | |
|       cairo_region_subtract (diff, old_region);
 | |
| 
 | |
|       gdk_window_invalidate_region_full (window, diff, TRUE, CLEAR_BG_ALL);
 | |
| 
 | |
|       cairo_region_destroy (diff);
 | |
| 
 | |
|       if (!gdk_window_is_toplevel (window))
 | |
| 	{
 | |
| 	  /* New area in the non-root parent window, needs invalidation */
 | |
| 	  diff = cairo_region_copy (old_region);
 | |
| 	  cairo_region_subtract (diff, new_region);
 | |
| 
 | |
| 	  /* Adjust region to parent window coords */
 | |
| 	  cairo_region_translate (diff, window->x, window->y);
 | |
| 
 | |
| 	  gdk_window_invalidate_region_full (window->parent, diff, TRUE, CLEAR_BG_ALL);
 | |
| 
 | |
| 	  cairo_region_destroy (diff);
 | |
| 	}
 | |
| 
 | |
|       cairo_region_destroy (new_region);
 | |
|       cairo_region_destroy (old_region);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| do_child_shapes (GdkWindow *window,
 | |
| 		 gboolean merge)
 | |
| {
 | |
|   GdkRectangle r;
 | |
|   cairo_region_t *region;
 | |
| 
 | |
|   r.x = 0;
 | |
|   r.y = 0;
 | |
|   r.width = window->width;
 | |
|   r.height = window->height;
 | |
| 
 | |
|   region = cairo_region_create_rectangle (&r);
 | |
|   remove_child_area (window, NULL, FALSE, region, NULL);
 | |
| 
 | |
|   if (merge && window->shape)
 | |
|     cairo_region_subtract (region, window->shape);
 | |
| 
 | |
|   gdk_window_shape_combine_region (window, region, 0, 0);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_child_shapes:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Sets the shape mask of @window to the union of shape masks
 | |
|  * for all children of @window, ignoring the shape mask of @window
 | |
|  * itself. Contrast with gdk_window_merge_child_shapes() which includes
 | |
|  * the shape mask of @window in the masks to be merged.
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_child_shapes (GdkWindow *window)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   do_child_shapes (window, FALSE);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_merge_child_shapes:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Merges the shape masks for any child windows into the
 | |
|  * shape mask for @window. i.e. the union of all masks
 | |
|  * for @window and its children will become the new mask
 | |
|  * for @window. See gdk_window_shape_combine_region().
 | |
|  *
 | |
|  * This function is distinct from gdk_window_set_child_shapes()
 | |
|  * because it includes @window's shape mask in the set of shapes to
 | |
|  * be merged.
 | |
|  */
 | |
| void
 | |
| gdk_window_merge_child_shapes (GdkWindow *window)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   do_child_shapes (window, TRUE);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_input_shape_combine_region:
 | |
|  * @window: a #GdkWindow
 | |
|  * @shape_region: region of window to be non-transparent
 | |
|  * @offset_x: X position of @shape_region in @window coordinates
 | |
|  * @offset_y: Y position of @shape_region in @window coordinates
 | |
|  *
 | |
|  * Like gdk_window_shape_combine_region(), but the shape applies
 | |
|  * only to event handling. Mouse events which happen while
 | |
|  * the pointer position corresponds to an unset bit in the
 | |
|  * mask will be passed on the window below @window.
 | |
|  *
 | |
|  * An input shape is typically used with RGBA windows.
 | |
|  * The alpha channel of the window defines which pixels are
 | |
|  * invisible and allows for nicely antialiased borders,
 | |
|  * and the input shape controls where the window is
 | |
|  * "clickable".
 | |
|  *
 | |
|  * On the X11 platform, this requires version 1.1 of the
 | |
|  * shape extension.
 | |
|  *
 | |
|  * On the Win32 platform, this functionality is not present and the
 | |
|  * function does nothing.
 | |
|  *
 | |
|  * Since: 2.10
 | |
|  */
 | |
| void
 | |
| gdk_window_input_shape_combine_region (GdkWindow       *window,
 | |
| 				       const cairo_region_t *shape_region,
 | |
| 				       gint             offset_x,
 | |
| 				       gint             offset_y)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   if (window->input_shape)
 | |
|     cairo_region_destroy (window->input_shape);
 | |
| 
 | |
|   if (shape_region)
 | |
|     {
 | |
|       window->input_shape = cairo_region_copy (shape_region);
 | |
|       cairo_region_translate (window->input_shape, offset_x, offset_y);
 | |
|     }
 | |
|   else
 | |
|     window->input_shape = NULL;
 | |
| 
 | |
|   if (gdk_window_has_impl (window))
 | |
|     {
 | |
|       impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|       impl_class->input_shape_combine_region (window, window->input_shape, 0, 0);
 | |
|     }
 | |
| 
 | |
|   /* Pointer may have e.g. moved outside window due to the input mask change */
 | |
|   _gdk_synthesize_crossing_events_for_geometry_change (window);
 | |
| }
 | |
| 
 | |
| static void
 | |
| do_child_input_shapes (GdkWindow *window,
 | |
| 		       gboolean merge)
 | |
| {
 | |
|   GdkRectangle r;
 | |
|   cairo_region_t *region;
 | |
| 
 | |
|   r.x = 0;
 | |
|   r.y = 0;
 | |
|   r.width = window->width;
 | |
|   r.height = window->height;
 | |
| 
 | |
|   region = cairo_region_create_rectangle (&r);
 | |
|   remove_child_area (window, NULL, TRUE, region, NULL);
 | |
| 
 | |
|   if (merge && window->shape)
 | |
|     cairo_region_subtract (region, window->shape);
 | |
|   if (merge && window->input_shape)
 | |
|     cairo_region_subtract (region, window->input_shape);
 | |
| 
 | |
|   gdk_window_input_shape_combine_region (window, region, 0, 0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_child_input_shapes:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Sets the input shape mask of @window to the union of input shape masks
 | |
|  * for all children of @window, ignoring the input shape mask of @window
 | |
|  * itself. Contrast with gdk_window_merge_child_input_shapes() which includes
 | |
|  * the input shape mask of @window in the masks to be merged.
 | |
|  *
 | |
|  * Since: 2.10
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_child_input_shapes (GdkWindow *window)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   do_child_input_shapes (window, FALSE);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_merge_child_input_shapes:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Merges the input shape masks for any child windows into the
 | |
|  * input shape mask for @window. i.e. the union of all input masks
 | |
|  * for @window and its children will become the new input mask
 | |
|  * for @window. See gdk_window_input_shape_combine_region().
 | |
|  *
 | |
|  * This function is distinct from gdk_window_set_child_input_shapes()
 | |
|  * because it includes @window's input shape mask in the set of
 | |
|  * shapes to be merged.
 | |
|  *
 | |
|  * Since: 2.10
 | |
|  **/
 | |
| void
 | |
| gdk_window_merge_child_input_shapes (GdkWindow *window)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   do_child_input_shapes (window, TRUE);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_static_gravities:
 | |
|  * @window: a #GdkWindow
 | |
|  * @use_static: %TRUE to turn on static gravity
 | |
|  *
 | |
|  * Set the bit gravity of the given window to static, and flag it so
 | |
|  * all children get static subwindow gravity. This is used if you are
 | |
|  * implementing scary features that involve deep knowledge of the
 | |
|  * windowing system. Don't worry about it unless you have to.
 | |
|  *
 | |
|  * Return value: %TRUE if the server supports static gravity
 | |
|  */
 | |
| gboolean
 | |
| gdk_window_set_static_gravities (GdkWindow *window,
 | |
| 				 gboolean   use_static)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 | |
| 
 | |
|   if (gdk_window_has_impl (window))
 | |
|     {
 | |
|       impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|       return impl_class->set_static_gravities (window, use_static);
 | |
|     }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_composited:
 | |
|  * @window: a #GdkWindow
 | |
|  *
 | |
|  * Determines whether @window is composited.
 | |
|  *
 | |
|  * See gdk_window_set_composited().
 | |
|  *
 | |
|  * Returns: %TRUE if the window is composited.
 | |
|  *
 | |
|  * Since: 2.22
 | |
|  **/
 | |
| gboolean
 | |
| gdk_window_get_composited (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 | |
| 
 | |
|   return window->composited;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_composited:
 | |
|  * @window: a #GdkWindow
 | |
|  * @composited: %TRUE to set the window as composited
 | |
|  *
 | |
|  * Sets a #GdkWindow as composited, or unsets it. Composited
 | |
|  * windows do not automatically have their contents drawn to
 | |
|  * the screen. Drawing is redirected to an offscreen buffer
 | |
|  * and an expose event is emitted on the parent of the composited
 | |
|  * window. It is the responsibility of the parent's expose handler
 | |
|  * to manually merge the off-screen content onto the screen in
 | |
|  * whatever way it sees fit. See <xref linkend="composited-window-example"/>
 | |
|  * for an example.
 | |
|  *
 | |
|  * It only makes sense for child windows to be composited; see
 | |
|  * gdk_window_set_opacity() if you need translucent toplevel
 | |
|  * windows.
 | |
|  *
 | |
|  * An additional effect of this call is that the area of this
 | |
|  * window is no longer clipped from regions marked for
 | |
|  * invalidation on its parent. Draws done on the parent
 | |
|  * window are also no longer clipped by the child.
 | |
|  *
 | |
|  * This call is only supported on some systems (currently,
 | |
|  * only X11 with new enough Xcomposite and Xdamage extensions).
 | |
|  * You must call gdk_display_supports_composite() to check if
 | |
|  * setting a window as composited is supported before
 | |
|  * attempting to do so.
 | |
|  *
 | |
|  * Since: 2.12
 | |
|  */
 | |
| void
 | |
| gdk_window_set_composited (GdkWindow *window,
 | |
| 			   gboolean   composited)
 | |
| {
 | |
|   GdkDisplay *display;
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   composited = composited != FALSE;
 | |
| 
 | |
|   if (window->composited == composited)
 | |
|     return;
 | |
| 
 | |
|   if (composited)
 | |
|     gdk_window_ensure_native (window);
 | |
| 
 | |
|   display = gdk_window_get_display (window);
 | |
| 
 | |
|   impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
| 
 | |
|   if (composited && (!gdk_display_supports_composite (display) || !impl_class->set_composited))
 | |
|     {
 | |
|       g_warning ("gdk_window_set_composited called but "
 | |
|                  "compositing is not supported");
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   impl_class->set_composited (window, composited);
 | |
| 
 | |
|   recompute_visible_regions (window, TRUE, FALSE);
 | |
| 
 | |
|   if (GDK_WINDOW_IS_MAPPED (window))
 | |
|     gdk_window_invalidate_in_parent (window);
 | |
| 
 | |
|   window->composited = composited;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_modal_hint:
 | |
|  * @window: A toplevel #GdkWindow.
 | |
|  *
 | |
|  * Determines whether or not the window manager is hinted that @window
 | |
|  * has modal behaviour.
 | |
|  *
 | |
|  * Return value: whether or not the window has the modal hint set.
 | |
|  *
 | |
|  * Since: 2.22
 | |
|  */
 | |
| gboolean
 | |
| gdk_window_get_modal_hint (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 | |
| 
 | |
|   return window->modal_hint;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_accept_focus:
 | |
|  * @window: a toplevel #GdkWindow.
 | |
|  *
 | |
|  * Determines whether or not the desktop environment shuld be hinted that
 | |
|  * the window does not want to receive input focus.
 | |
|  *
 | |
|  * Return value: whether or not the window should receive input focus.
 | |
|  *
 | |
|  * Since: 2.22
 | |
|  */
 | |
| gboolean
 | |
| gdk_window_get_accept_focus (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 | |
| 
 | |
|   return window->accept_focus;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_focus_on_map:
 | |
|  * @window: a toplevel #GdkWindow.
 | |
|  *
 | |
|  * Determines whether or not the desktop environment should be hinted that the
 | |
|  * window does not want to receive input focus when it is mapped.
 | |
|  *
 | |
|  * Return value: whether or not the window wants to receive input focus when
 | |
|  * it is mapped.
 | |
|  *
 | |
|  * Since: 2.22
 | |
|  */
 | |
| gboolean
 | |
| gdk_window_get_focus_on_map (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 | |
| 
 | |
|   return window->focus_on_map;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_is_input_only:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Determines whether or not the window is an input only window.
 | |
|  *
 | |
|  * Return value: %TRUE if @window is input only
 | |
|  *
 | |
|  * Since: 2.22
 | |
|  */
 | |
| gboolean
 | |
| gdk_window_is_input_only (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 | |
| 
 | |
|   return window->input_only;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_is_shaped:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Determines whether or not the window is shaped.
 | |
|  *
 | |
|  * Return value: %TRUE if @window is shaped
 | |
|  *
 | |
|  * Since: 2.22
 | |
|  */
 | |
| gboolean
 | |
| gdk_window_is_shaped (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 | |
| 
 | |
|   return window->shaped;
 | |
| }
 | |
| 
 | |
| void
 | |
| _gdk_window_add_damage (GdkWindow *toplevel,
 | |
| 			cairo_region_t *damaged_region)
 | |
| {
 | |
|   GdkDisplay *display;
 | |
|   GdkEvent event = { 0, };
 | |
|   event.expose.type = GDK_DAMAGE;
 | |
|   event.expose.window = toplevel;
 | |
|   event.expose.send_event = FALSE;
 | |
|   event.expose.region = damaged_region;
 | |
|   cairo_region_get_extents (event.expose.region, &event.expose.area);
 | |
|   display = gdk_window_get_display (event.expose.window);
 | |
|   _gdk_event_queue_append (display, gdk_event_copy (&event));
 | |
| }
 | |
| 
 | |
| /* Gets the toplevel for a window as used for events,
 | |
|    i.e. including offscreen parents */
 | |
| static GdkWindow *
 | |
| get_event_parent (GdkWindow *window)
 | |
| {
 | |
|   if (gdk_window_is_offscreen (window))
 | |
|     return gdk_offscreen_window_get_embedder ((GdkWindow *)window);
 | |
|   else
 | |
|     return window->parent;
 | |
| }
 | |
| 
 | |
| /* Gets the toplevel for a window as used for events,
 | |
|    i.e. including offscreen parents going up to the native
 | |
|    toplevel */
 | |
| static GdkWindow *
 | |
| get_event_toplevel (GdkWindow *window)
 | |
| {
 | |
|   GdkWindow *parent;
 | |
| 
 | |
|   while ((parent = get_event_parent (window)) != NULL &&
 | |
| 	 (parent->window_type != GDK_WINDOW_ROOT))
 | |
|     window = parent;
 | |
| 
 | |
|   return window;
 | |
| }
 | |
| 
 | |
| gboolean
 | |
| _gdk_window_event_parent_of (GdkWindow *parent,
 | |
|  	  	             GdkWindow *child)
 | |
| {
 | |
|   GdkWindow *w;
 | |
| 
 | |
|   w = child;
 | |
|   while (w != NULL)
 | |
|     {
 | |
|       if (w == parent)
 | |
| 	return TRUE;
 | |
| 
 | |
|       w = get_event_parent (w);
 | |
|     }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| update_cursor (GdkDisplay *display,
 | |
|                GdkDevice  *device)
 | |
| {
 | |
|   GdkWindow *cursor_window, *parent, *toplevel;
 | |
|   GdkWindow *pointer_window;
 | |
|   GdkWindowImplClass *impl_class;
 | |
|   GdkPointerWindowInfo *pointer_info;
 | |
|   GdkDeviceGrabInfo *grab;
 | |
|   GdkCursor *cursor;
 | |
| 
 | |
|   pointer_info = _gdk_display_get_pointer_info (display, device);
 | |
|   pointer_window = pointer_info->window_under_pointer;
 | |
| 
 | |
|   /* We ignore the serials here and just pick the last grab
 | |
|      we've sent, as that would shortly be used anyway. */
 | |
|   grab = _gdk_display_get_last_device_grab (display, device);
 | |
|   if (/* have grab */
 | |
|       grab != NULL &&
 | |
|       /* the pointer is not in a descendant of the grab window */
 | |
|       !_gdk_window_event_parent_of (grab->window, pointer_window))
 | |
|     {
 | |
|       /* use the cursor from the grab window */
 | |
|       cursor_window = grab->window;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       /* otherwise use the cursor from the pointer window */
 | |
|       cursor_window = pointer_window;
 | |
|     }
 | |
| 
 | |
|   /* Find the first window with the cursor actually set, as
 | |
|      the cursor is inherited from the parent */
 | |
|   while (cursor_window->cursor == NULL &&
 | |
| 	 (parent = get_event_parent (cursor_window)) != NULL &&
 | |
| 	 parent->window_type != GDK_WINDOW_ROOT)
 | |
|     cursor_window = parent;
 | |
| 
 | |
|   cursor = g_hash_table_lookup (cursor_window->device_cursor, device);
 | |
| 
 | |
|   if (!cursor)
 | |
|     cursor = cursor_window->cursor;
 | |
| 
 | |
|   /* Set all cursors on toplevel, otherwise its tricky to keep track of
 | |
|    * which native window has what cursor set. */
 | |
|   toplevel = get_event_toplevel (pointer_window);
 | |
|   impl_class = GDK_WINDOW_IMPL_GET_CLASS (toplevel->impl);
 | |
|   impl_class->set_device_cursor (toplevel, device, cursor);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| point_in_window (GdkWindow *window,
 | |
| 		 gdouble    x,
 | |
|                  gdouble    y)
 | |
| {
 | |
|   return
 | |
|     x >= 0 && x < window->width &&
 | |
|     y >= 0 && y < window->height &&
 | |
|     (window->shape == NULL ||
 | |
|      cairo_region_contains_point (window->shape,
 | |
| 			  x, y)) &&
 | |
|     (window->input_shape == NULL ||
 | |
|      cairo_region_contains_point (window->input_shape,
 | |
| 			  x, y));
 | |
| }
 | |
| 
 | |
| static GdkWindow *
 | |
| convert_native_coords_to_toplevel (GdkWindow *window,
 | |
| 				   gdouble    child_x,
 | |
|                                    gdouble    child_y,
 | |
| 				   gdouble   *toplevel_x,
 | |
|                                    gdouble   *toplevel_y)
 | |
| {
 | |
|   gdouble x, y;
 | |
| 
 | |
|   x = child_x;
 | |
|   y = child_y;
 | |
| 
 | |
|   while (!gdk_window_is_toplevel (window))
 | |
|     {
 | |
|       x += window->x;
 | |
|       y += window->y;
 | |
|       window = window->parent;
 | |
|     }
 | |
| 
 | |
|   *toplevel_x = x;
 | |
|   *toplevel_y = y;
 | |
| 
 | |
|   return window;
 | |
| }
 | |
| 
 | |
| static void
 | |
| convert_toplevel_coords_to_window (GdkWindow *window,
 | |
| 				   gdouble    toplevel_x,
 | |
| 				   gdouble    toplevel_y,
 | |
| 				   gdouble   *window_x,
 | |
| 				   gdouble   *window_y)
 | |
| {
 | |
|   GdkWindow *parent;
 | |
|   gdouble x, y;
 | |
|   GList *children, *l;
 | |
| 
 | |
|   x = toplevel_x;
 | |
|   y = toplevel_y;
 | |
| 
 | |
|   children = NULL;
 | |
|   while ((parent = get_event_parent (window)) != NULL &&
 | |
| 	 (parent->window_type != GDK_WINDOW_ROOT))
 | |
|     {
 | |
|       children = g_list_prepend (children, window);
 | |
|       window = parent;
 | |
|     }
 | |
| 
 | |
|   for (l = children; l != NULL; l = l->next)
 | |
|     gdk_window_coords_from_parent (l->data, x, y, &x, &y);
 | |
| 
 | |
|   g_list_free (children);
 | |
| 
 | |
|   *window_x = x;
 | |
|   *window_y = y;
 | |
| }
 | |
| 
 | |
| static GdkWindow *
 | |
| pick_embedded_child (GdkWindow *window,
 | |
| 		     gdouble    x,
 | |
|                      gdouble    y)
 | |
| {
 | |
|   GdkWindow *res;
 | |
| 
 | |
|   res = NULL;
 | |
|   g_signal_emit (window,
 | |
| 		 signals[PICK_EMBEDDED_CHILD], 0,
 | |
| 		 x, y, &res);
 | |
| 
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| GdkWindow *
 | |
| _gdk_window_find_child_at (GdkWindow *window,
 | |
| 			   int        x,
 | |
|                            int        y)
 | |
| {
 | |
|   GdkWindow *sub;
 | |
|   double child_x, child_y;
 | |
|   GList *l;
 | |
| 
 | |
|   if (point_in_window (window, x, y))
 | |
|     {
 | |
|       /* Children is ordered in reverse stack order, i.e. first is topmost */
 | |
|       for (l = window->children; l != NULL; l = l->next)
 | |
| 	{
 | |
| 	  sub = l->data;
 | |
| 
 | |
| 	  if (!GDK_WINDOW_IS_MAPPED (sub))
 | |
| 	    continue;
 | |
| 
 | |
| 	  gdk_window_coords_from_parent ((GdkWindow *)sub,
 | |
|                                          x, y,
 | |
|                                          &child_x, &child_y);
 | |
| 	  if (point_in_window (sub, child_x, child_y))
 | |
| 	    return (GdkWindow *)sub;
 | |
| 	}
 | |
| 
 | |
|       if (window->num_offscreen_children > 0)
 | |
| 	{
 | |
| 	  sub = pick_embedded_child (window,
 | |
| 				     x, y);
 | |
| 	  if (sub)
 | |
| 	    return (GdkWindow *)sub;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| GdkWindow *
 | |
| _gdk_window_find_descendant_at (GdkWindow *window,
 | |
| 				gdouble    x,
 | |
|                                 gdouble    y,
 | |
| 				gdouble   *found_x,
 | |
| 				gdouble   *found_y)
 | |
| {
 | |
|   GdkWindow *sub;
 | |
|   gdouble child_x, child_y;
 | |
|   GList *l;
 | |
|   gboolean found;
 | |
| 
 | |
|   if (point_in_window (window, x, y))
 | |
|     {
 | |
|       do
 | |
| 	{
 | |
| 	  found = FALSE;
 | |
| 	  /* Children is ordered in reverse stack order, i.e. first is topmost */
 | |
| 	  for (l = window->children; l != NULL; l = l->next)
 | |
| 	    {
 | |
| 	      sub = l->data;
 | |
| 
 | |
| 	      if (!GDK_WINDOW_IS_MAPPED (sub))
 | |
| 		continue;
 | |
| 
 | |
| 	      gdk_window_coords_from_parent ((GdkWindow *)sub,
 | |
|                                              x, y,
 | |
|                                              &child_x, &child_y);
 | |
| 	      if (point_in_window (sub, child_x, child_y))
 | |
| 		{
 | |
| 		  x = child_x;
 | |
| 		  y = child_y;
 | |
| 		  window = sub;
 | |
| 		  found = TRUE;
 | |
| 		  break;
 | |
| 		}
 | |
| 	    }
 | |
| 	  if (!found &&
 | |
| 	      window->num_offscreen_children > 0)
 | |
| 	    {
 | |
| 	      sub = pick_embedded_child (window,
 | |
| 					 x, y);
 | |
| 	      if (sub)
 | |
| 		{
 | |
| 		  found = TRUE;
 | |
| 		  window = sub;
 | |
| 		  from_embedder (sub, x, y, &x, &y);
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|       while (found);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       /* Not in window at all */
 | |
|       window = NULL;
 | |
|     }
 | |
| 
 | |
|   if (found_x)
 | |
|     *found_x = x;
 | |
|   if (found_y)
 | |
|     *found_y = y;
 | |
| 
 | |
|   return window;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_beep:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Emits a short beep associated to @window in the appropriate
 | |
|  * display, if supported. Otherwise, emits a short beep on
 | |
|  * the display just as gdk_display_beep().
 | |
|  *
 | |
|  * Since: 2.12
 | |
|  **/
 | |
| void
 | |
| gdk_window_beep (GdkWindow *window)
 | |
| {
 | |
|   GdkDisplay *display;
 | |
|   GdkWindow *toplevel;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   toplevel = get_event_toplevel (window);
 | |
|   display = gdk_window_get_display (window);
 | |
| 
 | |
|   if (toplevel)
 | |
|     {
 | |
|       if (GDK_WINDOW_IMPL_GET_CLASS (toplevel->impl)->beep (toplevel))
 | |
|         return;
 | |
|     }
 | |
|   
 | |
|   /* If windows fail to beep, we beep the display. */
 | |
|   gdk_display_beep (display);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_support_multidevice:
 | |
|  * @window: a #GdkWindow.
 | |
|  * @support_multidevice: %TRUE to enable multidevice support in @window.
 | |
|  *
 | |
|  * This function will enable multidevice features in @window.
 | |
|  *
 | |
|  * Multidevice aware windows will need to handle properly multiple,
 | |
|  * per device enter/leave events, device grabs and grab ownerships.
 | |
|  *
 | |
|  * Since: 3.0
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_support_multidevice (GdkWindow *window,
 | |
|                                     gboolean   support_multidevice)
 | |
| {
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return;
 | |
| 
 | |
|   if (window->support_multidevice == support_multidevice)
 | |
|     return;
 | |
| 
 | |
|   window->support_multidevice = support_multidevice;
 | |
| 
 | |
|   /* FIXME: What to do if called when some pointers are inside the window ? */
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_support_multidevice:
 | |
|  * @window: a #GdkWindow.
 | |
|  *
 | |
|  * Returns %TRUE if the window is aware of the existence of multiple
 | |
|  * devices.
 | |
|  *
 | |
|  * Returns: %TRUE if the window handles multidevice features.
 | |
|  *
 | |
|  * Since: 3.0
 | |
|  **/
 | |
| gboolean
 | |
| gdk_window_get_support_multidevice (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (window))
 | |
|     return FALSE;
 | |
| 
 | |
|   return window->support_multidevice;
 | |
| }
 | |
| 
 | |
| static const guint type_masks[] = {
 | |
|   GDK_SUBSTRUCTURE_MASK, /* GDK_DELETE                 = 0  */
 | |
|   GDK_STRUCTURE_MASK, /* GDK_DESTROY                   = 1  */
 | |
|   GDK_EXPOSURE_MASK, /* GDK_EXPOSE                     = 2  */
 | |
|   GDK_POINTER_MOTION_MASK, /* GDK_MOTION_NOTIFY        = 3  */
 | |
|   GDK_BUTTON_PRESS_MASK, /* GDK_BUTTON_PRESS           = 4  */
 | |
|   GDK_BUTTON_PRESS_MASK, /* GDK_2BUTTON_PRESS          = 5  */
 | |
|   GDK_BUTTON_PRESS_MASK, /* GDK_3BUTTON_PRESS          = 6  */
 | |
|   GDK_BUTTON_RELEASE_MASK, /* GDK_BUTTON_RELEASE       = 7  */
 | |
|   GDK_KEY_PRESS_MASK, /* GDK_KEY_PRESS                 = 8  */
 | |
|   GDK_KEY_RELEASE_MASK, /* GDK_KEY_RELEASE             = 9  */
 | |
|   GDK_ENTER_NOTIFY_MASK, /* GDK_ENTER_NOTIFY           = 10 */
 | |
|   GDK_LEAVE_NOTIFY_MASK, /* GDK_LEAVE_NOTIFY           = 11 */
 | |
|   GDK_FOCUS_CHANGE_MASK, /* GDK_FOCUS_CHANGE           = 12 */
 | |
|   GDK_STRUCTURE_MASK, /* GDK_CONFIGURE                 = 13 */
 | |
|   GDK_VISIBILITY_NOTIFY_MASK, /* GDK_MAP               = 14 */
 | |
|   GDK_VISIBILITY_NOTIFY_MASK, /* GDK_UNMAP             = 15 */
 | |
|   GDK_PROPERTY_CHANGE_MASK, /* GDK_PROPERTY_NOTIFY     = 16 */
 | |
|   GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_CLEAR     = 17 */
 | |
|   GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_REQUEST   = 18 */
 | |
|   GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_NOTIFY    = 19 */
 | |
|   GDK_PROXIMITY_IN_MASK, /* GDK_PROXIMITY_IN           = 20 */
 | |
|   GDK_PROXIMITY_OUT_MASK, /* GDK_PROXIMITY_OUT         = 21 */
 | |
|   GDK_ALL_EVENTS_MASK, /* GDK_DRAG_ENTER               = 22 */
 | |
|   GDK_ALL_EVENTS_MASK, /* GDK_DRAG_LEAVE               = 23 */
 | |
|   GDK_ALL_EVENTS_MASK, /* GDK_DRAG_MOTION              = 24 */
 | |
|   GDK_ALL_EVENTS_MASK, /* GDK_DRAG_STATUS              = 25 */
 | |
|   GDK_ALL_EVENTS_MASK, /* GDK_DROP_START               = 26 */
 | |
|   GDK_ALL_EVENTS_MASK, /* GDK_DROP_FINISHED            = 27 */
 | |
|   GDK_ALL_EVENTS_MASK, /* GDK_CLIENT_EVENT	       = 28 */
 | |
|   GDK_VISIBILITY_NOTIFY_MASK, /* GDK_VISIBILITY_NOTIFY = 29 */
 | |
|   GDK_EXPOSURE_MASK, /* GDK_NO_EXPOSE                  = 30 */
 | |
|   GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK,/* GDK_SCROLL= 31 */
 | |
|   0, /* GDK_WINDOW_STATE = 32 */
 | |
|   0, /* GDK_SETTING = 33 */
 | |
|   0, /* GDK_OWNER_CHANGE = 34 */
 | |
|   0, /* GDK_GRAB_BROKEN = 35 */
 | |
|   0, /* GDK_DAMAGE = 36 */
 | |
|   GDK_TOUCH_MASK, /* GDK_TOUCH_BEGIN = 37 */
 | |
|   GDK_TOUCH_MASK, /* GDK_TOUCH_UPDATE = 38 */
 | |
|   GDK_TOUCH_MASK, /* GDK_TOUCH_END = 39 */
 | |
|   GDK_TOUCH_MASK /* GDK_TOUCH_CANCEL = 40 */
 | |
| };
 | |
| G_STATIC_ASSERT (G_N_ELEMENTS (type_masks) == GDK_EVENT_LAST);
 | |
| 
 | |
| /* send motion events if the right buttons are down */
 | |
| static guint
 | |
| update_evmask_for_button_motion (guint           evmask,
 | |
| 				 GdkModifierType mask)
 | |
| {
 | |
|   if (evmask & GDK_BUTTON_MOTION_MASK &&
 | |
|       mask & (GDK_BUTTON1_MASK |
 | |
| 	      GDK_BUTTON2_MASK |
 | |
| 	      GDK_BUTTON3_MASK |
 | |
| 	      GDK_BUTTON4_MASK |
 | |
| 	      GDK_BUTTON5_MASK))
 | |
|     evmask |= GDK_POINTER_MOTION_MASK;
 | |
| 
 | |
|   if ((evmask & GDK_BUTTON1_MOTION_MASK && mask & GDK_BUTTON1_MASK) ||
 | |
|       (evmask & GDK_BUTTON2_MOTION_MASK && mask & GDK_BUTTON2_MASK) ||
 | |
|       (evmask & GDK_BUTTON3_MOTION_MASK && mask & GDK_BUTTON3_MASK))
 | |
|     evmask |= GDK_POINTER_MOTION_MASK;
 | |
| 
 | |
|   return evmask;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| is_button_type (GdkEventType type)
 | |
| {
 | |
|   return type == GDK_BUTTON_PRESS ||
 | |
| 	 type == GDK_2BUTTON_PRESS ||
 | |
| 	 type == GDK_3BUTTON_PRESS ||
 | |
| 	 type == GDK_BUTTON_RELEASE ||
 | |
|          type == GDK_TOUCH_BEGIN ||
 | |
|          type == GDK_TOUCH_END ||
 | |
| 	 type == GDK_SCROLL;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| is_motion_type (GdkEventType type)
 | |
| {
 | |
|   return type == GDK_MOTION_NOTIFY ||
 | |
|          type == GDK_TOUCH_UPDATE ||
 | |
| 	 type == GDK_ENTER_NOTIFY ||
 | |
| 	 type == GDK_LEAVE_NOTIFY;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| is_touch_type (GdkEventType type)
 | |
| {
 | |
|   return type == GDK_TOUCH_BEGIN ||
 | |
|          type == GDK_TOUCH_UPDATE ||
 | |
|          type == GDK_TOUCH_END ||
 | |
|          type == GDK_TOUCH_CANCEL;
 | |
| }
 | |
| 
 | |
| static GdkWindow *
 | |
| find_common_ancestor (GdkWindow *win1,
 | |
| 		      GdkWindow *win2)
 | |
| {
 | |
|   GdkWindow *tmp;
 | |
|   GList *path1 = NULL, *path2 = NULL;
 | |
|   GList *list1, *list2;
 | |
| 
 | |
|   tmp = win1;
 | |
|   while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
 | |
|     {
 | |
|       path1 = g_list_prepend (path1, tmp);
 | |
|       tmp = get_event_parent (tmp);
 | |
|     }
 | |
| 
 | |
|   tmp = win2;
 | |
|   while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
 | |
|     {
 | |
|       path2 = g_list_prepend (path2, tmp);
 | |
|       tmp = get_event_parent (tmp);
 | |
|     }
 | |
| 
 | |
|   list1 = path1;
 | |
|   list2 = path2;
 | |
|   tmp = NULL;
 | |
|   while (list1 && list2 && (list1->data == list2->data))
 | |
|     {
 | |
|       tmp = list1->data;
 | |
|       list1 = g_list_next (list1);
 | |
|       list2 = g_list_next (list2);
 | |
|     }
 | |
|   g_list_free (path1);
 | |
|   g_list_free (path2);
 | |
| 
 | |
|   return tmp;
 | |
| }
 | |
| 
 | |
| GdkEvent *
 | |
| _gdk_make_event (GdkWindow    *window,
 | |
| 		 GdkEventType  type,
 | |
| 		 GdkEvent     *event_in_queue,
 | |
| 		 gboolean      before_event)
 | |
| {
 | |
|   GdkEvent *event = gdk_event_new (type);
 | |
|   guint32 the_time;
 | |
|   GdkModifierType the_state;
 | |
| 
 | |
|   the_time = gdk_event_get_time (event_in_queue);
 | |
|   gdk_event_get_state (event_in_queue, &the_state);
 | |
| 
 | |
|   event->any.window = g_object_ref (window);
 | |
|   event->any.send_event = FALSE;
 | |
|   if (event_in_queue && event_in_queue->any.send_event)
 | |
|     event->any.send_event = TRUE;
 | |
| 
 | |
|   switch (type)
 | |
|     {
 | |
|     case GDK_MOTION_NOTIFY:
 | |
|       event->motion.time = the_time;
 | |
|       event->motion.axes = NULL;
 | |
|       event->motion.state = the_state;
 | |
|       break;
 | |
| 
 | |
|     case GDK_BUTTON_PRESS:
 | |
|     case GDK_2BUTTON_PRESS:
 | |
|     case GDK_3BUTTON_PRESS:
 | |
|     case GDK_BUTTON_RELEASE:
 | |
|       event->button.time = the_time;
 | |
|       event->button.axes = NULL;
 | |
|       event->button.state = the_state;
 | |
|       break;
 | |
| 
 | |
|     case GDK_TOUCH_BEGIN:
 | |
|     case GDK_TOUCH_UPDATE:
 | |
|     case GDK_TOUCH_END:
 | |
|     case GDK_TOUCH_CANCEL:
 | |
|       event->touch.time = the_time;
 | |
|       event->touch.axes = NULL;
 | |
|       event->touch.state = the_state;
 | |
|       break;
 | |
| 
 | |
|     case GDK_SCROLL:
 | |
|       event->scroll.time = the_time;
 | |
|       event->scroll.state = the_state;
 | |
|       break;
 | |
| 
 | |
|     case GDK_KEY_PRESS:
 | |
|     case GDK_KEY_RELEASE:
 | |
|       event->key.time = the_time;
 | |
|       event->key.state = the_state;
 | |
|       break;
 | |
| 
 | |
|     case GDK_ENTER_NOTIFY:
 | |
|     case GDK_LEAVE_NOTIFY:
 | |
|       event->crossing.time = the_time;
 | |
|       event->crossing.state = the_state;
 | |
|       break;
 | |
| 
 | |
|     case GDK_PROPERTY_NOTIFY:
 | |
|       event->property.time = the_time;
 | |
|       event->property.state = the_state;
 | |
|       break;
 | |
| 
 | |
|     case GDK_SELECTION_CLEAR:
 | |
|     case GDK_SELECTION_REQUEST:
 | |
|     case GDK_SELECTION_NOTIFY:
 | |
|       event->selection.time = the_time;
 | |
|       break;
 | |
| 
 | |
|     case GDK_PROXIMITY_IN:
 | |
|     case GDK_PROXIMITY_OUT:
 | |
|       event->proximity.time = the_time;
 | |
|       break;
 | |
| 
 | |
|     case GDK_DRAG_ENTER:
 | |
|     case GDK_DRAG_LEAVE:
 | |
|     case GDK_DRAG_MOTION:
 | |
|     case GDK_DRAG_STATUS:
 | |
|     case GDK_DROP_START:
 | |
|     case GDK_DROP_FINISHED:
 | |
|       event->dnd.time = the_time;
 | |
|       break;
 | |
| 
 | |
|     case GDK_FOCUS_CHANGE:
 | |
|     case GDK_CONFIGURE:
 | |
|     case GDK_MAP:
 | |
|     case GDK_UNMAP:
 | |
|     case GDK_CLIENT_EVENT:
 | |
|     case GDK_VISIBILITY_NOTIFY:
 | |
|     case GDK_DELETE:
 | |
|     case GDK_DESTROY:
 | |
|     case GDK_EXPOSE:
 | |
|     default:
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|   if (event_in_queue)
 | |
|     {
 | |
|     if (before_event)
 | |
|       _gdk_event_queue_insert_before (gdk_window_get_display (window), event_in_queue, event);
 | |
|     else
 | |
|       _gdk_event_queue_insert_after (gdk_window_get_display (window), event_in_queue, event);
 | |
|     }
 | |
|   else
 | |
|     _gdk_event_queue_append (gdk_window_get_display (window), event);
 | |
| 
 | |
|   return event;
 | |
| }
 | |
| 
 | |
| 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,
 | |
| 		     gint                        toplevel_x,
 | |
| 		     gint                        toplevel_y,
 | |
| 		     GdkModifierType             mask,
 | |
| 		     guint32                     time_,
 | |
| 		     GdkEvent                   *event_in_queue,
 | |
| 		     gulong                      serial)
 | |
| {
 | |
|   GdkEvent *event;
 | |
|   guint32 window_event_mask, type_event_mask;
 | |
|   GdkDeviceGrabInfo *grab;
 | |
|   GdkTouchGrabInfo *touch_grab = NULL;
 | |
|   GdkPointerWindowInfo *pointer_info;
 | |
|   gboolean block_event = FALSE;
 | |
|   GdkEventSequence *sequence;
 | |
| 
 | |
|   grab = _gdk_display_has_device_grab (display, device, serial);
 | |
|   pointer_info = _gdk_display_get_pointer_info (display, device);
 | |
| 
 | |
|   sequence = gdk_event_get_event_sequence (event_in_queue);
 | |
|   if (sequence)
 | |
|     touch_grab = _gdk_display_has_touch_grab (display, device, sequence, serial);
 | |
| 
 | |
|   if (touch_grab)
 | |
|     {
 | |
|       if (window != touch_grab->window)
 | |
|         return;
 | |
| 
 | |
|       window_event_mask = touch_grab->event_mask;
 | |
|     }
 | |
|   else if (grab != NULL &&
 | |
|            !grab->owner_events)
 | |
|     {
 | |
|       /* !owner_event => only report events wrt grab window, ignore rest */
 | |
|       if ((GdkWindow *)window != grab->window)
 | |
| 	return;
 | |
|       window_event_mask = grab->event_mask;
 | |
|     }
 | |
|   else
 | |
|     window_event_mask = window->event_mask;
 | |
| 
 | |
|   if (type == GDK_ENTER_NOTIFY &&
 | |
|       (pointer_info->need_touch_press_enter ||
 | |
|        gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN) &&
 | |
|       mode != GDK_CROSSING_TOUCH_BEGIN &&
 | |
|       mode != GDK_CROSSING_TOUCH_END)
 | |
|     {
 | |
|       pointer_info->need_touch_press_enter = TRUE;
 | |
|       block_event = TRUE;
 | |
|     }
 | |
|   else if (type == GDK_LEAVE_NOTIFY)
 | |
|     {
 | |
|       type_event_mask = GDK_LEAVE_NOTIFY_MASK;
 | |
|       window->devices_inside = g_list_remove (window->devices_inside, device);
 | |
| 
 | |
|       if (!window->support_multidevice && window->devices_inside)
 | |
|         {
 | |
|           /* Block leave events unless it's the last pointer */
 | |
|           block_event = TRUE;
 | |
|         }
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       type_event_mask = GDK_ENTER_NOTIFY_MASK;
 | |
| 
 | |
|       if (!window->support_multidevice && window->devices_inside)
 | |
|         {
 | |
|           /* Only emit enter events for the first device */
 | |
|           block_event = TRUE;
 | |
|         }
 | |
| 
 | |
|       if (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER &&
 | |
|           gdk_device_get_mode (device) != GDK_MODE_DISABLED &&
 | |
|           !g_list_find (window->devices_inside, device))
 | |
|         window->devices_inside = g_list_prepend (window->devices_inside, device);
 | |
|     }
 | |
| 
 | |
|   if (block_event)
 | |
|     return;
 | |
| 
 | |
|   if (window_event_mask & type_event_mask)
 | |
|     {
 | |
|       event = _gdk_make_event ((GdkWindow *)window, type, event_in_queue, TRUE);
 | |
|       gdk_event_set_device (event, device);
 | |
| 
 | |
|       if (source_device)
 | |
|         gdk_event_set_source_device (event, source_device);
 | |
| 
 | |
|       event->crossing.time = time_;
 | |
|       event->crossing.subwindow = subwindow;
 | |
|       if (subwindow)
 | |
| 	g_object_ref (subwindow);
 | |
|       convert_toplevel_coords_to_window ((GdkWindow *)window,
 | |
| 					 toplevel_x, toplevel_y,
 | |
| 					 &event->crossing.x, &event->crossing.y);
 | |
|       event->crossing.x_root = toplevel_x + toplevel->x;
 | |
|       event->crossing.y_root = toplevel_y + toplevel->y;
 | |
|       event->crossing.mode = mode;
 | |
|       event->crossing.detail = notify_type;
 | |
|       event->crossing.focus = FALSE;
 | |
|       event->crossing.state = mask;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /* The coordinates are in the toplevel window that src/dest are in.
 | |
|  * src and dest are always (if != NULL) in the same toplevel, as
 | |
|  * we get a leave-notify and set the window_under_pointer to null
 | |
|  * before crossing to another toplevel.
 | |
|  */
 | |
| void
 | |
| _gdk_synthesize_crossing_events (GdkDisplay                 *display,
 | |
| 				 GdkWindow                  *src,
 | |
| 				 GdkWindow                  *dest,
 | |
|                                  GdkDevice                  *device,
 | |
|                                  GdkDevice                  *source_device,
 | |
| 				 GdkCrossingMode             mode,
 | |
| 				 gint                        toplevel_x,
 | |
| 				 gint                        toplevel_y,
 | |
| 				 GdkModifierType             mask,
 | |
| 				 guint32                     time_,
 | |
| 				 GdkEvent                   *event_in_queue,
 | |
| 				 gulong                      serial,
 | |
| 				 gboolean                    non_linear)
 | |
| {
 | |
|   GdkWindow *c;
 | |
|   GdkWindow *win, *last, *next;
 | |
|   GList *path, *list;
 | |
|   GdkWindow *a;
 | |
|   GdkWindow *b;
 | |
|   GdkWindow *toplevel;
 | |
|   GdkNotifyType notify_type;
 | |
| 
 | |
|   /* TODO: Don't send events to toplevel, as we get those from the windowing system */
 | |
| 
 | |
|   a = src;
 | |
|   b = dest;
 | |
|   if (src == dest)
 | |
|     return; /* No crossings generated between src and dest */
 | |
| 
 | |
|   if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
 | |
|     {
 | |
|       if (a && gdk_window_get_device_events (src, device) == 0)
 | |
|         a = NULL;
 | |
| 
 | |
|       if (b && gdk_window_get_device_events (dest, device) == 0)
 | |
|         b = NULL;
 | |
|     }
 | |
| 
 | |
|   if (!a && !b)
 | |
|     return;
 | |
| 
 | |
|   c = find_common_ancestor (a, b);
 | |
| 
 | |
|   non_linear |= (c != a) && (c != b);
 | |
| 
 | |
|   if (a) /* There might not be a source (i.e. if no previous pointer_in_window) */
 | |
|     {
 | |
|       toplevel = gdk_window_get_toplevel (a);
 | |
| 
 | |
|       /* Traverse up from a to (excluding) c sending leave events */
 | |
|       if (non_linear)
 | |
| 	notify_type = GDK_NOTIFY_NONLINEAR;
 | |
|       else if (c == a)
 | |
| 	notify_type = GDK_NOTIFY_INFERIOR;
 | |
|       else
 | |
| 	notify_type = GDK_NOTIFY_ANCESTOR;
 | |
|       send_crossing_event (display, toplevel,
 | |
| 			   a, GDK_LEAVE_NOTIFY,
 | |
| 			   mode,
 | |
| 			   notify_type,
 | |
| 			   NULL, device, source_device,
 | |
| 			   toplevel_x, toplevel_y,
 | |
| 			   mask, time_,
 | |
| 			   event_in_queue,
 | |
| 			   serial);
 | |
| 
 | |
|       if (c != a)
 | |
| 	{
 | |
| 	  if (non_linear)
 | |
| 	    notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
 | |
| 	  else
 | |
| 	    notify_type = GDK_NOTIFY_VIRTUAL;
 | |
| 
 | |
| 	  last = a;
 | |
| 	  win = get_event_parent (a);
 | |
| 	  while (win != c && win->window_type != GDK_WINDOW_ROOT)
 | |
| 	    {
 | |
| 	      send_crossing_event (display, toplevel,
 | |
| 				   win, GDK_LEAVE_NOTIFY,
 | |
| 				   mode,
 | |
| 				   notify_type,
 | |
| 				   (GdkWindow *)last,
 | |
| 				   device, source_device,
 | |
| 				   toplevel_x, toplevel_y,
 | |
| 				   mask, time_,
 | |
| 				   event_in_queue,
 | |
| 				   serial);
 | |
| 
 | |
| 	      last = win;
 | |
| 	      win = get_event_parent (win);
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   if (b) /* Might not be a dest, e.g. if we're moving out of the window */
 | |
|     {
 | |
|       toplevel = gdk_window_get_toplevel ((GdkWindow *)b);
 | |
| 
 | |
|       /* Traverse down from c to b */
 | |
|       if (c != b)
 | |
| 	{
 | |
| 	  path = NULL;
 | |
| 	  win = get_event_parent (b);
 | |
| 	  while (win != c && win->window_type != GDK_WINDOW_ROOT)
 | |
| 	    {
 | |
| 	      path = g_list_prepend (path, win);
 | |
| 	      win = get_event_parent (win);
 | |
| 	    }
 | |
| 
 | |
| 	  if (non_linear)
 | |
| 	    notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
 | |
| 	  else
 | |
| 	    notify_type = GDK_NOTIFY_VIRTUAL;
 | |
| 
 | |
| 	  list = path;
 | |
| 	  while (list)
 | |
| 	    {
 | |
| 	      win = list->data;
 | |
| 	      list = g_list_next (list);
 | |
| 	      if (list)
 | |
| 		next = list->data;
 | |
| 	      else
 | |
| 		next = b;
 | |
| 
 | |
| 	      send_crossing_event (display, toplevel,
 | |
| 				   win, GDK_ENTER_NOTIFY,
 | |
| 				   mode,
 | |
| 				   notify_type,
 | |
| 				   (GdkWindow *)next,
 | |
| 				   device, source_device,
 | |
| 				   toplevel_x, toplevel_y,
 | |
| 				   mask, time_,
 | |
| 				   event_in_queue,
 | |
| 				   serial);
 | |
| 	    }
 | |
| 	  g_list_free (path);
 | |
| 	}
 | |
| 
 | |
| 
 | |
|       if (non_linear)
 | |
| 	notify_type = GDK_NOTIFY_NONLINEAR;
 | |
|       else if (c == a)
 | |
| 	notify_type = GDK_NOTIFY_ANCESTOR;
 | |
|       else
 | |
| 	notify_type = GDK_NOTIFY_INFERIOR;
 | |
| 
 | |
|       send_crossing_event (display, toplevel,
 | |
| 			   b, GDK_ENTER_NOTIFY,
 | |
| 			   mode,
 | |
| 			   notify_type,
 | |
| 			   NULL,
 | |
|                            device, source_device,
 | |
| 			   toplevel_x, toplevel_y,
 | |
| 			   mask, time_,
 | |
| 			   event_in_queue,
 | |
| 			   serial);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Returns the window inside the event window with the pointer in it
 | |
|  * at the specified coordinates, or NULL if its not in any child of
 | |
|  * the toplevel. It also takes into account !owner_events grabs.
 | |
|  */
 | |
| static GdkWindow *
 | |
| get_pointer_window (GdkDisplay *display,
 | |
| 		    GdkWindow *event_window,
 | |
|                     GdkDevice *device,
 | |
| 		    gdouble toplevel_x,
 | |
| 		    gdouble toplevel_y,
 | |
| 		    gulong serial)
 | |
| {
 | |
|   GdkWindow *pointer_window;
 | |
|   GdkDeviceGrabInfo *grab;
 | |
|   GdkPointerWindowInfo *pointer_info;
 | |
| 
 | |
|   pointer_info = _gdk_display_get_pointer_info (display, device);
 | |
| 
 | |
|   if (event_window == pointer_info->toplevel_under_pointer)
 | |
|     pointer_window =
 | |
|       _gdk_window_find_descendant_at (event_window,
 | |
| 				      toplevel_x, toplevel_y,
 | |
| 				      NULL, NULL);
 | |
|   else
 | |
|     pointer_window = NULL;
 | |
| 
 | |
|   grab = _gdk_display_has_device_grab (display, device, serial);
 | |
|   if (grab != NULL &&
 | |
|       !grab->owner_events &&
 | |
|       pointer_window != grab->window)
 | |
|     pointer_window = NULL;
 | |
| 
 | |
|   return pointer_window;
 | |
| }
 | |
| 
 | |
| void
 | |
| _gdk_display_set_window_under_pointer (GdkDisplay *display,
 | |
|                                        GdkDevice  *device,
 | |
| 				       GdkWindow  *window)
 | |
| {
 | |
|   GdkPointerWindowInfo *device_info;
 | |
| 
 | |
|   device_info = _gdk_display_get_pointer_info (display, device);
 | |
| 
 | |
|   if (device_info->window_under_pointer)
 | |
|     g_object_unref (device_info->window_under_pointer);
 | |
|   device_info->window_under_pointer = window;
 | |
| 
 | |
|   if (window)
 | |
|     {
 | |
|       g_object_ref (window);
 | |
|       update_cursor (display, device);
 | |
|     }
 | |
| 
 | |
|   _gdk_display_enable_motion_hints (display, device);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_pointer_grab:
 | |
|  * @window: the #GdkWindow which will own the grab (the grab window).
 | |
|  * @owner_events: if %FALSE then all pointer events are reported with respect to
 | |
|  *                @window and are only reported if selected by @event_mask. If %TRUE then pointer
 | |
|  *                events for this application are reported as normal, but pointer events outside
 | |
|  *                this application are reported with respect to @window and only if selected by
 | |
|  *                @event_mask. In either mode, unreported events are discarded.
 | |
|  * @event_mask: specifies the event mask, which is used in accordance with
 | |
|  *              @owner_events. Note that only pointer events (i.e. button and motion events)
 | |
|  *              may be selected.
 | |
|  * @confine_to: (allow-none): If non-%NULL, the pointer will be confined to this
 | |
|  *              window during the grab. If the pointer is outside @confine_to, it will
 | |
|  *              automatically be moved to the closest edge of @confine_to and enter
 | |
|  *              and leave events will be generated as necessary.
 | |
|  * @cursor: (allow-none): the cursor to display while the grab is active. If this is %NULL then
 | |
|  *          the normal cursors are used for @window and its descendants, and the cursor
 | |
|  *          for @window is used for all other windows.
 | |
|  * @time_: the timestamp of the event which led to this pointer grab. This usually
 | |
|  *         comes from a #GdkEventButton struct, though %GDK_CURRENT_TIME can be used if
 | |
|  *         the time isn't known.
 | |
|  *
 | |
|  * Grabs the pointer (usually a mouse) so that all events are passed to this
 | |
|  * application until the pointer is ungrabbed with gdk_pointer_ungrab(), or
 | |
|  * the grab window becomes unviewable.
 | |
|  * This overrides any previous pointer grab by this client.
 | |
|  *
 | |
|  * Pointer grabs are used for operations which need complete control over mouse
 | |
|  * events, even if the mouse leaves the application.
 | |
|  * For example in GTK+ it is used for Drag and Drop, for dragging the handle in
 | |
|  * the #GtkHPaned and #GtkVPaned widgets.
 | |
|  *
 | |
|  * Note that if the event mask of an X window has selected both button press and
 | |
|  * button release events, then a button press event will cause an automatic
 | |
|  * pointer grab until the button is released.
 | |
|  * X does this automatically since most applications expect to receive button
 | |
|  * press and release events in pairs.
 | |
|  * It is equivalent to a pointer grab on the window with @owner_events set to
 | |
|  * %TRUE.
 | |
|  *
 | |
|  * If you set up anything at the time you take the grab that needs to be cleaned
 | |
|  * up when the grab ends, you should handle the #GdkEventGrabBroken events that
 | |
|  * are emitted when the grab ends unvoluntarily.
 | |
|  *
 | |
|  * Returns: %GDK_GRAB_SUCCESS if the grab was successful.
 | |
|  *
 | |
|  * Deprecated: 3.0: Use gdk_device_grab() instead.
 | |
|  **/
 | |
| GdkGrabStatus
 | |
| gdk_pointer_grab (GdkWindow *	  window,
 | |
| 		  gboolean	  owner_events,
 | |
| 		  GdkEventMask	  event_mask,
 | |
| 		  GdkWindow *	  confine_to,
 | |
| 		  GdkCursor *	  cursor,
 | |
| 		  guint32	  time)
 | |
| {
 | |
|   GdkWindow *native;
 | |
|   GdkDisplay *display;
 | |
|   GdkDeviceManager *device_manager;
 | |
|   GdkDevice *device;
 | |
|   GdkGrabStatus res = 0;
 | |
|   gulong serial;
 | |
|   GList *devices, *dev;
 | |
| 
 | |
|   g_return_val_if_fail (window != NULL, 0);
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 | |
|   g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
 | |
| 
 | |
|   /* We need a native window for confine to to work, ensure we have one */
 | |
|   if (confine_to)
 | |
|     {
 | |
|       if (!gdk_window_ensure_native (confine_to))
 | |
| 	{
 | |
| 	  g_warning ("Can't confine to grabbed window, not native");
 | |
| 	  confine_to = NULL;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   /* Non-viewable client side window => fail */
 | |
|   if (!_gdk_window_has_impl (window) &&
 | |
|       !gdk_window_is_viewable (window))
 | |
|     return GDK_GRAB_NOT_VIEWABLE;
 | |
| 
 | |
|   native = gdk_window_get_toplevel (window);
 | |
|   while (gdk_window_is_offscreen (native))
 | |
|     {
 | |
|       native = gdk_offscreen_window_get_embedder (native);
 | |
| 
 | |
|       if (native == NULL ||
 | |
| 	  (!_gdk_window_has_impl (native) &&
 | |
| 	   !gdk_window_is_viewable (native)))
 | |
| 	return GDK_GRAB_NOT_VIEWABLE;
 | |
| 
 | |
|       native = gdk_window_get_toplevel (native);
 | |
|     }
 | |
| 
 | |
|   display = gdk_window_get_display (window);
 | |
| 
 | |
|   serial = _gdk_display_get_next_serial (display);
 | |
|   device_manager = gdk_display_get_device_manager (display);
 | |
|   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
 | |
| 
 | |
|   /* FIXME: Should this be generic to all backends? */
 | |
|   /* FIXME: What happens with extended devices? */
 | |
|   for (dev = devices; dev; dev = dev->next)
 | |
|     {
 | |
|       device = dev->data;
 | |
| 
 | |
|       if (gdk_device_get_source (device) != GDK_SOURCE_MOUSE)
 | |
|         continue;
 | |
| 
 | |
|       res = GDK_DEVICE_GET_CLASS (device)->grab (device,
 | |
|                                                  native,
 | |
|                                                  owner_events,
 | |
|                                                  get_native_grab_event_mask (event_mask),
 | |
|                                                  confine_to,
 | |
|                                                  cursor,
 | |
|                                                  time);
 | |
| 
 | |
|       if (res == GDK_GRAB_SUCCESS)
 | |
|         _gdk_display_add_device_grab (display,
 | |
|                                       device,
 | |
|                                       window,
 | |
|                                       native,
 | |
|                                       GDK_OWNERSHIP_NONE,
 | |
|                                       owner_events,
 | |
|                                       event_mask,
 | |
|                                       serial,
 | |
|                                       time,
 | |
|                                       FALSE);
 | |
|     }
 | |
| 
 | |
|   /* FIXME: handle errors when grabbing */
 | |
| 
 | |
|   g_list_free (devices);
 | |
| 
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_keyboard_grab:
 | |
|  * @window: the #GdkWindow which will own the grab (the grab window).
 | |
|  * @owner_events: if %FALSE then all keyboard events are reported with respect to
 | |
|  *   @window. If %TRUE then keyboard events for this application are
 | |
|  *   reported as normal, but keyboard events outside this application
 | |
|  *   are reported with respect to @window. Both key press and key
 | |
|  *   release events are always reported, independant of the event mask
 | |
|  *   set by the application.
 | |
|  * @time_: a timestamp from a #GdkEvent, or %GDK_CURRENT_TIME if no timestamp is
 | |
|  *   available.
 | |
|  *
 | |
|  * Grabs the keyboard so that all events are passed to this
 | |
|  * application until the keyboard is ungrabbed with gdk_keyboard_ungrab().
 | |
|  * This overrides any previous keyboard grab by this client.
 | |
|  *
 | |
|  * If you set up anything at the time you take the grab that needs to be cleaned
 | |
|  * up when the grab ends, you should handle the #GdkEventGrabBroken events that
 | |
|  * are emitted when the grab ends unvoluntarily.
 | |
|  *
 | |
|  * Returns: %GDK_GRAB_SUCCESS if the grab was successful.
 | |
|  *
 | |
|  * Deprecated: 3.0: Use gdk_device_grab() instead.
 | |
|  **/
 | |
| GdkGrabStatus
 | |
| gdk_keyboard_grab (GdkWindow *window,
 | |
| 		   gboolean   owner_events,
 | |
| 		   guint32    time)
 | |
| {
 | |
|   GdkWindow *native;
 | |
|   GdkDisplay *display;
 | |
|   GdkDeviceManager *device_manager;
 | |
|   GdkDevice *device;
 | |
|   GdkGrabStatus res = 0;
 | |
|   gulong serial;
 | |
|   GList *devices, *dev;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 | |
| 
 | |
|   /* Non-viewable client side window => fail */
 | |
|   if (!_gdk_window_has_impl (window) &&
 | |
|       !gdk_window_is_viewable (window))
 | |
|     return GDK_GRAB_NOT_VIEWABLE;
 | |
| 
 | |
|   native = gdk_window_get_toplevel (window);
 | |
| 
 | |
|   while (gdk_window_is_offscreen (native))
 | |
|     {
 | |
|       native = gdk_offscreen_window_get_embedder (native);
 | |
| 
 | |
|       if (native == NULL ||
 | |
| 	  (!_gdk_window_has_impl (native) &&
 | |
| 	   !gdk_window_is_viewable (native)))
 | |
| 	return GDK_GRAB_NOT_VIEWABLE;
 | |
| 
 | |
|       native = gdk_window_get_toplevel (native);
 | |
|     }
 | |
| 
 | |
|   display = gdk_window_get_display (window);
 | |
|   serial = _gdk_display_get_next_serial (display);
 | |
|   device_manager = gdk_display_get_device_manager (display);
 | |
|   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
 | |
| 
 | |
|   /* FIXME: Should this be generic to all backends? */
 | |
|   /* FIXME: What happens with extended devices? */
 | |
|   for (dev = devices; dev; dev = dev->next)
 | |
|     {
 | |
|       device = dev->data;
 | |
| 
 | |
|       if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
 | |
|         continue;
 | |
| 
 | |
|       res = GDK_DEVICE_GET_CLASS (device)->grab (device,
 | |
|                                                  native,
 | |
|                                                  owner_events,
 | |
|                                                  GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
 | |
|                                                  NULL,
 | |
|                                                  NULL,
 | |
|                                                  time);
 | |
| 
 | |
|       if (res == GDK_GRAB_SUCCESS)
 | |
|         _gdk_display_add_device_grab (display,
 | |
|                                       device,
 | |
|                                       window,
 | |
|                                       native,
 | |
|                                       GDK_OWNERSHIP_NONE,
 | |
|                                       owner_events, 0,
 | |
|                                       serial,
 | |
|                                       time,
 | |
|                                       FALSE);
 | |
|     }
 | |
| 
 | |
|   /* FIXME: handle errors when grabbing */
 | |
| 
 | |
|   g_list_free (devices);
 | |
| 
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_geometry_changed:
 | |
|  * @window: an embedded offscreen #GdkWindow
 | |
|  *
 | |
|  * This function informs GDK that the geometry of an embedded
 | |
|  * offscreen window has changed. This is necessary for GDK to keep
 | |
|  * track of which offscreen window the pointer is in.
 | |
|  *
 | |
|  * Since: 2.18
 | |
|  */
 | |
| void
 | |
| gdk_window_geometry_changed (GdkWindow *window)
 | |
| {
 | |
|   _gdk_synthesize_crossing_events_for_geometry_change (window);
 | |
| }
 | |
| 
 | |
| static void
 | |
| source_events_device_added (GdkDeviceManager *device_manager,
 | |
|                             GdkDevice        *device,
 | |
|                             gpointer          user_data)
 | |
| {
 | |
|   GdkWindow *window;
 | |
|   GdkEventMask event_mask;
 | |
|   GdkInputSource source;
 | |
| 
 | |
|   if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_FLOATING)
 | |
|     return;
 | |
| 
 | |
|   window = user_data;
 | |
|   source = gdk_device_get_source (device);
 | |
| 
 | |
|   event_mask = GPOINTER_TO_INT (g_hash_table_lookup (window->source_event_masks,
 | |
|                                                      GINT_TO_POINTER (source)));
 | |
|   if (event_mask)
 | |
|     gdk_window_set_device_events (window, device, event_mask);
 | |
| }
 | |
| 
 | |
| static void
 | |
| source_events_device_changed (GdkDeviceManager *device_manager,
 | |
|                               GdkDevice        *device,
 | |
|                               gpointer          user_data)
 | |
| {
 | |
|   GdkDeviceType type;
 | |
|   GdkInputSource source;
 | |
|   GdkEventMask event_mask;
 | |
|   GdkWindow *window;
 | |
| 
 | |
|   window = user_data;
 | |
|   type = gdk_device_get_device_type (device);
 | |
|   source = gdk_device_get_source (device);
 | |
| 
 | |
|   event_mask = GPOINTER_TO_INT (g_hash_table_lookup (window->source_event_masks,
 | |
|                                                      GINT_TO_POINTER (source)));
 | |
| 
 | |
|   if (!event_mask)
 | |
|     return;
 | |
| 
 | |
|   if (type == GDK_DEVICE_TYPE_FLOATING)
 | |
|     {
 | |
|       /* The device was just floated, enable its event mask */
 | |
|       gdk_window_set_device_events (window, device, event_mask);
 | |
|     }
 | |
|   else if (type == GDK_DEVICE_TYPE_SLAVE)
 | |
|     gdk_window_set_device_events (window, device, 0);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_source_events:
 | |
|  * @window: a #GdkWindow
 | |
|  * @source: a #GdkInputSource to define the source class.
 | |
|  * @event_mask: event mask for @window
 | |
|  *
 | |
|  * Sets the event mask for any floating device (i.e. not attached to any
 | |
|  * visible pointer) that has the source defined as @source. This event
 | |
|  * mask will be applied both to currently existing, newly added devices
 | |
|  * after this call, and devices being attached/detached.
 | |
|  *
 | |
|  * Since: 3.0
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_source_events (GdkWindow      *window,
 | |
|                               GdkInputSource  source,
 | |
|                               GdkEventMask    event_mask)
 | |
| {
 | |
|   GdkDeviceManager *device_manager;
 | |
|   GdkDisplay *display;
 | |
|   GList *devices, *d;
 | |
|   guint size;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   display = gdk_window_get_display (window);
 | |
|   device_manager = gdk_display_get_device_manager (display);
 | |
| 
 | |
|   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING);
 | |
| 
 | |
|   /* Set event mask for existing devices */
 | |
|   for (d = devices; d; d = d->next)
 | |
|     {
 | |
|       GdkDevice *device = d->data;
 | |
| 
 | |
|       if (source == gdk_device_get_source (device))
 | |
|         gdk_window_set_device_events (window, device, event_mask);
 | |
|     }
 | |
| 
 | |
|   g_list_free (devices);
 | |
| 
 | |
|   /* Update accounting */
 | |
|   if (G_UNLIKELY (!window->source_event_masks))
 | |
|     window->source_event_masks = g_hash_table_new (NULL, NULL);
 | |
| 
 | |
|   if (event_mask)
 | |
|     g_hash_table_insert (window->source_event_masks,
 | |
|                          GUINT_TO_POINTER (source),
 | |
|                          GUINT_TO_POINTER (event_mask));
 | |
|   else
 | |
|     g_hash_table_remove (window->source_event_masks,
 | |
|                          GUINT_TO_POINTER (source));
 | |
| 
 | |
|   size = g_hash_table_size (window->source_event_masks);
 | |
| 
 | |
|   /* Update handler if needed */
 | |
|   if (!window->device_added_handler_id && size > 0)
 | |
|     {
 | |
|       window->device_added_handler_id =
 | |
|         g_signal_connect (device_manager, "device-added",
 | |
|                           G_CALLBACK (source_events_device_added), window);
 | |
|       window->device_changed_handler_id =
 | |
|         g_signal_connect (device_manager, "device-changed",
 | |
|                           G_CALLBACK (source_events_device_changed), window);
 | |
|     }
 | |
|   else if (window->device_added_handler_id && size == 0)
 | |
|     g_signal_handler_disconnect (device_manager, window->device_added_handler_id);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_source_events:
 | |
|  * @window: a #GdkWindow
 | |
|  * @source: a #GdkInputSource to define the source class.
 | |
|  *
 | |
|  * Returns the event mask for @window corresponding to the device class specified
 | |
|  * by @source.
 | |
|  *
 | |
|  * Returns: source event mask for @window
 | |
|  **/
 | |
| GdkEventMask
 | |
| gdk_window_get_source_events (GdkWindow      *window,
 | |
|                               GdkInputSource  source)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 | |
| 
 | |
|   return GPOINTER_TO_UINT (g_hash_table_lookup (window->source_event_masks,
 | |
|                                                 GUINT_TO_POINTER (source)));
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| do_synthesize_crossing_event (gpointer data)
 | |
| {
 | |
|   GdkDisplay *display;
 | |
|   GdkWindow *changed_toplevel;
 | |
|   GHashTableIter iter;
 | |
|   gpointer key, value;
 | |
|   gulong serial;
 | |
| 
 | |
|   changed_toplevel = data;
 | |
| 
 | |
|   changed_toplevel->synthesize_crossing_event_queued = FALSE;
 | |
| 
 | |
|   if (GDK_WINDOW_DESTROYED (changed_toplevel))
 | |
|     return FALSE;
 | |
| 
 | |
|   display = gdk_window_get_display (changed_toplevel);
 | |
|   serial = _gdk_display_get_next_serial (display);
 | |
|   g_hash_table_iter_init (&iter, display->pointers_info);
 | |
| 
 | |
|   while (g_hash_table_iter_next (&iter, &key, &value))
 | |
|     {
 | |
|       GdkWindow *new_window_under_pointer;
 | |
|       GdkPointerWindowInfo *pointer_info = value;
 | |
|       GdkDevice *device = key;
 | |
| 
 | |
|       if (changed_toplevel == pointer_info->toplevel_under_pointer)
 | |
|         {
 | |
|           new_window_under_pointer =
 | |
|             get_pointer_window (display, changed_toplevel,
 | |
|                                 device,
 | |
|                                 pointer_info->toplevel_x,
 | |
|                                 pointer_info->toplevel_y,
 | |
|                                 serial);
 | |
|           if (new_window_under_pointer != pointer_info->window_under_pointer)
 | |
|             {
 | |
|               _gdk_synthesize_crossing_events (display,
 | |
|                                                pointer_info->window_under_pointer,
 | |
|                                                new_window_under_pointer,
 | |
|                                                device, pointer_info->last_slave,
 | |
|                                                GDK_CROSSING_NORMAL,
 | |
|                                                pointer_info->toplevel_x,
 | |
|                                                pointer_info->toplevel_y,
 | |
|                                                pointer_info->state,
 | |
|                                                GDK_CURRENT_TIME,
 | |
|                                                NULL,
 | |
|                                                serial,
 | |
|                                                FALSE);
 | |
|               _gdk_display_set_window_under_pointer (display, device, new_window_under_pointer);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| void
 | |
| _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
 | |
| {
 | |
|   GdkWindow *toplevel;
 | |
| 
 | |
|   toplevel = get_event_toplevel (changed_window);
 | |
| 
 | |
|   if (!toplevel->synthesize_crossing_event_queued)
 | |
|     {
 | |
|       toplevel->synthesize_crossing_event_queued = TRUE;
 | |
| 
 | |
|       gdk_threads_add_idle_full (GDK_PRIORITY_EVENTS - 1,
 | |
|                                  do_synthesize_crossing_event,
 | |
|                                  g_object_ref (toplevel),
 | |
|                                  g_object_unref);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Don't use for crossing events */
 | |
| 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)
 | |
| {
 | |
|   guint evmask, emulated_mask = 0;
 | |
|   GdkWindow *grab_window;
 | |
|   GdkDeviceGrabInfo *grab;
 | |
|   GdkTouchGrabInfo *touch_grab;
 | |
| 
 | |
|   touch_grab = _gdk_display_has_touch_grab (display, device, sequence, serial);
 | |
|   grab = _gdk_display_get_last_device_grab (display, device);
 | |
| 
 | |
|   if (is_touch_type (type) && pointer_emulated)
 | |
|     {
 | |
|       switch (type)
 | |
|         {
 | |
|         case GDK_TOUCH_BEGIN:
 | |
|           emulated_mask |= GDK_BUTTON_PRESS_MASK;
 | |
|           break;
 | |
|         case GDK_TOUCH_UPDATE:
 | |
|           emulated_mask |= GDK_POINTER_MOTION_MASK;
 | |
|           break;
 | |
|         case GDK_TOUCH_END:
 | |
|           emulated_mask |= GDK_BUTTON_RELEASE_MASK;
 | |
|         default:
 | |
|           break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   if (touch_grab != NULL &&
 | |
|       (!grab || grab->implicit || touch_grab->serial >= grab->serial_start))
 | |
|     {
 | |
|       evmask = touch_grab->event_mask;
 | |
|       evmask = update_evmask_for_button_motion (evmask, mask);
 | |
| 
 | |
|       if (evmask & (type_masks[type] | emulated_mask))
 | |
|         {
 | |
|           if (evmask_out)
 | |
|             *evmask_out = evmask;
 | |
|           return touch_grab->window;
 | |
|         }
 | |
|       else
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|   if (grab != NULL && !grab->owner_events)
 | |
|     {
 | |
|       evmask = grab->event_mask;
 | |
|       evmask = update_evmask_for_button_motion (evmask, mask);
 | |
| 
 | |
|       grab_window = grab->window;
 | |
| 
 | |
|       if (evmask & (type_masks[type] | emulated_mask))
 | |
| 	{
 | |
| 	  if (evmask_out)
 | |
| 	    *evmask_out = evmask;
 | |
| 	  return grab_window;
 | |
| 	}
 | |
|       else
 | |
| 	return NULL;
 | |
|     }
 | |
| 
 | |
|   while (pointer_window != NULL)
 | |
|     {
 | |
|       evmask = pointer_window->event_mask;
 | |
|       evmask = update_evmask_for_button_motion (evmask, mask);
 | |
| 
 | |
|       if (evmask & (type_masks[type] | emulated_mask))
 | |
| 	{
 | |
| 	  if (evmask_out)
 | |
| 	    *evmask_out = evmask;
 | |
| 	  return pointer_window;
 | |
| 	}
 | |
| 
 | |
|       pointer_window = get_event_parent (pointer_window);
 | |
|     }
 | |
| 
 | |
|   if (grab != NULL &&
 | |
|       grab->owner_events)
 | |
|     {
 | |
|       evmask = grab->event_mask;
 | |
|       evmask = update_evmask_for_button_motion (evmask, mask);
 | |
| 
 | |
|       if (evmask & (type_masks[type] | emulated_mask))
 | |
| 	{
 | |
| 	  if (evmask_out)
 | |
| 	    *evmask_out = evmask;
 | |
| 	  return grab->window;
 | |
| 	}
 | |
|       else
 | |
| 	return NULL;
 | |
|     }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| proxy_pointer_event (GdkDisplay                 *display,
 | |
| 		     GdkEvent                   *source_event,
 | |
| 		     gulong                      serial)
 | |
| {
 | |
|   GdkWindow *toplevel_window, *event_window;
 | |
|   GdkWindow *pointer_window;
 | |
|   GdkPointerWindowInfo *pointer_info;
 | |
|   GdkDevice *device, *source_device;
 | |
|   GdkEvent *event;
 | |
|   guint state;
 | |
|   gdouble toplevel_x, toplevel_y;
 | |
|   guint32 time_;
 | |
|   gboolean non_linear, need_synthetic_enter = FALSE;
 | |
|   gint event_type;
 | |
| 
 | |
|   event_type = source_event->type;
 | |
|   event_window = source_event->any.window;
 | |
|   gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
 | |
|   gdk_event_get_state (source_event, &state);
 | |
|   time_ = gdk_event_get_time (source_event);
 | |
|   device = gdk_event_get_device (source_event);
 | |
|   source_device = gdk_event_get_source_device (source_event);
 | |
|   pointer_info = _gdk_display_get_pointer_info (display, device);
 | |
|   toplevel_window = convert_native_coords_to_toplevel (event_window,
 | |
| 						       toplevel_x, toplevel_y,
 | |
| 						       &toplevel_x, &toplevel_y);
 | |
| 
 | |
|   non_linear = FALSE;
 | |
|   if ((source_event->type == GDK_LEAVE_NOTIFY ||
 | |
|        source_event->type == GDK_ENTER_NOTIFY) &&
 | |
|       (source_event->crossing.detail == GDK_NOTIFY_NONLINEAR ||
 | |
|        source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))
 | |
|     non_linear = TRUE;
 | |
| 
 | |
|   if (pointer_info->need_touch_press_enter &&
 | |
|       gdk_device_get_source (pointer_info->last_slave) != GDK_SOURCE_TOUCHSCREEN &&
 | |
|       (source_event->type != GDK_TOUCH_UPDATE ||
 | |
|        _gdk_event_get_pointer_emulated (source_event)))
 | |
|     {
 | |
|       pointer_info->need_touch_press_enter = FALSE;
 | |
|       need_synthetic_enter = TRUE;
 | |
|     }
 | |
| 
 | |
|   /* If we get crossing events with subwindow unexpectedly being NULL
 | |
|      that means there is a native subwindow that gdk doesn't know about.
 | |
|      We track these and forward them, with the correct virtual window
 | |
|      events inbetween.
 | |
|      This is important to get right, as metacity uses gdk for the frame
 | |
|      windows, but gdk doesn't know about the client windows reparented
 | |
|      into the frame. */
 | |
|   if (((source_event->type == GDK_LEAVE_NOTIFY &&
 | |
| 	source_event->crossing.detail == GDK_NOTIFY_INFERIOR) ||
 | |
|        (source_event->type == GDK_ENTER_NOTIFY &&
 | |
| 	(source_event->crossing.detail == GDK_NOTIFY_VIRTUAL ||
 | |
| 	 source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))) &&
 | |
|       source_event->crossing.subwindow == NULL)
 | |
|     {
 | |
|       /* Left for an unknown (to gdk) subwindow */
 | |
| 
 | |
|       /* Send leave events from window under pointer to event window
 | |
| 	 that will get the subwindow == NULL window */
 | |
|       _gdk_synthesize_crossing_events (display,
 | |
| 				       pointer_info->window_under_pointer,
 | |
| 				       event_window,
 | |
|                                        device, source_device,
 | |
| 				       source_event->crossing.mode,
 | |
| 				       toplevel_x, toplevel_y,
 | |
| 				       state, time_,
 | |
| 				       source_event,
 | |
| 				       serial,
 | |
| 				       non_linear);
 | |
| 
 | |
|       /* Send subwindow == NULL event */
 | |
|       send_crossing_event (display,
 | |
| 			   toplevel_window,
 | |
| 			   event_window,
 | |
| 			   source_event->type,
 | |
| 			   source_event->crossing.mode,
 | |
| 			   source_event->crossing.detail,
 | |
| 			   NULL,
 | |
|                            device, source_device,
 | |
| 			   toplevel_x, toplevel_y,
 | |
| 			   state, time_,
 | |
| 			   source_event,
 | |
| 			   serial);
 | |
| 
 | |
|       _gdk_display_set_window_under_pointer (display, device, NULL);
 | |
|       return TRUE;
 | |
|     }
 | |
| 
 | |
|   pointer_window = get_pointer_window (display, toplevel_window, device,
 | |
| 				       toplevel_x, toplevel_y, serial);
 | |
| 
 | |
|   if (((source_event->type == GDK_ENTER_NOTIFY &&
 | |
| 	source_event->crossing.detail == GDK_NOTIFY_INFERIOR) ||
 | |
|        (source_event->type == GDK_LEAVE_NOTIFY &&
 | |
| 	(source_event->crossing.detail == GDK_NOTIFY_VIRTUAL ||
 | |
| 	 source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))) &&
 | |
|       source_event->crossing.subwindow == NULL)
 | |
|     {
 | |
|       /* Entered from an unknown (to gdk) subwindow */
 | |
| 
 | |
|       /* Send subwindow == NULL event */
 | |
|       send_crossing_event (display,
 | |
| 			   toplevel_window,
 | |
| 			   event_window,
 | |
| 			   source_event->type,
 | |
| 			   source_event->crossing.mode,
 | |
| 			   source_event->crossing.detail,
 | |
| 			   NULL,
 | |
|                            device, source_device,
 | |
| 			   toplevel_x, toplevel_y,
 | |
| 			   state, time_,
 | |
| 			   source_event,
 | |
| 			   serial);
 | |
| 
 | |
|       /* Send enter events from event window to pointer_window */
 | |
|       _gdk_synthesize_crossing_events (display,
 | |
| 				       event_window,
 | |
| 				       pointer_window,
 | |
|                                        device, source_device,
 | |
| 				       source_event->crossing.mode,
 | |
| 				       toplevel_x, toplevel_y,
 | |
| 				       state, time_,
 | |
| 				       source_event,
 | |
| 				       serial, non_linear);
 | |
|       _gdk_display_set_window_under_pointer (display, device, pointer_window);
 | |
|       return TRUE;
 | |
|     }
 | |
| 
 | |
|   if ((source_event->type != GDK_TOUCH_UPDATE ||
 | |
|        _gdk_event_get_pointer_emulated (source_event)) &&
 | |
|       pointer_info->window_under_pointer != pointer_window)
 | |
|     {
 | |
|       /* Either a toplevel crossing notify that ended up inside a child window,
 | |
| 	 or a motion notify that got into another child window  */
 | |
| 
 | |
|       /* Different than last time, send crossing events */
 | |
|       _gdk_synthesize_crossing_events (display,
 | |
| 				       pointer_info->window_under_pointer,
 | |
| 				       pointer_window,
 | |
|                                        device, source_device,
 | |
| 				       GDK_CROSSING_NORMAL,
 | |
| 				       toplevel_x, toplevel_y,
 | |
| 				       state, time_,
 | |
| 				       source_event,
 | |
| 				       serial, non_linear);
 | |
|       _gdk_display_set_window_under_pointer (display, device, pointer_window);
 | |
|     }
 | |
|   else if (source_event->type == GDK_MOTION_NOTIFY ||
 | |
|            source_event->type == GDK_TOUCH_UPDATE)
 | |
|     {
 | |
|       GdkWindow *event_win;
 | |
|       guint evmask;
 | |
|       gboolean is_hint;
 | |
|       GdkEventSequence *sequence;
 | |
| 
 | |
|       sequence = gdk_event_get_event_sequence (source_event);
 | |
| 
 | |
|       event_win = get_event_window (display,
 | |
|                                     device,
 | |
|                                     sequence,
 | |
|                                     pointer_window,
 | |
|                                     source_event->type,
 | |
|                                     state,
 | |
|                                     &evmask,
 | |
|                                     _gdk_event_get_pointer_emulated (source_event),
 | |
|                                     serial);
 | |
| 
 | |
|       if (event_type == GDK_TOUCH_UPDATE)
 | |
|         {
 | |
|           if (_gdk_event_get_pointer_emulated (source_event))
 | |
|             {
 | |
|               /* Touch events emulating pointer events are transformed back
 | |
|                * to pointer events if:
 | |
|                * 1 - The event window doesn't select for touch events
 | |
|                * 2 - There's no touch grab for this sequence, which means
 | |
|                *     it was started as a pointer sequence, but a device
 | |
|                *     grab added touch events afterwards, the sequence must
 | |
|                *     not mutate in this case.
 | |
|                */
 | |
|               if ((evmask & GDK_TOUCH_MASK) == 0 ||
 | |
|                   !_gdk_display_has_touch_grab (display, device, sequence, serial))
 | |
|                 event_type = GDK_MOTION_NOTIFY;
 | |
|             }
 | |
|           else if ((evmask & GDK_TOUCH_MASK) == 0)
 | |
|             return TRUE;
 | |
|         }
 | |
| 
 | |
|       if (is_touch_type (source_event->type) && !is_touch_type (event_type))
 | |
|         state |= GDK_BUTTON1_MASK;
 | |
| 
 | |
|       if (event_win &&
 | |
|           gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER &&
 | |
|           gdk_window_get_device_events (event_win, device) == 0)
 | |
|         return TRUE;
 | |
| 
 | |
|       /* The last device to interact with the window was a touch device,
 | |
|        * which synthesized a leave notify event, so synthesize another enter
 | |
|        * notify to tell the pointer is on the window.
 | |
|        */
 | |
|       if (need_synthetic_enter)
 | |
|         _gdk_synthesize_crossing_events (display,
 | |
|                                          NULL, pointer_window,
 | |
|                                          device, source_device,
 | |
|                                          GDK_CROSSING_DEVICE_SWITCH,
 | |
|                                          toplevel_x, toplevel_y,
 | |
|                                          state, time_, NULL,
 | |
|                                          serial, FALSE);
 | |
| 
 | |
|       is_hint = FALSE;
 | |
| 
 | |
|       if (event_win &&
 | |
|           event_type == GDK_MOTION_NOTIFY &&
 | |
| 	  (evmask & GDK_POINTER_MOTION_HINT_MASK))
 | |
| 	{
 | |
|           gulong *device_serial;
 | |
| 
 | |
|           device_serial = g_hash_table_lookup (display->motion_hint_info, device);
 | |
| 
 | |
|           if (!device_serial ||
 | |
|               (*device_serial != 0 &&
 | |
|                serial < *device_serial))
 | |
| 	    event_win = NULL; /* Ignore event */
 | |
| 	  else
 | |
| 	    {
 | |
| 	      is_hint = TRUE;
 | |
|               *device_serial = G_MAXULONG;
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|       if (!event_win)
 | |
|         return TRUE;
 | |
| 
 | |
|       event = gdk_event_new (event_type);
 | |
|       event->any.window = g_object_ref (event_win);
 | |
|       event->any.send_event = source_event->any.send_event;
 | |
| 
 | |
|       gdk_event_set_device (event, gdk_event_get_device (source_event));
 | |
|       gdk_event_set_source_device (event, source_device);
 | |
| 
 | |
|       if (event_type == GDK_TOUCH_UPDATE)
 | |
| 	{
 | |
| 	  event->touch.time = time_;
 | |
| 	  event->touch.state = state | GDK_BUTTON1_MASK;
 | |
| 	  event->touch.sequence = source_event->touch.sequence;
 | |
| 	  event->touch.emulating_pointer = source_event->touch.emulating_pointer;
 | |
| 	  convert_toplevel_coords_to_window (event_win,
 | |
| 					     toplevel_x, toplevel_y,
 | |
| 					     &event->touch.x, &event->touch.y);
 | |
| 	  gdk_event_get_root_coords (source_event,
 | |
| 				     &event->touch.x_root,
 | |
| 				     &event->touch.y_root);
 | |
| 
 | |
| 	  event->touch.axes = g_memdup (source_event->touch.axes,
 | |
| 					sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  event->motion.time = time_;
 | |
| 	  event->motion.state = state;
 | |
| 	  event->motion.is_hint = is_hint;
 | |
| 
 | |
| 	  convert_toplevel_coords_to_window (event_win,
 | |
| 					     toplevel_x, toplevel_y,
 | |
| 					     &event->motion.x, &event->motion.y);
 | |
| 	  gdk_event_get_root_coords (source_event,
 | |
| 				     &event->motion.x_root,
 | |
| 				     &event->motion.y_root);
 | |
| 
 | |
| 	  if (is_touch_type (source_event->type))
 | |
| 	    event->motion.axes = g_memdup (source_event->touch.axes,
 | |
| 					   sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
 | |
| 	  else
 | |
| 	    event->motion.axes = g_memdup (source_event->motion.axes,
 | |
| 					   sizeof (gdouble) * gdk_device_get_n_axes (source_event->motion.device));
 | |
| 	}
 | |
| 
 | |
|       /* Just insert the event */
 | |
|       _gdk_event_queue_insert_after (gdk_window_get_display (event_win),
 | |
| 				     source_event, event);
 | |
|     }
 | |
| 
 | |
|   /* unlink all move events from queue.
 | |
|      We handle our own, including our emulated masks. */
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| #define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \
 | |
| 			     GDK_BUTTON2_MASK | \
 | |
| 			     GDK_BUTTON3_MASK | \
 | |
| 			     GDK_BUTTON4_MASK | \
 | |
| 			     GDK_BUTTON5_MASK)
 | |
| 
 | |
| static gboolean
 | |
| proxy_button_event (GdkEvent *source_event,
 | |
| 		    gulong serial)
 | |
| {
 | |
|   GdkWindow *toplevel_window, *event_window;
 | |
|   GdkWindow *event_win;
 | |
|   GdkWindow *pointer_window;
 | |
|   GdkWindow *parent;
 | |
|   GdkEvent *event;
 | |
|   GdkPointerWindowInfo *pointer_info;
 | |
|   GdkDeviceGrabInfo *pointer_grab;
 | |
|   guint state;
 | |
|   guint32 time_;
 | |
|   GdkEventType type;
 | |
|   gdouble toplevel_x, toplevel_y;
 | |
|   GdkDisplay *display;
 | |
|   GdkWindow *w;
 | |
|   GdkDevice *device, *source_device;
 | |
|   GdkEventMask evmask;
 | |
|   GdkEventSequence *sequence;
 | |
| 
 | |
|   type = source_event->any.type;
 | |
|   event_window = source_event->any.window;
 | |
|   gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
 | |
|   gdk_event_get_state (source_event, &state);
 | |
|   time_ = gdk_event_get_time (source_event);
 | |
|   device = gdk_event_get_device (source_event);
 | |
|   source_device = gdk_event_get_source_device (source_event);
 | |
|   display = gdk_window_get_display (source_event->any.window);
 | |
|   toplevel_window = convert_native_coords_to_toplevel (event_window,
 | |
| 						       toplevel_x, toplevel_y,
 | |
| 						       &toplevel_x, &toplevel_y);
 | |
| 
 | |
|   sequence = gdk_event_get_event_sequence (source_event);
 | |
| 
 | |
|   pointer_info = _gdk_display_get_pointer_info (display, device);
 | |
|   pointer_grab = _gdk_display_has_device_grab (display, device, serial);
 | |
| 
 | |
|   if ((type == GDK_BUTTON_PRESS ||
 | |
|        type == GDK_TOUCH_BEGIN) &&
 | |
|       !source_event->any.send_event &&
 | |
|       (!pointer_grab ||
 | |
|        (type == GDK_TOUCH_BEGIN && pointer_grab->implicit &&
 | |
|         !_gdk_event_get_pointer_emulated (source_event))))
 | |
|     {
 | |
|       pointer_window =
 | |
| 	_gdk_window_find_descendant_at (toplevel_window,
 | |
| 					toplevel_x, toplevel_y,
 | |
| 					NULL, NULL);
 | |
| 
 | |
|       /* Find the event window, that gets the grab */
 | |
|       w = pointer_window;
 | |
|       while (w != NULL &&
 | |
| 	     (parent = get_event_parent (w)) != NULL &&
 | |
| 	     parent->window_type != GDK_WINDOW_ROOT)
 | |
| 	{
 | |
| 	  if (w->event_mask & GDK_BUTTON_PRESS_MASK &&
 | |
|               (type == GDK_BUTTON_PRESS ||
 | |
|                _gdk_event_get_pointer_emulated (source_event)))
 | |
| 	    break;
 | |
| 
 | |
|           if (type == GDK_TOUCH_BEGIN &&
 | |
|               w->event_mask & GDK_TOUCH_MASK)
 | |
|             break;
 | |
| 
 | |
| 	  w = parent;
 | |
| 	}
 | |
|       pointer_window = w;
 | |
| 
 | |
|       if (pointer_window)
 | |
|         {
 | |
|           if (type == GDK_TOUCH_BEGIN &&
 | |
|               pointer_window->event_mask & GDK_TOUCH_MASK)
 | |
|             {
 | |
|               _gdk_display_add_touch_grab (display, device, sequence,
 | |
|                                            pointer_window, event_window,
 | |
|                                            gdk_window_get_events (pointer_window),
 | |
|                                            serial, time_);
 | |
|             }
 | |
|           else if (type == GDK_BUTTON_PRESS ||
 | |
|                    _gdk_event_get_pointer_emulated (source_event))
 | |
|             {
 | |
|               _gdk_display_add_device_grab  (display,
 | |
|                                              device,
 | |
|                                              pointer_window,
 | |
|                                              event_window,
 | |
|                                              GDK_OWNERSHIP_NONE,
 | |
|                                              FALSE,
 | |
|                                              gdk_window_get_events (pointer_window),
 | |
|                                              serial,
 | |
|                                              time_,
 | |
|                                              TRUE);
 | |
|               _gdk_display_device_grab_update (display, device,
 | |
|                                                source_device, serial);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   pointer_window = get_pointer_window (display, toplevel_window, device,
 | |
| 				       toplevel_x, toplevel_y,
 | |
| 				       serial);
 | |
| 
 | |
|   event_win = get_event_window (display,
 | |
|                                 device,
 | |
|                                 sequence,
 | |
|                                 pointer_window,
 | |
|                                 type, state,
 | |
|                                 &evmask,
 | |
|                                 _gdk_event_get_pointer_emulated (source_event),
 | |
|                                 serial);
 | |
| 
 | |
|   if (type == GDK_TOUCH_BEGIN || type == GDK_TOUCH_END)
 | |
|     {
 | |
|       if (_gdk_event_get_pointer_emulated (source_event))
 | |
|         {
 | |
|           if ((evmask & GDK_TOUCH_MASK) == 0 ||
 | |
|               !_gdk_display_has_touch_grab (display, device, sequence, serial))
 | |
|             {
 | |
|               if (type == GDK_TOUCH_BEGIN)
 | |
|                 type = GDK_BUTTON_PRESS;
 | |
|               else if (type == GDK_TOUCH_END)
 | |
|                 type = GDK_BUTTON_RELEASE;
 | |
|             }
 | |
|         }
 | |
|       else if ((evmask & GDK_TOUCH_MASK) == 0)
 | |
|         return TRUE;
 | |
|     }
 | |
| 
 | |
|   if (source_event->type == GDK_TOUCH_END && !is_touch_type (type))
 | |
|     state |= GDK_BUTTON1_MASK;
 | |
| 
 | |
|   if (event_win == NULL)
 | |
|     return TRUE;
 | |
| 
 | |
|   if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER &&
 | |
|       gdk_window_get_device_events (event_win, device) == 0)
 | |
|     return TRUE;
 | |
| 
 | |
|   if ((type == GDK_BUTTON_PRESS ||
 | |
|        (type == GDK_TOUCH_BEGIN &&
 | |
|         _gdk_event_get_pointer_emulated (source_event))) &&
 | |
|       pointer_info->need_touch_press_enter)
 | |
|     {
 | |
|       GdkCrossingMode mode;
 | |
| 
 | |
|       /* The last device to interact with the window was a touch device,
 | |
|        * which synthesized a leave notify event, so synthesize another enter
 | |
|        * notify to tell the pointer is on the window.
 | |
|        */
 | |
|       if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
 | |
|         mode = GDK_CROSSING_TOUCH_BEGIN;
 | |
|       else
 | |
|         mode = GDK_CROSSING_DEVICE_SWITCH;
 | |
| 
 | |
|       pointer_info->need_touch_press_enter = FALSE;
 | |
|       _gdk_synthesize_crossing_events (display,
 | |
|                                        NULL,
 | |
|                                        pointer_info->window_under_pointer,
 | |
|                                        device, source_device, mode,
 | |
|                                        toplevel_x, toplevel_y,
 | |
|                                        state, time_, source_event,
 | |
|                                        serial, FALSE);
 | |
|     }
 | |
|   else if (type == GDK_SCROLL &&
 | |
|            (((evmask & GDK_SMOOTH_SCROLL_MASK) == 0 &&
 | |
|              source_event->scroll.direction == GDK_SCROLL_SMOOTH) ||
 | |
|             ((evmask & GDK_SMOOTH_SCROLL_MASK) != 0 &&
 | |
|              source_event->scroll.direction != GDK_SCROLL_SMOOTH &&
 | |
|              _gdk_event_get_pointer_emulated (source_event))))
 | |
|     return FALSE;
 | |
| 
 | |
|   event = _gdk_make_event (event_win, type, source_event, FALSE);
 | |
| 
 | |
|   switch (type)
 | |
|     {
 | |
|     case GDK_BUTTON_PRESS:
 | |
|     case GDK_BUTTON_RELEASE:
 | |
|       event->button.button = source_event->button.button;
 | |
|       convert_toplevel_coords_to_window (event_win,
 | |
| 					 toplevel_x, toplevel_y,
 | |
| 					 &event->button.x, &event->button.y);
 | |
|       gdk_event_get_root_coords (source_event,
 | |
| 				 &event->button.x_root,
 | |
| 				 &event->button.y_root);
 | |
|       gdk_event_set_device (event, gdk_event_get_device (source_event));
 | |
|       gdk_event_set_source_device (event, source_device);
 | |
| 
 | |
|       if (is_touch_type (source_event->type))
 | |
|         {
 | |
|           if (type == GDK_BUTTON_RELEASE)
 | |
|             event->button.state |= GDK_BUTTON1_MASK;
 | |
| 	  event->button.button = 1;
 | |
| 	  event->button.axes = g_memdup (source_event->touch.axes,
 | |
| 					 sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  event->button.button = source_event->button.button;
 | |
| 	  event->button.axes = g_memdup (source_event->button.axes,
 | |
| 					 sizeof (gdouble) * gdk_device_get_n_axes (source_event->button.device));
 | |
| 	}
 | |
| 
 | |
|       if (type == GDK_BUTTON_PRESS)
 | |
|         _gdk_event_button_generate (display, event);
 | |
|       else if ((type == GDK_BUTTON_RELEASE ||
 | |
|                 (type == GDK_TOUCH_END &&
 | |
|                  _gdk_event_get_pointer_emulated (source_event))) &&
 | |
|                pointer_window == pointer_info->window_under_pointer &&
 | |
|                gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
 | |
|         {
 | |
|           /* Synthesize a leave notify event
 | |
|            * whenever a touch device is released
 | |
|            */
 | |
|           pointer_info->need_touch_press_enter = TRUE;
 | |
|           _gdk_synthesize_crossing_events (display,
 | |
|                                            pointer_window, NULL,
 | |
|                                            device, source_device,
 | |
|                                            GDK_CROSSING_TOUCH_END,
 | |
|                                            toplevel_x, toplevel_y,
 | |
|                                            state, time_, NULL,
 | |
|                                            serial, FALSE);
 | |
|         }
 | |
|       return TRUE;
 | |
| 
 | |
|     case GDK_TOUCH_BEGIN:
 | |
|     case GDK_TOUCH_END:
 | |
|       convert_toplevel_coords_to_window (event_win,
 | |
|                                          toplevel_x, toplevel_y,
 | |
|                                          &event->button.x, &event->button.y);
 | |
|       gdk_event_get_root_coords (source_event,
 | |
| 				 &event->touch.x_root,
 | |
| 				 &event->touch.y_root);
 | |
|       event->touch.state = state;
 | |
|       event->touch.device = source_event->touch.device;
 | |
|       event->touch.axes = g_memdup (source_event->touch.axes,
 | |
|                                      sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
 | |
|       event->touch.sequence = source_event->touch.sequence;
 | |
|       event->touch.emulating_pointer = source_event->touch.emulating_pointer;
 | |
| 
 | |
|       gdk_event_set_source_device (event, source_device);
 | |
| 
 | |
|       if ((type == GDK_TOUCH_END &&
 | |
|            _gdk_event_get_pointer_emulated (source_event)) &&
 | |
|            pointer_window == pointer_info->window_under_pointer &&
 | |
|            gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
 | |
|         {
 | |
|           /* Synthesize a leave notify event
 | |
|            * whenever a touch device is released
 | |
|            */
 | |
|           pointer_info->need_touch_press_enter = TRUE;
 | |
|           _gdk_synthesize_crossing_events (display,
 | |
|                                            pointer_window, NULL,
 | |
|                                            device, source_device,
 | |
|                                            GDK_CROSSING_TOUCH_END,
 | |
|                                            toplevel_x, toplevel_y,
 | |
|                                            state, time_, NULL,
 | |
|                                            serial, FALSE);
 | |
|         }
 | |
|       return TRUE;
 | |
| 
 | |
|     case GDK_SCROLL:
 | |
|       event->scroll.direction = source_event->scroll.direction;
 | |
|       convert_toplevel_coords_to_window (event_win,
 | |
| 					 toplevel_x, toplevel_y,
 | |
| 					 &event->scroll.x, &event->scroll.y);
 | |
|       event->scroll.x_root = source_event->scroll.x_root;
 | |
|       event->scroll.y_root = source_event->scroll.y_root;
 | |
|       event->scroll.state = state;
 | |
|       event->scroll.device = source_event->scroll.device;
 | |
|       event->scroll.delta_x = source_event->scroll.delta_x;
 | |
|       event->scroll.delta_y = source_event->scroll.delta_y;
 | |
|       gdk_event_set_source_device (event, source_device);
 | |
|       return TRUE;
 | |
| 
 | |
|     default:
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|   return TRUE; /* Always unlink original, we want to obey the emulated event mask */
 | |
| }
 | |
| 
 | |
| #ifdef DEBUG_WINDOW_PRINTING
 | |
| 
 | |
| #ifdef GDK_WINDOWING_X11
 | |
| #include "x11/gdkx.h"
 | |
| #endif
 | |
| 
 | |
| static void
 | |
| gdk_window_print (GdkWindow *window,
 | |
| 		  int indent)
 | |
| {
 | |
|   char *s;
 | |
|   const char *window_types[] = {
 | |
|     "root",
 | |
|     "toplevel",
 | |
|     "child",
 | |
|     "dialog",
 | |
|     "temp",
 | |
|     "foreign",
 | |
|     "offscreen"
 | |
|   };
 | |
| 
 | |
|   g_print ("%*s%p: [%s] %d,%d %dx%d", indent, "", window,
 | |
| 	   window->user_data ? g_type_name_from_instance (window->user_data) : "no widget",
 | |
| 	   window->x, window->y,
 | |
| 	   window->width, window->height
 | |
| 	   );
 | |
| 
 | |
|   if (gdk_window_has_impl (window))
 | |
|     {
 | |
| #ifdef GDK_WINDOWING_X11
 | |
|       g_print (" impl(0x%lx)", gdk_x11_window_get_xid (window));
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|   if (window->window_type != GDK_WINDOW_CHILD)
 | |
|     g_print (" %s", window_types[window->window_type]);
 | |
| 
 | |
|   if (window->input_only)
 | |
|     g_print (" input-only");
 | |
| 
 | |
|   if (window->shaped)
 | |
|     g_print (" shaped");
 | |
| 
 | |
|   if (!gdk_window_is_visible ((GdkWindow *)window))
 | |
|     g_print (" hidden");
 | |
| 
 | |
|   g_print (" abs[%d,%d]",
 | |
| 	   window->abs_x, window->abs_y);
 | |
| 
 | |
|   s = print_region (window->clip_region);
 | |
|   g_print (" clipbox[%s]", s);
 | |
| 
 | |
|   g_print ("\n");
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| gdk_window_print_tree (GdkWindow *window,
 | |
| 		       int indent,
 | |
| 		       gboolean include_input_only)
 | |
| {
 | |
|   GList *l;
 | |
| 
 | |
|   if (window->input_only && !include_input_only)
 | |
|     return;
 | |
| 
 | |
|   gdk_window_print (window, indent);
 | |
| 
 | |
|   for (l = window->children; l != NULL; l = l->next)
 | |
|     gdk_window_print_tree (l->data, indent + 4, include_input_only);
 | |
| }
 | |
| 
 | |
| #endif /* DEBUG_WINDOW_PRINTING */
 | |
| 
 | |
| void
 | |
| _gdk_windowing_got_event (GdkDisplay *display,
 | |
|                           GList      *event_link,
 | |
|                           GdkEvent   *event,
 | |
|                           gulong      serial)
 | |
| {
 | |
|   GdkWindow *event_window;
 | |
|   gdouble x, y;
 | |
|   gboolean unlink_event;
 | |
|   GdkDeviceGrabInfo *button_release_grab;
 | |
|   GdkPointerWindowInfo *pointer_info = NULL;
 | |
|   GdkDevice *device, *source_device;
 | |
|   gboolean is_toplevel;
 | |
| 
 | |
|   if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
 | |
|     display->last_event_time = gdk_event_get_time (event);
 | |
| 
 | |
|   device = gdk_event_get_device (event);
 | |
|   source_device = gdk_event_get_source_device (event);
 | |
| 
 | |
|   if (device)
 | |
|     {
 | |
|       GdkInputMode mode;
 | |
| 
 | |
|       if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
 | |
|         {
 | |
|           pointer_info = _gdk_display_get_pointer_info (display, device);
 | |
| 
 | |
|           if (source_device != pointer_info->last_slave &&
 | |
|               gdk_device_get_device_type (source_device) == GDK_DEVICE_TYPE_SLAVE)
 | |
|             pointer_info->last_slave = source_device;
 | |
|           else
 | |
|             source_device = pointer_info->last_slave;
 | |
|         }
 | |
| 
 | |
|       g_object_get (device, "input-mode", &mode, NULL);
 | |
|       _gdk_display_device_grab_update (display, device, source_device, serial);
 | |
| 
 | |
|       if (mode == GDK_MODE_DISABLED ||
 | |
|           !_gdk_display_check_grab_ownership (display, device, serial))
 | |
|         {
 | |
|           /* Device events are blocked by another
 | |
|            * device grab, or the device is disabled
 | |
|            */
 | |
|           unlink_event = TRUE;
 | |
|           goto out;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   event_window = event->any.window;
 | |
|   if (!event_window)
 | |
|     return;
 | |
| 
 | |
| #ifdef DEBUG_WINDOW_PRINTING
 | |
|   if (event->type == GDK_KEY_PRESS &&
 | |
|       (event->key.keyval == 0xa7 ||
 | |
|        event->key.keyval == 0xbd))
 | |
|     {
 | |
|       gdk_window_print_tree (event_window, 0, event->key.keyval == 0xbd);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|   if (event->type == GDK_VISIBILITY_NOTIFY)
 | |
|     {
 | |
|       event_window->native_visibility = event->visibility.state;
 | |
|       gdk_window_update_visibility_recursively (event_window, event_window);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   if (!(is_button_type (event->type) ||
 | |
|         is_motion_type (event->type)) ||
 | |
|       event_window->window_type == GDK_WINDOW_ROOT)
 | |
|     return;
 | |
| 
 | |
|   is_toplevel = gdk_window_is_toplevel (event_window);
 | |
| 
 | |
|   if ((event->type == GDK_ENTER_NOTIFY ||
 | |
|        event->type == GDK_LEAVE_NOTIFY) &&
 | |
|       (event->crossing.mode == GDK_CROSSING_GRAB ||
 | |
|        event->crossing.mode == GDK_CROSSING_UNGRAB) &&
 | |
|       (_gdk_display_has_device_grab (display, device, serial) ||
 | |
|        event->crossing.detail == GDK_NOTIFY_INFERIOR))
 | |
|     {
 | |
|       /* We synthesize all crossing events due to grabs ourselves,
 | |
|        * so we ignore the native ones caused by our native pointer_grab
 | |
|        * calls. Otherwise we would proxy these crossing event and cause
 | |
|        * multiple copies of crossing events for grabs.
 | |
|        *
 | |
|        * We do want to handle grabs from other clients though, as for
 | |
|        * instance alt-tab in metacity causes grabs like these and
 | |
|        * we want to handle those. Thus the has_pointer_grab check.
 | |
|        *
 | |
|        * Implicit grabs on child windows create some grabbing events
 | |
|        * that are sent before the button press. This means we can't
 | |
|        * detect these with the has_pointer_grab check (as the implicit
 | |
|        * grab is only noticed when we get button press event), so we
 | |
|        * detect these events by checking for INFERIOR enter or leave
 | |
|        * events. These should never be a problem to filter out.
 | |
|        */
 | |
| 
 | |
|       /* We ended up in this window after some (perhaps other clients)
 | |
|        * grab, so update the toplevel_under_window state
 | |
|        */
 | |
|       if (is_toplevel &&
 | |
|           event->type == GDK_ENTER_NOTIFY &&
 | |
|           event->crossing.mode == GDK_CROSSING_UNGRAB)
 | |
|         {
 | |
|           if (pointer_info->toplevel_under_pointer)
 | |
|             g_object_unref (pointer_info->toplevel_under_pointer);
 | |
|           pointer_info->toplevel_under_pointer = g_object_ref (event_window);
 | |
|         }
 | |
| 
 | |
|       unlink_event = TRUE;
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|   /* Track toplevel_under_pointer */
 | |
|   if (is_toplevel)
 | |
|     {
 | |
|       if (event->type == GDK_ENTER_NOTIFY &&
 | |
|           event->crossing.detail != GDK_NOTIFY_INFERIOR)
 | |
|         {
 | |
|           if (pointer_info->toplevel_under_pointer)
 | |
|             g_object_unref (pointer_info->toplevel_under_pointer);
 | |
|           pointer_info->toplevel_under_pointer = g_object_ref (event_window);
 | |
|         }
 | |
|       else if (event->type == GDK_LEAVE_NOTIFY &&
 | |
|                event->crossing.detail != GDK_NOTIFY_INFERIOR &&
 | |
|                pointer_info->toplevel_under_pointer == event_window)
 | |
|         {
 | |
|           if (pointer_info->toplevel_under_pointer)
 | |
|             g_object_unref (pointer_info->toplevel_under_pointer);
 | |
|           pointer_info->toplevel_under_pointer = NULL;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   if (pointer_info &&
 | |
|       (!is_touch_type (event->type) ||
 | |
|        _gdk_event_get_pointer_emulated (event)))
 | |
|     {
 | |
|       guint old_state, old_button;
 | |
| 
 | |
|       /* Store last pointer window and position/state */
 | |
|       old_state = pointer_info->state;
 | |
|       old_button = pointer_info->button;
 | |
| 
 | |
|       gdk_event_get_coords (event, &x, &y);
 | |
|       convert_native_coords_to_toplevel (event_window, x, y,  &x, &y);
 | |
|       pointer_info->toplevel_x = x;
 | |
|       pointer_info->toplevel_y = y;
 | |
|       gdk_event_get_state (event, &pointer_info->state);
 | |
| 
 | |
|       if (event->type == GDK_BUTTON_PRESS ||
 | |
|           event->type == GDK_BUTTON_RELEASE)
 | |
|         pointer_info->button = event->button.button;
 | |
|       else if (event->type == GDK_TOUCH_BEGIN ||
 | |
|                event->type == GDK_TOUCH_END)
 | |
|         pointer_info->button = 1;
 | |
| 
 | |
|       if (device &&
 | |
|           (pointer_info->state != old_state ||
 | |
|            pointer_info->button != old_button))
 | |
|         _gdk_display_enable_motion_hints (display, device);
 | |
|     }
 | |
| 
 | |
|   unlink_event = FALSE;
 | |
|   if (is_motion_type (event->type))
 | |
|     unlink_event = proxy_pointer_event (display, event, serial);
 | |
|   else if (is_button_type (event->type))
 | |
|     unlink_event = proxy_button_event (event, serial);
 | |
| 
 | |
|   if ((event->type == GDK_BUTTON_RELEASE ||
 | |
|        event->type == GDK_TOUCH_END) &&
 | |
|       !event->any.send_event)
 | |
|     {
 | |
|       GdkEventSequence *sequence;
 | |
| 
 | |
|       sequence = gdk_event_get_event_sequence (event);
 | |
|       if (event->type == GDK_TOUCH_END && sequence)
 | |
|         {
 | |
|           _gdk_display_end_touch_grab (display, device, sequence);
 | |
|         }
 | |
| 
 | |
|       if (event->type == GDK_BUTTON_RELEASE ||
 | |
|           _gdk_event_get_pointer_emulated (event))
 | |
|         {
 | |
|           button_release_grab =
 | |
|             _gdk_display_has_device_grab (display, device, serial);
 | |
| 
 | |
|           if (button_release_grab &&
 | |
|               button_release_grab->implicit &&
 | |
|               (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
 | |
|             {
 | |
|               button_release_grab->serial_end = serial;
 | |
|               button_release_grab->implicit_ungrab = FALSE;
 | |
|               _gdk_display_device_grab_update (display, device, source_device, serial);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|  out:
 | |
|   if (unlink_event)
 | |
|     {
 | |
|       _gdk_event_queue_remove_link (display, event_link);
 | |
|       g_list_free_1 (event_link);
 | |
|       gdk_event_free (event);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_create_similar_surface:
 | |
|  * @window: window to make new surface similar to
 | |
|  * @content: the content for the new surface
 | |
|  * @width: width of the new surface
 | |
|  * @height: height of the new surface
 | |
|  *
 | |
|  * Create a new surface that is as compatible as possible with the
 | |
|  * given @window. For example the new surface will have the same
 | |
|  * fallback resolution and font options as @window. Generally, the new
 | |
|  * surface will also use the same backend as @window, unless that is
 | |
|  * not possible for some reason. The type of the returned surface may
 | |
|  * be examined with cairo_surface_get_type().
 | |
|  *
 | |
|  * Initially the surface contents are all 0 (transparent if contents
 | |
|  * have transparency, black otherwise.)
 | |
|  *
 | |
|  * Returns: a pointer to the newly allocated surface. The caller
 | |
|  * owns the surface and should call cairo_surface_destroy() when done
 | |
|  * with it.
 | |
|  *
 | |
|  * This function always returns a valid pointer, but it will return a
 | |
|  * pointer to a "nil" surface if @other is already in an error state
 | |
|  * or any other error occurs.
 | |
|  *
 | |
|  * Since: 2.22
 | |
|  **/
 | |
| cairo_surface_t *
 | |
| gdk_window_create_similar_surface (GdkWindow *     window,
 | |
|                                    cairo_content_t content,
 | |
|                                    int             width,
 | |
|                                    int             height)
 | |
| {
 | |
|   cairo_surface_t *window_surface, *surface;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 | |
|   
 | |
|   window_surface = gdk_window_ref_impl_surface (window);
 | |
| 
 | |
|   switch (_gdk_rendering_mode)
 | |
|   {
 | |
|     case GDK_RENDERING_MODE_RECORDING:
 | |
|       {
 | |
|         cairo_rectangle_t rect = { 0, 0, width, height };
 | |
|         surface = cairo_recording_surface_create (content, &rect);
 | |
|       }
 | |
|       break;
 | |
|     case GDK_RENDERING_MODE_IMAGE:
 | |
|       surface = cairo_image_surface_create (content == CAIRO_CONTENT_COLOR ? CAIRO_FORMAT_RGB24 :
 | |
|                                             content == CAIRO_CONTENT_ALPHA ? CAIRO_FORMAT_A8 : CAIRO_FORMAT_ARGB32,
 | |
|                                             width, height);
 | |
|       break;
 | |
|     case GDK_RENDERING_MODE_SIMILAR:
 | |
|     default:
 | |
|       surface = cairo_surface_create_similar (window_surface,
 | |
|                                               content,
 | |
|                                               width, height);
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   cairo_surface_destroy (window_surface);
 | |
| 
 | |
|   return surface;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_focus:
 | |
|  * @window: a #GdkWindow
 | |
|  * @timestamp: timestamp of the event triggering the window focus
 | |
|  *
 | |
|  * Sets keyboard focus to @window. In most cases, gtk_window_present()
 | |
|  * should be used on a #GtkWindow, rather than calling this function.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_focus (GdkWindow *window,
 | |
|                   guint32    timestamp)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->focus (window, timestamp);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_type_hint:
 | |
|  * @window: A toplevel #GdkWindow
 | |
|  * @hint: A hint of the function this window will have
 | |
|  *
 | |
|  * The application can use this call to provide a hint to the window
 | |
|  * manager about the functionality of a window. The window manager
 | |
|  * can use this information when determining the decoration and behaviour
 | |
|  * of the window.
 | |
|  *
 | |
|  * The hint must be set before the window is mapped.
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_type_hint (GdkWindow        *window,
 | |
| 			  GdkWindowTypeHint hint)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_type_hint (window, hint);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_type_hint:
 | |
|  * @window: A toplevel #GdkWindow
 | |
|  *
 | |
|  * This function returns the type hint set for a window.
 | |
|  *
 | |
|  * Return value: The type hint set for @window
 | |
|  *
 | |
|  * Since: 2.10
 | |
|  **/
 | |
| GdkWindowTypeHint
 | |
| gdk_window_get_type_hint (GdkWindow *window)
 | |
| {
 | |
|   return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_type_hint (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_modal_hint:
 | |
|  * @window: A toplevel #GdkWindow
 | |
|  * @modal: %TRUE if the window is modal, %FALSE otherwise.
 | |
|  *
 | |
|  * The application can use this hint to tell the window manager
 | |
|  * that a certain window has modal behaviour. The window manager
 | |
|  * can use this information to handle modal windows in a special
 | |
|  * way.
 | |
|  *
 | |
|  * You should only use this on windows for which you have
 | |
|  * previously called gdk_window_set_transient_for()
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_modal_hint (GdkWindow *window,
 | |
| 			   gboolean   modal)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_modal_hint (window, modal);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_skip_taskbar_hint:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @skips_taskbar: %TRUE to skip the taskbar
 | |
|  *
 | |
|  * Toggles whether a window should appear in a task list or window
 | |
|  * list. If a window's semantic type as specified with
 | |
|  * gdk_window_set_type_hint() already fully describes the window, this
 | |
|  * function should <emphasis>not</emphasis> be called in addition,
 | |
|  * instead you should allow the window to be treated according to
 | |
|  * standard policy for its semantic type.
 | |
|  *
 | |
|  * Since: 2.2
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_skip_taskbar_hint (GdkWindow *window,
 | |
|                                   gboolean   skips_taskbar)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_skip_taskbar_hint (window, skips_taskbar);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_skip_pager_hint:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @skips_pager: %TRUE to skip the pager
 | |
|  *
 | |
|  * Toggles whether a window should appear in a pager (workspace
 | |
|  * switcher, or other desktop utility program that displays a small
 | |
|  * thumbnail representation of the windows on the desktop). If a
 | |
|  * window's semantic type as specified with gdk_window_set_type_hint()
 | |
|  * already fully describes the window, this function should
 | |
|  * <emphasis>not</emphasis> be called in addition, instead you should
 | |
|  * allow the window to be treated according to standard policy for
 | |
|  * its semantic type.
 | |
|  *
 | |
|  * Since: 2.2
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_skip_pager_hint (GdkWindow *window,
 | |
|                                 gboolean   skips_pager)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_skip_pager_hint (window, skips_pager);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_urgency_hint:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @urgent: %TRUE if the window is urgent
 | |
|  *
 | |
|  * Toggles whether a window needs the user's
 | |
|  * urgent attention.
 | |
|  *
 | |
|  * Since: 2.8
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_urgency_hint (GdkWindow *window,
 | |
| 			     gboolean   urgent)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_urgency_hint (window, urgent);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_geometry_hints:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @geometry: geometry hints
 | |
|  * @geom_mask: bitmask indicating fields of @geometry to pay attention to
 | |
|  *
 | |
|  * Sets the geometry hints for @window. Hints flagged in @geom_mask
 | |
|  * are set, hints not flagged in @geom_mask are unset.
 | |
|  * To unset all hints, use a @geom_mask of 0 and a @geometry of %NULL.
 | |
|  *
 | |
|  * This function provides hints to the windowing system about
 | |
|  * acceptable sizes for a toplevel window. The purpose of
 | |
|  * this is to constrain user resizing, but the windowing system
 | |
|  * will typically  (but is not required to) also constrain the
 | |
|  * current size of the window to the provided values and
 | |
|  * constrain programatic resizing via gdk_window_resize() or
 | |
|  * gdk_window_move_resize().
 | |
|  *
 | |
|  * Note that on X11, this effect has no effect on windows
 | |
|  * of type %GDK_WINDOW_TEMP or windows where override redirect
 | |
|  * has been turned on via gdk_window_set_override_redirect()
 | |
|  * since these windows are not resizable by the user.
 | |
|  *
 | |
|  * Since you can't count on the windowing system doing the
 | |
|  * constraints for programmatic resizes, you should generally
 | |
|  * call gdk_window_constrain_size() yourself to determine
 | |
|  * appropriate sizes.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_geometry_hints (GdkWindow         *window,
 | |
| 			       const GdkGeometry *geometry,
 | |
| 			       GdkWindowHints     geom_mask)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_geometry_hints (window, geometry, geom_mask);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_title:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @title: title of @window
 | |
|  *
 | |
|  * Sets the title of a toplevel window, to be displayed in the titlebar.
 | |
|  * If you haven't explicitly set the icon name for the window
 | |
|  * (using gdk_window_set_icon_name()), the icon name will be set to
 | |
|  * @title as well. @title must be in UTF-8 encoding (as with all
 | |
|  * user-readable strings in GDK/GTK+). @title may not be %NULL.
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_title (GdkWindow   *window,
 | |
| 		      const gchar *title)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_title (window, title);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_role:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @role: a string indicating its role
 | |
|  *
 | |
|  * When using GTK+, typically you should use gtk_window_set_role() instead
 | |
|  * of this low-level function.
 | |
|  *
 | |
|  * The window manager and session manager use a window's role to
 | |
|  * distinguish it from other kinds of window in the same application.
 | |
|  * When an application is restarted after being saved in a previous
 | |
|  * session, all windows with the same title and role are treated as
 | |
|  * interchangeable.  So if you have two windows with the same title
 | |
|  * that should be distinguished for session management purposes, you
 | |
|  * should set the role on those windows. It doesn't matter what string
 | |
|  * you use for the role, as long as you have a different role for each
 | |
|  * non-interchangeable kind of window.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_role (GdkWindow   *window,
 | |
| 		     const gchar *role)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_role (window, role);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_startup_id:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @startup_id: a string with startup-notification identifier
 | |
|  *
 | |
|  * When using GTK+, typically you should use gtk_window_set_startup_id()
 | |
|  * instead of this low-level function.
 | |
|  *
 | |
|  * Since: 2.12
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_startup_id (GdkWindow   *window,
 | |
| 			   const gchar *startup_id)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_startup_id (window, startup_id);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_transient_for:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @parent: another toplevel #GdkWindow
 | |
|  *
 | |
|  * Indicates to the window manager that @window is a transient dialog
 | |
|  * associated with the application window @parent. This allows the
 | |
|  * window manager to do things like center @window on @parent and
 | |
|  * keep @window above @parent.
 | |
|  *
 | |
|  * See gtk_window_set_transient_for() if you're using #GtkWindow or
 | |
|  * #GtkDialog.
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_transient_for (GdkWindow *window,
 | |
| 			      GdkWindow *parent)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_transient_for (window, parent);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_root_origin:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @x: (out): return location for X position of window frame
 | |
|  * @y: (out): return location for Y position of window frame
 | |
|  *
 | |
|  * Obtains the top-left corner of the window manager frame in root
 | |
|  * window coordinates.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_get_root_origin (GdkWindow *window,
 | |
| 			    gint      *x,
 | |
| 			    gint      *y)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_root_origin (window, x, y);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_frame_extents:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @rect: (out): rectangle to fill with bounding box of the window frame
 | |
|  *
 | |
|  * Obtains the bounding box of the window, including window manager
 | |
|  * titlebar/borders if any. The frame position is given in root window
 | |
|  * coordinates. To get the position of the window itself (rather than
 | |
|  * the frame) in root window coordinates, use gdk_window_get_origin().
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_get_frame_extents (GdkWindow    *window,
 | |
|                               GdkRectangle *rect)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_frame_extents (window, rect);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_override_redirect:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @override_redirect: %TRUE if window should be override redirect
 | |
|  *
 | |
|  * An override redirect window is not under the control of the window manager.
 | |
|  * This means it won't have a titlebar, won't be minimizable, etc. - it will
 | |
|  * be entirely under the control of the application. The window manager
 | |
|  * can't see the override redirect window at all.
 | |
|  *
 | |
|  * Override redirect should only be used for short-lived temporary
 | |
|  * windows, such as popup menus. #GtkMenu uses an override redirect
 | |
|  * window in its implementation, for example.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_override_redirect (GdkWindow *window,
 | |
| 				  gboolean override_redirect)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_override_redirect (window, override_redirect);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_accept_focus:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @accept_focus: %TRUE if the window should receive input focus
 | |
|  *
 | |
|  * Setting @accept_focus to %FALSE hints the desktop environment that the
 | |
|  * window doesn't want to receive input focus.
 | |
|  *
 | |
|  * On X, it is the responsibility of the window manager to interpret this
 | |
|  * hint. ICCCM-compliant window manager usually respect it.
 | |
|  *
 | |
|  * Since: 2.4
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_accept_focus (GdkWindow *window,
 | |
| 			     gboolean accept_focus)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_accept_focus (window, accept_focus);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_focus_on_map:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @focus_on_map: %TRUE if the window should receive input focus when mapped
 | |
|  *
 | |
|  * Setting @focus_on_map to %FALSE hints the desktop environment that the
 | |
|  * window doesn't want to receive input focus when it is mapped.
 | |
|  * focus_on_map should be turned off for windows that aren't triggered
 | |
|  * interactively (such as popups from network activity).
 | |
|  *
 | |
|  * On X, it is the responsibility of the window manager to interpret
 | |
|  * this hint. Window managers following the freedesktop.org window
 | |
|  * manager extension specification should respect it.
 | |
|  *
 | |
|  * Since: 2.6
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_focus_on_map (GdkWindow *window,
 | |
| 			     gboolean focus_on_map)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_focus_on_map (window, focus_on_map);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_icon_list:
 | |
|  * @window: The #GdkWindow toplevel window to set the icon of.
 | |
|  * @pixbufs: (transfer none) (element-type GdkPixbuf):
 | |
|  *     A list of pixbufs, of different sizes.
 | |
|  *
 | |
|  * Sets a list of icons for the window. One of these will be used
 | |
|  * to represent the window when it has been iconified. The icon is
 | |
|  * usually shown in an icon box or some sort of task bar. Which icon
 | |
|  * size is shown depends on the window manager. The window manager
 | |
|  * can scale the icon  but setting several size icons can give better
 | |
|  * image quality since the window manager may only need to scale the
 | |
|  * icon by a small amount or not at all.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_icon_list (GdkWindow *window,
 | |
| 			  GList     *pixbufs)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_icon_list (window, pixbufs);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_icon_name:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @name: (allow-none): name of window while iconified (minimized)
 | |
|  *
 | |
|  * Windows may have a name used while minimized, distinct from the
 | |
|  * name they display in their titlebar. Most of the time this is a bad
 | |
|  * idea from a user interface standpoint. But you can set such a name
 | |
|  * with this function, if you like.
 | |
|  *
 | |
|  * After calling this with a non-%NULL @name, calls to gdk_window_set_title()
 | |
|  * will not update the icon title.
 | |
|  *
 | |
|  * Using %NULL for @name unsets the icon title; further calls to
 | |
|  * gdk_window_set_title() will again update the icon title as well.
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_icon_name (GdkWindow   *window,
 | |
| 			  const gchar *name)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_icon_name (window, name);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_iconify:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Asks to iconify (minimize) @window. The window manager may choose
 | |
|  * to ignore the request, but normally will honor it. Using
 | |
|  * gtk_window_iconify() is preferred, if you have a #GtkWindow widget.
 | |
|  *
 | |
|  * This function only makes sense when @window is a toplevel window.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_iconify (GdkWindow *window)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->iconify (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_deiconify:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Attempt to deiconify (unminimize) @window. On X11 the window manager may
 | |
|  * choose to ignore the request to deiconify. When using GTK+,
 | |
|  * use gtk_window_deiconify() instead of the #GdkWindow variant. Or better yet,
 | |
|  * you probably want to use gtk_window_present(), which raises the window, focuses it,
 | |
|  * unminimizes it, and puts it on the current desktop.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_deiconify (GdkWindow *window)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->deiconify (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_stick:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * "Pins" a window such that it's on all workspaces and does not scroll
 | |
|  * with viewports, for window managers that have scrollable viewports.
 | |
|  * (When using #GtkWindow, gtk_window_stick() may be more useful.)
 | |
|  *
 | |
|  * On the X11 platform, this function depends on window manager
 | |
|  * support, so may have no effect with many window managers. However,
 | |
|  * GDK will do the best it can to convince the window manager to stick
 | |
|  * the window. For window managers that don't support this operation,
 | |
|  * there's nothing you can do to force it to happen.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_stick (GdkWindow *window)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->stick (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_unstick:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Reverse operation for gdk_window_stick(); see gdk_window_stick(),
 | |
|  * and gtk_window_unstick().
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_unstick (GdkWindow *window)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->unstick (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_maximize:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Maximizes the window. If the window was already maximized, then
 | |
|  * this function does nothing.
 | |
|  *
 | |
|  * On X11, asks the window manager to maximize @window, if the window
 | |
|  * manager supports this operation. Not all window managers support
 | |
|  * this, and some deliberately ignore it or don't have a concept of
 | |
|  * "maximized"; so you can't rely on the maximization actually
 | |
|  * happening. But it will happen with most standard window managers,
 | |
|  * and GDK makes a best effort to get it to happen.
 | |
|  *
 | |
|  * On Windows, reliably maximizes the window.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_maximize (GdkWindow *window)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->maximize (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_unmaximize:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Unmaximizes the window. If the window wasn't maximized, then this
 | |
|  * function does nothing.
 | |
|  *
 | |
|  * On X11, asks the window manager to unmaximize @window, if the
 | |
|  * window manager supports this operation. Not all window managers
 | |
|  * support this, and some deliberately ignore it or don't have a
 | |
|  * concept of "maximized"; so you can't rely on the unmaximization
 | |
|  * actually happening. But it will happen with most standard window
 | |
|  * managers, and GDK makes a best effort to get it to happen.
 | |
|  *
 | |
|  * On Windows, reliably unmaximizes the window.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_unmaximize (GdkWindow *window)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->unmaximize (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_fullscreen:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Moves the window into fullscreen mode. This means the
 | |
|  * window covers the entire screen and is above any panels
 | |
|  * or task bars.
 | |
|  *
 | |
|  * If the window was already fullscreen, then this function does nothing.
 | |
|  *
 | |
|  * On X11, asks the window manager to put @window in a fullscreen
 | |
|  * state, if the window manager supports this operation. Not all
 | |
|  * window managers support this, and some deliberately ignore it or
 | |
|  * don't have a concept of "fullscreen"; so you can't rely on the
 | |
|  * fullscreenification actually happening. But it will happen with
 | |
|  * most standard window managers, and GDK makes a best effort to get
 | |
|  * it to happen.
 | |
|  *
 | |
|  * Since: 2.2
 | |
|  **/
 | |
| void
 | |
| gdk_window_fullscreen (GdkWindow *window)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->fullscreen (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_fullscreen_mode:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @mode: fullscreen mode
 | |
|  *
 | |
|  * Specifies whether the @window should span over all monitors (in a multi-head
 | |
|  * setup) or only the current monitor when in fullscreen mode.
 | |
|  *
 | |
|  * The @mode argument is from the #GdkFullscreenMode enumeration.
 | |
|  * If #GDK_FULLSCREEN_ON_ALL_MONITORS is specified, the fullscreen @window will
 | |
|  * span over all monitors from the #GdkScreen.
 | |
|  *
 | |
|  * On X11, searches through the list of monitors from the #GdkScreen the ones
 | |
|  * which delimit the 4 edges of the entire #GdkScreen and will ask the window
 | |
|  * manager to span the @window over these monitors.
 | |
|  *
 | |
|  * If the XINERAMA extension is not available or not usable, this function
 | |
|  * has no effect.
 | |
|  *
 | |
|  * Not all window managers support this, so you can't rely on the fullscreen
 | |
|  * window to span over the multiple monitors when #GDK_FULLSCREEN_ON_ALL_MONITORS
 | |
|  * is specified.
 | |
|  *
 | |
|  * Since: 3.8
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_fullscreen_mode (GdkWindow        *window,
 | |
|                                 GdkFullscreenMode mode)
 | |
| {
 | |
|   GdkWindowImplClass *impl_class;
 | |
| 
 | |
|   g_return_if_fail (GDK_IS_WINDOW (window));
 | |
| 
 | |
|   if (window->fullscreen_mode != mode)
 | |
|     {
 | |
|       window->fullscreen_mode = mode;
 | |
| 
 | |
|       impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
 | |
|       if (impl_class->apply_fullscreen_mode != NULL)
 | |
|         impl_class->apply_fullscreen_mode (window);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_fullscreen_mode:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Obtains the #GdkFullscreenMode of the @window.
 | |
|  *
 | |
|  * Returns: The #GdkFullscreenMode applied to the window when fullscreen.
 | |
|  *
 | |
|  * Since: 3.8
 | |
|  **/
 | |
| GdkFullscreenMode
 | |
| gdk_window_get_fullscreen_mode (GdkWindow *window)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), GDK_FULLSCREEN_ON_CURRENT_MONITOR);
 | |
| 
 | |
|   return window->fullscreen_mode;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_unfullscreen:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Moves the window out of fullscreen mode. If the window was not
 | |
|  * fullscreen, does nothing.
 | |
|  *
 | |
|  * On X11, asks the window manager to move @window out of the fullscreen
 | |
|  * state, if the window manager supports this operation. Not all
 | |
|  * window managers support this, and some deliberately ignore it or
 | |
|  * don't have a concept of "fullscreen"; so you can't rely on the
 | |
|  * unfullscreenification actually happening. But it will happen with
 | |
|  * most standard window managers, and GDK makes a best effort to get
 | |
|  * it to happen.
 | |
|  *
 | |
|  * Since: 2.2
 | |
|  **/
 | |
| void
 | |
| gdk_window_unfullscreen (GdkWindow *window)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->unfullscreen (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_keep_above:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @setting: whether to keep @window above other windows
 | |
|  *
 | |
|  * Set if @window must be kept above other windows. If the
 | |
|  * window was already above, then this function does nothing.
 | |
|  *
 | |
|  * On X11, asks the window manager to keep @window above, if the window
 | |
|  * manager supports this operation. Not all window managers support
 | |
|  * this, and some deliberately ignore it or don't have a concept of
 | |
|  * "keep above"; so you can't rely on the window being kept above.
 | |
|  * But it will happen with most standard window managers,
 | |
|  * and GDK makes a best effort to get it to happen.
 | |
|  *
 | |
|  * Since: 2.4
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_keep_above (GdkWindow *window,
 | |
|                            gboolean   setting)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_keep_above (window, setting);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_keep_below:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @setting: whether to keep @window below other windows
 | |
|  *
 | |
|  * Set if @window must be kept below other windows. If the
 | |
|  * window was already below, then this function does nothing.
 | |
|  *
 | |
|  * On X11, asks the window manager to keep @window below, if the window
 | |
|  * manager supports this operation. Not all window managers support
 | |
|  * this, and some deliberately ignore it or don't have a concept of
 | |
|  * "keep below"; so you can't rely on the window being kept below.
 | |
|  * But it will happen with most standard window managers,
 | |
|  * and GDK makes a best effort to get it to happen.
 | |
|  *
 | |
|  * Since: 2.4
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_keep_below (GdkWindow *window, gboolean setting)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_keep_below (window, setting);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_group:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Returns the group leader window for @window. See gdk_window_set_group().
 | |
|  *
 | |
|  * Return value: (transfer none): the group leader window for @window
 | |
|  *
 | |
|  * Since: 2.4
 | |
|  **/
 | |
| GdkWindow *
 | |
| gdk_window_get_group (GdkWindow *window)
 | |
| {
 | |
|   return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_group (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_group:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @leader: (allow-none): group leader window, or %NULL to restore the default group leader window
 | |
|  *
 | |
|  * Sets the group leader window for @window. By default,
 | |
|  * GDK sets the group leader for all toplevel windows
 | |
|  * to a global window implicitly created by GDK. With this function
 | |
|  * you can override this default.
 | |
|  *
 | |
|  * The group leader window allows the window manager to distinguish
 | |
|  * all windows that belong to a single application. It may for example
 | |
|  * allow users to minimize/unminimize all windows belonging to an
 | |
|  * application at once. You should only set a non-default group window
 | |
|  * if your application pretends to be multiple applications.
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_group (GdkWindow *window,
 | |
| 		      GdkWindow *leader)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_group (window, leader);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_decorations:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @decorations: decoration hint mask
 | |
|  *
 | |
|  * "Decorations" are the features the window manager adds to a toplevel #GdkWindow.
 | |
|  * This function sets the traditional Motif window manager hints that tell the
 | |
|  * window manager which decorations you would like your window to have.
 | |
|  * Usually you should use gtk_window_set_decorated() on a #GtkWindow instead of
 | |
|  * using the GDK function directly.
 | |
|  *
 | |
|  * The @decorations argument is the logical OR of the fields in
 | |
|  * the #GdkWMDecoration enumeration. If #GDK_DECOR_ALL is included in the
 | |
|  * mask, the other bits indicate which decorations should be turned off.
 | |
|  * If #GDK_DECOR_ALL is not included, then the other bits indicate
 | |
|  * which decorations should be turned on.
 | |
|  *
 | |
|  * Most window managers honor a decorations hint of 0 to disable all decorations,
 | |
|  * but very few honor all possible combinations of bits.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_decorations (GdkWindow      *window,
 | |
| 			    GdkWMDecoration decorations)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_decorations (window, decorations);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_decorations:
 | |
|  * @window: The toplevel #GdkWindow to get the decorations from
 | |
|  * @decorations: (out): The window decorations will be written here
 | |
|  *
 | |
|  * Returns the decorations set on the GdkWindow with
 | |
|  * gdk_window_set_decorations().
 | |
|  *
 | |
|  * Returns: %TRUE if the window has decorations set, %FALSE otherwise.
 | |
|  **/
 | |
| gboolean
 | |
| gdk_window_get_decorations(GdkWindow       *window,
 | |
| 			   GdkWMDecoration *decorations)
 | |
| {
 | |
|   return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_decorations (window, decorations);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_functions:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @functions: bitmask of operations to allow on @window
 | |
|  *
 | |
|  * Sets hints about the window management functions to make available
 | |
|  * via buttons on the window frame.
 | |
|  *
 | |
|  * On the X backend, this function sets the traditional Motif window
 | |
|  * manager hint for this purpose. However, few window managers do
 | |
|  * anything reliable or interesting with this hint. Many ignore it
 | |
|  * entirely.
 | |
|  *
 | |
|  * The @functions argument is the logical OR of values from the
 | |
|  * #GdkWMFunction enumeration. If the bitmask includes #GDK_FUNC_ALL,
 | |
|  * then the other bits indicate which functions to disable; if
 | |
|  * it doesn't include #GDK_FUNC_ALL, it indicates which functions to
 | |
|  * enable.
 | |
|  *
 | |
|  **/
 | |
| void
 | |
| gdk_window_set_functions (GdkWindow    *window,
 | |
| 			  GdkWMFunction functions)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_functions (window, functions);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_begin_resize_drag_for_device:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @edge: the edge or corner from which the drag is started
 | |
|  * @device: the device used for the operation
 | |
|  * @button: the button being used to drag
 | |
|  * @root_x: root window X coordinate of mouse click that began the drag
 | |
|  * @root_y: root window Y coordinate of mouse click that began the drag
 | |
|  * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
 | |
|  *
 | |
|  * Begins a window resize operation (for a toplevel window).
 | |
|  * You might use this function to implement a "window resize grip," for
 | |
|  * example; in fact #GtkStatusbar uses it. The function works best
 | |
|  * with window managers that support the <ulink url="http://www.freedesktop.org/Standards/wm-spec">Extended Window Manager Hints</ulink>, but has a
 | |
|  * fallback implementation for other window managers.
 | |
|  *
 | |
|  * Since: 3.4
 | |
|  */
 | |
| void
 | |
| gdk_window_begin_resize_drag_for_device (GdkWindow     *window,
 | |
|                                          GdkWindowEdge  edge,
 | |
|                                          GdkDevice     *device,
 | |
|                                          gint           button,
 | |
|                                          gint           root_x,
 | |
|                                          gint           root_y,
 | |
|                                          guint32        timestamp)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->begin_resize_drag (window, edge, device, button, root_x, root_y, timestamp);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_begin_resize_drag:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @edge: the edge or corner from which the drag is started
 | |
|  * @button: the button being used to drag
 | |
|  * @root_x: root window X coordinate of mouse click that began the drag
 | |
|  * @root_y: root window Y coordinate of mouse click that began the drag
 | |
|  * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
 | |
|  *
 | |
|  * Begins a window resize operation (for a toplevel window).
 | |
|  *
 | |
|  * This function assumes that the drag is controlled by the
 | |
|  * client pointer device, use gdk_window_begin_resize_drag_for_device()
 | |
|  * to begin a drag with a different device.
 | |
|  */
 | |
| void
 | |
| gdk_window_begin_resize_drag (GdkWindow     *window,
 | |
|                               GdkWindowEdge  edge,
 | |
|                               gint           button,
 | |
|                               gint           root_x,
 | |
|                               gint           root_y,
 | |
|                               guint32        timestamp)
 | |
| {
 | |
|   GdkDeviceManager *device_manager;
 | |
|   GdkDevice *device;
 | |
| 
 | |
|   device_manager = gdk_display_get_device_manager (gdk_window_get_display (window));
 | |
|   device = gdk_device_manager_get_client_pointer (device_manager);
 | |
|   gdk_window_begin_resize_drag_for_device (window, edge,
 | |
|                                            device, button, root_x, root_y, timestamp);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_begin_move_drag_for_device:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @device: the device used for the operation
 | |
|  * @button: the button being used to drag
 | |
|  * @root_x: root window X coordinate of mouse click that began the drag
 | |
|  * @root_y: root window Y coordinate of mouse click that began the drag
 | |
|  * @timestamp: timestamp of mouse click that began the drag
 | |
|  *
 | |
|  * Begins a window move operation (for a toplevel window).
 | |
|  * You might use this function to implement a "window move grip," for
 | |
|  * example. The function works best with window managers that support
 | |
|  * the <ulink url="http://www.freedesktop.org/Standards/wm-spec">Extended
 | |
|  * Window Manager Hints</ulink>, but has a fallback implementation for
 | |
|  * other window managers.
 | |
|  *
 | |
|  * Since: 3.4
 | |
|  */
 | |
| void
 | |
| gdk_window_begin_move_drag_for_device (GdkWindow *window,
 | |
|                                        GdkDevice *device,
 | |
|                                        gint       button,
 | |
|                                        gint       root_x,
 | |
|                                        gint       root_y,
 | |
|                                        guint32    timestamp)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->begin_move_drag (window,
 | |
|                                                              device, button, root_x, root_y, timestamp);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_begin_move_drag:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * @button: the button being used to drag
 | |
|  * @root_x: root window X coordinate of mouse click that began the drag
 | |
|  * @root_y: root window Y coordinate of mouse click that began the drag
 | |
|  * @timestamp: timestamp of mouse click that began the drag
 | |
|  *
 | |
|  * Begins a window move operation (for a toplevel window).
 | |
|  *
 | |
|  * This function assumes that the drag is controlled by the
 | |
|  * client pointer device, use gdk_window_begin_move_drag_for_device()
 | |
|  * to begin a drag with a different device.
 | |
|  */
 | |
| void
 | |
| gdk_window_begin_move_drag (GdkWindow *window,
 | |
|                             gint       button,
 | |
|                             gint       root_x,
 | |
|                             gint       root_y,
 | |
|                             guint32    timestamp)
 | |
| {
 | |
|   GdkDeviceManager *device_manager;
 | |
|   GdkDevice *device;
 | |
| 
 | |
|   device_manager = gdk_display_get_device_manager (gdk_window_get_display (window));
 | |
|   device = gdk_device_manager_get_client_pointer (device_manager);
 | |
|   gdk_window_begin_move_drag_for_device (window, device, button, root_x, root_y, timestamp);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_enable_synchronized_configure:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  *
 | |
|  * Indicates that the application will cooperate with the window
 | |
|  * system in synchronizing the window repaint with the window
 | |
|  * manager during resizing operations. After an application calls
 | |
|  * this function, it must call gdk_window_configure_finished() every
 | |
|  * time it has finished all processing associated with a set of
 | |
|  * Configure events. Toplevel GTK+ windows automatically use this
 | |
|  * protocol.
 | |
|  *
 | |
|  * On X, calling this function makes @window participate in the
 | |
|  * _NET_WM_SYNC_REQUEST window manager protocol.
 | |
|  *
 | |
|  * Since: 2.6
 | |
|  **/
 | |
| void
 | |
| gdk_window_enable_synchronized_configure (GdkWindow *window)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->enable_synchronized_configure (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_configure_finished:
 | |
|  * @window: a toplevel #GdkWindow
 | |
|  * 
 | |
|  * Signal to the window system that the application has finished
 | |
|  * handling Configure events it has received. Window Managers can
 | |
|  * use this to better synchronize the frame repaint with the
 | |
|  * application. GTK+ applications will automatically call this
 | |
|  * function when appropriate.
 | |
|  *
 | |
|  * This function can only be called if gdk_window_enable_synchronized_configure()
 | |
|  * was called previously.
 | |
|  *
 | |
|  * Since: 2.6
 | |
|  **/
 | |
| void
 | |
| gdk_window_configure_finished (GdkWindow *window)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->configure_finished (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_set_opacity:
 | |
|  * @window: a top-level #GdkWindow
 | |
|  * @opacity: opacity
 | |
|  *
 | |
|  * Request the windowing system to make @window partially transparent,
 | |
|  * with opacity 0 being fully transparent and 1 fully opaque. (Values
 | |
|  * of the opacity parameter are clamped to the [0,1] range.) 
 | |
|  *
 | |
|  * On X11, this works only on X screens with a compositing manager 
 | |
|  * running.
 | |
|  *
 | |
|  * For setting up per-pixel alpha, see gdk_screen_get_rgba_visual().
 | |
|  * For making non-toplevel windows translucent, see 
 | |
|  * gdk_window_set_composited().
 | |
|  *
 | |
|  * Since: 2.12
 | |
|  */
 | |
| void
 | |
| gdk_window_set_opacity (GdkWindow *window,
 | |
| 			gdouble    opacity)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_opacity (window, opacity);
 | |
| }
 | |
| 
 | |
| /* This function is called when the XWindow is really gone.
 | |
|  */
 | |
| void
 | |
| gdk_window_destroy_notify (GdkWindow *window)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->destroy_notify (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_register_dnd:
 | |
|  * @window: a #GdkWindow.
 | |
|  *
 | |
|  * Registers a window as a potential drop destination.
 | |
|  */
 | |
| void
 | |
| gdk_window_register_dnd (GdkWindow *window)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->register_dnd (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_window_get_drag_protocol:
 | |
|  * @window: the destination window
 | |
|  * @target: (out) (allow-none) (transfer full): location of the window
 | |
|  *    where the drop should happen. This may be @window or a proxy window,
 | |
|  *    or %NULL if @window does not support Drag and Drop.
 | |
|  *
 | |
|  * Finds out the DND protocol supported by a window.
 | |
|  *
 | |
|  * Returns: the supported DND protocol.
 | |
|  *
 | |
|  * Since: 3.0
 | |
|  */
 | |
| GdkDragProtocol
 | |
| gdk_window_get_drag_protocol (GdkWindow  *window,
 | |
|                               GdkWindow **target)
 | |
| {
 | |
|   g_return_val_if_fail (GDK_IS_WINDOW (window), GDK_DRAG_PROTO_NONE);
 | |
| 
 | |
|   return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_drag_protocol (window, target);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_drag_begin:
 | |
|  * @window: the source window for this drag.
 | |
|  * @targets: (transfer none) (element-type GdkAtom): the offered targets,
 | |
|  *     as list of #GdkAtoms
 | |
|  *
 | |
|  * Starts a drag and creates a new drag context for it.
 | |
|  * This function assumes that the drag is controlled by the
 | |
|  * client pointer device, use gdk_drag_begin_for_device() to
 | |
|  * begin a drag with a different device.
 | |
|  *
 | |
|  * This function is called by the drag source.
 | |
|  *
 | |
|  * Return value: (transfer full): a newly created #GdkDragContext
 | |
|  */
 | |
| GdkDragContext *
 | |
| gdk_drag_begin (GdkWindow     *window,
 | |
|                 GList         *targets)
 | |
| {
 | |
|   GdkDeviceManager *device_manager;
 | |
|   GdkDevice *device;
 | |
| 
 | |
|   device_manager = gdk_display_get_device_manager (gdk_window_get_display (window));
 | |
|   device = gdk_device_manager_get_client_pointer (device_manager);
 | |
| 
 | |
|   return gdk_drag_begin_for_device (window, device, targets);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_drag_begin_for_device:
 | |
|  * @window: the source window for this drag
 | |
|  * @device: the device that controls this drag
 | |
|  * @targets: (transfer none) (element-type GdkAtom): the offered targets,
 | |
|  *     as list of #GdkAtoms
 | |
|  *
 | |
|  * Starts a drag and creates a new drag context for it.
 | |
|  *
 | |
|  * This function is called by the drag source.
 | |
|  *
 | |
|  * Return value: (transfer full): a newly created #GdkDragContext
 | |
|  */
 | |
| GdkDragContext *
 | |
| gdk_drag_begin_for_device (GdkWindow     *window,
 | |
|                            GdkDevice     *device,
 | |
|                            GList         *targets)
 | |
| {
 | |
|   return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->drag_begin (window, device, targets);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_test_render_sync:
 | |
|  * @window: a mapped #GdkWindow
 | |
|  *
 | |
|  * Retrieves a pixel from @window to force the windowing
 | |
|  * system to carry out any pending rendering commands.
 | |
|  *
 | |
|  * This function is intended to be used to synchronize with rendering
 | |
|  * pipelines, to benchmark windowing system rendering operations.
 | |
|  *
 | |
|  * Since: 2.14
 | |
|  **/
 | |
| void
 | |
| gdk_test_render_sync (GdkWindow *window)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->sync_rendering (window);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_test_simulate_key:
 | |
|  * @window: a #GdkWindow to simulate a key event for
 | |
|  * @x:      x coordinate within @window for the key event
 | |
|  * @y:      y coordinate within @window for the key event
 | |
|  * @keyval: A GDK keyboard value
 | |
|  * @modifiers: Keyboard modifiers the event is setup with
 | |
|  * @key_pressrelease: either %GDK_KEY_PRESS or %GDK_KEY_RELEASE
 | |
|  *
 | |
|  * This function is intended to be used in GTK+ test programs.
 | |
|  * If (@x,@y) are > (-1,-1), it will warp the mouse pointer to
 | |
|  * the given (@x,@y) coordinates within @window and simulate a
 | |
|  * key press or release event.
 | |
|  *
 | |
|  * When the mouse pointer is warped to the target location, use
 | |
|  * of this function outside of test programs that run in their
 | |
|  * own virtual windowing system (e.g. Xvfb) is not recommended.
 | |
|  * If (@x,@y) are passed as (-1,-1), the mouse pointer will not
 | |
|  * be warped and @window origin will be used as mouse pointer
 | |
|  * location for the event.
 | |
|  *
 | |
|  * Also, gdk_test_simulate_key() is a fairly low level function,
 | |
|  * for most testing purposes, gtk_test_widget_send_key() is the
 | |
|  * right function to call which will generate a key press event
 | |
|  * followed by its accompanying key release event.
 | |
|  *
 | |
|  * Returns: whether all actions necessary for a key event simulation
 | |
|  *     were carried out successfully
 | |
|  *
 | |
|  * Since: 2.14
 | |
|  */
 | |
| gboolean
 | |
| gdk_test_simulate_key (GdkWindow      *window,
 | |
|                        gint            x,
 | |
|                        gint            y,
 | |
|                        guint           keyval,
 | |
|                        GdkModifierType modifiers,
 | |
|                        GdkEventType    key_pressrelease)
 | |
| {
 | |
|   return GDK_WINDOW_IMPL_GET_CLASS (window->impl)
 | |
|     ->simulate_key (window, x, y, keyval, modifiers, key_pressrelease);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_test_simulate_button:
 | |
|  * @window: a #GdkWindow to simulate a button event for
 | |
|  * @x:      x coordinate within @window for the button event
 | |
|  * @y:      y coordinate within @window for the button event
 | |
|  * @button: Number of the pointer button for the event, usually 1, 2 or 3
 | |
|  * @modifiers: Keyboard modifiers the event is setup with
 | |
|  * @button_pressrelease: either %GDK_BUTTON_PRESS or %GDK_BUTTON_RELEASE
 | |
|  *
 | |
|  * This function is intended to be used in GTK+ test programs.
 | |
|  * It will warp the mouse pointer to the given (@x,@y) coordinates
 | |
|  * within @window and simulate a button press or release event.
 | |
|  * Because the mouse pointer needs to be warped to the target
 | |
|  * location, use of this function outside of test programs that
 | |
|  * run in their own virtual windowing system (e.g. Xvfb) is not
 | |
|  * recommended.
 | |
|  *
 | |
| * Also, gdk_test_simulate_button() is a fairly low level function,
 | |
|  * for most testing purposes, gtk_test_widget_click() is the right
 | |
|  * function to call which will generate a button press event followed
 | |
|  * by its accompanying button release event.
 | |
|  *
 | |
|  * Returns: whether all actions necessary for a button event simulation
 | |
|  *     were carried out successfully
 | |
|  *
 | |
|  * Since: 2.14
 | |
|  */
 | |
| gboolean
 | |
| gdk_test_simulate_button (GdkWindow      *window,
 | |
|                           gint            x,
 | |
|                           gint            y,
 | |
|                           guint           button, /*1..3*/
 | |
|                           GdkModifierType modifiers,
 | |
|                           GdkEventType    button_pressrelease)
 | |
| {
 | |
|   return GDK_WINDOW_IMPL_GET_CLASS (window->impl)
 | |
|     ->simulate_button (window, x, y, button, modifiers, button_pressrelease);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_property_get:
 | |
|  * @window: a #GdkWindow
 | |
|  * @property: the property to retrieve
 | |
|  * @type: the desired property type, or %GDK_NONE, if any type of data
 | |
|  *   is acceptable. If this does not match the actual
 | |
|  *   type, then @actual_format and @actual_length will
 | |
|  *   be filled in, a warning will be printed to stderr
 | |
|  *   and no data will be returned.
 | |
|  * @offset: the offset into the property at which to begin
 | |
|  *   retrieving data, in 4 byte units.
 | |
|  * @length: the length of the data to retrieve in bytes.  Data is
 | |
|  *   considered to be retrieved in 4 byte chunks, so @length
 | |
|  *   will be rounded up to the next highest 4 byte boundary
 | |
|  *   (so be careful not to pass a value that might overflow
 | |
|  *   when rounded up).
 | |
|  * @pdelete: if %TRUE, delete the property after retrieving the
 | |
|  *   data.
 | |
|  * @actual_property_type: (out) (transfer none): location to store the
 | |
|  *   actual type of the property.
 | |
|  * @actual_format: (out): location to store the actual return format of the
 | |
|  *   data; either 8, 16 or 32 bits.
 | |
|  * @actual_length: location to store the length of the retrieved data, in
 | |
|  *   bytes.  Data returned in the 32 bit format is stored
 | |
|  *   in a long variable, so the actual number of 32 bit
 | |
|  *   elements should be be calculated via
 | |
|  *   @actual_length / sizeof(glong) to ensure portability to
 | |
|  *   64 bit systems.
 | |
|  * @data: (out) (array length=actual_length) (transfer full): location
 | |
|  *   to store a pointer to the data. The retrieved data should be
 | |
|  *   freed with g_free() when you are finished using it.
 | |
|  *
 | |
|  * Retrieves a portion of the contents of a property. If the
 | |
|  * property does not exist, then the function returns %FALSE,
 | |
|  * and %GDK_NONE will be stored in @actual_property_type.
 | |
|  *
 | |
|  * <note>
 | |
|  * <para>
 | |
|  * The XGetWindowProperty() function that gdk_property_get()
 | |
|  * uses has a very confusing and complicated set of semantics.
 | |
|  * Unfortunately, gdk_property_get() makes the situation
 | |
|  * worse instead of better (the semantics should be considered
 | |
|  * undefined), and also prints warnings to stderr in cases where it
 | |
|  * should return a useful error to the program. You are advised to use
 | |
|  * XGetWindowProperty() directly until a replacement function for
 | |
|  * gdk_property_get()
 | |
|  * is provided.
 | |
|  * </para>
 | |
|  * </note>
 | |
|  *
 | |
|  * Returns: %TRUE if data was successfully received and stored
 | |
|  *   in @data, otherwise %FALSE.
 | |
|  */
 | |
| 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)
 | |
| {
 | |
|   return GDK_WINDOW_IMPL_GET_CLASS (window->impl)
 | |
|     ->get_property (window, property, type, offset, length, pdelete,
 | |
|                     actual_property_type, actual_format_type,
 | |
|                     actual_length, data);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_property_change: (skip)
 | |
|  * @window: a #GdkWindow
 | |
|  * @property: the property to change
 | |
|  * @type: the new type for the property. If @mode is
 | |
|  *   %GDK_PROP_MODE_PREPEND or %GDK_PROP_MODE_APPEND, then this
 | |
|  *   must match the existing type or an error will occur.
 | |
|  * @format: the new format for the property. If @mode is
 | |
|  *   %GDK_PROP_MODE_PREPEND or %GDK_PROP_MODE_APPEND, then this
 | |
|  *   must match the existing format or an error will occur.
 | |
|  * @mode: a value describing how the new data is to be combined
 | |
|  *   with the current data.
 | |
|  * @data: the data (a <literal>guchar *</literal>
 | |
|  *   <literal>gushort *</literal>, or <literal>gulong *</literal>,
 | |
|  *   depending on @format), cast to a <literal>guchar *</literal>.
 | |
|  * @nelements: the number of elements of size determined by the format,
 | |
|  *   contained in @data.
 | |
|  *
 | |
|  * Changes the contents of a property on a window.
 | |
|  */
 | |
| void
 | |
| gdk_property_change (GdkWindow    *window,
 | |
|                      GdkAtom       property,
 | |
|                      GdkAtom       type,
 | |
|                      gint          format,
 | |
|                      GdkPropMode   mode,
 | |
|                      const guchar *data,
 | |
|                      gint          nelements)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)
 | |
|     ->change_property (window, property, type, format, mode, data, nelements);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gdk_property_delete:
 | |
|  * @window: a #GdkWindow
 | |
|  * @property: the property to delete
 | |
|  *
 | |
|  * Deletes a property from a window.
 | |
|  */
 | |
| void
 | |
| gdk_property_delete (GdkWindow *window,
 | |
|                      GdkAtom    property)
 | |
| {
 | |
|   GDK_WINDOW_IMPL_GET_CLASS (window->impl)->delete_property (window, property);
 | |
| }
 |