[gtk+] Don't unnecessarily clear windows with no exposure mask set



commit 9e51c10edc50333997a28c221b200cc6f83bdcef
Author: Alexander Larsson <alexl redhat com>
Date:   Wed Nov 4 14:03:04 2009 +0100

    Don't unnecessarily clear windows with no exposure mask set
    
    When we just invalidate some area from the app we don't need to clear
    windows with no exposure mask, because that wouldn't have happened pre-csw
    anyway. Additionally we can avoid such clearing for native windows in cases
    where the xserver already did the clearing like on exposes or when resizing
    toplevels.
    
    This means we don't fully redraw a GtkSocket when it resizes, thus
    avoiding flicker in gnome-mplayer as reported in this bug:
    https://bugzilla.gnome.org/show_bug.cgi?id=598050

 gdk/gdkwindow.c |  198 +++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 133 insertions(+), 65 deletions(-)
---
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 889a2d1..479ae59 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -134,6 +134,12 @@ enum {
   PROP_CURSOR
 };
 
+typedef enum {
+  CLEAR_BG_NONE,
+  CLEAR_BG_WINCLEARED, /* Clear backgrounds except those that the window system clears */
+  CLEAR_BG_ALL
+} ClearBg;
+
 struct _GdkWindowPaint
 {
   GdkRegion *region;
@@ -332,6 +338,14 @@ static void update_cursor               (GdkDisplay *display);
 static void impl_window_add_update_area (GdkWindowObject *impl_window,
 					 GdkRegion *region);
 static void gdk_window_region_move_free (GdkWindowRegionMove *move);
+static void gdk_window_invalidate_region_full (GdkWindow       *window,
+					       const GdkRegion *region,
+					       gboolean         invalidate_children,
+					       ClearBg          clear_bg);
+static void gdk_window_invalidate_rect_full (GdkWindow          *window,
+					     const GdkRectangle *rect,
+					     gboolean            invalidate_children,
+					     ClearBg             clear_bg);
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
@@ -3922,9 +3936,10 @@ gdk_window_draw_drawable (GdkDrawable *drawable,
 	  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_window_invalidate_region_full (GDK_WINDOW (private),
+					      exposure_region,
+					      _gdk_gc_get_subwindow (gc) == GDK_INCLUDE_INFERIORS,
+					      CLEAR_BG_ALL);
 
 	  gdk_region_destroy (exposure_region);
 	}
@@ -5423,21 +5438,11 @@ gdk_window_process_updates (GdkWindow *window,
   g_object_unref (window);
 }
 
-/**
- * gdk_window_invalidate_rect:
- * @window: a #GdkWindow
- * @rect: rectangle to invalidate or %NULL to invalidate the whole
- *      window
- * @invalidate_children: whether to also invalidate child windows
- *
- * A convenience wrapper around gdk_window_invalidate_region() which
- * invalidates a rectangular region. See
- * gdk_window_invalidate_region() for details.
- **/
-void
-gdk_window_invalidate_rect (GdkWindow          *window,
-			    const GdkRectangle *rect,
-			    gboolean            invalidate_children)
+static void
+gdk_window_invalidate_rect_full (GdkWindow          *window,
+				  const GdkRectangle *rect,
+				  gboolean            invalidate_children,
+				  ClearBg             clear_bg)
 {
   GdkRectangle window_rect;
   GdkRegion *region;
@@ -5462,10 +5467,29 @@ gdk_window_invalidate_rect (GdkWindow          *window,
     }
 
   region = gdk_region_rectangle (rect);
-  gdk_window_invalidate_region (window, region, invalidate_children);
+  gdk_window_invalidate_region_full (window, region, invalidate_children, clear_bg);
   gdk_region_destroy (region);
 }
 
+/**
+ * gdk_window_invalidate_rect:
+ * @window: a #GdkWindow
+ * @rect: rectangle to invalidate or %NULL to invalidate the whole
+ *      window
+ * @invalidate_children: whether to also invalidate child windows
+ *
+ * A convenience wrapper around gdk_window_invalidate_region() which
+ * invalidates a rectangular region. See
+ * gdk_window_invalidate_region() for details.
+ **/
+void
+gdk_window_invalidate_rect (GdkWindow          *window,
+			    const GdkRectangle *rect,
+			    gboolean            invalidate_children)
+{
+  gdk_window_invalidate_rect_full (window, rect, invalidate_children, CLEAR_BG_NONE);
+}
+
 static void
 draw_ugly_color (GdkWindow       *window,
 		 const GdkRegion *region)
@@ -5504,37 +5528,23 @@ impl_window_add_update_area (GdkWindowObject *impl_window,
     }
 }
 
