[mutter] Simplify relationship between mapping and visibility



commit 6726fcd25dbd335ec64a2415bb6aacf79903c6ae
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Sun Jun 28 17:10:40 2009 -0400

    Simplify relationship between mapping and visibility
    
    Previously, changes to the visibility of a window could be indicated
    by meta_compositor_map_window(), meta_compositor_unminimize_window(),
    meta_compositor_set_window_hidden(), etc, with the exact behavior
    depending on the 'live_hidden_windows' preference.
    
    Simplify this so that visibility is controlled by:
    
     meta_compositor_show_window()
     meta_compositor_hide_window()
    
    With an 'effect' parameter provided to indicate the appropriate
    effect (CREATE/UNMINIMIZE/MINIMIZE/DESTROY/NONE.)
    
    The map state of the window is signalled separately by:
    
     meta_compositor_map_window()
     meta_compositor_unmap_window()
    
    And is used only to control resource handling.
    
    Other changes:
    
     * The desired effect on show/hide is explicitly stored in
       MetaWindow, avoiding the need for the was_minimized flag.
       At idle, once we calculate the window state, we pass the
       effect to the compositor if it matches the new window
       state, and then clear the effect to start over for future
       map state changes.
    
     * meta_compositor_switch_workspace() is called before any windows
       are hidden or shown, allowing the compositor to avoid hiding
       or showing an effect for windows involved in the switch.
       http://bugzilla.gnome.org/show_bug.cgi?id=582341
    
     * Handling of post-effect cleanups for MutterWindow are
       simplified - instead of trying to do different things based
       on the individual needs of different effects, we just wait until
       all effects complete and sync the window state to what it
       should be.
    
     * On unmap, once we destroy the pixmap, we tell ClutterX11Pixmap
       that we've done so, so it can clean up and unbind. (The
       unbinding doesn't seem to be working properly because of
       ClutterGLXPixmap or video driver issues.)
    
    http://bugzilla.gnome.org/show_bug.cgi?id=587251

 src/compositor/compositor.c            |  159 ++----------
 src/compositor/mutter-window-private.h |   18 +-
 src/compositor/mutter-window.c         |  435 ++++++++++++--------------------
 src/core/screen.c                      |    1 +
 src/core/window-private.h              |   20 ++-
 src/core/window.c                      |  307 +++++++++++-----------
 src/core/workspace.c                   |   51 ++---
 src/include/compositor.h               |  105 +++++++--
 8 files changed, 479 insertions(+), 617 deletions(-)
---
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
index 833782b..a6130e7 100644
--- a/src/compositor/compositor.c
+++ b/src/compositor/compositor.c
@@ -90,28 +90,11 @@ static void sync_actor_stacking (GList *windows);
 static void
 mutter_finish_workspace_switch (MetaCompScreen *info)
 {
-#ifdef FIXME
-  GList *last = g_list_last (info->windows);
   GList *l;
 
-/*   printf ("FINISHING DESKTOP SWITCH\n"); */
-
-  if (!meta_prefs_get_live_hidden_windows ())
-    {
-      /* When running in the traditional mode where hidden windows get
-       * unmapped, we need to fix up the map status for each window, since
-       * we are ignoring unmap requests during the effect.
-       */
-      l = last;
-
-      while (l)
-	{
-          mutter_window_finish_workspace_switch (l->data);
-
-	  l = l->prev;
-	}
-    }
-#endif
+  /* Finish hiding and showing actors for the new workspace */
+  for (l = info->windows; l; l = l->next)
+    mutter_window_sync_visibility (l->data);
 
   /*
    * Fix up stacking order in case the plugin messed it up.
@@ -616,90 +599,31 @@ meta_compositor_process_event (MetaCompositor *compositor,
 }
 
 void
-meta_compositor_map_window (MetaCompositor *compositor,
-			    MetaWindow	   *window)
+meta_compositor_show_window (MetaCompositor *compositor,
+			     MetaWindow	    *window,
+                             MetaCompEffect  effect)
 {
   MutterWindow *cw = MUTTER_WINDOW (meta_window_get_compositor_private (window));
-  DEBUG_TRACE ("meta_compositor_map_window\n");
+  DEBUG_TRACE ("meta_compositor_show_window\n");
   if (!cw)
     return;
 
-  mutter_window_map (cw);
+  mutter_window_show (cw, effect);
 }
 
 void
-meta_compositor_unmap_window (MetaCompositor *compositor,
-			      MetaWindow     *window)
+meta_compositor_hide_window (MetaCompositor *compositor,
+                             MetaWindow     *window,
+                             MetaCompEffect  effect)
 {
   MutterWindow *cw = MUTTER_WINDOW (meta_window_get_compositor_private (window));
-  DEBUG_TRACE ("meta_compositor_unmap_window\n");
-  if (!cw)
-    return;
-
-  mutter_window_unmap (cw);
-}
-
-void
-meta_compositor_minimize_window (MetaCompositor *compositor,
-                                 MetaWindow     *window,
-				 MetaRectangle	*window_rect,
-				 MetaRectangle	*icon_rect)
-{
-  MutterWindow	 *cw = MUTTER_WINDOW (meta_window_get_compositor_private (window));
-  MetaScreen	 *screen = meta_window_get_screen (window);
-  MetaCompScreen *info = meta_screen_get_compositor_data (screen);
-
-  DEBUG_TRACE ("meta_compositor_minimize_window\n");
-
-  g_return_if_fail (info);
-
-  if (!cw)
-    return;
-
-  mutter_window_minimize (cw);
-}
-
-void
-meta_compositor_unminimize_window (MetaCompositor    *compositor,
-                                   MetaWindow        *window,
-				   MetaRectangle     *window_rect,
-				   MetaRectangle     *icon_rect)
-{
-#if 0
-  MutterWindow	 *cw = MUTTER_WINDOW (meta_window_get_compositor_private (window));
-  MetaScreen	 *screen = meta_window_get_screen (window);
-  MetaCompScreen *info = meta_screen_get_compositor_data (screen);
-
-  g_return_if_fail (info);
-
-  if (!cw)
-    return;
-
-  /*
-   * If there is a plugin manager, try to run an effect; if no effect is
-   * executed, hide the actor.
-   */
-  cw->priv->unminimize_in_progress++;
-
-  if (!info->plugin_mgr ||
-      !mutter_plugin_manager_event_simple (info->plugin_mgr,
-					   cw,
-					   MUTTER_PLUGIN_UNMINIMIZE))
-    {
-      cw->priv->is_minimized = TRUE;
-      cw->priv->minimize_in_progress--;
-    }
-#else
-  MutterWindow	 *cw = MUTTER_WINDOW (meta_window_get_compositor_private (window));
-  DEBUG_TRACE ("meta_compositor_unminimize_window\n");
+  DEBUG_TRACE ("meta_compositor_hide_window\n");
   if (!cw)
     return;
 
-  mutter_window_map (cw);
-#endif
+  mutter_window_hide (cw, effect);
 }
 
