mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-05-19 03:20:21 -07:00
issue 105 was due to the fact that tab windows created when bootstrapping the windowset after a restart where managed. Setting the override_redirect attributes to True fixes the issue. Added the possibility to set the override_redirect attribute with XMonad.Util.XUtils.creationNewWindow
241 lines
9.7 KiB
Haskell
241 lines
9.7 KiB
Haskell
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, PatternGuards, TypeSynonymInstances #-}
|
|
-----------------------------------------------------------------------------
|
|
-- |
|
|
-- Module : XMonad.Layout.Tabbed
|
|
-- Copyright : (c) 2007 David Roundy, Andrea Rossato
|
|
-- License : BSD-style (see xmonad/LICENSE)
|
|
--
|
|
-- Maintainer : droundy@darcs.net, andrea.rossato@unibz.it
|
|
-- Stability : unstable
|
|
-- Portability : unportable
|
|
--
|
|
-- A tabbed layout for the Xmonad Window Manager
|
|
--
|
|
-----------------------------------------------------------------------------
|
|
|
|
module XMonad.Layout.Tabbed (
|
|
-- * Usage:
|
|
-- $usage
|
|
tabbed
|
|
, shrinkText, CustomShrink(CustomShrink)
|
|
, TConf (..), defaultTConf
|
|
, Shrinker(..)
|
|
) where
|
|
|
|
import Data.Maybe
|
|
import Data.List
|
|
|
|
import XMonad
|
|
import qualified XMonad.StackSet as W
|
|
|
|
import XMonad.Util.NamedWindows
|
|
import XMonad.Util.Invisible
|
|
import XMonad.Util.XUtils
|
|
import XMonad.Util.Font
|
|
|
|
import XMonad.Hooks.UrgencyHook
|
|
|
|
-- $usage
|
|
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
|
--
|
|
-- > import XMonad.Layout.Tabbed
|
|
--
|
|
-- Then edit your @layoutHook@ by adding the Tabbed layout:
|
|
--
|
|
-- > myLayouts = tabbed shrinkText defaultTConf ||| Full ||| etc..
|
|
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
|
|
--
|
|
-- For more detailed instructions on editing the layoutHook see:
|
|
--
|
|
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
|
|
--
|
|
-- You can also edit the default configuration options.
|
|
--
|
|
-- > myTabConfig = defaultTConf { inactiveBorderColor = "#FF0000"
|
|
-- > , activeTextColor = "#00FF00"}
|
|
--
|
|
-- and
|
|
--
|
|
-- > mylayout = tabbed shrinkText myTabConfig ||| Full ||| etc..
|
|
|
|
tabbed :: Shrinker s => s -> TConf -> Tabbed s a
|
|
tabbed s t = Tabbed (I Nothing) s t
|
|
|
|
data TConf =
|
|
TConf { activeColor :: String
|
|
, inactiveColor :: String
|
|
, urgentColor :: String
|
|
, activeBorderColor :: String
|
|
, inactiveBorderColor :: String
|
|
, urgentBorderColor :: String
|
|
, activeTextColor :: String
|
|
, inactiveTextColor :: String
|
|
, urgentTextColor :: String
|
|
, fontName :: String
|
|
, tabSize :: Int
|
|
} deriving (Show, Read)
|
|
|
|
defaultTConf :: TConf
|
|
defaultTConf =
|
|
TConf { activeColor = "#999999"
|
|
, inactiveColor = "#666666"
|
|
, urgentColor = "#FFFF00"
|
|
, activeBorderColor = "#FFFFFF"
|
|
, inactiveBorderColor = "#BBBBBB"
|
|
, urgentBorderColor = "##00FF00"
|
|
, activeTextColor = "#FFFFFF"
|
|
, inactiveTextColor = "#BFBFBF"
|
|
, urgentTextColor = "#FF0000"
|
|
, fontName = "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"
|
|
, tabSize = 20
|
|
}
|
|
|
|
data TabState =
|
|
TabState { tabsWindows :: [(Window,Window)]
|
|
, scr :: Rectangle
|
|
, font :: XMonadFont
|
|
}
|
|
|
|
data Tabbed s a =
|
|
Tabbed (Invisible Maybe TabState) s TConf
|
|
deriving (Show, Read)
|
|
|
|
instance Shrinker s => LayoutClass (Tabbed s) Window where
|
|
doLayout (Tabbed ist ishr conf) = doLay ist ishr conf
|
|
handleMessage = handleMess
|
|
description _ = "Tabbed"
|
|
|
|
doLay :: Shrinker s => Invisible Maybe TabState -> s -> TConf
|
|
-> Rectangle -> W.Stack Window -> X ([(Window, Rectangle)], Maybe (Tabbed s Window))
|
|
doLay ist ishr c sc (W.Stack w [] []) = do
|
|
whenIJust ist $ \st -> mapM_ deleteWindow (map fst $ tabsWindows st)
|
|
return ([(w,sc)], Just $ Tabbed (I Nothing) ishr c)
|
|
doLay ist ishr c sc@(Rectangle _ _ wid _) s@(W.Stack w _ _) = do
|
|
let ws = W.integrate s
|
|
width = wid `div` fromIntegral (length ws)
|
|
-- initialize state
|
|
st <- case ist of
|
|
(I Nothing ) -> initState c sc ws
|
|
(I (Just ts)) -> if map snd (tabsWindows ts) == ws && scr ts == sc
|
|
then return ts
|
|
else do mapM_ deleteWindow (map fst $ tabsWindows ts)
|
|
tws <- createTabs c sc ws
|
|
return (ts {scr = sc, tabsWindows = zip tws ws})
|
|
mapM_ showWindow $ map fst $ tabsWindows st
|
|
mapM_ (updateTab ishr c (font st) width) $ tabsWindows st
|
|
return ([(w,shrink c sc)], Just (Tabbed (I (Just st)) ishr c))
|
|
|
|
handleMess :: Shrinker s => Tabbed s Window -> SomeMessage -> X (Maybe (Tabbed s Window))
|
|
handleMess (Tabbed (I (Just st@(TabState {tabsWindows = tws}))) ishr conf) m
|
|
| Just e <- fromMessage m :: Maybe Event = handleEvent ishr conf st e >> return Nothing
|
|
| Just Hide == fromMessage m = mapM_ hideWindow (map fst tws) >> return Nothing
|
|
| Just ReleaseResources == fromMessage m = do mapM_ deleteWindow $ map fst tws
|
|
releaseXMF (font st)
|
|
return $ Just $ Tabbed (I Nothing) ishr conf
|
|
handleMess _ _ = return Nothing
|
|
|
|
handleEvent :: Shrinker s => s -> TConf -> TabState -> Event -> X ()
|
|
-- button press
|
|
handleEvent ishr conf (TabState {tabsWindows = tws, scr = screen, font = fs})
|
|
(ButtonEvent {ev_window = thisw, ev_subwindow = thisbw, ev_event_type = t })
|
|
| t == buttonPress, tl <- map fst tws, thisw `elem` tl || thisbw `elem` tl = do
|
|
case lookup thisw tws of
|
|
Just x -> do focus x
|
|
updateTab ishr conf fs width (thisw, x)
|
|
Nothing -> return ()
|
|
where
|
|
width = rect_width screen`div` fromIntegral (length tws)
|
|
|
|
handleEvent ishr conf (TabState {tabsWindows = tws, scr = screen, font = fs})
|
|
(AnyEvent {ev_window = thisw, ev_event_type = t })
|
|
-- expose
|
|
| thisw `elem` (map fst tws) && t == expose = do
|
|
updateTab ishr conf fs width (thisw, fromJust $ lookup thisw tws)
|
|
where
|
|
width = rect_width screen`div` fromIntegral (length tws)
|
|
|
|
-- propertyNotify
|
|
handleEvent ishr conf (TabState {tabsWindows = tws, scr = screen, font = fs})
|
|
(PropertyEvent {ev_window = thisw})
|
|
| thisw `elem` (map snd tws) = do
|
|
let tabwin = (fst $ fromJust $ find ((== thisw) . snd) tws, thisw)
|
|
updateTab ishr conf fs width tabwin
|
|
where width = rect_width screen `div` fromIntegral (length tws)
|
|
-- expose
|
|
handleEvent ishr conf (TabState {tabsWindows = tws, scr = screen, font = fs})
|
|
(ExposeEvent {ev_window = thisw})
|
|
| thisw `elem` (map fst tws) = do
|
|
updateTab ishr conf fs width (thisw, fromJust $ lookup thisw tws)
|
|
where width = rect_width screen `div` fromIntegral (length tws)
|
|
handleEvent _ _ _ _ = return ()
|
|
|
|
initState :: TConf -> Rectangle -> [Window] -> X TabState
|
|
initState conf sc ws = do
|
|
fs <- initXMF (fontName conf)
|
|
tws <- createTabs conf sc ws
|
|
return $ TabState (zip tws ws) sc fs
|
|
|
|
createTabs :: TConf -> Rectangle -> [Window] -> X [Window]
|
|
createTabs _ _ [] = return []
|
|
createTabs c (Rectangle x y wh ht) owl@(ow:ows) = do
|
|
let wid = wh `div` (fromIntegral $ length owl)
|
|
height = fromIntegral $ tabSize c
|
|
mask = Just (exposureMask .|. buttonPressMask)
|
|
d <- asks display
|
|
w <- createNewWindow (Rectangle x y wid height) mask (inactiveColor c) True
|
|
io $ restackWindows d $ w : [ow]
|
|
ws <- createTabs c (Rectangle (x + fromIntegral wid) y (wh - wid) ht) ows
|
|
return (w:ws)
|
|
|
|
updateTab :: Shrinker s => s -> TConf -> XMonadFont -> Dimension -> (Window,Window) -> X ()
|
|
updateTab ishr c fs wh (tabw,ow) = do
|
|
nw <- getName ow
|
|
ur <- readUrgents
|
|
let ht = fromIntegral $ tabSize c :: Dimension
|
|
focusColor win ic ac uc = (maybe ic (\focusw -> case () of
|
|
_ | focusw == win -> ac
|
|
| win `elem` ur -> uc
|
|
| otherwise -> ic) . W.peek)
|
|
`fmap` gets windowset
|
|
(bc',borderc',tc') <- focusColor ow
|
|
(inactiveColor c, inactiveBorderColor c, inactiveTextColor c)
|
|
(activeColor c, activeBorderColor c, activeTextColor c)
|
|
(urgentColor c, urgentBorderColor c, urgentTextColor c)
|
|
dpy <- asks display
|
|
let s = shrinkIt ishr
|
|
name <- shrinkWhile s (\n -> do
|
|
size <- io $ textWidthXMF dpy fs n
|
|
return $ size > fromIntegral wh - fromIntegral (ht `div` 2)) (show nw)
|
|
paintAndWrite tabw fs wh ht 1 bc' borderc' tc' bc' AlignCenter name
|
|
|
|
shrink :: TConf -> Rectangle -> Rectangle
|
|
shrink c (Rectangle x y w h) =
|
|
Rectangle x (y + fromIntegral (tabSize c)) w (h - fromIntegral (tabSize c))
|
|
|
|
shrinkWhile :: (String -> [String]) -> (String -> X Bool) -> String -> X String
|
|
shrinkWhile sh p x = sw $ sh x
|
|
where sw [n] = return n
|
|
sw [] = return ""
|
|
sw (n:ns) = do
|
|
cond <- p n
|
|
if cond
|
|
then sw ns
|
|
else return n
|
|
|
|
data CustomShrink = CustomShrink
|
|
instance Show CustomShrink where show _ = ""
|
|
instance Read CustomShrink where readsPrec _ s = [(CustomShrink,s)]
|
|
|
|
class (Read s, Show s) => Shrinker s where
|
|
shrinkIt :: s -> String -> [String]
|
|
|
|
data DefaultShrinker = DefaultShrinker
|
|
instance Show DefaultShrinker where show _ = ""
|
|
instance Read DefaultShrinker where readsPrec _ s = [(DefaultShrinker,s)]
|
|
instance Shrinker DefaultShrinker where
|
|
shrinkIt _ "" = [""]
|
|
shrinkIt s cs = cs : shrinkIt s (init cs)
|
|
|
|
shrinkText :: DefaultShrinker
|
|
shrinkText = DefaultShrinker
|