#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"
LAST_SIGNAL
};
+enum {
+ PROP_0,
+ PROP_CURSOR
+};
+
struct _GdkWindowPaint
{
GdkRegion *region;
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_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 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 };
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;
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
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)
{
* siblings in parents above window
*/
clip_region_changed = FALSE;
- if (recalculate_clip && private->viewable)
+ 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 &&
- private->parent->window_type != GDK_WINDOW_ROOT &&
- /* For foreign children, don't remove local parents, as parent
- may not be mapped yet, and the non-native parents are not really
- enforced for it anyways. */
- private->window_type != GDK_WINDOW_FOREIGN)
+ 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);
- }
+ /* 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);
+ /* 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))
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;
+ 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)
static GdkEventMask
get_native_event_mask (GdkWindowObject *private)
{
- if (private->window_type != GDK_WINDOW_ROOT &&
- private->window_type != GDK_WINDOW_FOREIGN)
+ if (_gdk_native_windows ||
+ private->window_type == GDK_WINDOW_ROOT ||
+ private->window_type == GDK_WINDOW_FOREIGN)
+ return private->event_mask;
+ else
{
return
/* We need thse for all native window so we can emulate
GDK_BUTTON2_MOTION_MASK |
GDK_BUTTON3_MOTION_MASK));
}
- else
- return private->event_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. */
+ * 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)
{
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;
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 */
+ 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 &&
/* 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 */
- sync_native_window_stack_position (window);
+ if (!_gdk_window_has_impl (real_parent))
+ sync_native_window_stack_position (window);
}
else
{
GdkWindowObject *new_parent_private;
GdkWindowObject *old_parent;
GdkScreen *screen;
- gboolean show, was_toplevel, was_mapped;
+ 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));
private->redirect = NULL;
}
- was_toplevel = private->parent == NULL;
was_mapped = GDK_WINDOW_IS_MAPPED (window);
show = FALSE;
new_parent_private->window_type == GDK_WINDOW_FOREIGN)
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);
}
/* 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)
/* 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 */
- sync_native_window_stack_position (window);
+ if (!gdk_window_has_impl (new_parent_private))
+ sync_native_window_stack_position (window);
}
if (show)
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 */
+ * 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)
{
/* The shape may not have been set, as the clip region doesn't actually
change, so do it here manually */
- if (private->viewable)
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0);
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0);
reparent_to_impl (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;
}
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 */
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;
-
+ gdk_drawable_get_size (paint->pixmap, &width, &height);
paint->surface = _gdk_drawable_create_cairo_surface (paint->pixmap, width, height);
-
}
else
{
}
tmp_gc = _gdk_drawable_get_subwindow_scratch_gc ((GdkWindow *)private);
+ 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); /* Temporarily move to source area */
+ 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_region_offset (dest_region, dx, dy); /* back to dest area */
-
- gdk_region_get_clipbox (dest_region, ©_rect);
- gdk_gc_set_clip_region (tmp_gc, dest_region);
gdk_draw_drawable (impl_window->impl,
tmp_gc,
private->impl,
}
}
-/* 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 */
/* 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);
guarantee ordering. */
gdk_window_flush ((GdkWindow *)drawable);
- /* Don't clip when drawing to root */
- if (private->window_type != GDK_WINDOW_ROOT)
+ /* 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;
BEGIN_DRAW;
- gdk_draw_drawable (impl, gc, src, xsrc, ysrc,
- xdest - x_offset, ydest - y_offset, width, height);
+ /* 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)
{
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,
gdk_window_clear_backing_region_redirect (window, region);
if (GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_region &&
- gdk_window_has_impl (private))
+ clears_on_native (private))
{
GdkRegion *copy;
copy = gdk_region_copy (region);
gint y_dither)
{
GdkWindowObject *private = (GdkWindowObject *)drawable;
+ GdkDrawableClass *klass;
if (GDK_WINDOW_DESTROYED (drawable))
return;
gc = _gdk_drawable_get_scratch_gc (drawable, FALSE);
BEGIN_DRAW;
+
+ klass = GDK_DRAWABLE_GET_CLASS (impl);
+
if (private->paint_stack)
- gdk_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);
+ 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
- gdk_draw_pixbuf (impl, gc, pixbuf, src_x, src_y,
- dest_x - x_offset, dest_y - y_offset,
- width, height,
- dither, x_dither, y_dither);
+ 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;
}
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_with_children);
/* 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);
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
gdk_region_destroy (child_region);
}
- if (!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)
{
if (private->event_mask & GDK_EXPOSURE_MASK)
{
}
}
+/* 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.
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 */
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);
-
-
- /* No need to do any moves that will end up over the update area */
+ /* 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;
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);
private->outstanding_moves =
g_list_delete_link (private->outstanding_moves, l);
}
- else
+ else /* move back */
gdk_region_offset (move->dest_region, move->dx, move->dy);
}
gdk_region_destroy (remove);
}
- gdk_region_get_clipbox (expose_region, &clip_box);
+ /* 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);
- if (end_implicit) /* rendering is not double buffered, do moves now */
+ 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)
{
- /* Do moves right before exposes are rendered */
+ /* 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);
}
-
- if (expose_region != update_area)
- gdk_region_destroy (expose_region);
+ gdk_region_destroy (expose_region);
}
if (!save_region)
gdk_region_destroy (update_area);
no actual invalid area */
gdk_window_flush_outstanding_moves (window);
}
+
+ g_object_unref (window);
}
static void
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) &&
/* 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);
}
/**
if (private->input_only ||
!private->viewable ||
- gdk_region_empty (region))
+ gdk_region_empty (region) ||
+ private->window_type == GDK_WINDOW_ROOT)
return;
visible_region = gdk_drawable_get_visible_region (window);
**/
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);
/* Just do native raise for toplevels */
if (private->parent == NULL ||
- private->parent->window_type == 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);
}
}
}
-/* Showing a non-native parent may cause children to become visible,
- we need to handle this by manually showing them then. To simplify
- things we hide them all when they are not visible. */
-static void
-show_all_visible_impls (GdkWindowObject *private, gboolean already_mapped)
-{
- GdkWindowObject *child;
- GList *l;
-
- for (l = private->children; l != NULL; l = l->next)
- {
- child = l->data;
-
- /* For foreign windows, only show if if was
- explicitly hidden, otherwise we might cause
- suprising things to happen to the other client. */
- if (GDK_WINDOW_IS_MAPPED (child) &&
- child->window_type != GDK_WINDOW_FOREIGN)
- show_all_visible_impls (child, FALSE);
- }
-
- if (gdk_window_has_impl (private))
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show ((GdkWindow *)private, already_mapped);
-}
-
-static void
+/* Returns TRUE If the native window was mapped or unmapped */
+static gboolean
set_viewable (GdkWindowObject *w,
gboolean val)
{
GdkWindowObject *child;
GList *l;
+ if (w->viewable == val)
+ return FALSE;
+
w->viewable = val;
+ if (val)
+ recompute_visible_regions (w, FALSE, FALSE);
+
for (l = w->children; l != NULL; l = l->next)
{
child = l->data;
child->window_type != GDK_WINDOW_FOREIGN)
set_viewable (child, val);
}
+
+ 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;
}
-void
+/* Returns TRUE If the native window was mapped or unmapped */
+gboolean
_gdk_window_update_viewable (GdkWindow *window)
{
GdkWindowObject *priv = (GdkWindowObject *)window;
else
viewable = FALSE;
- if (priv->viewable != viewable)
- set_viewable (priv, viewable);
+ 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 */
private->state = 0;
}
- _gdk_window_update_viewable (window);
+ did_show = _gdk_window_update_viewable (window);
- if (gdk_window_is_viewable (window))
- show_all_visible_impls (private, was_mapped);
+ /* 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))
{
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 ||
- private->parent->window_type == 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);
}
gdk_window_show_internal (window, TRUE);
}
-/* Hiding a non-native parent may cause parents to become non-visible,
- even if their parent native window is visible. We need to handle this
- by manually hiding them then. To simplify things we hide them all
- when they are not visible. */
-static void
-hide_all_visible_impls (GdkWindowObject *private)
-{
- GdkWindowObject *child;
- GList *l;
-
- for (l = private->children; l != NULL; l = l->next)
- {
- child = l->data;
-
- /* For foreign windows, only hide if if was
- explicitly hidden, otherwise we might cause
- suprising things to happen to the other client. */
- if (GDK_WINDOW_IS_MAPPED (child) &&
- child->window_type != GDK_WINDOW_FOREIGN)
- 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))
{
private->state = GDK_WINDOW_STATE_WITHDRAWN;
}
- _gdk_window_update_viewable (window);
+ did_hide = _gdk_window_update_viewable (window);
- if (was_viewable)
- hide_all_visible_impls (private);
+ /* 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);
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);
/* convert from window coords to impl */
gdk_region_offset (copy_area, private->abs_x, private->abs_y);
-
move_region_on_impl (impl_window, copy_area, dx, dy); /* Takes ownership of copy_area */
+
+ gdk_window_invalidate_region (window, nocopy_area, FALSE);
+ gdk_region_destroy (nocopy_area);
}
/**
GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, private->bg_pixmap);
}
+/**
+ * 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 *private;
+
+ g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
+
+ private = (GdkWindowObject *) window;
+
+ return private->cursor;
+}
+
/**
* gdk_window_set_cursor:
* @window: a #GdkWindow
if (cursor)
private->cursor = gdk_cursor_ref (cursor);
- if (_gdk_window_event_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)
{
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)
gdk_region_destroy (private->shape);
old_region = NULL;
- if (private->viewable)
+ if (GDK_WINDOW_IS_MAPPED (window))
old_region = gdk_region_copy (private->clip_region);
if (shape_region)
/**
* 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
*
region,
x, y);
- gdk_region_destroy (region);
+ if (region != NULL)
+ gdk_region_destroy (region);
}
/**
toplevel = get_event_toplevel (window);
display = gdk_drawable_get_display (GDK_DRAWABLE (window));
- if (toplevel && gdk_window_is_offscreen ((GdkWindowObject *)toplevel))
+ if (toplevel && !gdk_window_is_offscreen ((GdkWindowObject *)toplevel))
_gdk_windowing_window_beep (toplevel);
else
gdk_display_beep (display);
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)
{
{
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_window_is_viewable (window))
return GDK_GRAB_NOT_VIEWABLE;
- native = gdk_window_get_toplevel (window);
+ 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);
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);
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