-
 void
 meta_compositor_maximize_window (MetaCompositor    *compositor,
                                  MetaWindow        *window,
@@ -766,41 +690,6 @@ meta_compositor_switch_workspace (MetaCompositor     *compositor,
   from_indx = meta_workspace_index (from);
 
   DEBUG_TRACE ("meta_compositor_switch_workspace\n");
-  if (!meta_prefs_get_live_hidden_windows ())
-    {
-      GList *l;
-
-      /*
-       * We are in the traditional mode where hidden windows get unmapped,
-       * we need to pre-calculate the map status of each window so that once
-       * the effect finishes we can put everything into proper order
-       * (we need to ignore the map notifications during the effect so that
-       * actors do not just disappear while the effect is running).
-       */
-      for (l = info->windows; l != NULL; l = l->next)
-	{
-	  MutterWindow *cw = l->data;
-	  MetaWindow   *mw = mutter_window_get_meta_window (cw);
-	  gboolean      sticky;
-	  gint          workspace = -1;
-
-	  sticky = (!mw || meta_window_is_on_all_workspaces (mw));
-
-	  if (!sticky)
-	    {
-	      MetaWorkspace *w;
-
-	      w = meta_window_get_workspace (mw);
-	      workspace = meta_workspace_index (w);
-
-	      /*
-	       * If the window is not on the target workspace, mark it for
-	       * unmap.
-	       */
-              mutter_window_queue_map_change (cw, to_indx == workspace);
-	    }
-	}
-    }
 
   info->switch_workspace_in_progress++;
 
@@ -927,19 +816,27 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
 }
 
 void
-meta_compositor_set_window_hidden (MetaCompositor *compositor,
-				   MetaScreen	  *screen,
-				   MetaWindow	  *window,
-				   gboolean	   hidden)
+meta_compositor_window_mapped (MetaCompositor *compositor,
+                               MetaWindow     *window)
 {
   MutterWindow *cw = MUTTER_WINDOW (meta_window_get_compositor_private (window));
+  DEBUG_TRACE ("meta_compositor_window_mapped\n");
+  if (!cw)
+    return;
 
-  DEBUG_TRACE ("meta_compositor_set_window_hidden\n");
-  
+  mutter_window_mapped (cw);
+}
+
+void
+meta_compositor_window_unmapped (MetaCompositor *compositor,
+                                 MetaWindow     *window)
+{
+  MutterWindow *cw = MUTTER_WINDOW (meta_window_get_compositor_private (window));
+  DEBUG_TRACE ("meta_compositor_window_unmapped\n");
   if (!cw)
     return;
 
-  mutter_window_set_hidden (cw, hidden);
+  mutter_window_unmapped (cw);
 }
 
 void
diff --git a/src/compositor/mutter-window-private.h b/src/compositor/mutter-window-private.h
index abf5be3..2cf5d98 100644
--- a/src/compositor/mutter-window-private.h
+++ b/src/compositor/mutter-window-private.h
@@ -8,10 +8,12 @@
 
 MutterWindow *mutter_window_new (MetaWindow *window);
 
-void mutter_window_map      (MutterWindow *cw);
-void mutter_window_unmap    (MutterWindow *cw);
-void mutter_window_minimize (MutterWindow *cw);
-void mutter_window_destroy  (MutterWindow *cw);
+void mutter_window_destroy   (MutterWindow *cw);
+
+void mutter_window_show (MutterWindow   *cw,
+                         MetaCompEffect  effect);
+void mutter_window_hide (MutterWindow   *cw,
+                         MetaCompEffect  effect);
 
 void mutter_window_maximize   (MutterWindow  *cw,
                                MetaRectangle *old_rect,
@@ -26,15 +28,13 @@ void     mutter_window_pre_paint               (MutterWindow       *self);
 
 gboolean mutter_window_effect_in_progress      (MutterWindow       *cw);
 void     mutter_window_sync_actor_position     (MutterWindow       *cw);
-void     mutter_window_finish_workspace_switch (MutterWindow       *cw);
+void     mutter_window_sync_visibility         (MutterWindow       *cw);
 void     mutter_window_update_window_type      (MutterWindow       *cw);
 void     mutter_window_update_shape            (MutterWindow       *cw,
                                                 gboolean            shaped);
 void     mutter_window_update_opacity          (MutterWindow       *cw);
-void     mutter_window_set_hidden              (MutterWindow       *cw,
-                                                gboolean            hidden);
-void     mutter_window_queue_map_change        (MutterWindow       *cw,
-                                                gboolean            should_be_mapped);
+void     mutter_window_mapped                  (MutterWindow       *cw);
+void     mutter_window_unmapped                (MutterWindow       *cw);
 
 void mutter_window_effect_completed (MutterWindow *actor,
                                      gulong        event);
diff --git a/src/compositor/mutter-window.c b/src/compositor/mutter-window.c
index 69605f6..3270190 100644
--- a/src/compositor/mutter-window.c
+++ b/src/compositor/mutter-window.c
@@ -49,17 +49,13 @@ struct _MutterWindowPrivate
   gint              map_in_progress;
   gint              destroy_in_progress;
 
+  guint		    visible                : 1;
+  guint		    mapped                 : 1;
   guint		    shaped                 : 1;
-  guint		    destroy_pending        : 1;
   guint		    argb32                 : 1;
   guint		    disposed               : 1;
-  guint		    is_minimized           : 1;
-  guint		    hide_after_effect      : 1;
   guint             redecorating           : 1;
 
-  /* Desktop switching flags */
-  guint		    needs_map              : 1;
-  guint		    needs_unmap            : 1;
   guint		    needs_repair           : 1;
   guint		    needs_reshape          : 1;
   guint		    size_changed           : 1;
@@ -746,7 +742,7 @@ mutter_window_mark_for_repair (MutterWindow *self)
 
   priv->needs_repair = TRUE;
 
-  if (priv->attrs.map_state == IsUnmapped)
+  if (!priv->mapped)
     return;
 
   /* This will cause the compositor paint function to be run
@@ -760,15 +756,76 @@ mutter_window_mark_for_repair (MutterWindow *self)
   clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
 }
 
+static gboolean
+start_simple_effect (MutterWindow *self,
+                     gulong        event)
+{
+  MutterWindowPrivate *priv = self->priv;
+  MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen);
+  gint *counter = NULL;
+
+  if (!info->plugin_mgr)
+    return FALSE;
+
+  switch (event)
+  {
+  case MUTTER_PLUGIN_MINIMIZE:
+    counter = &priv->minimize_in_progress;
+    break;
+  case MUTTER_PLUGIN_MAP:
+    counter = &priv->map_in_progress;
+    break;
+  case MUTTER_PLUGIN_DESTROY:
+    counter = &priv->destroy_in_progress;
+    break;
+  case MUTTER_PLUGIN_UNMAXIMIZE:
+  case MUTTER_PLUGIN_MAXIMIZE:
+  case MUTTER_PLUGIN_SWITCH_WORKSPACE:
+    g_assert_not_reached ();
+    break;
+  }
+
+  g_assert (counter);
+
+  (*counter)++;
+
+  if (!mutter_plugin_manager_event_simple (info->plugin_mgr,
+                                           self,
+                                           event))
+    {
+      (*counter)--;
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+mutter_window_after_effects (MutterWindow *self)
+{
+  MutterWindowPrivate *priv = self->priv;
+
+  if (priv->needs_destroy)
+    {
+      clutter_actor_destroy (CLUTTER_ACTOR (self));
+      return;
+    }
+
+  mutter_window_sync_visibility (self);
+  mutter_window_sync_actor_position (self);
+
+  if (!priv->window->mapped)
+    mutter_window_detach (self);
+
+  if (priv->needs_repair)
+    clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+}
+
 void
 mutter_window_effect_completed (MutterWindow *self,
 				gulong        event)
 {
   MutterWindowPrivate *priv   = self->priv;
-  MetaScreen          *screen = priv->screen;
-  MetaCompScreen      *info   = meta_screen_get_compositor_data (screen);
-  ClutterActor        *actor  = CLUTTER_ACTOR (self);
-  gboolean             effect_done = FALSE;
 
   /* NB: Keep in mind that when effects get completed it possible
    * that the corresponding MetaWindow may have be been destroyed.
@@ -778,34 +835,12 @@ mutter_window_effect_completed (MutterWindow *self,
   {
   case MUTTER_PLUGIN_MINIMIZE:
     {
-      ClutterActor *a = CLUTTER_ACTOR (self);
-
       priv->minimize_in_progress--;
       if (priv->minimize_in_progress < 0)
 	{
 	  g_warning ("Error in minimize accounting.");
 	  priv->minimize_in_progress = 0;
 	}
-
-      if (!priv->minimize_in_progress)
-	{
-	  priv->is_minimized = TRUE;
-
-	  /*
-	   * We must ensure that the minimized actor is pushed down the stack
-	   * (the XConfigureEvent has 'above' semantics, i.e., when a window
-	   * is lowered, we get a bunch of 'raise' notifications, but might
-	   * not get any notification for the window that has been lowered.
-	   */
-	  clutter_actor_lower_bottom (a);
-
-	  /* Make sure that after the effect finishes, the actor is
-	   * made visible for sake of live previews.
-	   */
-	  clutter_actor_show (a);
-
-	  effect_done = TRUE;
-	}
     }
     break;
   case MUTTER_PLUGIN_MAP:
