mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 17:40:40 -05:00
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);
|
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
|
static gboolean
|
||||||
is_grabbed_event (MetaDisplay *display,
|
is_grabbed_event (MetaDisplay *display,
|
||||||
XEvent *event)
|
XEvent *event)
|
||||||
|
@ -51,6 +51,8 @@ void meta_window_actor_mapped (MetaWindowActor *self);
|
|||||||
void meta_window_actor_unmapped (MetaWindowActor *self);
|
void meta_window_actor_unmapped (MetaWindowActor *self);
|
||||||
void meta_window_actor_set_updates_frozen (MetaWindowActor *self,
|
void meta_window_actor_set_updates_frozen (MetaWindowActor *self,
|
||||||
gboolean updates_frozen);
|
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);
|
cairo_region_t *meta_window_actor_get_obscured_region (MetaWindowActor *self);
|
||||||
|
|
||||||
|
@ -107,6 +107,7 @@ struct _MetaWindowActorPrivate
|
|||||||
|
|
||||||
guint needs_damage_all : 1;
|
guint needs_damage_all : 1;
|
||||||
guint received_damage : 1;
|
guint received_damage : 1;
|
||||||
|
guint repaint_scheduled : 1;
|
||||||
|
|
||||||
/* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
|
/* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
|
||||||
* client message using the most recent frame in ->frames */
|
* 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));
|
cogl_texture_get_height (texture));
|
||||||
|
|
||||||
priv->needs_damage_all = FALSE;
|
priv->needs_damage_all = FALSE;
|
||||||
|
priv->repaint_scheduled = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -961,17 +963,41 @@ meta_window_actor_thaw (MetaWindowActor *self)
|
|||||||
* don't know what real damage has happened. */
|
* don't know what real damage has happened. */
|
||||||
if (self->priv->needs_damage_all)
|
if (self->priv->needs_damage_all)
|
||||||
meta_window_actor_damage_all (self);
|
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;
|
ClutterActor *stage = clutter_actor_get_stage (CLUTTER_ACTOR (self));
|
||||||
* we need to make sure that the pre_paint/post_paint functions
|
clutter_stage_skip_sync_delay (CLUTTER_STAGE (stage));
|
||||||
* 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 (!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 };
|
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.y,
|
||||||
event->area.width,
|
event->area.width,
|
||||||
event->area.height);
|
event->area.height);
|
||||||
|
priv->repaint_scheduled = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2350,25 +2377,6 @@ meta_window_actor_handle_updates (MetaWindowActor *self)
|
|||||||
check_needs_pixmap (self);
|
check_needs_pixmap (self);
|
||||||
check_needs_reshape (self);
|
check_needs_reshape (self);
|
||||||
check_needs_shadow (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
|
void
|
||||||
@ -2396,6 +2404,8 @@ meta_window_actor_post_paint (MetaWindowActor *self)
|
|||||||
{
|
{
|
||||||
MetaWindowActorPrivate *priv = self->priv;
|
MetaWindowActorPrivate *priv = self->priv;
|
||||||
|
|
||||||
|
priv->repaint_scheduled = FALSE;
|
||||||
|
|
||||||
if (priv->needs_frame_drawn)
|
if (priv->needs_frame_drawn)
|
||||||
{
|
{
|
||||||
MetaScreen *screen = priv->screen;
|
MetaScreen *screen = priv->screen;
|
||||||
|
@ -356,15 +356,6 @@ struct _MetaWindow
|
|||||||
* also handles application frames */
|
* also handles application frames */
|
||||||
guint extended_sync_request_counter : 1;
|
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 */
|
/* Note: can be NULL */
|
||||||
GSList *struts;
|
GSList *struts;
|
||||||
|
|
||||||
|
@ -9510,11 +9510,13 @@ void
|
|||||||
meta_window_update_sync_request_counter (MetaWindow *window,
|
meta_window_update_sync_request_counter (MetaWindow *window,
|
||||||
gint64 new_counter_value)
|
gint64 new_counter_value)
|
||||||
{
|
{
|
||||||
if (window->extended_sync_request_counter &&
|
gboolean needs_frame_drawn = FALSE;
|
||||||
new_counter_value % 2 == 0)
|
gboolean no_delay_frame = FALSE;
|
||||||
|
|
||||||
|
if (window->extended_sync_request_counter && new_counter_value % 2 == 0)
|
||||||
{
|
{
|
||||||
window->needs_frame_drawn = TRUE;
|
needs_frame_drawn = TRUE;
|
||||||
window->no_delay_frame = new_counter_value == window->sync_request_serial + 1;
|
no_delay_frame = new_counter_value == window->sync_request_serial + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
window->sync_request_serial = new_counter_value;
|
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,
|
window->display->grab_latest_motion_y,
|
||||||
TRUE);
|
TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needs_frame_drawn)
|
||||||
|
meta_compositor_queue_frame_drawn (window->display->compositor, window,
|
||||||
|
no_delay_frame);
|
||||||
}
|
}
|
||||||
#endif /* HAVE_XSYNC */
|
#endif /* HAVE_XSYNC */
|
||||||
|
|
||||||
|
@ -156,6 +156,9 @@ void meta_compositor_sync_window_geometry (MetaCompositor *compositor,
|
|||||||
void meta_compositor_set_updates_frozen (MetaCompositor *compositor,
|
void meta_compositor_set_updates_frozen (MetaCompositor *compositor,
|
||||||
MetaWindow *window,
|
MetaWindow *window,
|
||||||
gboolean updates_frozen);
|
gboolean updates_frozen);
|
||||||
|
void meta_compositor_queue_frame_drawn (MetaCompositor *compositor,
|
||||||
|
MetaWindow *window,
|
||||||
|
gboolean no_delay_frame);
|
||||||
|
|
||||||
void meta_compositor_sync_stack (MetaCompositor *compositor,
|
void meta_compositor_sync_stack (MetaCompositor *compositor,
|
||||||
MetaScreen *screen,
|
MetaScreen *screen,
|
||||||
|
Loading…
Reference in New Issue
Block a user