--- ./src/screen.h +++ ./src/screen.h @@ -201,6 +201,7 @@ struct _ScreenInfo #endif /* HAVE_RANDR */ #endif /* HAVE_COMPOSITOR */ + Window last_raise_sibling; }; gboolean myScreenCheckWMAtom (ScreenInfo *, --- ./src/stacking.c +++ ./src/stacking.c @@ -43,13 +43,13 @@ static guint raise_timeout = 0; void -clientApplyStackList (ScreenInfo *screen_info) +clientApplyStackList (ScreenInfo *screen_info, Client *client, StackingAction action ) { Window *xwinstack; guint nwindows; gint i; - DBG ("applying stack list"); + DBG ("applying stack list, action=%s on window 0x%lx", (action==Raise)? "Raise" : ((action==Lower)? "Lower" : "Restack"), client->window ); nwindows = g_list_length (screen_info->windows_stack); i = 0; @@ -68,11 +68,48 @@ clientApplyStackList (ScreenInfo *screen { c = (Client *) list->data; xwinstack[i++] = c->frame; - DBG (" [%i] \"%s\" (0x%lx)", i, c->name, c->window); + if ( !((action==Raise || action==Lower) && c->window!=client->window) ) + { + DBG (" [%i] \"%s\" (0x%lx)", i, c->name, c->window); + } } } - XRestackWindows (myScreenGetXDisplay (screen_info), xwinstack, (int) nwindows + 4); + switch (action) + { + case Restack: + default: + // Restack the windows. This is the preferred action if the lowering/raising has to be done with respect to + // a sibling window. + XRestackWindows (myScreenGetXDisplay (screen_info), xwinstack, (int) nwindows + 4); + break; + case Raise: + // Raise the windows inconditionally, working backwards (xwinstack[n-1] .. xwinstack[0]) as RestackWindows would do too. + // This is the preferred action when raising a window on Mac OS X or MS Windows when the X server does not + // manage all windows on the screen. Using Restack, the window would remain behind non X windows if it was + // not already in front of them. + for (i = nwindows ; i >= 0 ; --i) + { + if (xwinstack[i] == client->frame || i <= 3) + { + XRaiseWindow (myScreenGetXDisplay (screen_info), xwinstack[i]); + } + } + break; + case Lower: + // Lower the windows inconditionally, (xwinstack[0] .. xwinstack[n-1]). + // This is the preferred action when lowering a window on Mac OS X or MS Windows when the X server does not + // manage all windows on the screen. Using Restack, the window would remain in front of non X windows if it was + // not already behind them. + for (i = 0 ; i < nwindows ; ++i) + { + if (xwinstack[i] == client->frame || i <= 3) + { + XLowerWindow (myScreenGetXDisplay (screen_info), xwinstack[i]); + } + } + break; + } g_free (xwinstack); } @@ -297,9 +334,9 @@ clientRaise (Client * c, Window wsibling transients = NULL; sibling = NULL; - if (c == screen_info->last_raise) + if (c == screen_info->last_raise && (wsibling && wsibling == screen_info->last_raise_sibling)) { - TRACE ("client \"%s\" (0x%lx) already raised", c->name, c->window); + TRACE ("client \"%s\" (0x%lx) already raised w.r.t. sibling %lx", c->name, c->window, wsibling); return; } TRACE ("raising client \"%s\" (0x%lx) over (0x%lx)", c->name, c->window, wsibling); @@ -429,10 +466,12 @@ clientRaise (Client * c, Window wsibling } /* Now, screen_info->windows_stack contains the correct window stack We still need to tell the X Server to reflect the changes + This is done using XRestackWindows when we're restacking w.r.t. wsibling, and using XRaiseWindow otherwise. */ - clientApplyStackList (screen_info); + clientApplyStackList (screen_info, c, (wsibling)? Restack : Raise); clientSetNetClientList (c->screen_info, display_info->atoms[NET_CLIENT_LIST_STACKING], screen_info->windows_stack); screen_info->last_raise = c; + screen_info->last_raise_sibling = wsibling; } } @@ -518,13 +557,15 @@ clientLower (Client * c, Window wsibling } /* Now, screen_info->windows_stack contains the correct window stack We still need to tell the X Server to reflect the changes + This is done using XRestackWindows when we're restacking w.r.t. wsibling, and using XLowerWindow otherwise. */ - clientApplyStackList (screen_info); + clientApplyStackList (screen_info, c, (wsibling)? Restack : Lower); clientSetNetClientList (screen_info, display_info->atoms[NET_CLIENT_LIST_STACKING], screen_info->windows_stack); clientPassFocus (screen_info, c, NULL); if (screen_info->last_raise == c) { screen_info->last_raise = NULL; + screen_info->last_raise_sibling = 0; } } } --- ./src/stacking.h +++ ./src/stacking.h @@ -31,7 +31,9 @@ #include "screen.h" #include "client.h" -void clientApplyStackList (ScreenInfo *); +typedef enum StackingAction {Restack, Raise, Lower} StackingAction; + +void clientApplyStackList (ScreenInfo *, Client *, StackingAction); Client *clientGetLowestTransient (Client *); Client *clientGetHighestTransientOrModalFor (Client *); gboolean clientIsTopMost (Client *);