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
This commit is contained in:
Alexander Larsson 2009-11-04 14:03:04 +01:00
parent 9ae0d9a44f
commit 9e51c10edc

View File

@ -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);
}