[gtk+/client-side-windows: 99/284] Make moving subwindows correctly handle native windows
- From: Alexander Larsson <alexl src gnome org>
- To: svn-commits-list gnome org
- Subject: [gtk+/client-side-windows: 99/284] Make moving subwindows correctly handle native windows
- Date: Thu, 2 Apr 2009 14:08:03 -0400 (EDT)
commit 905d3289330af0b66f3efffc58f14eb7e7f2af56
Author: Alexander Larsson <alexl redhat com>
Date: Tue Jan 20 23:03:16 2009 +0100
Make moving subwindows correctly handle native windows
Whenever a native window is moved this causes an immediate change in
the window (the window content is copied). This change conflicts can
conflict with outstanding moves or other cached changed, so we need
to flush all outstanding moves in the related windows.
To simplify the code for window move/resize the toplevel version was
split out to its own function.
Move native windows after recomputing so that we get the right new
shape before moving (and the implied copy). This means we're not
copying too much data.
Take into account the area of a moved window that contains native
subwindows, as these affect things in two ways:
First of all we shouldn't copy the original window location, as that
is copied by the native window move.
Secondly, we can't copy things that would end up copying from the
native window move destination, as the data that used to be there is
now destroyed by the native window move.
---
gdk/gdkwindow.c | 273 ++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 230 insertions(+), 43 deletions(-)
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 584e595..3122628 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -238,10 +238,11 @@ static void apply_redirect_to_children (GdkWindowObject *private,
static void remove_redirect_from_children (GdkWindowObject *private,
GdkWindowRedirect *redirect);
-static void recompute_visible_regions (GdkWindowObject *private,
- gboolean recalculate_siblings,
- gboolean recalculate_children);
-static void gdk_window_flush (GdkWindow *window);
+static void recompute_visible_regions (GdkWindowObject *private,
+ gboolean recalculate_siblings,
+ gboolean recalculate_children);
+static void gdk_window_flush (GdkWindow *window);
+static void gdk_window_flush_recursive (GdkWindowObject *window);
static void do_move_region_bits_on_impl (GdkWindowObject *private,
GdkDrawable *dest,
int dest_off_x, int dest_off_y,
@@ -2610,6 +2611,32 @@ gdk_window_flush (GdkWindow *window)
}
static void
+gdk_window_flush_recursive_helper (GdkWindowObject *window,
+ GdkWindow *impl)
+{
+ GdkWindowObject *child;
+ GList *l;
+
+ for (l = window->children; l != NULL; l = l->next)
+ {
+ child = l->data;
+
+ if (child->impl == impl)
+ /* Same impl, ignore */
+ gdk_window_flush_recursive_helper (child, impl);
+ else
+ gdk_window_flush_recursive (child);
+ }
+}
+
+static void
+gdk_window_flush_recursive (GdkWindowObject *window)
+{
+ gdk_window_flush ((GdkWindow *)window);
+ gdk_window_flush_recursive_helper (window, window->impl);
+}
+
+static void
gdk_window_get_offsets (GdkWindow *window,
gint *x_offset,
gint *y_offset)
@@ -5792,6 +5819,72 @@ gdk_window_get_events (GdkWindow *window)
}
static void
+gdk_window_move_resize_toplevel (GdkWindow *window,
+ gboolean with_move,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GdkWindowObject *private;
+ GdkRegion *old_region, *new_region;
+ GdkWindowObject *impl_window;
+ gboolean expose;
+ int old_x, old_y, old_abs_x, old_abs_y;
+ int dx, dy;
+ gboolean is_resize;
+
+ private = (GdkWindowObject *) window;
+
+ expose = FALSE;
+ old_region = NULL;
+
+ impl_window = gdk_window_get_impl_window (private);
+
+ old_x = private->x;
+ old_y = private->y;
+
+ is_resize = (width != -1) || (height != -1);
+
+ if (GDK_WINDOW_IS_MAPPED (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);
+}
+
+
+static void
move_native_children (GdkWindowObject *private)
{
GList *l;
@@ -5808,6 +5901,60 @@ move_native_children (GdkWindowObject *private)
}
}
+static gboolean
+collect_native_child_region_helper (GdkWindowObject *window,
+ GdkWindow *impl,
+ GdkRegion **region,
+ int x_offset,
+ int y_offset)
+{
+ GdkWindowObject *child;
+ GdkRegion *tmp;
+ GList *l;
+
+ for (l = window->children; l != NULL; l = l->next)
+ {
+ child = l->data;
+
+ if (child->impl != impl)
+ {
+ tmp = gdk_region_copy (child->clip_region);
+ gdk_region_offset (tmp,
+ x_offset + child->x,
+ y_offset + child->y);
+ if (*region == NULL)
+ *region = tmp;
+ else
+ {
+ gdk_region_union (*region, tmp);
+ gdk_region_destroy (tmp);
+ }
+ }
+ else
+ collect_native_child_region_helper (child, impl, region,
+ x_offset + child->x,
+ y_offset + child->y);
+ }
+
+ return FALSE;
+}
+
+static GdkRegion *
+collect_native_child_region (GdkWindowObject *window)
+{
+ GdkRegion *region;
+
+ if (gdk_window_has_impl (window))
+ return gdk_region_copy (window->clip_region);
+
+ region = NULL;
+
+ collect_native_child_region_helper (window, window->impl, ®ion, 0, 0);
+
+ return region;
+}
+
+
static void
gdk_window_move_resize_internal (GdkWindow *window,
gboolean with_move,
@@ -5818,12 +5965,11 @@ gdk_window_move_resize_internal (GdkWindow *window,
{
GdkWindowObject *private;
GdkRegion *old_region, *new_region, *copy_area;
+ GdkRegion *old_native_child_region, *new_native_child_region;
GdkWindowObject *impl_window;
gboolean expose;
int old_x, old_y, old_abs_x, old_abs_y;
int dx, dy;
- gboolean do_move_native_children;
- gboolean is_toplevel, is_resize;
g_return_if_fail (GDK_IS_WINDOW (window));
@@ -5831,7 +5977,15 @@ gdk_window_move_resize_internal (GdkWindow *window,
if (private->destroyed)
return;
- do_move_native_children = FALSE;
+ if (private->parent == NULL ||
+ GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
+ {
+ gdk_window_move_resize_toplevel (window, with_move, x, y, width, height);
+ return;
+ }
+
+ /* Handle child windows */
+
expose = FALSE;
old_region = NULL;
@@ -5840,14 +5994,7 @@ gdk_window_move_resize_internal (GdkWindow *window,
old_x = private->x;
old_y = private->y;
- is_toplevel =
- private->parent == NULL ||
- GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT;
-
- is_resize = (width != -1) || (height != -1);
-
if (GDK_WINDOW_IS_MAPPED (window) &&
- (!is_toplevel || is_resize) &&
!private->input_only)
{
expose = TRUE;
@@ -5856,44 +6003,62 @@ gdk_window_move_resize_internal (GdkWindow *window,
/* Adjust region to parent window coords */
gdk_region_offset (old_region, private->x, private->y);
}
-
- if (gdk_window_has_impl (private))
+
+ old_native_child_region = collect_native_child_region (private);
+ if (old_native_child_region)
{
- GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, with_move, x, y, width, height);
+ /* 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);
}
- else
+
+ /* Set the new position and size */
+ if (with_move)
{
- if (with_move)
- {
- private->x = x;
- private->y = y;
- }
- if (!(width < 0 && height < 0))
- {
- if (width < 1)
- width = 1;
- private->width = width;
- if (height < 1)
- height = 1;
- private->height = height;
- }
-
- do_move_native_children = TRUE;
+ private->x = x;
+ private->y = y;
}
-
+ if (!(width < 0 && height < 0))
+ {
+ if (width < 1)
+ width = 1;
+ private->width = width;
+ if (height < 1)
+ 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;
- /* Avoid recomputing for pure toplevel moves, for performance reasons */
- if (!is_toplevel || is_resize)
- recompute_visible_regions (private, TRUE, FALSE);
+ recompute_visible_regions (private, TRUE, FALSE);
+
+ new_native_child_region = NULL;
+ if (old_native_child_region)
+ {
+ new_native_child_region = collect_native_child_region (private);
+ /* Adjust region to parent window coords */
+ gdk_region_offset (new_native_child_region, private->x, private->y);
+ }
- if (do_move_native_children &&
- (old_abs_x != private->abs_x ||
- old_abs_y != private->abs_y))
+ if (gdk_window_has_impl (private))
+ {
+ /* Do the actual move after recomputing things, as this will have set the shape to
+ the now correct one, thus avoiding copying regions that should not be copied. */
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, with_move, x, y, width, height);
+ }
+ else if (old_abs_x != private->abs_x ||
+ old_abs_y != private->abs_y)
move_native_children (private);
if (expose)
@@ -5913,11 +6078,27 @@ gdk_window_move_resize_internal (GdkWindow *window,
* invalidated (including children) as this is newly exposed
*/
copy_area = gdk_region_copy (new_region);
-
- gdk_region_union (new_region, old_region);
+ gdk_region_union (new_region, old_region);
+
+ if (old_native_child_region)
+ {
+ /* Don't copy from inside native children, as this is copied by
+ * the native window move.
+ */
+ gdk_region_subtract (old_region, old_native_child_region);
+ }
gdk_region_offset (old_region, dx, dy);
+
gdk_region_intersect (copy_area, old_region);
+
+ if (new_native_child_region)
+ {
+ /* Don't copy any bits that would cause a read from the moved
+ native windows, as we can't read that data */
+ 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);
@@ -5945,6 +6126,12 @@ gdk_window_move_resize_internal (GdkWindow *window,
gdk_region_destroy (new_region);
}
+ if (old_native_child_region)
+ {
+ gdk_region_destroy (old_native_child_region);
+ gdk_region_destroy (new_native_child_region);
+ }
+
_gdk_syntesize_crossing_events_for_geometry_change (window);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]