mirror of
https://github.com/brl/mutter.git
synced 2025-06-13 16:59:30 +00:00
Live previews for hidden windows.
ClutterActors for hidden windows (such windows on different than active workspaces and windows that are minimized) are available, and reflect the actual state of the window. This is intended for use in task-switchers etc. This feature is disabled by default (due to increased demand on resources), and can be enabled through the metacity/general/live_hidden_windows gconf key. A trivial sample window switcher is included in the scratch plugin (activated by clicking on the slide out panel).
This commit is contained in:
@ -68,6 +68,8 @@
|
||||
#define KEY_CLUTTER_PLUGINS "/apps/metacity/general/clutter_plugins"
|
||||
#endif
|
||||
|
||||
#define KEY_LIVE_HIDDEN_WINDOWS "/apps/metacity/general/live_hidden_windows"
|
||||
|
||||
#ifdef HAVE_GCONF
|
||||
static GConfClient *default_client = NULL;
|
||||
static GList *changes = NULL;
|
||||
@ -114,6 +116,8 @@ static gboolean clutter_disabled = FALSE;
|
||||
static GSList *clutter_plugins = NULL;
|
||||
#endif
|
||||
|
||||
static gboolean live_hidden_windows = FALSE;
|
||||
|
||||
#ifdef HAVE_GCONF
|
||||
static gboolean handle_preference_update_enum (const gchar *key, GConfValue *value);
|
||||
|
||||
@ -423,6 +427,11 @@ static MetaBoolPreference preferences_bool[] =
|
||||
FALSE,
|
||||
},
|
||||
#endif
|
||||
{ "/apps/metacity/general/live_hidden_windows",
|
||||
META_PREF_LIVE_HIDDEN_WINDOWS,
|
||||
&live_hidden_windows,
|
||||
FALSE,
|
||||
},
|
||||
{ NULL, 0, NULL, FALSE },
|
||||
};
|
||||
|
||||
@ -1827,6 +1836,8 @@ meta_preference_to_string (MetaPreference pref)
|
||||
case META_PREF_CLUTTER_PLUGINS:
|
||||
return "CLUTTER_PLUGINS";
|
||||
#endif
|
||||
case META_PREF_LIVE_HIDDEN_WINDOWS:
|
||||
return "LIVE_HIDDEN_WINDOWS";
|
||||
}
|
||||
|
||||
return "(unknown)";
|
||||
@ -2962,6 +2973,34 @@ meta_prefs_set_clutter_plugins (GSList *list)
|
||||
}
|
||||
#endif
|
||||
|
||||
gboolean
|
||||
meta_prefs_get_live_hidden_windows (void)
|
||||
{
|
||||
return live_hidden_windows;
|
||||
}
|
||||
|
||||
void
|
||||
meta_prefs_set_live_hidden_windows (gboolean whether)
|
||||
{
|
||||
#ifdef HAVE_GCONF
|
||||
GError *err = NULL;
|
||||
|
||||
gconf_client_set_bool (default_client,
|
||||
KEY_LIVE_HIDDEN_WINDOWS,
|
||||
whether,
|
||||
&err);
|
||||
|
||||
if (err)
|
||||
{
|
||||
meta_warning (_("Error setting live hidden windows status status: %s\n"),
|
||||
err->message);
|
||||
g_error_free (err);
|
||||
}
|
||||
#else
|
||||
live_hidden_windows = whether;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef HAVE_GCONF
|
||||
static void
|
||||
init_button_layout(void)
|
||||
|
@ -772,6 +772,17 @@ meta_screen_manage_all_windows (MetaScreen *screen)
|
||||
}
|
||||
meta_stack_thaw (screen->stack);
|
||||
|
||||
/*
|
||||
* Because the windows have already been created/mapped/etc, if the compositor
|
||||
* maintains a separate stack based on ConfigureNotify restack messages, it
|
||||
* will not necessarily get what it needs; we explicitely notify the
|
||||
* compositor to fix up its stacking order.
|
||||
*
|
||||
* For more on this issue, see comments in meta_window_hide().
|
||||
*/
|
||||
if (screen->display->compositor)
|
||||
meta_compositor_ensure_stack_order (screen->display->compositor, screen);
|
||||
|
||||
g_list_foreach (windows, (GFunc)g_free, NULL);
|
||||
g_list_free (windows);
|
||||
|
||||
|
@ -240,7 +240,13 @@ get_standalone_layer (MetaWindow *window)
|
||||
{
|
||||
MetaStackLayer layer;
|
||||
gboolean focused_transient = FALSE;
|
||||
|
||||
|
||||
if (window->hidden)
|
||||
{
|
||||
layer = META_LAYER_DESKTOP;
|
||||
return layer;
|
||||
}
|
||||
|
||||
switch (window->type)
|
||||
{
|
||||
case META_WINDOW_DESKTOP:
|
||||
@ -329,7 +335,8 @@ compute_layer (MetaWindow *window)
|
||||
* windows getting in fullscreen layer if any terminal is
|
||||
* fullscreen.
|
||||
*/
|
||||
if (WINDOW_HAS_TRANSIENT_TYPE(window) &&
|
||||
if (window->layer != META_LAYER_DESKTOP &&
|
||||
WINDOW_HAS_TRANSIENT_TYPE(window) &&
|
||||
(window->xtransient_for == None ||
|
||||
window->transient_parent_is_root_window))
|
||||
{
|
||||
@ -854,7 +861,6 @@ stack_do_relayer (MetaStack *stack)
|
||||
meta_topic (META_DEBUG_STACK,
|
||||
"Window %s moved from layer %u to %u\n",
|
||||
w->desc, old_layer, w->layer);
|
||||
|
||||
stack->need_resort = TRUE;
|
||||
stack->need_constrain = TRUE;
|
||||
/* don't need to constrain as constraining
|
||||
|
@ -150,6 +150,11 @@ struct _MetaWindow
|
||||
*/
|
||||
guint mapped : 1;
|
||||
|
||||
/* Whether window has been hidden from view by lowering it to the bottom
|
||||
* of window stack.
|
||||
*/
|
||||
guint hidden : 1;
|
||||
|
||||
/* Iconic is the state in WM_STATE; happens for workspaces/shading
|
||||
* in addition to minimize
|
||||
*/
|
||||
@ -393,11 +398,6 @@ void meta_window_change_workspace (MetaWindow *window,
|
||||
void meta_window_stick (MetaWindow *window);
|
||||
void meta_window_unstick (MetaWindow *window);
|
||||
|
||||
void meta_window_activate (MetaWindow *window,
|
||||
guint32 current_time);
|
||||
void meta_window_activate_with_workspace (MetaWindow *window,
|
||||
guint32 current_time,
|
||||
MetaWorkspace *workspace);
|
||||
void meta_window_make_fullscreen_internal (MetaWindow *window);
|
||||
void meta_window_make_fullscreen (MetaWindow *window);
|
||||
void meta_window_unmake_fullscreen (MetaWindow *window);
|
||||
|
@ -472,6 +472,7 @@ meta_window_new_with_attrs (MetaDisplay *display,
|
||||
window->tab_unminimized = FALSE;
|
||||
window->iconic = FALSE;
|
||||
window->mapped = attrs->map_state != IsUnmapped;
|
||||
window->hidden = 0;
|
||||
/* 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 */
|
||||
@ -2243,8 +2244,22 @@ meta_window_show (MetaWindow *window)
|
||||
XMapWindow (window->display->xdisplay, window->xwindow);
|
||||
meta_error_trap_pop (window->display, FALSE);
|
||||
did_show = TRUE;
|
||||
|
||||
if (window->was_minimized)
|
||||
window->hidden = FALSE;
|
||||
}
|
||||
else if (meta_prefs_get_live_hidden_windows ())
|
||||
{
|
||||
if (window->hidden && window->type != META_WINDOW_DESKTOP)
|
||||
{
|
||||
window->hidden = FALSE;
|
||||
meta_stack_freeze (window->screen->stack);
|
||||
meta_window_update_layer (window);
|
||||
meta_window_raise (window);
|
||||
meta_stack_thaw (window->screen->stack);
|
||||
did_show = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (did_show && window->was_minimized)
|
||||
{
|
||||
MetaRectangle window_rect;
|
||||
MetaRectangle icon_rect;
|
||||
@ -2261,7 +2276,6 @@ meta_window_show (MetaWindow *window)
|
||||
NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (window->iconic)
|
||||
{
|
||||
@ -2309,33 +2323,83 @@ static void
|
||||
meta_window_hide (MetaWindow *window)
|
||||
{
|
||||
gboolean did_hide;
|
||||
|
||||
|
||||
meta_topic (META_DEBUG_WINDOW_STATE,
|
||||
"Hiding window %s\n", window->desc);
|
||||
|
||||
did_hide = FALSE;
|
||||
|
||||
if (window->frame && window->frame->mapped)
|
||||
{
|
||||
meta_topic (META_DEBUG_WINDOW_STATE, "Frame actually needs unmap\n");
|
||||
window->frame->mapped = FALSE;
|
||||
meta_ui_unmap_frame (window->screen->ui, window->frame->xwindow);
|
||||
did_hide = TRUE;
|
||||
}
|
||||
|
||||
if (window->mapped)
|
||||
if (meta_prefs_get_live_hidden_windows ())
|
||||
{
|
||||
meta_topic (META_DEBUG_WINDOW_STATE,
|
||||
"%s actually needs unmap\n", window->desc);
|
||||
meta_topic (META_DEBUG_WINDOW_STATE,
|
||||
"Incrementing unmaps_pending on %s for hide\n",
|
||||
window->desc);
|
||||
window->mapped = FALSE;
|
||||
window->unmaps_pending += 1;
|
||||
meta_error_trap_push (window->display);
|
||||
XUnmapWindow (window->display->xdisplay, window->xwindow);
|
||||
meta_error_trap_pop (window->display, FALSE);
|
||||
gboolean was_mapped;
|
||||
|
||||
if (window->hidden)
|
||||
return;
|
||||
|
||||
was_mapped = window->mapped;
|
||||
|
||||
if (!was_mapped)
|
||||
meta_window_show (window);
|
||||
|
||||
window->hidden = TRUE;
|
||||
did_hide = TRUE;
|
||||
|
||||
meta_stack_freeze (window->screen->stack);
|
||||
meta_window_update_layer (window);
|
||||
meta_window_lower (window);
|
||||
meta_stack_thaw (window->screen->stack);
|
||||
|
||||
/*
|
||||
* The X server does not implement lower-below semantics for restacking
|
||||
* windows, only raise-above; consequently each single lower-bottom call
|
||||
* gets translated to a bunch of raise-above moves, and often there will
|
||||
* be no ConfigureNotify at all for the window we are lowering (only for
|
||||
* its siblings). If we mix the lower-bottom sequence of calls with
|
||||
* mapping of windows, the batch of ConfigureNotify events that is
|
||||
* generated does not correctly reflect the stack order, and if the
|
||||
* Compositor relies on these for its own internal stack, it will
|
||||
* invariably end up with wrong stacking order.
|
||||
*
|
||||
* I have not been able to find a way to get this just work so that the
|
||||
* resulting ConfigureNotify messages would reflect the actual state of
|
||||
* the stack, so in the special case we map a window while hiding it, we
|
||||
* explitely notify the compositor that it should ensure its stacking
|
||||
* matches the cannonical stack of the WM.
|
||||
*
|
||||
* NB: this is uncommon, and generally only happens on the WM start up,
|
||||
* when we are taking over pre-existing windows, so this brute-force
|
||||
* fix is OK performance wise.
|
||||
*/
|
||||
if (!was_mapped && window->display->compositor)
|
||||
{
|
||||
meta_compositor_ensure_stack_order (window->display->compositor,
|
||||
window->screen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (window->frame && window->frame->mapped)
|
||||
{
|
||||
meta_topic (META_DEBUG_WINDOW_STATE, "Frame actually needs unmap\n");
|
||||
window->frame->mapped = FALSE;
|
||||
meta_ui_unmap_frame (window->screen->ui, window->frame->xwindow);
|
||||
did_hide = TRUE;
|
||||
}
|
||||
|
||||
if (window->mapped)
|
||||
{
|
||||
meta_topic (META_DEBUG_WINDOW_STATE,
|
||||
"%s actually needs unmap\n", window->desc);
|
||||
meta_topic (META_DEBUG_WINDOW_STATE,
|
||||
"Incrementing unmaps_pending on %s for hide\n",
|
||||
window->desc);
|
||||
window->mapped = FALSE;
|
||||
window->unmaps_pending += 1;
|
||||
meta_error_trap_push (window->display);
|
||||
XUnmapWindow (window->display->xdisplay, window->xwindow);
|
||||
meta_error_trap_pop (window->display, FALSE);
|
||||
did_hide = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!window->iconic)
|
||||
@ -7974,7 +8038,7 @@ meta_window_update_layer (MetaWindow *window)
|
||||
|
||||
meta_stack_freeze (window->screen->stack);
|
||||
group = meta_window_get_group (window);
|
||||
if (group)
|
||||
if (!window->hidden && group)
|
||||
meta_group_update_layers (group);
|
||||
else
|
||||
meta_stack_update_layer (window->screen->stack, window);
|
||||
@ -8223,3 +8287,9 @@ meta_window_is_on_all_workspaces (MetaWindow *window)
|
||||
return window->on_all_workspaces;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_window_is_hidden (MetaWindow *window)
|
||||
{
|
||||
return window->hidden;
|
||||
}
|
||||
|
||||
|
@ -65,11 +65,6 @@ void meta_workspace_remove_window (MetaWorkspace *workspace,
|
||||
MetaWindow *window);
|
||||
void meta_workspace_relocate_windows (MetaWorkspace *workspace,
|
||||
MetaWorkspace *new_home);
|
||||
void meta_workspace_activate_with_focus (MetaWorkspace *workspace,
|
||||
MetaWindow *focus_this,
|
||||
guint32 timestamp);
|
||||
void meta_workspace_activate (MetaWorkspace *workspace,
|
||||
guint32 timestamp);
|
||||
GList* meta_workspace_list_windows (MetaWorkspace *workspace);
|
||||
|
||||
void meta_workspace_invalidate_work_area (MetaWorkspace *workspace);
|
||||
|
@ -306,7 +306,19 @@ meta_workspace_queue_calc_showing (MetaWorkspace *workspace)
|
||||
tmp = workspace->windows;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
meta_window_queue (tmp->data, META_QUEUE_CALC_SHOWING);
|
||||
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);
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
Reference in New Issue
Block a user