{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
module XMonad.Layout.DecorationEx.Common (
WindowDecoration (..)
, WindowCommand (..)
, DecorationWidget (..)
, WidgetPlace (..)
, WidgetLayout (..)
, HasWidgets (..)
, ClickHandler (..)
, ThemeAttributes (..)
, XPaintingContext
, BoxBorders (..)
, BorderColors
, ThemeStyleType (..)
, SimpleStyle (..)
, GenericTheme (..)
, ThemeEx
, widgetLayout
, windowStyleType
, genericWindowStyle
, themeEx
, borderColor
, shadowBorder
) where
import qualified Data.Map as M
import Data.Bits (testBit)
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Hooks.UrgencyHook
import qualified XMonad.Layout.Decoration as D
data WindowDecoration = WindowDecoration {
WindowDecoration -> Window
wdOrigWindow :: !Window
, WindowDecoration -> Rectangle
wdOrigWinRect :: !Rectangle
, WindowDecoration -> Maybe Window
wdDecoWindow :: !(Maybe Window)
, WindowDecoration -> Maybe Rectangle
wdDecoRect :: !(Maybe Rectangle)
, WindowDecoration -> [WidgetPlace]
wdWidgets :: ![WidgetPlace]
}
class (Read cmd, Show cmd) => WindowCommand cmd where
executeWindowCommand :: cmd -> Window -> X Bool
isCommandChecked :: cmd -> Window -> X Bool
class (WindowCommand (WidgetCommand widget), Read widget, Show widget)
=> DecorationWidget widget where
type WidgetCommand widget
widgetCommand :: widget -> Int -> WidgetCommand widget
isShrinkable :: widget -> Bool
data WidgetLayout a = WidgetLayout {
forall a. WidgetLayout a -> [a]
wlLeft :: ![a]
, forall a. WidgetLayout a -> [a]
wlCenter :: ![a]
, forall a. WidgetLayout a -> [a]
wlRight :: ![a]
}
data WidgetPlace = WidgetPlace {
WidgetPlace -> Position
wpTextYPosition :: !Position
, WidgetPlace -> Rectangle
wpRectangle :: !Rectangle
}
deriving (Int -> WidgetPlace -> ShowS
[WidgetPlace] -> ShowS
WidgetPlace -> String
(Int -> WidgetPlace -> ShowS)
-> (WidgetPlace -> String)
-> ([WidgetPlace] -> ShowS)
-> Show WidgetPlace
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> WidgetPlace -> ShowS
showsPrec :: Int -> WidgetPlace -> ShowS
$cshow :: WidgetPlace -> String
show :: WidgetPlace -> String
$cshowList :: [WidgetPlace] -> ShowS
showList :: [WidgetPlace] -> ShowS
Show)
data BoxBorders a = BoxBorders {
forall a. BoxBorders a -> a
bxTop :: !a
, forall a. BoxBorders a -> a
bxRight :: !a
, forall a. BoxBorders a -> a
bxBottom :: !a
, forall a. BoxBorders a -> a
bxLeft :: !a
} deriving (BoxBorders a -> BoxBorders a -> Bool
(BoxBorders a -> BoxBorders a -> Bool)
-> (BoxBorders a -> BoxBorders a -> Bool) -> Eq (BoxBorders a)
forall a. Eq a => BoxBorders a -> BoxBorders a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => BoxBorders a -> BoxBorders a -> Bool
== :: BoxBorders a -> BoxBorders a -> Bool
$c/= :: forall a. Eq a => BoxBorders a -> BoxBorders a -> Bool
/= :: BoxBorders a -> BoxBorders a -> Bool
Eq, ReadPrec [BoxBorders a]
ReadPrec (BoxBorders a)
Int -> ReadS (BoxBorders a)
ReadS [BoxBorders a]
(Int -> ReadS (BoxBorders a))
-> ReadS [BoxBorders a]
-> ReadPrec (BoxBorders a)
-> ReadPrec [BoxBorders a]
-> Read (BoxBorders a)
forall a. Read a => ReadPrec [BoxBorders a]
forall a. Read a => ReadPrec (BoxBorders a)
forall a. Read a => Int -> ReadS (BoxBorders a)
forall a. Read a => ReadS [BoxBorders a]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: forall a. Read a => Int -> ReadS (BoxBorders a)
readsPrec :: Int -> ReadS (BoxBorders a)
$creadList :: forall a. Read a => ReadS [BoxBorders a]
readList :: ReadS [BoxBorders a]
$creadPrec :: forall a. Read a => ReadPrec (BoxBorders a)
readPrec :: ReadPrec (BoxBorders a)
$creadListPrec :: forall a. Read a => ReadPrec [BoxBorders a]
readListPrec :: ReadPrec [BoxBorders a]
Read, Int -> BoxBorders a -> ShowS
[BoxBorders a] -> ShowS
BoxBorders a -> String
(Int -> BoxBorders a -> ShowS)
-> (BoxBorders a -> String)
-> ([BoxBorders a] -> ShowS)
-> Show (BoxBorders a)
forall a. Show a => Int -> BoxBorders a -> ShowS
forall a. Show a => [BoxBorders a] -> ShowS
forall a. Show a => BoxBorders a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> BoxBorders a -> ShowS
showsPrec :: Int -> BoxBorders a -> ShowS
$cshow :: forall a. Show a => BoxBorders a -> String
show :: BoxBorders a -> String
$cshowList :: forall a. Show a => [BoxBorders a] -> ShowS
showList :: [BoxBorders a] -> ShowS
Show)
type BorderColors = BoxBorders String
data SimpleStyle = SimpleStyle {
SimpleStyle -> String
sBgColor :: !String
, SimpleStyle -> String
sTextColor :: !String
, SimpleStyle -> String
sTextBgColor :: !String
, SimpleStyle -> Dimension
sDecoBorderWidth :: !Dimension
, SimpleStyle -> BorderColors
sDecorationBorders :: !BorderColors
}
deriving (Int -> SimpleStyle -> ShowS
[SimpleStyle] -> ShowS
SimpleStyle -> String
(Int -> SimpleStyle -> ShowS)
-> (SimpleStyle -> String)
-> ([SimpleStyle] -> ShowS)
-> Show SimpleStyle
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SimpleStyle -> ShowS
showsPrec :: Int -> SimpleStyle -> ShowS
$cshow :: SimpleStyle -> String
show :: SimpleStyle -> String
$cshowList :: [SimpleStyle] -> ShowS
showList :: [SimpleStyle] -> ShowS
Show, ReadPrec [SimpleStyle]
ReadPrec SimpleStyle
Int -> ReadS SimpleStyle
ReadS [SimpleStyle]
(Int -> ReadS SimpleStyle)
-> ReadS [SimpleStyle]
-> ReadPrec SimpleStyle
-> ReadPrec [SimpleStyle]
-> Read SimpleStyle
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS SimpleStyle
readsPrec :: Int -> ReadS SimpleStyle
$creadList :: ReadS [SimpleStyle]
readList :: ReadS [SimpleStyle]
$creadPrec :: ReadPrec SimpleStyle
readPrec :: ReadPrec SimpleStyle
$creadListPrec :: ReadPrec [SimpleStyle]
readListPrec :: ReadPrec [SimpleStyle]
Read)
class HasWidgets theme widget where
themeWidgets :: theme widget -> WidgetLayout widget
class ClickHandler theme widget where
onDecorationClick :: theme widget
-> Int
-> Maybe (WidgetCommand widget)
isDraggingEnabled :: theme widget
-> Int
-> Bool
class (Read theme, Show theme) => ThemeAttributes theme where
type Style theme
selectWindowStyle :: theme -> Window -> X (Style theme)
widgetsPadding :: theme -> BoxBorders Dimension
defaultBgColor :: theme -> String
themeFontName :: theme -> String
data GenericTheme style widget = GenericTheme {
forall style widget. GenericTheme style widget -> style
exActive :: !style
, forall style widget. GenericTheme style widget -> style
exInactive :: !style
, forall style widget. GenericTheme style widget -> style
exUrgent :: !style
, forall style widget.
GenericTheme style widget -> BoxBorders Dimension
exPadding :: !(BoxBorders Dimension)
, forall style widget. GenericTheme style widget -> String
exFontName :: !String
, forall style widget.
GenericTheme style widget -> Map Int (WidgetCommand widget)
exOnDecoClick :: !(M.Map Int (WidgetCommand widget))
, forall style widget. GenericTheme style widget -> [Int]
exDragWindowButtons :: ![Int]
, forall style widget. GenericTheme style widget -> [widget]
exWidgetsLeft :: ![widget]
, forall style widget. GenericTheme style widget -> [widget]
exWidgetsCenter :: ![widget]
, forall style widget. GenericTheme style widget -> [widget]
exWidgetsRight :: ![widget]
}
deriving instance (Show widget, Show (WidgetCommand widget), Show style) => Show (GenericTheme style widget)
deriving instance (Read widget, Read (WidgetCommand widget), Read style) => Read (GenericTheme style widget)
type ThemeEx widget = GenericTheme SimpleStyle widget
instance HasWidgets (GenericTheme style) widget where
themeWidgets :: GenericTheme style widget -> WidgetLayout widget
themeWidgets GenericTheme style widget
theme = [widget] -> [widget] -> [widget] -> WidgetLayout widget
forall a. [a] -> [a] -> [a] -> WidgetLayout a
WidgetLayout (GenericTheme style widget -> [widget]
forall style widget. GenericTheme style widget -> [widget]
exWidgetsLeft GenericTheme style widget
theme) (GenericTheme style widget -> [widget]
forall style widget. GenericTheme style widget -> [widget]
exWidgetsCenter GenericTheme style widget
theme) (GenericTheme style widget -> [widget]
forall style widget. GenericTheme style widget -> [widget]
exWidgetsRight GenericTheme style widget
theme)
data ThemeStyleType = ActiveWindow | UrgentWindow | InactiveWindow
deriving (ThemeStyleType -> ThemeStyleType -> Bool
(ThemeStyleType -> ThemeStyleType -> Bool)
-> (ThemeStyleType -> ThemeStyleType -> Bool) -> Eq ThemeStyleType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ThemeStyleType -> ThemeStyleType -> Bool
== :: ThemeStyleType -> ThemeStyleType -> Bool
$c/= :: ThemeStyleType -> ThemeStyleType -> Bool
/= :: ThemeStyleType -> ThemeStyleType -> Bool
Eq, Int -> ThemeStyleType -> ShowS
[ThemeStyleType] -> ShowS
ThemeStyleType -> String
(Int -> ThemeStyleType -> ShowS)
-> (ThemeStyleType -> String)
-> ([ThemeStyleType] -> ShowS)
-> Show ThemeStyleType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ThemeStyleType -> ShowS
showsPrec :: Int -> ThemeStyleType -> ShowS
$cshow :: ThemeStyleType -> String
show :: ThemeStyleType -> String
$cshowList :: [ThemeStyleType] -> ShowS
showList :: [ThemeStyleType] -> ShowS
Show, ReadPrec [ThemeStyleType]
ReadPrec ThemeStyleType
Int -> ReadS ThemeStyleType
ReadS [ThemeStyleType]
(Int -> ReadS ThemeStyleType)
-> ReadS [ThemeStyleType]
-> ReadPrec ThemeStyleType
-> ReadPrec [ThemeStyleType]
-> Read ThemeStyleType
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS ThemeStyleType
readsPrec :: Int -> ReadS ThemeStyleType
$creadList :: ReadS [ThemeStyleType]
readList :: ReadS [ThemeStyleType]
$creadPrec :: ReadPrec ThemeStyleType
readPrec :: ReadPrec ThemeStyleType
$creadListPrec :: ReadPrec [ThemeStyleType]
readListPrec :: ReadPrec [ThemeStyleType]
Read)
widgetLayout :: WidgetLayout widget -> [widget]
widgetLayout :: forall a. WidgetLayout a -> [a]
widgetLayout WidgetLayout widget
ws = WidgetLayout widget -> [widget]
forall a. WidgetLayout a -> [a]
wlLeft WidgetLayout widget
ws [widget] -> [widget] -> [widget]
forall a. [a] -> [a] -> [a]
++ WidgetLayout widget -> [widget]
forall a. WidgetLayout a -> [a]
wlCenter WidgetLayout widget
ws [widget] -> [widget] -> [widget]
forall a. [a] -> [a] -> [a]
++ WidgetLayout widget -> [widget]
forall a. WidgetLayout a -> [a]
wlRight WidgetLayout widget
ws
type XPaintingContext = (Display, Pixmap, GC)
instance (Show widget, Read widget, Read (WidgetCommand widget), Show (WidgetCommand widget))
=> ThemeAttributes (ThemeEx widget) where
type Style (ThemeEx widget) = SimpleStyle
selectWindowStyle :: ThemeEx widget -> Window -> X (Style (ThemeEx widget))
selectWindowStyle ThemeEx widget
theme Window
w = Window -> ThemeEx widget -> X SimpleStyle
forall style widget. Window -> GenericTheme style widget -> X style
genericWindowStyle Window
w ThemeEx widget
theme
defaultBgColor :: ThemeEx widget -> String
defaultBgColor ThemeEx widget
t = SimpleStyle -> String
sBgColor (SimpleStyle -> String) -> SimpleStyle -> String
forall a b. (a -> b) -> a -> b
$ ThemeEx widget -> SimpleStyle
forall style widget. GenericTheme style widget -> style
exInactive ThemeEx widget
t
widgetsPadding :: ThemeEx widget -> BoxBorders Dimension
widgetsPadding = ThemeEx widget -> BoxBorders Dimension
forall style widget.
GenericTheme style widget -> BoxBorders Dimension
exPadding
themeFontName :: ThemeEx widget -> String
themeFontName = ThemeEx widget -> String
forall style widget. GenericTheme style widget -> String
exFontName
instance ClickHandler (GenericTheme SimpleStyle) widget where
onDecorationClick :: GenericTheme SimpleStyle widget
-> Int -> Maybe (WidgetCommand widget)
onDecorationClick GenericTheme SimpleStyle widget
theme Int
button = Int
-> Map Int (WidgetCommand widget) -> Maybe (WidgetCommand widget)
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Int
button (GenericTheme SimpleStyle widget -> Map Int (WidgetCommand widget)
forall style widget.
GenericTheme style widget -> Map Int (WidgetCommand widget)
exOnDecoClick GenericTheme SimpleStyle widget
theme)
isDraggingEnabled :: GenericTheme SimpleStyle widget -> Int -> Bool
isDraggingEnabled GenericTheme SimpleStyle widget
theme Int
button = Int
button Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` GenericTheme SimpleStyle widget -> [Int]
forall style widget. GenericTheme style widget -> [Int]
exDragWindowButtons GenericTheme SimpleStyle widget
theme
genericWindowStyle :: Window -> GenericTheme style widget -> X style
genericWindowStyle :: forall style widget. Window -> GenericTheme style widget -> X style
genericWindowStyle Window
win GenericTheme style widget
theme = do
ThemeStyleType
styleType <- Window -> X ThemeStyleType
windowStyleType Window
win
style -> X style
forall a. a -> X a
forall (m :: * -> *) a. Monad m => a -> m a
return (style -> X style) -> style -> X style
forall a b. (a -> b) -> a -> b
$ case ThemeStyleType
styleType of
ThemeStyleType
ActiveWindow -> GenericTheme style widget -> style
forall style widget. GenericTheme style widget -> style
exActive GenericTheme style widget
theme
ThemeStyleType
InactiveWindow -> GenericTheme style widget -> style
forall style widget. GenericTheme style widget -> style
exInactive GenericTheme style widget
theme
ThemeStyleType
UrgentWindow -> GenericTheme style widget -> style
forall style widget. GenericTheme style widget -> style
exUrgent GenericTheme style widget
theme
windowStyleType :: Window -> X ThemeStyleType
windowStyleType :: Window -> X ThemeStyleType
windowStyleType Window
win = do
Maybe Window
mbFocused <- StackSet String (Layout Window) Window ScreenId ScreenDetail
-> Maybe Window
forall i l a s sd. StackSet i l a s sd -> Maybe a
W.peek (StackSet String (Layout Window) Window ScreenId ScreenDetail
-> Maybe Window)
-> X (StackSet String (Layout Window) Window ScreenId ScreenDetail)
-> X (Maybe Window)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (XState
-> StackSet String (Layout Window) Window ScreenId ScreenDetail)
-> X (StackSet String (Layout Window) Window ScreenId ScreenDetail)
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets XState
-> StackSet String (Layout Window) Window ScreenId ScreenDetail
windowset
Bool
isWmStateUrgent <- (Window
win Window -> [Window] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem`) ([Window] -> Bool) -> X [Window] -> X Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> X [Window]
readUrgents
Bool
isUrgencyBitSet <- (Display -> X Bool) -> X Bool
forall a. (Display -> X a) -> X a
withDisplay ((Display -> X Bool) -> X Bool) -> (Display -> X Bool) -> X Bool
forall a b. (a -> b) -> a -> b
$ \Display
dpy -> do
WMHints
hints <- IO WMHints -> X WMHints
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO WMHints -> X WMHints) -> IO WMHints -> X WMHints
forall a b. (a -> b) -> a -> b
$ Display -> Window -> IO WMHints
getWMHints Display
dpy Window
win
Bool -> X Bool
forall a. a -> X a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> X Bool) -> Bool -> X Bool
forall a b. (a -> b) -> a -> b
$ WMHints -> CLong
wmh_flags WMHints
hints CLong -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
`testBit` Int
urgencyHintBit
if Bool
isWmStateUrgent Bool -> Bool -> Bool
|| Bool
isUrgencyBitSet
then ThemeStyleType -> X ThemeStyleType
forall a. a -> X a
forall (m :: * -> *) a. Monad m => a -> m a
return ThemeStyleType
UrgentWindow
else ThemeStyleType -> X ThemeStyleType
forall a. a -> X a
forall (m :: * -> *) a. Monad m => a -> m a
return (ThemeStyleType -> X ThemeStyleType)
-> ThemeStyleType -> X ThemeStyleType
forall a b. (a -> b) -> a -> b
$
case Maybe Window
mbFocused of
Maybe Window
Nothing -> ThemeStyleType
InactiveWindow
Just Window
focused
| Window
focused Window -> Window -> Bool
forall a. Eq a => a -> a -> Bool
== Window
win -> ThemeStyleType
ActiveWindow
| Bool
otherwise -> ThemeStyleType
InactiveWindow
themeEx :: Default (WidgetCommand widget) => D.Theme -> ThemeEx widget
themeEx :: forall widget.
Default (WidgetCommand widget) =>
Theme -> ThemeEx widget
themeEx Theme
t =
GenericTheme {
exActive :: SimpleStyle
exActive = String
-> String -> String -> Dimension -> BorderColors -> SimpleStyle
SimpleStyle (Theme -> String
D.activeColor Theme
t) (Theme -> String
D.activeTextColor Theme
t) (Theme -> String
D.activeColor Theme
t) (Theme -> Dimension
D.activeBorderWidth Theme
t) (String -> BorderColors
borderColor (String -> BorderColors) -> String -> BorderColors
forall a b. (a -> b) -> a -> b
$ Theme -> String
D.activeColor Theme
t)
, exInactive :: SimpleStyle
exInactive = String
-> String -> String -> Dimension -> BorderColors -> SimpleStyle
SimpleStyle (Theme -> String
D.inactiveColor Theme
t) (Theme -> String
D.inactiveTextColor Theme
t) (Theme -> String
D.inactiveColor Theme
t) (Theme -> Dimension
D.inactiveBorderWidth Theme
t) (String -> BorderColors
borderColor (String -> BorderColors) -> String -> BorderColors
forall a b. (a -> b) -> a -> b
$ Theme -> String
D.inactiveColor Theme
t)
, exUrgent :: SimpleStyle
exUrgent = String
-> String -> String -> Dimension -> BorderColors -> SimpleStyle
SimpleStyle (Theme -> String
D.urgentColor Theme
t) (Theme -> String
D.urgentTextColor Theme
t) (Theme -> String
D.urgentColor Theme
t) (Theme -> Dimension
D.urgentBorderWidth Theme
t) (String -> BorderColors
borderColor (String -> BorderColors) -> String -> BorderColors
forall a b. (a -> b) -> a -> b
$ Theme -> String
D.urgentColor Theme
t)
, exPadding :: BoxBorders Dimension
exPadding = Dimension
-> Dimension -> Dimension -> Dimension -> BoxBorders Dimension
forall a. a -> a -> a -> a -> BoxBorders a
BoxBorders Dimension
0 Dimension
4 Dimension
0 Dimension
4
, exFontName :: String
exFontName = Theme -> String
D.fontName Theme
t
, exOnDecoClick :: Map Int (WidgetCommand widget)
exOnDecoClick = [(Int, WidgetCommand widget)] -> Map Int (WidgetCommand widget)
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [(Int
1, WidgetCommand widget
forall a. Default a => a
def)]
, exDragWindowButtons :: [Int]
exDragWindowButtons = [Int
1]
, exWidgetsLeft :: [widget]
exWidgetsLeft = []
, exWidgetsCenter :: [widget]
exWidgetsCenter = []
, exWidgetsRight :: [widget]
exWidgetsRight = []
}
instance Default (WidgetCommand widget) => Default (ThemeEx widget) where
def :: ThemeEx widget
def = Theme -> ThemeEx widget
forall widget.
Default (WidgetCommand widget) =>
Theme -> ThemeEx widget
themeEx (Theme
forall a. Default a => a
def :: D.Theme)
borderColor :: String -> BorderColors
borderColor :: String -> BorderColors
borderColor String
c = String -> String -> String -> String -> BorderColors
forall a. a -> a -> a -> a -> BoxBorders a
BoxBorders String
c String
c String
c String
c
shadowBorder :: String -> String -> BorderColors
shadowBorder :: String -> String -> BorderColors
shadowBorder String
highlight String
shadow = String -> String -> String -> String -> BorderColors
forall a. a -> a -> a -> a -> BoxBorders a
BoxBorders String
highlight String
shadow String
shadow String
highlight