diff --git a/XMonad/Util/Hacks.hs b/XMonad/Util/Hacks.hs index c343a4eb..0b493073 100644 --- a/XMonad/Util/Hacks.hs +++ b/XMonad/Util/Hacks.hs @@ -27,12 +27,17 @@ module XMonad.Util.Hacks ( -- * Java Hack -- $java javaHack, + + -- * Stacking trays (trayer) above panels (xmobar) + -- $raiseTrayer + trayerAboveXmobarEventHook, + trayAbovePanelEventHook, ) where import XMonad import Data.Monoid (All(All)) -import Control.Monad (when) +import Control.Monad (when, filterM) import System.Posix.Env (putEnv) @@ -93,3 +98,49 @@ javaHack conf = conf { startupHook = startupHook conf *> io (putEnv "_JAVA_AWT_WM_NONREPARENTING=1") } + + +-- $raiseTrayer +-- Placing @trayer@ on top of @xmobar@ is somewhat tricky: +-- +-- - they both should be lowered to the bottom of the stacking order to avoid +-- overlapping fullscreen windows +-- +-- - the tray needs to be stacked on top of the panel regardless of which +-- happens to start first +-- +-- 'trayerAboveXmobarEventHook' (and the more generic +-- 'trayAbovePanelEventHook') is an event hook that ensures the latter: +-- whenever the tray lowers itself to the bottom of the stack, it checks +-- whether there are any panels above it and lowers these again. +-- +-- To ensure the former, that is having both @trayer@ and @xmobar@ lower +-- themselves, which is a necessary prerequisite for this event hook to +-- trigger: +-- +-- - set @lowerOnStart = True@ and @overrideRedirect = True@ in @~/.xmobarrc@ +-- - pass @-l@ to @trayer@ +-- +-- Usage: +-- +-- > handleEventHook = … <> Hacks.trayerAboveXmobarEventHook + +-- | 'trayAbovePanelEventHook' for trayer/xmobar +trayerAboveXmobarEventHook :: Event -> X All +trayerAboveXmobarEventHook = trayAbovePanelEventHook (className =? "trayer") (appName =? "xmobar") + +-- | Whenever a tray window lowers itself to the bottom of the stack, look for +-- any panels above it and lower these. +trayAbovePanelEventHook + :: Query Bool -- ^ tray + -> Query Bool -- ^ panel + -> (Event -> X All) -- ^ event hook +trayAbovePanelEventHook trayQ panelQ ConfigureEvent{ev_window = w, ev_above = a} | a == none = do + whenX (runQuery trayQ w) $ withDisplay $ \dpy -> do + rootw <- asks theRoot + (_, _, ws) <- io $ queryTree dpy rootw + let aboveTrayWs = dropWhile (w /=) ws + panelWs <- filterM (runQuery panelQ) aboveTrayWs + mapM_ (io . lowerWindow dpy) panelWs + mempty +trayAbovePanelEventHook _ _ _ = mempty