summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2007-04-08 20:02:35 -0400
committerRay Strode <rstrode@redhat.com>2007-04-08 20:02:35 -0400
commite93c2261ea14048c594c97ea4cba90f84c6b0b25 (patch)
tree226aad0b1c1576e545b973f945cfee70f76c7241
parenta17a4c7eaf01ded2ab08be25d8f9c674d8bfd497 (diff)
Try to draw less
Make some motions toward implementing what is described in FIGURING-OUT-WHAT-TO-REDRAW
-rw-r--r--src/pop-demo.c77
-rw-r--r--src/pop-event-listener.c32
-rw-r--r--src/pop-window-stack.c92
-rw-r--r--src/pop-window-stack.h6
-rw-r--r--src/pop-window-view.c49
-rw-r--r--src/pop-window-view.h2
6 files changed, 229 insertions, 29 deletions
diff --git a/src/pop-demo.c b/src/pop-demo.c
index 53aa7de..ac62797 100644
--- a/src/pop-demo.c
+++ b/src/pop-demo.c
@@ -138,11 +138,72 @@ add_window_to_list (GdkWindow *window)
}
static void
+view_subtract_overlapping_region (PopWindowStack *stack,
+ GdkWindow *window,
+ GdkWindow *above_window,
+ GdkRegion **visible_region)
+{
+ PopWindowView *view, *above_view;
+ GdkRegion *difference;
+
+ g_assert (POP_IS_WINDOW_STACK (stack));
+ g_assert (GDK_IS_WINDOW (window));
+ g_assert (GDK_IS_WINDOW (above_window));
+ g_assert (visible_region != NULL);
+
+ above_view = g_object_get_data (G_OBJECT (above_window), "pop-window-view");
+
+ if (!POP_IS_WINDOW_VIEW (above_view))
+ return;
+
+ view = g_object_get_data (G_OBJECT (window), "pop-window-view");
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ difference = pop_window_view_get_difference (view, above_view);
+
+ g_assert (difference != NULL);
+
+ if (*visible_region == NULL)
+ *visible_region = difference;
+ else
+ {
+ gdk_region_intersect (*visible_region, difference);
+ gdk_region_destroy (difference);
+ }
+
+}
+
+static GdkRegion *
+get_view_visible_region (PopWindowStack *stack,
+ PopWindowView *view)
+{
+ GdkWindow *window;
+ GdkRegion *visible_region;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ window = pop_window_view_get_window (view);
+
+ g_assert (GDK_IS_WINDOW (window));
+
+ visible_region = NULL;
+ pop_window_stack_above_window_foreach (stack, window,
+ (PopWindowStackAboveWindowForeachFunc)
+ view_subtract_overlapping_region,
+ &visible_region);
+ if (visible_region == NULL)
+ visible_region = gdk_region_new ();
+
+ return visible_region;
+}
+
+static void
draw_window_from_stack (PopWindowStack *stack,
GdkWindow *window,
cairo_t *cairo_context)
{
PopWindowView *view;
+ GdkRegion *visible_region;
view = g_object_get_data (G_OBJECT (window), "pop-window-view");
@@ -151,9 +212,16 @@ draw_window_from_stack (PopWindowStack *stack,
g_assert (POP_IS_WINDOW_VIEW (view));
- cairo_save (cairo_context);
- pop_window_view_render_to_context (view, cairo_context);
- cairo_restore (cairo_context);
+ visible_region = get_view_visible_region (stack, view);
+
+ if (!gdk_region_empty (visible_region))
+ {
+ cairo_save (cairo_context);
+ pop_window_view_render_to_context (view, cairo_context);
+ cairo_restore (cairo_context);
+ }
+
+ gdk_region_destroy (visible_region);
}
static void
@@ -253,6 +321,7 @@ on_create_window_event (XCreateWindowEvent *window_event,
return;
window = gdk_window_foreign_new (window_event->window);
+
if (window != NULL)
add_window_to_list (window);
else
@@ -356,6 +425,8 @@ main (int argc,
gtk_widget_show (overlay_window);
+ g_print ("overlay window is 0x%lx\n", GDK_WINDOW_XWINDOW (overlay_window->window));
+
gtk_main();
return 0;
diff --git a/src/pop-event-listener.c b/src/pop-event-listener.c
index 70e5297..9667b98 100644
--- a/src/pop-event-listener.c
+++ b/src/pop-event-listener.c
@@ -665,22 +665,24 @@ pop_event_listener_get_cached_window_layer (PopEventListener *listener,
"layer-window-above");
if (cached_window_above)
- cached_window_below = g_object_get_data (G_OBJECT (cached_window_above),
- "pop-event-listener-cached-window-"
- "layer-window-below");
-
- /* referential integrity is broken, assume it's stale
- */
- if (cached_window_below != window)
{
- g_object_set_data (G_OBJECT (window),
- "pop-event-listener-cached-window-"
- "layer-window-above", NULL);
- g_object_set_data (G_OBJECT (window),
- "pop-event-listener-has-cached-window-layer",
- GINT_TO_POINTER (FALSE));
- g_object_unref (cached_window_above);
- return FALSE;
+ cached_window_below = g_object_get_data (G_OBJECT (cached_window_above),
+ "pop-event-listener-cached-window-"
+ "layer-window-below");
+
+ /* referential integrity is broken, assume it's stale
+ */
+ if (cached_window_below != window)
+ {
+ g_object_set_data (G_OBJECT (window),
+ "pop-event-listener-cached-window-"
+ "layer-window-above", NULL);
+ g_object_set_data (G_OBJECT (window),
+ "pop-event-listener-has-cached-window-layer",
+ GINT_TO_POINTER (FALSE));
+ g_object_unref (cached_window_above);
+ return FALSE;
+ }
}
return TRUE;
diff --git a/src/pop-window-stack.c b/src/pop-window-stack.c
index c81193d..8ad0320 100644
--- a/src/pop-window-stack.c
+++ b/src/pop-window-stack.c
@@ -46,6 +46,14 @@ typedef struct
gpointer user_data;
} PopWindowStackForeachClosure;
+typedef struct
+{
+ PopWindowStack *stack;
+ GdkWindow *window;
+ PopWindowStackAboveWindowForeachFunc func;
+ gpointer user_data;
+} PopWindowStackAboveWindowForeachClosure;
+
static void pop_window_stack_finalize (GObject * object);
#if 0
static void pop_window_stack_class_install_signals (PopWindowStackClass *
@@ -276,8 +284,8 @@ pop_window_stack_get_length (PopWindowStack *stack)
}
static void
-pop_window_stack_queue_foreach_func (gpointer data,
- gpointer user_data)
+pop_window_stack_foreach_func (gpointer data,
+ gpointer user_data)
{
GdkWindow *window;
PopWindowStackForeachClosure *closure;
@@ -298,18 +306,55 @@ pop_window_stack_foreach (PopWindowStack *stack,
g_return_if_fail (POP_IS_WINDOW_STACK (stack));
g_return_if_fail (func != NULL);
-#if 0
- /* FIXME: need to listen for display events and keep the list up to date
- * that way instead of constantly rebuilding it
- */
- pop_window_stack_get_initial_window_list (stack);
-#endif
-
closure.stack = stack;
closure.func = func;
closure.user_data = user_data;
- g_queue_foreach (stack->priv->windows, pop_window_stack_queue_foreach_func, &closure);
+ g_queue_foreach (stack->priv->windows, pop_window_stack_foreach_func, &closure);
+}
+
+static void
+pop_window_stack_above_window_foreach_func (gpointer data,
+ gpointer user_data)
+{
+ GdkWindow *above_window;
+ PopWindowStackAboveWindowForeachClosure *closure;
+
+ above_window = (GdkWindow *) data;
+ closure = (PopWindowStackAboveWindowForeachClosure *) user_data;
+
+ closure->func (closure->stack, closure->window, above_window, closure->user_data);
+}
+
+void
+pop_window_stack_above_window_foreach (PopWindowStack *stack,
+ GdkWindow *window,
+ PopWindowStackAboveWindowForeachFunc func,
+ gpointer user_data)
+{
+ PopWindowStackAboveWindowForeachClosure closure;
+ GList *window_link;
+
+ g_return_if_fail (POP_IS_WINDOW_STACK (stack));
+ g_return_if_fail (func != NULL);
+ g_return_if_fail (window != NULL);
+
+ window_link = g_queue_find (stack->priv->windows, window);
+
+ if (window_link == NULL)
+ {
+ g_warning ("window with id 0x%lx is not in window stack\n",
+ GDK_WINDOW_XWINDOW (window));
+ return;
+ }
+
+ closure.stack = stack;
+ closure.window = g_object_ref (window); closure.func = func;
+ closure.user_data = user_data;
+
+ g_list_foreach (window_link->next, pop_window_stack_above_window_foreach_func, &closure);
+
+ g_object_unref (window);
}
static void
@@ -324,6 +369,26 @@ pop_window_stack_clear_window_list (PopWindowStack *stack)
stack->priv->windows = g_queue_new ();
}
+static gboolean
+window_can_output (GdkWindow *window)
+{
+ XWindowAttributes attrs;
+ gboolean received_attrs;
+
+ /* FIXME: this sucks because it requires a server round trip.
+ */
+
+ gdk_error_trap_push ();
+ received_attrs = XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XWINDOW (window),
+ &attrs);
+
+ if (gdk_error_trap_pop () || !received_attrs)
+ return FALSE;
+
+ return attrs.class == InputOutput;
+}
+
static void
pop_window_stack_get_initial_window_list (PopWindowStack *stack)
{
@@ -359,6 +424,13 @@ pop_window_stack_get_initial_window_list (PopWindowStack *stack)
if (window == NULL)
continue;
+ if (!window_can_output (window))
+ {
+ g_print ("excluding window 0x%lx\n", GDK_WINDOW_XWINDOW (window));
+ g_object_unref (window);
+ continue;
+ }
+
g_queue_push_tail (stack->priv->windows, window);
}
XFree (children);
diff --git a/src/pop-window-stack.h b/src/pop-window-stack.h
index b54a450..d8e7803 100644
--- a/src/pop-window-stack.h
+++ b/src/pop-window-stack.h
@@ -38,6 +38,7 @@ typedef struct _PopWindowStackClass PopWindowStackClass;
typedef struct _PopWindowStackPrivate PopWindowStackPrivate;
typedef enum _PopWindowStackError PopWindowStackError;
typedef void (* PopWindowStackForeachFunc) (PopWindowStack *stack, GdkWindow *window, gpointer user_data);
+typedef void (* PopWindowStackAboveWindowForeachFunc) (PopWindowStack *stack, GdkWindow *window, GdkWindow *above_window, gpointer user_data);
struct _PopWindowStack
{
@@ -71,6 +72,11 @@ guint pop_window_stack_get_length (PopWindowStack *stack);
void pop_window_stack_foreach (PopWindowStack *stack,
PopWindowStackForeachFunc func,
gpointer user_data);
+void pop_window_stack_above_window_foreach (PopWindowStack *stack,
+ GdkWindow *window,
+ PopWindowStackAboveWindowForeachFunc func,
+ gpointer user_data);
+
#endif
G_END_DECLS
diff --git a/src/pop-window-view.c b/src/pop-window-view.c
index d3976b6..660c37a 100644
--- a/src/pop-window-view.c
+++ b/src/pop-window-view.c
@@ -48,6 +48,7 @@ struct _PopWindowViewPrivate
Damage damage;
cairo_pattern_t *pattern;
cairo_path_t *clip_path;
+
GdkRectangle damaged_area;
guint is_damaged : 1;
@@ -542,7 +543,7 @@ pop_window_view_enable_window_damage_reporting (PopWindowView *view)
view->priv->damage =
XDamageCreate (GDK_WINDOW_XDISPLAY (view->priv->window),
GDK_WINDOW_XWINDOW (view->priv->window),
- XDamageReportRawRectangles);
+ XDamageReportBoundingBox);
}
static void
@@ -891,6 +892,52 @@ pop_window_view_report_fixed_damage (PopWindowView *view)
view->priv->damaged_area.height = 0;
}
+static GdkRegion *
+pop_window_view_get_bounding_region (PopWindowView *view)
+{
+ GdkRectangle bounding_area;
+
+ g_assert (POP_IS_WINDOW_VIEW (view));
+
+ bounding_area.x = view->priv->x;
+ bounding_area.y = view->priv->y;
+ bounding_area.width = view->priv->width;
+ bounding_area.height = view->priv->height;
+
+ return gdk_region_rectangle (&bounding_area);
+}
+
+GdkRegion *
+pop_window_view_get_difference (PopWindowView *view,
+ PopWindowView *other_view)
+{
+ GdkRegion *view_bounding_region, *other_view_bounding_region;
+
+ g_return_val_if_fail (POP_IS_WINDOW_VIEW (view), NULL);
+ g_return_val_if_fail (POP_IS_WINDOW_VIEW (other_view), NULL);
+
+ if (!gdk_window_is_visible (view->priv->window))
+ return gdk_region_new ();
+
+ view_bounding_region = pop_window_view_get_bounding_region (view);
+
+ if (!gdk_window_is_visible (other_view->priv->window))
+ return view_bounding_region;
+ other_view_bounding_region = pop_window_view_get_bounding_region (other_view);
+
+ /* This is the part of the view that isn't overlapped by the
+ * other view
+ */
+ gdk_region_subtract (view_bounding_region, other_view_bounding_region);
+ gdk_region_destroy (other_view_bounding_region);
+ other_view_bounding_region = NULL;
+
+ /* FIXME: need to also add in overlapping areas where the other view isn't
+ * fully opaque.
+ */
+ return view_bounding_region;
+}
+
void
pop_window_view_render_to_context (PopWindowView *view,
cairo_t *cairo_context)
diff --git a/src/pop-window-view.h b/src/pop-window-view.h
index 40f20d3..3e3bb5b 100644
--- a/src/pop-window-view.h
+++ b/src/pop-window-view.h
@@ -73,6 +73,8 @@ void pop_window_view_unset_window (PopWindowView *view);
GdkWindow *pop_window_view_get_window (PopWindowView *view);
void pop_window_view_get_size (PopWindowView *view, gint *width, gint *height);
void pop_window_view_get_position (PopWindowView *view, int *x, int *y);
+GdkRegion *pop_window_view_get_difference (PopWindowView *view,
+ PopWindowView *other_view);
void pop_window_view_render_to_context (PopWindowView *view,
cairo_t *cairo_context);
#endif