@@ -820,17 +855,6 @@ mutter_window_effect_completed (MutterWindow *self,
 	g_warning ("Error in map accounting.");
 	priv->map_in_progress = 0;
       }
-
-    if (!priv->map_in_progress && priv->window && !priv->no_more_x_calls)
-      {
-	MetaRectangle rect;
-	meta_window_get_outer_rect (priv->window, &rect);
-	priv->is_minimized = FALSE;
-	clutter_actor_set_anchor_point (actor, 0, 0);
-	clutter_actor_set_position (actor, rect.x, rect.y);
-	clutter_actor_show_all (actor);
-	effect_done = TRUE;
-      }
     break;
   case MUTTER_PLUGIN_DESTROY:
     priv->destroy_in_progress--;
@@ -840,12 +864,6 @@ mutter_window_effect_completed (MutterWindow *self,
 	g_warning ("Error in destroy accounting.");
 	priv->destroy_in_progress = 0;
       }
-
-    if (!priv->destroy_in_progress)
-      {
-	priv->needs_destroy = TRUE;
-	effect_done = TRUE;
-      }
     break;
   case MUTTER_PLUGIN_UNMAXIMIZE:
     priv->unmaximize_in_progress--;
@@ -854,15 +872,6 @@ mutter_window_effect_completed (MutterWindow *self,
 	g_warning ("Error in unmaximize accounting.");
 	priv->unmaximize_in_progress = 0;
       }
-
-    if (!priv->unmaximize_in_progress && priv->window && !priv->no_more_x_calls)
-      {
-	MetaRectangle rect;
-	meta_window_get_outer_rect (priv->window, &rect);
-	clutter_actor_set_position (actor, rect.x, rect.y);
-        clutter_actor_set_size (actor, rect.width,rect.height);
-        effect_done = TRUE;
-      }
     break;
   case MUTTER_PLUGIN_MAXIMIZE:
     priv->maximize_in_progress--;
@@ -871,58 +880,14 @@ mutter_window_effect_completed (MutterWindow *self,
 	g_warning ("Error in maximize accounting.");
 	priv->maximize_in_progress = 0;
       }
-
-    if (!priv->maximize_in_progress && priv->window && !priv->no_more_x_calls)
-      {
-	MetaRectangle rect;
-	meta_window_get_outer_rect (priv->window, &rect);
-	clutter_actor_set_position (actor, rect.x, rect.y);
-        clutter_actor_set_size (actor, rect.width, rect.height);
-        effect_done = TRUE;
-      }
     break;
   case MUTTER_PLUGIN_SWITCH_WORKSPACE:
     g_assert_not_reached ();
     break;
-  default:
-    break;
   }
 
-  switch (event)
-  {
-  case MUTTER_PLUGIN_MINIMIZE:
-  case MUTTER_PLUGIN_MAP:
-  case MUTTER_PLUGIN_DESTROY:
-  case MUTTER_PLUGIN_UNMAXIMIZE:
-  case MUTTER_PLUGIN_MAXIMIZE:
-
-    if (effect_done &&
-	priv->hide_after_effect &&
-	mutter_window_effect_in_progress (self) == FALSE)
-      {
-	if (clutter_actor_get_parent (CLUTTER_ACTOR (self)) != info->hidden_group)
-	  {
-	    clutter_actor_reparent (CLUTTER_ACTOR (self),
-				    info->hidden_group);
-	  }
-	priv->hide_after_effect = FALSE;
-      }
-
-    if (priv->needs_destroy && mutter_window_effect_in_progress (self) == FALSE)
-      {
-        clutter_actor_destroy (CLUTTER_ACTOR (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;
-  }
+  if (!mutter_window_effect_in_progress (self))
+    mutter_window_after_effects (self);
 }
 
 /* Called to drop our reference to a window backing pixmap that we
@@ -943,6 +908,9 @@ mutter_window_detach (MutterWindow *self)
 
   XFreePixmap (xdisplay, priv->back_pixmap);
   priv->back_pixmap = None;
+  clutter_x11_texture_pixmap_set_pixmap (CLUTTER_X11_TEXTURE_PIXMAP (priv->actor),
+                                         None);
+
   mutter_window_mark_for_repair (self);
 }
 
@@ -952,7 +920,6 @@ mutter_window_destroy (MutterWindow *self)
   MetaWindow	      *window;
   MetaCompScreen      *info;
   MutterWindowPrivate *priv;
-  gboolean             effect_in_progress;
 
   priv = self->priv;
 
@@ -982,13 +949,7 @@ mutter_window_destroy (MutterWindow *self)
       return;
     }
 
-  effect_in_progress = mutter_window_effect_in_progress (self);
-
-  /*
-   * If a plugin manager is present, try to run an effect; if no effect of this
-   * type is present, destroy the actor.
-   */
-  priv->destroy_in_progress++;
+  priv->needs_destroy = TRUE;
 
   /*
    * Once the window destruction is initiated we can no longer perform any
@@ -998,20 +959,8 @@ mutter_window_destroy (MutterWindow *self)
    */
   priv->no_more_x_calls = TRUE;
 
-  if (!info->plugin_mgr ||
-      !mutter_plugin_manager_event_simple (info->plugin_mgr,
-					   self,
-					   MUTTER_PLUGIN_DESTROY))
-    {
-      priv->destroy_in_progress--;
-
-      if (effect_in_progress)
-	{
-	  priv->needs_destroy = TRUE;
-	}
-      else
-        clutter_actor_destroy (CLUTTER_ACTOR (self));
-    }
+  if (!mutter_window_effect_in_progress (self))
+    clutter_actor_destroy (CLUTTER_ACTOR (self));
 }
 
 void
@@ -1045,118 +994,88 @@ mutter_window_sync_actor_position (MutterWindow *self)
 }
 
 void
