summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorjao <jao@gnu.org>2022-09-09 03:03:08 +0100
committerjao <jao@gnu.org>2022-09-09 03:03:08 +0100
commitcf9c9d37707fb86e99f2402ccad33a1545706564 (patch)
treee5c2132f2cab43fae497357c12851fc21b0c5e0c
parentba24c0b31c2b0c5806909f3c982802a3b11c7586 (diff)
downloadxmobar-cf9c9d37707fb86e99f2402ccad33a1545706564.tar.gz
xmobar-cf9c9d37707fb86e99f2402ccad33a1545706564.tar.bz2
cairo: pure xlib/xft drawing code factored out
-rw-r--r--src/Xmobar/X11/Draw.hs232
-rw-r--r--src/Xmobar/X11/XlibDraw.hs234
2 files changed, 257 insertions, 209 deletions
diff --git a/src/Xmobar/X11/Draw.hs b/src/Xmobar/X11/Draw.hs
index aed9420..6890fb1 100644
--- a/src/Xmobar/X11/Draw.hs
+++ b/src/Xmobar/X11/Draw.hs
@@ -1,5 +1,4 @@
{-# LANGUAGE CPP #-}
-{-# LANGUAGE TupleSections #-}
------------------------------------------------------------------------------
-- |
@@ -20,224 +19,39 @@
module Xmobar.X11.Draw (drawInWin) where
-import Prelude hiding (lookup)
import Control.Monad.IO.Class
import Control.Monad.Reader
-import Control.Arrow ((&&&))
-import Data.Map hiding ((\\), foldr, map, filter)
-import Data.List ((\\))
-import qualified Data.List.NonEmpty as NE
-import Graphics.X11.Xlib hiding (textExtents, textWidth, Segment)
-import Graphics.X11.Xlib.Extras
+import Graphics.X11.Xlib hiding (Segment)
-import Xmobar.Config.Types
-import Xmobar.Run.Parsers hiding (parseString)
-import qualified Xmobar.X11.Bitmap as B
+import Xmobar.Run.Parsers (Segment)
import Xmobar.X11.Types
-import Xmobar.X11.Text
-import Xmobar.X11.ColorCache
-import Xmobar.X11.Window (drawBorder)
-import Xmobar.System.Utils (safeIndex)
-#ifdef XFT
-import Xmobar.X11.MinXft
-import Graphics.X11.Xrender
+#ifdef CAIRO
+import Xmobar.X11.CairoDraw
+#else
+import Xmobar.X11.XlibDraw
#endif
-fi :: (Integral a, Num b) => a -> b
-fi = fromIntegral
-
-- | Draws in and updates the window
drawInWin :: Rectangle -> [[Segment]] -> X ()
-drawInWin wr@(Rectangle _ _ wid ht) ~[left,center,right] = do
+drawInWin (Rectangle _ _ wid ht) segments = do
r <- ask
- let (c,d) = (config &&& display) r
- (w,(fs,vs)) = (window &&& fontListS &&& verticalOffsets) r
- strLn = liftIO . mapM getWidth
- iconW i = maybe 0 B.width (lookup i $ iconS r)
- getWidth (Text s,cl,i,_) =
- textWidth d (safeIndex fs i) s >>= \tw -> return (Text s,cl,i,fi tw)
- getWidth (Icon s,cl,i,_) = return (Icon s,cl,i,fi $ iconW s)
- getWidth (Hspace p,cl,i,_) = return (Hspace p,cl,i,fi p)
-
- p <- liftIO $ createPixmap d w wid ht
- (defaultDepthOfScreen (defaultScreenOfDisplay d))
-#if XFT
- when (alpha c /= 255) (liftIO $ drawBackground d p (bgColor c) (alpha c) wr)
+ let d = display r
+ w = window r
+ depth = defaultDepthOfScreen (defaultScreenOfDisplay d)
+ p <- liftIO $ createPixmap d w wid ht depth
+ gc <- liftIO $ createGC d w
+ liftIO $ setGraphicsExposures d gc False
+#ifdef CAIRO
+ drawInPixmap p wid ht segments
#else
- _ <- return wr
-#endif
- withColors d [bgColor c, borderColor c] $ \[bgcolor, bdcolor] -> do
- gc <- liftIO $ createGC d w
- liftIO $ setGraphicsExposures d gc False
-#if XFT
- when (alpha c == 255) $ do
-#else
- do
-#endif
- liftIO $ setForeground d gc bgcolor
- liftIO $ fillRectangle d p gc 0 0 wid ht
- -- write to the pixmap the new string
- printStrings p gc fs vs 1 L [] =<< strLn left
- printStrings p gc fs vs 1 R [] =<< strLn right
- printStrings p gc fs vs 1 C [] =<< strLn center
- -- draw border if requested
- liftIO $ drawBorder (border c) (borderWidth c) d p gc bdcolor wid ht
- -- copy the pixmap with the new string to the window
- liftIO $ copyArea d p w gc 0 0 wid ht 0 0
- -- free up everything (we do not want to leak memory!)
- liftIO $ freeGC d gc
- liftIO $ freePixmap d p
- -- resync (discard events, we don't read/process events from this display conn)
- liftIO $ sync d True
-
-verticalOffset :: (Integral b, Integral a, MonadIO m) =>
- a -> Widget -> XFont -> Int -> Config -> m b
-verticalOffset ht (Text t) fontst voffs _
- | voffs > -1 = return $ fi voffs
- | otherwise = do
- (as,ds) <- liftIO $ textExtents fontst t
- let margin = (fi ht - fi ds - fi as) `div` 2
- return $ fi as + margin - 1
-verticalOffset ht (Icon _) _ _ conf
- | iconOffset conf > -1 = return $ fi (iconOffset conf)
- | otherwise = return $ fi (ht `div` 2) - 1
-verticalOffset _ (Hspace _) _ voffs _ = return $ fi voffs
-
-printString :: Display
- -> Drawable
- -> XFont
- -> GC
- -> String
- -> String
- -> Position
- -> Position
- -> Position
- -> Position
- -> String
- -> Int
- -> IO ()
-printString d p (Core fs) gc fc bc x y _ _ s a = do
- setFont d gc $ fontFromFontStruct fs
- withColors d [fc, bc] $ \[fc', bc'] -> do
- setForeground d gc fc'
- when (a == 255) (setBackground d gc bc')
- drawImageString d p gc x y s
-
-printString d p (Utf8 fs) gc fc bc x y _ _ s a =
- withColors d [fc, bc] $ \[fc', bc'] -> do
- setForeground d gc fc'
- when (a == 255) (setBackground d gc bc')
- liftIO $ wcDrawImageString d p fs gc x y s
-
-#ifdef XFT
-printString dpy drw fs@(Xft fonts) _ fc bc x y ay ht s al =
- withDrawingColors dpy drw fc bc $ \draw fc' bc' -> do
- when (al == 255) $ do
- (a,d) <- textExtents fs s
- gi <- xftTxtExtents' dpy fonts s
- if ay < 0
- then drawXftRect draw bc' x (y - a) (1 + xglyphinfo_xOff gi) (a + d + 2)
- else drawXftRect draw bc' x ay (1 + xglyphinfo_xOff gi) ht
- drawXftString' draw fc' fonts (toInteger x) (toInteger y) s
+ drawInPixmap gc p wid ht segments
#endif
-
--- | An easy way to print the stuff we need to print
-printStrings :: Drawable
- -> GC
- -> NE.NonEmpty XFont
- -> NE.NonEmpty Int
- -> Position
- -> Align
- -> [((Position, Position), Box)]
- -> [(Widget, TextRenderInfo, Int, Position)] -> X ()
-printStrings _ _ _ _ _ _ _ [] = return ()
-printStrings dr gc fontlist voffs offs a boxes sl@((s,c,i,l):xs) = do
- r <- ask
- let (conf,d) = (config &&& display) r
- alph = alpha conf
- Rectangle _ _ wid ht = rect r
- totSLen = foldr (\(_,_,_,len) -> (+) len) 0 sl
- remWidth = fi wid - fi totSLen
- fontst = safeIndex fontlist i
- voff = safeIndex voffs i
- offset = case a of
- C -> (remWidth + offs) `div` 2
- R -> remWidth
- L -> offs
- (fc,bc) = colorComponents conf (tColorsString c)
- valign <- verticalOffset ht s fontst voff conf
- let (ht',ay) = case (tBgTopOffset c, tBgBottomOffset c) of
- (-1,_) -> (0, -1)
- (_,-1) -> (0, -1)
- (ot,ob) -> (fromIntegral ht - ot - ob, ob)
- case s of
- (Text t) -> liftIO $ printString d dr fontst gc fc bc offset valign ay ht' t alph
- (Icon p) -> liftIO $ maybe (return ())
- (B.drawBitmap d dr gc fc bc offset valign)
- (lookup p (iconS r))
- (Hspace _) -> liftIO $ return ()
- let triBoxes = tBoxes c
- dropBoxes = filter (\(_,b) -> b `notElem` triBoxes) boxes
- boxes' = map (\((x1,_),b) -> ((x1, offset + l), b))
- (filter (\(_,b) -> b `elem` triBoxes) boxes)
- ++ map ((offset, offset + l),) (triBoxes \\ map snd boxes)
- if Prelude.null xs
- then liftIO $ drawBoxes d dr gc (fromIntegral ht) (dropBoxes ++ boxes')
- else liftIO $ drawBoxes d dr gc (fromIntegral ht) dropBoxes
- printStrings dr gc fontlist voffs (offs + l) a boxes' xs
-
-drawBoxes :: Display
- -> Drawable
- -> GC
- -> Position
- -> [((Position, Position), Box)]
- -> IO ()
-drawBoxes _ _ _ _ [] = return ()
-drawBoxes d dr gc ht (b:bs) = do
- let (xx, Box bb offset lineWidth fc mgs) = b
- lw = fromIntegral lineWidth :: Position
- withColors d [fc] $ \[fc'] -> do
- setForeground d gc fc'
- setLineAttributes d gc lineWidth lineSolid capNotLast joinMiter
- case bb of
- BBVBoth -> do
- drawBoxBorder d dr gc BBTop offset ht xx lw mgs
- drawBoxBorder d dr gc BBBottom offset ht xx lw mgs
- BBHBoth -> do
- drawBoxBorder d dr gc BBLeft offset ht xx lw mgs
- drawBoxBorder d dr gc BBRight offset ht xx lw mgs
- BBFull -> do
- drawBoxBorder d dr gc BBTop offset ht xx lw mgs
- drawBoxBorder d dr gc BBBottom offset ht xx lw mgs
- drawBoxBorder d dr gc BBLeft offset ht xx lw mgs
- drawBoxBorder d dr gc BBRight offset ht xx lw mgs
- _ -> drawBoxBorder d dr gc bb offset ht xx lw mgs
- drawBoxes d dr gc ht bs
-
-drawBoxBorder :: Display
- -> Drawable
- -> GC
- -> BoxBorder
- -> BoxOffset
- -> Position
- -> (Position, Position)
- -> Position
- -> BoxMargins
- -> IO ()
-drawBoxBorder
- d dr gc pos (BoxOffset alg offset) ht (x1,x2) lw (BoxMargins mt mr mb ml) = do
- let (p1,p2) = case alg of
- L -> (0, -offset)
- C -> (offset, -offset)
- R -> (offset, 0 )
- lc = lw `div` 2
- case pos of
- BBTop -> drawLine d dr gc (x1 + p1) (mt + lc) (x2 + p2) (mt + lc)
- BBBottom -> do
- let lc' = max lc 1 + mb
- drawLine d dr gc (x1 + p1) (ht - lc') (x2 + p2) (ht - lc')
- BBLeft -> drawLine d dr gc (x1 - 1 + ml) p1 (x1 - 1 + ml) (ht + p2)
- BBRight -> drawLine d dr gc (x2 + lc - 1 - mr) p1 (x2 + lc - 1 - mr) (ht + p2)
- _ -> error "unreachable code"
+ -- copy the pixmap with the new string to the window
+ liftIO $ copyArea d p w gc 0 0 wid ht 0 0
+ -- free up everything (we do not want to leak memory!)
+ liftIO $ freeGC d gc
+ liftIO $ freePixmap d p
+ -- resync (discard events, we don't read/process events from this display conn)
+ liftIO $ sync d True
diff --git a/src/Xmobar/X11/XlibDraw.hs b/src/Xmobar/X11/XlibDraw.hs
new file mode 100644
index 0000000..3536791
--- /dev/null
+++ b/src/Xmobar/X11/XlibDraw.hs
@@ -0,0 +1,234 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE TupleSections #-}
+
+------------------------------------------------------------------------------
+-- |
+-- Module: Xmobar.X11.XlibDraw
+-- Copyright: (c) 2018, 2020, 2022 Jose Antonio Ortega Ruiz
+-- License: BSD3-style (see LICENSE)
+--
+-- Maintainer: jao@gnu.org
+-- Stability: unstable
+-- Portability: portable
+-- Created: Sat Nov 24, 2018 18:49
+--
+--
+-- Drawing the xmobar contents using Xlib and Xft primitives
+--
+------------------------------------------------------------------------------
+
+
+module Xmobar.X11.XlibDraw (drawInPixmap) where
+
+import Prelude hiding (lookup)
+import Control.Monad.IO.Class
+import Control.Monad.Reader
+import Data.Map hiding ((\\), foldr, map, filter)
+import Data.List ((\\))
+import qualified Data.List.NonEmpty as NE
+
+import Graphics.X11.Xlib hiding (textExtents, textWidth, Segment)
+import Graphics.X11.Xlib.Extras
+
+import Xmobar.Config.Types
+import Xmobar.Run.Parsers hiding (parseString)
+import qualified Xmobar.X11.Bitmap as B
+import Xmobar.X11.Types
+import Xmobar.X11.Text
+import Xmobar.X11.ColorCache
+import Xmobar.X11.Window (drawBorder)
+import Xmobar.System.Utils (safeIndex)
+
+#ifdef XFT
+import Xmobar.X11.MinXft
+import Graphics.X11.Xrender
+#endif
+
+fi :: (Integral a, Num b) => a -> b
+fi = fromIntegral
+
+drawInPixmap :: GC -> Pixmap -> Dimension -> Dimension -> [[Segment]] -> X()
+drawInPixmap gc p wid ht ~[left,center,right] = do
+ r <- ask
+ let c = config r
+ d = display r
+ fs = fontListS r
+ vs = verticalOffsets r
+ strLn = liftIO . mapM getWidth
+ iconW i = maybe 0 B.width (lookup i $ iconS r)
+ getWidth (Text s,cl,i,_) =
+ textWidth d (safeIndex fs i) s >>= \tw -> return (Text s,cl,i,fi tw)
+ getWidth (Icon s,cl,i,_) = return (Icon s,cl,i,fi $ iconW s)
+ getWidth (Hspace s,cl,i,_) = return (Hspace s,cl,i,fi s)
+
+#if XFT
+ when (alpha c /= 255)
+ (liftIO $ drawBackground d p (bgColor c) (alpha c) (Rectangle 0 0 wid ht))
+#endif
+
+ withColors d [bgColor c, borderColor c] $ \[bgcolor, bdcolor] -> do
+#if XFT
+ when (alpha c == 255) $ do
+ liftIO $ setForeground d gc bgcolor
+ liftIO $ fillRectangle d p gc 0 0 wid ht
+#else
+ liftIO $ setForeground d gc bgcolor
+ liftIO $ fillRectangle d p gc 0 0 wid ht
+#endif
+ -- write to the pixmap the new string
+ printStrings p gc fs vs 1 L [] =<< strLn left
+ printStrings p gc fs vs 1 R [] =<< strLn right
+ printStrings p gc fs vs 1 C [] =<< strLn center
+ -- draw border if requested
+ liftIO $ drawBorder (border c) (borderWidth c) d p gc bdcolor wid ht
+
+verticalOffset :: (Integral b, Integral a, MonadIO m) =>
+ a -> Widget -> XFont -> Int -> Config -> m b
+verticalOffset ht (Text t) fontst voffs _
+ | voffs > -1 = return $ fi voffs
+ | otherwise = do
+ (as,ds) <- liftIO $ textExtents fontst t
+ let margin = (fi ht - fi ds - fi as) `div` 2
+ return $ fi as + margin - 1
+verticalOffset ht (Icon _) _ _ conf
+ | iconOffset conf > -1 = return $ fi (iconOffset conf)
+ | otherwise = return $ fi (ht `div` 2) - 1
+verticalOffset _ (Hspace _) _ voffs _ = return $ fi voffs
+
+printString :: Display
+ -> Drawable
+ -> XFont
+ -> GC
+ -> String
+ -> String
+ -> Position
+ -> Position
+ -> Position
+ -> Position
+ -> String
+ -> Int
+ -> IO ()
+printString d p (Core fs) gc fc bc x y _ _ s a = do
+ setFont d gc $ fontFromFontStruct fs
+ withColors d [fc, bc] $ \[fc', bc'] -> do
+ setForeground d gc fc'
+ when (a == 255) (setBackground d gc bc')
+ drawImageString d p gc x y s
+
+printString d p (Utf8 fs) gc fc bc x y _ _ s a =
+ withColors d [fc, bc] $ \[fc', bc'] -> do
+ setForeground d gc fc'
+ when (a == 255) (setBackground d gc bc')
+ liftIO $ wcDrawImageString d p fs gc x y s
+
+#ifdef XFT
+printString dpy drw fs@(Xft fonts) _ fc bc x y ay ht s al =
+ withDrawingColors dpy drw fc bc $ \draw fc' bc' -> do
+ when (al == 255) $ do
+ (a,d) <- textExtents fs s
+ gi <- xftTxtExtents' dpy fonts s
+ if ay < 0
+ then drawXftRect draw bc' x (y - a) (1 + xglyphinfo_xOff gi) (a + d + 2)
+ else drawXftRect draw bc' x ay (1 + xglyphinfo_xOff gi) ht
+ drawXftString' draw fc' fonts (toInteger x) (toInteger y) s
+#endif
+
+-- | An easy way to print the stuff we need to print
+printStrings :: Drawable
+ -> GC
+ -> NE.NonEmpty XFont
+ -> NE.NonEmpty Int
+ -> Position
+ -> Align
+ -> [((Position, Position), Box)]
+ -> [(Widget, TextRenderInfo, Int, Position)] -> X ()
+printStrings _ _ _ _ _ _ _ [] = return ()
+printStrings dr gc fontlist voffs offs a boxes sl@((s,c,i,l):xs) = do
+ r <- ask
+ let conf = config r
+ d = display r
+ alph = alpha conf
+ Rectangle _ _ wid ht = rect r
+ totSLen = foldr (\(_,_,_,len) -> (+) len) 0 sl
+ remWidth = fi wid - fi totSLen
+ fontst = safeIndex fontlist i
+ voff = safeIndex voffs i
+ offset = case a of
+ C -> (remWidth + offs) `div` 2
+ R -> remWidth
+ L -> offs
+ (fc,bc) = colorComponents conf (tColorsString c)
+ valign <- verticalOffset ht s fontst voff conf
+ let (ht',ay) = case (tBgTopOffset c, tBgBottomOffset c) of
+ (-1,_) -> (0, -1)
+ (_,-1) -> (0, -1)
+ (ot,ob) -> (fromIntegral ht - ot - ob, ob)
+ case s of
+ (Text t) -> liftIO $ printString d dr fontst gc fc bc offset valign ay ht' t alph
+ (Icon p) -> liftIO $ maybe (return ())
+ (B.drawBitmap d dr gc fc bc offset valign)
+ (lookup p (iconS r))
+ (Hspace _) -> liftIO $ return ()
+ let triBoxes = tBoxes c
+ dropBoxes = filter (\(_,b) -> b `notElem` triBoxes) boxes
+ boxes' = map (\((x1,_),b) -> ((x1, offset + l), b))
+ (filter (\(_,b) -> b `elem` triBoxes) boxes)
+ ++ map ((offset, offset + l),) (triBoxes \\ map snd boxes)
+ if Prelude.null xs
+ then liftIO $ drawBoxes d dr gc (fromIntegral ht) (dropBoxes ++ boxes')
+ else liftIO $ drawBoxes d dr gc (fromIntegral ht) dropBoxes
+ printStrings dr gc fontlist voffs (offs + l) a boxes' xs
+
+drawBoxes :: Display
+ -> Drawable
+ -> GC
+ -> Position
+ -> [((Position, Position), Box)]
+ -> IO ()
+drawBoxes _ _ _ _ [] = return ()
+drawBoxes d dr gc ht (b:bs) = do
+ let (xx, Box bb offset lineWidth fc mgs) = b
+ lw = fromIntegral lineWidth :: Position
+ withColors d [fc] $ \[fc'] -> do
+ setForeground d gc fc'
+ setLineAttributes d gc lineWidth lineSolid capNotLast joinMiter
+ case bb of
+ BBVBoth -> do
+ drawBoxBorder d dr gc BBTop offset ht xx lw mgs
+ drawBoxBorder d dr gc BBBottom offset ht xx lw mgs
+ BBHBoth -> do
+ drawBoxBorder d dr gc BBLeft offset ht xx lw mgs
+ drawBoxBorder d dr gc BBRight offset ht xx lw mgs
+ BBFull -> do
+ drawBoxBorder d dr gc BBTop offset ht xx lw mgs
+ drawBoxBorder d dr gc BBBottom offset ht xx lw mgs
+ drawBoxBorder d dr gc BBLeft offset ht xx lw mgs
+ drawBoxBorder d dr gc BBRight offset ht xx lw mgs
+ _ -> drawBoxBorder d dr gc bb offset ht xx lw mgs
+ drawBoxes d dr gc ht bs
+
+drawBoxBorder :: Display
+ -> Drawable
+ -> GC
+ -> BoxBorder
+ -> BoxOffset
+ -> Position
+ -> (Position, Position)
+ -> Position
+ -> BoxMargins
+ -> IO ()
+drawBoxBorder
+ d dr gc pos (BoxOffset alg offset) ht (x1,x2) lw (BoxMargins mt mr mb ml) = do
+ let (p1,p2) = case alg of
+ L -> (0, -offset)
+ C -> (offset, -offset)
+ R -> (offset, 0 )
+ lc = lw `div` 2
+ case pos of
+ BBTop -> drawLine d dr gc (x1 + p1) (mt + lc) (x2 + p2) (mt + lc)
+ BBBottom -> do
+ let lc' = max lc 1 + mb
+ drawLine d dr gc (x1 + p1) (ht - lc') (x2 + p2) (ht - lc')
+ BBLeft -> drawLine d dr gc (x1 - 1 + ml) p1 (x1 - 1 + ml) (ht + p2)
+ BBRight -> drawLine d dr gc (x2 + lc - 1 - mr) p1 (x2 + lc - 1 - mr) (ht + p2)
+ _ -> error "unreachable code"