X.H.WindowSwallowing: Fix single window getting lost

ConfigureEvents may occur after a window has been deleted, an UnmapEvent
has already been sent (and thus xmonad already unmanaged the window),
but before a DestroyWindowEvent is caught by the eventHook.  For
example, this is the case when one uses smartBorders with a single
window (such that smartBorders is "active").  The ConfigureEvents
sensibly already have an empty stack (because the UnmapEvent has already
been received), which we then copy to the history.

Whenever a parent window has been found, the sensible thing to do is to
always restore it.  The fact that oldStack is Nothing simply encodes an
empty workspace and is thus something we definitely need to handle as
well.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/638
This commit is contained in:
slotThe
2021-11-07 15:24:47 +01:00
parent feee11a0ba
commit 5c50387db0
2 changed files with 23 additions and 11 deletions

View File

@@ -155,14 +155,19 @@ swallowEventHook parentQ childQ event = do
maybeOldStack <- XS.gets stackBeforeWindowClosing
oldFloating <- XS.gets floatingBeforeClosing
case (maybeSwallowedParent, maybeOldStack) of
-- If there actually is a corresponding swallowed parent window for this window,
-- we will try to restore it.
-- Because there are some cases where the stack-state is not stored correctly in the ConfigureEvent hook,
-- we have to first check if the stack-state is valid.
-- If it is, we can restore the parent exactly where the child window was before being closed.
-- If the stored stack-state is invalid however, we still restore the window
-- by just inserting it as the focused window in the stack.
--
-- After restoring, we remove the information about the swallowing from the state.
(Just parent, Nothing) -> do
windows (insertIntoStack parent)
deleteState childWindow
(Just parent, Just oldStack) -> do
-- If there actually is a corresponding swallowed parent window for this window,
-- we will try to restore it.
-- because there are some cases where the stack-state is not stored correctly in the ConfigureEvent hook,
-- we have to first check if the stack-state is valid.
-- if it is, we can restore the parent exactly where the child window was before being closed
-- if the stored stack-state is invalid however, we still restore the window
-- by just inserting it as the focused window in the stack.
stackStoredCorrectly <- do
curStack <- withWindowSet (return . currentStack)
let oldLen = length (W.integrate oldStack)
@@ -178,13 +183,15 @@ swallowEventHook parentQ childQ event = do
$ ws { W.floating = oldFloating }
)
else windows (insertIntoStack parent)
-- after restoring, we remove the information about the swallowing from the state.
XS.modify $ removeSwallowed childWindow
XS.modify $ setStackBeforeWindowClosing Nothing
deleteState childWindow
_ -> return ()
return ()
_ -> return ()
return $ All True
where
deleteState :: Window -> X ()
deleteState childWindow = do
XS.modify $ removeSwallowed childWindow
XS.modify $ setStackBeforeWindowClosing Nothing
-- | insert a window as focused into the current stack, moving the previously focused window down the stack
insertIntoStack :: a -> W.StackSet i l a sid sd -> W.StackSet i l a sid sd