mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-05-19 03:20:21 -07:00
* First version of DecorationEx. * Fixed most warnings. * Fix build error with ghc-9.8.1. * Fix title shrinking with text decoration. * Add convinience re-exports. * Get rid of orphan instances. * Fix a couple of warnings. * Rename X.L.DecorationEx.Types -> X.L.DecorationEx.Common * Add instance Default StandardCommand. * Fix some typos and formatting thanks to @geekosaur Co-authored-by: brandon s allbery kf8nh <allbery.b@gmail.com> * Fix reference to xmonad.hs See also #859 Co-authored-by: brandon s allbery kf8nh <allbery.b@gmail.com> * Fix reference to xmonad.hs Co-authored-by: brandon s allbery kf8nh <allbery.b@gmail.com> * Fix formatting Co-authored-by: brandon s allbery kf8nh <allbery.b@gmail.com> * Fix some typos and formatting thanks to @geekosaur Co-authored-by: brandon s allbery kf8nh <allbery.b@gmail.com> * Remove commented code. * Update CHANGES.md. * calcWidgetPlace is now allowed to return rectangle with any X, but that will be ignored. * More generic instance for DecorationWidget GenericWidget. * Replace explicit definition of `fi` with import from X.Prelude. thanks to @slotThe. * Move fetch-all pattern to the end of definition. thanks to @slotThe. * X.L.DecorationEx: Add screenshot --------- Co-authored-by: brandon s allbery kf8nh <allbery.b@gmail.com> Co-authored-by: Tony Zorman <soliditsallgood@mailbox.org>
273 lines
11 KiB
Haskell
273 lines
11 KiB
Haskell
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
{-# LANGUAGE TypeFamilies #-}
|
|
{-# LANGUAGE StandaloneDeriving #-}
|
|
{-# LANGUAGE UndecidableInstances #-}
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- |
|
|
-- Module : XMonad.Layout.DecorationEx.Common
|
|
-- Description : Declaration of types used by DecorationEx module,
|
|
-- and commonly used utility functions.
|
|
-- Copyright : (c) 2007 Andrea Rossato, 2009 Jan Vornberger, 2023 Ilya Portnov
|
|
-- License : BSD-style (see xmonad/LICENSE)
|
|
--
|
|
-- Maintainer : portnov84@rambler.ru
|
|
-- Stability : unstable
|
|
-- Portability : unportable
|
|
--
|
|
-- This module exposes a number of types which are used by other sub-modules
|
|
-- of "XMonad.Layout.DecorationEx" module.
|
|
-----------------------------------------------------------------------------
|
|
|
|
module XMonad.Layout.DecorationEx.Common (
|
|
-- * Common types
|
|
WindowDecoration (..)
|
|
, WindowCommand (..)
|
|
, DecorationWidget (..)
|
|
, WidgetPlace (..)
|
|
, WidgetLayout (..)
|
|
, HasWidgets (..)
|
|
, ClickHandler (..)
|
|
, ThemeAttributes (..)
|
|
, XPaintingContext
|
|
, BoxBorders (..)
|
|
, BorderColors
|
|
, ThemeStyleType (..)
|
|
, SimpleStyle (..)
|
|
, GenericTheme (..)
|
|
, ThemeEx
|
|
-- * Utilities
|
|
, 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
|
|
|
|
-- | Information about decoration of one window
|
|
data WindowDecoration = WindowDecoration {
|
|
wdOrigWindow :: !Window -- ^ Original window (one being decorated)
|
|
, wdOrigWinRect :: !Rectangle -- ^ Rectangle of original window
|
|
, wdDecoWindow :: !(Maybe Window) -- ^ Decoration window, or Nothing if this window should not be decorated
|
|
, wdDecoRect :: !(Maybe Rectangle) -- ^ Rectangle for decoration window
|
|
, wdWidgets :: ![WidgetPlace] -- ^ Places for widgets
|
|
}
|
|
|
|
-- | Type class for window commands (such as maximize or close window)
|
|
class (Read cmd, Show cmd) => WindowCommand cmd where
|
|
-- | Execute the command
|
|
executeWindowCommand :: cmd -> Window -> X Bool
|
|
|
|
-- | Is the command currently in `checked' state.
|
|
-- For example, for 'sticky' command, check if the
|
|
-- window is currently sticky.
|
|
isCommandChecked :: cmd -> Window -> X Bool
|
|
|
|
-- | Type class for decoration widgets
|
|
class (WindowCommand (WidgetCommand widget), Read widget, Show widget)
|
|
=> DecorationWidget widget where
|
|
-- | Type of window commands which this type of widgets can execute
|
|
type WidgetCommand widget
|
|
|
|
-- | Get window command which is associated with this widget.
|
|
widgetCommand :: widget -> Int -> WidgetCommand widget
|
|
|
|
-- | Check if the widget is shrinkable, i.e. if it's width
|
|
-- can be reduced if there is not enough place in the decoration.
|
|
isShrinkable :: widget -> Bool
|
|
|
|
-- | Layout of widgets
|
|
data WidgetLayout a = WidgetLayout {
|
|
wlLeft :: ![a] -- ^ Widgets that should be aligned to the left side of decoration
|
|
, wlCenter :: ![a] -- ^ Widgets that should be in the center of decoration
|
|
, wlRight :: ![a] -- ^ Widgets taht should be aligned to the right side of decoration
|
|
}
|
|
|
|
-- | Data type describing where the decoration widget (e.g. window button)
|
|
-- should be placed.
|
|
-- All coordinates are relative to decoration rectangle.
|
|
data WidgetPlace = WidgetPlace {
|
|
wpTextYPosition :: !Position -- ^ Y position of text base line
|
|
-- (for widgets like window title or text-based buttons)
|
|
, wpRectangle :: !Rectangle -- ^ Rectangle where to place the widget
|
|
}
|
|
deriving (Show)
|
|
|
|
-- | Generic data type which is used to
|
|
-- describe characteristics of rectangle borders.
|
|
data BoxBorders a = BoxBorders {
|
|
bxTop :: !a
|
|
, bxRight :: !a
|
|
, bxBottom :: !a
|
|
, bxLeft :: !a
|
|
} deriving (Eq, Read, Show)
|
|
|
|
-- | Convinience data type describing colors of decoration rectangle borders.
|
|
type BorderColors = BoxBorders String
|
|
|
|
-- | Data type describing look of window decoration
|
|
-- in particular state (active or inactive)
|
|
data SimpleStyle = SimpleStyle {
|
|
sBgColor :: !String -- ^ Decoration background color
|
|
, sTextColor :: !String -- ^ Text (foreground) color
|
|
, sTextBgColor :: !String -- ^ Text background color
|
|
, sDecoBorderWidth :: !Dimension -- ^ Width of border of decoration rectangle. Set to 0 to disable the border.
|
|
, sDecorationBorders :: !BorderColors -- ^ Colors of borders of decoration rectangle.
|
|
}
|
|
deriving (Show, Read)
|
|
|
|
-- | Type class for themes, which claims that
|
|
-- the theme contains the list of widgets and their alignments.
|
|
class HasWidgets theme widget where
|
|
themeWidgets :: theme widget -> WidgetLayout widget
|
|
|
|
-- | Type class for themes, which claims that
|
|
-- the theme can describe how the decoration should respond
|
|
-- to clicks on decoration itself (between widgets).
|
|
class ClickHandler theme widget where
|
|
-- | This is called when the user clicks on the decoration rectangle
|
|
-- (not on one of widgets).
|
|
onDecorationClick :: theme widget
|
|
-> Int -- ^ Mouse button number
|
|
-> Maybe (WidgetCommand widget)
|
|
|
|
-- | Determine if it is possible to drag window by it's decoration
|
|
-- with mouse button.
|
|
isDraggingEnabled :: theme widget
|
|
-> Int -- ^ Mouse button number
|
|
-> Bool
|
|
|
|
-- | Type class for themes, which claims that the theme
|
|
-- is responsible for determining looks of decoration.
|
|
class (Read theme, Show theme) => ThemeAttributes theme where
|
|
-- | Type which describes looks of decoration in one
|
|
-- of window states (active, inactive, urgent, etc).
|
|
type Style theme
|
|
|
|
-- | Select style based on window state.
|
|
selectWindowStyle :: theme -> Window -> X (Style theme)
|
|
|
|
-- | Define padding between decoration rectangle and widgets.
|
|
widgetsPadding :: theme -> BoxBorders Dimension
|
|
|
|
-- | Initial background color of decoration rectangle.
|
|
-- When decoration widget is created, it is initially filled
|
|
-- with this color.
|
|
defaultBgColor :: theme -> String
|
|
|
|
-- | Font name defined in the theme.
|
|
themeFontName :: theme -> String
|
|
|
|
-- | Generic Theme data type. This is used
|
|
-- by @TextEngine@ and can be used by other relatively
|
|
-- simple decoration engines.
|
|
data GenericTheme style widget = GenericTheme {
|
|
exActive :: !style -- ^ Decoration style for active (focused) windows
|
|
, exInactive :: !style -- ^ Decoration style for inactive (unfocused) windows
|
|
, exUrgent :: !style -- ^ Decoration style for urgent windows
|
|
, exPadding :: !(BoxBorders Dimension) -- ^ Padding between decoration rectangle and widgets
|
|
, exFontName :: !String -- ^ Font name
|
|
, exOnDecoClick :: !(M.Map Int (WidgetCommand widget)) -- ^ Correspondence between mouse button number and window command.
|
|
, exDragWindowButtons :: ![Int] -- ^ For which mouse buttons dragging is enabled
|
|
, exWidgetsLeft :: ![widget] -- ^ Widgets that should appear at the left of decoration rectangle (listed left to right)
|
|
, exWidgetsCenter :: ![widget] -- ^ Widgets that should appear in the center of decoration rectangle (listed left to right)
|
|
, exWidgetsRight :: ![widget] -- ^ Widgets that should appear at the right of decoration rectangle (listed left to right)
|
|
}
|
|
|
|
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)
|
|
|
|
-- | Convience type for themes used by @TextDecoration@.
|
|
type ThemeEx widget = GenericTheme SimpleStyle widget
|
|
|
|
instance HasWidgets (GenericTheme style) widget where
|
|
themeWidgets theme = WidgetLayout (exWidgetsLeft theme) (exWidgetsCenter theme) (exWidgetsRight theme)
|
|
|
|
-- | Supported states of windows (on which looks of decorations can depend).
|
|
data ThemeStyleType = ActiveWindow | UrgentWindow | InactiveWindow
|
|
deriving (Eq, Show, Read)
|
|
|
|
-- | Utility function to convert WidgetLayout to plain list of widgets.
|
|
widgetLayout :: WidgetLayout widget -> [widget]
|
|
widgetLayout ws = wlLeft ws ++ wlCenter ws ++ wlRight ws
|
|
|
|
-- | Painting context for decoration engines based on plain X11 calls.
|
|
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 theme w = genericWindowStyle w theme
|
|
defaultBgColor t = sBgColor $ exInactive t
|
|
widgetsPadding = exPadding
|
|
themeFontName = exFontName
|
|
|
|
instance ClickHandler (GenericTheme SimpleStyle) widget where
|
|
onDecorationClick theme button = M.lookup button (exOnDecoClick theme)
|
|
isDraggingEnabled theme button = button `elem` exDragWindowButtons theme
|
|
|
|
-- | Generic utility function to select style from @GenericTheme@
|
|
-- based on current state of the window.
|
|
genericWindowStyle :: Window -> GenericTheme style widget -> X style
|
|
genericWindowStyle win theme = do
|
|
styleType <- windowStyleType win
|
|
return $ case styleType of
|
|
ActiveWindow -> exActive theme
|
|
InactiveWindow -> exInactive theme
|
|
UrgentWindow -> exUrgent theme
|
|
|
|
-- | Detect type of style to be used from current state of the window.
|
|
windowStyleType :: Window -> X ThemeStyleType
|
|
windowStyleType win = do
|
|
mbFocused <- W.peek <$> gets windowset
|
|
isWmStateUrgent <- (win `elem`) <$> readUrgents
|
|
isUrgencyBitSet <- withDisplay $ \dpy -> do
|
|
hints <- io $ getWMHints dpy win
|
|
return $ wmh_flags hints `testBit` urgencyHintBit
|
|
if isWmStateUrgent || isUrgencyBitSet
|
|
then return UrgentWindow
|
|
else return $
|
|
case mbFocused of
|
|
Nothing -> InactiveWindow
|
|
Just focused
|
|
| focused == win -> ActiveWindow
|
|
| otherwise -> InactiveWindow
|
|
|
|
-- | Convert Theme type from "XMonad.Layout.Decoration" to
|
|
-- theme type used by "XMonad.Layout.DecorationEx.TextEngine".
|
|
themeEx :: Default (WidgetCommand widget) => D.Theme -> ThemeEx widget
|
|
themeEx t =
|
|
GenericTheme {
|
|
exActive = SimpleStyle (D.activeColor t) (D.activeTextColor t) (D.activeColor t) (D.activeBorderWidth t) (borderColor $ D.activeColor t)
|
|
, exInactive = SimpleStyle (D.inactiveColor t) (D.inactiveTextColor t) (D.inactiveColor t) (D.inactiveBorderWidth t) (borderColor $ D.inactiveColor t)
|
|
, exUrgent = SimpleStyle (D.urgentColor t) (D.urgentTextColor t) (D.urgentColor t) (D.urgentBorderWidth t) (borderColor $ D.urgentColor t)
|
|
, exPadding = BoxBorders 0 4 0 4
|
|
, exFontName = D.fontName t
|
|
, exOnDecoClick = M.fromList [(1, def)]
|
|
, exDragWindowButtons = [1]
|
|
, exWidgetsLeft = []
|
|
, exWidgetsCenter = []
|
|
, exWidgetsRight = []
|
|
}
|
|
|
|
instance Default (WidgetCommand widget) => Default (ThemeEx widget) where
|
|
def = themeEx (def :: D.Theme)
|
|
|
|
borderColor :: String -> BorderColors
|
|
borderColor c = BoxBorders c c c c
|
|
|
|
shadowBorder :: String -> String -> BorderColors
|
|
shadowBorder highlight shadow = BoxBorders highlight shadow shadow highlight
|
|
|