/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * 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
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
-#include <config.h>
+#include "config.h"
#include "gdkwindow.h"
+#include "gdkwindowimpl.h"
#include "gdkinternals.h"
#include "gdk.h" /* For gdk_rectangle_union() */
#include "gdkpixmap.h"
#include "gdkdrawable.h"
-#include "gdkpixmap.h"
#include "gdkscreen.h"
#include "gdkalias.h"
cairo_surface_t *surface;
};
+typedef struct {
+ GdkRegion *old_region;
+ gint old_clip_x_origin;
+ gint old_clip_y_origin;
+ gint x_offset;
+ gint y_offset;
+} GdkWindowClipData;
+
+struct _GdkWindowRedirect
+{
+ GdkWindowObject *redirected;
+ GdkDrawable *pixmap;
+ gint src_x;
+ gint src_y;
+ gint dest_x;
+ gint dest_y;
+ gint width;
+ gint height;
+};
+
static GdkGC *gdk_window_create_gc (GdkDrawable *drawable,
GdkGCValues *values,
GdkGCValuesMask mask);
gint y,
gint width,
gint height);
+static void setup_redirect_clip (GdkWindow *window,
+ GdkGC *gc,
+ GdkWindowClipData *data);
+static void reset_redirect_clip (GdkWindow *offscreen,
+ GdkGC *gc,
+ GdkWindowClipData *data);
+static void gdk_window_redirect_free (GdkWindowRedirect *redirect);
+static void apply_redirect_to_children (GdkWindowObject *private,
+ GdkWindowRedirect *redirect);
+static void remove_redirect_from_children (GdkWindowObject *private,
+ GdkWindowRedirect *redirect);
+static GdkRegion *_gdk_window_calculate_full_clip_region (GdkWindow *window,
+ GdkWindow *base_window,
+ GdkGC *gc,
+ gboolean do_children,
+ gint *base_x_offset,
+ gint *base_y_offset);
static gpointer parent_class = NULL;
static GType object_type = 0;
if (!object_type)
+ object_type = g_type_register_static_simple (GDK_TYPE_DRAWABLE,
+ "GdkWindow",
+ sizeof (GdkWindowObjectClass),
+ (GClassInitFunc) gdk_window_class_init,
+ sizeof (GdkWindowObject),
+ (GInstanceInitFunc) gdk_window_init,
+ 0);
+
+ return object_type;
+}
+
+GType
+_gdk_paintable_get_type (void)
+{
+ static GType paintable_type = 0;
+
+ if (!paintable_type)
{
- static const GTypeInfo object_info =
+ const GTypeInfo paintable_info =
{
- sizeof (GdkWindowObjectClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gdk_window_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GdkWindowObject),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gdk_window_init,
+ sizeof (GdkPaintableIface), /* class_size */
+ NULL, /* base_init */
+ NULL, /* base_finalize */
};
-
- object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
- "GdkWindow",
- &object_info, 0);
+
+ 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 object_type;
+
+ return paintable_type;
}
static void
window->window_type = GDK_WINDOW_CHILD;
window->state = GDK_WINDOW_STATE_WITHDRAWN;
-
- window->impl = g_object_new (_gdk_window_impl_get_type (), NULL);
}
static void
G_OBJECT_CLASS (parent_class)->finalize (object);
}
+/**
+ * gdk_window_new:
+ * @parent: 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: 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: the new #GdkWindow
+ **/
+GdkWindow*
+gdk_window_new (GdkWindow *parent,
+ GdkWindowAttr *attributes,
+ gint attributes_mask)
+{
+ GdkWindow *window;
+ GdkWindowObject *private, *parent_private;
+
+ g_return_val_if_fail (attributes != NULL, NULL);
+
+ window = _gdk_window_new (parent, attributes, attributes_mask);
+
+ /* Inherit redirection from parent */
+ if (parent != NULL)
+ {
+ parent_private = GDK_WINDOW_OBJECT (parent);
+ private = GDK_WINDOW_OBJECT (window);
+ private->redirect = parent_private->redirect;
+ }
+
+ return window;
+}
+
+/**
+ * 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)
+{
+ GdkWindowObject *private;
+ gboolean show;
+
+ 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;
+ }
+
+ private = (GdkWindowObject *) window;
+
+ /* Break up redirection if inherited */
+ if (private->redirect && private->redirect->redirected != private)
+ {
+ remove_redirect_from_children (private, private->redirect);
+ private->redirect = NULL;
+ }
+
+ show = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->reparent (window, new_parent, x, y);
+
+ /* Inherit parent redirect if we don't have our own */
+ if (private->parent && private->redirect == NULL)
+ {
+ private->redirect = private->parent->redirect;
+ apply_redirect_to_children (private, private->redirect);
+ }
+
+ if (show)
+ gdk_window_show (window);
+}
+
static void
window_remove_filters (GdkWindow *window)
{
GdkWindowObject *private;
GdkWindowObject *temp_private;
GdkWindow *temp_window;
+ GdkScreen *screen;
GList *children;
GList *tmp;
switch (GDK_WINDOW_TYPE (window))
{
+ case GDK_WINDOW_ROOT:
+ screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
+ 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_DIALOG:
window_remove_filters (window);
gdk_drawable_set_colormap (GDK_DRAWABLE (window), NULL);
+
+ /* If we own the redirect, free it */
+ if (private->redirect && private->redirect->redirected == private)
+ gdk_window_redirect_free (private->redirect);
+
+ private->redirect = NULL;
}
break;
-
- case GDK_WINDOW_ROOT:
- g_error ("attempted to destroy root window");
- break;
}
}
* 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.
- *
+ *
+ * See gdk_display_add_client_message_filter() if you are interested
+ * in X ClientMessage events.
**/
void
gdk_window_add_filter (GdkWindow *window,
* gdk_window_get_toplevels:
*
* Obtains a list of all toplevel windows known to GDK on the default
- * screen (see gdk_window_get_toplevels_for_screen()).
+ * screen (see gdk_screen_get_toplevel_windows()).
* A toplevel window is a child of the root window (see
* gdk_get_default_root_window()).
*
*
**/
void
-gdk_window_begin_paint_rect (GdkWindow *window,
- GdkRectangle *rectangle)
+gdk_window_begin_paint_rect (GdkWindow *window,
+ const GdkRectangle *rectangle)
{
GdkRegion *region;
*
**/
void
-gdk_window_begin_paint_region (GdkWindow *window,
- GdkRegion *region)
+gdk_window_begin_paint_region (GdkWindow *window,
+ const GdkRegion *region)
{
#ifdef USE_BACKING_STORE
GdkWindowObject *private = (GdkWindowObject *)window;
if (GDK_WINDOW_DESTROYED (window))
return;
+ if (GDK_IS_PAINTABLE (private->impl))
+ {
+ GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (private->impl);
+
+ if (iface->begin_paint_region)
+ iface->begin_paint_region ((GdkPaintable*)private->impl, region);
+
+ return;
+ }
+
gdk_region_get_clipbox (region, &clip_box);
paint = g_new (GdkWindowPaint, 1);
{
#ifdef USE_BACKING_STORE
GdkWindowObject *private = (GdkWindowObject *)window;
+ GdkWindowObject *composited;
GdkWindowPaint *paint;
GdkGC *tmp_gc;
GdkRectangle clip_box;
if (GDK_WINDOW_DESTROYED (window))
return;
+ if (GDK_IS_PAINTABLE (private->impl))
+ {
+ GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (private->impl);
+
+ if (iface->end_paint)
+ iface->end_paint ((GdkPaintable*)private->impl);
+ return;
+ }
+
if (private->paint_stack == NULL)
{
g_warning (G_STRLOC": no preceding call to gdk_window_begin_paint_region(), see documentation");
tmp_gc = _gdk_drawable_get_scratch_gc (window, FALSE);
- _gdk_windowing_window_get_offsets (window, &x_offset, &y_offset);
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (window, &x_offset, &y_offset);
gdk_gc_set_clip_region (tmp_gc, paint->region);
gdk_gc_set_clip_origin (tmp_gc, - x_offset, - y_offset);
clip_box.x - x_offset, clip_box.y - y_offset,
clip_box.width, clip_box.height);
+ if (private->redirect)
+ {
+ GdkWindowClipData data;
+
+ setup_redirect_clip (window, tmp_gc, &data);
+ gdk_draw_drawable (private->redirect->pixmap, tmp_gc, paint->pixmap,
+ clip_box.x - paint->x_offset,
+ clip_box.y - paint->y_offset,
+ clip_box.x + data.x_offset,
+ clip_box.y + data.y_offset,
+ clip_box.width, clip_box.height);
+ reset_redirect_clip (window, tmp_gc, &data);
+ }
+
/* Reset clip region of the cached GdkGC */
gdk_gc_set_clip_region (tmp_gc, NULL);
g_object_unref (paint->pixmap);
gdk_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 = private;
+ composited->parent;
+ composited = composited->parent)
+ {
+ int width, height;
+
+ gdk_drawable_get_size (GDK_DRAWABLE (composited->parent),
+ &width, &height);
+
+ clip_box.x += composited->x;
+ clip_box.y += composited->y;
+ clip_box.width = MIN (clip_box.width, width - clip_box.x);
+ clip_box.height = MIN (clip_box.height, height - clip_box.y);
+
+ if (composited->composited)
+ {
+ gdk_window_invalidate_rect (GDK_WINDOW (composited->parent),
+ &clip_box, FALSE);
+ break;
+ }
+ }
#endif /* USE_BACKING_STORE */
}
*y_offset = paint->y_offset;
}
else
- _gdk_windowing_window_get_offsets (window, x_offset, y_offset);
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (window, x_offset, y_offset);
}
/**
{
GdkWindowPaint *paint = private->paint_stack->data;
gdk_draw_rectangle (paint->pixmap, gc, filled,
- x - x_offset, y - y_offset, width, height);
+ x - x_offset, y - y_offset, width, height);
}
else
gdk_draw_rectangle (private->impl, gc, filled,
GdkGC *tmp_gc;
gboolean overlap_buffer;
- _gdk_windowing_window_get_offsets (drawable,
- composite_x_offset,
- composite_y_offset);
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (GDK_WINDOW (drawable),
+ composite_x_offset,
+ composite_y_offset);
if ((GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable))
|| private->paint_stack == NULL)
tmp_matrix.y0 -= y_offset;
matrix = &tmp_matrix;
}
+ else if (GDK_PANGO_UNITS_OVERFLOWS (x_offset, y_offset))
+ {
+ PangoMatrix identity = PANGO_MATRIX_INIT;
+
+ tmp_matrix = identity;
+ tmp_matrix.x0 -= x_offset;
+ tmp_matrix.y0 -= y_offset;
+ matrix = &tmp_matrix;
+ }
else
{
x -= x_offset * PANGO_SCALE;
RESTORE_GC (gc);
}
+typedef struct {
+ cairo_t *cr; /* if non-null, it means use this cairo context */
+ GdkGC *gc; /* if non-null, it means use this GC instead */
+} BackingRectMethod;
+
static void
-gdk_window_set_bg_pattern (GdkWindow *window,
- cairo_t *cr,
- int x_offset,
- int y_offset)
+setup_backing_rect_method (BackingRectMethod *method, GdkWindow *window, GdkWindowPaint *paint, int x_offset_cairo, int y_offset_cairo)
{
GdkWindowObject *private = (GdkWindowObject *)window;
if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG && private->parent)
{
- gdk_window_set_bg_pattern (GDK_WINDOW (private->parent), cr,
- private->x, private->y);
+ GdkWindowPaint tmp_paint;
+
+ tmp_paint = *paint;
+ tmp_paint.x_offset += private->x;
+ tmp_paint.y_offset += private->y;
+
+ x_offset_cairo += private->x;
+ y_offset_cairo += private->y;
+
+ setup_backing_rect_method (method, GDK_WINDOW (private->parent), &tmp_paint, x_offset_cairo, y_offset_cairo);
}
- else if (private->bg_pixmap &&
- private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
- private->bg_pixmap != GDK_NO_BG)
+ else if (private->bg_pixmap &&
+ private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
+ private->bg_pixmap != GDK_NO_BG)
{
+/* This is a workaround for https://bugs.freedesktop.org/show_bug.cgi?id=4320.
+ * In it, using a pixmap as a repeating pattern in Cairo, and painting it to a
+ * pixmap destination surface, can be very slow (on the order of seconds for a
+ * whole-screen copy). The workaround is to use pretty much the same code that
+ * we used in GTK+ 2.6 (pre-Cairo), which clears the double-buffer pixmap with
+ * a tiled GC XFillRectangle().
+ */
+
+/* Actually computing this flag is left as an exercise for the reader */
+#if defined (G_OS_UNIX)
+# define GDK_CAIRO_REPEAT_IS_FAST 0
+#else
+# define GDK_CAIRO_REPEAT_IS_FAST 1
+#endif
+
+#if GDK_CAIRO_REPEAT_IS_FAST
cairo_surface_t *surface = _gdk_drawable_ref_cairo_surface (private->bg_pixmap);
cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
- if (x_offset != 0 || y_offset)
+ if (x_offset_cairo != 0 || y_offset_cairo != 0)
{
- cairo_matrix_t *matrix = cairo_matrix_create ();
- cairo_matrix_translate (matrix, x_offset, y_offset);
- cairo_pattern_set_matrix (pattern, matrix);
- cairo_matrix_destroy (matrix);
+ cairo_matrix_t matrix;
+ cairo_matrix_init_translate (&matrix, x_offset_cairo, y_offset_cairo);
+ cairo_pattern_set_matrix (pattern, &matrix);
}
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
- cairo_set_source (cr, pattern);
+
+ method->cr = cairo_create (paint->surface);
+ method->gc = NULL;
+
+ cairo_set_source (method->cr, pattern);
cairo_pattern_destroy (pattern);
+#else
+ guint gc_mask;
+ GdkGCValues gc_values;
+
+ gc_values.fill = GDK_TILED;
+ gc_values.tile = private->bg_pixmap;
+ gc_values.ts_x_origin = -x_offset_cairo;
+ gc_values.ts_y_origin = -y_offset_cairo;
+
+ gc_mask = GDK_GC_FILL | GDK_GC_TILE | GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN;
+
+ method->gc = gdk_gc_new_with_values (paint->pixmap, &gc_values, gc_mask);
+#endif
}
else
{
- gdk_cairo_set_source_color (cr, &private->bg_color);
- }
-}
+ method->cr = cairo_create (paint->surface);
-static void
-region_path (cairo_t *cr,
- GdkRegion *region)
-{
- GdkRectangle *rectangles;
- int n_rectangles, i;
-
- gdk_region_get_rectangles (region, &rectangles, &n_rectangles);
- for (i = 0; i < n_rectangles; i++)
- {
- cairo_rectangle (cr,
- rectangles[i].x, rectangles[i].y,
- rectangles[i].width, rectangles[i].height);
+ gdk_cairo_set_source_color (method->cr, &private->bg_color);
}
- g_free (rectangles);
}
static void
{
GdkWindowObject *private = (GdkWindowObject *)window;
GdkWindowPaint *paint = private->paint_stack->data;
- cairo_t *cr;
+ BackingRectMethod method;
+#if 0
+ GTimer *timer;
+ double elapsed;
+#endif
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+#if 0
+ timer = g_timer_new ();
+#endif
+
+ method.cr = NULL;
+ method.gc = NULL;
+ setup_backing_rect_method (&method, window, paint, 0, 0);
+
+ if (method.cr)
+ {
+ g_assert (method.gc == NULL);
+
+ cairo_rectangle (method.cr, x, y, width, height);
+ cairo_clip (method.cr);
+
+ gdk_cairo_region (method.cr, paint->region);
+ cairo_fill (method.cr);
+
+ cairo_destroy (method.cr);
+#if 0
+ elapsed = g_timer_elapsed (timer, NULL);
+ g_print ("Draw the background with Cairo: %fs\n", elapsed);
+#endif
+ }
+ else
+ {
+ g_assert (method.gc != NULL);
+
+ gdk_gc_set_clip_region (method.gc, paint->region);
+ gdk_draw_rectangle (window, method.gc, TRUE, x, y, width, height);
+ g_object_unref (method.gc);
+
+#if 0
+ elapsed = g_timer_elapsed (timer, NULL);
+ g_print ("Draw the background with GDK: %fs\n", elapsed);
+#endif
+ }
+
+#if 0
+ g_timer_destroy (timer);
+#endif
+}
+
+static void
+gdk_window_clear_backing_rect_redirect (GdkWindow *window,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GdkWindowObject *private = (GdkWindowObject *)window;
+ GdkWindowRedirect *redirect = private->redirect;
+ GdkRegion *clip_region;
+ gint x_offset, y_offset;
+ BackingRectMethod method;
+ GdkWindowPaint paint;
+
if (GDK_WINDOW_DESTROYED (window))
return;
- cr = cairo_create ();
- cairo_set_target_surface (cr, paint->surface);
+ paint.x_offset = x_offset;
+ paint.y_offset = y_offset;
+ paint.pixmap = redirect->pixmap;
+ paint.surface = _gdk_drawable_ref_cairo_surface (redirect->pixmap);
+
+ clip_region = _gdk_window_calculate_full_clip_region (window,
+ GDK_WINDOW (redirect->redirected),
+ NULL, TRUE,
+ &x_offset, &y_offset);
+
+
+ method.cr = NULL;
+ method.gc = NULL;
+ setup_backing_rect_method (&method, window, &paint, 0, 0);
+
+ if (method.cr)
+ {
+ g_assert (method.gc == NULL);
+
+ cairo_rectangle (method.cr, x, y, width, height);
+ cairo_clip (method.cr);
- gdk_window_set_bg_pattern (window, cr, 0, 0);
+ gdk_cairo_region (method.cr, clip_region);
+ cairo_fill (method.cr);
+
+ cairo_destroy (method.cr);
+ }
+ else
+ {
+ g_assert (method.gc != NULL);
- cairo_rectangle (cr, x, y, width, height);
- cairo_clip (cr);
+ gdk_gc_set_clip_region (method.gc, clip_region);
+ gdk_draw_rectangle (window, method.gc, TRUE, x, y, width, height);
+ g_object_unref (method.gc);
- region_path (cr, paint->region);
- cairo_fill (cr);
+ }
- cairo_destroy (cr);
+ gdk_region_destroy (clip_region);
+ cairo_surface_destroy (paint.surface);
}
+
/**
* gdk_window_clear:
* @window: a #GdkWindow
g_return_if_fail (window != NULL);
g_return_if_fail (GDK_IS_WINDOW (window));
-
+
if (private->paint_stack)
gdk_window_clear_backing_rect (window, x, y, width, height);
else
- _gdk_windowing_window_clear_area (window, x, y, width, height);
+ {
+ if (private->redirect)
+ gdk_window_clear_backing_rect_redirect (window, x, y, width, height);
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_area (window,
+ x, y,
+ width, height,
+ FALSE);
+ }
}
/**
if (private->paint_stack)
gdk_window_clear_backing_rect (window, x, y, width, height);
- _gdk_windowing_window_clear_area_e (window, x, y, width, height);
+ if (private->redirect)
+ gdk_window_clear_backing_rect_redirect (window, x, y, width, height);
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_area (window,
+ x, y,
+ width, height,
+ TRUE);
}
static void
else
gdk_draw_trapezoids (private->impl, gc, trapezoids, n_trapezoids);
- if (new_trapezoids)
- g_free (new_trapezoids);
+ g_free (new_trapezoids);
RESTORE_GC (gc);
}
gint width,
gint height)
{
+ GdkWindowObject *private = (GdkWindowObject *) drawable;
gint x_offset, y_offset;
g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
* we can ignore the paint stack.
*/
- _gdk_windowing_window_get_offsets (drawable, &x_offset, &y_offset);
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (drawable,
+ &x_offset, &y_offset);
- return gdk_drawable_copy_to_image (((GdkWindowObject*)drawable)->impl,
+ return gdk_drawable_copy_to_image (private->impl,
image,
src_x - x_offset,
src_y - y_offset,
{
GdkWindowObject *private = (GdkWindowObject*) drawable;
cairo_surface_t *surface;
- gint x_offset, y_offset;
-
- gdk_window_get_offsets (GDK_WINDOW (drawable), &x_offset, &y_offset);
if (private->paint_stack)
{
static gboolean
gdk_window_update_idle (gpointer data)
{
- GDK_THREADS_ENTER ();
gdk_window_process_all_updates ();
- GDK_THREADS_LEAVE ();
return FALSE;
}
+static gboolean
+gdk_window_is_toplevel_frozen (GdkWindow *window)
+{
+ GdkWindowObject *toplevel;
+
+ toplevel = (GdkWindowObject *)gdk_window_get_toplevel (window);
+
+ return toplevel->update_and_descendants_freeze_count > 0;
+}
+
static void
gdk_window_schedule_update (GdkWindow *window)
{
- if (window && GDK_WINDOW_OBJECT (window)->update_freeze_count)
+ if (window &&
+ (GDK_WINDOW_OBJECT (window)->update_freeze_count ||
+ gdk_window_is_toplevel_frozen (window)))
return;
if (!update_idle)
{
- update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW,
+ update_idle = gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW,
gdk_window_update_idle, NULL, NULL);
}
}
event.expose.type = GDK_EXPOSE;
event.expose.window = g_object_ref (window);
+ event.expose.send_event = FALSE;
event.expose.count = 0;
event.expose.region = expose_region;
gdk_region_get_clipbox (expose_region, &event.expose.area);
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:
*
{
GdkWindowObject *private = (GdkWindowObject *)tmp_list->data;
- if (private->update_freeze_count)
- update_windows = g_slist_prepend (update_windows, private);
- else
- gdk_window_process_updates_internal (tmp_list->data);
-
+ if (!GDK_WINDOW_DESTROYED (tmp_list->data))
+ {
+ if (private->update_freeze_count ||
+ gdk_window_is_toplevel_frozen (tmp_list->data))
+ update_windows = g_slist_prepend (update_windows, private);
+ else
+ gdk_window_process_updates_internal (tmp_list->data);
+ }
+
g_object_unref (tmp_list->data);
tmp_list = tmp_list->next;
}
g_return_if_fail (window != NULL);
g_return_if_fail (GDK_IS_WINDOW (window));
- if (private->update_area && !private->update_freeze_count)
+ if (GDK_IS_PAINTABLE (private->impl))
+ {
+ GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (private->impl);
+
+ if (iface->process_updates)
+ iface->process_updates ((GdkPaintable*)private->impl, update_children);
+
+ return;
+ }
+
+ if (private->update_area &&
+ !private->update_freeze_count &&
+ !gdk_window_is_toplevel_frozen (window))
{
gdk_window_process_updates_internal (window);
update_windows = g_slist_remove (update_windows, window);
/**
* gdk_window_invalidate_rect:
* @window: a #GdkWindow
- * @rect: rectangle to invalidate
+ * @rect: 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,
- GdkRectangle *rect,
- gboolean invalidate_children)
+gdk_window_invalidate_rect (GdkWindow *window,
+ const GdkRectangle *rect,
+ gboolean invalidate_children)
{
GdkRectangle window_rect;
GdkRegion *region;
}
static void
-draw_ugly_color (GdkWindow *window,
- GdkRegion *region)
+draw_ugly_color (GdkWindow *window,
+ const GdkRegion *region)
{
/* Draw ugly color all over the newly-invalid region */
GdkColor ugly_color = { 0, 50000, 10000, 10000 };
* invalidated.
**/
void
-gdk_window_invalidate_maybe_recurse (GdkWindow *window,
- GdkRegion *region,
- gboolean (*child_func) (GdkWindow *, gpointer),
+gdk_window_invalidate_maybe_recurse (GdkWindow *window,
+ const GdkRegion *region,
+ gboolean (*child_func) (GdkWindow *,
+ gpointer),
gpointer user_data)
{
GdkWindowObject *private = (GdkWindowObject *)window;
if (private->input_only || !GDK_WINDOW_IS_MAPPED (window))
return;
- visible_region = gdk_drawable_get_visible_region (window);
+ if (GDK_IS_PAINTABLE (private->impl))
+ {
+ GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (private->impl);
+
+ if (iface->invalidate_maybe_recurse)
+ iface->invalidate_maybe_recurse ((GdkPaintable*)private->impl,
+ region, child_func, user_data);
+ return;
+ }
+
+ /* windows that a redirection has ben setup for need to be considered
+ * fully visible, in order to avoid missing redirected paint ops
+ * anywhere in the window area.
+ */
+ if (private->redirect && private->redirect->redirected == private)
+ {
+ GdkRectangle visible_rect = { 0, 0, 0, 0 };
+ gdk_drawable_get_size (GDK_DRAWABLE (window), &visible_rect.width, &visible_rect.height);
+ visible_region = gdk_region_rectangle (&visible_rect);
+ }
+ else
+ visible_region = gdk_drawable_get_visible_region (window);
gdk_region_intersect (visible_region, region);
tmp_list = private->children;
child_region = gdk_region_rectangle (&child_rect);
/* remove child area from the invalid area of the parent */
- if (GDK_WINDOW_IS_MAPPED (child))
+ if (GDK_WINDOW_IS_MAPPED (child) && !child->shaped &&
+ !child->composited)
gdk_region_subtract (visible_region, child_region);
if (child_func && (*child_func) ((GdkWindow *)child, user_data))
{
- gdk_region_offset (region, - child_rect.x, - child_rect.y);
+ GdkRegion *tmp = gdk_region_copy (region);
+
+ gdk_region_offset (tmp, - child_rect.x, - child_rect.y);
gdk_region_offset (child_region, - child_rect.x, - child_rect.y);
- gdk_region_intersect (child_region, region);
+ gdk_region_intersect (child_region, tmp);
gdk_window_invalidate_maybe_recurse ((GdkWindow *)child,
child_region, child_func, user_data);
- gdk_region_offset (region, child_rect.x, child_rect.y);
+ gdk_region_destroy (tmp);
}
gdk_region_destroy (child_region);
{
if (debug_updates)
draw_ugly_color (window, region);
-
+
if (private->update_area)
{
gdk_region_union (private->update_area, visible_region);
* fine grained control over which children are invalidated.
**/
void
-gdk_window_invalidate_region (GdkWindow *window,
- GdkRegion *region,
- gboolean invalidate_children)
+gdk_window_invalidate_region (GdkWindow *window,
+ const GdkRegion *region,
+ gboolean invalidate_children)
{
gdk_window_invalidate_maybe_recurse (window, region,
invalidate_children ?
gdk_window_schedule_update (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)
+{
+ GdkWindowObject *private = (GdkWindowObject *)window;
+
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (GDK_IS_WINDOW (window));
+ g_return_if_fail (private->window_type != GDK_WINDOW_CHILD);
+
+ private->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)
+{
+ GdkWindowObject *private = (GdkWindowObject *)window;
+
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (GDK_IS_WINDOW (window));
+ g_return_if_fail (private->window_type != GDK_WINDOW_CHILD);
+ g_return_if_fail (private->update_and_descendants_freeze_count > 0);
+
+ private->update_and_descendants_freeze_count--;
+
+ gdk_window_schedule_update (window);
+}
+
/**
* gdk_window_set_debug_updates:
* @setting: %TRUE to turn on update debugging
/**
* gdk_window_get_pointer:
* @window: a #GdkWindow
- * @x: return location for X coordinate of pointer
- * @y: return location for Y coordinate of pointer
- * @mask: return location for modifier mask
+ * @x: return location for X coordinate of pointer or %NULL to not
+ * return the X coordinate
+ * @y: return location for Y coordinate of pointer or %NULL to not
+ * return the Y coordinate
+ * @mask: 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 @window.
+ * The position is given in coordinates relative to the upper left
+ * corner of @window.
*
* Return value: the window containing the pointer (as with
* gdk_window_at_pointer()), or %NULL if the window containing the
return gdk_window_foreign_new_for_display (gdk_display_get_default (), anid);
}
+/**
+ * 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)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+ if (private->destroyed)
+ return;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window, FALSE);
+}
+
+static inline void
+gdk_window_raise_internal (GdkWindow *window)
+{
+ GdkWindowObject *private = (GdkWindowObject *)window;
+ GdkWindowObject *parent = private->parent;
+
+ if (parent)
+ {
+ parent->children = g_list_remove (parent->children, window);
+ parent->children = g_list_prepend (parent->children, window);
+ }
+}
+
+/**
+ * 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)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+ if (private->destroyed)
+ return;
+
+ /* Keep children in (reverse) stacking order */
+ gdk_window_raise_internal (window);
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (window);
+}
+
+static void
+gdk_window_lower_internal (GdkWindow *window)
+{
+ GdkWindowObject *private = (GdkWindowObject *)window;
+ GdkWindowObject *parent = private->parent;
+
+ if (parent)
+ {
+ parent->children = g_list_remove (parent->children, window);
+ parent->children = g_list_append (parent->children, window);
+ }
+}
+
+/**
+ * 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)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+ if (private->destroyed)
+ return;
+
+ /* Keep children in (reverse) stacking order */
+ gdk_window_lower_internal (window);
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->lower (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)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+ if (private->destroyed)
+ return;
+
+ /* Keep children in (reverse) stacking order */
+ gdk_window_raise_internal (window);
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (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)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+ if (private->destroyed)
+ return;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->hide (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)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+ if (private->destroyed)
+ return;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->withdraw (window);
+}
+
+/**
+ * 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. 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)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+ if (private->destroyed)
+ return;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_events (window, event_mask);
+}
+
+/**
+ * gdk_window_get_events:
+ * @window: a #GdkWindow
+ *
+ * Gets the event mask for @window. See gdk_window_set_events().
+ *
+ * Return value: event mask for @window
+ **/
+GdkEventMask
+gdk_window_get_events (GdkWindow *window)
+{
+ GdkWindowObject *private;
+
+ g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+
+ private = (GdkWindowObject *) window;
+ if (private->destroyed)
+ return 0;
+
+ return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_events (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)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+ if (private->destroyed)
+ return;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (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)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+ if (private->destroyed)
+ return;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (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)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+ if (private->destroyed)
+ return;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (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)
+{
+ GdkWindowObject *private = (GdkWindowObject *) window;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ if (dx == 0 && dy == 0)
+ return;
+
+ if (private->destroyed)
+ return;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->scroll (window, dx, dy);
+}
+
+/**
+ * gdk_window_move_region:
+ * @window: a #GdkWindow
+ * @region: The #GdkRegion 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 GdkRegion *region,
+ gint dx,
+ gint dy)
+{
+ GdkWindowObject *private = (GdkWindowObject *) window;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+ g_return_if_fail (region != NULL);
+
+ if (dx == 0 && dy == 0)
+ return;
+
+ if (private->destroyed)
+ return;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_region (window, region, dx, dy);
+}
+
+/**
+ * gdk_window_set_background:
+ * @window: a #GdkWindow
+ * @color: an allocated #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.)
+ *
+ * The @color must be allocated; gdk_rgb_find_color() is the best way
+ * to allocate a color.
+ *
+ * See also gdk_window_set_back_pixmap().
+ */
+void
+gdk_window_set_background (GdkWindow *window,
+ const GdkColor *color)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_background (window, color);
+}
+
+/**
+ * gdk_window_set_back_pixmap:
+ * @window: a #GdkWindow
+ * @pixmap: a #GdkPixmap, or %NULL
+ * @parent_relative: whether the tiling origin is at the origin of
+ * @window's parent
+ *
+ * Sets the background pixmap of @window. May also be used to set a
+ * background of "None" on @window, by setting a background pixmap
+ * of %NULL.
+ *
+ * A background pixmap will be tiled, positioning the first tile at
+ * the origin of @window, or if @parent_relative is %TRUE, the tiling
+ * will be done based on the origin of the parent window (useful to
+ * align tiles in a parent with tiles in a child).
+ *
+ * A background pixmap of %NULL means that the window will have no
+ * background. A window with no background will never have its
+ * background filled by the windowing system, instead the window will
+ * contain whatever pixels were already in the corresponding area of
+ * the display.
+ *
+ * The windowing system will normally fill a window with its background
+ * when the window is obscured then exposed, and when you call
+ * gdk_window_clear().
+ */
+void
+gdk_window_set_back_pixmap (GdkWindow *window,
+ GdkPixmap *pixmap,
+ gboolean parent_relative)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+ g_return_if_fail (pixmap == NULL || !parent_relative);
+ g_return_if_fail (pixmap == NULL || gdk_drawable_get_depth (window) == gdk_drawable_get_depth (pixmap));
+
+ private = (GdkWindowObject *) window;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, pixmap, parent_relative);
+}
+
+/**
+ * gdk_window_set_cursor:
+ * @window: a #GdkWindow
+ * @cursor: a cursor
+ *
+ * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new() or
+ * gdk_cursor_new_from_pixmap() to create the cursor.
+ * To make the cursor invisible, use gdk_cursor_new_from_pixmap() to create
+ * a cursor with no pixels in it. 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)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_cursor (window, cursor);
+}
+
+/**
+ * gdk_window_get_geometry:
+ * @window: a #GdkWindow
+ * @x: return location for X coordinate of window (relative to its parent)
+ * @y: return location for Y coordinate of window (relative to its parent)
+ * @width: return location for width of window
+ * @height: return location for height of window
+ * @depth: return location for bit depth 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() and gdk_drawable_get_size() instead,
+ * because it avoids the roundtrip to the X server and because
+ * gdk_drawable_get_size() supports 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,
+ gint *depth)
+{
+ GdkWindowObject *private;
+
+ 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));
+
+ private = (GdkWindowObject *) window;
+
+ if (!GDK_WINDOW_DESTROYED (window))
+ {
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_geometry (window, x, y,
+ width, height,
+ depth);
+ }
+}
+
+/**
+ * gdk_window_get_origin:
+ * @window: a #GdkWindow
+ * @x: return location for X coordinate
+ * @y: 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)
+{
+ GdkWindowObject *private;
+
+ g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+
+ private = (GdkWindowObject *) window;
+
+ return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_origin (window, x, y);
+}
+
+/**
+ * gdk_window_shape_combine_mask:
+ * @window: a #GdkWindow
+ * @mask: shape mask
+ * @x: X position of shape mask with respect to @window
+ * @y: Y position of shape mask with respect to @window
+ *
+ * Applies a shape mask to @window. Pixels in @window corresponding to
+ * set bits in the @mask will be visible; pixels in @window
+ * corresponding to unset bits in the @mask will be transparent. This
+ * gives a non-rectangular window.
+ *
+ * If @mask is %NULL, the shape mask will be unset, and the @x/@y
+ * parameters are not used.
+ *
+ * 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_mask (GdkWindow *window,
+ GdkBitmap *mask,
+ gint x,
+ gint y)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_mask (window, mask, x, y);
+}
+
+/**
+ * gdk_window_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
+ *
+ * Makes pixels in @window outside @shape_region be transparent,
+ * so that the window may be nonrectangular. See also
+ * gdk_window_shape_combine_mask() to use a bitmap as the mask.
+ *
+ * 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 GdkRegion *shape_region,
+ gint offset_x,
+ gint offset_y)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region (window, shape_region, offset_x, offset_y);
+}
+
+/**
+ * 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)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_child_shapes (window);
+}
+
+/**
+ * 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_mask().
+ *
+ * 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)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->merge_child_shapes (window);
+}
+
+
+/**
+ * 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)
+{
+ GdkWindowObject *private;
+
+ g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+
+ private = (GdkWindowObject *) window;
+
+ return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_static_gravities (window, use_static);
+}
+
+/**
+ * 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)
+{
+ GdkWindowObject *private = (GdkWindowObject *)window;
+ GdkDisplay *display;
+
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ composited = composited != FALSE;
+
+ if (private->composited == composited)
+ return;
+
+ display = gdk_drawable_get_display (GDK_DRAWABLE (window));
+
+ if (!gdk_display_supports_composite (display) && composited)
+ {
+ g_warning ("gdk_window_set_composited called but "
+ "compositing is not supported");
+ return;
+ }
+
+ _gdk_windowing_window_set_composited (window, composited);
+
+ private->composited = composited;
+}
+
+
+static void
+remove_redirect_from_children (GdkWindowObject *private, GdkWindowRedirect *redirect)
+{
+ GList *l;
+ GdkWindowObject *child;
+
+ for (l = private->children; l != NULL; l = l->next)
+ {
+ child = l->data;
+
+ /* Don't redirect this child if it already has another redirect */
+ if (child->redirect == redirect)
+ {
+ child->redirect = NULL;
+ remove_redirect_from_children (child, redirect);
+ }
+ }
+}
+
+/**
+ * gdk_window_remove_redirection:
+ * @window: a #GdkWindow
+ *
+ * Removes and active redirection started by
+ * gdk_window_redirect_to_drawable().
+ **/
+void
+gdk_window_remove_redirection (GdkWindow *window)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+
+ if (private->redirect &&
+ private->redirect->redirected == private)
+ {
+ remove_redirect_from_children (private, private->redirect);
+ gdk_window_redirect_free (private->redirect);
+ private->redirect = NULL;
+ }
+}
+
+static void
+apply_redirect_to_children (GdkWindowObject *private, GdkWindowRedirect *redirect)
+{
+ GList *l;
+ GdkWindowObject *child;
+
+ for (l = private->children; l != NULL; l = l->next)
+ {
+ child = l->data;
+
+ /* Don't redirect this child if it already has another redirect */
+ if (!child->redirect)
+ {
+ child->redirect = redirect;
+ apply_redirect_to_children (child, redirect);
+ }
+ }
+}
+
+/**
+ * gdk_window_redirect_to_drawable:
+ * @window: a #GdkWindow
+ * @drawable: a #GdkDrawable
+ * @src_x: x position in @window
+ * @src_y: y position in @window
+ * @dest_x: x position in @drawable
+ * @dest_y: y position in @drawable
+ * @width: width of redirection
+ * @height: height of redirection
+ *
+ * Redirects drawing into @windows so that drawing to the
+ * window in the rectangle specified by @src_x, @src_y,
+ * @width and @height is also drawn into @drawable at
+ * @dest_x, @dest_y.
+ *
+ * Only drawing between gdk_window_begin_paint_region() and
+ * gdk_window_end_paint() is redirected.
+ *
+ * Redirection is active until gdk_window_remove_redirection()
+ * is called.
+ *
+ * This function should not be used on windows created by
+ * gdk_window_new_offscreen(), as that is implemented using
+ * redirection.
+ **/
+void
+gdk_window_redirect_to_drawable (GdkWindow *window,
+ GdkDrawable *drawable,
+ gint src_x, gint src_y,
+ gint dest_x, gint dest_y,
+ gint width, gint height)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+ g_return_if_fail (GDK_IS_DRAWABLE (drawable));
+ g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
+
+ private = (GdkWindowObject *) window;
+
+ if (private->redirect)
+ gdk_window_remove_redirection (window);
+
+ if (width == -1 || height == -1)
+ {
+ gint w, h;
+ gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h);
+ if (width == -1)
+ width = w;
+ if (height == -1)
+ height = h;
+ }
+
+ private->redirect = g_new0 (GdkWindowRedirect, 1);
+ private->redirect->redirected = private;
+ private->redirect->pixmap = g_object_ref (drawable);
+ private->redirect->src_x = src_x;
+ private->redirect->src_y = src_y;
+ private->redirect->dest_x = dest_x;
+ private->redirect->dest_y = dest_y;
+ private->redirect->width = width;
+ private->redirect->height = height;
+
+ apply_redirect_to_children (private, private->redirect);
+}
+
+static void
+window_get_size_rectangle (GdkWindow *window,
+ GdkRectangle *rect)
+{
+ rect->x = rect->y = 0;
+ gdk_drawable_get_size (GDK_DRAWABLE (window), &rect->width, &rect->height);
+}
+
+/* Calculates the real clipping region for a window, in window coordinates,
+ * taking into account other windows, gc clip region and gc clip mask.
+ */
+static GdkRegion *
+_gdk_window_calculate_full_clip_region (GdkWindow *window,
+ GdkWindow *base_window,
+ GdkGC *gc,
+ gboolean do_children,
+ gint *base_x_offset,
+ gint *base_y_offset)
+{
+ GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
+ GdkRectangle visible_rect;
+ GdkRegion *real_clip_region, *tmpreg;
+ gint x_offset, y_offset;
+ GdkWindowObject *parentwin, *lastwin;
+
+ if (base_x_offset)
+ *base_x_offset = 0;
+ if (base_y_offset)
+ *base_y_offset = 0;
+
+ if (!GDK_WINDOW_IS_MAPPED (window) || private->input_only)
+ return gdk_region_new ();
+
+ window_get_size_rectangle (window, &visible_rect);
+
+ /* windows that a redirection has ben setup for need to be considered
+ * fully visible, in order to avoid missing redirected paint ops
+ * anywhere in the window area.
+ */
+ if (private->redirect && private->redirect->redirected == private)
+ return gdk_region_rectangle (&visible_rect);
+
+ /* real_clip_region is in window coordinates */
+ real_clip_region = gdk_region_rectangle (&visible_rect);
+
+ x_offset = y_offset = 0;
+
+ lastwin = private;
+ if (do_children)
+ parentwin = lastwin;
+ else
+ parentwin = lastwin->parent;
+
+ /* Remove the areas of all overlapping windows above parentwin in the hiearachy */
+ for (; parentwin != NULL && (parentwin == private || lastwin != (GdkWindowObject *)base_window);
+ lastwin = parentwin, parentwin = lastwin->parent)
+ {
+ GList *cur;
+ GdkRectangle real_clip_rect;
+
+ if (parentwin != private)
+ {
+ x_offset += GDK_WINDOW_OBJECT (lastwin)->x;
+ y_offset += GDK_WINDOW_OBJECT (lastwin)->y;
+ }
+
+ /* children is ordered in reverse stack order */
+ for (cur = GDK_WINDOW_OBJECT (parentwin)->children; cur && cur->data != lastwin; cur = cur->next)
+ {
+ GdkWindow *child = cur->data;
+ GdkWindowObject *child_private = (GdkWindowObject *)child;
+
+ if (!GDK_WINDOW_IS_MAPPED (child) || child_private->input_only)
+ continue;
+
+ window_get_size_rectangle (child, &visible_rect);
+
+ /* Convert rect to "window" coords */
+ visible_rect.x += child_private->x - x_offset;
+ visible_rect.y += child_private->y - y_offset;
+
+ /* This shortcut is really necessary for performance when there are a lot of windows */
+ gdk_region_get_clipbox (real_clip_region, &real_clip_rect);
+ if (visible_rect.x >= real_clip_rect.x + real_clip_rect.width ||
+ visible_rect.x + visible_rect.width <= real_clip_rect.x ||
+ visible_rect.y >= real_clip_rect.y + real_clip_rect.height ||
+ visible_rect.y + visible_rect.height <= real_clip_rect.y)
+ continue;
+
+ tmpreg = gdk_region_rectangle (&visible_rect);
+ gdk_region_subtract (real_clip_region, tmpreg);
+ gdk_region_destroy (tmpreg);
+ }
+
+ }
+
+ if (gc)
+ {
+ GdkRegion *clip_region = _gdk_gc_get_clip_region (gc);
+
+ if (clip_region)
+ {
+ /* clip_region is relative to gc clip origin which is relative to the window */
+ /* offset it to window relative: */
+ tmpreg = gdk_region_copy (clip_region);
+ gdk_region_offset (real_clip_region,
+ gc->clip_x_origin,
+ gc->clip_y_origin);
+ /* Intersect it with window hierarchy cliprect: */
+ gdk_region_intersect (real_clip_region, tmpreg);
+ gdk_region_destroy (tmpreg);
+ }
+ }
+
+ if (base_x_offset)
+ *base_x_offset = x_offset;
+ if (base_y_offset)
+ *base_y_offset = y_offset;
+
+ return real_clip_region;
+}
+
+static void
+gdk_window_add_damage (GdkWindow *toplevel,
+ GdkRegion *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;
+ gdk_region_get_clipbox (event.expose.region, &event.expose.area);
+ display = gdk_drawable_get_display (event.expose.window);
+ _gdk_event_queue_append (display, gdk_event_copy (&event));
+}
+
+static void
+setup_redirect_clip (GdkWindow *window,
+ GdkGC *gc,
+ GdkWindowClipData *data)
+{
+ GdkWindowObject *private = (GdkWindowObject *)window;
+ GdkRegion *visible_region;
+ GdkRectangle dest_rect;
+ GdkRegion *tmpreg;
+ GdkWindow *toplevel;
+
+ data->old_region = _gdk_gc_get_clip_region (gc);
+ if (data->old_region)
+ data->old_region = gdk_region_copy (data->old_region);
+
+ data->old_clip_x_origin = gc->clip_x_origin;
+ data->old_clip_y_origin = gc->clip_y_origin;
+
+ toplevel = GDK_WINDOW (private->redirect->redirected);
+
+ /* Get the clip region for gc clip rect + window hierarchy in
+ window relative coords */
+ visible_region =
+ _gdk_window_calculate_full_clip_region (window, toplevel,
+ gc, TRUE,
+ &data->x_offset,
+ &data->y_offset);
+
+ /* Compensate for the source pos/size */
+ data->x_offset -= private->redirect->src_x;
+ data->y_offset -= private->redirect->src_y;
+ dest_rect.x = -data->x_offset;
+ dest_rect.y = -data->y_offset;
+ dest_rect.width = private->redirect->width;
+ dest_rect.height = private->redirect->height;
+ tmpreg = gdk_region_rectangle (&dest_rect);
+ gdk_region_intersect (visible_region, tmpreg);
+ gdk_region_destroy (tmpreg);
+
+ /* Compensate for the dest pos */
+ data->x_offset += private->redirect->dest_x;
+ data->y_offset += private->redirect->dest_y;
+
+ gdk_gc_set_clip_region (gc, visible_region); /* This resets clip origin! */
+
+ /* offset clip and tiles from window coords to pixmaps coords */
+ gdk_gc_offset (gc, -data->x_offset, -data->y_offset);
+
+ /* Offset region to abs coords and add to damage */
+ gdk_region_offset (visible_region, data->x_offset, data->y_offset);
+ gdk_window_add_damage (toplevel, visible_region);
+
+ gdk_region_destroy (visible_region);
+}
+
+static void
+reset_redirect_clip (GdkWindow *offscreen, GdkGC *gc, GdkWindowClipData *data)
+{
+ /* offset back */
+ gdk_gc_offset (gc, data->x_offset, data->y_offset);
+
+ /* reset old clip */
+ gdk_gc_set_clip_region (gc, data->old_region);
+ if (data->old_region)
+ gdk_region_destroy (data->old_region);
+ gdk_gc_set_clip_origin (gc, data->old_clip_x_origin, data->old_clip_y_origin);
+}
+
+static void
+gdk_window_redirect_free (GdkWindowRedirect *redirect)
+{
+ g_object_unref (redirect->pixmap);
+ g_free (redirect);
+}
+
#define __GDK_WINDOW_C__
#include "gdkaliasdef.c"