-mutter_window_map (MutterWindow *self)
+mutter_window_show (MutterWindow   *self,
+                    MetaCompEffect  effect)
 {
   MutterWindowPrivate *priv;
   MetaCompScreen      *info;
-
-  if (!self)
-    return;
+  gulong               event;
 
   priv = self->priv;
   info = meta_screen_get_compositor_data (priv->screen);
 
-  if (priv->attrs.map_state == IsViewable)
-    return;
-
-  priv->attrs.map_state = IsViewable;
+  g_return_if_fail (!priv->visible);
 
-  mutter_window_mark_for_repair (self);
+  self->priv->visible = TRUE;
 
-  /*
-   * Make sure the position is set correctly (we might have got moved while
-   * unmapped.
-   */
-  if (!info->switch_workspace_in_progress)
+  event = 0;
+  switch (effect)
     {
-      MetaRectangle rect;
-      meta_window_get_outer_rect (priv->window, &rect);
-      clutter_actor_set_anchor_point (CLUTTER_ACTOR (self), 0, 0);
-      clutter_actor_set_position (CLUTTER_ACTOR (self), rect.x, rect.y);
+    case META_COMP_EFFECT_CREATE:
+      event = MUTTER_PLUGIN_MAP;
+      break;
+    case META_COMP_EFFECT_UNMINIMIZE:
+      /* FIXME: should have MUTTER_PLUGIN_UNMINIMIZE */
+      event = MUTTER_PLUGIN_MAP;
+      break;
+    case META_COMP_EFFECT_NONE:
+      break;
+    case META_COMP_EFFECT_DESTROY:
+    case META_COMP_EFFECT_MINIMIZE:
+      g_assert_not_reached();
     }
 
-  priv->map_in_progress++;
-
-  /*
-   * If a plugin manager is present, try to run an effect; if no effect of this
-   * type is present, destroy the actor.
-   */
   if (priv->redecorating ||
-      info->switch_workspace_in_progress || !info->plugin_mgr ||
-      !mutter_plugin_manager_event_simple (info->plugin_mgr,
-				self,
-                                MUTTER_PLUGIN_MAP))
+      info->switch_workspace_in_progress ||
+      event == 0 ||
+      !start_simple_effect (self, event))
     {
       clutter_actor_show_all (CLUTTER_ACTOR (self));
-      priv->map_in_progress--;
-      priv->is_minimized = FALSE;
       priv->redecorating = FALSE;
     }
 }
 
 void
-mutter_window_unmap (MutterWindow *self)
+mutter_window_hide (MutterWindow  *self,
+                    MetaCompEffect effect)
 {
   MutterWindowPrivate *priv;
   MetaCompScreen      *info;
+  gulong               event;
 
   priv = self->priv;
   info = meta_screen_get_compositor_data (priv->screen);
 
-  /*
-   * If the needs_unmap flag is set, we carry on even if the winow is
-   * already marked as unmapped; this is necessary so windows temporarily
-   * shown during an effect (like desktop switch) are properly hidden again.
-   */
-  if (priv->attrs.map_state == IsUnmapped && !priv->needs_unmap)
-    return;
-
-  if (info->switch_workspace_in_progress)
-    {
-      /*
-       * Cannot unmap windows while switching desktops effect is in progress.
-       */
-      priv->needs_unmap = TRUE;
-      return;
-    }
+  g_return_if_fail (priv->visible);
 
-  priv->attrs.map_state = IsUnmapped;
-  priv->needs_unmap = FALSE;
-  priv->needs_map   = FALSE;
-
-  if (!priv->minimize_in_progress &&
-      (!meta_prefs_get_live_hidden_windows () ||
-       priv->type == META_COMP_WINDOW_DROPDOWN_MENU ||
-       priv->type == META_COMP_WINDOW_POPUP_MENU ||
-       priv->type == META_COMP_WINDOW_TOOLTIP ||
-       priv->type == META_COMP_WINDOW_NOTIFICATION ||
-       priv->type == META_COMP_WINDOW_COMBO ||
-       priv->type == META_COMP_WINDOW_DND ||
-       priv->type == META_COMP_WINDOW_OVERRIDE_OTHER))
-    {
-      clutter_actor_hide (CLUTTER_ACTOR (self));
-    }
-}
+  priv->visible = FALSE;
 
-void
-mutter_window_minimize (MutterWindow *self)
-{
-  MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen);
-
-  /*
-   * If there is a plugin manager, try to run an effect; if no effect is
-   * executed, hide the actor.
+  /* If a plugin is animating a workspace transition, we have to
+   * hold off on hiding the window, and do it after the workspace
+   * switch completes
    */
-  self->priv->minimize_in_progress++;
+  if (info->switch_workspace_in_progress)
+    return;
 
-  if (!info->plugin_mgr ||
-      !mutter_plugin_manager_event_simple (info->plugin_mgr,
-					   self,
-					   MUTTER_PLUGIN_MINIMIZE))
+  event = 0;
+  switch (effect)
     {
-      self->priv->is_minimized = TRUE;
-      self->priv->minimize_in_progress--;
+    case META_COMP_EFFECT_DESTROY:
+      event = MUTTER_PLUGIN_DESTROY;
+      break;
+    case META_COMP_EFFECT_MINIMIZE:
+      event = MUTTER_PLUGIN_MINIMIZE;
+      break;
+    case META_COMP_EFFECT_NONE:
+      break;
+    case META_COMP_EFFECT_UNMINIMIZE:
+    case META_COMP_EFFECT_CREATE:
+      g_assert_not_reached();
     }
+
+  if (event == 0 ||
+      !start_simple_effect (self, event))
+    clutter_actor_hide (CLUTTER_ACTOR (self));
 }
 
 void
@@ -1246,6 +1165,8 @@ mutter_window_new (MetaWindow *window)
 
   priv = self->priv;
 
+  priv->mapped = meta_window_toplevel_is_mapped (priv->window);
+
   mutter_window_sync_actor_position (self);
 
   /* Hang our compositor window state off the MetaWindow for fast retrieval */
@@ -1255,23 +1176,43 @@ mutter_window_new (MetaWindow *window)
 			       CLUTTER_ACTOR (self));
   clutter_actor_hide (CLUTTER_ACTOR (self));
 
-  /*
-   * Add this to the list at the top of the stack before it is mapped so that
-   * map_win can find it again
+  /* Initial position in the stack is arbitrary; stacking will be synced
+   * before we first paint.
    */
   info->windows = g_list_append (info->windows, self);
   g_hash_table_insert (info->windows_by_xid, (gpointer) top_window, self);
 
-  if (priv->attrs.map_state == IsViewable)
-    {
-      /* Need to reset the map_state for map_win() to work */
-      priv->attrs.map_state = IsUnmapped;
-      mutter_window_map (self);
-    }
-
   return self;
 }
 
