From 20a68552c1e35467cb9dc70be0c3d2fe0734066e Mon Sep 17 00:00:00 2001 From: Leon Kowarschick <5300871+elkowar@users.noreply.github.com> Date: Mon, 6 Jul 2020 13:45:59 +0200 Subject: [PATCH] Fix window swallowing problems in xmonad --- files/.xmonad/lib/Config.hs | 4 +-- files/.xmonad/lib/WindowSwallowing.hs | 48 +++++++++++++++++++-------- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/files/.xmonad/lib/Config.hs b/files/.xmonad/lib/Config.hs index 3680931..48356d6 100644 --- a/files/.xmonad/lib/Config.hs +++ b/files/.xmonad/lib/Config.hs @@ -23,9 +23,9 @@ import qualified XMonad.Util.ExtensibleState as XS import qualified Rofi import qualified DescribedSubmap import qualified TiledDragging ---import qualified WindowSwallowing +import qualified WindowSwallowing -import XMonad.Hooks.WindowSwallowing as WindowSwallowing +--import XMonad.Hooks.WindowSwallowing as WindowSwallowing import Data.Foldable ( for_ ) diff --git a/files/.xmonad/lib/WindowSwallowing.hs b/files/.xmonad/lib/WindowSwallowing.hs index 7035fca..31b98af 100644 --- a/files/.xmonad/lib/WindowSwallowing.hs +++ b/files/.xmonad/lib/WindowSwallowing.hs @@ -44,11 +44,14 @@ where import XMonad import qualified XMonad.StackSet as W import qualified XMonad.Util.ExtensibleState as XS -import XMonad.Util.Run ( runProcessWithInput ) +import XMonad.Util.Run ( runProcessWithInput + , safeSpawn + ) import XMonad.Util.WindowProperties import Data.Semigroup ( All(..) ) import qualified Data.Map.Strict as M import Data.List ( isInfixOf ) +import Data.Maybe ( fromMaybe ) import Control.Monad ( when ) -- $usage @@ -58,7 +61,7 @@ import Control.Monad ( when ) -- -- and using 'swallowEventHook' somewhere in your 'handleEventHook', for example: -- --- > myHandleEventHook = swallowEventHook [className =? "Alacritty", className =? "Termite"] [return True] +-- > myHandleEventHook = swallowEventHook (className =? "Alacritty" <||> className =? "Termite") (return True) -- -- For more information on editing your handleEventHook and key bindings, -- see "XMonad.Doc.Extending". @@ -117,6 +120,7 @@ swallowEventHook parentQueries childQueries event = do XS.modify . setStackBeforeWindowClosing . currentStack $ ws XS.modify . setFloatingBeforeWindowClosing . W.floating $ ws + -- This is called right after any window closes. DestroyWindowEvent { ev_event = eventId, ev_window = childWindow } -> -- Because DestroyWindowEvent is emitted a lot more often then you think, @@ -130,17 +134,33 @@ swallowEventHook parentQueries childQueries event = do case (maybeSwallowedParent, maybeOldStack) of (Just parent, Just oldStack) -> do -- If there actually is a corresponding swallowed parent window for this window, - -- we will restore and place it where the closed window was. - -- For this, we look at the stack-state that was stored /before/ the window was closed, - -- and replace the focused window with the now restored parent. - -- we do this to make sure the parent is restored in the exact position the child was at. - windows - (\ws -> - updateCurrentStack - (const $ Just $ oldStack { W.focus = parent }) - $ moveFloatingState childWindow parent - $ ws { W.floating = oldFloating } - ) + -- 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) + let curLen = length (W.integrate' curStack) + return (oldLen - 1 == curLen && childWindow == W.focus oldStack) + + if stackStoredCorrectly + then windows + (\ws -> + updateCurrentStack + (const $ Just $ oldStack { W.focus = parent }) + $ moveFloatingState childWindow parent + $ ws { W.floating = oldFloating } + ) + else windows + (W.modify + (Just $ W.Stack parent [] []) + (\s -> Just + $ s { W.focus = parent, W.down = W.focus s : W.down s } + ) + ) -- after restoring, we remove the information about the swallowing from the state. XS.modify $ removeSwallowed childWindow XS.modify $ setStackBeforeWindowClosing Nothing @@ -149,7 +169,6 @@ swallowEventHook parentQueries childQueries event = do _ -> return () return $ All True - -- | run a pure transformation on the Stack of the currently focused workspace. updateCurrentStack :: (Maybe (W.Stack a) -> Maybe (W.Stack a)) @@ -223,3 +242,4 @@ instance ExtensionClass SwallowingState where fi :: (Integral a, Num b) => a -> b fi = fromIntegral +