Move window repair and reshape to a paint function

Add a paint function that checks all windows for repair and
shape updates; this:

 - simplifies the logic for when a window needs to be repaired
 - avoids duplicate work when we get multiple damage effects
 - avoids the need to look ahead in the event queue

Instead of relying on repair to implicitly resize the
MutterWindow actor, set the size explicitly when the core
code updates the geometry. (This is needed because we haven't
repaired yet when we start an animation, and the animation
may depend on the size to, e.g., rescale from the center.)

Because the core geometry update happens before we start
maximize/unmaximize effects we need to work around this by
passing both the old and new geometry to the compositor.

http://bugzilla.gnome.org/show_bug.cgi?id=587251
This commit is contained in:
Owen W. Taylor 2009-06-28 12:26:23 -04:00
parent bc9a2cc92a
commit 9244f0f113
6 changed files with 178 additions and 70 deletions

View File

@ -19,6 +19,7 @@ struct _MetaCompositor
Atom atom_x_root_pixmap;
Atom atom_x_set_root;
Atom atom_net_wm_window_opacity;
guint repaint_func_id;
ClutterActor *shadow_src;

View File

@ -142,6 +142,7 @@ mutter_switch_workspace_completed (MetaScreen *screen)
void
meta_compositor_destroy (MetaCompositor *compositor)
{
clutter_threads_remove_repaint_func (compositor->repaint_func_id);
}
static void
@ -704,27 +705,29 @@ meta_compositor_unminimize_window (MetaCompositor *compositor,
void
meta_compositor_maximize_window (MetaCompositor *compositor,
MetaWindow *window,
MetaRectangle *window_rect)
MetaRectangle *old_rect,
MetaRectangle *new_rect)
{
MutterWindow *cw = MUTTER_WINDOW (meta_window_get_compositor_private (window));
DEBUG_TRACE ("meta_compositor_maximize_window\n");
if (!cw)
return;
mutter_window_maximize (cw, window_rect);
mutter_window_maximize (cw, old_rect, new_rect);
}
void
meta_compositor_unmaximize_window (MetaCompositor *compositor,
MetaWindow *window,
MetaRectangle *window_rect)
MetaRectangle *old_rect,
MetaRectangle *new_rect)
{
MutterWindow *cw = MUTTER_WINDOW (meta_window_get_compositor_private (window));
DEBUG_TRACE ("meta_compositor_unmaximize_window\n");
if (!cw)
return;
mutter_window_unmaximize (cw, window_rect);
mutter_window_unmaximize (cw, old_rect, new_rect);
}
void
@ -976,6 +979,35 @@ meta_compositor_sync_screen_size (MetaCompositor *compositor,
width, height);
}
static void
pre_paint_windows (MetaCompScreen *info)
{
GList *l;
for (l = info->windows; l; l = l->next)
mutter_window_pre_paint (l->data);
}
static gboolean
mutter_repaint_func (gpointer data)
{
MetaCompositor *compositor = data;
GSList *screens = meta_display_get_screens (compositor->display);
GSList *l;
for (l = screens; l; l = l->next)
{
MetaScreen *screen = l->data;
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
if (!info)
continue;
pre_paint_windows (info);
}
return TRUE;
}
MetaCompositor *
meta_compositor_new (MetaDisplay *display)
{
@ -1006,6 +1038,10 @@ meta_compositor_new (MetaDisplay *display)
compositor->atom_x_set_root = atoms[1];
compositor->atom_net_wm_window_opacity = atoms[2];
compositor->repaint_func_id = clutter_threads_add_repaint_func (mutter_repaint_func,
compositor,
NULL);
return compositor;
}

View File