+void
+mutter_window_mapped (MutterWindow *self)
+{
+  MutterWindowPrivate *priv = self->priv;
+
+  g_return_if_fail (!priv->mapped);
+
+  priv->mapped = TRUE;
+
+  mutter_window_mark_for_repair (self);
+}
+
+void
+mutter_window_unmapped (MutterWindow *self)
+{
+  MutterWindowPrivate *priv = self->priv;
+
+  g_return_if_fail (priv->mapped);
+
+  priv->mapped = FALSE;
+
+  if (mutter_window_effect_in_progress (self))
+    return;
+
+  mutter_window_detach (self);
+  priv->needs_repair = FALSE;
+}
+
 static void
 check_needs_repair (MutterWindow *self)
 {
@@ -1287,7 +1228,7 @@ check_needs_repair (MutterWindow *self)
   if (!priv->needs_repair)
     return;
 
-  if (priv->attrs.map_state == IsUnmapped)
+  if (!priv->mapped)
     return;
 
   if (xwindow == meta_screen_get_xroot (screen) ||
@@ -1426,18 +1367,16 @@ mutter_window_process_damage (MutterWindow       *self,
 }
 
 void
-mutter_window_finish_workspace_switch (MutterWindow *self)
+mutter_window_sync_visibility (MutterWindow *self)
 {
   MutterWindowPrivate *priv = self->priv;
 
-  if (priv->needs_map && !priv->needs_unmap)
-    {
-      mutter_window_map (self);
-    }
-
-  if (priv->needs_unmap)
+  if (CLUTTER_ACTOR_IS_VISIBLE (self) != priv->visible)
     {
-      mutter_window_unmap (self);
+      if (priv->visible)
+        clutter_actor_show (CLUTTER_ACTOR (self));
+      else
+        clutter_actor_hide (CLUTTER_ACTOR (self));
     }
 }
 
@@ -1527,49 +1466,3 @@ mutter_window_update_opacity (MutterWindow *self)
   self->priv->opacity = opacity;
   clutter_actor_set_opacity (CLUTTER_ACTOR (self), opacity);
 }
-
-void
-mutter_window_set_hidden (MutterWindow	  *self,
-                          gboolean	   hidden)
-{
-  MutterWindowPrivate *priv = self->priv;
-  MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen);
-
-  if (hidden)
-    {
-      if (mutter_window_effect_in_progress (self))
-	{
-	  priv->hide_after_effect = TRUE;
-	}
-      else
-	{
-	  if (clutter_actor_get_parent (CLUTTER_ACTOR (self)) != info->hidden_group)
-	    {
-	      clutter_actor_reparent (CLUTTER_ACTOR (self),
-				      info->hidden_group);
-	    }
-	}
-    }
-  else
-    {
-      priv->hide_after_effect = FALSE;
-      if (clutter_actor_get_parent (CLUTTER_ACTOR (self)) != info->window_group)
-	clutter_actor_reparent (CLUTTER_ACTOR (self),
-				info->window_group);
-    }
-}
-
-void
-mutter_window_queue_map_change (MutterWindow *self,
-                                gboolean      should_be_mapped)
-{
-  if (should_be_mapped)
-    {
-      self->priv->needs_map = TRUE;
-      self->priv->needs_unmap = FALSE;
-    }
-  else
-    {
-      self->priv->needs_unmap = TRUE;
-    }
-}
diff --git a/src/core/screen.c b/src/core/screen.c
index c6d6109..17b3c5c 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -961,6 +961,7 @@ meta_screen_manage_all_windows (MetaScreen *screen)
       MetaWindow *window;
 
       window = meta_window_new_with_attrs (screen->display, info->xwindow, TRUE,
+                                           META_COMP_EFFECT_NONE,
                                            &info->attrs);
     }
   meta_stack_thaw (screen->stack);
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 467b6b9..f143bc4 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -35,6 +35,7 @@
 #define META_WINDOW_PRIVATE_H
 
 #include <config.h>
+#include "compositor.h"
 #include "window.h"
 #include "screen-private.h"
 #include "util.h"
@@ -152,7 +153,6 @@ struct _MetaWindow
 
   /* Minimize is the state controlled by the minimize button */
   guint minimized : 1;
-  guint was_minimized : 1;
   guint tab_unminimized : 1;
 
   /* Whether the window is mapped; actual server-side state
@@ -165,6 +165,15 @@ struct _MetaWindow
    */
   guint hidden : 1;
 
+  /* Whether the compositor thinks the window is visible
+   */
+  guint visible_to_compositor : 1;
+
+  /* When we next show or hide the window, what effect we should
+   * tell the compositor to perform.
+   */
+  guint pending_compositor_effect : 4; /* MetaCompEffect */
+
   /* Iconic is the state in WM_STATE; happens for workspaces/shading
    * in addition to minimize
    */
@@ -389,9 +398,10 @@ struct _MetaWindowClass
 MetaWindow* meta_window_new                (MetaDisplay *display,
                                             Window       xwindow,
                                             gboolean     must_be_viewable);
