diff options
| -rw-r--r-- | Main.hs | 18 | ||||
| -rw-r--r-- | Xmobar.hs | 176 | 
2 files changed, 92 insertions, 102 deletions
| @@ -36,16 +36,16 @@ main :: IO ()  main =       do args     <- getArgs         (o,file) <- getOpts args -       conf     <- case file of +       c        <- case file of                       [cfgfile] -> readConfig cfgfile                       _         -> readDefaultConfig -       c        <- newIORef conf -       doOpts c o -       config   <- readIORef c -       cl       <- parseTemplate config (template config) +       civ      <- newIORef c +       doOpts civ o +       conf     <- readIORef civ +       cl       <- parseTemplate conf (template conf)         vars     <- mapM startCommand cl -       (d,w)    <- createWin config -       eventLoop config vars d w +       (d,w)    <- createWin conf +       eventLoop conf vars d w         return ()  -- | Reads the configuration files or quits with an error @@ -54,9 +54,9 @@ readConfig f =      do file <- fileExist f         s    <- if file then readFile f else error $ f ++ ": file not found!\n" ++ usage         case reads s of -         [(config,_)] -> return config +         [(conf,_)] -> return conf           [] -> error $ f ++ ": configuration file contains errors!\n" ++ usage -         _ -> error ("Some problem occured. Aborting...") +         _  -> error ("Some problem occured. Aborting...")  -- | Read default configuration file or load the default config  readDefaultConfig :: IO Config @@ -15,24 +15,22 @@  module Xmobar (-- * Main Stuff                 -- $main -               Xbar -              , runXbar +               X, XConf (..), runX                , eventLoop -              , createWin -              , updateWin -              -- * Printing -              -- $print -              , drawInWin -              , printStrings                -- * Program Execution -              -- $commands +              -- $command                , startCommand +              -- * Window Management +              -- $window +              , createWin, updateWin +              -- * Printing +              -- $print +              , drawInWin, printStrings                -- * Unmamaged Windows                -- $unmanwin                , mkUnmanagedWindow                -- * Useful Utilities -              , initColor -              , io +              , initColor, io, nextEvent', fi                ) where  import Prelude hiding (catch) @@ -40,7 +38,7 @@ import Graphics.X11.Xlib  import Graphics.X11.Xlib.Misc  import Graphics.X11.Xlib.Event -import Control.Monad.State +import Control.Arrow ((&&&))  import Control.Monad.Reader  import Control.Concurrent  import Control.Concurrent.STM @@ -56,32 +54,29 @@ import Runnable  --  -- The Xmobar data type and basic loops and functions. --- | This is copied from XMonad. -newtype Xbar a = X (ReaderT Config (StateT XState IO) a) -    deriving (Functor, Monad, MonadIO, MonadState XState, MonadReader Config) +-- | The X type is a ReaderT +type X = ReaderT XConf IO --- | The State component of StateT -data XState =  -    XState { display :: Display -           , window  :: Window -           } +-- | The ReaderT inner component +data XConf = +    XConf { display :: Display +          , window  :: Window +          , config  :: Config +         } --- | We use get to get the state and ask to get the configuration: whis way  --- functions requires less arguments. -runXbar :: Config -> Display -> Window -> Xbar () -> IO () -runXbar c d w (X f) =  -    do runStateT (runReaderT f c) (XState d w) -       return () +-- | Runs the ReaderT +runX :: Config -> Display -> Window -> X () -> IO () +runX c d w f = runReaderT f (XConf d w c)  -- | The event loop  eventLoop :: Config -> [(Maybe ThreadId, TVar String)] -> Display -> Window -> IO ()  eventLoop c v d w = do      tv <- atomically $ newTVar [] -    t    <- forkIO (block $ go tv) -    timer t tv +    t  <- forkIO (block $ go tv) +    checker t tv   where      -- interrupt the drawing thread every time a var is updated -    timer t tvar = do +    checker t tvar = do        nval <- atomically $ do                ov <- readTVar tvar                nv <- mapM readTVar (map snd v) @@ -89,21 +84,14 @@ eventLoop c v d w = do        atomically $ writeTVar tvar nval        threadDelay 1000        throwTo t (ErrorCall "Xmobar.eventLoop: yield") -      timer t tvar +      checker t tvar      -- Continuously wait for a timer interrupt or an expose event      go tvar = do -      runXbar c d w (updateWin tvar) +      runX c d w (updateWin tvar)        catch (unblock $ allocaXEvent $ nextEvent' d) (const $ return ())        go tvar -updateWin :: TVar String -> Xbar () -updateWin v = -    do i  <- io $ atomically $ readTVar v -       c  <- ask -       ps <- io $ parseString c i -       drawInWin ps - --- $commands  +-- $command  -- | Runs a command as an independent thread and returns its thread id  -- and the TVar the command will be writing to. @@ -118,88 +106,91 @@ startCommand (com,s,ss)                              return (Just h,var)      where is = "Updating... " +-- $window +  -- | The function to create the initial window  createWin :: Config -> IO (Display, Window) -createWin config = +createWin conf =    do dpy   <- openDisplay ""       let dflt = defaultScreen dpy       rootw <- rootWindow dpy dflt       win   <- mkUnmanagedWindow dpy (defaultScreenOfDisplay dpy) rootw  -            (fi $ xPos   config)  -            (fi $ yPos   config)  -            (fi $ width  config)  -            (fi $ height config) +            (fi $ xPos   conf)  +            (fi $ yPos   conf)  +            (fi $ width  conf)  +            (fi $ height conf)       selectInput dpy win exposureMask       mapWindow   dpy win -     return (dpy,win) +     return     (dpy,win) + +updateWin :: TVar String -> X () +updateWin v = +    do c  <- asks config +       i  <- io $ atomically $ readTVar v +       ps <- io $ parseString c i +       drawInWin ps  -- $print  -- | Draws in and updates the window -drawInWin :: [(String, String)] -> Xbar () +drawInWin :: [(String, String)] -> X ()  drawInWin str =  -    do config  <- ask -       st      <- get -       let (dpy,win) = (display st, window st) -       bgcolor <- io $ initColor dpy $ bgColor config -       gc      <- io $ createGC dpy win +    do r <- ask +       let (conf,(d,w)) = (config &&& display &&& window) r +       bgcolor <- io $ initColor d $ bgColor conf +       gc      <- io $ createGC  d w         --let's get the fonts -       let lf c = loadQueryFont dpy (font c) -       fontst  <- io $ catch (lf config) (const $ lf defaultConfig) -       io $ setFont dpy gc (fontFromFontStruct fontst) +       let lf c = loadQueryFont d (font c) +       fontst  <- io $ catch (lf conf) (const $ lf defaultConfig) +       io $ setFont d gc (fontFromFontStruct fontst)         -- create a pixmap to write to and fill it with a rectangle -       p       <- io $ createPixmap dpy win  -                         (fi (width  config))  -                         (fi (height config))  -                         (defaultDepthOfScreen (defaultScreenOfDisplay dpy)) +       p <- io $ createPixmap d w  +                 (fi (width  conf))  +                 (fi (height conf))  +                 (defaultDepthOfScreen (defaultScreenOfDisplay d))         -- the fgcolor of the rectangle will be the bgcolor of the window -       io $ setForeground dpy gc bgcolor -       io $ fillRectangle dpy p gc 0 0  -              (fi $ width  config)  -              (fi $ height config) +       io $ setForeground d gc bgcolor +       io $ fillRectangle d p gc 0 0  +              (fi $ width  conf)  +              (fi $ height conf)         -- write to the pixmap the new string         let strWithLenth = map (\(s,c) -> (s,c,textWidth fontst s)) str         printStrings p gc fontst 1 strWithLenth          -- copy the pixmap with the new string to the window -       io $ copyArea dpy p win gc 0 0 (fi (width config)) (fi (height config)) 0 0 +       io $ copyArea   d p w gc 0 0 (fi (width conf)) (fi (height conf)) 0 0         -- free up everything (we do not want to leak memory!) -       io $ freeFont   dpy fontst -       io $ freeGC     dpy gc -       io $ freePixmap dpy p +       io $ freeFont   d fontst +       io $ freeGC     d gc +       io $ freePixmap d p         -- resync -       io $ sync dpy True +       io $ sync d True  -- | An easy way to print the stuff we need to print -printStrings :: Drawable  -             -> GC -             -> FontStruct -             -> Position -             -> [(String, String, Position)] -             -> Xbar () +printStrings :: Drawable -> GC -> FontStruct -> Position +             -> [(String, String, Position)] -> X ()  printStrings _ _ _ _ [] = return () -printStrings d gc fontst offs sl@((s,c,l):xs) = -    do config <- ask -       st     <- get -       let (_,asc,_,_) = textExtents fontst s +printStrings dr gc fontst offs sl@((s,c,l):xs) = +    do r <- ask +       let (conf,d)    = (config &&& display) r +           (_,asc,_,_) = textExtents fontst s             totSLen     = foldr (\(_,_,len) -> (+) len) 0 sl -           valign      = (fi (height config) + fi asc) `div` 2 -           remWidth    = fi (width config) - fi totSLen -           offset      = case (align config) of +           valign      = (fi (height conf) + fi asc) `div` 2 +           remWidth    = fi (width conf) - fi totSLen +           offset      = case (align conf) of                             "center" -> (remWidth + offs) `div` 2                             "right"  -> remWidth - 1                             "left"   -> offs                             _        -> offs -       fgcolor <- io $ initColor (display st) c -       bgcolor <- io $ initColor (display st) (bgColor config) -       io $ setForeground (display st) gc fgcolor -       io $ setBackground (display st) gc bgcolor -       io $ drawImageString (display st) d gc offset valign s -       printStrings d gc fontst (offs + l) xs +       fgcolor <- io $ initColor d c +       bgcolor <- io $ initColor d (bgColor conf) +       io $ setForeground d gc fgcolor +       io $ setBackground d gc bgcolor +       io $ drawImageString d dr gc offset valign s +       printStrings dr gc fontst (offs + l) xs  {- $unmanwin -This is a way to create unmamaged window. It was a mistery in Haskell.  -Till I've found out...;-) +This is a way to create unmamaged window.  -} @@ -214,17 +205,16 @@ mkUnmanagedWindow :: Display                    -> Dimension                    -> IO Window  mkUnmanagedWindow dpy scr rw x y w h = do -  let visual = defaultVisualOfScreen scr +  let visual   = defaultVisualOfScreen scr        attrmask = cWOverrideRedirect -  win <- allocaSetWindowAttributes $  +  allocaSetWindowAttributes $            \attributes -> do             set_override_redirect attributes True             createWindow dpy rw x y w h 0 (defaultDepthOfScreen scr)                           inputOutput visual attrmask attributes                                 -  return win  {- $utility -Utilities, aka stollen without givin' credit stuff. +Utilities  -}  -- | Get the Pixel value for a named color: if an invalid name is @@ -250,7 +240,7 @@ nextEvent' d p = do      fd = connectionNumber d  -- | Short-hand for lifting in the IO monad -io :: IO a -> Xbar a +io :: IO a -> X a  io = liftIO  -- | Short-hand for 'fromIntegral' | 
