Fix corner cases where _NET_WM_FRAME_DRAWN might be missed
The WM spec requires _NET_WM_FRAME_DRAWN to *always* be sent when there is an appropriate update to the sync counter value. We were potentially missing _NET_WM_FRAME_DRAWN when an application did a spontaneous update during an interactive resize and during effects. Refactor the code to always send _NET_WM_FRAME_DRAWN, even when a window is frozen. https://bugzilla.gnome.org/show_bug.cgi?id=693833
This commit is contained in:
parent
aeb589c176
commit
5876f2e3e5
@ -764,6 +764,21 @@ meta_compositor_set_updates_frozen (MetaCompositor *compositor,
|
||||
meta_window_actor_set_updates_frozen (window_actor, updates_frozen);
|
||||
}
|
||||
|
||||
void
|
||||
meta_compositor_queue_frame_drawn (MetaCompositor *compositor,
|
||||
MetaWindow *window,
|
||||
gboolean no_delay_frame)
|
||||
{
|
||||
MetaWindowActor *window_actor;
|
||||
|
||||
DEBUG_TRACE ("meta_compositor_queue_frame_drawn\n");
|
||||
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||
if (!window_actor)
|
||||
return;
|
||||
|
||||
meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_grabbed_event (MetaDisplay *display,
|
||||
XEvent *event)
|
||||
|
@ -51,6 +51,8 @@ void meta_window_actor_mapped (MetaWindowActor *self);
|
||||
void meta_window_actor_unmapped (MetaWindowActor *self);
|
||||
void meta_window_actor_set_updates_frozen (MetaWindowActor *self,
|
||||
gboolean updates_frozen);
|
||||
void meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
|
||||
gboolean no_delay_frame);
|
||||
|
||||
cairo_region_t *meta_window_actor_get_obscured_region (MetaWindowActor *self);
|
||||
|
||||
|
@ -107,6 +107,7 @@ struct _MetaWindowActorPrivate
|
||||
|
||||
guint needs_damage_all : 1;
|
||||
guint received_damage : 1;
|
||||
guint repaint_scheduled : 1;
|
||||
|
||||
/* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
|
||||
* client message using the most recent frame in ->frames */
|
||||
@ -932,6 +933,7 @@ meta_window_actor_damage_all (MetaWindowActor *self)
|
||||
cogl_texture_get_height (texture));
|
||||
|
||||
priv->needs_damage_all = FALSE;
|
||||
priv->repaint_scheduled = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -961,17 +963,41 @@ meta_window_actor_thaw (MetaWindowActor *self)
|
||||
* don't know what real damage has happened. */
|
||||
if (self->priv->needs_damage_all)
|
||||
meta_window_actor_damage_all (self);
|
||||
else if (self->priv->needs_frame_drawn != 0)
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
|
||||
gboolean no_delay_frame)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
FrameData *frame = g_slice_new0 (FrameData);
|
||||
|
||||
priv->needs_frame_drawn = TRUE;
|
||||
|
||||
frame->sync_request_serial = priv->window->sync_request_serial;
|
||||
|
||||
priv->frames = g_list_prepend (priv->frames, frame);
|
||||
|
||||
if (no_delay_frame)
|
||||
{
|
||||
/* A frame was marked by the client without actually doing any damage;
|
||||
* we need to make sure that the pre_paint/post_paint functions
|
||||
* get called, enabling us to send a _NET_WM_FRAME_DRAWN. We do a
|
||||
* 1-pixel redraw to get consistent timing with non-empty frames.
|
||||
ClutterActor *stage = clutter_actor_get_stage (CLUTTER_ACTOR (self));
|
||||
clutter_stage_skip_sync_delay (CLUTTER_STAGE (stage));
|
||||
}
|
||||
|
||||
if (!priv->repaint_scheduled)
|
||||
{
|
||||
/* A frame was marked by the client without actually doing any
|
||||
* damage, or while we had the window frozen (e.g. during an
|
||||
* interactive resize.) We need to make sure that the
|
||||
* pre_paint/post_paint functions get called, enabling us to
|
||||
* send a _NET_WM_FRAME_DRAWN. We do a 1-pixel redraw to get
|
||||
* consistent timing with non-empty frames.
|
||||
*/
|
||||
if (self->priv->mapped && !self->priv->needs_pixmap)
|
||||
if (priv->mapped && !priv->needs_pixmap)
|
||||
{
|
||||
const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
|
||||
clutter_actor_queue_redraw_with_clip (self->priv->actor, &clip);
|
||||
clutter_actor_queue_redraw_with_clip (priv->actor, &clip);
|
||||
priv->repaint_scheduled = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1949,6 +1975,7 @@ meta_window_actor_process_damage (MetaWindowActor *self,
|
||||
event->area.y,
|
||||
event->area.width,
|
||||
event->area.height);
|
||||
priv->repaint_scheduled = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
@ -2350,25 +2377,6 @@ meta_window_actor_handle_updates (MetaWindowActor *self)
|
||||
check_needs_pixmap (self);
|
||||
check_needs_reshape (self);
|
||||
check_needs_shadow (self);
|
||||
|
||||
if (priv->window->needs_frame_drawn)
|
||||
{
|
||||
FrameData *frame = g_slice_new0 (FrameData);
|
||||
|
||||
priv->needs_frame_drawn = TRUE;
|
||||
|
||||
frame->sync_request_serial = priv->window->sync_request_serial;
|
||||
|
||||
priv->frames = g_list_prepend (priv->frames, frame);
|
||||
|
||||
priv->window->needs_frame_drawn = FALSE;
|
||||
|
||||
if (priv->window->no_delay_frame)
|
||||
{
|
||||
ClutterActor *stage = clutter_actor_get_stage (CLUTTER_ACTOR (self));
|
||||
clutter_stage_skip_sync_delay (CLUTTER_STAGE (stage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -2396,6 +2404,8 @@ meta_window_actor_post_paint (MetaWindowActor *self)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
|
||||
priv->repaint_scheduled = FALSE;
|
||||
|
||||
if (priv->needs_frame_drawn)
|
||||
{
|
||||
MetaScreen *screen = priv->screen;
|
||||
|
@ -356,15 +356,6 @@ struct _MetaWindow
|
||||
* also handles application frames */
|
||||
guint extended_sync_request_counter : 1;
|
||||
|
||||
/* if TRUE, we still need to send a _NET_WM_FRAME_DRAWN message for the
|
||||
* last update the sync request counter */
|
||||
guint needs_frame_drawn : 1;
|
||||
|
||||
/* if TRUE, the frame that was just drawn was drawn without any delay
|
||||
* on the client's part and thus is high-priority - if we add delay
|
||||
* we might cause the client to miss it's target frame rate */
|
||||
guint no_delay_frame : 1;
|
||||
|
||||
/* Note: can be NULL */
|
||||
GSList *struts;
|
||||
|
||||
|
@ -9510,11 +9510,13 @@ void
|
||||
meta_window_update_sync_request_counter (MetaWindow *window,
|
||||
gint64 new_counter_value)
|
||||
{
|
||||
if (window->extended_sync_request_counter &&
|
||||
new_counter_value % 2 == 0)
|
||||
gboolean needs_frame_drawn = FALSE;
|
||||
gboolean no_delay_frame = FALSE;
|
||||
|
||||
if (window->extended_sync_request_counter && new_counter_value % 2 == 0)
|
||||
{
|
||||
window->needs_frame_drawn = TRUE;
|
||||
window->no_delay_frame = new_counter_value == window->sync_request_serial + 1;
|
||||
needs_frame_drawn = TRUE;
|
||||
no_delay_frame = new_counter_value == window->sync_request_serial + 1;
|
||||
}
|
||||
|
||||
window->sync_request_serial = new_counter_value;
|
||||
@ -9547,6 +9549,10 @@ meta_window_update_sync_request_counter (MetaWindow *window,
|
||||
window->display->grab_latest_motion_y,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
if (needs_frame_drawn)
|
||||
meta_compositor_queue_frame_drawn (window->display->compositor, window,
|
||||
no_delay_frame);
|
||||
}
|
||||
#endif /* HAVE_XSYNC */
|
||||
|
||||
|
@ -156,6 +156,9 @@ void meta_compositor_sync_window_geometry (MetaCompositor *compositor,
|
||||
void meta_compositor_set_updates_frozen (MetaCompositor *compositor,
|
||||
MetaWindow *window,
|
||||
gboolean updates_frozen);
|
||||
void meta_compositor_queue_frame_drawn (MetaCompositor *compositor,
|
||||
MetaWindow *window,
|
||||
gboolean no_delay_frame);
|
||||
|
||||
void meta_compositor_sync_stack (MetaCompositor *compositor,
|
||||
MetaScreen *screen,
|
||||
|
Loading…
Reference in New Issue
Block a user