-MetaWindow* meta_window_new_with_attrs     (MetaDisplay *display,
-                                            Window       xwindow,
-                                            gboolean     must_be_viewable,
+MetaWindow* meta_window_new_with_attrs     (MetaDisplay       *display,
+                                            Window             xwindow,
+                                            gboolean           must_be_viewable,
+                                            MetaCompEffect     effect,
                                             XWindowAttributes *attrs);
 void        meta_window_unmanage           (MetaWindow  *window,
                                             guint32      timestamp);
@@ -446,6 +456,8 @@ void        meta_window_resize_with_gravity (MetaWindow  *window,
 /* Return whether the window should be currently mapped */
 gboolean    meta_window_should_be_showing   (MetaWindow  *window);
 
+gboolean    meta_window_toplevel_is_mapped  (MetaWindow  *window);
+
 /* See warning in window.c about this function */
 gboolean    __window_is_terminal (MetaWindow *window);
 
diff --git a/src/core/window.c b/src/core/window.c
index 613eb2a..c0e4e8a 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -42,7 +42,6 @@
 #include "group.h"
 #include "window-props.h"
 #include "constraints.h"
-#include "compositor.h"
 
 #include <X11/Xatom.h>
 #include <string.h>
@@ -391,7 +390,9 @@ meta_window_new (MetaDisplay *display,
           return NULL;
        }
       window = meta_window_new_with_attrs (display, xwindow,
-                                       must_be_viewable, &attrs);
+                                           must_be_viewable,
+                                           META_COMP_EFFECT_CREATE,
+                                           &attrs);
    }
   else
    {
@@ -414,6 +415,7 @@ MetaWindow*
 meta_window_new_with_attrs (MetaDisplay       *display,
                             Window             xwindow,
                             gboolean           must_be_viewable,
+                            MetaCompEffect     effect,
                             XWindowAttributes *attrs)
 {
   MetaWindow *window;
@@ -665,11 +667,12 @@ meta_window_new_with_attrs (MetaDisplay       *display,
   window->shaded = FALSE;
   window->initially_iconic = FALSE;
   window->minimized = FALSE;
-  window->was_minimized = FALSE;
   window->tab_unminimized = FALSE;
   window->iconic = FALSE;
   window->mapped = attrs->map_state != IsUnmapped;
-  window->hidden = 0;
+  window->hidden = FALSE;
+  window->visible_to_compositor = FALSE;
+  window->pending_compositor_effect = effect;
   /* if already mapped, no need to worry about focus-on-first-time-showing */
   window->showing_for_first_time = !window->mapped;
   /* if already mapped we don't want to do the placement thing;
@@ -1186,7 +1189,13 @@ meta_window_unmanage (MetaWindow  *window,
   meta_verbose ("Unmanaging 0x%lx\n", window->xwindow);
 
   if (window->display->compositor)
-    meta_compositor_remove_window (window->display->compositor, window);
+    {
+      if (window->visible_to_compositor)
+        meta_compositor_hide_window (window->display->compositor, window,
+                                     META_COMP_EFFECT_DESTROY);
+
+      meta_compositor_remove_window (window->display->compositor, window);
+    }
 
   if (window->display->window_with_menu == window)
     {
@@ -1630,41 +1639,6 @@ meta_window_should_be_showing (MetaWindow  *window)
 }
 
 static void
-finish_minimize (gpointer data)
-{
-  MetaWindow *window = data;
-  /* FIXME: It really sucks to put timestamp pinging here; it'd
-   * probably make more sense in implement_showing() so that it's at
-   * least not duplicated in meta_window_show; but since
-   * finish_minimize is a callback making things just slightly icky, I
-   * haven't done that yet.
-   */
-  guint32 timestamp = meta_display_get_current_time_roundtrip (window->display);
-
-  meta_window_hide (window);
-  if (window->has_focus)
-    {
-      MetaWindow *not_this_one = NULL;
-      MetaWorkspace *my_workspace = meta_window_get_workspace (window);
-
-      /*
-       * If this window is modal, passing the not_this_one window to
-       * _focus_default_window() makes the focus to be given to this window's
-       * ancestor. This can only be the case if the window is on the currently
-       * active workspace; when it is not, we need to pass in NULL, so as to
-       * focus the default window for the active workspace (this scenario
-       * arises when we are switching workspaces).
-       */
-      if (my_workspace == window->screen->active_workspace)
-        not_this_one = window;
-
-      meta_workspace_focus_default_window (window->screen->active_workspace,
-                                           not_this_one,
-                                           timestamp);
-    }
-}
-
-static void
 implement_showing (MetaWindow *window,
                    gboolean    showing)
 {
@@ -1673,55 +1647,11 @@ implement_showing (MetaWindow *window,
                 showing, window->desc);
 
   if (!showing)
-    {
-      gboolean on_workspace;
-
-      on_workspace = meta_window_located_on_workspace (window,
-                                                       window->screen->active_workspace);
-
-      /* Really this effects code should probably
-       * be in meta_window_hide so the window->mapped
-       * test isn't duplicated here. Anyhow, we animate
-       * if we are mapped now, we are supposed to
-       * be minimized, and we are on the current workspace.
-       */
-      if (on_workspace && window->minimized && window->mapped &&
-          !window->hidden)
-        {
-          MetaRectangle icon_rect, window_rect;
-          gboolean result;
-
-          /* Check if the window has an icon geometry */
-          result = meta_window_get_icon_geometry (window, &icon_rect);
-
-          if (!result)
-            {
-              /* just animate into the corner somehow - maybe
-               * not a good idea...
-               */
-              icon_rect.x = window->screen->rect.width;
-              icon_rect.y = window->screen->rect.height;
-              icon_rect.width = 1;
-              icon_rect.height = 1;
-            }
-
-          meta_window_get_outer_rect (window, &window_rect);
-
-          meta_compositor_minimize_window (window->display->compositor,
-                                               window,
-					       &window_rect,
-					       &icon_rect);
-              finish_minimize (window);
-        }
-      else
-        {
-          finish_minimize (window);
-        }
-    }
+    meta_window_hide (window);
   else
-    {
-      meta_window_show (window);
-    }
+    meta_window_show (window);
+
+  window->pending_compositor_effect = META_COMP_EFFECT_NONE;
 }
 
 void
@@ -2324,6 +2254,7 @@ map_client_window (MetaWindow *window)
       meta_error_trap_push (window->display);
       XMapWindow (window->display->xdisplay, window->xwindow);
       meta_error_trap_pop (window->display, FALSE);
+
       return TRUE;
     }
   else
@@ -2347,13 +2278,32 @@ unmap_client_window (MetaWindow *window,
       meta_error_trap_push (window->display);
       XUnmapWindow (window->display->xdisplay, window->xwindow);
       meta_error_trap_pop (window->display, FALSE);
+
       return TRUE;
     }
   else
     return FALSE;
 }
 
-/* XXX META_EFFECT_*_MAP */
+/**
+ * meta_window_toplevel_is_mapped:
+ * @window: a #MetaWindow
+ *
+ * Determines whether the toplevel X window for the MetaWindow is
+ * mapped. (The frame window is mapped even without the client window
+ * when a window is shaded.)
+ *
+ * Return Value: %TRUE if the toplevel is mapped.
+ */
+gboolean
+meta_window_toplevel_is_mapped (MetaWindow *window)
+{
+  /* The frame is mapped but not the client window when the window
+   * is shaded.
+   */
+  return window->mapped || (window->frame && window->frame->mapped);
+}
+
 static void
 meta_window_show (MetaWindow *window)
 {
@@ -2362,18 +2312,15 @@ meta_window_show (MetaWindow *window)
   gboolean place_on_top_on_map;
   gboolean needs_stacking_adjustment;
   MetaWindow *focus_window;
-  guint32     timestamp;
-
-  /* FIXME: It really sucks to put timestamp pinging here; it'd
-   * probably make more sense in implement_showing() so that it's at
-   * least not duplicated in finish_minimize.  *shrug*
-   */
-  timestamp = meta_display_get_current_time_roundtrip (window->display);
+  gboolean toplevel_was_mapped;
+  gboolean toplevel_now_mapped;
 
   meta_topic (META_DEBUG_WINDOW_STATE,
               "Showing window %s, shaded: %d iconic: %d placed: %d\n",
               window->desc, window->shaded, window->iconic, window->placed);
 
+  toplevel_was_mapped = meta_window_toplevel_is_mapped (window);
+
   focus_window = window->display->focus_window;  /* May be NULL! */
   did_show = FALSE;
   window_state_on_map (window, &takes_focus_on_map, &place_on_top_on_map);
@@ -2402,6 +2349,10 @@ meta_window_show (MetaWindow *window)
     ) {
       if (meta_window_is_ancestor_of_transient (focus_window, window))
         {
+          guint32     timestamp;
+
+          timestamp = meta_display_get_current_time_roundtrip (window->display);
+
           /* This happens for error dialogs or alerts; these need to remain on
            * top, but it would be confusing to have its ancestor remain
            * focused.
@@ -2526,54 +2477,48 @@ meta_window_show (MetaWindow *window)
             {
               meta_stack_freeze (window->screen->stack);
               window->hidden = FALSE;
-	      /* Inform the compositor that the window isn't hidden */
-              if (window->display->compositor)
-                meta_compositor_set_window_hidden (window->display->compositor,
-                                                   window->screen,
-                                                   window,
-                                                   window->hidden);
               meta_stack_thaw (window->screen->stack);
               did_show = TRUE;
             }
         }
 
-      if (did_show)
-	{
-	  MetaRectangle icon_rect;
+      if (window->iconic)
+        {
+          window->iconic = FALSE;
+          set_wm_state (window, NormalState);
+        }
+    }
 
