Merge branch 'fix-stacking' into clutter

This commit is contained in:
Robert Bragg
2008-11-04 15:26:17 +00:00
11 changed files with 309 additions and 366 deletions

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");
@@ -772,17 +807,6 @@ 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);

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)
@@ -1065,6 +1070,10 @@ stack_sync_to_server (MetaStack *stack)
meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n");
stack_ensure_sorted (stack);
meta_compositor_sync_stack (stack->screen->display->compositor,
stack->screen,
stack->sorted);
/* Create stacked xwindow arrays.
* Painfully, "stacked" is in bottom-to-top order for the
@@ -1073,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");
@@ -1213,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

@@ -348,6 +348,10 @@ struct _MetaWindow
/* maintained by group.c */
MetaGroup *group;
#ifdef HAVE_COMPOSITE_EXTENSIONS
void *compositor_private;
#endif
};
/* These differ from window->has_foo_func in that they consider
@@ -424,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

@@ -476,7 +476,7 @@ meta_window_new_with_attrs (MetaDisplay *display,
/* 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 */
window->placed = window->mapped;
window->placed = (window->mapped && !window->hidden);
if (window->placed)
meta_topic (META_DEBUG_PLACEMENT,
"Not placing window 0x%lx since it's already mapped\n",
@@ -558,6 +558,8 @@ meta_window_new_with_attrs (MetaDisplay *display,
window->stack_position = -1;
window->initial_workspace = 0; /* not used */
window->initial_timestamp = 0; /* not used */
window->compositor_private = NULL;
meta_display_register_x_window (display, &window->xwindow, window);
@@ -1459,7 +1461,7 @@ implement_showing (MetaWindow *window,
* be minimized, and we are on the current workspace.
*/
if (on_workspace && window->minimized && window->mapped &&
!meta_prefs_get_reduced_resources ())
!window->hidden && !meta_prefs_get_reduced_resources ())
{
MetaRectangle icon_rect, window_rect;
gboolean result;
@@ -2244,38 +2246,41 @@ meta_window_show (MetaWindow *window)
XMapWindow (window->display->xdisplay, window->xwindow);
meta_error_trap_pop (window->display, FALSE);
did_show = TRUE;
window->hidden = FALSE;
}
else if (meta_prefs_get_live_hidden_windows ())
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;
/* Inform the compositor that the window isn't hidden */
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 && 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)
{
@@ -2331,50 +2336,34 @@ 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)
meta_window_show (window);
window->hidden = TRUE;
did_hide = TRUE;
if (!window->mapped)
{
Window top_level_window;
meta_topic (META_DEBUG_WINDOW_STATE,
"%s actually needs map\n", window->desc);
window->mapped = TRUE;
meta_error_trap_push (window->display);
if (window->frame)
top_level_window = window->frame->xwindow;
else
top_level_window = window->xwindow;
XMapWindow (window->display->xdisplay, top_level_window);
meta_error_trap_pop (window->display, FALSE);
}
meta_stack_freeze (window->screen->stack);
meta_window_update_layer (window);
meta_window_lower (window);
window->hidden = TRUE;
/* Tell the compositor this window is now hidden */
meta_compositor_set_window_hidden (window->display->compositor,
window->screen,
window,
window->hidden);
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);
}
did_hide = TRUE;
}
else
{
@@ -4149,7 +4138,7 @@ meta_window_focus (MetaWindow *window,
meta_window_flush_calc_showing (window);
if (!window->mapped && !window->shaded)
if ((!window->mapped || window->hidden) && !window->shaded)
{
meta_topic (META_DEBUG_FOCUS,
"Window %s is not showing, not focusing after all\n",
@@ -8038,7 +8027,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);