Re-works the approach to supporting live preview to handle stacking.

We can't easily use a metacity layer to hide windows as that means we
loose our original stacking position. (Metacity's stack positions are
only valid within a single layer) We now have a "guard window" per
screen that is a fullscreen override redirect that is lowered to the
bottom of the stack. Hidden windows now remain in their original layer
so the stacking position remains valid, but all hidden windows get
XRestacked under the guard window.

A new compositor hook is also added to inform it when a window becomes
hidden/unhidded, this lets us map/unmap the corresponding actor.

missing files in preview commit (TODO: rebase -i and squash this later)
This commit is contained in:
Robert Bragg 2008-11-03 14:50:22 +00:00
parent cfa45beee1
commit 0058271aaa
9 changed files with 217 additions and 65 deletions

View File

@ -80,7 +80,13 @@ struct _MetaCompositor
MetaMotionDirection direction);
void (*sync_stack) (MetaCompositor *compositor,
MetaScreen *screen,
GList *stack);
void (*set_window_hidden) (MetaCompositor *compositor,
MetaScreen *screen,
MetaWindow *window,
gboolean hidden);
};
#endif

View File

@ -244,11 +244,24 @@ meta_compositor_switch_workspace (MetaCompositor *compositor,
void
meta_compositor_sync_stack (MetaCompositor *compositor,
MetaScreen *screen,
GList *stack)
{
#ifdef HAVE_COMPOSITE_EXTENSIONS
if (compositor && compositor->sync_stack)
compositor->sync_stack (compositor, stack);
compositor->sync_stack (compositor, screen, stack);
#endif
}
void
meta_compositor_set_window_hidden (MetaCompositor *compositor,
MetaScreen *screen,
MetaWindow *window,
gboolean hidden)
{
#ifdef HAVE_COMPOSITE_EXTENSIONS
if (compositor && compositor->set_window_hidden)
compositor->set_window_hidden (compositor, screen, window, hidden);
#endif
}

View File

@ -783,7 +783,7 @@ mutter_window_get_workspace (MutterWindow *mcw)
return meta_workspace_index (workspace);
}
gboolean
mutter_window_showing_on_its_workspace (MutterWindow *mcw)
{
if (!mcw)
@ -796,7 +796,7 @@ mutter_window_showing_on_its_workspace (MutterWindow *mcw)
return meta_window_showing_on_its_workspace (mcw->priv->window);
}
tatic void repair_win (MutterWindow *cw);
static void repair_win (MutterWindow *cw);
static void map_win (MutterWindow *cw);
static void unmap_win (MutterWindow *cw);
@ -834,7 +834,8 @@ mutter_finish_workspace_switch (MetaCompScreen *info)
l = l->prev;
}
}
#if 0
/*
* Fix up stacking order in case the plugin messed it up.
*/
@ -874,6 +875,7 @@ mutter_finish_workspace_switch (MetaCompScreen *info)
l = l->prev;
}
#endif
/* printf ("... FINISHED DESKTOP SWITCH\n"); */
@ -1222,7 +1224,22 @@ add_win (MetaScreen *screen, MetaWindow *window, Window xwindow)
Display *xdisplay = meta_display_get_xdisplay (display);
XWindowAttributes attrs;
gulong events_needed;
/* Note: this blacklist internal windows is copied from screen.c
* Ideally add_win shouldn't be driven by CreateNotify events and
* should instead be an event directly from metacity core. */
if (xwindow == screen->no_focus_window ||
xwindow == screen->flash_window ||
#ifdef HAVE_COMPOSITE_EXTENSIONS
xwindow == screen->wm_cm_selection_window ||
xwindow == screen->guard_window ||
#endif
xwindow == screen->wm_sn_selection_window) {
meta_verbose ("Not managing our own windows\n");
return;
}
g_printerr ("window =%p\n", window);
if (info == NULL)
return;
@ -1932,6 +1949,8 @@ clutter_cmp_manage_screen (MetaCompositor *compositor,
KeyPressMask | KeyReleaseMask);
info->window_group = clutter_group_new ();
g_object_set_property (G_OBJECT (info->window_group),
"show-on-set-parent", FALSE);
info->overlay_group = clutter_group_new ();
clutter_container_add (CLUTTER_CONTAINER (info->stage),
@ -2285,9 +2304,11 @@ clutter_cmp_switch_workspace (MetaCompositor *compositor,
info = meta_screen_get_compositor_data (screen);
to_indx = meta_workspace_index (to);
from_indx = meta_workspace_index (from);
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
@ -2295,14 +2316,12 @@ clutter_cmp_switch_workspace (MetaCompositor *compositor,
* (we need to ignore the map notifications during the effect so that
* actors do not just disappear while the effect is running).
*/
GList *l = info->windows;
while (l)
for (l = info->windows; l != NULL; l = l->next)
{
MutterWindow *cw = l->data;
MetaWindow *mw = cw->priv->window;
gboolean sticky;
gint workspace = -1;
MetaWindow *mw = cw->priv->window;
gboolean sticky;
gint workspace = -1;
sticky = (!mw || meta_window_is_on_all_workspaces (mw));
@ -2327,8 +2346,6 @@ clutter_cmp_switch_workspace (MetaCompositor *compositor,
cw->priv->needs_unmap = FALSE;
}
}
l = l->next;
}
}
@ -2355,14 +2372,23 @@ clutter_cmp_switch_workspace (MetaCompositor *compositor,
static void
clutter_cmp_sync_stack (MetaCompositor *compositor,
MetaScreen *screen,
GList *stack)
{
GList *tmp;
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
g_printerr ("----------------------------------------\n");
for (tmp = stack; tmp != NULL; tmp = tmp->next)
{
MetaWindow *window = tmp->data;
MutterWindow *cw = window->compositor_private;
GList *link;
/* FIXME -debug */
g_printerr ("sync DEBUG window = %p stack_position=%d\n",
window, window->stack_position);
if (!cw)
{
meta_verbose ("Failed to find corresponding MutterWindow "
@ -2371,15 +2397,55 @@ clutter_cmp_sync_stack (MetaCompositor *compositor,
}
#if 0
/* FIXME: There should be a seperate composite manager hook
* for hiding/unhiding the actor when the window becomes
* hidden or not */
if (meta_window_is_hidden (window))
/* This is a failsafe, it shouldn't be needed if everything is
* well behaved, but if some plugin accidentally shows a
* hidden window, this may help. */
if (window->hidden)
clutter_actor_hide (CLUTTER_ACTOR (cw));
#endif
clutter_actor_lower_bottom (CLUTTER_ACTOR (cw));
/* Also maintain the order of info->windows */
info->windows = g_list_remove (info->windows, (gconstpointer)cw);
info->windows = g_list_prepend (info->windows, cw);
}
#if 0
/* FIXME debug */
{
g_printerr ("----------------------------------------\n");
MetaWindow *window = stack->data;
MutterWindow *cw = window->compositor_private;
ClutterActor *parent = clutter_actor_get_parent (cw);
for (tmp = clutter_container_get_children (parent);
tmp != NULL;
tmp = tmp->next)
{
g_printerr ("sync DEBUG: %p\n", tmp->data);
}
}
#endif
}
static void
clutter_cmp_set_window_hidden (MetaCompositor *compositor,
MetaScreen *screen,
MetaWindow *window,
gboolean hidden)
{
MutterWindow *cw = window->compositor_private;
g_return_if_fail (cw);
if (hidden)
{
/* FIXME: There needs to be a way to queue this if there is an effect
* in progress for this window */
clutter_actor_hide (CLUTTER_ACTOR (cw));
}
else
clutter_actor_show (CLUTTER_ACTOR (cw));
}
static MetaCompositor comp_info = {
@ -2398,7 +2464,8 @@ static MetaCompositor comp_info = {
clutter_cmp_unmaximize_window,
clutter_cmp_update_workspace_geometry,
clutter_cmp_switch_workspace,
clutter_cmp_sync_stack
clutter_cmp_sync_stack,
clutter_cmp_set_window_hidden
};
MetaCompositor *

View File

@ -132,6 +132,11 @@ struct _MetaScreen
/* Managed by compositor.c */
gpointer compositor_data;
/* Instead of unmapping withdrawn windows we can leave them mapped
* and restack them below a guard window. When using a compositor
* this allows us to provide live previews of unmapped windows */
Window guard_window;
};
MetaScreen* meta_screen_new (MetaDisplay *display,

View File

@ -311,6 +311,38 @@ reload_xinerama_infos (MetaScreen *screen)
g_assert (screen->xinerama_infos != NULL);
}
/* The guard window allows us to leave minimized windows mapped so
* that compositor code may provide live previews of them.
* Instead of being unmapped/withdrawn, they get pushed underneath
* the guard window. */
static Window
create_guard_window (Display *xdisplay, MetaScreen *screen)
{
XSetWindowAttributes attributes;
Window guard_window;
attributes.event_mask = NoEventMask;
attributes.override_redirect = True;
attributes.background_pixel = BlackPixel (xdisplay, screen->number);
guard_window =
XCreateWindow (xdisplay,
screen->xroot,
0, /* x */
0, /* y */
screen->rect.width,
screen->rect.height,
0, /* border width */
CopyFromParent, /* depth */
CopyFromParent, /* class */
CopyFromParent, /* visual */
CWEventMask|CWOverrideRedirect|CWBackPixel,
&attributes);
XLowerWindow (xdisplay, guard_window);
XMapWindow (xdisplay, guard_window);
return guard_window;
}
MetaScreen*
meta_screen_new (MetaDisplay *display,
int number,
@ -490,6 +522,8 @@ meta_screen_new (MetaDisplay *display,
screen->vertical_workspaces = FALSE;
screen->starting_corner = META_SCREEN_TOPLEFT;
screen->compositor_data = NULL;
screen->guard_window = create_guard_window (xdisplay, screen);
{
XFontStruct *font_info;
@ -760,6 +794,7 @@ meta_screen_manage_all_windows (MetaScreen *screen)
info->xwindow == screen->flash_window ||
#ifdef HAVE_COMPOSITE_EXTENSIONS
info->xwindow == screen->wm_cm_selection_window ||
info->xwindow == screen->guard_window ||
#endif
info->xwindow == screen->wm_sn_selection_window) {
meta_verbose ("Not managing our own windows\n");

View File

@ -35,6 +35,10 @@
#include "prefs.h"
#include "workspace.h"
#ifdef HAVE_COMPOSITE_EXTENSIONS
#include "compositor.h"
#endif
#include <X11/Xatom.h>
#define WINDOW_HAS_TRANSIENT_TYPE(w) \
@ -1057,6 +1061,7 @@ stack_sync_to_server (MetaStack *stack)
GArray *stacked;
GArray *root_children_stacked;
GList *tmp;
GArray *all_hidden;
/* Bail out if frozen */
if (stack->freeze_count > 0)
@ -1067,6 +1072,7 @@ stack_sync_to_server (MetaStack *stack)
stack_ensure_sorted (stack);
meta_compositor_sync_stack (stack->screen->display->compositor,
stack->screen,
stack->sorted);
/* Create stacked xwindow arrays.
@ -1076,29 +1082,42 @@ stack_sync_to_server (MetaStack *stack)
*/
stacked = g_array_new (FALSE, FALSE, sizeof (Window));
root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
all_hidden = g_array_new (FALSE, FALSE, sizeof (Window));
/* The screen guard window sits above all hidden windows and acts as
* a barrier to input reaching these windows. */
g_array_append_val (all_hidden, stack->screen->guard_window);
meta_topic (META_DEBUG_STACK, "Top to bottom: ");
meta_push_no_msg_prefix ();
tmp = stack->sorted;
while (tmp != NULL)
for (tmp = stack->sorted; tmp != NULL; tmp = tmp->next)
{
MetaWindow *w;
w = tmp->data;
MetaWindow *w = tmp->data;
Window top_level_window;
meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
w->layer, w->stack_position, w->desc);
/* remember, stacked is in reverse order (bottom to top) */
g_array_prepend_val (stacked, w->xwindow);
/* build XRestackWindows() array from top to bottom */
if (w->frame)
g_array_append_val (root_children_stacked, w->frame->xwindow);
top_level_window = w->frame->xwindow;
else
g_array_append_val (root_children_stacked, w->xwindow);
meta_topic (META_DEBUG_STACK, "%u:%d - %s ", w->layer, w->stack_position, w->desc);
tmp = tmp->next;
top_level_window = w->xwindow;
/* We don't restack hidden windows along with the rest, though they are
* reflected in the _NET hints. Hidden windows all get pushed below
* the screens fullscreen guard_window. */
if (w->hidden)
{
g_array_append_val (all_hidden, top_level_window);
continue;
}
/* build XRestackWindows() array from top to bottom */
g_array_append_val (root_children_stacked, top_level_window);
}
meta_topic (META_DEBUG_STACK, "\n");
@ -1216,6 +1235,13 @@ stack_sync_to_server (MetaStack *stack)
}
}
/* Push hidden windows to the bottom of the stack under the guard window */
XLowerWindow (stack->screen->display->xdisplay, stack->screen->guard_window);
XRestackWindows (stack->screen->display->xdisplay,
(Window *)all_hidden->data,
all_hidden->len);
g_array_free (all_hidden, TRUE);
meta_error_trap_pop (stack->screen->display, FALSE);
/* on error, a window was destroyed; it should eventually
* get removed from the stacking list when we unmanage it

View File

@ -428,9 +428,6 @@ void meta_window_resize_with_gravity (MetaWindow *window,
int gravity);
/* Return whether the window would be showing if we were on its workspace */
gboolean meta_window_showing_on_its_workspace (MetaWindow *window);
/* Return whether the window should be currently mapped */
gboolean meta_window_should_be_showing (MetaWindow *window);

View File

@ -2250,34 +2250,37 @@ meta_window_show (MetaWindow *window)
}
else if (meta_prefs_get_live_hidden_windows ())
{
if (window->hidden && window->type != META_WINDOW_DESKTOP)
if (window->hidden)
{
window->hidden = FALSE;
meta_stack_freeze (window->screen->stack);
meta_window_update_layer (window);
meta_window_raise (window);
window->hidden = FALSE;
meta_stack_thaw (window->screen->stack);
/* Inform the compositor that the window isn't hidden */
meta_compositor_set_window_hidden (window->display->compositor,
window->screen,
window,
window->hidden);
did_show = TRUE;
}
}
if (did_show && window->was_minimized)
{
MetaRectangle window_rect;
MetaRectangle icon_rect;
window->was_minimized = FALSE;
if (meta_window_get_icon_geometry (window, &icon_rect))
{
meta_window_get_outer_rect (window, &window_rect);
meta_effect_run_unminimize (window,
&window_rect,
&icon_rect,
NULL, NULL);
}
}
{
MetaRectangle window_rect;
MetaRectangle icon_rect;
window->was_minimized = FALSE;
if (meta_window_get_icon_geometry (window, &icon_rect))
{
meta_window_get_outer_rect (window, &window_rect);
meta_effect_run_unminimize (window,
&window_rect,
&icon_rect,
NULL, NULL);
}
}
if (window->iconic)
{
@ -2333,23 +2336,22 @@ meta_window_hide (MetaWindow *window)
if (meta_prefs_get_live_hidden_windows ())
{
gboolean was_mapped;
if (window->hidden)
return;
was_mapped = window->mapped;
if (!was_mapped)
if (!window->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);
window->hidden = TRUE;
meta_stack_thaw (window->screen->stack);
/* Tell the compositor this window is now hidden */
meta_compositor_set_window_hidden (window->display->compositor,
window->screen,
window,
window->hidden);
did_hide = TRUE;
}
else
{
@ -8013,7 +8015,7 @@ meta_window_update_layer (MetaWindow *window)
meta_stack_freeze (window->screen->stack);
group = meta_window_get_group (window);
if (!window->hidden && group)
if (group)
meta_group_update_layers (group);
else
meta_stack_update_layer (window->screen->stack, window);

View File

@ -130,6 +130,7 @@ meta_compositor_switch_workspace (MetaCompositor *compositor,
void
meta_compositor_sync_stack (MetaCompositor *compositor,
MetaScreen *screen,
GList *stack);
#endif