-	  if (window->was_minimized
-	      && meta_window_get_icon_geometry (window, &icon_rect))
-	    {
-	      MetaRectangle window_rect;
+  toplevel_now_mapped = meta_window_toplevel_is_mapped (window);
+  if (toplevel_now_mapped != toplevel_was_mapped)
+    {
+      if (window->display->compositor)
+        meta_compositor_window_mapped (window->display->compositor, window);
+    }
 
-	      meta_window_get_outer_rect (window, &window_rect);
+  if (!window->visible_to_compositor)
+    {
+      if (window->display->compositor)
+        {
+          MetaCompEffect effect = META_COMP_EFFECT_NONE;
 
-	      if (window->display->compositor)
-		meta_compositor_unminimize_window (window->display->compositor,
-						   window,
-						   &window_rect,
-						   &icon_rect);
-	    }
-	  else
+          switch (window->pending_compositor_effect)
             {
-              if (window->display->compositor)
-                meta_compositor_map_window (window->display->compositor,
-                                            window);
+            case META_COMP_EFFECT_CREATE:
+            case META_COMP_EFFECT_UNMINIMIZE:
+              effect = window->pending_compositor_effect;
+              break;
+            case META_COMP_EFFECT_NONE:
+            case META_COMP_EFFECT_DESTROY:
+            case META_COMP_EFFECT_MINIMIZE:
+              break;
             }
 
-	  window->was_minimized = FALSE;
-	}
-      else
-        {
-          if (window->display->compositor)
-	    meta_compositor_map_window (window->display->compositor, window);
+          meta_compositor_show_window (window->display->compositor,
+                                       window, effect);
         }
 
-      if (window->iconic)
-        {
-          window->iconic = FALSE;
-          set_wm_state (window, NormalState);
-        }
+      window->visible_to_compositor = TRUE;
     }
 
   /* We don't want to worry about all cases from inside
@@ -2585,6 +2530,10 @@ meta_window_show (MetaWindow *window)
       window->showing_for_first_time = FALSE;
       if (takes_focus_on_map)
         {
+          guint32     timestamp;
+
+          timestamp = meta_display_get_current_time_roundtrip (window->display);
+
           meta_window_focus (window, timestamp);
         }
       else
@@ -2610,50 +2559,64 @@ meta_window_show (MetaWindow *window)
     }
 }
 
-/* XXX META_EFFECT_*_UNMAP */
 static void
 meta_window_hide (MetaWindow *window)
 {
   gboolean did_hide;
+  gboolean toplevel_was_mapped;
+  gboolean toplevel_now_mapped;
 
   meta_topic (META_DEBUG_WINDOW_STATE,
               "Hiding window %s\n", window->desc);
 
+  toplevel_was_mapped = meta_window_toplevel_is_mapped (window);
+
+  if (window->visible_to_compositor)
+    {
+      if (window->display->compositor)
+        {
+          MetaCompEffect effect = META_COMP_EFFECT_NONE;
+
+          switch (window->pending_compositor_effect)
+            {
+            case META_COMP_EFFECT_CREATE:
+            case META_COMP_EFFECT_UNMINIMIZE:
+            case META_COMP_EFFECT_NONE:
+              break;
+            case META_COMP_EFFECT_DESTROY:
+            case META_COMP_EFFECT_MINIMIZE:
+              effect = window->pending_compositor_effect;
+              break;
+            }
+
+          meta_compositor_hide_window (window->display->compositor,
+                                       window, effect);
+        }
+
+      window->visible_to_compositor = FALSE;
+    }
+
   did_hide = FALSE;
 
   if (meta_prefs_get_live_hidden_windows ())
     {
-      if (window->hidden)
-        return;
-
       /* If this is the first time that we've calculating the showing
        * state of the window, the frame and client window might not
        * yet be mapped, so we need to map them now */
       map_frame (window);
       map_client_window (window);
 
-      meta_stack_freeze (window->screen->stack);
-      window->hidden = TRUE;
-      /* Tell the compositor this window is now hidden */
-      if (window->display->compositor)
-        meta_compositor_set_window_hidden (window->display->compositor,
-                                           window->screen,
-                                           window,
-                                           window->hidden);
-      meta_stack_thaw (window->screen->stack);
-
-      if (window->display->compositor)
-        meta_compositor_unmap_window (window->display->compositor,
-                                      window);
+      if (!window->hidden)
+        {
+          meta_stack_freeze (window->screen->stack);
+          window->hidden = TRUE;
+          meta_stack_thaw (window->screen->stack);
 
-      did_hide = TRUE;
+          did_hide = TRUE;
+        }
     }
   else
     {
-      if (window->display->compositor)
-        meta_compositor_unmap_window (window->display->compositor,
-                                      window);
-
       /* Unmapping the frame is enough to make the window disappear,
        * but we need to hide the window itself so the client knows
        * it has been hidden */
@@ -2669,6 +2632,19 @@ meta_window_hide (MetaWindow *window)
       set_wm_state (window, IconicState);
     }
 
+  toplevel_now_mapped = meta_window_toplevel_is_mapped (window);
+  if (toplevel_now_mapped != toplevel_was_mapped)
+    {
+      if (window->display->compositor)
+        {
+          /* As above, we may be *mapping* live hidden windows */
+          if (toplevel_now_mapped)
+            meta_compositor_window_mapped (window->display->compositor, window);
+          else
+            meta_compositor_window_unmapped (window->display->compositor, window);
+        }
+    }
+
   set_net_wm_state (window);
 
   if (did_hide && window->struts)
@@ -2678,6 +2654,28 @@ meta_window_hide (MetaWindow *window)
                   window->desc);
       invalidate_work_areas (window);
     }
+
+  if (window->has_focus)
+    {
+      MetaWindow *not_this_one = NULL;
+      MetaWorkspace *my_workspace = meta_window_get_workspace (window);
+      guint32 timestamp = meta_display_get_current_time_roundtrip (window->display);
+
+      /*
+       * If this window is modal, passing the not_this_one window to
+       * _focus_default_window() makes the focus to be given to this window's
+       * ancestor. This can only be the case if the window is on the currently
+       * active workspace; when it is not, we need to pass in NULL, so as to
+       * focus the default window for the active workspace (this scenario
+       * arises when we are switching workspaces).
+       */
+      if (my_workspace == window->screen->active_workspace)
+        not_this_one = window;
+
+      meta_workspace_focus_default_window (window->screen->active_workspace,
+                                           not_this_one,
+                                           timestamp);
+    }
 }
 
 static gboolean
