window-actor/x11: Cache the frame bounds

When resizing an X11 window with client side decorations, the shadow is
clipped by the frame bounds so that we don't need to paint the shadow
under the opaque areas covered by the window and its frame.

When the X11 client uses the EMWH synchronization mechanism (like all
gtk-3 based clients), the actual window may not be updated so that the
actual window and it frame may be behind the expected window frame
bounds, which gives the impression of de-synchronized shadows.

To avoid the issue, keep a copy of the frame bounds as a cache and only
update it when the client is not frozen so that the clipping occurs on
the actual content.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/1178
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1214
This commit is contained in:
Olivier Fourdan 2020-04-24 12:19:02 +02:00
parent 793a9d45e1
commit bd45a00fa3

View File

@ -86,6 +86,8 @@ struct _MetaWindowActorX11
cairo_region_t *shape_region; cairo_region_t *shape_region;
/* The region we should clip to when painting the shadow */ /* The region we should clip to when painting the shadow */
cairo_region_t *shadow_clip; cairo_region_t *shadow_clip;
/* The frame region */
cairo_region_t *frame_bounds;
/* Extracted size-invariant shape used for shadows */ /* Extracted size-invariant shape used for shadows */
MetaWindowShape *shadow_shape; MetaWindowShape *shadow_shape;
@ -709,11 +711,8 @@ set_clip_region_beneath (MetaWindowActorX11 *actor_x11,
if (clip_shadow_under_window (actor_x11)) if (clip_shadow_under_window (actor_x11))
{ {
cairo_region_t *frame_bounds; if (actor_x11->frame_bounds)
cairo_region_subtract (actor_x11->shadow_clip, actor_x11->frame_bounds);
frame_bounds = meta_window_get_frame_bounds (window);
if (frame_bounds)
cairo_region_subtract (actor_x11->shadow_clip, frame_bounds);
} }
} }
else else
@ -1133,6 +1132,17 @@ update_opaque_region (MetaWindowActorX11 *actor_x11)
cairo_region_destroy (opaque_region); cairo_region_destroy (opaque_region);
} }
static void
update_frame_bounds (MetaWindowActorX11 *actor_x11)
{
MetaWindow *window =
meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
g_clear_pointer (&actor_x11->frame_bounds, cairo_region_destroy);
actor_x11->frame_bounds =
cairo_region_copy (meta_window_get_frame_bounds (window));
}
static void static void
update_regions (MetaWindowActorX11 *actor_x11) update_regions (MetaWindowActorX11 *actor_x11)
{ {
@ -1204,6 +1214,7 @@ handle_updates (MetaWindowActorX11 *actor_x11)
if (!meta_surface_actor_is_visible (surface)) if (!meta_surface_actor_is_visible (surface))
return; return;
update_frame_bounds (actor_x11);
check_needs_reshape (actor_x11); check_needs_reshape (actor_x11);
check_needs_shadow (actor_x11); check_needs_shadow (actor_x11);
} }
@ -1257,15 +1268,13 @@ meta_window_actor_x11_paint (ClutterActor *actor,
*/ */
if (!clip && clip_shadow_under_window (actor_x11)) if (!clip && clip_shadow_under_window (actor_x11))
{ {
cairo_region_t *frame_bounds;
cairo_rectangle_int_t bounds; cairo_rectangle_int_t bounds;
get_shadow_bounds (actor_x11, appears_focused, &bounds); get_shadow_bounds (actor_x11, appears_focused, &bounds);
clip = cairo_region_create_rectangle (&bounds); clip = cairo_region_create_rectangle (&bounds);
frame_bounds = meta_window_get_frame_bounds (window); if (actor_x11->frame_bounds)
if (frame_bounds) cairo_region_subtract (clip, actor_x11->frame_bounds);
cairo_region_subtract (clip, frame_bounds);
} }
framebuffer = clutter_paint_context_get_framebuffer (paint_context); framebuffer = clutter_paint_context_get_framebuffer (paint_context);
@ -1552,6 +1561,7 @@ meta_window_actor_x11_dispose (GObject *object)
g_clear_pointer (&actor_x11->shape_region, cairo_region_destroy); g_clear_pointer (&actor_x11->shape_region, cairo_region_destroy);
g_clear_pointer (&actor_x11->shadow_clip, cairo_region_destroy); g_clear_pointer (&actor_x11->shadow_clip, cairo_region_destroy);
g_clear_pointer (&actor_x11->frame_bounds, cairo_region_destroy);
g_clear_pointer (&actor_x11->shadow_class, g_free); g_clear_pointer (&actor_x11->shadow_class, g_free);
g_clear_pointer (&actor_x11->focused_shadow, meta_shadow_unref); g_clear_pointer (&actor_x11->focused_shadow, meta_shadow_unref);