diff options
author | Ray Strode <rstrode@redhat.com> | 2007-04-08 20:02:35 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2007-04-08 20:02:35 -0400 |
commit | e93c2261ea14048c594c97ea4cba90f84c6b0b25 (patch) | |
tree | 226aad0b1c1576e545b973f945cfee70f76c7241 | |
parent | a17a4c7eaf01ded2ab08be25d8f9c674d8bfd497 (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.c | 77 | ||||
-rw-r--r-- | src/pop-event-listener.c | 32 | ||||
-rw-r--r-- | src/pop-window-stack.c | 92 | ||||
-rw-r--r-- | src/pop-window-stack.h | 6 | ||||
-rw-r--r-- | src/pop-window-view.c | 49 | ||||
-rw-r--r-- | src/pop-window-view.h | 2 |
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 |