* 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/.
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "config.h"
#include "gdk.h" /* For gdk_rectangle_union() */
#include "gdkpixmap.h"
#include "gdkdrawable.h"
+#include "gdkintl.h"
#include "gdkscreen.h"
+#include "gdkmarshalers.h"
#include "gdkalias.h"
#undef DEBUG_WINDOW_PRINTING
#include "math.h"
-/* Not all GdkWindows have a corresponding native window.
- * Instead some draw into the nearest parent that has whatss
- * called an "impl", i.e. the implementation window.
- * For toplevel window system windows the impl is always native
- * window, but child windows can also have native windows as
- * this is sometimes necessary. Furthermore, offscreen windows
- * (type GDK_WINDOW_OFFSCREEN) have an impl of type
- * GdkOffscreenWindow rather than a backend implementation native
- * window. Such windows draw into an offscreen pixmap instead
- * of a window and collect damage that lets you paint it where
- * you want.
- *
- * All GdkWindow track their position, size, clip region and
- * absolute position in the impl window. For child window with
- * native windows the clip region is set on the native window
- * as a window shape to make it clip against other non-native windows.
- */
+/* Historically a GdkWindow always matches a platform native window,
+ * be it a toplevel window or a child window. In this setup the
+ * GdkWindow (and other GdkDrawables) were platform independent classes,
+ * and the actual platform specific implementation was in a delegate
+ * object availible as "impl" in the window object.
+ *
+ * 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 GdkPixmap 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 pixmap
+ * 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 pixmap 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 pixmap.
+ *
+ * All drawing to windows are wrapped with macros that set up the GC such that
+ * the offsets and clip region is right for drawing to the paint object or
+ * directly to the emulated window. It also automatically handles any flushing
+ * needed when drawing directly to a window. Adding window/paint clipping is
+ * done using _gdk_gc_add_drawable_clip which lets us efficiently add and then
+ * remove a custom clip region.
+ */
#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,
+ LAST_SIGNAL
+};
+
+enum {
+ PROP_0,
+ PROP_CURSOR
+};
+
struct _GdkWindowPaint
{
GdkRegion *region;
};
typedef struct {
- GdkRegion *region; /* The destination region */
- int dx, dy;
+ GdkRegion *dest_region; /* The destination region */
+ int dx, dy; /* The amount that the source was moved to reach dest_region */
} GdkWindowRegionMove;
/* Global info */
static GdkGC *gdk_window_create_gc (GdkDrawable *drawable,
- GdkGCValues *values,
- GdkGCValuesMask mask);
+ GdkGCValues *values,
+ GdkGCValuesMask mask);
static void gdk_window_draw_rectangle (GdkDrawable *drawable,
- GdkGC *gc,
- gboolean filled,
- gint x,
- gint y,
- gint width,
- gint height);
+ GdkGC *gc,
+ gboolean filled,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
static void gdk_window_draw_arc (GdkDrawable *drawable,
- GdkGC *gc,
- gboolean filled,
- gint x,
- gint y,
- gint width,
- gint height,
- gint angle1,
- gint angle2);
+ GdkGC *gc,
+ gboolean filled,
+ gint x,
+ gint y,
+ gint width,
+ gint height,
+ gint angle1,
+ gint angle2);
static void gdk_window_draw_polygon (GdkDrawable *drawable,
- GdkGC *gc,
- gboolean filled,
- GdkPoint *points,
- gint npoints);
+ GdkGC *gc,
+ gboolean filled,
+ GdkPoint *points,
+ gint npoints);
static void gdk_window_draw_text (GdkDrawable *drawable,
- GdkFont *font,
- GdkGC *gc,
- gint x,
- gint y,
- const gchar *text,
- gint text_length);
+ GdkFont *font,
+ GdkGC *gc,
+ gint x,
+ gint y,
+ const gchar *text,
+ gint text_length);
static void gdk_window_draw_text_wc (GdkDrawable *drawable,
- GdkFont *font,
- GdkGC *gc,
- gint x,
- gint y,
- const GdkWChar *text,
- gint text_length);
+ GdkFont *font,
+ GdkGC *gc,
+ gint x,
+ gint y,
+ const GdkWChar *text,
+ gint text_length);
static void gdk_window_draw_drawable (GdkDrawable *drawable,
- GdkGC *gc,
- GdkPixmap *src,
- gint xsrc,
- gint ysrc,
- gint xdest,
- gint ydest,
- gint width,
- gint height);
+ GdkGC *gc,
+ GdkPixmap *src,
+ gint xsrc,
+ gint ysrc,
+ gint xdest,
+ gint ydest,
+ gint width,
+ gint height,
+ GdkDrawable *original_src);
static void gdk_window_draw_points (GdkDrawable *drawable,
- GdkGC *gc,
- GdkPoint *points,
- gint npoints);
+ GdkGC *gc,
+ GdkPoint *points,
+ gint npoints);
static void gdk_window_draw_segments (GdkDrawable *drawable,
- GdkGC *gc,
- GdkSegment *segs,
- gint nsegs);
+ GdkGC *gc,
+ GdkSegment *segs,
+ gint nsegs);
static void gdk_window_draw_lines (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
PangoGlyphString *glyphs);
static void gdk_window_draw_image (GdkDrawable *drawable,
- GdkGC *gc,
- GdkImage *image,
- gint xsrc,
- gint ysrc,
- gint xdest,
- gint ydest,
- gint width,
- gint height);
+ GdkGC *gc,
+ GdkImage *image,
+ gint xsrc,
+ gint ysrc,
+ gint xdest,
+ gint ydest,
+ gint width,
+ gint height);
static void gdk_window_draw_pixbuf (GdkDrawable *drawable,
GdkGC *gc,
cairo_t *cr);
static void gdk_window_real_get_size (GdkDrawable *drawable,
- gint *width,
- gint *height);
+ gint *width,
+ gint *height);
static GdkVisual* gdk_window_real_get_visual (GdkDrawable *drawable);
static gint gdk_window_real_get_depth (GdkDrawable *drawable);
static void gdk_window_init (GdkWindowObject *window);
static void gdk_window_class_init (GdkWindowObjectClass *klass);
static void gdk_window_finalize (GObject *object);
-static void gdk_window_clear_backing_rect (GdkWindow *window,
- gint x,
- gint y,
- gint width,
- gint height);
+
+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,
+ GdkRegion *region);
static void gdk_window_redirect_free (GdkWindowRedirect *redirect);
static void apply_redirect_to_children (GdkWindowObject *private,
GdkWindowRedirect *redirect);
int dx, int dy);
static void gdk_window_invalidate_in_parent (GdkWindowObject *private);
static void move_native_children (GdkWindowObject *private);
-
+static void update_cursor (GdkDisplay *display);
+static void gdk_window_region_move_free (GdkWindowRegionMove *move);
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
static gpointer parent_class = NULL;
static const cairo_user_data_key_t gdk_window_cairo_key;
sizeof (GdkWindowObject),
(GInstanceInitFunc) gdk_window_init,
0);
-
+
return object_type;
}
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;
+}
+
+/* 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 GQuark quark_pointer_window = 0;
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkDrawableClass *drawable_class = GDK_DRAWABLE_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;
drawable_class->create_gc = gdk_window_create_gc;
drawable_class->draw_rectangle = gdk_window_draw_rectangle;
drawable_class->draw_polygon = gdk_window_draw_polygon;
drawable_class->draw_text = gdk_window_draw_text;
drawable_class->draw_text_wc = gdk_window_draw_text_wc;
- drawable_class->draw_drawable = gdk_window_draw_drawable;
+ drawable_class->draw_drawable_with_src = gdk_window_draw_drawable;
drawable_class->draw_points = gdk_window_draw_points;
drawable_class->draw_segments = gdk_window_draw_segments;
drawable_class->draw_lines = gdk_window_draw_lines;
drawable_class->get_source_drawable = gdk_window_get_source_drawable;
quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window");
+
+
+ /* Properties */
+ g_object_class_install_property (object_class,
+ PROP_CURSOR,
+ g_param_spec_pointer ("cursor",
+ P_("Cursor"),
+ P_("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: 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,
+ 0,
+ 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: return location for the x coordinate in the embedder window
+ * @embedder-y: return location for the y coordinate in the embedder window
+ *
+ * The ::to-embedder signal is emitted to translate coordinates
+ * in an offscreen window to its embedder.
+ *
+ * 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,
+ 0,
+ 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: return location for the x coordinate in the offscreen window
+ * @offscreen-y: return location for the y coordinate in the offscreen window
+ *
+ * The ::from-embedder signal is emitted to translate coordinates
+ * in the embedder of an offscreen window to the offscreen window.
+ *
+ * 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,
+ 0,
+ 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);
}
static void
{
GdkWindow *window = GDK_WINDOW (object);
GdkWindowObject *obj = (GdkWindowObject *) object;
-
+
if (!GDK_WINDOW_DESTROYED (window))
{
if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
g_object_unref (obj->impl_window);
obj->impl_window = NULL;
}
-
+
if (obj->shape)
gdk_region_destroy (obj->shape);
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_pointer (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_pointer (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 (GdkWindowObject *window)
{
- return GDK_WINDOW_TYPE (window) == GDK_WINDOW_OFFSCREEN;
+ return window->window_type == GDK_WINDOW_OFFSCREEN;
}
static GdkWindowObject *
GdkRectangle r;
GList *l;
GdkRegion *shape;
-
+
for (l = private->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 (gdk_region_empty (region))
+ break;
+
if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
continue;
r.width = child->width;
r.height = child->height;
+ /* Bail early if child totally outside region */
+ if (gdk_region_rect_in (region, &r) == GDK_OVERLAP_RECTANGLE_OUT)
+ continue;
+
child_region = gdk_region_rectangle (&r);
-
+
if (child->shape)
- gdk_region_intersect (child_region, child->shape);
+ {
+ /* Adjust shape region to parent window coords */
+ gdk_region_offset (child->shape, child->x, child->y);
+ gdk_region_intersect (child_region, child->shape);
+ gdk_region_offset (child->shape, -child->x, -child->y);
+ }
else if (private->window_type == GDK_WINDOW_FOREIGN)
{
shape = _gdk_windowing_window_get_shape ((GdkWindow *)child);
}
}
}
-
+
gdk_region_subtract (region, child_region);
gdk_region_destroy (child_region);
}
}
+static GdkVisibilityState
+effective_visibility (GdkWindowObject *private)
+{
+ GdkVisibilityState native;
+
+ if (!gdk_window_is_viewable ((GdkWindow *)private))
+ return GDK_VISIBILITY_NOT_VIEWABLE;
+
+ native = private->impl_window->native_visibility;
+
+ if (native == GDK_VISIBILITY_FULLY_OBSCURED ||
+ private->visibility == GDK_VISIBILITY_FULLY_OBSCURED)
+ return GDK_VISIBILITY_FULLY_OBSCURED;
+ else if (native == GDK_VISIBILITY_UNOBSCURED)
+ return private->visibility;
+ else /* native PARTIAL, private partial or unobscured */
+ return GDK_VISIBILITY_PARTIAL;
+}
+
+static void
+gdk_window_update_visibility (GdkWindowObject *private)
+{
+ GdkVisibilityState new_visibility;
+ GdkEvent *event;
+
+ new_visibility = effective_visibility (private);
+
+ if (new_visibility != private->effective_visibility)
+ {
+ private->effective_visibility = new_visibility;
+
+ if (new_visibility != GDK_VISIBILITY_NOT_VIEWABLE &&
+ private->event_mask & GDK_VISIBILITY_NOTIFY)
+ {
+ event = _gdk_make_event ((GdkWindow *)private, GDK_VISIBILITY_NOTIFY,
+ NULL, FALSE);
+ event->visibility.state = new_visibility;
+ }
+ }
+}
+
+static void
+gdk_window_update_visibility_recursively (GdkWindowObject *private,
+ GdkWindowObject *only_for_impl)
+{
+ GdkWindowObject *child;
+ GList *l;
+
+ gdk_window_update_visibility (private);
+ for (l = private->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 void
recompute_visible_regions_internal (GdkWindowObject *private,
gboolean recalculate_clip,
old_abs_x = private->abs_x;
old_abs_y = private->abs_y;
-
+
/* Update absolute position */
if (gdk_window_has_impl (private))
{
clip_region_changed = FALSE;
if (recalculate_clip)
{
- /* 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 = gdk_region_rectangle (&r);
-
- if (private->parent != NULL && GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
+ if (private->viewable)
{
- gdk_region_intersect (new_clip, private->parent->clip_region);
-
- /* Remove all overlapping children from parent */
- remove_child_area (private->parent, private, FALSE, new_clip);
- }
-
- /* Convert from parent coords to window coords */
- gdk_region_offset (new_clip, -private->x, -private->y);
+ /* 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 = gdk_region_rectangle (&r);
+
+ if (private->parent != NULL &&
+ private->parent->window_type != GDK_WINDOW_ROOT)
+ {
+ gdk_region_intersect (new_clip, private->parent->clip_region);
+
+ /* Remove all overlapping children from parent.
+ * Unless we're all native, because then we don't need to take
+ * siblings into account since X does that clipping for us.
+ * This makes things like SWT that modify the raw X stacking
+ * order without GDKs knowledge work.
+ */
+ if (!_gdk_native_windows)
+ remove_child_area (private->parent, private, FALSE, new_clip);
+ }
+
+ /* Convert from parent coords to window coords */
+ gdk_region_offset (new_clip, -private->x, -private->y);
- if (private->shape)
- gdk_region_intersect (new_clip, private->shape);
+ if (private->shape)
+ gdk_region_intersect (new_clip, private->shape);
+ }
+ else
+ new_clip = gdk_region_new ();
if (private->clip_region == NULL ||
!gdk_region_equal (private->clip_region, new_clip))
clip_region_changed = TRUE;
-
+
if (private->clip_region)
gdk_region_destroy (private->clip_region);
private->clip_region = new_clip;
old_clip_region_with_children = private->clip_region_with_children;
private->clip_region_with_children = gdk_region_copy (private->clip_region);
- remove_child_area (private, NULL, FALSE, private->clip_region_with_children);
+ if (private->window_type != GDK_WINDOW_ROOT)
+ remove_child_area (private, NULL, FALSE, private->clip_region_with_children);
if (clip_region_changed ||
!gdk_region_equal (private->clip_region_with_children, old_clip_region_with_children))
gdk_region_destroy (old_clip_region_with_children);
}
- /* Update all children, recursively. */
- if (abs_pos_changed || clip_region_changed || recalculate_children)
+ if (clip_region_changed)
+ {
+ GdkVisibilityState visibility;
+ gboolean fully_visible;
+
+ if (gdk_region_empty (private->clip_region))
+ visibility = GDK_VISIBILITY_FULLY_OBSCURED;
+ else
+ {
+ if (private->shape)
+ {
+ fully_visible = gdk_region_equal (private->clip_region,
+ private->shape);
+ }
+ else
+ {
+ r.x = 0;
+ r.y = 0;
+ r.width = private->width;
+ r.height = private->height;
+ fully_visible = gdk_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)
{
* 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);
+ recompute_visible_regions_internal (child,
+ recalculate_clip && (clip_region_changed || recalculate_children),
+ FALSE, FALSE);
}
}
/* or for non-shaped toplevels */
(private->shaped ||
(private->parent != NULL &&
- GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)) &&
+ private->parent->window_type != GDK_WINDOW_ROOT)) &&
/* or for foreign windows */
- GDK_WINDOW_TYPE (private) != GDK_WINDOW_FOREIGN
+ private->window_type != GDK_WINDOW_FOREIGN &&
+ /* or for the root window */
+ private->window_type != GDK_WINDOW_ROOT
)
{
GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0);
if (recalculate_siblings &&
private->parent != NULL &&
- GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
+ private->parent->window_type != GDK_WINDOW_ROOT)
{
/* 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
_gdk_windowing_set_cairo_surface_size (private->cairo_surface,
width, height);
- cairo_surface_set_device_offset (private->cairo_surface,
+ cairo_surface_set_device_offset (private->cairo_surface,
private->abs_x,
private->abs_y);
}
*
* 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
*/
for (; l != NULL; l = l->prev)
{
w = l->data;
-
+
if (gdk_window_has_impl (w))
return w;
static GdkEventMask
get_native_event_mask (GdkWindowObject *private)
{
- if (GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
- return
- GDK_EXPOSURE_MASK |
- GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
- GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
- GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK |
- GDK_PROXIMITY_IN_MASK | GDK_PROXIMITY_OUT_MASK | GDK_SCROLL_MASK;
+ if (_gdk_native_windows ||
+ private->window_type == GDK_WINDOW_ROOT ||
+ private->window_type == GDK_WINDOW_FOREIGN)
+ return private->event_mask;
else
- return GDK_EXPOSURE_MASK;
+ {
+ return
+ /* We need thse for all native window so we can emulate
+ events on children: */
+ GDK_EXPOSURE_MASK |
+ GDK_VISIBILITY_NOTIFY_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
+ GDK_SCROLL_MASK |
+ /* Then do whatever the app asks to, since the app
+ * may be asking for weird things for native windows,
+ * but filter out things that override the above
+ * requests somehow. */
+ (private->event_mask &
+ ~(GDK_POINTER_MOTION_HINT_MASK |
+ GDK_BUTTON_MOTION_MASK |
+ GDK_BUTTON1_MOTION_MASK |
+ GDK_BUTTON2_MOTION_MASK |
+ GDK_BUTTON3_MOTION_MASK));
+ }
+}
+
+/* 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)
+{
+ GdkWindowObject *above;
+ GdkWindowObject *private;
+ GList listhead = {0};
+
+ private = (GdkWindowObject *) window;
+
+ above = find_native_sibling_above (private->parent, private);
+ if (above)
+ {
+ listhead.data = window;
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above,
+ &listhead);
+ }
}
/**
* 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*
gboolean native;
GdkEventMask event_mask;
GdkWindow *real_parent;
-
+
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);
}
screen = gdk_drawable_get_screen (parent);
g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL);
-
+
if (GDK_WINDOW_DESTROYED (parent))
- return NULL;
+ {
+ g_warning ("gdk_window_new(): parent is destroyed\n");
+ return NULL;
+ }
+
+ if (attributes->window_type == GDK_WINDOW_OFFSCREEN &&
+ _gdk_native_windows)
+ {
+ g_warning ("Offscreen windows not supported with native-windows gdk");
+ return NULL;
+ }
window = g_object_new (GDK_TYPE_WINDOW, NULL);
private = (GdkWindowObject *) window;
x = attributes->x;
else
x = 0;
-
+
if (attributes_mask & GDK_WA_Y)
y = attributes->y;
else
y = 0;
-
+
private->x = x;
private->y = y;
private->width = (attributes->width > 1) ? (attributes->width) : (1);
private->height = (attributes->height > 1) ? (attributes->height) : (1);
#ifdef GDK_WINDOWING_X11
- /* Work around a bug where Xorg refuses to map toplevel InputOnly windows
+ /* Work around a bug where Xorg refuses to map toplevel InputOnly windows
* from an untrusted client: http://bugs.freedesktop.org/show_bug.cgi?id=6988
*/
if (attributes->wclass == GDK_INPUT_ONLY &&
- GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT &&
+ private->parent->window_type == GDK_WINDOW_ROOT &&
!G_LIKELY (GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (parent))->trusted_client))
{
g_warning ("Coercing GDK_INPUT_ONLY toplevel window to GDK_INPUT_OUTPUT to work around bug in Xorg server");
attributes->wclass = GDK_INPUT_OUTPUT;
}
#endif
-
+
if (attributes->wclass == GDK_INPUT_ONLY)
{
/* Backwards compatiblity - we've always ignored
case GDK_WINDOW_TOPLEVEL:
case GDK_WINDOW_DIALOG:
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:
- case GDK_WINDOW_OFFSCREEN:
+ break;
break;
default:
g_warning (G_STRLOC "cannot make windows of type %d", private->window_type);
return NULL;
}
-
+
if (attributes_mask & GDK_WA_VISUAL)
visual = attributes->visual;
else
{
private->input_only = FALSE;
private->depth = visual->depth;
-
- private->bg_color.pixel = 0; // TODO: BlackPixel (xdisplay, screen_x11->screen_num);
+
+ private->bg_color.pixel = 0; /* TODO: BlackPixel (xdisplay, screen_x11->screen_num); */
private->bg_color.red = private->bg_color.green = private->bg_color.blue = 0;
private->bg_pixmap = NULL;
if (private->parent)
private->parent->children = g_list_prepend (private->parent->children, window);
- native = FALSE; /* Default */
- if (GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
+ native = _gdk_native_windows; /* Default */
+ if (private->parent->window_type == GDK_WINDOW_ROOT)
native = TRUE; /* Always use native windows for toplevels */
else if (!private->input_only &&
((attributes_mask & GDK_WA_COLORMAP &&
}
else if (native)
{
- GdkWindowObject *above;
- GList listhead = {0};
-
event_mask = get_native_event_mask (private);
-
+
/* Create the impl */
_gdk_window_impl_new (window, real_parent, screen, visual, event_mask, attributes, attributes_mask);
private->impl_window = private;
/* 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 */
- above = find_native_sibling_above (private->parent, private);
- if (above)
- {
- listhead.data = window;
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above,
- &listhead);
- }
-
+ if (!_gdk_window_has_impl (real_parent))
+ sync_native_window_stack_position (window);
}
else
{
}
recompute_visible_regions (private, TRUE, FALSE);
-
- if (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
+
+ if (private->parent->window_type != GDK_WINDOW_ROOT)
{
/* Inherit redirection from parent */
private->redirect = private->parent->redirect;
}
-
+
gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
(attributes->cursor) :
NULL));
static gboolean
is_parent_of (GdkWindow *parent,
- GdkWindow *child)
+ GdkWindow *child)
{
GdkWindow *w;
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;
*
* Reparents @window into the given @new_parent. The window being
* reparented will be unmapped as a side effect.
- *
+ *
**/
void
gdk_window_reparent (GdkWindow *window,
GdkWindowObject *private;
GdkWindowObject *new_parent_private;
GdkWindowObject *old_parent;
- gboolean show, was_toplevel, was_mapped;
+ GdkScreen *screen;
+ gboolean show, was_mapped;
gboolean do_reparent_to_impl;
-
+ GdkEventMask old_native_event_mask;
+
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);
(new_parent && GDK_WINDOW_DESTROYED (new_parent)))
return;
+ screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
if (!new_parent)
- new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window));
-
+ new_parent = gdk_screen_get_root_window (screen);
+
private = (GdkWindowObject *) window;
new_parent_private = (GdkWindowObject *)new_parent;
/* Don't create loops in hierarchy */
if (is_parent_of (window, new_parent))
return;
-
+
if (private->cairo_surface)
{
/* This might be wrong in the new parent, e.g. for non-native surfaces.
cairo_surface_set_user_data (private->cairo_surface, &gdk_window_cairo_key,
NULL, NULL);
}
-
+
old_parent = private->parent;
/* Break up redirection if inherited */
private->redirect = NULL;
}
- was_toplevel = private->parent == NULL;
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_private->window_type == GDK_WINDOW_ROOT ||
new_parent_private->window_type == GDK_WINDOW_FOREIGN)
- gdk_window_set_has_native (window, TRUE);
+ gdk_window_ensure_native (window);
+ old_native_event_mask = 0;
do_reparent_to_impl = FALSE;
if (gdk_window_has_impl (private))
{
+ old_native_event_mask = get_native_event_mask (private);
/* Native window */
show = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->reparent (window, new_parent, x, y);
}
*/
if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
{
- new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window));
+ new_parent = gdk_screen_get_root_window (screen);
new_parent_private = (GdkWindowObject *)new_parent;
}
- if (private->parent)
- private->parent->children = g_list_remove (private->parent->children, window);
-
+ if (old_parent)
+ old_parent->children = g_list_remove (old_parent->children, window);
+
private->parent = new_parent_private;
private->x = x;
private->y = y;
new_parent_private->children = g_list_prepend (new_parent_private->children, window);
-
+
/* Switch the window type as appropriate */
switch (GDK_WINDOW_TYPE (new_parent))
/* We might have changed window type for a native windows, so we
need to change the event mask too. */
if (gdk_window_has_impl (private))
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_events (window, get_native_event_mask (private));
-
+ {
+ GdkEventMask native_event_mask = get_native_event_mask (private);
+
+ if (native_event_mask != old_native_event_mask)
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_events (window,
+ native_event_mask);
+ }
+
/* Inherit parent redirect if we don't have our own */
if (private->parent && private->redirect == NULL)
{
apply_redirect_to_children (private, private->redirect);
}
+ _gdk_window_update_viewable (window);
+
recompute_visible_regions (private, TRUE, FALSE);
if (old_parent && GDK_WINDOW_TYPE (old_parent) != GDK_WINDOW_ROOT)
recompute_visible_regions (old_parent, FALSE, TRUE);
reparent_to_impl (private);
else
{
- GdkWindowObject *above;
- GList listhead = {0};
-
/* 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 */
- above = find_native_sibling_above (private->parent, private);
- if (above)
- {
- listhead.data = window;
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above,
- &listhead);
- }
+ if (!gdk_window_has_impl (new_parent_private))
+ sync_native_window_stack_position (window);
}
if (show)
gdk_window_show_unraised (window);
else
- _gdk_syntesize_crossing_events_for_geometry_change (window);
+ _gdk_synthesize_crossing_events_for_geometry_change (window);
}
/**
- * gdk_window_set_has_native:
+ * gdk_window_ensure_native:
* @window: a #GdkWindow
- * @has_native: whethe the window should have a native window
*
- * Tries to create or remove a window-system native window for this
- * GdkWindow. This may fail in some situations. For instance:
+ * Tries to ensure that there is a window-system native window for this
+ * GdkWindow. This may fail in some situations, returning %FALSE.
*
- * Toplevel and foreign windows must have a native window.
* Offscreen window and children of them can never have native windows.
+ *
* Some backends may not support native child windows.
- *
- **/
-void
-gdk_window_set_has_native (GdkWindow *window, gboolean has_native)
+ *
+ * Returns: %TRUE if the window has a native window, %FALSE otherwise
+ *
+ * Since: 2.18
+ */
+gboolean
+gdk_window_ensure_native (GdkWindow *window)
{
GdkWindowObject *private;
GdkWindowObject *impl_window;
GdkWindowObject *above;
GList listhead;
- g_return_if_fail (GDK_IS_WINDOW (window));
+ g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT ||
GDK_WINDOW_DESTROYED (window))
- return;
+ return FALSE;
private = (GdkWindowObject *) window;
-
- if (has_native)
- {
- /* Create native window */
-
- if (gdk_window_has_impl (private))
- /* Already has an impl, either native (ok) or
- offscreen (not supported). Bail. */
- return;
-
- impl_window = gdk_window_get_impl_window (private);
- if (impl_window->window_type == GDK_WINDOW_OFFSCREEN)
- return; /* native in offscreens not supported */
-
- screen = gdk_drawable_get_screen (window);
- visual = gdk_drawable_get_visual (window);
-
- attributes.colormap = gdk_drawable_get_colormap (window);
-
- old_impl = private->impl;
- _gdk_window_impl_new (window, (GdkWindow *)private->parent, screen, visual,
- get_native_event_mask (private), &attributes, GDK_WA_COLORMAP);
- new_impl = private->impl;
-
- private->impl = old_impl;
- change_impl (private, private, new_impl);
-
- /* Native window creation 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 */
- above = find_native_sibling_above (private->parent, private);
- if (above)
- {
- listhead.data = window;
- listhead.prev = NULL;
- listhead.next = NULL;
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above,
- &listhead);
- }
-
- recompute_visible_regions (private, FALSE, FALSE);
- /* The shape may not have been set, as the clip region doesn't actually
- change, so do it here manually */
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0);
+ impl_window = gdk_window_get_impl_window (private);
- reparent_to_impl (private);
+ if (impl_window->window_type == GDK_WINDOW_OFFSCREEN)
+ return FALSE; /* native in offscreens not supported */
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_background (window, &private->bg_color);
- if (private->bg_pixmap != NULL)
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, private->bg_pixmap);
-
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->input_shape_combine_region ((GdkWindow *)private, private->input_shape, 0, 0);
+ if (impl_window == private)
+ /* Already has an impl, and its not offscreen . */
+ return TRUE;
- if (gdk_window_is_viewable (window))
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window);
+ /* Need to create a native window */
- /* We sync here to ensure the window is created in the Xserver when
- * this function returns. This is required because the returned XID
- * for this window must be valid immediately, even with another
- * connection to the Xserver */
- gdk_display_sync (gdk_drawable_get_display (window));
- }
- else
- {
- /* Remove native window */
+ screen = gdk_drawable_get_screen (window);
+ visual = gdk_drawable_get_visual (window);
- if (!gdk_window_has_impl (private))
- return; /* Not native, can't remove */
+ attributes.colormap = gdk_drawable_get_colormap (window);
- if (private->window_type == GDK_WINDOW_OFFSCREEN)
- return; /* Not native, can't remove */
-
- if (private->parent == NULL ||
- GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
- return; /* toplevel, must be native */
+ old_impl = private->impl;
+ _gdk_window_impl_new (window, (GdkWindow *)private->parent, screen, visual,
+ get_native_event_mask (private), &attributes, GDK_WA_COLORMAP);
+ new_impl = private->impl;
- g_warning ("Tried to turn native window to client side window, this is not supported yet.");
+ private->impl = old_impl;
+ change_impl (private, private, new_impl);
- /* TODO: remove native */
+ /* 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 (private->parent, private);
+ if (above)
+ {
+ listhead.data = window;
+ listhead.prev = NULL;
+ listhead.next = NULL;
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above,
+ &listhead);
+ }
+
+ recompute_visible_regions (private, FALSE, FALSE);
+
+ /* The shape may not have been set, as the clip region doesn't actually
+ change, so do it here manually */
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0);
+
+ reparent_to_impl (private);
+
+ if (!private->input_only)
+ {
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_background (window, &private->bg_color);
+ if (private->bg_pixmap != NULL)
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, private->bg_pixmap);
}
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->input_shape_combine_region ((GdkWindow *)private, private->input_shape, 0, 0);
+
+ if (gdk_window_is_viewable (window))
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window, FALSE);
+
+ return TRUE;
}
static void
if (obj->filters)
{
GList *tmp_list;
-
+
for (tmp_list = obj->filters; tmp_list; tmp_list = tmp_list->next)
g_free (tmp_list->data);
-
+
g_list_free (obj->filters);
obj->filters = NULL;
}
* _gdk_window_destroy_hierarchy:
* @window: a #GdkWindow
* @recursing: If TRUE, then this is being called because a parent
- * was destroyed. This generally means that the call to the
+ * 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
+ * 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.)
*
static void
_gdk_window_destroy_hierarchy (GdkWindow *window,
gboolean recursing,
+ gboolean recursing_native,
gboolean foreign_destroy)
{
GdkWindowObject *private;
g_return_if_fail (GDK_IS_WINDOW (window));
private = (GdkWindowObject*) window;
-
+
if (GDK_WINDOW_DESTROYED (window))
return;
-
+
display = gdk_drawable_get_display (GDK_DRAWABLE (window));
screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
temp_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
g_object_set_qdata (G_OBJECT (screen), quark_pointer_window, NULL);
- switch (GDK_WINDOW_TYPE (window))
+ switch (private->window_type)
{
case GDK_WINDOW_ROOT:
if (!screen->closed)
case GDK_WINDOW_TEMP:
case GDK_WINDOW_FOREIGN:
case GDK_WINDOW_OFFSCREEN:
- if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_FOREIGN && !foreign_destroy)
+ if (private->window_type == GDK_WINDOW_FOREIGN && !foreign_destroy)
{
/* Logically, it probably makes more sense to send
* a "destroy yourself" message to the foreign window
}
gdk_window_free_paint_stack (window);
-
+
if (private->bg_pixmap &&
- private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
- private->bg_pixmap != GDK_NO_BG)
+ private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
+ private->bg_pixmap != GDK_NO_BG)
{
g_object_unref (private->bg_pixmap);
private->bg_pixmap = NULL;
}
-
- if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_FOREIGN)
+
+ if (private->window_type == GDK_WINDOW_FOREIGN)
g_assert (private->children == NULL);
else
{
children = tmp = private->children;
private->children = NULL;
-
+
while (tmp)
{
temp_window = tmp->data;
tmp = tmp->next;
-
+
temp_private = (GdkWindowObject*) temp_window;
if (temp_private)
_gdk_window_destroy_hierarchy (temp_window,
- TRUE, foreign_destroy);
+ TRUE,
+ recursing_native || gdk_window_has_impl (private),
+ foreign_destroy);
}
-
+
g_list_free (children);
}
- _gdk_window_clear_update_area (window);
-
+ _gdk_window_clear_update_area (window);
+
if (private->cairo_surface)
{
cairo_surface_finish (private->cairo_surface);
NULL, NULL);
}
+
+ if (private->extension_events)
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->input_window_destroy (window);
+
if (gdk_window_has_impl (private))
{
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->destroy (window, recursing, foreign_destroy);
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->destroy (window, recursing_native, foreign_destroy);
}
else
{
window_remove_filters (window);
- gdk_drawable_set_colormap (GDK_DRAWABLE (window), NULL);
+ gdk_drawable_set_colormap (GDK_DRAWABLE (window), NULL);
/* If we own the redirect, free it */
if (private->redirect && private->redirect->redirected == private)
g_object_unref (display->pointer_info.toplevel_under_pointer);
display->pointer_info.toplevel_under_pointer = NULL;
}
+
+ if (private->clip_region)
+ {
+ gdk_region_destroy (private->clip_region);
+ private->clip_region = NULL;
+ }
+
+ if (private->clip_region_with_children)
+ {
+ gdk_region_destroy (private->clip_region_with_children);
+ private->clip_region_with_children = NULL;
+ }
+
+ if (private->outstanding_moves)
+ {
+ g_list_foreach (private->outstanding_moves, (GFunc)gdk_window_region_move_free, NULL);
+ g_list_free (private->outstanding_moves);
+ private->outstanding_moves = NULL;
+ }
}
break;
}
_gdk_window_destroy (GdkWindow *window,
gboolean foreign_destroy)
{
- _gdk_window_destroy_hierarchy (window, FALSE, foreign_destroy);
+ _gdk_window_destroy_hierarchy (window, FALSE, FALSE, foreign_destroy);
}
/**
void
gdk_window_destroy (GdkWindow *window)
{
- _gdk_window_destroy_hierarchy (window, FALSE, FALSE);
+ _gdk_window_destroy_hierarchy (window, FALSE, FALSE, FALSE);
g_object_unref (window);
}
* 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,
*
* 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,
/**
* 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);
}
* received or processed.
*
* The position coordinates are relative to the window's parent window.
- *
+ *
**/
void
gdk_window_get_position (GdkWindow *window,
gint *y)
{
GdkWindowObject *obj;
-
+
g_return_if_fail (GDK_IS_WINDOW (window));
-
+
obj = (GdkWindowObject*) window;
-
+
if (x)
*x = obj->x;
if (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.
- *
+ *
* Return value: parent of @window
**/
GdkWindow*
gdk_window_get_parent (GdkWindow *window)
{
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
-
+
return (GdkWindow*) ((GdkWindowObject*) 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.
- *
+ * has a root window as parent.
+ *
* Return value: the toplevel window containing @window
**/
GdkWindow*
gdk_window_get_toplevel (GdkWindow *window)
{
GdkWindowObject *obj;
-
+
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
obj = (GdkWindowObject *)window;
-
- while (GDK_WINDOW_TYPE (obj) == GDK_WINDOW_CHILD)
+
+ while (obj->window_type == GDK_WINDOW_CHILD)
{
if (obj->parent == NULL ||
- GDK_WINDOW_TYPE (obj->parent) == GDK_WINDOW_ROOT)
+ obj->parent->window_type == GDK_WINDOW_ROOT)
break;
obj = obj->parent;
}
-
+
return GDK_WINDOW (obj);
}
/**
* 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;
*
* The returned list must be freed, but the elements in the
* list need not be.
- *
+ *
* Return value: list of child windows inside @window
**/
GList*
/**
* 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: a reference to the list of child windows in @window
**/
GList *
* See gdk_display_add_client_message_filter() if you are interested
* in X ClientMessage events.
**/
-void
+void
gdk_window_add_filter (GdkWindow *window,
GdkFilterFunc function,
gpointer data)
GdkWindowObject *private;
GList *tmp_list;
GdkEventFilter *filter;
-
+
g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
private = (GdkWindowObject*) window;
/* Filters are for the native events on the native window, so
ensure there is a native window. */
if (window)
- gdk_window_set_has_native (window, TRUE);
-
+ gdk_window_ensure_native (window);
+
if (private)
tmp_list = private->filters;
else
tmp_list = _gdk_default_filters;
-
+
while (tmp_list)
{
filter = (GdkEventFilter *)tmp_list->data;
return;
tmp_list = tmp_list->next;
}
-
+
filter = g_new (GdkEventFilter, 1);
filter->function = function;
filter->data = data;
-
+
if (private)
private->filters = g_list_append (private->filters, filter);
else
* @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,
GdkWindowObject *private;
GList *tmp_list, *node;
GdkEventFilter *filter;
-
+
g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
private = (GdkWindowObject*) window;
-
+
if (private)
tmp_list = private->filters;
else
tmp_list = _gdk_default_filters;
-
+
while (tmp_list)
{
filter = (GdkEventFilter *)tmp_list->data;
node = tmp_list;
tmp_list = tmp_list->next;
-
+
if ((filter->function == function) && (filter->data == data))
{
if (private)
_gdk_default_filters = g_list_remove_link (_gdk_default_filters, node);
g_list_free_1 (node);
g_free (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: list of toplevel windows, free with g_list_free()
*
* Since: 2.2
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 = ((GdkWindowObject *)root_window)->children;
while (tmp_list)
{
- if (GDK_WINDOW_TYPE (tmp_list->data) != GDK_WINDOW_FOREIGN)
- new_list = g_list_prepend (new_list, tmp_list->data);
+ GdkWindowObject *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_get_toplevels:
- *
+ *
* Obtains a list of all toplevel windows known to GDK on the default
* screen (see gdk_screen_get_toplevel_windows()).
* A toplevel window is a child of the root window (see
*
* The returned list should be freed with g_list_free(), but
* its elements need not be freed.
- *
+ *
* Return value: list of toplevel windows, free with g_list_free()
*
* Deprecated: 2.16: Use gdk_screen_get_toplevel_windows() instead.
/**
* 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
+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
*
* Return value: %TRUE if the window is viewable
**/
-gboolean
+gboolean
gdk_window_is_viewable (GdkWindow *window)
{
GdkWindowObject *private = (GdkWindowObject *)window;
- GdkScreen *screen;
- GdkWindow *root_window;
g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
- screen = gdk_drawable_get_screen (window);
- root_window = gdk_screen_get_root_window (screen);
-
- while (private &&
- (private != (GdkWindowObject *)root_window) &&
- (GDK_WINDOW_TYPE (private) != GDK_WINDOW_FOREIGN))
- {
- if (GDK_WINDOW_DESTROYED (private) || !GDK_WINDOW_IS_MAPPED (private))
- return FALSE;
-
- private = (GdkWindowObject *)private->parent;
- }
-
- return TRUE;
+ if (private->destroyed)
+ return FALSE;
+
+ return private->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)
{
GdkWindowObject *private = (GdkWindowObject *)window;
-
+
g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
-
+
return private->state;
}
g_assert (gdk_window_has_impl (private));
+ if (_gdk_native_windows)
+ return FALSE; /* No need for implicit paints since we can't merge draws anyway */
+
if (GDK_IS_PAINTABLE (private->impl))
return FALSE; /* Implementation does double buffering */
-
+
if (private->paint_stack != NULL ||
private->implicit_paint != NULL)
return FALSE; /* Don't stack implicit paints */
MAX (rect->width, 1), MAX (rect->height, 1), -1);
private->implicit_paint = paint;
-
+
return TRUE;
}
/* Ensure that all content related to this (sub)window is pushed to the
- native region */
+ native region. If there is an active paint then that area is not
+ pushed, in order to not show partially finished double buffers. */
static void
gdk_window_flush_implicit_paint (GdkWindow *window)
{
GdkWindowPaint *paint;
GdkRegion *region;
GdkGC *tmp_gc;
+ GSList *list;
- /* Ensure that there is no explicit paint region. */
- g_assert (private->paint_stack == NULL);
-
impl_window = gdk_window_get_impl_window (private);
if (impl_window->implicit_paint == NULL)
return;
paint = impl_window->implicit_paint;
region = gdk_region_copy (private->clip_region_with_children);
+
+ /* Don't flush active double buffers, as that may show partially done
+ * rendering */
+ for (list = private->paint_stack; list != NULL; list = list->next)
+ {
+ GdkWindowPaint *tmp_paint = list->data;
+
+ gdk_region_subtract (region, tmp_paint->region);
+ }
+
gdk_region_offset (region, private->abs_x, private->abs_y);
gdk_region_intersect (region, paint->region);
-
+
if (!gdk_region_empty (region))
{
/* Some regions are valid, push these to window now */
private->implicit_paint = NULL;
- gdk_window_flush_outstanding_moves (window);
-
if (!gdk_region_empty (paint->region))
{
/* Some regions are valid, push these to window now */
/* Reset clip region of the cached GdkGC */
gdk_gc_set_clip_region (tmp_gc, NULL);
}
-
+
g_object_unref (paint->pixmap);
g_free (paint);
}
* 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)
+ const GdkRectangle *rectangle)
{
GdkRegion *region;
gdk_region_destroy (region);
}
-#ifdef GDK_WINDOWING_X11
-#include "x11/gdkx.h"
-#endif
-
/**
* gdk_window_begin_paint_region:
* @window: a #GdkWindow
* 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
+void
gdk_window_begin_paint_region (GdkWindow *window,
- const GdkRegion *region)
+ const GdkRegion *region)
{
#ifdef USE_BACKING_STORE
GdkWindowObject *private = (GdkWindowObject *)window;
GdkWindowPaint *paint, *implicit_paint;
GdkWindowObject *impl_window;
GSList *list;
- GList *l;
- GdkWindowRegionMove *move;
g_return_if_fail (GDK_IS_WINDOW (window));
if (GDK_WINDOW_DESTROYED (window))
return;
- if (GDK_IS_PAINTABLE (private->impl))
+ 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, window, region);
-
+ iface->begin_paint_region ((GdkPaintable*)private->impl, window, region);
+
return;
}
gdk_region_offset (paint->region, private->abs_x, private->abs_y);
/* Mark the region as valid on the implicit paint */
-
+
if (implicit_paint)
gdk_region_union (implicit_paint->region, paint->region);
- /* No need to do any moves that will end up over the exposed area */
- for (l = impl_window->outstanding_moves; l != NULL; l = l->next)
- {
- move = l->data;
- gdk_region_subtract (move->region, paint->region);
- }
-
/* Convert back to normal coords */
gdk_region_offset (paint->region, -private->abs_x, -private->abs_y);
-
+
if (implicit_paint)
{
int width, height;
-
+
paint->uses_implicit = TRUE;
paint->pixmap = g_object_ref (implicit_paint->pixmap);
paint->x_offset = -private->abs_x + implicit_paint->x_offset;
paint->y_offset = -private->abs_y + implicit_paint->y_offset;
-
- /* It would be nice if we had some cairo support here so we
- could set the clip rect on the cairo surface */
- width = private->abs_x + private->width;
- height = private->abs_y + private->height;
-
- paint->surface = _gdk_drawable_create_cairo_surface (paint->pixmap, width, height);
+ gdk_drawable_get_size (paint->pixmap, &width, &height);
+ paint->surface = _gdk_drawable_create_cairo_surface (paint->pixmap, width, height);
}
else
{
MAX (clip_box.width, 1), MAX (clip_box.height, 1), -1);
paint->surface = _gdk_drawable_ref_cairo_surface (paint->pixmap);
}
-
+
if (paint->surface)
cairo_surface_set_device_offset (paint->surface,
-paint->x_offset, -paint->y_offset);
-
+
for (list = private->paint_stack; list != NULL; list = list->next)
{
GdkWindowPaint *tmp_paint = list->data;
gdk_region_subtract (tmp_paint->region, paint->region);
}
-
+
private->paint_stack = g_slist_prepend (private->paint_stack, paint);
if (!gdk_region_empty (paint->region))
{
- gdk_window_clear_backing_rect (window,
- clip_box.x, clip_box.y,
- clip_box.width, clip_box.height);
+ gdk_window_clear_backing_region (window,
+ paint->region);
}
#endif /* USE_BACKING_STORE */
int x_offset, y_offset;
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,
TRUE,
- &x_offset,
+ &x_offset,
&y_offset);
/* Compensate for the source pos/size */
* 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)
GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (private->impl);
if (iface->end_paint)
- iface->end_paint ((GdkPaintable*)private->impl);
+ iface->end_paint ((GdkPaintable*)private->impl);
return;
}
paint = private->paint_stack->data;
- private->paint_stack = g_slist_delete_link (private->paint_stack,
+ private->paint_stack = g_slist_delete_link (private->paint_stack,
private->paint_stack);
gdk_region_get_clipbox (paint->region, &clip_box);
if (!paint->uses_implicit)
{
gdk_window_flush_outstanding_moves (window);
-
+
full_clip = gdk_region_copy (private->clip_region_with_children);
gdk_region_intersect (full_clip, paint->region);
_gdk_gc_set_clip_region_internal (tmp_gc, full_clip, TRUE); /* Takes ownership of full_clip */
clip_box.x - x_offset, clip_box.y - y_offset,
clip_box.width, clip_box.height);
}
-
+
if (private->redirect)
{
int x_offset, y_offset;
clip_box.y + y_offset,
clip_box.width, clip_box.height);
}
-
+
/* Reset clip region of the cached GdkGC */
gdk_gc_set_clip_region (tmp_gc, NULL);
gdk_window_free_paint_stack (GdkWindow *window)
{
GdkWindowObject *private = (GdkWindowObject *)window;
-
+
if (private->paint_stack)
{
GSList *tmp_list = private->paint_stack;
if (tmp_list == private->paint_stack)
g_object_unref (paint->pixmap);
-
+
gdk_region_destroy (paint->region);
g_free (paint);
}
static void
-do_move_region_bits_on_impl (GdkWindowObject *private,
- GdkRegion *region, /* In impl window coords */
+do_move_region_bits_on_impl (GdkWindowObject *impl_window,
+ GdkRegion *dest_region, /* In impl window coords */
int dx, int dy)
{
GdkGC *tmp_gc;
GdkRectangle copy_rect;
- GdkDrawable *dest;
-
- dest = private->impl;
-
- gdk_region_get_clipbox (region, ©_rect);
+ GdkWindowObject *private;
/* We need to get data from subwindows here, because we might have
* shaped a native window over the moving region (with bg none,
* from overlapping native window that are not children of this window,
* so we copy from the toplevel with INCLUDE_INFERIORS.
*/
- private = gdk_window_get_impl_window (private);
+ private = impl_window;
while (private->parent != NULL &&
- GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
+ private->parent->window_type != GDK_WINDOW_ROOT)
{
dx -= private->parent->abs_x + private->x;
dy -= private->parent->abs_y + private->y;
private = gdk_window_get_impl_window (private->parent);
}
tmp_gc = _gdk_drawable_get_subwindow_scratch_gc ((GdkWindow *)private);
- gdk_gc_set_clip_region (tmp_gc, region);
- gdk_draw_drawable (dest,
+
+ gdk_region_get_clipbox (dest_region, ©_rect);
+ gdk_gc_set_clip_region (tmp_gc, dest_region);
+
+ /* The region area is moved and we queue translations for all expose events
+ to the source area that were sent prior to the copy */
+ gdk_region_offset (dest_region, -dx, -dy); /* Move to source region */
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->queue_translation ((GdkWindow *)impl_window,
+ tmp_gc,
+ dest_region, dx, dy);
+
+ gdk_draw_drawable (impl_window->impl,
tmp_gc,
private->impl,
copy_rect.x-dx, copy_rect.y-dy,
gdk_gc_set_clip_region (tmp_gc, NULL);
}
-static void
-append_move_region (GdkWindowObject *impl_window,
- GdkRegion *region,
- int dx, int dy)
+static GdkWindowRegionMove *
+gdk_window_region_move_new (GdkRegion *region,
+ int dx, int dy)
{
- GList *moves_to_add, *l, *s;
- GdkRegion *intersection;
- GdkWindowRegionMove *move, *new_move, *existing_move;
-
+ GdkWindowRegionMove *move;
+
move = g_slice_new (GdkWindowRegionMove);
- move->region = region;
+ move->dest_region = gdk_region_copy (region);
move->dx = dx;
move->dy = dy;
- moves_to_add = g_list_prepend (NULL, move);
+ return move;
+}
- for (l = impl_window->outstanding_moves; l != NULL; l = l->next)
- {
- existing_move = l->data;
-
- for (s = moves_to_add; s != NULL; s = s->next)
- {
- move = s->data;
+static void
+gdk_window_region_move_free (GdkWindowRegionMove *move)
+{
+ gdk_region_destroy (move->dest_region);
+ g_slice_free (GdkWindowRegionMove, move);
+}
+
+static void
+append_move_region (GdkWindowObject *impl_window,
+ GdkRegion *new_dest_region,
+ int dx, int dy)
+{
+ GdkWindowRegionMove *move, *old_move;
+ GdkRegion *new_total_region, *old_total_region;
+ GdkRegion *source_overlaps_destination;
+ GdkRegion *non_overwritten;
+ gboolean added_move;
+ GList *l, *prev;
- intersection = gdk_region_copy (move->region);
- gdk_region_offset (intersection, -move->dx, -move->dy);
- gdk_region_intersect (intersection, existing_move->region);
- gdk_region_offset (intersection, move->dx, move->dy);
+ if (gdk_region_empty (new_dest_region))
+ return;
- if (!gdk_region_empty (intersection))
+ /* 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 = gdk_region_copy (new_dest_region);
+ gdk_region_offset (new_total_region, -dx, -dy);
+ gdk_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 = gdk_region_copy (old_move->dest_region);
+ gdk_region_offset (old_total_region, -old_move->dx, -old_move->dy);
+ gdk_region_union (old_total_region, old_move->dest_region);
+
+ gdk_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 (!gdk_region_empty (old_total_region))
+ {
+ /* The area where the new moves source overlaps the old ones
+ destination */
+ source_overlaps_destination = gdk_region_copy (new_dest_region);
+ gdk_region_offset (source_overlaps_destination, -dx, -dy);
+ gdk_region_intersect (source_overlaps_destination, old_move->dest_region);
+ gdk_region_offset (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 (gdk_region_equal (source_overlaps_destination, new_dest_region))
{
-
- new_move = g_slice_new (GdkWindowRegionMove);
- new_move->region = intersection;
- new_move->dx = move->dx + existing_move->dx;
- new_move->dy = move->dy + existing_move->dy;
- moves_to_add = g_list_prepend (moves_to_add, new_move);
-
- gdk_region_subtract (move->region, intersection);
- gdk_region_subtract (existing_move->region, intersection);
+ /* 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 = gdk_region_copy (old_move->dest_region);
+ gdk_region_subtract (non_overwritten, new_dest_region);
+ /* move to source region */
+ gdk_region_offset (non_overwritten, -old_move->dx, -old_move->dy);
+
+ gdk_region_intersect (non_overwritten, new_dest_region);
+ if (gdk_region_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);
+ gdk_region_subtract (old_move->dest_region, new_dest_region);
+ }
+ gdk_region_destroy (non_overwritten);
}
- else
- gdk_region_destroy (intersection);
+
+ gdk_region_destroy (source_overlaps_destination);
+ gdk_region_destroy (old_total_region);
+ break;
}
+ gdk_region_destroy (old_total_region);
}
- impl_window->outstanding_moves = g_list_concat (impl_window->outstanding_moves,
- moves_to_add);
-
+ gdk_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.
- */
+/* 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 (GdkWindowObject *private,
GdkRegion *region, /* In impl window coords */
int dx, int dy)
{
GdkWindowObject *impl_window;
- gboolean free_region;
if ((dx == 0 && dy == 0) ||
gdk_region_empty (region))
gdk_region_destroy (region);
return;
}
-
- free_region = TRUE;
- impl_window = gdk_window_get_impl_window (private);
- if (1) /* Enable flicker free handling of moves. */
- {
- free_region = FALSE;
+ impl_window = gdk_window_get_impl_window (private);
- append_move_region (impl_window, region, dx, dy);
- }
- else
- do_move_region_bits_on_impl (private,
- region, dx, dy);
-
/* Move any old invalid regions in the copy source area by dx/dy */
if (impl_window->update_area)
{
GdkRegion *update_area;
-
update_area = gdk_region_copy (region);
+
/* Convert from target to source */
gdk_region_offset (update_area, -dx, -dy);
gdk_region_intersect (update_area, impl_window->update_area);
- gdk_region_subtract (impl_window->update_area, 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 */
gdk_region_offset (update_area, dx, dy);
gdk_region_union (impl_window->update_area, update_area);
+
+ /* This area of the destination is now invalid,
+ so no need to copy to it. */
+ gdk_region_subtract (region, update_area);
+
gdk_region_destroy (update_area);
}
- if (free_region)
- gdk_region_destroy (region);
+ if (1) /* Enable flicker free handling of moves. */
+ append_move_region (impl_window, region, dx, dy);
+ else
+ do_move_region_bits_on_impl (impl_window,
+ region, dx, dy);
+
+ gdk_region_destroy (region);
}
/* Flushes all outstanding changes to the window, call this
GdkWindowRegionMove *move;
private = (GdkWindowObject *) window;
-
+
impl_window = gdk_window_get_impl_window (private);
-
+
for (l = impl_window->outstanding_moves; l != NULL; l = l->next)
{
move = l->data;
- do_move_region_bits_on_impl (private,
- move->region, move->dx, move->dy);
+ do_move_region_bits_on_impl (impl_window,
+ move->dest_region, move->dx, move->dy);
- gdk_region_destroy (move->region);
- g_slice_free (GdkWindowRegionMove, move);
+ gdk_window_region_move_free (move);
}
-
+
g_list_free (impl_window->outstanding_moves);
impl_window->outstanding_moves = NULL;
}
{
GdkWindowObject *child;
GList *l;
-
+
for (l = window->children; l != NULL; l = l->next)
{
child = l->data;
/**
* gdk_window_get_internal_paint_info:
* @window: a #GdkWindow
- * @real_drawable: location to store the drawable to which drawing should be
+ * @real_drawable: location to store the drawable to which drawing should be
* done.
* @x_offset: location to store the X offset between coordinates in @window,
- * and the underlying window system primitive coordinates for
+ * and the underlying window system primitive coordinates for
* *@real_drawable.
* @y_offset: location to store the Y offset between coordinates in @window,
* and the underlying window system primitive coordinates for
* *@real_drawable.
- *
+ *
* If you bypass the GDK layer and use windowing system primitives to
* draw directly onto a #GdkWindow, then you need to deal with two
* details: there may be an offset between GDK coordinates and windowing
gint *y_offset)
{
gint x_off, y_off;
-
+
GdkWindowObject *private;
g_return_if_fail (GDK_IS_WINDOW (window));
*y_offset = y_off;
}
-static void
-setup_clip_for_draw (GdkDrawable *drawable,
- GdkGC *gc,
- int old_clip_x, int old_clip_y)
+static GdkDrawable *
+start_draw_helper (GdkDrawable *drawable,
+ GdkGC *gc,
+ gint *x_offset_out,
+ gint *y_offset_out)
{
GdkWindowObject *private = (GdkWindowObject *)drawable;
+ gint x_offset, y_offset;
+ GdkDrawable *impl;
+ gint old_clip_x = gc->clip_x_origin;
+ gint old_clip_y = gc->clip_y_origin;
GdkRegion *clip;
+ guint32 clip_region_tag;
+ GdkWindowPaint *paint;
- if (private->window_type == GDK_WINDOW_ROOT)
- return;
-
- if (_gdk_gc_get_subwindow (gc) == GDK_CLIP_BY_CHILDREN)
- clip = private->clip_region_with_children;
- else
- clip = private->clip_region;
-
- _gdk_gc_add_drawable_clip (gc,
- private->clip_tag,
- clip,
- /* If there was a clip origin set appart from the
- * window offset, need to take that into consideration */
- -old_clip_x, -old_clip_y);
-}
+ paint = NULL;
+ if (private->paint_stack)
+ paint = private->paint_stack->data;
-static void
-setup_clip_for_paint (GdkDrawable *drawable,
- GdkWindowPaint *paint,
- GdkGC *gc,
- int old_clip_x, int old_clip_y)
-{
- _gdk_gc_add_drawable_clip (gc,
- paint->region_tag,
- /* This includes the window clip */
- paint->region,
- /* If there was a clip origin set appart from the
- * window offset, need to take that into consideration */
- -old_clip_x, -old_clip_y);
-}
-
-
-#define OFFSET_GC(gc) \
- gint x_offset, y_offset; \
- gint old_clip_x = gc->clip_x_origin; \
- gint old_clip_y = gc->clip_y_origin; \
- gint old_ts_x = gc->ts_x_origin; \
- gint old_ts_y = gc->ts_y_origin; \
- gdk_window_get_offsets (drawable, &x_offset, &y_offset); \
- if (x_offset != 0 || y_offset != 0) \
- { \
- gdk_gc_set_clip_origin (gc, old_clip_x - x_offset, \
- old_clip_y - y_offset); \
- gdk_gc_set_ts_origin (gc, old_ts_x - x_offset, \
- old_ts_y - y_offset); \
- }
-
-#define RESTORE_GC(gc) \
- if (x_offset != 0 || y_offset != 0) \
- { \
- gdk_gc_set_clip_origin (gc, old_clip_x, old_clip_y); \
- gdk_gc_set_ts_origin (gc, old_ts_x, old_ts_y); \
- }
+ if (paint)
+ {
+ x_offset = paint->x_offset;
+ y_offset = paint->y_offset;
+ }
+ else
+ {
+ x_offset = -private->abs_x;
+ y_offset = -private->abs_y;
+ }
-#define SETUP_PAINT_GC_CLIP(gc) \
- if (paint->uses_implicit) \
- setup_clip_for_paint (drawable, paint, gc, old_clip_x, \
- old_clip_y);
+ if (x_offset != 0 || y_offset != 0)
+ {
+ gdk_gc_set_clip_origin (gc,
+ old_clip_x - x_offset,
+ old_clip_y - y_offset);
+ gdk_gc_set_ts_origin (gc,
+ gc->ts_x_origin - x_offset,
+ gc->ts_y_origin - y_offset);
+ }
-#define RESTORE_PAINT_GC_CLIP(gc)
+ *x_offset_out = x_offset;
+ *y_offset_out = y_offset;
+ /* Add client side window clip region to gc */
+ clip = NULL;
+ if (paint)
+ {
+ /* Only need clipping if using implicit paint, otherwise
+ the pixmap is clipped when copying to the window in end_paint */
+ if (paint->uses_implicit)
+ {
+ /* This includes the window clip */
+ clip = paint->region;
+ }
+ clip_region_tag = paint->region_tag;
-#define SETUP_DIRECT_GC_CLIP(gc) \
- gdk_window_flush ((GdkWindow *)drawable);\
- setup_clip_for_draw (drawable, gc, old_clip_x, old_clip_y);
+ /* After having set up the drawable clip rect on a GC we need to make sure
+ * that we draw to th the impl, otherwise the pixmap code will reset the
+ * drawable clip. */
+ impl = ((GdkPixmapObject *)(paint->pixmap))->impl;
+ }
+ else
+ {
+ /* Drawing directly to the window, flush anything outstanding to
+ guarantee ordering. */
+ gdk_window_flush ((GdkWindow *)drawable);
-#define RESTORE_DIRECT_GC_CLIP(gc)
+ /* Don't clip when drawing to root or all native */
+ if (!_gdk_native_windows && private->window_type != GDK_WINDOW_ROOT)
+ {
+ if (_gdk_gc_get_subwindow (gc) == GDK_CLIP_BY_CHILDREN)
+ clip = private->clip_region_with_children;
+ else
+ clip = private->clip_region;
+ }
+ clip_region_tag = private->clip_tag;
+ impl = private->impl;
+ }
+
+ if (clip)
+ _gdk_gc_add_drawable_clip (gc,
+ clip_region_tag, clip,
+ /* If there was a clip origin set appart from the
+ * window offset, need to take that into
+ * consideration */
+ -old_clip_x, -old_clip_y);
+
+ return impl;
+}
+
+#define BEGIN_DRAW \
+ { \
+ GdkDrawable *impl; \
+ gint x_offset, y_offset; \
+ gint old_clip_x = gc->clip_x_origin; \
+ gint old_clip_y = gc->clip_y_origin; \
+ gint old_ts_x = gc->ts_x_origin; \
+ gint old_ts_y = gc->ts_y_origin; \
+ impl = start_draw_helper (drawable, gc, \
+ &x_offset, &y_offset);
+
+#define END_DRAW \
+ if (x_offset != 0 || y_offset != 0) \
+ { \
+ gdk_gc_set_clip_origin (gc, old_clip_x, old_clip_y); \
+ gdk_gc_set_ts_origin (gc, old_ts_x, old_ts_y); \
+ } \
+ }
static GdkGC *
gdk_window_create_gc (GdkDrawable *drawable,
- GdkGCValues *values,
- GdkGCValuesMask mask)
+ GdkGCValues *values,
+ GdkGCValuesMask mask)
{
g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
-
+
if (GDK_WINDOW_DESTROYED (drawable))
return NULL;
return gdk_gc_new_with_values (((GdkWindowObject *) drawable)->impl,
- values, mask);
-}
-
-/* After having set up the drawable clip rect on a GC we need
- * to make sure that if we draw to a pixmap we draw to the impl,
- * otherwise the pixmap code will reset the drawable clip.
- */
-static GdkDrawable *
-pixmap_impl (GdkPixmap *pixmap)
-{
- return ((GdkPixmapObject *)pixmap)->impl;
+ values, mask);
}
static void
gint width,
gint height)
{
- GdkWindowObject *private = (GdkWindowObject *)drawable;
- OFFSET_GC (gc);
-
if (GDK_WINDOW_DESTROYED (drawable))
return;
-
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_rectangle (pixmap_impl (paint->pixmap), gc, filled,
- x - x_offset, y - y_offset, width, height);
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
- {
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_rectangle (private->impl, gc, filled,
- x - x_offset, y - y_offset, width, height);
- RESTORE_DIRECT_GC_CLIP(gc);
- }
- RESTORE_GC (gc);
+ BEGIN_DRAW;
+ gdk_draw_rectangle (impl, gc, filled,
+ x - x_offset, y - y_offset, width, height);
+ END_DRAW;
}
static void
gint angle1,
gint angle2)
{
- GdkWindowObject *private = (GdkWindowObject *)drawable;
- OFFSET_GC (gc);
-
if (GDK_WINDOW_DESTROYED (drawable))
return;
-
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_arc (pixmap_impl (paint->pixmap), gc, filled,
- x - x_offset, y - y_offset,
- width, height, angle1, angle2);
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
- {
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_arc (private->impl, gc, filled,
- x - x_offset, y - y_offset,
- width, height, angle1, angle2);
- RESTORE_DIRECT_GC_CLIP(gc);
- }
- RESTORE_GC (gc);
+
+ BEGIN_DRAW;
+ gdk_draw_arc (impl, gc, filled,
+ x - x_offset, y - y_offset,
+ width, height, angle1, angle2);
+ END_DRAW;
}
static void
GdkPoint *points,
gint npoints)
{
- GdkWindowObject *private = (GdkWindowObject *)drawable;
GdkPoint *new_points;
-
- OFFSET_GC (gc);
if (GDK_WINDOW_DESTROYED (drawable))
return;
-
+
+ BEGIN_DRAW;
+
if (x_offset != 0 || y_offset != 0)
{
int i;
-
+
new_points = g_new (GdkPoint, npoints);
for (i=0; i<npoints; i++)
{
else
new_points = points;
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_polygon (pixmap_impl (paint->pixmap), gc, filled, new_points, npoints);
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
- {
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_polygon (private->impl, gc, filled, new_points, npoints);
- RESTORE_DIRECT_GC_CLIP(gc);
- }
-
+ gdk_draw_polygon (impl, gc, filled, new_points, npoints);
+
if (new_points != points)
g_free (new_points);
- RESTORE_GC (gc);
+ END_DRAW;
}
static void
const gchar *text,
gint text_length)
{
- GdkWindowObject *private = (GdkWindowObject *)drawable;
- OFFSET_GC (gc);
-
if (GDK_WINDOW_DESTROYED (drawable))
return;
-
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_text (pixmap_impl (paint->pixmap), font, gc,
- x - x_offset, y - y_offset, text, text_length);
-
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
- {
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_text (private->impl, font, gc,
- x - x_offset, y - y_offset, text, text_length);
- RESTORE_DIRECT_GC_CLIP(gc);
- }
- RESTORE_GC (gc);
+ BEGIN_DRAW;
+ gdk_draw_text (impl, font, gc,
+ x - x_offset, y - y_offset, text, text_length);
+ END_DRAW;
}
static void
const GdkWChar *text,
gint text_length)
{
- GdkWindowObject *private = (GdkWindowObject *)drawable;
- OFFSET_GC (gc);
-
if (GDK_WINDOW_DESTROYED (drawable))
return;
-
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_text_wc (pixmap_impl (paint->pixmap), font, gc,
- x - x_offset, y - y_offset, text, text_length);
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
- {
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_text_wc (private->impl, font, gc,
- x - x_offset, y - y_offset, text, text_length);
- RESTORE_DIRECT_GC_CLIP(gc);
- }
-
- RESTORE_GC (gc);
+
+ BEGIN_DRAW;
+ gdk_draw_text_wc (impl, font, gc,
+ x - x_offset, y - y_offset, text, text_length);
+ END_DRAW;
}
static GdkDrawable *
private = (GdkWindowObject *) window;
if (GDK_DRAWABLE_GET_CLASS (private->impl)->get_source_drawable)
return GDK_DRAWABLE_GET_CLASS (private->impl)->get_source_drawable (private->impl);
-
+
return drawable;
}
static GdkDrawable *
gdk_window_get_composite_drawable (GdkDrawable *drawable,
- gint x,
- gint y,
- gint width,
- gint height,
- gint *composite_x_offset,
- gint *composite_y_offset)
+ gint x,
+ gint y,
+ gint width,
+ gint height,
+ gint *composite_x_offset,
+ gint *composite_y_offset)
{
GdkWindowObject *private = (GdkWindowObject *)drawable;
GSList *list;
{
GdkWindowPaint *paint = list->data;
GdkOverlapType overlap;
-
+
overlap = gdk_region_rect_in (paint->region, &rect);
-
+
if (overlap == GDK_OVERLAP_RECTANGLE_IN)
{
*composite_x_offset = paint->x_offset;
*composite_y_offset = paint->y_offset;
-
+
return g_object_ref (paint->pixmap);
}
else if (overlap == GDK_OVERLAP_RECTANGLE_PART)
rect.x += private->abs_x;
rect.y += private->abs_y;
-
+
overlap = gdk_region_rect_in (implicit_paint->region, &rect);
if (overlap == GDK_OVERLAP_RECTANGLE_IN)
{
*composite_x_offset = -private->abs_x + implicit_paint->x_offset;
*composite_y_offset = -private->abs_y + implicit_paint->y_offset;
-
+
return g_object_ref (implicit_paint->pixmap);
}
else if (overlap == GDK_OVERLAP_RECTANGLE_PART)
if (!overlap_buffer)
return g_object_ref (_gdk_drawable_get_source_drawable (drawable));
-
+
tmp_pixmap = gdk_pixmap_new (drawable, width, height, -1);
tmp_gc = _gdk_drawable_get_scratch_gc (tmp_pixmap, FALSE);
source = _gdk_drawable_get_source_drawable (drawable);
-
+
/* Copy the current window contents */
gdk_draw_drawable (tmp_pixmap,
- tmp_gc,
- GDK_WINDOW_OBJECT (source)->impl,
- x - *composite_x_offset,
- y - *composite_y_offset,
- 0, 0,
- width, height);
+ tmp_gc,
+ GDK_WINDOW_OBJECT (source)->impl,
+ x - *composite_x_offset,
+ y - *composite_y_offset,
+ 0, 0,
+ width, height);
/* paint the backing stores */
if (implicit_paint)
{
GdkWindowPaint *paint = list->data;
-
+
gdk_gc_set_clip_region (tmp_gc, paint->region);
gdk_gc_set_clip_origin (tmp_gc, -x - paint->x_offset, -y - paint->y_offset);
-
+
gdk_draw_drawable (tmp_pixmap, tmp_gc, paint->pixmap,
x - paint->x_offset,
y - paint->y_offset,
0, 0, width, height);
}
-
+
for (list = private->paint_stack; list != NULL; list = list->next)
{
GdkWindowPaint *paint = list->data;
if (paint->uses_implicit)
continue; /* We already copied this above */
-
+
gdk_gc_set_clip_region (tmp_gc, paint->region);
gdk_gc_set_clip_origin (tmp_gc, -x, -y);
-
+
gdk_draw_drawable (tmp_pixmap, tmp_gc, paint->pixmap,
x - paint->x_offset,
y - paint->y_offset,
0, 0, width, height);
}
-
+
/* Reset clip region of the cached GdkGC */
gdk_gc_set_clip_region (tmp_gc, NULL);
while (tmp_list)
{
GdkWindowPaint *paint = tmp_list->data;
-
+
gdk_region_union (paint_region, paint->region);
- tmp_list = tmp_list->next;
+ tmp_list = tmp_list->next;
}
gdk_region_intersect (result, paint_region);
gint xdest,
gint ydest,
gint width,
- gint height)
+ gint height,
+ GdkDrawable *original_src)
{
GdkWindowObject *private = (GdkWindowObject *)drawable;
- OFFSET_GC (gc);
-
+
if (GDK_WINDOW_DESTROYED (drawable))
return;
- /* If we have a backing pixmap draw to that */
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_drawable (pixmap_impl (paint->pixmap), gc,
- src, xsrc, ysrc,
- xdest - x_offset, ydest - y_offset, width, height);
+ BEGIN_DRAW;
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
+ /* Call the method directly to avoid getting the composite drawable again */
+ GDK_DRAWABLE_GET_CLASS (impl)->draw_drawable_with_src (impl, gc,
+ src,
+ xsrc, ysrc,
+ xdest - x_offset,
+ ydest - y_offset,
+ width, height,
+ original_src);
+
+ if (!private->paint_stack)
{
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_drawable (private->impl, gc,
- src, xsrc, ysrc,
- xdest - x_offset, ydest - y_offset,
- width, height);
- RESTORE_DIRECT_GC_CLIP(gc);
+ /* We might have drawn from an obscured part of a client
+ side window, if so we need to send graphics exposures */
+ if (_gdk_gc_get_exposures (gc) &&
+ GDK_IS_WINDOW (original_src))
+ {
+ GdkRegion *exposure_region;
+ GdkRegion *clip;
+ GdkRectangle r;
+
+ r.x = xdest;
+ r.y = ydest;
+ r.width = width;
+ r.height = height;
+ exposure_region = gdk_region_rectangle (&r);
+
+ if (_gdk_gc_get_subwindow (gc) == GDK_CLIP_BY_CHILDREN)
+ clip = private->clip_region_with_children;
+ else
+ clip = private->clip_region;
+ gdk_region_intersect (exposure_region, clip);
+
+ clip = _gdk_gc_get_clip_region (gc);
+ if (clip)
+ {
+ gdk_region_offset (exposure_region,
+ old_clip_x,
+ old_clip_y);
+ gdk_region_intersect (exposure_region, clip);
+ gdk_region_offset (exposure_region,
+ -old_clip_x,
+ -old_clip_y);
+ }
+
+ /* Note: We don't clip by the clip mask if set, so this
+ may invalidate to much */
+
+ /* Remove the area that is correctly copied from the src.
+ * Note that xsrc/ysrc has been corrected for abs_x/y offsets already,
+ * which need to be undone */
+ clip = gdk_drawable_get_visible_region (original_src);
+ gdk_region_offset (clip,
+ xdest - (xsrc - GDK_WINDOW_OBJECT (original_src)->abs_x),
+ ydest - (ysrc - GDK_WINDOW_OBJECT (original_src)->abs_y));
+ gdk_region_subtract (exposure_region, clip);
+ gdk_region_destroy (clip);
+
+ gdk_window_invalidate_region (GDK_WINDOW (private),
+ exposure_region,
+ _gdk_gc_get_subwindow (gc) == GDK_INCLUDE_INFERIORS);
+
+ gdk_region_destroy (exposure_region);
+ }
}
- RESTORE_GC (gc);
+ END_DRAW;
}
static void
GdkPoint *points,
gint npoints)
{
- GdkWindowObject *private = (GdkWindowObject *)drawable;
GdkPoint *new_points;
-
- OFFSET_GC (gc);
if (GDK_WINDOW_DESTROYED (drawable))
return;
-
+
+ BEGIN_DRAW;
+
if (x_offset != 0 || y_offset != 0)
{
gint i;
else
new_points = points;
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_points (pixmap_impl (paint->pixmap), gc, new_points, npoints);
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
- {
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_points (private->impl, gc, new_points, npoints);
- RESTORE_DIRECT_GC_CLIP(gc);
- }
+ gdk_draw_points (impl, gc, new_points, npoints);
if (new_points != points)
g_free (new_points);
- RESTORE_GC (gc);
+ END_DRAW;
}
static void
GdkSegment *segs,
gint nsegs)
{
- GdkWindowObject *private = (GdkWindowObject *)drawable;
GdkSegment *new_segs;
- OFFSET_GC (gc);
-
if (GDK_WINDOW_DESTROYED (drawable))
return;
-
+
+ BEGIN_DRAW;
+
if (x_offset != 0 || y_offset != 0)
{
gint i;
else
new_segs = segs;
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_segments (pixmap_impl (paint->pixmap), gc, new_segs, nsegs);
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
- {
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_segments (private->impl, gc, new_segs, nsegs);
- RESTORE_DIRECT_GC_CLIP(gc);
- }
-
+ gdk_draw_segments (impl, gc, new_segs, nsegs);
+
if (new_segs != segs)
g_free (new_segs);
- RESTORE_GC (gc);
+ END_DRAW;
}
static void
GdkPoint *points,
gint npoints)
{
- GdkWindowObject *private = (GdkWindowObject *)drawable;
GdkPoint *new_points;
- OFFSET_GC (gc);
-
if (GDK_WINDOW_DESTROYED (drawable))
return;
-
+
+ BEGIN_DRAW;
+
if (x_offset != 0 || y_offset != 0)
{
gint i;
else
new_points = points;
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_lines (pixmap_impl (paint->pixmap), gc, new_points, npoints);
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
- {
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_lines (private->impl, gc, new_points, npoints);
- RESTORE_DIRECT_GC_CLIP(gc);
- }
+ gdk_draw_lines (impl, gc, new_points, npoints);
if (new_points != points)
g_free (new_points);
- RESTORE_GC (gc);
+ END_DRAW;
}
static void
gint y,
PangoGlyphString *glyphs)
{
- GdkWindowObject *private = (GdkWindowObject *)drawable;
-
- OFFSET_GC (gc);
-
if (GDK_WINDOW_DESTROYED (drawable))
return;
-
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_glyphs (pixmap_impl (paint->pixmap), gc, font, x - x_offset, y - y_offset, glyphs);
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
- {
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_glyphs (private->impl, gc, font,
- x - x_offset, y - y_offset, glyphs);
- RESTORE_DIRECT_GC_CLIP(gc);
- }
-
- RESTORE_GC (gc);
+ BEGIN_DRAW;
+ gdk_draw_glyphs (impl, gc, font,
+ x - x_offset, y - y_offset, glyphs);
+ END_DRAW;
}
static void
gint y,
PangoGlyphString *glyphs)
{
- GdkWindowObject *private = (GdkWindowObject *)drawable;
PangoMatrix tmp_matrix;
- OFFSET_GC (gc);
-
if (GDK_WINDOW_DESTROYED (drawable))
return;
+ BEGIN_DRAW;
+
if (x_offset != 0 || y_offset != 0)
{
if (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;
y -= y_offset * PANGO_SCALE;
}
}
-
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_glyphs_transformed (pixmap_impl (paint->pixmap), gc, matrix, font, x, y, glyphs);
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
- {
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_glyphs_transformed (private->impl, gc, matrix, font, x, y, glyphs);
- RESTORE_DIRECT_GC_CLIP(gc);
- }
+ gdk_draw_glyphs_transformed (impl, gc, matrix, font, x, y, glyphs);
- RESTORE_GC (gc);
+ END_DRAW;
}
typedef struct {
}
static void
-gdk_window_clear_backing_rect (GdkWindow *window,
- gint x,
- gint y,
- gint width,
- gint height)
+gdk_window_clear_backing_region (GdkWindow *window,
+ GdkRegion *region)
{
GdkWindowObject *private = (GdkWindowObject *)window;
GdkWindowPaint *paint = private->paint_stack->data;
BackingRectMethod method;
+ GdkRegion *clip;
+ GdkRectangle clipbox;
#if 0
GTimer *timer;
double elapsed;
method.gc = NULL;
setup_backing_rect_method (&method, window, paint, 0, 0);
+ clip = gdk_region_copy (paint->region);
+ gdk_region_intersect (clip, region);
+ gdk_region_get_clipbox (clip, &clipbox);
+
+
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);
+ gdk_cairo_region (method.cr, clip);
cairo_fill (method.cr);
cairo_destroy (method.cr);
{
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);
+ gdk_gc_set_clip_region (method.gc, clip);
+ gdk_draw_rectangle (window, method.gc, TRUE,
+ clipbox.x, clipbox.y,
+ clipbox.width, clipbox.height);
g_object_unref (method.gc);
#if 0
#endif
}
+ gdk_region_destroy (clip);
+
#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)
+gdk_window_clear_backing_region_redirect (GdkWindow *window,
+ GdkRegion *region)
{
GdkWindowObject *private = (GdkWindowObject *)window;
GdkWindowRedirect *redirect = private->redirect;
GdkRegion *clip_region;
+ GdkRectangle clipbox;
gint x_offset, y_offset;
BackingRectMethod method;
GdkWindowPaint paint;
-
+
if (GDK_WINDOW_DESTROYED (window))
return;
GDK_WINDOW (redirect->redirected),
TRUE,
&x_offset, &y_offset);
-
- paint.x_offset = x_offset;
- paint.y_offset = y_offset;
+ gdk_region_intersect (clip_region, region);
+
+ /* offset is from redirected window origin to window origin, convert to
+ the offset from the redirected pixmap origin to the window origin */
+ x_offset += redirect->dest_x - redirect->src_x;
+ y_offset += redirect->dest_y - redirect->src_y;
+
+ /* Convert region to pixmap coords */
+ gdk_region_offset (clip_region, x_offset, y_offset);
+
+ paint.x_offset = 0;
+ paint.y_offset = 0;
paint.pixmap = redirect->pixmap;
paint.surface = _gdk_drawable_ref_cairo_surface (redirect->pixmap);
-
+
method.cr = NULL;
method.gc = NULL;
- setup_backing_rect_method (&method, window, &paint, 0, 0);
+ setup_backing_rect_method (&method, window, &paint, -x_offset, -y_offset);
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, clip_region);
cairo_fill (method.cr);
{
g_assert (method.gc != NULL);
+ gdk_region_get_clipbox (clip_region, &clipbox);
gdk_gc_set_clip_region (method.gc, clip_region);
- gdk_draw_rectangle (window, method.gc, TRUE, x, y, width, height);
+ gdk_draw_rectangle (redirect->pixmap, method.gc, TRUE,
+ clipbox.x, clipbox.y,
+ clipbox.width, clipbox.height);
g_object_unref (method.gc);
}
}
static void
-gdk_window_clear_backing_rect_direct (GdkWindow *window,
- gint x,
- gint y,
- gint width,
- gint height)
+gdk_window_clear_backing_region_direct (GdkWindow *window,
+ GdkRegion *region)
{
GdkWindowObject *private = (GdkWindowObject *)window;
BackingRectMethod method;
GdkWindowPaint paint;
-
+ GdkRegion *clip;
+ GdkRectangle clipbox;
+
if (GDK_WINDOW_DESTROYED (window))
return;
paint.y_offset = 0;
paint.pixmap = window;
paint.surface = _gdk_drawable_ref_cairo_surface (window);
-
+
method.cr = NULL;
method.gc = NULL;
setup_backing_rect_method (&method, window, &paint, 0, 0);
+ clip = gdk_region_copy (private->clip_region_with_children);
+ gdk_region_intersect (clip, region);
+ gdk_region_get_clipbox (clip, &clipbox);
+
if (method.cr)
{
g_assert (method.gc == NULL);
- gdk_cairo_region (method.cr, private->clip_region_with_children);
- cairo_clip (method.cr);
-
- cairo_rectangle (method.cr, x, y, width, height);
+ gdk_cairo_region (method.cr, clip);
cairo_fill (method.cr);
cairo_destroy (method.cr);
{
g_assert (method.gc != NULL);
- gdk_gc_set_clip_region (method.gc, private->clip_region_with_children);
- gdk_draw_rectangle (window, method.gc, TRUE, x, y, width, height);
+ gdk_gc_set_clip_region (method.gc, clip);
+ gdk_draw_rectangle (window, method.gc, TRUE,
+ clipbox.x, clipbox.y,
+ clipbox.width, clipbox.height);
g_object_unref (method.gc);
}
+ gdk_region_destroy (clip);
cairo_surface_destroy (paint.surface);
}
/**
* gdk_window_clear:
* @window: a #GdkWindow
- *
+ *
* Clears an entire @window to the background color or background pixmap.
**/
void
g_return_if_fail (GDK_IS_WINDOW (window));
gdk_drawable_get_size (GDK_DRAWABLE (window), &width, &height);
-
+
gdk_window_clear_area (window, 0, 0,
- width, height);
+ width, height);
+}
+
+static gboolean
+clears_on_native (GdkWindowObject *private)
+{
+ GdkWindowObject *next;
+
+ next = private;
+ do
+ {
+ private = next;
+ if (gdk_window_has_impl (private))
+ return TRUE;
+ next = private->parent;
+ }
+ while (private->bg_pixmap == GDK_PARENT_RELATIVE_BG &&
+ next && next->window_type != GDK_WINDOW_ROOT);
+ return FALSE;
+}
+
+static void
+gdk_window_clear_region_internal (GdkWindow *window,
+ GdkRegion *region,
+ gboolean send_expose)
+{
+ GdkWindowObject *private = (GdkWindowObject *)window;
+
+ if (private->paint_stack)
+ gdk_window_clear_backing_region (window, region);
+ else
+ {
+ if (private->redirect)
+ gdk_window_clear_backing_region_redirect (window, region);
+
+ if (GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_region &&
+ clears_on_native (private))
+ {
+ GdkRegion *copy;
+ copy = gdk_region_copy (region);
+ gdk_region_intersect (copy, private->clip_region_with_children);
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_region
+ (window, copy, send_expose);
+
+ gdk_region_destroy (copy);
+ }
+ else
+ {
+ gdk_window_clear_backing_region_direct (window, region);
+ if (send_expose)
+ gdk_window_invalidate_region (window, region, FALSE);
+ }
+ }
}
static void
gboolean send_expose)
{
GdkWindowObject *private = (GdkWindowObject *)window;
+ GdkRectangle rect;
+ GdkRegion *region;
g_return_if_fail (GDK_IS_WINDOW (window));
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
/* This is what XClearArea does, and e.g. GtkCList uses it,
so we need to duplicate that */
if (width == 0)
width = private->width - x;
if (height == 0)
height = private->height - y;
-
- if (private->paint_stack)
- gdk_window_clear_backing_rect (window, x, y, width, height);
- else
- {
- if (private->redirect)
- gdk_window_clear_backing_rect_redirect (window, x, y, width, height);
-
- gdk_window_clear_backing_rect_direct (window, x, y, width, height);
- if (send_expose)
- {
- GdkRectangle rect;
-
- rect.x = x;
- rect.y = x;
- rect.width = width;
- rect.height = height;
-
- gdk_window_invalidate_rect (window, &rect, FALSE);
- }
- }
-}
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+
+ region = gdk_region_rectangle (&rect);
+ gdk_window_clear_region_internal (window,
+ region,
+ FALSE);
+ gdk_region_destroy (region);
+
+}
/**
* gdk_window_clear_area:
* @height: height of rectangle to clear
*
* Clears an area of @window to the background color or background pixmap.
- *
+ *
**/
void
gdk_window_clear_area (GdkWindow *window,
*
* This function has a stupid name because it dates back to the mists
* time, pre-GDK-1.0.
- *
+ *
**/
void
gdk_window_clear_area_e (GdkWindow *window,
- gint x,
- gint y,
- gint width,
- gint height)
+ gint x,
+ gint y,
+ gint width,
+ gint height)
{
gdk_window_clear_area_internal (window,
x, y,
static void
gdk_window_draw_image (GdkDrawable *drawable,
- GdkGC *gc,
- GdkImage *image,
- gint xsrc,
- gint ysrc,
- gint xdest,
- gint ydest,
- gint width,
- gint height)
+ GdkGC *gc,
+ GdkImage *image,
+ gint xsrc,
+ gint ysrc,
+ gint xdest,
+ gint ydest,
+ gint width,
+ gint height)
{
- GdkWindowObject *private = (GdkWindowObject *)drawable;
-
- OFFSET_GC (gc);
-
if (GDK_WINDOW_DESTROYED (drawable))
return;
-
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_image (pixmap_impl (paint->pixmap), gc, image, xsrc, ysrc,
- xdest - x_offset, ydest - y_offset,
- width, height);
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
- {
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_image (private->impl, gc, image, xsrc, ysrc,
- xdest - x_offset, ydest - y_offset,
- width, height);
- RESTORE_DIRECT_GC_CLIP(gc);
- }
-
- RESTORE_GC (gc);
+ BEGIN_DRAW;
+ gdk_draw_image (impl, gc, image, xsrc, ysrc,
+ xdest - x_offset, ydest - y_offset,
+ width, height);
+ END_DRAW;
}
static void
gint y_dither)
{
GdkWindowObject *private = (GdkWindowObject *)drawable;
+ GdkDrawableClass *klass;
if (GDK_WINDOW_DESTROYED (drawable))
return;
if (!gc)
gc = _gdk_drawable_get_scratch_gc (drawable, FALSE);
- /* Need block to make OFFSET_GC macro to work */
- {
- OFFSET_GC (gc);
-
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_pixbuf (pixmap_impl (paint->pixmap), gc, pixbuf, src_x, src_y,
- dest_x - x_offset, dest_y - y_offset,
- width, height,
- dither, x_dither - x_offset, y_dither - y_offset);
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
- {
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_pixbuf (private->impl, gc, pixbuf, src_x, src_y,
- dest_x - x_offset, dest_y - y_offset,
- width, height,
- dither, x_dither, y_dither);
- RESTORE_DIRECT_GC_CLIP(gc);
- }
-
- RESTORE_GC (gc);
- }
+ BEGIN_DRAW;
+
+ klass = GDK_DRAWABLE_GET_CLASS (impl);
+
+ if (private->paint_stack)
+ klass->draw_pixbuf (impl, gc, pixbuf, src_x, src_y,
+ dest_x - x_offset, dest_y - y_offset,
+ width, height,
+ dither, x_dither - x_offset, y_dither - y_offset);
+ else
+ klass->draw_pixbuf (impl, gc, pixbuf, src_x, src_y,
+ dest_x - x_offset, dest_y - y_offset,
+ width, height,
+ dither, x_dither, y_dither);
+ END_DRAW;
}
static void
GdkTrapezoid *trapezoids,
gint n_trapezoids)
{
- GdkWindowObject *private = (GdkWindowObject *)drawable;
GdkTrapezoid *new_trapezoids = NULL;
- OFFSET_GC (gc);
-
if (GDK_WINDOW_DESTROYED (drawable))
return;
-
+
+ BEGIN_DRAW;
+
if (x_offset != 0 || y_offset != 0)
{
gint i;
trapezoids = new_trapezoids;
}
- if (private->paint_stack)
- {
- GdkWindowPaint *paint = private->paint_stack->data;
- SETUP_PAINT_GC_CLIP (gc);
- gdk_draw_trapezoids (pixmap_impl (paint->pixmap), gc, trapezoids, n_trapezoids);
- RESTORE_PAINT_GC_CLIP (gc);
- }
- else
- {
- SETUP_DIRECT_GC_CLIP(gc);
- gdk_draw_trapezoids (private->impl, gc, trapezoids, n_trapezoids);
- RESTORE_DIRECT_GC_CLIP(gc);
- }
-
+ gdk_draw_trapezoids (impl, gc, trapezoids, n_trapezoids);
+
g_free (new_trapezoids);
- RESTORE_GC (gc);
+ END_DRAW;
}
static void
gdk_window_real_get_size (GdkDrawable *drawable,
- gint *width,
- gint *height)
+ gint *width,
+ gint *height)
{
GdkWindowObject *private = (GdkWindowObject *)drawable;
static void
gdk_window_real_set_colormap (GdkDrawable *drawable,
- GdkColormap *cmap)
+ GdkColormap *cmap)
{
GdkWindowObject *private;
-
- g_return_if_fail (GDK_IS_WINDOW (drawable));
+
+ g_return_if_fail (GDK_IS_WINDOW (drawable));
if (GDK_WINDOW_DESTROYED (drawable))
return;
/* different colormap than parent, requires native window */
if (!private->input_only &&
cmap != gdk_drawable_get_colormap ((GdkDrawable *)(private->parent)))
- gdk_window_set_has_native ((GdkWindow *)drawable, TRUE);
-
+ gdk_window_ensure_native ((GdkWindow *)drawable);
+
gdk_drawable_set_colormap (private->impl, cmap);
}
if (GDK_WINDOW_DESTROYED (drawable))
return NULL;
-
+
return gdk_drawable_get_colormap (((GdkWindowObject*)drawable)->impl);
}
-
+
static GdkImage*
gdk_window_copy_to_image (GdkDrawable *drawable,
GdkImage *image,
{
GdkWindowObject *private = (GdkWindowObject *) drawable;
gint x_offset, y_offset;
-
+
g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
-
+
if (GDK_WINDOW_DESTROYED (drawable))
return NULL;
/* TODO: Is this right? */
x_offset = 0;
- y_offset = 0;
-
+ y_offset = 0;
+
return gdk_drawable_copy_to_image (private->impl,
image,
src_x - x_offset,
}
else
{
-
+
/* This will be drawing directly to the window, so flush implicit paint */
gdk_window_flush ((GdkWindow *)drawable);
-
+
if (!private->cairo_surface)
{
int width, height;
/* TODO: Avoid the typecheck crap by adding virtual call */
private->cairo_surface = _gdk_drawable_create_cairo_surface (source, width, height);
-
+
if (private->cairo_surface)
{
- cairo_surface_set_device_offset (private->cairo_surface,
+ cairo_surface_set_device_offset (private->cairo_surface,
private->abs_x,
private->abs_y);
-
+
cairo_surface_set_user_data (private->cairo_surface, &gdk_window_cairo_key,
drawable, gdk_window_cairo_surface_destroy);
}
}
else
cairo_surface_reference (private->cairo_surface);
-
+
surface = private->cairo_surface;
}
if (!private->paint_stack)
{
+ cairo_reset_clip (cr);
+
cairo_save (cr);
cairo_identity_matrix (cr);
- cairo_reset_clip (cr);
-
cairo_new_path (cr);
- gdk_cairo_region (cr, private->clip_region);
-
+ gdk_cairo_region (cr, private->clip_region_with_children);
+
cairo_restore (cr);
cairo_clip (cr);
}
/* Only needs to clip to region if piggybacking
on an implicit paint pixmap */
+ cairo_reset_clip (cr);
if (paint->uses_implicit)
{
cairo_save (cr);
cairo_identity_matrix (cr);
-
- cairo_reset_clip (cr);
-
+
cairo_new_path (cr);
gdk_cairo_region (cr, paint->region);
cairo_restore (cr);
-
+
cairo_clip (cr);
}
}
static inline gboolean
gdk_window_is_ancestor (GdkWindow *window,
- GdkWindow *ancestor)
+ GdkWindow *ancestor)
{
while (window)
{
GdkWindow *parent = (GdkWindow*) ((GdkWindowObject*) window)->parent;
if (parent == ancestor)
- return TRUE;
+ return TRUE;
window = parent;
}
* 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;
+ 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_OBJECT (tmp->data)->parent)
- {
- gint index = g_list_index (parent->children, window);
- for (; tmp && parent == GDK_WINDOW_OBJECT (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;
- }
+ {
+ gint index = g_list_index (parent->children, window);
+ for (; tmp && parent == GDK_WINDOW_OBJECT (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);
+ {
+ tmp = g_slist_prepend (tmp, window);
- if (prev)
- prev->next = tmp;
- else
- update_windows = tmp;
- return;
- }
+ 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;
- }
+ {
+ tmp = g_slist_append (tmp, window);
+ return;
+ }
prev = tmp;
}
gdk_window_update_idle (gpointer data)
{
gdk_window_process_all_updates ();
-
+
return FALSE;
}
void
_gdk_window_process_updates_recurse (GdkWindow *window,
- GdkRegion *expose_region)
+ GdkRegion *expose_region)
{
GdkWindowObject *private = (GdkWindowObject *)window;
GdkWindowObject *child;
GdkRegion *child_region;
GdkRectangle r;
- GList *l;
+ GList *l, *children;
if (gdk_region_empty (expose_region))
return;
-
+
+ /* Make this reentrancy safe for expose handlers freeing windows */
+ children = g_list_copy (private->children);
+ g_list_foreach (children, (GFunc)g_object_ref, NULL);
+
/* Iterate over children, starting at topmost */
- for (l = private->children; l != NULL; l = l->next)
+ for (l = children; l != NULL; l = l->next)
{
child = l->data;
-
- if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
+
+ 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
r.y = child->y;
r.width = child->width;
r.height = child->height;
-
+
child_region = gdk_region_rectangle (&r);
if (child->shape)
- gdk_region_intersect (child_region, child->shape);
-
- if (child->impl == private->impl)
+ {
+ /* Adjust shape region to parent window coords */
+ gdk_region_offset (child->shape, child->x, child->y);
+ gdk_region_intersect (child_region, child->shape);
+ gdk_region_offset (child->shape, -child->x, -child->y);
+ }
+
+ if (child->impl == private->impl)
{
/* Client side child, expose */
gdk_region_intersect (child_region, expose_region);
gdk_region_offset (child_region, -child->x, -child->y);
_gdk_window_process_updates_recurse ((GdkWindow *)child, child_region);
}
- else
+ else
{
/* Native child, just remove area from expose region */
gdk_region_subtract (expose_region, child_region);
gdk_region_destroy (child_region);
}
- if (private->event_mask & GDK_EXPOSURE_MASK &&
- !gdk_region_empty (expose_region))
+ g_list_foreach (children, (GFunc)g_object_unref, NULL);
+ g_list_free (children);
+
+ if (!gdk_region_empty (expose_region) &&
+ !private->destroyed)
{
- 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 = expose_region;
- gdk_region_get_clipbox (expose_region, &event.expose.area);
-
- (*_gdk_event_func) (&event, _gdk_event_data);
-
- g_object_unref (window);
+ if (private->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 = expose_region;
+ gdk_region_get_clipbox (expose_region, &event.expose.area);
+
+ (*_gdk_event_func) (&event, _gdk_event_data);
+
+ g_object_unref (window);
+ }
+ else if (private->bg_pixmap != GDK_NO_BG)
+ {
+ /* 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.
+ *
+ * We use begin/end_paint around the clear so that we can
+ * piggyback on the implicit paint */
+
+ gdk_window_begin_paint_region (window, expose_region);
+ gdk_window_clear_region_internal (window, expose_region, FALSE);
+ gdk_window_end_paint (window);
+ }
}
}
+/* 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)
{
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.
{
GdkRegion *update_area = private->update_area;
private->update_area = NULL;
-
- if (_gdk_event_func && gdk_window_is_viewable (window))
+
+ if (_gdk_event_func && gdk_window_is_viewable (window) &&
+ private->window_type != GDK_WINDOW_FOREIGN)
{
- GdkRectangle window_rect;
GdkRegion *expose_region;
- GdkRegion *window_region;
gboolean end_implicit;
/* Clip to part visible in toplevel */
gdk_region_intersect (update_area, private->clip_region);
-
- if (debug_updates)
- {
- /* Make sure we see the red invalid area before redrawing. */
- gdk_display_sync (gdk_drawable_get_display (window));
- g_usleep (70000);
- }
- save_region = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->queue_antiexpose (window, update_area);
- if (save_region)
- expose_region = gdk_region_copy (update_area);
- else
- expose_region = update_area;
-
- window_rect.x = 0;
- window_rect.y = 0;
- window_rect.width = private->width;
- window_rect.height = private->height;
-
- window_region = gdk_region_rectangle (&window_rect);
- gdk_region_intersect (expose_region,
- window_region);
- gdk_region_destroy (window_region);
-
- gdk_region_get_clipbox (expose_region, &clip_box);
+ if (debug_updates)
+ {
+ /* Make sure we see the red invalid area before redrawing. */
+ gdk_display_sync (gdk_drawable_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 (private->outstanding_moves)
+ {
+ GdkWindowRegionMove *move;
+ GdkRegion *remove;
+ GList *l, *prev;
+
+ remove = gdk_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 (private->outstanding_moves); l != NULL; l = prev)
+ {
+ prev = l->prev;
+ move = l->data;
+
+ /* Don't need this area */
+ gdk_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 */
+ gdk_region_offset (move->dest_region, -move->dx, -move->dy);
+ gdk_region_subtract (remove, move->dest_region);
+
+ if (gdk_region_empty (move->dest_region))
+ {
+ gdk_window_region_move_free (move);
+ private->outstanding_moves =
+ g_list_delete_link (private->outstanding_moves, l);
+ }
+ else /* move back */
+ gdk_region_offset (move->dest_region, move->dx, move->dy);
+ }
+ gdk_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 pixmap 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 pixmap
+ * allocated and only once pixmap 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 pixmap).
+ *
+ * Secondly, in the case of implicit double buffering we expose all
+ * the child windows into the implicit pixmap 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.
+ */
+
+ gdk_region_get_clipbox (update_area, &clip_box);
end_implicit = gdk_window_begin_implicit_paint (window, &clip_box);
+ expose_region = gdk_region_copy (update_area);
+ 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 = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->queue_antiexpose (window, update_area);
+ }
+
+ /* Render the invalid areas to the implicit paint, by sending exposes.
+ * May flush if non-double buffered widget draw. */
_gdk_windowing_window_process_updates_recurse (window, expose_region);
+
if (end_implicit)
- gdk_window_end_implicit_paint (window);
-
- if (expose_region != update_area)
- gdk_region_destroy (expose_region);
+ {
+ /* 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.
+ * However, it may be that due to an non-double buffered expose
+ * 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 (private->implicit_paint != NULL) /* didn't flush implicit paint */
+ save_region = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->queue_antiexpose (window, update_area);
+
+ gdk_window_end_implicit_paint (window);
+ }
+ gdk_region_destroy (expose_region);
}
if (!save_region)
gdk_region_destroy (update_area);
}
-
+
if (private->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
*
* Calls gdk_window_process_updates() for all windows (see #GdkWindow)
* in the application.
- *
+ *
**/
void
gdk_window_process_all_updates (void)
if (update_idle)
g_source_remove (update_idle);
-
+
update_windows = NULL;
update_idle = 0;
_gdk_windowing_before_process_all_updates ();
g_slist_foreach (old_update_windows, (GFunc)g_object_ref, NULL);
-
+
while (tmp_list)
{
GdkWindowObject *private = (GdkWindowObject *)tmp_list->data;
-
+
if (!GDK_WINDOW_DESTROYED (tmp_list->data))
- {
+ {
if (private->update_freeze_count ||
gdk_window_is_toplevel_frozen (tmp_list->data))
gdk_window_add_update_window ((GdkWindow *) private);
* @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
+ * 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
* 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,
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 (private);
if ((impl_window->update_area ||
impl_window->outstanding_moves) &&
!impl_window->update_freeze_count &&
!gdk_window_is_toplevel_frozen (window))
- {
+ {
gdk_window_process_updates_internal ((GdkWindow *)impl_window);
gdk_window_remove_update_window ((GdkWindow *)impl_window);
}
/* process updates in reverse stacking order so composition or
* painting over achieves the desired effect for offscreen windows
*/
- GList *node;
- for (node = g_list_last (private->children); node; node = node->prev)
- gdk_window_process_updates (node->data, TRUE);
+ GList *node, *children;
+
+ children = g_list_copy (private->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);
}
/**
**/
void
gdk_window_invalidate_rect (GdkWindow *window,
- const GdkRectangle *rect,
- gboolean invalidate_children)
+ const GdkRectangle *rect,
+ gboolean invalidate_children)
{
GdkRectangle window_rect;
GdkRegion *region;
if (GDK_WINDOW_DESTROYED (window))
return;
-
- if (private->input_only || !GDK_WINDOW_IS_MAPPED (window))
+
+ if (private->input_only || !private->viewable)
return;
if (!rect)
window_rect.x = 0;
window_rect.y = 0;
gdk_drawable_get_size (GDK_DRAWABLE (window),
- &window_rect.width,
- &window_rect.height);
+ &window_rect.width,
+ &window_rect.height);
rect = &window_rect;
}
static void
draw_ugly_color (GdkWindow *window,
- const GdkRegion *region)
+ const GdkRegion *region)
{
/* Draw ugly color all over the newly-invalid region */
GdkColor ugly_color = { 0, 50000, 10000, 10000 };
GdkGC *ugly_gc;
GdkRectangle clipbox;
-
+
ugly_gc = gdk_gc_new (window);
gdk_gc_set_rgb_fg_color (ugly_gc, &ugly_color);
gdk_gc_set_clip_region (ugly_gc, region);
gdk_region_get_clipbox (region, &clipbox);
-
+
gdk_draw_rectangle (window,
ugly_gc,
TRUE,
clipbox.x, clipbox.y,
clipbox.width, clipbox.height);
-
+
g_object_unref (ugly_gc);
}
**/
void
gdk_window_invalidate_maybe_recurse (GdkWindow *window,
- const GdkRegion *region,
- gboolean (*child_func) (GdkWindow *,
- gpointer),
+ const GdkRegion *region,
+ gboolean (*child_func) (GdkWindow *,
+ gpointer),
gpointer user_data)
{
GdkWindowObject *private = (GdkWindowObject *)window;
if (GDK_WINDOW_DESTROYED (window))
return;
-
- if (private->input_only || !GDK_WINDOW_IS_MAPPED (window))
+
+ if (private->input_only ||
+ !private->viewable ||
+ gdk_region_empty (region) ||
+ private->window_type == GDK_WINDOW_ROOT)
return;
visible_region = gdk_drawable_get_visible_region (window);
while (tmp_list)
{
GdkWindowObject *child = tmp_list->data;
-
+
if (!child->input_only)
{
GdkRegion *child_region;
child_rect.width = child->width;
child_rect.height = child->height;
child_region = gdk_region_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))
+ !gdk_window_is_offscreen (child))
gdk_region_subtract (visible_region, child_region);
-
+
if (child_func && (*child_func) ((GdkWindow *)child, user_data))
{
- GdkRegion *tmp = gdk_region_copy (region);
+ 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, tmp);
-
+
gdk_window_invalidate_maybe_recurse ((GdkWindow *)child,
child_region, child_func, user_data);
-
+
gdk_region_destroy (tmp);
}
}
impl_window = gdk_window_get_impl_window (private);
-
+
if (!gdk_region_empty (visible_region) ||
/* Even if we're not exposing anything, make sure we process
idles for windows with outstanding moves */
impl_window->update_area == NULL))
{
if (debug_updates)
- draw_ugly_color (window, region);
-
+ draw_ugly_color (window, region);
+
/* Convert to impl coords */
gdk_region_offset (visible_region, private->abs_x, private->abs_y);
if (impl_window->update_area)
{
gdk_window_add_update_window ((GdkWindow *)impl_window);
impl_window->update_area = gdk_region_copy (visible_region);
-
+
gdk_window_schedule_update ((GdkWindow *)impl_window);
}
}
-
+
gdk_region_destroy (visible_region);
}
* gdk_window_invalidate_region:
* @window: a #GdkWindow
* @region: a #GdkRegion
- * @invalidate_children: %TRUE to also invalidate child windows
+ * @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_invalidate_maybe_recurse (window, region,
invalidate_children ?
- true_predicate : (gboolean (*) (GdkWindow *, gpointer))NULL,
+ true_predicate : (gboolean (*) (GdkWindow *, gpointer))NULL,
NULL);
}
* 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).
+ * have gotten their own expose events).
**/
void
_gdk_window_invalidate_for_expose (GdkWindow *window,
- const GdkRegion *region)
+ GdkRegion *region)
{
+ GdkWindowObject *private = (GdkWindowObject *) window;
+ GdkWindowRegionMove *move;
+ GdkRegion *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 = private->outstanding_moves; l != NULL; l = l->next)
+ {
+ move = l->data;
+
+ /* covert to move source region */
+ move_region = gdk_region_copy (move->dest_region);
+ gdk_region_offset (move_region, -move->dx, -move->dy);
+
+ /* Move area of region that intersects with move source
+ by dx, dy of the move*/
+ gdk_region_intersect (move_region, region);
+ gdk_region_subtract (region, move_region);
+ gdk_region_offset (move_region, move->dx, move->dy);
+ gdk_region_union (region, move_region);
+
+ gdk_region_destroy (move_region);
+ }
+
gdk_window_invalidate_maybe_recurse (window, region,
(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 gdk_region_destroy() on the returned region if it's non-%NULL.
- *
+ *
* Return value: the update area for @window
**/
GdkRegion *
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
impl_window = gdk_window_get_impl_window (private);
-
+
if (impl_window->update_area)
{
tmp_region = gdk_region_copy (private->clip_region_with_children);
{
gdk_region_destroy (impl_window->update_area);
impl_window->update_area = NULL;
-
+
gdk_window_remove_update_window ((GdkWindow *)impl_window);
}
-
+
/* Convert from impl coords */
gdk_region_offset (tmp_region, -private->abs_x, -private->abs_y);
return tmp_region;
/**
* _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.
**/
/**
* 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()
/**
* gdk_window_thaw_updates:
* @window: a #GdkWindow
- *
+ *
* Thaws a window frozen with gdk_window_freeze_updates().
**/
void
GdkWindowObject *impl_window;
g_return_if_fail (GDK_IS_WINDOW (window));
- g_return_if_fail (private->update_freeze_count > 0);
impl_window = gdk_window_get_impl_window (private);
-
+
+ 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_thaw_toplevel_updates_libgtk_only:
* @window: a #GdkWindow
- *
+ *
* Thaws a window frozen with
* gdk_window_freeze_toplevel_updates_libgtk_only().
*
* 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)
* @height: desired height of the window
* @new_width: location to store resulting width
* @new_height: location to store resulting height
- *
- * Constrains a desired width and height according to a
+ *
+ * Constrains a desired width and height according to a
* set of geometry hints (such as minimum and maximum size).
*/
void
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))
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);
/* constrain aspect ratio, according to:
*
- * width
+ * width
* min_aspect <= -------- <= max_aspect
- * height
+ * height
*/
-
+
if (flags & GDK_HINT_ASPECT &&
geometry->min_aspect > 0 &&
geometry->max_aspect > 0)
if (height - delta >= min_height)
height -= delta;
else
- {
+ {
delta = FLOOR (height * geometry->min_aspect - width, xinc);
- if (width + delta <= max_width)
+ 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)
+ if (width - delta >= min_width)
width -= delta;
else
{
}
#undef FLOOR
-
+
*new_width = width;
*new_height = height;
}
* modifier mask
*
* Obtains the current pointer position and modifier state.
- * The position is given in coordinates relative to the upper left
+ * 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
* pointer isn't known to GDK
gint tmp_x, tmp_y;
GdkModifierType tmp_mask;
GdkWindow *child;
-
+
g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
if (window)
display = gdk_screen_get_display (screen);
window = gdk_screen_get_root_window (screen);
-
+
GDK_NOTE (MULTIHEAD,
g_message ("Passing NULL for window to gdk_window_get_pointer()\n"
"is not multihead safe"));
*mask = tmp_mask;
_gdk_display_enable_motion_hints (display);
-
+
return child;
}
* gdk_window_at_pointer:
* @win_x: return location for origin of the window under the pointer
* @win_y: return location for origin of the window under the pointer
- *
+ *
* Obtains the window underneath the mouse pointer, returning the
* location of that window in @win_x, @win_y. Returns %NULL if the
* window under the mouse pointer is not known to GDK (if the window
*
* NOTE: For multihead-aware widgets or applications use
* gdk_display_get_window_at_pointer() instead.
- *
+ *
* Return value: window under the mouse pointer
**/
GdkWindow*
/**
* gdk_get_default_root_window:
- *
+ *
* Obtains the root window (parent all other windows are inside)
* for the default display and screen.
- *
+ *
* Return value: the default root window
**/
GdkWindow *
/**
* gdk_window_foreign_new:
* @anid: a native window handle.
- *
+ *
* Wraps a native window for the default display in a #GdkWindow.
* This may fail if the window has been destroyed.
*
* For example in the X backend, a native window handle is an Xlib
* <type>XID</type>.
- *
- * Return value: the newly-created #GdkWindow wrapper for the
+ *
+ * Return value: the newly-created #GdkWindow wrapper for the
* native window or %NULL if the window has been destroyed.
**/
GdkWindow *
{
GdkWindowObject *child;
GList *l;
-
+
for (l = private->children; l != NULL; l = l->next)
{
child = l->data;
/* Just do native raise for toplevels */
if (private->parent == NULL ||
- GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
+ private->parent->window_type == GDK_WINDOW_ROOT ||
+ /* 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 (private) && gdk_window_has_impl (parent)))
{
GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (window);
}
native_children);
else
{
- /* Right order, since native_chilren is bottom-opmost first */
+ /* Right order, since native_children is bottom-topmost first */
for (l = native_children; l != NULL; l = l->next)
GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (l->data);
}
-
+
g_list_free (native_children);
}
-
+
}
}
-static void
-show_all_visible_impls (GdkWindowObject *private)
+/* Returns TRUE If the native window was mapped or unmapped */
+static gboolean
+set_viewable (GdkWindowObject *w,
+ gboolean val)
{
GdkWindowObject *child;
GList *l;
-
- for (l = private->children; l != NULL; l = l->next)
+
+ 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))
- show_all_visible_impls (child);
+
+ if (GDK_WINDOW_IS_MAPPED (child) &&
+ child->window_type != GDK_WINDOW_FOREIGN)
+ set_viewable (child, val);
}
-
- if (gdk_window_has_impl (private))
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show ((GdkWindow *)private);
+
+ if (gdk_window_has_impl (w) &&
+ w->window_type != GDK_WINDOW_FOREIGN &&
+ w->parent != NULL &&
+ w->parent->window_type != GDK_WINDOW_ROOT)
+ {
+ /* 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.
+ */
+
+ if (val)
+ GDK_WINDOW_IMPL_GET_IFACE (w->impl)->show ((GdkWindow *)w, FALSE);
+ else
+ GDK_WINDOW_IMPL_GET_IFACE (w->impl)->hide ((GdkWindow *)w);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Returns TRUE If the native window was mapped or unmapped */
+gboolean
+_gdk_window_update_viewable (GdkWindow *window)
+{
+ GdkWindowObject *priv = (GdkWindowObject *)window;
+ gboolean viewable;
+
+ if (priv->window_type == GDK_WINDOW_FOREIGN ||
+ priv->window_type == GDK_WINDOW_ROOT)
+ viewable = TRUE;
+ else if (priv->parent == NULL ||
+ priv->parent->window_type == GDK_WINDOW_ROOT ||
+ priv->parent->viewable)
+ viewable = GDK_WINDOW_IS_MAPPED (priv);
+ else
+ viewable = FALSE;
+
+ return set_viewable (priv, viewable);
}
static void
gdk_window_show_internal (GdkWindow *window, gboolean raise)
{
GdkWindowObject *private;
- gboolean was_mapped;
+ gboolean was_mapped, was_viewable;
+ gboolean did_show;
g_return_if_fail (GDK_IS_WINDOW (window));
return;
was_mapped = GDK_WINDOW_IS_MAPPED (window);
-
+ was_viewable = private->viewable;
+
if (raise)
/* Keep children in (reverse) stacking order */
gdk_window_raise_internal (window);
private->state = 0;
}
- if (!was_mapped && gdk_window_is_viewable (window))
- show_all_visible_impls (private);
-
- if (!was_mapped)
+ 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 (private) && (was_viewable || !did_show))
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show ((GdkWindow *)private,
+ !did_show ?
+ was_mapped : TRUE);
+
+ if (!was_mapped && !gdk_window_has_impl (private))
{
if (private->event_mask & GDK_STRUCTURE_MASK)
_gdk_make_event (GDK_WINDOW (private), GDK_MAP, NULL, FALSE);
-
+
if (private->parent && private->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
_gdk_make_event (GDK_WINDOW (private), GDK_MAP, NULL, FALSE);
}
-
+
if (!was_mapped || raise)
{
recompute_visible_regions (private, TRUE, FALSE);
-
+
+ /* If any decendants became visible we need to send visibility notify */
+ gdk_window_update_visibility_recursively (private, NULL);
+
if (gdk_window_is_viewable (window))
{
- _gdk_syntesize_crossing_events_for_geometry_change (window);
+ _gdk_synthesize_crossing_events_for_geometry_change (window);
gdk_window_invalidate_rect (window, NULL, TRUE);
}
}
}
-
+
/**
* gdk_window_show_unraised:
* @window: a #GdkWindow
gdk_window_raise (GdkWindow *window)
{
GdkWindowObject *private;
+ GdkRegion *old_region, *new_region;
g_return_if_fail (GDK_IS_WINDOW (window));
if (private->destroyed)
return;
+ old_region = NULL;
+ if (gdk_window_is_viewable (window) &&
+ !private->input_only)
+ old_region = gdk_region_copy (private->clip_region);
+
/* Keep children in (reverse) stacking order */
gdk_window_raise_internal (window);
recompute_visible_regions (private, TRUE, FALSE);
- gdk_window_invalidate_rect (window, NULL, TRUE);
+ if (old_region)
+ {
+ new_region = gdk_region_copy (private->clip_region);
+
+ gdk_region_subtract (new_region, old_region);
+ gdk_window_invalidate_region (window, new_region, TRUE);
+
+ gdk_region_destroy (old_region);
+ gdk_region_destroy (new_region);
+ }
}
static void
/* Just do native lower for toplevels */
if (private->parent == NULL ||
- GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
+ private->parent->window_type == GDK_WINDOW_ROOT ||
+ /* 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 (private) && gdk_window_has_impl (parent)))
{
GDK_WINDOW_IMPL_GET_IFACE (private->impl)->lower (window);
}
native_children);
else
{
- /* Right order, since native_chilren is bottom-opmost first */
+ /* Right order, since native_children is bottom-topmost first */
for (l = native_children; l != NULL; l = l->next)
GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (l->data);
}
-
+
g_list_free (native_children);
}
-
+
}
}
GdkRectangle r, child;
if (private->parent == NULL ||
- GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
+ private->parent->window_type == GDK_WINDOW_ROOT)
return;
-
+
/* get the visible rectangle of the parent */
r.x = r.y = 0;
r.width = private->parent->width;
gdk_window_lower_internal (window);
recompute_visible_regions (private, TRUE, FALSE);
-
- _gdk_syntesize_crossing_events_for_geometry_change (window);
+
+ _gdk_synthesize_crossing_events_for_geometry_change (window);
gdk_window_invalidate_in_parent (private);
}
gdk_window_show_internal (window, TRUE);
}
-static void
-hide_all_visible_impls (GdkWindowObject *private)
-{
- GdkWindowObject *child;
- GList *l;
-
- for (l = private->children; l != NULL; l = l->next)
- {
- child = l->data;
-
- if (GDK_WINDOW_IS_MAPPED (child))
- hide_all_visible_impls (child);
- }
-
- if (gdk_window_has_impl (private))
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->hide ((GdkWindow *)private);
-}
-
-
/**
* gdk_window_hide:
* @window: a #GdkWindow
gdk_window_hide (GdkWindow *window)
{
GdkWindowObject *private;
- gboolean was_mapped, was_viewable;
+ gboolean was_mapped, did_hide;
g_return_if_fail (GDK_IS_WINDOW (window));
return;
was_mapped = GDK_WINDOW_IS_MAPPED (private);
- was_viewable = gdk_window_is_viewable (window);
-
+
if (gdk_window_has_impl (private))
{
if (GDK_WINDOW_IS_MAPPED (window))
- gdk_synthesize_window_state (window,
- 0,
- GDK_WINDOW_STATE_WITHDRAWN);
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_WITHDRAWN);
}
else if (was_mapped)
{
/* May need to break grabs on children */
display = gdk_drawable_get_display (window);
- if (display->pointer_grab.window != NULL)
- {
- if (is_parent_of (window, display->pointer_grab.window))
- {
- /* Call this ourselves, even though gdk_display_pointer_ungrab
- does so too, since we want to pass implicit == TRUE so the
- broken grab event is generated */
- _gdk_display_unset_has_pointer_grab (display,
- TRUE,
- FALSE,
- GDK_CURRENT_TIME);
- gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
- }
- }
+ if (_gdk_display_end_pointer_grab (display,
+ _gdk_windowing_window_get_next_serial (display),
+ window,
+ TRUE))
+ gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
if (display->keyboard_grab.window != NULL)
{
gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
}
}
-
+
private->state = GDK_WINDOW_STATE_WITHDRAWN;
}
- if (was_viewable)
- hide_all_visible_impls (private);
-
+ did_hide = _gdk_window_update_viewable (window);
+
+ /* Hide foreign window as those are not handled by update_viewable. */
+ if (gdk_window_has_impl (private) && (!did_hide))
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->hide ((GdkWindow *)private);
+
recompute_visible_regions (private, TRUE, FALSE);
-
- if (was_mapped)
+
+ /* all decendants became non-visible, we need to send visibility notify */
+ gdk_window_update_visibility_recursively (private, NULL);
+
+ if (was_mapped && !gdk_window_has_impl (private))
{
if (private->event_mask & GDK_STRUCTURE_MASK)
_gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE);
-
+
if (private->parent && private->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
_gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE);
-
- _gdk_syntesize_crossing_events_for_geometry_change (GDK_WINDOW (private->parent));
+
+ _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (private->parent));
}
-
+
/* Invalidate the rect */
gdk_window_invalidate_in_parent (private);
}
return;
was_mapped = GDK_WINDOW_IS_MAPPED (private);
-
+
if (gdk_window_has_impl (private))
{
GDK_WINDOW_IMPL_GET_IFACE (private->impl)->withdraw (window);
-
+
if (was_mapped)
{
if (private->event_mask & GDK_STRUCTURE_MASK)
_gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE);
-
+
if (private->parent && private->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
_gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE);
-
- _gdk_syntesize_crossing_events_for_geometry_change (GDK_WINDOW (private->parent));
+
+ _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (private->parent));
}
-
+
recompute_visible_regions (private, TRUE, FALSE);
}
}
{
GdkWindowObject *private;
GdkDisplay *display;
-
+
g_return_if_fail (GDK_IS_WINDOW (window));
if ((private->event_mask & GDK_POINTER_MOTION_HINT_MASK) &&
!(event_mask & GDK_POINTER_MOTION_HINT_MASK))
_gdk_display_enable_motion_hints (display);
-
+
private->event_mask = event_mask;
+
+ if (gdk_window_has_impl (private))
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_events (window,
+ get_native_event_mask (private));
+
}
/**
old_y = private->y;
is_resize = (width != -1) || (height != -1);
-
- if (GDK_WINDOW_IS_MAPPED (window) &&
+
+ if (gdk_window_is_viewable (window) &&
!private->input_only)
{
expose = TRUE;
old_region = gdk_region_copy (private->clip_region);
}
-
+
GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, with_move, x, y, width, height);
dx = private->x - old_x;
dy = private->y - old_y;
-
+
old_abs_x = private->abs_x;
old_abs_y = private->abs_y;
/* Avoid recomputing for pure toplevel moves, for performance reasons */
if (is_resize)
recompute_visible_regions (private, TRUE, FALSE);
-
+
if (expose)
{
new_region = gdk_region_copy (private->clip_region);
-
+
/* This is the newly exposed area (due to any resize),
* X will expose it, but lets do that without the
* roundtrip
*/
gdk_region_subtract (new_region, old_region);
gdk_window_invalidate_region (window, new_region, TRUE);
-
+
gdk_region_destroy (old_region);
gdk_region_destroy (new_region);
}
- _gdk_syntesize_crossing_events_for_geometry_change (window);
+ _gdk_synthesize_crossing_events_for_geometry_change (window);
}
{
GList *l;
GdkWindowObject *child;
-
+
for (l = private->children; l; l = l->next)
{
child = l->data;
-
+
if (child->impl != private->impl)
GDK_WINDOW_IMPL_GET_IFACE (child->impl)->move_resize ((GdkWindow *)child, TRUE, child->x, child->y, child->width, child->height);
else
GdkWindowObject *child;
GdkRegion *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 = gdk_region_copy (child->clip_region);
x_offset + child->x,
y_offset + child->y);
}
-
+
return FALSE;
}
gboolean include_this)
{
GdkRegion *region;
-
- if (include_this && gdk_window_has_impl (window))
+
+ if (include_this && gdk_window_has_impl (window) && window->viewable)
return gdk_region_copy (window->clip_region);
region = NULL;
-
+
collect_native_child_region_helper (window, window->impl, ®ion, 0, 0);
-
+
return region;
}
return;
if (private->parent == NULL ||
- GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
+ private->parent->window_type == GDK_WINDOW_ROOT)
{
gdk_window_move_resize_toplevel (window, with_move, x, y, width, height);
return;
}
/* Handle child windows */
-
+
expose = FALSE;
old_region = NULL;
old_x = private->x;
old_y = private->y;
- if (GDK_WINDOW_IS_MAPPED (window) &&
+ old_native_child_region = NULL;
+ if (gdk_window_is_viewable (window) &&
!private->input_only)
{
expose = TRUE;
-
+
old_region = gdk_region_copy (private->clip_region);
/* Adjust region to parent window coords */
gdk_region_offset (old_region, private->x, private->y);
- }
- old_native_child_region = collect_native_child_region (private, TRUE);
- if (old_native_child_region)
- {
- /* Adjust region to parent window coords */
- gdk_region_offset (old_native_child_region, private->x, private->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 (private->parent);
+ old_native_child_region = collect_native_child_region (private, TRUE);
+ if (old_native_child_region)
+ {
+ /* Adjust region to parent window coords */
+ gdk_region_offset (old_native_child_region, private->x, private->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 (private->parent);
+ }
}
-
+
/* Set the new position and size */
if (with_move)
{
height = 1;
private->height = height;
}
-
+
dx = private->x - old_x;
dy = private->y - old_y;
-
+
old_abs_x = private->abs_x;
old_abs_y = private->abs_y;
/* Adjust region to parent window coords */
gdk_region_offset (new_native_child_region, private->x, private->y);
}
-
+
if (gdk_window_has_impl (private))
{
/* Do the actual move after recomputing things, as this will have set the shape to
else if (old_abs_x != private->abs_x ||
old_abs_y != private->abs_y)
move_native_children (private);
-
+
if (expose)
{
new_region = gdk_region_copy (private->clip_region);
*
* new_region:
* Everything in the old and new regions that is not copied must be
- * invalidated (including children) as this is newly exposed
+ * invalidated (including children) as this is newly exposed
*/
copy_area = gdk_region_copy (new_region);
-
+
gdk_region_union (new_region, old_region);
if (old_native_child_region)
gdk_region_offset (new_native_child_region, dx, dy);
gdk_region_subtract (copy_area, new_native_child_region);
}
-
+
gdk_region_subtract (new_region, copy_area);
/* Convert old region to impl coords */
gdk_region_offset (old_region, -dx + private->abs_x - private->x, -dy + private->abs_y - private->y);
- /* The old_region area is moved and we queue translations for all expose events
- to it that will be sent before the copy operation */
- GDK_WINDOW_IMPL_GET_IFACE (impl_window->impl)->queue_translation ((GdkWindow *)impl_window,
- old_region, dx, dy);
-
/* convert from parent coords to impl */
gdk_region_offset (copy_area, private->abs_x - private->x, private->abs_y - private->y);
- move_region_on_impl (private, copy_area, dx, dy); /* Takes ownership of copy_area */
+ 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)
gdk_region_destroy (old_native_child_region);
gdk_region_destroy (new_native_child_region);
}
-
- _gdk_syntesize_crossing_events_for_geometry_change (window);
+
+ _gdk_synthesize_crossing_events_for_geometry_change (window);
}
{
GdkWindowObject *private = (GdkWindowObject *) window;
GdkWindowObject *impl_window;
- GdkRegion *source_area, *copy_area, *noncopy_area;
+ GdkRegion *copy_area, *noncopy_area;
GdkRegion *old_native_child_region, *new_native_child_region;
GList *tmp_list;
gdk_window_flush_recursive (private);
}
-
+
/* First move all child windows, without causing invalidation */
-
+
tmp_list = private->children;
while (tmp_list)
{
GdkWindow *child = GDK_WINDOW (tmp_list->data);
GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child);
-
+
/* Just update the positions, the bits will move with the copy */
child_obj->x += dx;
child_obj->y += dy;
-
+
tmp_list = tmp_list->next;
}
new_native_child_region = NULL;
if (old_native_child_region)
new_native_child_region = collect_native_child_region (private, FALSE);
-
+
move_native_children (private);
-
+
/* Then copy the actual bits of the window w/ child windows */
-
+
impl_window = gdk_window_get_impl_window (private);
/* Calculate the area that can be gotten by copying the old area */
* the native window move.
*/
gdk_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 */
gdk_region_subtract (copy_area, new_native_child_region);
noncopy_area = gdk_region_copy (private->clip_region);
gdk_region_subtract (noncopy_area, copy_area);
- /* Get window clip and convert to real window coords, this
- area is moved and we queue translations for all expose events
- to it that will be sent before the copy operation */
-
- source_area = gdk_region_copy (private->clip_region);
- /* convert from window coords to real parent */
- gdk_region_offset (source_area, private->abs_x, private->abs_y);
- GDK_WINDOW_IMPL_GET_IFACE (impl_window->impl)->queue_translation ((GdkWindow *)impl_window,
- source_area, dx, dy);
- gdk_region_destroy (source_area);
-
/* convert from window coords to impl */
gdk_region_offset (copy_area, private->abs_x, private->abs_y);
- move_region_on_impl (private, copy_area, dx, dy); /* Takes ownership of copy_area */
-
+ move_region_on_impl (impl_window, copy_area, dx, dy); /* takes ownership of copy_area */
+
/* Invalidate not copied regions */
gdk_window_invalidate_region (window, noncopy_area, TRUE);
gdk_region_destroy (old_native_child_region);
gdk_region_destroy (new_native_child_region);
}
-
- _gdk_syntesize_crossing_events_for_geometry_change (window);
+
+ _gdk_synthesize_crossing_events_for_geometry_change (window);
}
/**
{
GdkWindowObject *private = (GdkWindowObject *) window;
GdkWindowObject *impl_window;
- GdkRegion *source_area;
GdkRegion *nocopy_area;
GdkRegion *copy_area;
return;
impl_window = gdk_window_get_impl_window (private);
-
+
/* compute source regions */
- source_area = gdk_region_copy (region);
- gdk_region_intersect (source_area, private->clip_region_with_children);
+ copy_area = gdk_region_copy (region);
+ gdk_region_intersect (copy_area, private->clip_region_with_children);
/* compute destination regions */
- copy_area = gdk_region_copy (source_area);
gdk_region_offset (copy_area, dx, dy);
gdk_region_intersect (copy_area, private->clip_region_with_children);
- /* invalidate parts of the region not covered by the copy */
+ /* Invalidate parts of the region (source and dest) not covered
+ by the copy */
nocopy_area = gdk_region_copy (region);
gdk_region_offset (nocopy_area, dx, dy);
+ gdk_region_union (nocopy_area, region);
gdk_region_subtract (nocopy_area, copy_area);
- gdk_window_invalidate_region (window, nocopy_area, FALSE);
- gdk_region_destroy (nocopy_area);
- gdk_region_offset (source_area, private->abs_x, private->abs_y);
- GDK_WINDOW_IMPL_GET_IFACE (impl_window->impl)->queue_translation ((GdkWindow *)impl_window,
- source_area, dx, dy);
-
/* convert from window coords to impl */
gdk_region_offset (copy_area, private->abs_x, private->abs_y);
-
- move_region_on_impl (private, copy_area, dx, dy); /* Takes ownership of copy_area */
+ move_region_on_impl (impl_window, copy_area, dx, dy); /* Takes ownership of copy_area */
- gdk_region_destroy (source_area);
+ gdk_window_invalidate_region (window, nocopy_area, FALSE);
+ gdk_region_destroy (nocopy_area);
}
/**
g_return_if_fail (GDK_IS_WINDOW (window));
private = (GdkWindowObject *) window;
-
+
private->bg_color = *color;
gdk_colormap_query_color (colormap, private->bg_color.pixel, &private->bg_color);
private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
private->bg_pixmap != GDK_NO_BG)
g_object_unref (private->bg_pixmap);
-
+
private->bg_pixmap = NULL;
- if (!GDK_WINDOW_DESTROYED (window) && gdk_window_has_impl (private))
+ if (!GDK_WINDOW_DESTROYED (window) &&
+ gdk_window_has_impl (private) &&
+ !private->input_only)
GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_background (window, &private->bg_color);
}
g_warning ("gdk_window_set_back_pixmap(): pixmap must have a colormap");
return;
}
-
+
if (private->bg_pixmap &&
private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
private->bg_pixmap != GDK_NO_BG)
private->bg_pixmap = g_object_ref (pixmap);
else
private->bg_pixmap = GDK_NO_BG;
-
- if (!GDK_WINDOW_DESTROYED (window) && gdk_window_has_impl (private))
+
+ if (!GDK_WINDOW_DESTROYED (window) &&
+ gdk_window_has_impl (private) &&
+ !private->input_only)
GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, private->bg_pixmap);
}
-static void
-update_cursor (GdkDisplay *display)
+/**
+ * gdk_window_get_cursor:
+ * @window: a #GdkWindow
+ * @cursor: a cursor
+ *
+ * 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: 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)
{
- GdkWindowObject *pointer_window, *cursor_window;
-
- pointer_window = (GdkWindowObject *)display->pointer_info.window_under_pointer;
-
- cursor_window = pointer_window;
- while (cursor_window->cursor == NULL &&
- cursor_window->parent != NULL &&
- cursor_window->parent->window_type != GDK_WINDOW_ROOT)
- cursor_window = cursor_window->parent;
+ GdkWindowObject *private;
- if (display->pointer_grab.window != NULL &&
- !is_parent_of (display->pointer_grab.window, (GdkWindow *)cursor_window))
- cursor_window = (GdkWindowObject *)display->pointer_grab.window;
+ g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
- /* Set all cursors on toplevel, otherwise its tricky to keep track of
- * which native window has what cursor set. */
- GDK_WINDOW_IMPL_GET_IFACE (pointer_window->impl)->set_cursor (gdk_window_get_toplevel ((GdkWindow *)pointer_window),
- cursor_window->cursor);
+ private = (GdkWindowObject *) window;
+
+ return private->cursor;
}
/**
* @window: a #GdkWindow
* @cursor: a cursor
*
- * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new_for_display()
- * or gdk_cursor_new_from_pixmap() 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
+ * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new_for_display()
+ * or gdk_cursor_new_from_pixmap() 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
if (cursor)
private->cursor = gdk_cursor_ref (cursor);
- if (is_parent_of (window, display->pointer_info.window_under_pointer))
+ if (_gdk_native_windows ||
+ private->window_type == GDK_WINDOW_ROOT ||
+ private->window_type == GDK_WINDOW_FOREIGN)
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_cursor (window, cursor);
+ else if (_gdk_window_event_parent_of (window, display->pointer_info.window_under_pointer))
update_cursor (display);
+
+ g_object_notify (G_OBJECT (window), "cursor");
}
}
gint *height,
gint *depth)
{
- GdkWindowObject *private;
+ GdkWindowObject *private, *parent;
if (!window)
{
GDK_NOTE (MULTIHEAD,
g_message ("gdk_window_get_geometry(): Window needs "
- "to be non-NULL to be multi head safe"));
+ "to be non-NULL to be multi head safe"));
window = gdk_screen_get_root_window ((gdk_screen_get_default ()));
}
if (!GDK_WINDOW_DESTROYED (window))
{
if (gdk_window_has_impl (private))
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_geometry (window, x, y,
- width, height,
- depth);
+ {
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_geometry (window, x, y,
+ width, height,
+ depth);
+ /* This reports the position wrt to the native parent, we need to convert
+ it to be relative to the client side parent */
+ parent = private->parent;
+ if (parent && !gdk_window_has_impl (parent))
+ {
+ if (x)
+ *x -= parent->abs_x;
+ if (y)
+ *y -= parent->abs_y;
+ }
+ }
else
{
if (x)
g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
- private = (GdkWindowObject *) window;
+ if (GDK_WINDOW_DESTROYED (window))
+ {
+ if (x)
+ *x = 0;
+ if (y)
+ *y = 0;
+ return 0;
+ }
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_origin (window, x, y);
+ private = (GdkWindowObject *) window;
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_root_coords (window,
+ private->abs_x,
+ private->abs_y,
+ x, y);
- if (x)
- *x += private->abs_x;
- if (y)
- *y += private->abs_y;
-
return TRUE;
}
+/**
+ * gdk_window_get_root_coords:
+ * @window: a #GdkWindow
+ * @x: X coordinate in window
+ * @y: Y coordinate in window
+ * @root_x: return location for X coordinate
+ * @root_y: 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.
+ */
+void
+gdk_window_get_root_coords (GdkWindow *window,
+ gint x,
+ gint y,
+ gint *root_x,
+ gint *root_y)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+
+ if (GDK_WINDOW_DESTROYED (window))
+ {
+ if (x)
+ *root_x = x;
+ if (y)
+ *root_y = y;
+ return;
+ }
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_root_coords (window,
+ x + private->abs_x,
+ y + private->abs_y,
+ root_x, root_y);
+}
+
/**
* gdk_window_get_deskrelative_origin:
* @window: a toplevel #GdkWindow
* @x: return location for X coordinate
* @y: return location for Y coordinate
- *
+ *
* This gets the origin of a #GdkWindow relative to
* an Enlightenment-window-manager desktop. As long as you don't
* assume that the user's desktop/workspace covers the entire
* root window (i.e. you don't assume that the desktop begins
* at root window coordinate 0,0) this function is not necessary.
* It's deprecated for that reason.
- *
+ *
* Return value: not meaningful
**/
gboolean
g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
private = (GdkWindowObject *) window;
-
+
if (!GDK_WINDOW_DESTROYED (window))
{
return_val = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_deskrelative_origin (window, &tx, &ty);
-
+
if (x)
*x = tx + private->abs_x;
if (y)
*y = ty + private->abs_y;
}
-
+
return return_val;
}
gdk_window_shape_combine_mask (GdkWindow *window,
GdkBitmap *mask,
gint x,
- gint y)
+ gint y)
{
GdkWindowObject *private;
GdkRegion *region;
*/
void
gdk_window_shape_combine_region (GdkWindow *window,
- const GdkRegion *shape_region,
- gint offset_x,
- gint offset_y)
+ const GdkRegion *shape_region,
+ gint offset_x,
+ gint offset_y)
{
GdkWindowObject *private;
GdkRegion *old_region, *new_region, *diff;
if (private->shape)
gdk_region_destroy (private->shape);
-
+
old_region = NULL;
if (GDK_WINDOW_IS_MAPPED (window))
old_region = gdk_region_copy (private->clip_region);
if (shape_region)
{
private->shape = gdk_region_copy (shape_region);
- gdk_region_offset (private->shape, offset_x, offset_y);
+ gdk_region_offset (private->shape, offset_x, offset_y);
}
else
private->shape = NULL;
-
+
recompute_visible_regions (private, TRUE, FALSE);
if (old_region)
gdk_region_destroy (diff);
if (private->parent != NULL &&
- GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
+ private->parent->window_type != GDK_WINDOW_ROOT)
{
/* New area in the non-root parent window, needs invalidation */
diff = gdk_region_copy (old_region);
gdk_region_subtract (diff, new_region);
-
+
/* Adjust region to parent window coords */
gdk_region_offset (diff, private->x, private->y);
-
+
gdk_window_invalidate_region (GDK_WINDOW (private->parent), diff, TRUE);
-
+
gdk_region_destroy (diff);
}
GdkRegion *region;
private = (GdkWindowObject *) window;
-
+
r.x = 0;
r.y = 0;
r.width = private->width;
r.height = private->height;
-
+
region = gdk_region_rectangle (&r);
remove_child_area (private, NULL, FALSE, region);
if (merge && private->shape)
gdk_region_subtract (region, private->shape);
-
+
gdk_window_shape_combine_region (window, region, 0, 0);
}
/**
* gdk_window_input_shape_combine_mask:
* @window: a #GdkWindow
- * @mask: shape mask
+ * @mask: shape mask, or %NULL
* @x: X position of shape mask with respect to @window
* @y: Y position of shape mask with respect to @window
- *
+ *
* Like gdk_window_shape_combine_mask(), but the shape applies
* only to event handling. Mouse events which happen while
- * the pointer position corresponds to an unset bit in the
+ * 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
+ * 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".
*
* Since: 2.10
*/
-void
+void
gdk_window_input_shape_combine_mask (GdkWindow *window,
GdkBitmap *mask,
gint x,
gdk_window_input_shape_combine_region (window,
region,
x, y);
-
- gdk_region_destroy (region);
+
+ if (region != NULL)
+ gdk_region_destroy (region);
}
/**
* @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
+ * 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
+ * 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".
*
* Since: 2.10
*/
-void
+void
gdk_window_input_shape_combine_region (GdkWindow *window,
const GdkRegion *shape_region,
gint offset_x,
if (shape_region)
{
private->input_shape = gdk_region_copy (shape_region);
- gdk_region_offset (private->input_shape, offset_x, offset_y);
+ gdk_region_offset (private->input_shape, offset_x, offset_y);
}
else
private->input_shape = NULL;
GDK_WINDOW_IMPL_GET_IFACE (private->impl)->input_shape_combine_region ((GdkWindow *)private, private->input_shape, 0, 0);
/* Pointer may have e.g. moved outside window due to the input mask change */
- _gdk_syntesize_crossing_events_for_geometry_change (window);
+ _gdk_synthesize_crossing_events_for_geometry_change (window);
}
static void
GdkRegion *region;
private = (GdkWindowObject *) window;
-
+
r.x = 0;
r.y = 0;
r.width = private->width;
r.height = private->height;
-
+
region = gdk_region_rectangle (&r);
remove_child_area (private, NULL, TRUE, region);
gdk_region_subtract (region, private->shape);
if (merge && private->input_shape)
gdk_region_subtract (region, private->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
*
* Since: 2.10
**/
-void
+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_mask().
*
* This function is distinct from gdk_window_set_child_input_shapes()
- * because it includes @window's input shape mask in the set of
+ * because it includes @window's input shape mask in the set of
* shapes to be merged.
*
* Since: 2.10
**/
-void
+void
gdk_window_merge_child_input_shapes (GdkWindow *window)
{
g_return_if_fail (GDK_IS_WINDOW (window));
-
+
do_child_input_shapes (window, TRUE);
}
if (gdk_window_has_impl (private))
return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_static_gravities (window, use_static);
-
+
return FALSE;
}
* @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
+ * 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"/>
* 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).
+ * 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.
*/
void
gdk_window_set_composited (GdkWindow *window,
- gboolean composited)
+ gboolean composited)
{
GdkWindowObject *private = (GdkWindowObject *)window;
GdkDisplay *display;
return;
if (composited)
- gdk_window_set_has_native (window, TRUE);
+ gdk_window_ensure_native (window);
display = gdk_drawable_get_display (GDK_DRAWABLE (window));
if (GDK_WINDOW_IS_MAPPED (window))
gdk_window_invalidate_in_parent (private);
-
+
private->composited = composited;
}
static void
remove_redirect_from_children (GdkWindowObject *private,
- GdkWindowRedirect *redirect)
+ GdkWindowRedirect *redirect)
{
GList *l;
GdkWindowObject *child;
static void
apply_redirect_to_children (GdkWindowObject *private,
- GdkWindowRedirect *redirect)
+ GdkWindowRedirect *redirect)
{
GList *l;
GdkWindowObject *child;
gdk_window_redirect_to_drawable (GdkWindow *window,
GdkDrawable *drawable,
gint src_x,
- gint src_y,
+ gint src_y,
gint dest_x,
- gint dest_y,
+ gint dest_y,
gint width,
- gint height)
+ gint height)
{
GdkWindowObject *private;
if (height == -1)
height = h;
}
-
+
private->redirect = g_new0 (GdkWindowRedirect, 1);
private->redirect->redirected = private;
private->redirect->pixmap = g_object_ref (drawable);
static void
window_get_size_rectangle (GdkWindow *window,
- GdkRectangle *rect)
+ GdkRectangle *rect)
{
GdkWindowObject *private = (GdkWindowObject *) window;
-
+
rect->x = rect->y = 0;
rect->width = private->width;
rect->height = private->height;
*base_x_offset = 0;
if (base_y_offset)
*base_y_offset = 0;
-
- if (!GDK_WINDOW_IS_MAPPED (window) || private->input_only)
+
+ if (!private->viewable || private->input_only)
return gdk_region_new ();
window_get_size_rectangle (window, &visible_rect);
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);
+ (parentwin == private || lastwin != (GdkWindowObject*) base_window);
lastwin = parentwin, parentwin = lastwin->parent)
{
GList *cur;
/* children is ordered in reverse stack order */
for (cur = parentwin->children;
- cur && cur->data != lastwin;
- cur = cur->next)
+ 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;
- /* Ignore offscreen children, as they don't draw in their parent and
+ /* 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_private))
continue;
- window_get_size_rectangle (child, &visible_rect);
+ 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.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);
}
-
+
/* Clip to the parent */
window_get_size_rectangle ((GdkWindow *)parentwin, &visible_rect);
/* Convert rect to "window" coords */
visible_rect.x += - x_offset;
visible_rect.y += - y_offset;
-
+
tmpreg = gdk_region_rectangle (&visible_rect);
gdk_region_intersect (real_clip_region, tmpreg);
gdk_region_destroy (tmpreg);
g_free (redirect);
}
+/* Gets the toplevel for a window as used for events,
+ i.e. including offscreen parents */
+static GdkWindowObject *
+get_event_parent (GdkWindowObject *window)
+{
+ if (window->window_type == GDK_WINDOW_OFFSCREEN)
+ return (GdkWindowObject *)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 *w)
+{
+ GdkWindowObject *private = GDK_WINDOW_OBJECT (w);
+ GdkWindowObject *parent;
+
+ while ((parent = get_event_parent (private)) != NULL &&
+ (parent->window_type != GDK_WINDOW_ROOT))
+ private = parent;
+
+ return GDK_WINDOW (private);
+}
+
+gboolean
+_gdk_window_event_parent_of (GdkWindow *parent,
+ GdkWindow *child)
+{
+ GdkWindow *w;
+
+ w = child;
+ while (w != NULL)
+ {
+ if (w == parent)
+ return TRUE;
+
+ w = (GdkWindow *)get_event_parent ((GdkWindowObject *)w);
+ }
+
+ return FALSE;
+}
+
+static void
+update_cursor (GdkDisplay *display)
+{
+ GdkWindowObject *pointer_window, *cursor_window, *parent, *toplevel;
+ GdkPointerGrabInfo *grab;
+
+ pointer_window = (GdkWindowObject *)display->pointer_info.window_under_pointer;
+
+ cursor_window = pointer_window;
+ while (cursor_window->cursor == NULL &&
+ (parent = get_event_parent (cursor_window)) != NULL &&
+ parent->window_type != GDK_WINDOW_ROOT)
+ cursor_window = parent;
+
+ /* 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_pointer_grab (display);
+ if (grab != NULL &&
+ !_gdk_window_event_parent_of (grab->window, (GdkWindow *)cursor_window))
+ cursor_window = (GdkWindowObject *)grab->window;
+
+ /* Set all cursors on toplevel, otherwise its tricky to keep track of
+ * which native window has what cursor set. */
+ toplevel = (GdkWindowObject *)get_event_toplevel ((GdkWindow *)pointer_window);
+ GDK_WINDOW_IMPL_GET_IFACE (toplevel->impl)->set_cursor
+ ((GdkWindow *)toplevel, cursor_window->cursor);
+}
+
+static void
+from_embedder (GdkWindowObject *window,
+ double embedder_x, double embedder_y,
+ double *offscreen_x, double *offscreen_y)
+{
+ g_signal_emit (window,
+ signals[FROM_EMBEDDER], 0,
+ embedder_x, embedder_y,
+ offscreen_x, offscreen_y,
+ NULL);
+}
+
static void
convert_coords_to_child (GdkWindowObject *child,
double x, double y,
double *child_x, double *child_y)
{
- *child_x = x - child->x;
- *child_y = y - child->y;
-
- if (child->offscreen_hooks)
- child->offscreen_hooks->from_parent ((GdkWindow *)child, x, y, child_x, child_y);
+ if (gdk_window_is_offscreen (child))
+ {
+ from_embedder (child, x, y,
+ child_x, child_y);
+ }
+ else
+ {
+ *child_x = x - child->x;
+ *child_y = y - child->y;
+ }
}
static gboolean
double x, double y)
{
return
- x >= 0 && x < window->width &&
+ x >= 0 && x < window->width &&
y >= 0 && y < window->height &&
(window->shape == NULL ||
gdk_region_point_in (window->shape,
x, y));
}
+static GdkWindow *
+convert_native_coords_to_toplevel (GdkWindow *window,
+ double child_x, double child_y,
+ double *toplevel_x, double *toplevel_y)
+{
+ GdkWindowObject *private = (GdkWindowObject *)window;
+ gdouble x, y;
+
+ x = child_x;
+ y = child_y;
+
+ while (private->parent != NULL &&
+ (private->parent->window_type != GDK_WINDOW_ROOT))
+ {
+ x += private->x;
+ y += private->y;
+ private = private->parent;
+ }
+
+ *toplevel_x = x;
+ *toplevel_y = y;
+
+ return (GdkWindow *)private;
+}
+
static void
convert_toplevel_coords_to_window (GdkWindow *window,
gdouble toplevel_x,
gdouble *window_y)
{
GdkWindowObject *private;
+ GdkWindowObject *parent;
gdouble x, y;
GList *children, *l;
private = GDK_WINDOW_OBJECT (window);
-
+
x = toplevel_x;
y = toplevel_y;
children = NULL;
- while (private->parent != NULL &&
- (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT))
+ while ((parent = get_event_parent (private)) != NULL &&
+ (parent->window_type != GDK_WINDOW_ROOT))
{
children = g_list_prepend (children, private);
- private = private->parent;
+ private = parent;
}
for (l = children; l != NULL; l = l->next)
convert_coords_to_child (l->data, x, y, &x, &y);
-
+
g_list_free (children);
-
+
*window_x = x;
*window_y = y;
}
+static GdkWindowObject *
+pick_embedded_child (GdkWindowObject *window,
+ double x, double y)
+{
+ GdkWindowObject *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)
+{
+ GdkWindowObject *private, *sub;
+ double child_x, child_y;
+ GList *l;
+
+ private = (GdkWindowObject *)window;
+
+ if (point_in_window (private, x, y))
+ {
+ /* Children is ordered in reverse stack order, i.e. first is topmost */
+ for (l = private->children; l != NULL; l = l->next)
+ {
+ sub = l->data;
+
+ if (!GDK_WINDOW_IS_MAPPED (sub))
+ continue;
+
+ convert_coords_to_child (sub,
+ x, y,
+ &child_x, &child_y);
+ if (point_in_window (sub, child_x, child_y))
+ return (GdkWindow *)sub;
+ }
+
+ if (private->num_offscreen_children > 0)
+ {
+ sub = pick_embedded_child (private,
+ x, y);
+ if (sub)
+ return (GdkWindow *)sub;
+ }
+ }
+
+ return NULL;
+}
+
GdkWindow *
_gdk_window_find_descendant_at (GdkWindow *toplevel,
double x, double y,
GdkWindowObject *private, *sub;
double child_x, child_y;
GList *l;
+ gboolean found;
private = (GdkWindowObject *)toplevel;
-
+
if (point_in_window (private, x, y))
{
- do
+ do
{
+ found = FALSE;
/* Children is ordered in reverse stack order, i.e. first is topmost */
for (l = private->children; l != NULL; l = l->next)
{
sub = l->data;
- if (!GDK_WINDOW_IS_MAPPED (sub))
- continue;
-
+ if (!GDK_WINDOW_IS_MAPPED (sub))
+ continue;
+
convert_coords_to_child (sub,
x, y,
&child_x, &child_y);
x = child_x;
y = child_y;
private = sub;
+ found = TRUE;
break;
}
}
+ if (!found &&
+ private->num_offscreen_children > 0)
+ {
+ sub = pick_embedded_child (private,
+ x, y);
+ if (sub)
+ {
+ found = TRUE;
+ private = sub;
+ from_embedder (sub, x, y, &x, &y);
+ }
+ }
}
- while (l != NULL);
+ while (found);
}
else
{
*found_x = x;
if (found_y)
*found_y = y;
-
+
return (GdkWindow *)private;
}
+/**
+ * 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_drawable_get_display (GDK_DRAWABLE (window));
+
+ if (toplevel && !gdk_window_is_offscreen ((GdkWindowObject *)toplevel))
+ _gdk_windowing_window_beep (toplevel);
+ else
+ gdk_display_beep (display);
+}
+
static const guint type_masks[] = {
GDK_SUBSTRUCTURE_MASK, /* GDK_DELETE = 0 */
GDK_STRUCTURE_MASK, /* GDK_DESTROY = 1 */
/* send motion events if the right buttons are down */
static guint
update_evmask_for_button_motion (guint evmask,
- GdkModifierType mask)
+ GdkModifierType mask)
{
if (evmask & GDK_BUTTON_MOTION_MASK &&
mask & (GDK_BUTTON1_MASK |
is_button_type (GdkEventType type)
{
return type == GDK_BUTTON_PRESS ||
- type == GDK_2BUTTON_PRESS ||
- type == GDK_3BUTTON_PRESS ||
- type == GDK_BUTTON_RELEASE ||
- type == GDK_SCROLL;
+ type == GDK_2BUTTON_PRESS ||
+ type == GDK_3BUTTON_PRESS ||
+ type == GDK_BUTTON_RELEASE ||
+ type == GDK_SCROLL;
}
static gboolean
is_motion_type (GdkEventType type)
{
return type == GDK_MOTION_NOTIFY ||
- type == GDK_ENTER_NOTIFY ||
- type == GDK_LEAVE_NOTIFY;
+ type == GDK_ENTER_NOTIFY ||
+ type == GDK_LEAVE_NOTIFY;
}
static GdkWindowObject *
while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
{
path1 = g_list_prepend (path1, tmp);
- tmp = tmp->parent;
+ tmp = get_event_parent (tmp);
}
tmp = win2;
while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
{
path2 = g_list_prepend (path2, tmp);
- tmp = tmp->parent;
+ tmp = get_event_parent (tmp);
}
list1 = path1;
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)
{
gint toplevel_y,
GdkModifierType mask,
guint32 time_,
- GdkEvent *event_in_queue)
+ GdkEvent *event_in_queue,
+ gulong serial)
{
GdkEvent *event;
guint32 event_mask;
+ GdkPointerGrabInfo *grab;
+
+ grab = _gdk_display_has_pointer_grab (display, serial);
- if (display->pointer_grab.window != NULL &&
- !display->pointer_grab.owner_events &&
- (GdkWindow *)window != display->pointer_grab.window)
+ if (grab != NULL &&
+ !grab->owner_events &&
+ (GdkWindow *)window != grab->window)
return;
-
+
if (type == GDK_LEAVE_NOTIFY)
event_mask = GDK_LEAVE_NOTIFY_MASK;
else
event_mask = GDK_ENTER_NOTIFY_MASK;
+ if (window->extension_events != 0)
+ GDK_WINDOW_IMPL_GET_IFACE (window->impl)->input_window_crossing ((GdkWindow *)window,
+ type == GDK_ENTER_NOTIFY);
+
if (window->event_mask & event_mask)
{
event = _gdk_make_event ((GdkWindow *)window, type, event_in_queue, TRUE);
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
* before crossing to another toplevel.
*/
void
-_gdk_syntesize_crossing_events (GdkDisplay *display,
- GdkWindow *src,
- GdkWindow *dest,
- GdkCrossingMode mode,
- gint toplevel_x,
- gint toplevel_y,
- GdkModifierType mask,
- guint32 time_,
- GdkEvent *event_in_queue)
+_gdk_synthesize_crossing_events (GdkDisplay *display,
+ GdkWindow *src,
+ GdkWindow *dest,
+ GdkCrossingMode mode,
+ gint toplevel_x,
+ gint toplevel_y,
+ GdkModifierType mask,
+ guint32 time_,
+ GdkEvent *event_in_queue,
+ gulong serial,
+ gboolean non_linear)
{
GdkWindowObject *c;
GdkWindowObject *win, *last, *next;
GList *path, *list;
- gboolean non_linear;
GdkWindowObject *a;
GdkWindowObject *b;
GdkWindowObject *toplevel;
GdkNotifyType notify_type;
/* TODO: Don't send events to toplevel, as we get those from the windowing system */
-
+
a = (GdkWindowObject *)src;
b = (GdkWindowObject *)dest;
if (a == b)
c = find_common_ancestor (a, b);
- non_linear = (c != a) && (c != b);
+ non_linear |= (c != a) && (c != b);
if (a) /* There might not be a source (i.e. if no previous pointer_in_window) */
{
toplevel = (GdkWindowObject *)gdk_window_get_toplevel ((GdkWindow *)a);
-
+
/* Traverse up from a to (excluding) c sending leave events */
if (non_linear)
notify_type = GDK_NOTIFY_NONLINEAR;
NULL,
toplevel_x, toplevel_y,
mask, time_,
- event_in_queue);
-
+ 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 = a->parent;
- while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT)
+ win = get_event_parent (a);
+ while (win != c && win->window_type != GDK_WINDOW_ROOT)
{
send_crossing_event (display, toplevel,
win, GDK_LEAVE_NOTIFY,
(GdkWindow *)last,
toplevel_x, toplevel_y,
mask, time_,
- event_in_queue);
-
+ event_in_queue,
+ serial);
+
last = win;
- win = win->parent;
+ win = get_event_parent (win);
}
}
}
if (b) /* Might not be a dest, e.g. if we're moving out of the window */
{
toplevel = (GdkWindowObject *)gdk_window_get_toplevel ((GdkWindow *)b);
-
+
/* Traverse down from c to b */
if (c != b)
{
path = NULL;
- win = b->parent;
- while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT)
+ win = get_event_parent (b);
+ while (win != c && win->window_type != GDK_WINDOW_ROOT)
{
path = g_list_prepend (path, win);
- win = win->parent;
+ win = get_event_parent (win);
}
-
+
if (non_linear)
notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
else
notify_type = GDK_NOTIFY_VIRTUAL;
-
+
list = path;
while (list)
{
(GdkWindow *)next,
toplevel_x, toplevel_y,
mask, time_,
- event_in_queue);
+ event_in_queue,
+ serial);
}
g_list_free (path);
}
notify_type = GDK_NOTIFY_ANCESTOR;
else
notify_type = GDK_NOTIFY_INFERIOR;
-
+
send_crossing_event (display, toplevel,
b, GDK_ENTER_NOTIFY,
mode,
NULL,
toplevel_x, toplevel_y,
mask, time_,
- event_in_queue);
+ event_in_queue,
+ serial);
}
}
-static GdkWindow *
-get_toplevel (GdkWindow *w)
-{
- GdkWindowObject *private = GDK_WINDOW_OBJECT (w);
-
- while (private->parent != NULL &&
- (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT))
- private = private->parent;
-
- return GDK_WINDOW (private);
-}
-
/* 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.
get_pointer_window (GdkDisplay *display,
GdkWindow *event_window,
gdouble toplevel_x,
- gdouble toplevel_y)
+ gdouble toplevel_y,
+ gulong serial)
{
GdkWindow *pointer_window;
+ GdkPointerGrabInfo *grab;
if (event_window == display->pointer_info.toplevel_under_pointer)
pointer_window =
else
pointer_window = NULL;
- if (display->pointer_grab.window != NULL &&
- !display->pointer_grab.owner_events &&
- pointer_window != display->pointer_grab.window)
+ grab = _gdk_display_has_pointer_grab (display, serial);
+ if (grab != NULL &&
+ !grab->owner_events &&
+ pointer_window != grab->window)
pointer_window = NULL;
-
+
return pointer_window;
}
{
GdkWindowObject *private;
+ /* We don't track this if all native, and it can cause issues
+ with the update_cursor call below */
+ if (_gdk_native_windows)
+ return;
+
private = (GdkWindowObject *)window;
if (display->pointer_info.window_under_pointer)
_gdk_display_enable_motion_hints (display);
}
+/*
+ *--------------------------------------------------------------
+ * gdk_pointer_grab
+ *
+ * Grabs the pointer to a specific window
+ *
+ * Arguments:
+ * "window" is the window which will receive the grab
+ * "owner_events" specifies whether events will be reported as is,
+ * or relative to "window"
+ * "event_mask" masks only interesting events
+ * "confine_to" limits the cursor movement to the specified window
+ * "cursor" changes the cursor for the duration of the grab
+ * "time" specifies the time
+ *
+ * Results:
+ *
+ * Side effects:
+ * requires a corresponding call to gdk_pointer_ungrab
+ *
+ *--------------------------------------------------------------
+ */
+GdkGrabStatus
+gdk_pointer_grab (GdkWindow * window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkWindow * confine_to,
+ GdkCursor * cursor,
+ guint32 time)
+{
+ GdkWindow *native;
+ GdkDisplay *display;
+ GdkGrabStatus res;
+ gulong serial;
+
+ 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;
+
+ if (_gdk_native_windows)
+ native = window;
+ else
+ native = gdk_window_get_toplevel (window);
+ while (gdk_window_is_offscreen ((GdkWindowObject *)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_drawable_get_display (window);
+
+ serial = _gdk_windowing_window_get_next_serial (display);
+
+ res = _gdk_windowing_pointer_grab (window,
+ native,
+ owner_events,
+ event_mask,
+ confine_to,
+ cursor,
+ time);
+
+ if (res == GDK_GRAB_SUCCESS)
+ _gdk_display_add_pointer_grab (display,
+ window,
+ native,
+ owner_events,
+ event_mask,
+ serial,
+ time,
+ FALSE);
+
+ return res;
+}
+
+/**
+ * gdk_window_geometry_changed:
+ * @window: a #GdkWindow
+ *
+ * Since: 2.18
+ */
void
-_gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
+gdk_window_geometry_changed (GdkWindow *window)
+{
+ _gdk_synthesize_crossing_events_for_geometry_change (window);
+}
+
+static gboolean
+do_synthesize_crossing_event (gpointer data)
{
GdkDisplay *display;
GdkWindow *changed_toplevel;
+ GdkWindowObject *changed_toplevel_priv;
GdkWindow *new_window_under_pointer;
+ gulong serial;
+
+ changed_toplevel = data;
+ changed_toplevel_priv = (GdkWindowObject *)changed_toplevel;
+
+ changed_toplevel_priv->synthesize_crossing_event_queued = FALSE;
+
+ if (GDK_WINDOW_DESTROYED (changed_toplevel))
+ return FALSE;
+
+ display = gdk_drawable_get_display (changed_toplevel);
+ serial = _gdk_windowing_window_get_next_serial (display);
- changed_toplevel = get_toplevel (changed_window);
-
- display = gdk_drawable_get_display (changed_window);
if (changed_toplevel == display->pointer_info.toplevel_under_pointer)
{
new_window_under_pointer =
get_pointer_window (display, changed_toplevel,
display->pointer_info.toplevel_x,
- display->pointer_info.toplevel_y);
+ display->pointer_info.toplevel_y,
+ serial);
if (new_window_under_pointer !=
display->pointer_info.window_under_pointer)
{
- _gdk_syntesize_crossing_events (display,
- display->pointer_info.window_under_pointer,
- new_window_under_pointer,
- GDK_CROSSING_NORMAL,
- display->pointer_info.toplevel_x,
- display->pointer_info.toplevel_y,
- display->pointer_info.state,
- GDK_CURRENT_TIME,
- NULL);
+ _gdk_synthesize_crossing_events (display,
+ display->pointer_info.window_under_pointer,
+ new_window_under_pointer,
+ GDK_CROSSING_NORMAL,
+ display->pointer_info.toplevel_x,
+ display->pointer_info.toplevel_y,
+ display->pointer_info.state,
+ GDK_CURRENT_TIME,
+ NULL,
+ serial,
+ FALSE);
_gdk_display_set_window_under_pointer (display, new_window_under_pointer);
}
}
+
+ return FALSE;
+}
+
+void
+_gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
+{
+ GdkDisplay *display;
+ GdkWindow *toplevel;
+ GdkWindowObject *toplevel_priv;
+
+ if (_gdk_native_windows)
+ return; /* We use the native crossing events if all native */
+
+ display = gdk_drawable_get_display (changed_window);
+
+ toplevel = get_event_toplevel (changed_window);
+ toplevel_priv = (GdkWindowObject *)toplevel;
+
+ if (toplevel == display->pointer_info.toplevel_under_pointer &&
+ !toplevel_priv->synthesize_crossing_event_queued)
+ {
+ toplevel_priv->synthesize_crossing_event_queued = TRUE;
+ g_idle_add_full (GDK_PRIORITY_EVENTS - 1,
+ do_synthesize_crossing_event,
+ g_object_ref (toplevel),
+ g_object_unref);
+ }
}
/* Don't use for crossing events */
GdkWindow *pointer_window,
GdkEventType type,
GdkModifierType mask,
- guint *evmask_out)
+ guint *evmask_out,
+ gulong serial)
{
guint evmask;
GdkWindow *grab_window;
GdkWindowObject *w;
+ GdkPointerGrabInfo *grab;
- if ((display->pointer_grab.window != NULL && !display->pointer_grab.owner_events) ||
- (type == GDK_BUTTON_RELEASE && display->pointer_grab.grab_one_pointer_release_event))
+ grab = _gdk_display_has_pointer_grab (display, serial);
+
+ if (grab != NULL && !grab->owner_events)
{
- evmask = display->pointer_grab.event_mask;
+ evmask = grab->event_mask;
evmask = update_evmask_for_button_motion (evmask, mask);
- if (type == GDK_BUTTON_RELEASE &&
- display->pointer_grab.grab_one_pointer_release_event)
- {
- grab_window = display->pointer_grab.grab_one_pointer_release_event;
- display->pointer_grab.grab_one_pointer_release_event = NULL;
- }
- else
- grab_window = display->pointer_grab.window;
+ grab_window = grab->window;
-
if (evmask & type_masks[type])
{
if (evmask_out)
return (GdkWindow *)w;
}
- w = w->parent;
+ w = get_event_parent (w);
}
- if (display->pointer_grab.window != NULL &&
- display->pointer_grab.owner_events)
+ if (grab != NULL &&
+ grab->owner_events)
{
- evmask = display->pointer_grab.event_mask;
+ evmask = grab->event_mask;
evmask = update_evmask_for_button_motion (evmask, mask);
if (evmask & type_masks[type])
{
if (evmask_out)
*evmask_out = evmask;
- return display->pointer_grab.window;
+ return grab->window;
}
else
return NULL;
GdkEvent *source_event,
gulong serial)
{
- GdkWindow *toplevel_window;
+ GdkWindow *toplevel_window, *event_window;
GdkWindow *pointer_window;
- GdkWindow *cursor_window;
GdkEvent *event;
guint state;
gdouble toplevel_x, toplevel_y;
guint32 time_;
+ gboolean non_linear;
- toplevel_window = source_event->any.window;
+ 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);
+ 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 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,
+ display->pointer_info.window_under_pointer,
+ event_window,
+ source_event->crossing.mode,
+ toplevel_x, toplevel_y,
+ state, time_,
+ source_event,
+ serial,
+ non_linear);
+
+ /* Send subwindow == NULL event */
+ send_crossing_event (display,
+ (GdkWindowObject *)toplevel_window,
+ (GdkWindowObject *)event_window,
+ source_event->type,
+ source_event->crossing.mode,
+ source_event->crossing.detail,
+ NULL,
+ toplevel_x, toplevel_y,
+ state, time_,
+ source_event,
+ serial);
+
+ _gdk_display_set_window_under_pointer (display, NULL);
+ return TRUE;
+ }
+
+ pointer_window = get_pointer_window (display, toplevel_window,
+ 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,
+ (GdkWindowObject *)toplevel_window,
+ (GdkWindowObject *)event_window,
+ source_event->type,
+ source_event->crossing.mode,
+ source_event->crossing.detail,
+ NULL,
+ 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,
+ source_event->crossing.mode,
+ toplevel_x, toplevel_y,
+ state, time_,
+ source_event,
+ serial, non_linear);
+ _gdk_display_set_window_under_pointer (display, pointer_window);
+ return TRUE;
+ }
- pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
if (display->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_syntesize_crossing_events (display,
- display->pointer_info.window_under_pointer,
- pointer_window,
- GDK_CROSSING_NORMAL,
- toplevel_x, toplevel_y,
- state, time_,
- source_event);
+ /* Different than last time, send crossing events */
+ _gdk_synthesize_crossing_events (display,
+ display->pointer_info.window_under_pointer,
+ pointer_window,
+ GDK_CROSSING_NORMAL,
+ toplevel_x, toplevel_y,
+ state, time_,
+ source_event,
+ serial, non_linear);
_gdk_display_set_window_under_pointer (display, pointer_window);
}
else if (source_event->type == GDK_MOTION_NOTIFY)
pointer_window,
source_event->type,
state,
- &evmask);
+ &evmask,
+ serial);
is_hint = FALSE;
-
+
if (event_win &&
(evmask & GDK_POINTER_MOTION_HINT_MASK))
{
display->pointer_info.motion_hint_serial = G_MAXULONG;
}
}
-
- if (event_win)
+
+ if (event_win && !display->ignore_core_events)
{
event = _gdk_make_event (event_win, GDK_MOTION_NOTIFY, source_event, FALSE);
event->motion.time = time_;
}
}
- /* TODO: set cursor from cursor_window, or grab cursor */
- cursor_window = pointer_window;
- if (display->pointer_grab.window &&
- (pointer_window == NULL ||
- !is_parent_of (display->pointer_grab.window, pointer_window)))
- cursor_window = display->pointer_grab.window;
- /* Actually, this should probably happen in synthesize crossing so it works with geometry changes */
-
-
/* 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)
+proxy_button_event (GdkEvent *source_event,
+ gulong serial)
{
- GdkWindow *toplevel_window;
+ GdkWindow *toplevel_window, *event_window;
GdkWindow *event_win;
GdkWindow *pointer_window;
+ GdkWindowObject *parent;
GdkEvent *event;
guint state;
guint32 time_;
GdkWindowObject *w;
type = source_event->any.type;
- toplevel_window = source_event->any.window;
+ 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);
display = gdk_drawable_get_display (source_event->any.window);
+ toplevel_window = convert_native_coords_to_toplevel (event_window,
+ toplevel_x, toplevel_y,
+ &toplevel_x, &toplevel_y);
- if ((type == GDK_BUTTON_PRESS || type == GDK_SCROLL) &&
- display->pointer_grab.window == source_event->any.window &&
- display->pointer_grab.implicit &&
- !display->pointer_grab.converted_implicit)
+ if (type == GDK_BUTTON_PRESS &&
+ _gdk_display_has_pointer_grab (display, serial) == NULL)
{
pointer_window =
_gdk_window_find_descendant_at (toplevel_window,
toplevel_x, toplevel_y,
NULL, NULL);
- /* Find the actual event window, its what gets the grab */
+ /* Find the event window, that gets the grab */
w = (GdkWindowObject *)pointer_window;
- while (w != NULL && w->parent->window_type != GDK_WINDOW_ROOT)
+ while (w != NULL &&
+ (parent = get_event_parent (w)) != NULL &&
+ parent->window_type != GDK_WINDOW_ROOT)
{
if (w->event_mask & GDK_BUTTON_PRESS_MASK)
break;
- w = w->parent;
+ w = parent;
}
pointer_window = (GdkWindow *)w;
-
- if (pointer_window != NULL &&
- pointer_window != source_event->any.window)
- _gdk_display_set_has_pointer_grab (display,
- pointer_window,
- display->pointer_grab.native_window,
- display->pointer_grab.owner_events,
- gdk_window_get_events (pointer_window),
- display->pointer_grab.serial,
- display->pointer_grab.time,
- display->pointer_grab.implicit);
- display->pointer_grab.converted_implicit = TRUE;
- }
-
- pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
-
+
+ _gdk_display_add_pointer_grab (display,
+ pointer_window,
+ toplevel_window,
+ FALSE,
+ gdk_window_get_events (pointer_window),
+ serial,
+ time_,
+ TRUE);
+ _gdk_display_pointer_grab_update (display, serial);
+ }
+
+ pointer_window = get_pointer_window (display, toplevel_window,
+ toplevel_x, toplevel_y,
+ serial);
+
event_win = get_event_window (display,
pointer_window,
- type,
- state,
- NULL);
+ type, state,
+ NULL, serial);
- if (event_win == NULL)
+ if (event_win == NULL || display->ignore_core_events)
return TRUE;
-
+
event = _gdk_make_event (event_win, type, source_event, FALSE);
-
+
switch (type)
{
case GDK_BUTTON_PRESS:
event->button.y_root = source_event->button.y_root;
event->button.state = state;
event->button.device = source_event->button.device;
-
+
if (type == GDK_BUTTON_PRESS)
_gdk_event_button_generate (display, event);
return TRUE;
-
+
case GDK_SCROLL:
event->scroll.direction = source_event->scroll.direction;
convert_toplevel_coords_to_window (event_win,
event->scroll.state = state;
event->scroll.device = source_event->scroll.device;
return TRUE;
-
+
default:
return FALSE;
}
int indent)
{
GdkRectangle r;
-
+
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,
g_print (" impl(0x%lx)", gdk_x11_drawable_get_xid (GDK_DRAWABLE (window)));
#endif
}
-
+
if (window->input_only)
g_print (" input-only");
if (!gdk_window_is_visible ((GdkWindow *)window))
g_print (" hidden");
-
+
g_print (" abs[%d,%d]",
window->abs_x, window->abs_y);
-
+
gdk_region_get_clipbox (window->clip_region, &r);
if (gdk_region_empty (window->clip_region))
g_print (" clipbox[empty]");
else
g_print (" clipbox[%d,%d %dx%d]", r.x, r.y, r.width, r.height);
-
+
g_print ("\n");
}
if (private->input_only && !include_input_only)
return;
-
+
gdk_window_print (private, indent);
for (l = private->children; l != NULL; l = l->next)
#endif /* DEBUG_WINDOW_PRINTING */
+static gboolean
+is_input_event (GdkDisplay *display,
+ GdkEvent *event)
+{
+ GdkDevice *core_pointer;
+
+ core_pointer = gdk_display_get_core_pointer (display);
+ if ((event->type == GDK_MOTION_NOTIFY &&
+ event->motion.device != core_pointer) ||
+ ((event->type == GDK_BUTTON_PRESS ||
+ event->type == GDK_BUTTON_RELEASE) &&
+ event->button.device != core_pointer))
+ return TRUE;
+ return FALSE;
+}
+
void
_gdk_windowing_got_event (GdkDisplay *display,
GList *event_link,
gdouble x, y;
gboolean unlink_event;
guint old_state, old_button;
+ GdkPointerGrabInfo *button_release_grab;
+ gboolean is_toplevel;
+
+ if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
+ display->last_event_time = gdk_event_get_time (event);
+
+ _gdk_display_pointer_grab_update (display,
+ serial);
event_window = event->any.window;
if (!event_window)
return;
-
+
+ if (_gdk_native_windows)
+ {
+ if (event->type == GDK_BUTTON_PRESS &&
+ _gdk_display_has_pointer_grab (display, serial) == NULL)
+ {
+ _gdk_display_add_pointer_grab (display,
+ event_window,
+ event_window,
+ FALSE,
+ gdk_window_get_events (event_window),
+ serial,
+ gdk_event_get_time (event),
+ TRUE);
+ _gdk_display_pointer_grab_update (display,
+ serial);
+ }
+ if (event->type == GDK_BUTTON_RELEASE)
+ {
+ button_release_grab =
+ _gdk_display_has_pointer_grab (display, 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 = TRUE;
+ _gdk_display_pointer_grab_update (display, serial);
+ }
+ }
+
+ if (event->type == GDK_BUTTON_PRESS)
+ _gdk_event_button_generate (display, event);
+
+ return;
+ }
+
event_private = GDK_WINDOW_OBJECT (event_window);
-#ifdef DEBUG_WINDOW_PRINTING
+#ifdef DEBUG_WINDOW_PRINTING
if (event->type == GDK_KEY_PRESS &&
(event->key.keyval == 0xa7 ||
event->key.keyval == 0xbd))
event->key.keyval == 0xbd);
}
#endif
-
+
+ if (event->type == GDK_VISIBILITY_NOTIFY)
+ {
+ event_private->native_visibility = event->visibility.state;
+ gdk_window_update_visibility_recursively (event_private,
+ event_private);
+ return;
+ }
+
+ if (is_input_event (display, event))
+ return;
+
if (!(is_button_type (event->type) ||
is_motion_type (event->type)) ||
- GDK_WINDOW_TYPE (event_private) == GDK_WINDOW_ROOT)
+ event_private->window_type == GDK_WINDOW_ROOT)
return;
- if (event_private->parent != NULL &&
- GDK_WINDOW_TYPE (event_private->parent) != GDK_WINDOW_ROOT)
- {
- GEnumValue *event_type_value, *window_type_value;
+ is_toplevel =
+ event_private->parent == NULL ||
+ event_private->parent->window_type == GDK_WINDOW_ROOT;
+
+ 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_pointer_grab (display, 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.
+ */
- if (GDK_WINDOW_TYPE (event_private) == GDK_WINDOW_FOREIGN)
- return;
-
- event_type_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (GDK_TYPE_EVENT_TYPE),
- event->type);
- window_type_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (GDK_TYPE_WINDOW_TYPE),
- event_private->window_type);
-
- /* We should only get these events on toplevel windows */
- g_warning ("got unexpected event of type %s on non-toplevel window (gtype %s, type %d)",
- event_type_value->value_name,
- window_type_value->value_name,
- GDK_WINDOW_TYPE (event_window));
- return;
- }
+ /* 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 (display->pointer_info.toplevel_under_pointer)
+ g_object_unref (display->pointer_info.toplevel_under_pointer);
+ display->pointer_info.toplevel_under_pointer = g_object_ref (event_window);
+ }
- /* Store last pointer window and position/state */
- if (event->type == GDK_ENTER_NOTIFY &&
- event->crossing.detail != GDK_NOTIFY_INFERIOR)
- {
- if (display->pointer_info.toplevel_under_pointer)
- g_object_unref (display->pointer_info.toplevel_under_pointer);
- display->pointer_info.toplevel_under_pointer = g_object_ref (event_window);
+ unlink_event = TRUE;
+ goto out;
}
- else if (event->type == GDK_LEAVE_NOTIFY &&
- event->crossing.detail != GDK_NOTIFY_INFERIOR &&
- display->pointer_info.toplevel_under_pointer == event_window)
+
+ /* Track toplevel_under_pointer */
+ if (is_toplevel)
{
- if (display->pointer_info.toplevel_under_pointer)
- g_object_unref (display->pointer_info.toplevel_under_pointer);
- display->pointer_info.toplevel_under_pointer = NULL;
+ if (event->type == GDK_ENTER_NOTIFY &&
+ event->crossing.detail != GDK_NOTIFY_INFERIOR)
+ {
+ if (display->pointer_info.toplevel_under_pointer)
+ g_object_unref (display->pointer_info.toplevel_under_pointer);
+ display->pointer_info.toplevel_under_pointer = g_object_ref (event_window);
+ }
+ else if (event->type == GDK_LEAVE_NOTIFY &&
+ event->crossing.detail != GDK_NOTIFY_INFERIOR &&
+ display->pointer_info.toplevel_under_pointer == event_window)
+ {
+ if (display->pointer_info.toplevel_under_pointer)
+ g_object_unref (display->pointer_info.toplevel_under_pointer);
+ display->pointer_info.toplevel_under_pointer = NULL;
+ }
}
+ /* Store last pointer window and position/state */
old_state = display->pointer_info.state;
old_button = display->pointer_info.button;
-
+
gdk_event_get_coords (event, &x, &y);
+ convert_native_coords_to_toplevel (event_window, x, y, &x, &y);
display->pointer_info.toplevel_x = x;
display->pointer_info.toplevel_y = y;
gdk_event_get_state (event, &display->pointer_info.state);
if (display->pointer_info.state != old_state ||
display->pointer_info.button != old_button)
_gdk_display_enable_motion_hints (display);
-
+
unlink_event = FALSE;
if (is_motion_type (event->type))
unlink_event = proxy_pointer_event (display,
- event,
+ event,
serial);
else if (is_button_type (event->type))
- unlink_event = proxy_button_event (event);
+ unlink_event = proxy_button_event (event,
+ serial);
+
+ if (event->type == GDK_BUTTON_RELEASE)
+ {
+ button_release_grab =
+ _gdk_display_has_pointer_grab (display, 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 = TRUE;
+ _gdk_display_pointer_grab_update (display, serial);
+ }
+ }
+ out:
if (unlink_event)
{
_gdk_event_queue_remove_link (display, event_link);
}
}
+
+static GdkWindow *
+get_extension_event_window (GdkDisplay *display,
+ GdkWindow *pointer_window,
+ GdkEventType type,
+ gulong serial)
+{
+ guint evmask;
+ GdkWindow *grab_window;
+ GdkWindowObject *w;
+ GdkPointerGrabInfo *grab;
+
+ grab = _gdk_display_has_pointer_grab (display, serial);
+
+ if (grab != NULL && !grab->owner_events)
+ {
+ evmask = grab->event_mask;
+
+ grab_window = grab->window;
+
+ if (evmask & type_masks[type])
+ return grab_window;
+ else
+ return NULL;
+ }
+
+ w = (GdkWindowObject *)pointer_window;
+ while (w != NULL)
+ {
+ evmask = w->extension_events;
+
+ if (evmask & type_masks[type])
+ return (GdkWindow *)w;
+
+ w = get_event_parent (w);
+ }
+
+ if (grab != NULL &&
+ grab->owner_events)
+ {
+ evmask = grab->event_mask;
+
+ if (evmask & type_masks[type])
+ return grab->window;
+ else
+ return NULL;
+ }
+
+ return NULL;
+}
+
+
+GdkWindow *
+_gdk_window_get_input_window_for_event (GdkWindow *native_window,
+ GdkEventType event_type,
+ int x, int y,
+ gulong serial)
+{
+ GdkDisplay *display;
+ GdkWindow *toplevel_window;
+ GdkWindow *pointer_window;
+ GdkWindow *event_win;
+ gdouble toplevel_x, toplevel_y;
+
+ toplevel_x = x;
+ toplevel_y = y;
+
+ display = gdk_drawable_get_display (native_window);
+ toplevel_window = convert_native_coords_to_toplevel (native_window,
+ toplevel_x, toplevel_y,
+ &toplevel_x, &toplevel_y);
+ pointer_window = get_pointer_window (display, toplevel_window,
+ toplevel_x, toplevel_y, serial);
+ event_win = get_extension_event_window (display,
+ pointer_window,
+ event_type,
+ serial);
+
+ return event_win;
+}
+
+
#define __GDK_WINDOW_C__
#include "gdkaliasdef.c"