-/**
- * gdk_window_invalidate_maybe_recurse:
- * @window: a #GdkWindow
- * @region: a #GdkRegion
- * @child_func: function to use to decide if to recurse to a child,
- *              %NULL means never recurse.
- * @user_data: data passed to @child_func
- *
- * 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_process_updates() sends one or more expose events to the
- * window, which together cover the entire update area. An
- * application would normally redraw the contents of @window in
- * response to those expose events.
- *
- * GDK will call gdk_window_process_all_updates() on your behalf
- * whenever your program returns to the main loop and becomes idle, so
- * normally there's no need to do that manually, you just need to
- * invalidate regions that you know should be redrawn.
- *
- * The @child_func parameter controls whether the region of
- * each child window that intersects @region will also be invalidated.
- * Only children for which @child_func returns TRUE will have the area
- * invalidated.
- **/
-void
-gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
-				     const GdkRegion *region,
-				     gboolean       (*child_func) (GdkWindow *,
-								   gpointer),
-				     gpointer   user_data)
+/* clear_bg controls if the region will be cleared to
+ * the background color/pixmap if the exposure mask is not
+ * set for the window, whereas this might not otherwise be
+ * done (unless necessary to emulate background settings).
+ * Set this to CLEAR_BG_WINCLEARED or CLEAR_BG_ALL if you
+ * need to clear the background, such as when exposing the area beneath a
+ * hidden or moved window, but not when an app requests repaint or when the
+ * windowing system exposes a newly visible area (because then the windowing
+ * system has already cleared the area).
+ */
+static void
+gdk_window_invalidate_maybe_recurse_full (GdkWindow       *window,
+					  const GdkRegion *region,
+					  ClearBg          clear_bg,
+					  gboolean       (*child_func) (GdkWindow *,
+									gpointer),
+					  gpointer   user_data)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
   GdkWindowObject *impl_window;
@@ -5585,8 +5595,8 @@ gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
 	      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_window_invalidate_maybe_recurse_full ((GdkWindow *)child,
+							child_region, clear_bg, child_func, user_data);
 
 	      gdk_region_destroy (tmp);
 	    }
@@ -5610,12 +5620,58 @@ gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
 
       /* Convert to impl coords */
       gdk_region_offset (visible_region, private->abs_x, private->abs_y);
-      impl_window_add_update_area (impl_window, visible_region);
+
+      /* Only invalidate area if app requested expose events or if
+	 we need to clear the area (by request or to emulate background
+	 clearing for non-native windows or native windows with no support
+	 for window backgrounds */
+      if (private->event_mask & GDK_EXPOSURE_MASK ||
+	  clear_bg == CLEAR_BG_ALL ||
+	  (clear_bg == CLEAR_BG_WINCLEARED &&
+	   (!clears_as_native (private) ||
+	    !GDK_WINDOW_IMPL_GET_IFACE (private->impl)->supports_native_bg)))
+	impl_window_add_update_area (impl_window, visible_region);
     }
 
   gdk_region_destroy (visible_region);
 }
 
+/**
+ * gdk_window_invalidate_maybe_recurse:
+ * @window: a #GdkWindow
+ * @region: a #GdkRegion
+ * @child_func: function to use to decide if to recurse to a child,
+ *              %NULL means never recurse.
+ * @user_data: data passed to @child_func
+ *
+ * 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_process_updates() sends one or more expose events to the
+ * window, which together cover the entire update area. An
+ * application would normally redraw the contents of @window in
+ * response to those expose events.
+ *
+ * GDK will call gdk_window_process_all_updates() on your behalf
+ * whenever your program returns to the main loop and becomes idle, so
+ * normally there's no need to do that manually, you just need to
+ * invalidate regions that you know should be redrawn.
+ *
+ * The @child_func parameter controls whether the region of
+ * each child window that intersects @region will also be invalidated.
+ * Only children for which @child_func returns TRUE will have the area
+ * invalidated.
+ **/
+void
+gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
+				     const GdkRegion *region,
+				     gboolean       (*child_func) (GdkWindow *,
+								   gpointer),
+				     gpointer   user_data)
+{
+  gdk_window_invalidate_maybe_recurse_full (window, region, CLEAR_BG_NONE,
+					    child_func, user_data);
+}
+
 static gboolean
 true_predicate (GdkWindow *window,
 		gpointer   user_data)
@@ -5623,6 +5679,18 @@ true_predicate (GdkWindow *window,
   return TRUE;
 }
 