@@ -2696,6 +2694,7 @@ meta_window_minimize (MetaWindow  *window)
   if (!window->minimized)
     {
       window->minimized = TRUE;
+      window->pending_compositor_effect = META_COMP_EFFECT_MINIMIZE;
       meta_window_queue(window, META_QUEUE_CALC_SHOWING);
 
       meta_window_foreach_transient (window,
@@ -2725,7 +2724,7 @@ meta_window_unminimize (MetaWindow  *window)
   if (window->minimized)
     {
       window->minimized = FALSE;
-      window->was_minimized = TRUE;
+      window->pending_compositor_effect = META_COMP_EFFECT_UNMINIMIZE;
       meta_window_queue(window, META_QUEUE_CALC_SHOWING);
 
       meta_window_foreach_transient (window,
diff --git a/src/core/workspace.c b/src/core/workspace.c
index b270e20..4e28601 100644
--- a/src/core/workspace.c
+++ b/src/core/workspace.c
@@ -433,19 +433,7 @@ meta_workspace_queue_calc_showing  (MetaWorkspace *workspace)
   tmp = workspace->windows;
   while (tmp != NULL)
     {
-      if (meta_prefs_get_live_hidden_windows ())
-        {
-          /*
-           * When we hide rather than unmap windows, we need the show/hide
-           * status of the window to be recalculated *before* we call the
-           * compositor switch_workspace hook.
-           */
-          meta_window_calc_showing (tmp->data);
-        }
-      else
-        {
-          meta_window_queue (tmp->data, META_QUEUE_CALC_SHOWING);
-        }
+      meta_window_queue (tmp->data, META_QUEUE_CALC_SHOWING);
 
       tmp = tmp->next;
     }
@@ -520,23 +508,8 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
       /* Removes window from other spaces */
       meta_window_change_workspace (move_window, workspace);
 
-  if (focus_this)
-    {
-      meta_window_focus (focus_this, timestamp);
-      meta_window_raise (focus_this);
-    }
-  else if (move_window)
-    {
-      meta_window_raise (move_window);
-    }
-  else
-    {
-      meta_topic (META_DEBUG_FOCUS, "Focusing default window on new workspace\n");
-      meta_workspace_focus_default_window (workspace, NULL, timestamp);
-    }
-
    /*
-    * Notify the compositor that the active workspace changed.
+    * Notify the compositor that the active workspace is changing.
     */
    screen = workspace->screen;
    display = meta_screen_get_display (screen);
@@ -582,6 +555,26 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
 
    meta_compositor_switch_workspace (comp, screen, old, workspace, direction);
 
+  /* This needs to be done after telling the compositor we are switching
+   * workspaces since focusing a window will cause it to be immediately
+   * shown and that would confuse the compositor if it didn't know we
+   * were in a workspace switch.
+   */
+  if (focus_this)
+    {
+      meta_window_focus (focus_this, timestamp);
+      meta_window_raise (focus_this);
+    }
+  else if (move_window)
+    {
+      meta_window_raise (move_window);
+    }
+  else
+    {
+      meta_topic (META_DEBUG_FOCUS, "Focusing default window on new workspace\n");
+      meta_workspace_focus_default_window (workspace, NULL, timestamp);
+    }
+
    /* Emit switched signal from screen.c */
    meta_screen_workspace_switched (screen, current_space, new_space, direction);
 }
diff --git a/src/include/compositor.h b/src/include/compositor.h
index 370fb4d..843ff55 100644
--- a/src/include/compositor.h
+++ b/src/include/compositor.h
@@ -53,6 +53,32 @@ typedef enum _MetaCompWindowType
 
 } MetaCompWindowType;
 
+/**
+ * MetaCompEffect:
+ * @META_COMP_EFFECT_CREATE: The window is newly created
+ *   (also used for a window that was previously on a different
+ *   workspace and is changed to become visible on the active
+ *   workspace.)
+ * @META_COMP_EFFECT_UNMINIMIZE: The window should be shown
+ *   as unminimizing from its icon geometry.
+ * @META_COMP_EFFECT_DESTROY: The window is being destroyed
+ * @META_COMP_EFFECT_MINIMIZE: The window should be shown
+ *   as minimizing to its icon geometry.
+ * @META_COMP_EFFECT_NONE: No effect, the window should be
+ *   shown or hidden immediately.
+ *
+ * Indicates the appropriate effect to show the user for
+ * meta_compositor_show_window() and meta_compositor_hide_window()
+ */
+typedef enum
+{
+  META_COMP_EFFECT_CREATE,
+  META_COMP_EFFECT_UNMINIMIZE,
+  META_COMP_EFFECT_DESTROY,
+  META_COMP_EFFECT_MINIMIZE,
+  META_COMP_EFFECT_NONE
+} MetaCompEffect;
+
 MetaCompositor *meta_compositor_new     (MetaDisplay    *display);
 void            meta_compositor_destroy (MetaCompositor *compositor);
 
@@ -65,23 +91,69 @@ gboolean meta_compositor_process_event (MetaCompositor *compositor,
                                         XEvent         *event,
                                         MetaWindow     *window);
 
+/* At a high-level, a window is not-visible or visible. When a
+ * window is added (with add_window()) it is not visible.
+ * show_window() indicates a transition from not-visible to
+ * visible. Some of the reasons for this:
+ *
+ *  - Window newly created
+ *  - Window is unminimized
+ *  - Window is moved to the current desktop
+ *  - Window was made sticky
+ *
+ * hide_window() indicates that the window has transitioned from
+ * visible to not-visible. Some reasons include:
+ *
+ *  - Window was destroyed
+ *  - Window is minimized
+ *  - Window is moved to a different desktop
+ *  - Window no longer sticky.
+ *
+ * Note that combinations are possible - a window might have first
+ * been minimized and then moved to a different desktop. The
+ * 'effect' parameter to show_window() and hide_window() is a hint
+ * as to the appropriate effect to show the user and should not
+ * be considered to be indicative of a state change.
+ *
+ * When the active workspace is changed, switch_workspace() is called
+ * first, then show_window() and hide_window() are called individually
+ * for each window affected, with an effect of META_COMP_EFFECT_NONE.
+ * If hiding windows will affect the switch workspace animation, the
+ * compositor needs to delay hiding the windows until the switch
+ * workspace animation completes.
+ *
+ * maximize_window() and unmaximize_window() are transitions within
+ * the visible state. The window is resized *before* the call, so
+ * it may be necessary to readjust the display based on the old_rect
+ * to start the animation.
+ *
+ * window_mapped() and window_unmapped() are notifications when the
+ * toplevel window (frame or client window) is mapped or unmapped.
+ * That is, when the result of meta_window_toplevel_is_mapped()
+ * changes. The main use of this is to drop resources when a window
+ * is unmapped. A window will always be mapped before show_window()
+ * is called and will not be unmapped until after hide_window() is
+ * called. If the live_hidden_windows preference is set, windows will
+ * never be unmapped.
+ */
+
 void meta_compositor_add_window    (MetaCompositor *compositor,
                                     MetaWindow     *window);
 void meta_compositor_remove_window (MetaCompositor *compositor,
                                     MetaWindow     *window);
 
-void meta_compositor_map_window        (MetaCompositor      *compositor,
-                                        MetaWindow          *window);
-void meta_compositor_unmap_window      (MetaCompositor      *compositor,
-                                        MetaWindow          *window);
-void meta_compositor_minimize_window   (MetaCompositor      *compositor,
+void meta_compositor_show_window       (MetaCompositor      *compositor,
                                         MetaWindow          *window,
-                                        MetaRectangle       *window_rect,
-                                        MetaRectangle       *icon_rect);
-void meta_compositor_unminimize_window (MetaCompositor      *compositor,
+                                        MetaCompEffect       effect);
+void meta_compositor_hide_window       (MetaCompositor      *compositor,
                                         MetaWindow          *window,
-                                        MetaRectangle       *window_rect,
-                                        MetaRectangle       *icon_rect);
+                                        MetaCompEffect       effect);
+void meta_compositor_switch_workspace  (MetaCompositor      *compositor,
+                                        MetaScreen          *screen,
+                                        MetaWorkspace       *from,
+                                        MetaWorkspace       *to,
+                                        MetaMotionDirection  direction);
+
 void meta_compositor_maximize_window   (MetaCompositor      *compositor,
                                         MetaWindow          *window,
                                         MetaRectangle       *old_rect,
@@ -90,16 +162,11 @@ void meta_compositor_unmaximize_window (MetaCompositor      *compositor,
                                         MetaWindow          *window,
                                         MetaRectangle       *old_rect,
                                         MetaRectangle       *new_rect);
-void meta_compositor_switch_workspace  (MetaCompositor      *compositor,
-                                        MetaScreen          *screen,
-                                        MetaWorkspace       *from,
-                                        MetaWorkspace       *to,
-                                        MetaMotionDirection  direction);
 
-void meta_compositor_set_window_hidden    (MetaCompositor *compositor,
-                                           MetaScreen	  *screen,
-                                           MetaWindow     *window,
-                                           gboolean        hidden);
+void meta_compositor_window_mapped        (MetaCompositor *compositor,
+                                           MetaWindow     *window);
+void meta_compositor_window_unmapped      (MetaCompositor *compositor,
+                                           MetaWindow     *window);
 void meta_compositor_sync_window_geometry (MetaCompositor *compositor,
                                            MetaWindow     *window);
 void meta_compositor_set_updates          (MetaCompositor *compositor,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]