diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 833782b4b..a6130e7b8 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"); + DEBUG_TRACE ("meta_compositor_hide_window\n"); if (!cw) return; - mutter_window_unmap (cw); + mutter_window_hide (cw, effect); } -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"); - if (!cw) - return; - - mutter_window_map (cw); -#endif -} - - 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_set_window_hidden\n"); - + DEBUG_TRACE ("meta_compositor_window_mapped\n"); if (!cw) return; - mutter_window_set_hidden (cw, hidden); + 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_unmapped (cw); } void diff --git a/src/compositor/mutter-window-private.h b/src/compositor/mutter-window-private.h index abf5be352..2cf5d9883 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 69605f609..327019084 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; + g_return_if_fail (!priv->visible); - priv->attrs.map_state = IsViewable; + self->priv->visible = TRUE; - mutter_window_mark_for_repair (self); - - /* - * 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. + g_return_if_fail (priv->visible); + + priv->visible = FALSE; + + /* 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 */ - if (priv->attrs.map_state == IsUnmapped && !priv->needs_unmap) + if (info->switch_workspace_in_progress) return; - if (info->switch_workspace_in_progress) + event = 0; + switch (effect) { - /* - * Cannot unmap windows while switching desktops effect is in progress. - */ - priv->needs_unmap = TRUE; - return; + 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(); } - 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)); - } -} - -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. - */ - self->priv->minimize_in_progress++; - - if (!info->plugin_mgr || - !mutter_plugin_manager_event_simple (info->plugin_mgr, - self, - MUTTER_PLUGIN_MINIMIZE)) - { - self->priv->is_minimized = TRUE; - self->priv->minimize_in_progress--; - } + 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) + if (CLUTTER_ACTOR_IS_VISIBLE (self) != priv->visible) { - mutter_window_map (self); - } - - if (priv->needs_unmap) - { - 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 c6d6109c8..17b3c5c33 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 467b6b98c..f143bc490 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -35,6 +35,7 @@ #define META_WINDOW_PRIVATE_H #include +#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 613eb2a0a..c0e4e8adb 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 #include @@ -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) { @@ -1629,41 +1638,6 @@ meta_window_should_be_showing (MetaWindow *window) return on_workspace && meta_window_showing_on_its_workspace (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,49 +2477,11 @@ 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->was_minimized - && meta_window_get_icon_geometry (window, &icon_rect)) - { - MetaRectangle window_rect; - - meta_window_get_outer_rect (window, &window_rect); - - if (window->display->compositor) - meta_compositor_unminimize_window (window->display->compositor, - window, - &window_rect, - &icon_rect); - } - else - { - if (window->display->compositor) - meta_compositor_map_window (window->display->compositor, - window); - } - - window->was_minimized = FALSE; - } - else - { - if (window->display->compositor) - meta_compositor_map_window (window->display->compositor, window); - } - if (window->iconic) { window->iconic = FALSE; @@ -2576,6 +2489,38 @@ meta_window_show (MetaWindow *window) } } + 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); + } + + 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: + effect = window->pending_compositor_effect; + break; + case META_COMP_EFFECT_NONE: + case META_COMP_EFFECT_DESTROY: + case META_COMP_EFFECT_MINIMIZE: + break; + } + + meta_compositor_show_window (window->display->compositor, + window, effect); + } + + window->visible_to_compositor = TRUE; + } + /* We don't want to worry about all cases from inside * implement_showing(); we only want to worry about focus if this * window has not been shown before. @@ -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->hidden) + { + meta_stack_freeze (window->screen->stack); + window->hidden = TRUE; + meta_stack_thaw (window->screen->stack); - if (window->display->compositor) - meta_compositor_unmap_window (window->display->compositor, - window); - - 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 b270e200f..4e28601e8 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 370fb4d7c..843ff5504 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,