+static void
+gdk_window_invalidate_region_full (GdkWindow       *window,
+				    const GdkRegion *region,
+				    gboolean         invalidate_children,
+				    ClearBg          clear_bg)
+{
+  gdk_window_invalidate_maybe_recurse_full (window, region, clear_bg,
+					    invalidate_children ?
+					    true_predicate : (gboolean (*) (GdkWindow *, gpointer))NULL,
+				       NULL);
+}
+
 /**
  * gdk_window_invalidate_region:
  * @window: a #GdkWindow
@@ -5713,9 +5781,9 @@ _gdk_window_invalidate_for_expose (GdkWindow       *window,
       gdk_region_destroy (move_region);
     }
 
-  gdk_window_invalidate_maybe_recurse (window, region,
-				       (gboolean (*) (GdkWindow *, gpointer))gdk_window_has_no_impl,
-				       NULL);
+  gdk_window_invalidate_maybe_recurse_full (window, region, CLEAR_BG_WINCLEARED,
+					    (gboolean (*) (GdkWindow *, gpointer))gdk_window_has_no_impl,
+					    NULL);
 }
 
 
@@ -6411,7 +6479,7 @@ gdk_window_show_internal (GdkWindow *window, gboolean raise)
       if (gdk_window_is_viewable (window))
 	{
 	  _gdk_synthesize_crossing_events_for_geometry_change (window);
-	  gdk_window_invalidate_rect (window, NULL, TRUE);
+	  gdk_window_invalidate_rect_full (window, NULL, TRUE, CLEAR_BG_ALL);
 	}
     }
 }
@@ -6475,7 +6543,7 @@ gdk_window_raise (GdkWindow *window)
       new_region = gdk_region_copy (private->clip_region);
 
       gdk_region_subtract (new_region, old_region);
-      gdk_window_invalidate_region (window, new_region, TRUE);
+      gdk_window_invalidate_region_full (window, new_region, TRUE, CLEAR_BG_ALL);
 
       gdk_region_destroy (old_region);
       gdk_region_destroy (new_region);
@@ -6566,7 +6634,7 @@ gdk_window_invalidate_in_parent (GdkWindowObject *private)
   child.height = private->height;
   gdk_rectangle_intersect (&r, &child, &r);
 
-  gdk_window_invalidate_rect (GDK_WINDOW (private->parent), &r, TRUE);
+  gdk_window_invalidate_rect_full (GDK_WINDOW (private->parent), &r, TRUE, CLEAR_BG_ALL);
 }
 
 
@@ -6998,7 +7066,7 @@ gdk_window_move_resize_toplevel (GdkWindow *window,
        * roundtrip
        */
       gdk_region_subtract (new_region, old_region);
-      gdk_window_invalidate_region (window, new_region, TRUE);
+      gdk_window_invalidate_region_full (window, new_region, TRUE, CLEAR_BG_WINCLEARED);
 
       gdk_region_destroy (old_region);
       gdk_region_destroy (new_region);
@@ -7272,7 +7340,7 @@ gdk_window_move_resize_internal (GdkWindow *window,
 	  gdk_region_intersect (old_native_child_region, new_native_child_region);
 	  gdk_region_subtract (new_region, old_native_child_region);
 	}
-      gdk_window_invalidate_region (GDK_WINDOW (private->parent), new_region, TRUE);
+      gdk_window_invalidate_region_full (GDK_WINDOW (private->parent), new_region, TRUE, CLEAR_BG_ALL);
 
       gdk_region_destroy (old_region);
       gdk_region_destroy (new_region);
@@ -7472,7 +7540,7 @@ gdk_window_scroll (GdkWindow *window,
       gdk_region_intersect (old_native_child_region, new_native_child_region);
       gdk_region_subtract (noncopy_area, old_native_child_region);
     }
-  gdk_window_invalidate_region (window, noncopy_area, TRUE);
+  gdk_window_invalidate_region_full (window, noncopy_area, TRUE, CLEAR_BG_ALL);
 
   gdk_region_destroy (noncopy_area);
 
@@ -7541,7 +7609,7 @@ gdk_window_move_region (GdkWindow       *window,
   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_window_invalidate_region_full (window, nocopy_area, FALSE, CLEAR_BG_ALL);
   gdk_region_destroy (nocopy_area);
 }
 
@@ -8074,7 +8142,7 @@ gdk_window_shape_combine_region (GdkWindow       *window,
       diff = gdk_region_copy (new_region);
       gdk_region_subtract (diff, old_region);
 
-      gdk_window_invalidate_region (window, diff, TRUE);
+      gdk_window_invalidate_region_full (window, diff, TRUE, CLEAR_BG_ALL);
 
       gdk_region_destroy (diff);
 
@@ -8087,7 +8155,7 @@ gdk_window_shape_combine_region (GdkWindow       *window,
 	  /* 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_window_invalidate_region_full (GDK_WINDOW (private->parent), diff, TRUE, CLEAR_BG_ALL);
 
 	  gdk_region_destroy (diff);
 	}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]