From a98ac8fba46b8858959cee6062a49c9121f07fe9 Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Mon, 28 Nov 2011 02:09:41 -0500 Subject: Transparency and tint support. New configuration option 'alpha' which adjusts alpha transparency (0 is transparent, 255 is opaque). Signed-off-by: Edward Z. Yang --- readme.md | 4 +++ src/Config.hs | 2 ++ src/Main.hs | 5 ++- src/Parsers.hs | 3 +- src/XUtil.hsc | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/Xmobar.hs | 34 +++++++++++++++--- xmobar.cabal | 2 +- 7 files changed, 149 insertions(+), 13 deletions(-) diff --git a/readme.md b/readme.md index 62f5d2c..e3bdeff 100644 --- a/readme.md +++ b/readme.md @@ -207,6 +207,9 @@ Other configuration options: `fgColor` : Default font color. +`alpha` +: The transparency. 0 is transparent, 255 is opaque. + `position` : Top, TopP, TopW, TopSize, Bottom, BottomP, BottomW, BottomSize or Static (with x, y, width and height). @@ -324,6 +327,7 @@ xmobar --help): -f font name --font=font name The font name -B bg color --bgcolor=bg color The background color. Default black -F fg color --fgcolor=fg color The foreground color. Default grey + -a alpha --alpha=alpha The transparency: 0 is transparent, 255 is opaque -o --top Place xmobar at the top of the screen -b --bottom Place xmobar at the bottom of the screen -d --dock Try to start xmobar as a dock diff --git a/src/Config.hs b/src/Config.hs index 4f03d93..d785002 100644 --- a/src/Config.hs +++ b/src/Config.hs @@ -57,6 +57,7 @@ data Config = , position :: XPosition -- ^ Top Bottom or Static , border :: Border -- ^ NoBorder TopB BottomB or FullB , borderColor :: String -- ^ Border color + , alpha :: Int -- ^ Transparency from 0 (transparent) to 255 (opaque) , hideOnStart :: Bool -- ^ Hide (Unmap) the window on -- initialization , allDesktops :: Bool -- ^ Tell the WM to map to all desktops @@ -107,6 +108,7 @@ defaultConfig = Config { font = "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*" , bgColor = "#000000" , fgColor = "#BFBFBF" + , alpha = 0 , position = Top , border = NoBorder , borderColor = "#BFBFBF" diff --git a/src/Main.hs b/src/Main.hs index e90a158..f7a70ff 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -119,6 +119,7 @@ data Opts = Help | Font String | BgColor String | FgColor String + | Alpha String | T | B | D @@ -139,6 +140,8 @@ options = "The background color. Default black" , Option "F" ["fgcolor"] (ReqArg FgColor "fg color") "The foreground color. Default grey" + , Option "a" ["alpha"] (ReqArg Alpha "alpha") + "The transparency: 0 is transparent, 255 is opaque" , Option "o" ["top"] (NoArg T) "Place xmobar at the top of the screen" , Option "b" ["bottom"] (NoArg B) "Place xmobar at the bottom of the screen" @@ -195,6 +198,7 @@ doOpts conf (o:oo) = Font s -> doOpts' (conf {font = s}) BgColor s -> doOpts' (conf {bgColor = s}) FgColor s -> doOpts' (conf {fgColor = s}) + Alpha n -> doOpts' (conf {alpha = read n}) T -> doOpts' (conf {position = Top}) B -> doOpts' (conf {position = Bottom}) D -> doOpts' (conf {overrideRedirect = False}) @@ -215,4 +219,3 @@ doOpts conf (o:oo) = "specified with the -" ++ c:" option\n") readStr str = [x | (x,t) <- reads str, ("","") <- lex t] doOpts' opts = doOpts opts oo - diff --git a/src/Parsers.hs b/src/Parsers.hs index 919ce68..a5869ef 100644 --- a/src/Parsers.hs +++ b/src/Parsers.hs @@ -164,7 +164,7 @@ parseConfig = runParser parseConf fields "Config" . stripComments perms = permute $ Config <$?> pFont <|?> pBgColor <|?> pFgColor <|?> pPosition - <|?> pBorder <|?> pBdColor <|?> pHideOnStart <|?> pAllDesktops + <|?> pBorder <|?> pBdColor <|?> pAlpha <|?> pHideOnStart <|?> pAllDesktops <|?> pOverrideRedirect <|?> pLowerOnStart <|?> pPersistent <|?> pCommands <|?> pSepChar <|?> pAlignSep <|?> pTemplate @@ -182,6 +182,7 @@ parseConfig = runParser parseConf fields "Config" . stripComments pAlignSep = strField alignSep "alignSep" pTemplate = strField template "template" + pAlpha = readField alpha "alpha" pPosition = readField position "position" pHideOnStart = readField hideOnStart "hideOnStart" pLowerOnStart = readField lowerOnStart "lowerOnStart" diff --git a/src/XUtil.hsc b/src/XUtil.hsc index b1e885c..c3bca7c 100644 --- a/src/XUtil.hsc +++ b/src/XUtil.hsc @@ -26,6 +26,35 @@ module XUtil , hGetLineSafe , io , fi + , XRenderPictureAttributes(..) + , XRenderPictFormat(..) + , XRenderColor(..) -- reexport + , Picture + , xRenderFindStandardFormat + , xRenderCreatePicture + , xRenderFillRectangle + , xRenderComposite + , xRenderCreateSolidFill + , xRenderFreePicture + , withRenderPicture + , withRenderFill + , parseRenderColor + , pictOpMinimum + , pictOpClear + , pictOpSrc + , pictOpDst + , pictOpOver + , pictOpOverReverse + , pictOpIn + , pictOpInReverse + , pictOpOut + , pictOpOutReverse + , pictOpAtop + , pictOpAtopReverse + , pictOpXor + , pictOpAdd + , pictOpSaturate + , pictOpMaximum ) where import Control.Concurrent @@ -38,6 +67,7 @@ import Graphics.X11.Xlib.Extras import System.Mem.Weak ( addFinalizer ) import System.Posix.Types (Fd(..)) import System.IO +import Foreign.C #if defined XFT || defined UTF8 # if __GLASGOW_HASKELL__ < 612 @@ -157,13 +187,11 @@ printString d p (Core fs) gc fc bc x y s = do setFont d gc $ fontFromFontStruct fs withColors d [fc, bc] $ \[fc', bc'] -> do setForeground d gc fc' - setBackground d gc bc' drawImageString d p gc x y s printString d p (Utf8 fs) gc fc bc x y s = withColors d [fc, bc] $ \[fc', bc'] -> do setForeground d gc fc' - setBackground d gc bc' io $ wcDrawImageString d p fs gc x y s #ifdef XFT @@ -171,10 +199,6 @@ printString dpy drw fs@(Xft font) _ fc bc x y s = do (a,d) <- textExtents fs s gi <- xftTxtExtents dpy font s withDrawingColors dpy drw fc bc $ \draw -> \fc' -> \bc' -> - (drawXftRect draw bc' (x + 1 - fi (xglyphinfo_x gi)) - (y - (a + d) + 1) - (xglyphinfo_xOff gi) - (a + d)) >> (drawXftString draw fc' font x (y - 2) s) #endif @@ -220,3 +244,79 @@ setupLocale = withCString "" (setlocale $ #const LC_ALL) >> return () setupLocale :: IO () setupLocale = return () #endif + +-- More XRender nonsense +#include + +type Picture = XID +type PictOp = CInt + +foreign import ccall unsafe "X11/extensions/Xrender.h XRenderFillRectangle" + xRenderFillRectangle :: Display -> PictOp -> Picture -> Ptr XRenderColor -> CInt -> CInt -> CUInt -> CUInt -> IO () +foreign import ccall unsafe "X11/extensions/Xrender.h XRenderComposite" + xRenderComposite :: Display -> PictOp -> Picture -> Picture -> Picture -> CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> CUInt -> CUInt -> IO () +foreign import ccall unsafe "X11/extensions/Xrender.h XRenderCreateSolidFill" + xRenderCreateSolidFill :: Display -> Ptr XRenderColor -> IO Picture +foreign import ccall unsafe "X11/extensions/Xrender.h XRenderFreePicture" + xRenderFreePicture :: Display -> Picture -> IO () +foreign import ccall unsafe "string.h" memset :: Ptr a -> CInt -> CSize -> IO () +foreign import ccall unsafe "X11/extensions/Xrender.h XRenderFindStandardFormat" + xRenderFindStandardFormat :: Display -> CInt -> IO (Ptr XRenderPictFormat) +foreign import ccall unsafe "X11/extensions/Xrender.h XRenderCreatePicture" + xRenderCreatePicture :: Display -> Drawable -> Ptr XRenderPictFormat -> CULong -> Ptr XRenderPictureAttributes -> IO Picture + +data XRenderPictFormat = XRenderPictFormat +data XRenderPictureAttributes = XRenderPictureAttributes + +-- Attributes not supported +instance Storable XRenderPictureAttributes where + sizeOf _ = #{size XRenderPictureAttributes} + alignment _ = alignment (undefined :: CInt) + peek _ = return XRenderPictureAttributes + poke p XRenderPictureAttributes = do + memset p 0 #{size XRenderPictureAttributes} + +-- | Convenience function, gives us an XRender handle to a traditional +-- Pixmap. Don't let it escape. +withRenderPicture :: Display -> Drawable -> (Picture -> IO a) -> IO () +withRenderPicture d p f = do + format <- xRenderFindStandardFormat d 1 -- PictStandardRGB24 + alloca $ \attr -> do + pic <- xRenderCreatePicture d p format 0 attr + f pic + xRenderFreePicture d pic + +-- | Convenience function, gives us an XRender picture that is a solid +-- fill of color 'c'. Don't let it escape. +withRenderFill :: Display -> XRenderColor -> (Picture -> IO a) -> IO () +withRenderFill d c f = do + pic <- with c (xRenderCreateSolidFill d) + f pic + xRenderFreePicture d pic + +-- | Parses color into XRender color (allocation not necessary!) +parseRenderColor :: Display -> String -> IO XRenderColor +parseRenderColor d c = do + let colormap = defaultColormap d (defaultScreen d) + Color _ red green blue _ <- parseColor d colormap c + return $ XRenderColor (fromIntegral red) (fromIntegral green) (fromIntegral blue) 0xFFFF + +pictOpMinimum, pictOpClear, pictOpSrc, pictOpDst, pictOpOver, pictOpOverReverse, + pictOpIn, pictOpInReverse, pictOpOut, pictOpOutReverse, pictOpAtop, + pictOpAtopReverse, pictOpXor, pictOpAdd, pictOpSaturate, pictOpMaximum :: PictOp +pictOpMinimum = 0 +pictOpClear = 0 +pictOpSrc = 1 +pictOpDst = 2 +pictOpOver = 3 +pictOpOverReverse = 4 +pictOpIn = 5 +pictOpInReverse = 6 +pictOpOut = 7 +pictOpOutReverse = 8 +pictOpAtop = 9 +pictOpAtopReverse = 10 +pictOpXor = 11 +pictOpAdd = 12 +pictOpSaturate = 13 +pictOpMaximum = 13 diff --git a/src/Xmobar.hs b/src/Xmobar.hs index 3cff475..823b594 100644 --- a/src/Xmobar.hs +++ b/src/Xmobar.hs @@ -43,6 +43,9 @@ import Control.Exception (handle, SomeException(..)) import Data.Bits import Data.Map hiding (foldr, map, filter) import Data.Maybe (fromJust) +import Foreign.Marshal.Alloc +import Foreign.Storable +import Foreign.Ptr import Bitmap import Config @@ -276,14 +279,37 @@ drawInWin (Rectangle _ _ wid ht) ~[left,center,right] = do getWidth (Text s,cl,_) = textWidth d fs s >>= \tw -> return (Text s,cl,fi tw) getWidth (Icon s,cl,_) = return (Icon s,cl,fi $ iconW s) - withColors d [bgColor c, borderColor c] $ \[bgcolor, bdcolor] -> do + withColors d [borderColor c] $ \[bdcolor] -> do gc <- io $ createGC d w -- create a pixmap to write to and fill it with a rectangle p <- io $ createPixmap d w wid ht (defaultDepthOfScreen (defaultScreenOfDisplay d)) - -- the fgcolor of the rectangle will be the bgcolor of the window - io $ setForeground d gc bgcolor - io $ fillRectangle d p gc 0 0 wid ht + io $ withRenderPicture d p $ \pic -> do + -- Handle background color + bgcolor <- parseRenderColor d (bgColor c) + withRenderFill d bgcolor $ \bgfill -> + -- I apparently don't know how to do this properly with + -- just bgcolor' (putting in the mask alpha directly has strange + -- results. I wish someone had better docs on how + -- XRenderComposite worked...) + withRenderFill d (XRenderColor 0 0 0 (257 * alpha c)) $ \m -> + xRenderComposite d pictOpSrc bgfill m pic 0 0 0 0 0 0 (fromIntegral wid) (fromIntegral ht) + -- Handle transparency + internAtom d "_XROOTPMAP_ID" False >>= \xid -> + let xroot = defaultRootWindow d in + alloca $ \x1 -> + alloca $ \x2 -> + alloca $ \x3 -> + alloca $ \x4 -> + alloca $ \pprop -> do + xGetWindowProperty d xroot xid 0 1 False 20 x1 x2 x3 x4 pprop + prop <- peek pprop + when (prop /= nullPtr) $ do + rootbg <- peek (castPtr prop) :: IO Pixmap + xFree prop + withRenderPicture d rootbg $ \bgpic -> + withRenderFill d (XRenderColor 0 0 0 (0xFFFF - 257 * alpha c)) $ \m -> + xRenderComposite d pictOpAdd bgpic m pic 0 0 0 0 0 0 (fromIntegral wid) (fromIntegral ht) -- write to the pixmap the new string printStrings p gc fs 1 L =<< strLn left printStrings p gc fs 1 R =<< strLn right diff --git a/xmobar.cabal b/xmobar.cabal index 2ba7e57..1921b4d 100644 --- a/xmobar.cabal +++ b/xmobar.cabal @@ -92,7 +92,7 @@ executable xmobar ghc-prof-options: -prof -auto-all ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind - extra-libraries: Xrandr + extra-libraries: Xrandr Xrender build-depends: base == 4.*, -- cgit v1.2.3