diff options
| -rw-r--r-- | Xmobar.hs | 126 | 
1 files changed, 61 insertions, 65 deletions
| @@ -26,8 +26,7 @@ module Xmobar (-- * Main Stuff                , printStrings                -- * Program Execution                -- $commands -              , execCommand -              , readVariables +              , startCommand                -- * Unmamaged Windows                -- $unmanwin                , mkUnmanagedWindow @@ -44,8 +43,8 @@ import Graphics.X11.Xlib.Event  import Control.Monad.State  import Control.Monad.Reader  import Control.Concurrent +import Control.Concurrent.STM  import Control.Exception -  import System.Posix.Types (Fd(..))  import Config @@ -65,44 +64,59 @@ newtype Xbar a = X (ReaderT Config (StateT XState IO) a)  data XState =       XState { display :: Display             , window  :: Window -           , vars    :: [(Maybe ThreadId, MVar String)]             }  -- | We use get to get the state and ask to get the configuration: whis way   -- functions requires less arguments. -runXbar :: Config -> [(Maybe ThreadId, MVar String)] -> Display -> Window -> Xbar () -> IO () -runXbar c v d w (X f) =  -    do runStateT (runReaderT f c) (XState d w v) +runXbar :: Config -> Display -> Window -> Xbar () -> IO () +runXbar c d w (X f) =  +    do runStateT (runReaderT f c) (XState d w)         return () --- | A version of nextEvent that does not block in foreign calls. -nextEvent' :: Display -> XEventPtr -> IO () -nextEvent' d p = do -    pend <- pending d -    if pend /= 0 -        then nextEvent d p -        else do -            threadWaitRead (Fd fd) -            nextEvent' d p - where -    fd = connectionNumber d -  -- | The event loop -eventLoop :: Config -> [(Maybe ThreadId, MVar String)] -> Display -> Window -> IO () +eventLoop :: Config -> [(Maybe ThreadId, TVar String)] -> Display -> Window -> IO ()  eventLoop c v d w = do -    t <- forkIO (block go) -    timer t +    tv <- atomically $ newTVar [] +    t    <- forkIO (block $ go tv) +    timer t tv   where -    -- interrupt the drawing thread every so often -    timer t = do -        tenthSeconds (refresh c) -        throwTo t (ErrorCall "Xmobar.eventLoop: yield") -        timer t +    -- interrupt the drawing thread every time a var is updated +    timer t tvar = do +      nval <- atomically $ do +              ov <- readTVar tvar +              nv <- mapM readTVar (map snd v) +              if concat nv == ov then retry else return (concat nv) +      atomically $ writeTVar tvar nval +      threadDelay 1000 +      throwTo t (ErrorCall "Xmobar.eventLoop: yield") +      timer t tvar      -- Continuously wait for a timer interrupt or an expose event -    go = do -        runXbar c v d w updateWin -        catch (unblock $ allocaXEvent $ nextEvent' d) (const $ return ()) -        go +    go tvar = do +      runXbar 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  + +-- | Runs a command as an independent thread and returns its thread id +-- and the TVar the command will be writing to. +startCommand :: (Runnable,String,String) -> IO (Maybe ThreadId, TVar String) +startCommand (com,s,ss) +    | alias com == ""  = do var <- atomically $ newTVar is +                            atomically $ writeTVar var ("Could not parse the template") +                            return (Nothing,var) +    | otherwise        = do var <- atomically $ newTVar is +                            let cb str = atomically $ writeTVar var (s ++ str ++ ss) +                            h <- forkIO $ start com cb +                            return (Just h,var) +    where is = "Updating... "  -- | The function to create the initial window  createWin :: Config -> IO (Display, Window) @@ -111,22 +125,14 @@ createWin config =       let dflt = defaultScreen dpy       rootw <- rootWindow dpy dflt       win   <- mkUnmanagedWindow dpy (defaultScreenOfDisplay dpy) rootw  -            (fi $ xPos config)  -            (fi $ yPos config)  -            (fi $ width config)  +            (fi $ xPos   config)  +            (fi $ yPos   config)  +            (fi $ width  config)               (fi $ height config)       selectInput dpy win exposureMask       mapWindow   dpy win       return (dpy,win) -updateWin :: Xbar () -updateWin = -    do c  <- ask -       s  <- get -       i  <- io $ readVariables (vars s) -       ps <- io $ parseString c i -       drawInWin ps -  -- $print  -- | Draws in and updates the window @@ -173,7 +179,7 @@ printStrings :: Drawable  printStrings _ _ _ _ [] = return ()  printStrings d gc fontst offs sl@((s,c,l):xs) =      do config <- ask -       st <- get +       st     <- get         let (_,asc,_,_) = textExtents fontst s             totSLen     = foldr (\(_,_,len) -> (+) len) 0 sl             valign      = (fi (height config) + fi asc) `div` 2 @@ -190,28 +196,6 @@ printStrings d gc fontst offs sl@((s,c,l):xs) =         io $ drawImageString (display st) d gc offset valign s         printStrings d gc fontst (offs + l) xs --- $commands - --- | Runs a command as an independent thread and returns its thread id --- and the MVar the command will be writing to. -execCommand :: (Runnable,String,String) -> IO (Maybe ThreadId, MVar String) -execCommand (com,s,ss) -    | alias com == ""  = do var <- newMVar "Updating..." -                            modifyMVar_ var (const $ return $ "Could not parse the template") -                            return (Nothing,var) -    | otherwise        = do var <- newMVar "Updating..." -                            let cb str = modifyMVar_ var (\_ -> return $ s ++ str ++ ss) -                            h <- forkIO $ start com cb -                            return (Just h,var) - --- | Reads MVars set by 'runCommandLoop' -readVariables :: [(Maybe ThreadId, MVar String)] -> IO String -readVariables [] = return "" -readVariables ((_,v):xs) = -    do f  <- readMVar v -       fs <- readVariables xs -       return $! f ++ fs -  {- $unmanwin  This is a way to create unmamaged window. It was a mistery in Haskell.  @@ -253,6 +237,18 @@ initColor' :: Display -> String -> IO Pixel  initColor' dpy c = (color_pixel . fst) `liftM` allocNamedColor dpy colormap c      where colormap = defaultColormap dpy (defaultScreen dpy) +-- | A version of nextEvent that does not block in foreign calls. +nextEvent' :: Display -> XEventPtr -> IO () +nextEvent' d p = do +    pend <- pending d +    if pend /= 0 +        then nextEvent d p +        else do +            threadWaitRead (Fd fd) +            nextEvent' d p + where +    fd = connectionNumber d +  -- | Short-hand for lifting in the IO monad  io :: IO a -> Xbar a  io = liftIO | 
