diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Main.hs | 5 | ||||
| -rw-r--r-- | src/XUtil.hsc | 16 | ||||
| -rw-r--r-- | src/Xmobar.hs | 111 | 
3 files changed, 101 insertions, 31 deletions
| diff --git a/src/Main.hs b/src/Main.hs index 18e05e2..e8efd61 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -41,6 +41,7 @@ import Control.Monad (unless)  -- | The main entry point  main :: IO ()  main = do +  initThreads    d   <- openDisplay ""    args     <- getArgs    (o,file) <- getOpts args @@ -51,10 +52,6 @@ main = do    unless (null defaultings) $ putStrLn $ "Fields missing from config defaulted: "                                              ++ intercalate "," defaultings -  -- listen for ConfigureEvents on the root window, for xrandr support: -  rootw <- rootWindow d (defaultScreen d) -  selectInput d rootw structureNotifyMask -    conf  <- doOpts c o    fs    <- initFont d (font conf)    cls   <- mapM (parseTemplate conf) (splitTemplate conf) diff --git a/src/XUtil.hsc b/src/XUtil.hsc index 1de5e47..ea051f8 100644 --- a/src/XUtil.hsc +++ b/src/XUtil.hsc @@ -1,8 +1,8 @@ --- {-# OPTIONS -fglasgow-exts #-} +{-# LANGUAGE ForeignFunctionInterface #-}  -----------------------------------------------------------------------------  -- |  -- Module      :  XUtil --- Copyright   :  (C) 2007 Andrea Rossato +-- Copyright   :  (C) 2007, 2011 Andrea Rossato  -- License     :  BSD3  --  -- Maintainer  :  andrea.rossato@unitn.it @@ -28,12 +28,15 @@ module XUtil      , fi      , withColors      , DynPixel(..) +    , xrrSelectInput +    , xrrQueryExtension      ) where  import Control.Concurrent  import Control.Monad.Trans  import Data.IORef  import Foreign +import Foreign.C.Types  import Graphics.X11.Xlib hiding (textExtents, textWidth)  import qualified Graphics.X11.Xlib as Xlib (textExtents, textWidth)  import Graphics.X11.Xlib.Extras @@ -257,3 +260,12 @@ setupLocale = withCString "" (setlocale $ #const LC_ALL) >> return ()  setupLocale :: IO ()  setupLocale = return ()  #endif + +--  XRRSelectInput +#include <X11/extensions/Xrandr.h> +foreign import ccall unsafe "X11/extensions/Xrandr.h XRRSelectInput" +  xrrSelectInput :: Display -> Window -> EventMask -> IO () + +--  XRRQueryExtension +foreign import ccall unsafe "X11/extensions/Xrandr.h XRRQueryExtension" +  xrrQueryExtension :: Display -> Ptr CInt -> Ptr CInt -> IO (Bool) diff --git a/src/Xmobar.hs b/src/Xmobar.hs index eb7a1dd..37fd653 100644 --- a/src/Xmobar.hs +++ b/src/Xmobar.hs @@ -42,7 +42,9 @@ import Control.Exception hiding (handle)  import Data.Bits  import Data.Maybe(fromMaybe)  import Data.Typeable (Typeable) +import Foreign  import System.Posix.Process (getProcessID) +import System.Posix.Signals  import Config  import Parsers @@ -73,45 +75,94 @@ runX xc f = runReaderT f xc  data WakeUp = WakeUp deriving (Show,Typeable)  instance Exception WakeUp +data SignalType = Wakeup | Reposition | ChangeScreen +  -- | The event loop  eventLoop :: XConf -> [[(Maybe ThreadId, TVar String)]] -> IO () -eventLoop xc@(XConf d _ w fs c) vs = block $ do +eventLoop xcfg@(XConf d _ w fs _) vs = do      tv <- atomically $ newTVar [] -    t  <- myThreadId -    ct <- forkIO (checker t tv [] `catch` \(SomeException _) -> return ()) -    go tv ct - where +    sig <- setupSignalHandler +    _ <- forkIO (checker tv [] sig `catch` \(SomeException _) -> putStrLn "Thread checker failed" >> return ()) +    _ <- forkOS (eventer sig `catch` \(SomeException _) -> putStrLn "Thread eventer failed" >> return ()) +    go tv xcfg sig +  where      -- interrupt the drawing thread every time a var is updated -    checker t tvar ov = do +    checker tvar ov signal = do        nval <- atomically $ do                nv <- mapM concatV vs                guard (nv /= ov)                writeTVar tvar nv                return nv -      throwTo t WakeUp -      checker t tvar nval +      putMVar signal Wakeup +      checker tvar nval signal      concatV = fmap concat . mapM (readTVar . snd) -    -- Continuously wait for a timer interrupt or an expose event -    go tv ct = do -      catch (unblock $ allocaXEvent $ \e -> -                 handle tv ct =<< (nextEvent' d e >> getEvent e)) -            (\WakeUp -> runX xc (updateWin tv) >> return ()) -      go tv ct +    eventer signal = +      alloca $ \ptrEventBase -> +      alloca $ \ptrErrorBase -> +      allocaXEvent $ \e -> do -    -- event hanlder -    handle _ ct (ConfigureEvent {ev_window = win}) = do -      rootw <- rootWindow d (defaultScreen d) -      when (win == rootw) $ block $ do -                      killThread ct -                      destroyWindow d w -                      (r',w') <- createWin d fs c -                      eventLoop (XConf d r' w' fs c) vs +        dpy <- openDisplay "" +        --  keyPressMask is the same value as RRScreenChangeNotifyMask +        xrrSelectInput    dpy (defaultRootWindow dpy) keyPressMask +        selectInput       dpy w (exposureMask .|. structureNotifyMask) -    handle tvar _ (ExposeEvent {}) = runX xc (updateWin tvar) +        _ <- xrrQueryExtension dpy ptrEventBase ptrErrorBase +        xrrEventBase <- peek ptrEventBase -    handle _ _ _  = return () +        forever $ do +          nextEvent dpy e +          ev <- getEvent e +          case ev of +            ConfigureEvent {} -> putMVar signal Reposition +            ExposeEvent {} -> putMVar signal Wakeup +            _ -> +              --  0 is the value of RRScreenChangeNotify +              when ( (fromIntegral (ev_event_type ev) - xrrEventBase) == 0) +                   $ putMVar signal Reposition + + +    -- Continuously wait for a timer interrupt or an expose event +    go tv xc@(XConf _ _ _ _ cfg) signal = do +      typ <- takeMVar signal +      case typ of +        Wakeup -> do +          runX xc (updateWin tv) +          go tv xc signal +        Reposition -> reposWindow cfg +        ChangeScreen -> +          case position cfg of +            OnScreen n o -> do +              srs <- getScreenInfo d +              if n == length srs then +                  reposWindow (cfg {position = OnScreen 1 o}) +                else +                  reposWindow (cfg {position = OnScreen (n+1) o}) +            o -> +              reposWindow (cfg {position = OnScreen 1 o}) +      where +        reposWindow rcfg = do +          r' <- repositionWin d w fs rcfg +          go tv (XConf d r' w fs rcfg) signal + +-- | Signal handling +setupSignalHandler :: IO (MVar SignalType) +setupSignalHandler = do +   tid   <- newEmptyMVar +   installHandler sigUSR2 (Catch $ updatePosHandler tid) Nothing +   installHandler sigUSR1 (Catch $ changeScreenHandler tid) Nothing +   return tid + +updatePosHandler :: MVar SignalType -> IO () +updatePosHandler sig = do +   putMVar sig Reposition +   return () + +changeScreenHandler :: MVar SignalType -> IO () +changeScreenHandler sig = do +   putMVar sig ChangeScreen +   return ()  -- $command @@ -140,12 +191,22 @@ createWin d fs c = do    let ht    = as + ds + 4        (r,o) = setPosition (position c) srs (fi ht)    win <- newWindow  d (defaultScreenOfDisplay d) rootw r o -  selectInput       d win (exposureMask .|. structureNotifyMask)    setProperties r c d win srs    when (lowerOnStart c) (lowerWindow d win)    mapWindow         d win    return (r,win) +-- | Updates the size and position of the window +repositionWin :: Display -> Window -> XFont -> Config -> IO (Rectangle) +repositionWin d win fs c = do +  srs     <- getScreenInfo d +  (as,ds) <- textExtents fs "0" +  let ht    = as + ds + 4 +      (r,_) = setPosition (position c) srs (fi ht) +  moveResizeWindow d win (rect_x r) (rect_y r) (rect_width r) (rect_height r) +  setProperties r c d win srs +  return r +  setPosition :: XPosition -> [Rectangle] -> Dimension -> (Rectangle,Bool)  setPosition p rs ht =    case p' of | 
