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:
parent
cfa45beee1
commit
0058271aaa
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 *
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -130,6 +130,7 @@ meta_compositor_switch_workspace (MetaCompositor *compositor,
|
||||
|
||||
void
|
||||
meta_compositor_sync_stack (MetaCompositor *compositor,
|
||||
MetaScreen *screen,
|
||||
GList *stack);
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user