@ -14,12 +14,16 @@ void mutter_window_minimize (MutterWindow *cw);
void mutter_window_destroy (MutterWindow *cw);
void mutter_window_maximize (MutterWindow *cw,
MetaRectangle *window_rect);
MetaRectangle *old_rect,
MetaRectangle *new_rect);
void mutter_window_unmaximize (MutterWindow *cw,
MetaRectangle *window_rect);
MetaRectangle *old_rect,
MetaRectangle *new_rect);
void mutter_window_process_damage (MutterWindow *cw,
XDamageNotifyEvent *event);
void mutter_window_pre_paint (MutterWindow *self);
gboolean mutter_window_effect_in_progress (MutterWindow *cw,
gboolean include_destroy);
void mutter_window_sync_actor_position (MutterWindow *cw);

View File

@ -61,6 +61,8 @@ struct _MutterWindowPrivate
guint needs_map : 1;
guint needs_unmap : 1;
guint needs_repair : 1;
guint needs_reshape : 1;
guint size_changed : 1;
guint needs_destroy : 1;
@ -94,7 +96,6 @@ static void mutter_window_detach (MutterWindow *self);
static gboolean mutter_window_has_shadow (MutterWindow *self);
static void repair_win (MutterWindow *self);
static gboolean is_shaped (MetaDisplay *display,
Window xwindow);
/*
@ -739,6 +740,27 @@ mutter_window_effect_in_progress (MutterWindow *self,
(include_destroy && self->priv->destroy_in_progress));
}
static void
mutter_window_mark_for_repair (MutterWindow *self)
{
MutterWindowPrivate *priv = self->priv;
priv->needs_repair = TRUE;
if (priv->attrs.map_state == IsUnmapped)
return;
/* This will cause the compositor paint function to be run
* if the actor is visible or a clone of the actor is visible.
* if the actor isn't visible in any way, then we don't
* need to repair the window anyways, and can wait until
* the stage is redrawn for some other reason
*
* The compositor paint function repairs all windows.
*/
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
void
mutter_window_effect_completed (MutterWindow *self,
gulong event)
@ -839,8 +861,7 @@ mutter_window_effect_completed (MutterWindow *self,
MetaRectangle rect;
meta_window_get_outer_rect (priv->window, &rect);
clutter_actor_set_position (actor, rect.x, rect.y);
mutter_window_detach (self);
repair_win (self);
clutter_actor_set_size (actor, rect.width,rect.height);
effect_done = TRUE;
}
break;
@ -857,8 +878,7 @@ mutter_window_effect_completed (MutterWindow *self,
MetaRectangle rect;
meta_window_get_outer_rect (priv->window, &rect);
clutter_actor_set_position (actor, rect.x, rect.y);
mutter_window_detach (self);
repair_win (self);
clutter_actor_set_size (actor, rect.width, rect.height);
effect_done = TRUE;
}
break;
@ -895,11 +915,22 @@ mutter_window_effect_completed (MutterWindow *self,
return;
}
if (effect_done &&
(priv->needs_repair || priv->needs_reshape))
{
/* Make sure that pre_paint function gets called */
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
default:
break;
}
}
/* Called to drop our reference to a window backing pixmap that we
* previously obtained with XCompositeNameWindowPixmap. We do this
* when the window is unmapped or when we want to update to a new
* pixmap for a new size.
*/
static void
mutter_window_detach (MutterWindow *self)
{
@ -913,6 +944,7 @@ mutter_window_detach (MutterWindow *self)
XFreePixmap (xdisplay, priv->back_pixmap);
priv->back_pixmap = None;
mutter_window_mark_for_repair (self);
}
void
@ -990,7 +1022,10 @@ mutter_window_sync_actor_position (MutterWindow *self)
if (priv->attrs.width != window_rect.width ||
priv->attrs.height != window_rect.height)
mutter_window_detach (self);
{
priv->size_changed = TRUE;
mutter_window_mark_for_repair (self);
}
/* XXX deprecated: please use meta_window_get_outer_rect instead */
priv->attrs.width = window_rect.width;
@ -1002,7 +1037,9 @@ mutter_window_sync_actor_position (MutterWindow *self)
return;
clutter_actor_set_position (CLUTTER_ACTOR (self),
window_rect.x, window_rect.y);
window_rect.x, window_rect.y);
clutter_actor_set_size (CLUTTER_ACTOR (self),
window_rect.width, window_rect.height);
}
void
@ -1022,13 +1059,7 @@ mutter_window_map (MutterWindow *self)
priv->attrs.map_state = IsViewable;
/*
* Now repair the window; this ensures that the actor is correctly sized
* before we run any effects on it.
*/
priv->needs_map = FALSE;
mutter_window_detach (self);
repair_win (self);
mutter_window_mark_for_repair (self);
/*
* Make sure the position is set correctly (we might have got moved while
@ -1131,18 +1162,25 @@ mutter_window_minimize (MutterWindow *self)
void
mutter_window_maximize (MutterWindow *self,
MetaRectangle *window_rect)
MetaRectangle *old_rect,
MetaRectangle *new_rect)
{
MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen);
/* The window has already been resized (in order to compute new_rect),
* which by side effect caused the actor to be resized. Restore it to the
* old size and position */
clutter_actor_set_position (CLUTTER_ACTOR (self), old_rect->x, old_rect->y);
clutter_actor_set_size (CLUTTER_ACTOR (self), old_rect->width, old_rect->height);
self->priv->maximize_in_progress++;
if (!info->plugin_mgr ||
!mutter_plugin_manager_event_maximize (info->plugin_mgr,
self,
MUTTER_PLUGIN_MAXIMIZE,
window_rect->x, window_rect->y,
window_rect->width, window_rect->height))
new_rect->x, new_rect->y,
new_rect->width, new_rect->height))
{
self->priv->maximize_in_progress--;
@ -1151,18 +1189,25 @@ mutter_window_maximize (MutterWindow *self,
void
mutter_window_unmaximize (MutterWindow *self,
MetaRectangle *window_rect)
MetaRectangle *old_rect,
MetaRectangle *new_rect)
{
MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen);
/* The window has already been resized (in order to compute new_rect),
* which by side effect caused the actor to be resized. Restore it to the
* old size and position */
clutter_actor_set_position (CLUTTER_ACTOR (self), old_rect->x, old_rect->y);
clutter_actor_set_size (CLUTTER_ACTOR (self), old_rect->width, old_rect->height);
self->priv->unmaximize_in_progress++;
if (!info->plugin_mgr ||
!mutter_plugin_manager_event_maximize (info->plugin_mgr,
self,
MUTTER_PLUGIN_UNMAXIMIZE,
window_rect->x, window_rect->y,
window_rect->width, window_rect->height))
new_rect->x, new_rect->y,
new_rect->width, new_rect->height))
{
self->priv->unmaximize_in_progress--;
}
@ -1202,8 +1247,7 @@ mutter_window_new (MetaWindow *window)
priv = self->priv;
clutter_actor_set_position (CLUTTER_ACTOR (self),
priv->attrs.x, priv->attrs.y);
mutter_window_sync_actor_position (self);
/* Hang our compositor window state off the MetaWindow for fast retrieval */
meta_window_set_compositor_private (window, G_OBJECT (self));
@ -1230,7 +1274,7 @@ mutter_window_new (MetaWindow *window)
}
static void
repair_win (MutterWindow *self)
check_needs_repair (MutterWindow *self)
{
MutterWindowPrivate *priv = self->priv;
MetaScreen *screen = priv->screen;
@ -1241,12 +1285,24 @@ repair_win (MutterWindow *self)
Window xwindow = priv->xwindow;
gboolean full = FALSE;
if (!priv->needs_repair)
return;
if (priv->attrs.map_state == IsUnmapped)
return;
if (xwindow == meta_screen_get_xroot (screen) ||
xwindow == clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)))
return;
compositor = meta_display_get_compositor (display);
if (priv->size_changed)
{
mutter_window_detach (self);
priv->size_changed = FALSE;
}
meta_error_trap_push (display);
if (priv->back_pixmap == None)
@ -1367,33 +1423,7 @@ void
mutter_window_process_damage (MutterWindow *self,
XDamageNotifyEvent *event)
{
MutterWindowPrivate *priv = self->priv;
Display *dpy = event->display;
Drawable drawable = event->drawable;
XEvent next;
if (priv->destroy_pending ||
priv->maximize_in_progress ||
priv->unmaximize_in_progress)
{
priv->needs_repair = TRUE;
return;
}
/*
* Check if the event queue does not already contain DetstroyNotify for this
* window -- if it does, we need to stop updating the pixmap (to avoid damage
* notifications that come from the window teardown), and process the destroy
* immediately.
*/
if (XCheckTypedWindowEvent (dpy, drawable, DestroyNotify, &next))
{
priv->destroy_pending = TRUE;
mutter_window_destroy (self);
return;
}
repair_win (self);
mutter_window_mark_for_repair (self);
}
void
@ -1412,13 +1442,13 @@ mutter_window_finish_workspace_switch (MutterWindow *self)
}
}
void
mutter_window_update_shape (MutterWindow *self,
gboolean shaped)
static void
check_needs_reshape (MutterWindow *self)
{
MutterWindowPrivate *priv = self->priv;
priv->shaped = shaped;
if (!priv->needs_reshape)
return;
mutter_shaped_texture_clear_rectangles (MUTTER_SHAPED_TEXTURE (priv->actor));
@ -1444,6 +1474,36 @@ mutter_window_update_shape (MutterWindow *self,
}
}
#endif
priv->needs_reshape = FALSE;
}
void
mutter_window_update_shape (MutterWindow *self,
gboolean shaped)
{
MutterWindowPrivate *priv = self->priv;
priv->shaped = shaped;
priv->needs_reshape = TRUE;
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
void
mutter_window_pre_paint (MutterWindow *self)
{
MutterWindowPrivate *priv = self->priv;
/* The window is frozen due to a pending animation: we'll wait until
* the animation finishes to reshape and repair the window */
if (priv->destroy_in_progress ||
priv->maximize_in_progress ||
priv->unmaximize_in_progress)
return;
check_needs_reshape (self);
check_needs_repair (self);
}
void

View File

@ -2919,14 +2919,18 @@ meta_window_maximize (MetaWindow *window,
if (window->display->compositor)
{
MetaRectangle window_rect;
MetaRectangle old_rect;
MetaRectangle new_rect;
meta_window_get_outer_rect (window, &old_rect);
meta_window_move_resize_now (window);
meta_window_get_outer_rect (window, &window_rect);
meta_window_get_outer_rect (window, &new_rect);
meta_compositor_maximize_window (window->display->compositor,
window,
&window_rect);
&old_rect,
&new_rect);
}
else
{
@ -3035,7 +3039,9 @@ meta_window_unmaximize (MetaWindow *window,
if (window->display->compositor)
{
MetaRectangle window_rect;
MetaRectangle old_rect, new_rect;
meta_window_get_outer_rect (window, &old_rect);
meta_window_move_resize (window,
FALSE,
@ -3043,13 +3049,12 @@ meta_window_unmaximize (MetaWindow *window,
target_rect.y,
target_rect.width,
target_rect.height);
meta_window_move_resize_now (window);
meta_window_get_outer_rect (window, &window_rect);
meta_window_get_outer_rect (window, &new_rect);
meta_compositor_unmaximize_window (window->display->compositor,
window,
&window_rect);
&old_rect,
&new_rect);
}
else
{

View File

@ -84,10 +84,12 @@ void meta_compositor_unminimize_window (MetaCompositor *compositor,
MetaRectangle *icon_rect);
void meta_compositor_maximize_window (MetaCompositor *compositor,
MetaWindow *window,
MetaRectangle *window_rect);
MetaRectangle *old_rect,
MetaRectangle *new_rect);
void meta_compositor_unmaximize_window (MetaCompositor *compositor,
MetaWindow *window,
MetaRectangle *window_rect);
MetaRectangle *old_rect,
MetaRectangle *new_rect);
void meta_compositor_switch_workspace (MetaCompositor *compositor,
MetaScreen *screen,
MetaWorkspace *from,