Merge branch 'fix-stacking' into clutter

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

View File

@ -79,8 +79,14 @@ struct _MetaCompositor
MetaWorkspace *to,
MetaMotionDirection direction);
void (*ensure_stack_order) (MetaCompositor *compositor,
MetaScreen *screen);
void (*sync_stack) (MetaCompositor *compositor,
MetaScreen *screen,
GList *stack);
void (*set_window_hidden) (MetaCompositor *compositor,
MetaScreen *screen,
MetaWindow *window,
gboolean hidden);
};
#endif

View File

@ -243,11 +243,25 @@ meta_compositor_switch_workspace (MetaCompositor *compositor,
}
void
meta_compositor_ensure_stack_order (MetaCompositor *compositor,
MetaScreen *screen)
meta_compositor_sync_stack (MetaCompositor *compositor,
MetaScreen *screen,
GList *stack)
{
#ifdef HAVE_COMPOSITE_EXTENSIONS
if (compositor && compositor->ensure_stack_order)
compositor->ensure_stack_order (compositor, screen);
if (compositor && compositor->sync_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

@ -142,6 +142,7 @@ typedef struct _MetaCompScreen
MetaScreen *screen;
ClutterActor *stage, *window_group, *overlay_group;
ClutterActor *hidden_group;
GList *windows;
GHashTable *windows_by_xid;
MetaWindow *focus_window;
@ -474,6 +475,13 @@ static MutterWindow *
find_window_in_display (MetaDisplay *display, Window xwindow)
{
GSList *index;
MetaWindow *window = meta_display_lookup_x_window (display, xwindow);
if (window)
{
if (window->compositor_private)
return window->compositor_private;
}
for (index = meta_display_get_screens (display);
index;
@ -777,22 +785,18 @@ mutter_window_get_workspace (MutterWindow *mcw)
}
gboolean
mutter_window_is_hidden (MutterWindow *mcw)
mutter_window_showing_on_its_workspace (MutterWindow *mcw)
{
MutterWindowPrivate *priv;
if (!mcw)
return FALSE;
/* If override redirect: */
if (!mcw->priv->window)
return TRUE;
priv = mcw->priv;
if (!priv->window)
return FALSE;
return meta_window_is_hidden (priv->window);
return meta_window_showing_on_its_workspace (mcw->priv->window);
}
static void repair_win (MutterWindow *cw);
static void map_win (MutterWindow *cw);
static void unmap_win (MutterWindow *cw);
@ -831,7 +835,8 @@ mutter_finish_workspace_switch (MetaCompScreen *info)
l = l->prev;
}
}
#if 0
/*
* Fix up stacking order in case the plugin messed it up.
*/
@ -871,6 +876,7 @@ mutter_finish_workspace_switch (MetaCompScreen *info)
l = l->prev;
}
#endif
/* printf ("... FINISHED DESKTOP SWITCH\n"); */
@ -1028,6 +1034,7 @@ mutter_window_detach (MutterWindow *self)
static void
destroy_win (MutterWindow *cw, gboolean no_effect)
{
MetaWindow *window;
MetaCompScreen *info;
MutterWindowPrivate *priv;
MetaScreen *screen;
@ -1037,6 +1044,14 @@ destroy_win (MutterWindow *cw, gboolean no_effect)
priv = cw->priv;
window = meta_display_lookup_x_window (priv->screen->display, priv->xwindow);
if (window)
window->compositor_private = NULL;
/* If not override redirect */
if (window)
window->compositor_private = NULL;
screen = priv->screen;
info = meta_screen_get_compositor_data (screen);
@ -1073,157 +1088,6 @@ destroy_win (MutterWindow *cw, gboolean no_effect)
}
}
static void
restack_win (MutterWindow *cw, Window above)
{
MutterWindowPrivate *priv = cw->priv;
MetaScreen *screen = priv->screen;
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
Window previous_above;
GList *sibling, *next;
gboolean hide = FALSE;
gboolean live_mode;
live_mode = meta_prefs_get_live_hidden_windows ();
if (priv->window && meta_window_is_hidden (priv->window))
hide = TRUE;
sibling = g_list_find (info->windows, (gconstpointer) cw);
next = g_list_next (sibling);
previous_above = None;
if (next)
{
MutterWindow *ncw = next->data;
previous_above = ncw->priv->xwindow;
}
/* If above is set to None, the window whose state was changed is on
* the bottom of the stack with respect to sibling.
*/
if (above == None)
{
#if 0
printf ("Raising to top %p [0x%x] (%s)\n",
cw, (guint) priv->xwindow,
priv->window ? priv->window->desc : "unknown");
#endif
/* Insert at bottom of window stack */
CHECK_LIST_INTEGRITY_START(info->windows)
info->windows = g_list_delete_link (info->windows, sibling);
info->windows = g_list_append (info->windows, cw);
CHECK_LIST_INTEGRITY_END(info->windows)
if (!info->switch_workspace_in_progress)
{
clutter_actor_raise_top (CLUTTER_ACTOR (cw));
}
}
else if (previous_above != above)
{
GList *index;
/* Find the window that matches 'above'; if the window is hidden (i.e.,
* minimized, on a different desktop) find the first window above it tha
* is not and use it instead; if we cannot find any such window then
* fallback to raise to top (without this, we end up stacking up the act
* in the wrong place, and it probably will not be visible at all).
*/
for (index = info->windows; index; index = index->next)
{
MutterWindow *cw2 = (MutterWindow *) index->data;
if (cw2->priv->xwindow == above)
{
if (live_mode && !hide && cw2->priv->window &&
meta_window_is_hidden (cw2->priv->window))
{
index = index->prev;
while (index)
{
MutterWindow *prev = index->data;
if (!prev->priv->window ||
!meta_window_is_hidden (prev->priv->window))
{
break;
}
index = index->prev;
}
}
break;
}
}
if (index != NULL)
{
if (index != sibling)
{
ClutterActor *above_win = index->data;
CHECK_LIST_INTEGRITY_START(info->windows)
info->windows = g_list_delete_link (info->windows, sibling);
info->windows = g_list_insert_before (info->windows, index, cw);
CHECK_LIST_INTEGRITY_END(info->windows)
#if 0
printf ("Raising %p [0x%x] (%s) hidden %d, above %p [0x%x] (%s)\n",
cw, (guint) priv->xwindow,
priv->window ? priv->window->desc : "unknown", hide,
cw2, (guint) cw2->priv->xwindow,
cw2->priv->window ? cw2->priv->window->desc : "unknown");
#endif
if (!info->switch_workspace_in_progress)
{
clutter_actor_raise (CLUTTER_ACTOR (cw), above_win);
}
}
}
else if (live_mode)
{
if (!hide)
{
#if 0
printf ("Raising to top as fallback %p [0x%x] (%s)\n",
cw, (guint) priv->xwindow,
priv->window ? priv->window->desc : "unknown");
#endif
/* Insert at bottom of window stack */
CHECK_LIST_INTEGRITY_START(info->windows)
info->windows = g_list_delete_link (info->windows, sibling);
info->windows = g_list_append (info->windows, cw);
CHECK_LIST_INTEGRITY_END(info->windows)
if (!info->switch_workspace_in_progress)
{
clutter_actor_raise_top (CLUTTER_ACTOR (cw));
}
}
else
{
#if 0
printf ("Lowering to bottom as fallback %p [0x%x] (%s)\n",
cw, (guint) priv->xwindow,
priv->window ? priv->window->desc : "unknown");
#endif
/* Insert at bottom of window stack */
CHECK_LIST_INTEGRITY_START(info->windows)
info->windows = g_list_delete_link (info->windows, sibling);
info->windows = g_list_prepend (info->windows, cw);
CHECK_LIST_INTEGRITY_END(info->windows)
if (!info->switch_workspace_in_progress)
{
clutter_actor_lower_bottom (CLUTTER_ACTOR (cw));
}
}
}
}
}
static void
resize_win (MutterWindow *cw,
int x,
@ -1361,6 +1225,20 @@ 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;
}
if (info == NULL)
return;
@ -1446,6 +1324,11 @@ add_win (MetaScreen *screen, MetaWindow *window, Window xwindow)
printf("\n");
#endif
/* Hang our compositor window state off the MetaWindow for fast retrieval
* if we have one */
if (window)
window->compositor_private = cw;
/*
* Add this to the list at the top of the stack before it is mapped so that
@ -1530,7 +1413,7 @@ repair_win (MutterWindow *cw)
full = TRUE;
}
/*
/*
* TODO -- on some gfx hardware updating the whole texture instead of
* the individual rectangles is actually quicker, so we might want to
* make this a configurable option (on desktop HW with multiple pipelines
@ -1601,7 +1484,7 @@ process_create (Mutter *compositor,
{
MetaScreen *screen;
Window xwindow = event->window;
MutterWindow *mw;
MutterWindow *cw;
screen = meta_display_screen_for_root (compositor->display, event->parent);
@ -1612,18 +1495,18 @@ process_create (Mutter *compositor,
* This is quite silly as we end up creating windows as then immediatly
* destroying them as they (likely) become framed and thus reparented.
*/
mw = find_window_for_screen (screen, xwindow);
cw = find_window_for_screen (screen, xwindow);
if (!mw && window)
if (!cw && window)
{
xwindow = meta_window_get_xwindow (window);
mw = find_window_for_screen (screen, xwindow);
cw = find_window_for_screen (screen, xwindow);
}
if (mw)
if (cw)
{
destroy_win (mw, TRUE);
destroy_win (cw, TRUE);
}
add_win (screen, window, event->window);
@ -1635,7 +1518,7 @@ process_reparent (Mutter *compositor,
MetaWindow *window)
{
MetaScreen *screen;
MutterWindow *mw;
MutterWindow *cw;
Window xwindow = event->window;
gboolean viewable = FALSE;
@ -1643,28 +1526,16 @@ process_reparent (Mutter *compositor,
if (!screen)
return;
if (window)
cw = window->compositor_private;
else
cw = find_window_for_screen (screen, xwindow);
mw = find_window_for_screen (screen, xwindow);
if (!mw && window)
if (cw)
{
xwindow = meta_window_get_xwindow (window);
mw = find_window_for_screen (screen, xwindow);
}
if (!mw && window)
{
xwindow = meta_window_get_xwindow (window);
mw = find_window_for_screen (screen, xwindow);
}
if (mw)
{
viewable = (mw->priv->attrs.map_state == IsViewable);
destroy_win (mw, TRUE);
viewable = (cw->priv->attrs.map_state == IsViewable);
destroy_win (cw, TRUE);
}
add_win (screen, window, event->window);
@ -1755,11 +1626,11 @@ update_shape (Mutter *compositor,
#ifdef HAVE_SHAPE
static void
process_shape (Mutter *compositor,
XShapeEvent *event)
process_shape (Mutter *compositor,
XShapeEvent *event)
{
MutterWindow *cw = find_window_in_display (compositor->display,
event->window);
event->window);
MutterWindowPrivate *priv = cw->priv;
if (cw == NULL)
@ -1793,7 +1664,6 @@ process_configure_notify (Mutter *compositor,
if (cw)
{
restack_win (cw, event->above);
resize_win (cw,
event->x, event->y, event->width, event->height,
event->border_width, event->override_redirect);
@ -1831,47 +1701,20 @@ process_configure_notify (Mutter *compositor,
}
static void
process_circulate_notify (Mutter *compositor,
XCirculateEvent *event)
process_unmap (Mutter *compositor,
XUnmapEvent *event)
{
MutterWindow *cw = find_window_in_display (compositor->display,
event->window);
MutterWindow *top;
MetaCompScreen *info;
Window above;
MutterWindowPrivate *priv;
if (!cw)
return;
priv = cw->priv;
info = meta_screen_get_compositor_data (priv->screen);
top = info->windows->data;
if ((event->place == PlaceOnTop) && top)
above = top->priv->xwindow;
else
above = None;
restack_win (cw, above);
}
static void
process_unmap (Mutter *compositor,
XUnmapEvent *event)
{
MutterWindow *cw;
Window xwin = event->window;
Display *dpy = event->display;
MutterWindow *cw;
Window xwin = event->window;
Display *dpy = event->display;
if (event->from_configure)
{
/* Ignore unmap caused by parent's resize */
return;
}
cw = find_window_in_display (compositor->display, xwin);
cw = find_window_in_display (compositor->display, event->window);
if (cw)
{
@ -1899,8 +1742,11 @@ process_map (Mutter *compositor,
{
MutterWindow *cw;
Window xwindow = event->window;
cw = find_window_in_display (compositor->display, xwindow);
if (window)
cw = window->compositor_private;
else
cw = find_window_in_display (compositor->display, xwindow);
if (cw)
{
@ -1909,8 +1755,8 @@ process_map (Mutter *compositor,
}
static void
process_property_notify (Mutter *compositor,
XPropertyEvent *event)
process_property_notify (Mutter *compositor,
XPropertyEvent *event)
{
MetaDisplay *display = compositor->display;
@ -1918,7 +1764,7 @@ process_property_notify (Mutter *compositor,
if (event->atom == compositor->atom_net_wm_window_opacity)
{
MutterWindow *cw = find_window_in_display (display, event->window);
gulong value;
gulong value;
if (!cw)
{
@ -2103,13 +1949,18 @@ 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 ();
info->hidden_group = clutter_group_new ();
clutter_container_add (CLUTTER_CONTAINER (info->stage),
info->window_group,
info->overlay_group,
info->hidden_group,
NULL);
clutter_actor_hide (info->hidden_group);
/*
* Must do this *before* creating the plugin manager, in case any of the
@ -2224,10 +2075,6 @@ clutter_cmp_process_event (MetaCompositor *compositor,
meta_error_trap_push (xrc->display);
switch (event->type)
{
case CirculateNotify:
process_circulate_notify (xrc, (XCirculateEvent *) event);
break;
case ConfigureNotify:
process_configure_notify (xrc, (XConfigureEvent *) event);
break;
@ -2460,9 +2307,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
@ -2470,14 +2319,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));
@ -2502,8 +2349,6 @@ clutter_cmp_switch_workspace (MetaCompositor *compositor,
cw->priv->needs_unmap = FALSE;
}
}
l = l->next;
}
}
@ -2529,33 +2374,58 @@ clutter_cmp_switch_workspace (MetaCompositor *compositor,
}
static void
clutter_cmp_ensure_stack_order (MetaCompositor *compositor,
MetaScreen *screen)
clutter_cmp_sync_stack (MetaCompositor *compositor,
MetaScreen *screen,
GList *stack)
{
GList *tmp;
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
GList *l = g_list_last (info->windows);
while (l)
for (tmp = stack; tmp != NULL; tmp = tmp->next)
{
ClutterActor *a = l->data;
MutterWindow *mw = l->data;
MetaWindow *window = mw->priv->window;
MetaWindow *window = tmp->data;
MutterWindow *cw = window->compositor_private;
GList *link;
/*
* If this window is not marked as hidden, we raise it.
* If it has no MetaWindow associated (i.e., override redirect), we
* raise it too. Everything else we push to the bottom.
*/
if (!window || !meta_window_is_hidden (window))
if (!cw)
{
clutter_actor_raise_top (a);
}
else
{
clutter_actor_lower_bottom (a);
meta_verbose ("Failed to find corresponding MutterWindow "
"for window %p\n", window);
continue;
}
clutter_actor_lower_bottom (CLUTTER_ACTOR (cw));
l = l->prev;
/* Also maintain the order of info->windows */
info->windows = g_list_remove (info->windows, (gconstpointer)cw);
info->windows = g_list_prepend (info->windows, cw);
}
}
static void
clutter_cmp_set_window_hidden (MetaCompositor *compositor,
MetaScreen *screen,
MetaWindow *window,
gboolean hidden)
{
MutterWindow *cw = window->compositor_private;
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
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 */
if (clutter_actor_get_parent (CLUTTER_ACTOR (cw)) != info->hidden_group)
clutter_actor_reparent (CLUTTER_ACTOR (cw),
info->hidden_group);
}
else
{
if (clutter_actor_get_parent (CLUTTER_ACTOR (cw)) != info->window_group)
clutter_actor_reparent (CLUTTER_ACTOR (cw),
info->window_group);
}
}
@ -2575,7 +2445,8 @@ static MetaCompositor comp_info = {
clutter_cmp_unmaximize_window,
clutter_cmp_update_workspace_geometry,
clutter_cmp_switch_workspace,
clutter_cmp_ensure_stack_order,
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");
@ -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);

View File

@ -65,6 +65,7 @@ MetaWindow * mutter_window_get_meta_window (MutterWindow *mcw);
ClutterActor * mutter_window_get_texture (MutterWindow *mcw);
gboolean mutter_window_is_override_redirect (MutterWindow *mcw);
const char * mutter_window_get_description (MutterWindow *mcw);
gboolean mutter_window_showing_on_its_workspace (MutterWindow *mcw);
/* Compositor API */
MetaCompositor *mutter_new (MetaDisplay *display);

View File

@ -129,9 +129,9 @@ meta_compositor_switch_workspace (MetaCompositor *compositor,
MetaMotionDirection direction);
void
meta_compositor_ensure_stack_order (MetaCompositor *compositor,
MetaScreen *screen);
meta_compositor_sync_stack (MetaCompositor *compositor,
MetaScreen *screen,
GList *stack);
#endif

View File

@ -64,5 +64,8 @@ void meta_window_activate_with_workspace (MetaWindow *window,
guint32 current_time,
MetaWorkspace *workspace);
const char * meta_window_get_description (MetaWindow *window);
/* Return whether the window would be showing if we were on its workspace */
gboolean meta_window_showing_on_its_workspace (MetaWindow *window);
#endif