Skip to content

Latest commit

 

History

History
286 lines (219 loc) · 11.1 KB

window-managers.org

File metadata and controls

286 lines (219 loc) · 11.1 KB

Interfacing with window managers

Listed below are ways to interface xmobar with your window manager of choice.

Property-based Logging

XMonadLog
  • Aliases to XMonadLog
  • Displays information from xmonad’s _XMONAD_LOG. You can use this by using functions from the XMonad.Hooks.DynamicLog module. By using the xmonadPropLog function in your logHook, you can write the the above property. The following shows a minimal xmonad configuration that spawns xmobar and then writes to the _XMONAD_LOG property.
    main = do
      spawn "xmobar"
      xmonad $ def
        { logHook = dynamicLogString defaultPP >>= xmonadPropLog
        }
        

    This plugin can be used as a sometimes more convenient alternative to StdinReader. For instance, it allows you to (re)start xmobar outside xmonad.

UnsafeXMonadLog
  • Aliases to UnsafeXMonadLog
  • Displays any text received by xmobar on the _XMONAD_LOG atom.
  • Will not do anything to the text received. This means you can pass xmobar dynamic actions. Be careful to escape (using <raw=…>) or remove tags from dynamic text that you pipe through to xmobar in this way.
  • Sample usage: Send the list of your workspaces, enclosed by actions tags, to xmobar. This enables you to switch to a workspace when you click on it in xmobar!
    <action=`xdotool key alt+1`>ws1</action> <action=`xdotool key alt+1`>ws2</action>
        
  • If you use xmonad, It is advised that you still use xmobarStrip for the ppTitle in your logHook:
    myPP = defaultPP { ppTitle = xmobarStrip }
    main = xmonad $ def
      { logHook = dynamicLogString myPP >>= xmonadPropLog
      }
        
XPropertyLog PropName
  • Aliases to PropName
  • Reads the X property named by PropName (a string) and displays its value. The examples/xmonadpropwrite.hs script in xmobar’s distribution can be used to set the given property from the output of any other program or script.
UnsafeXPropertyLog PropName
  • Aliases to PropName
  • Same as XPropertyLog but the input is not filtered to avoid injection of actions (cf. UnsafeXMonadLog). The program writing the value of the read property is responsible of performing any needed cleanups.
NamedXPropertyLog PropName Alias
  • Aliases to Alias
  • Same as XPropertyLog but a custom alias can be specified.
UnsafeNamedXPropertyLog PropName Alias
  • Aliases to Alias
  • Same as UnsafeXPropertyLog, but a custom alias can be specified.

Logging via Stdin

StdinReader
  • Aliases to StdinReader
  • Displays any text received by xmobar on its standard input.
  • Strips actions from the text received. This means you can’t pass dynamic actions via stdin. This is safer than UnsafeStdinReader because there is no need to escape the content before passing it to xmobar’s standard input.
UnsafeStdinReader
  • Aliases to UnsafeStdinReader
  • Displays any text received by xmobar on its standard input.
  • Similar to UnsafeXMonadLog, in the sense that it does not strip any actions from the received text, only using stdin and not a property atom of the root window. Please be equally carefully when using this as when using UnsafeXMonadLog!

Pipe-based Logging

PipeReader "default text:/path/to/pipe" Alias
  • Reads its displayed output from the given pipe.
  • Prefix an optional default text separated by a colon
  • Expands environment variables in the first argument of syntax ${VAR} or $VAR
MarqueePipeReader "default text:/path/to/pipe" (length, rate, sep) Alias
  • Generally equivalent to PipeReader
  • Text is displayed as marquee with the specified length, rate in 10th seconds and separator when it wraps around
    Run MarqueePipeReader "/tmp/testpipe" (10, 7, "+") "mpipe"
        
  • Expands environment variables in the first argument
BufferedPipeReader Alias [(Timeout, Bool, "/path/to/pipe1"), ..]
  • Display data from multiple pipes.
  • Timeout (in tenth of seconds) is the value after which the previous content is restored i.e. if there was already something from a previous pipe it will be put on display again, overwriting the current status.
  • A pipe with Timeout of 0 will be displayed permanently, just like PipeReader
  • The boolean option indicates whether new data for this pipe should make xmobar appear (unhide, reveal). In this case, the Timeout additionally specifies when the window should be hidden again. The output is restored in any case.
  • Use it for OSD-like status bars e.g. for setting the volume or brightness:
    Run BufferedPipeReader "bpr"
        [ (  0, False, "/tmp/xmobar_window"  )
        , ( 15,  True, "/tmp/xmobar_status"  )
        ]
        

    Have your window manager send window titles to /tmp/xmobar_window. They will always be shown and not reveal your xmobar. Sending some status information to /tmp/xmobar_status will reveal xmonad for 1.5 seconds and temporarily overwrite the window titles.

  • Take a look at examples/status.sh
  • Expands environment variables for the pipe path

Handle-based Logging

HandleReader Handle Alias
  • Display data from a Haskell Handle
  • This plugin is only useful if you are running xmobar from another Haskell program like XMonad.
  • You can use System.Process.createPipe to create a pair of read & write Handles. Pass the read Handle to HandleReader and write your output to the write Handle:
    (readHandle, writeHandle) <- createPipe
    xmobarProcess <- forkProcess $ xmobar myConfig
            { commands =
                Run (HandleReader readHandle "handle") : commands myConfig
            }
    hPutStr writeHandle "Hello World"
        

Software Transactional Memory

When invoking xmobar from other Haskell code it can be easier and more performant to use shared memory. The following plugins leverage Control.Concurrent.STM to realize these gains for xmobar.

QueueReader (TQueue a) (a -> String) String
  • Display data from a Haskell TQueue a.
  • This plugin is only useful if you are running xmobar from another haskell program like xmonad.
  • You should make an IO safe TQueue a with Control.Concurrent.STM.newTQueueIO. Write to it from the user code with writeTQueue, and read with readTQueue. A common use is to overwite ppOutput from XMonad.Hooks.DynamicLog as shown below.
    main :: IO ()
    main = do
      initThreads
      q <- STM.newTQueueIO @String
      bar <- forkOS $ xmobar myConf
        { commands = Run (QueueReader q id "XMonadLog") : commands myConf }
      xmonad $ def { logHook = logWorkspacesToQueue q }
    
    logWorkspacesToQueue :: STM.TQueue String -> X ()
    logWorkspacesToQueue q =
      dynamicLogWithPP def { ppOutput = STM.atomically . STM.writeTQueue q }
        

    Note that xmonad uses blocking Xlib calls in its event loop and isn’t normally compiled with the threaded RTS so an xmobar thread running inside xmonad will suffer from delayed updates. It is thus necessary to enable -threaded when compiling xmonad configuration (xmonad.hs), e.g. by using a custom ~/.xmonad/build script.

Example of using the DBus IPC interface with XMonad

Bind the key which should {,un}map xmobar to a dummy value. This is necessary for {,un}grabKey in xmonad.

((0, xK_Alt_L), pure ())

Also, install avoidStruts layout modifier from XMonad.Hooks.ManageDocks

Finally, install these two event hooks (handleEventHook in XConfig) myDocksEventHook is a replacement for docksEventHook which reacts on unmap events as well (which docksEventHook doesn’t).

import qualified XMonad.Util.ExtensibleState as XS

data DockToggleTime = DTT { lastTime :: Time } deriving (Eq, Show, Typeable)

instance ExtensionClass DockToggleTime where
    initialValue = DTT 0

toggleDocksHook :: Int -> KeySym -> Event -> X All
toggleDocksHook to ks ( KeyEvent { ev_event_display = d
                                 , ev_event_type    = et
                                 , ev_keycode       = ekc
                                 , ev_time          = etime
                                 } ) =
        io (keysymToKeycode d ks) >>= toggleDocks >> return (All True)
    where
    toggleDocks kc
        | ekc == kc && et == keyPress = do
            safeSendSignal ["Reveal 0", "TogglePersistent"]
            XS.put ( DTT etime )
        | ekc == kc && et == keyRelease = do
            gap <- XS.gets ( (-) etime . lastTime )
            safeSendSignal [ "TogglePersistent"
                        , "Hide " ++ show (if gap < 400 then to else 0)
                        ]
        | otherwise = return ()

    safeSendSignal s = catchX (io $ sendSignal s) (return ())
    sendSignal    = withSession . callSignal
    withSession mc = connectSession >>= \c -> callNoReply c mc >> disconnect c
    callSignal :: [String] -> MethodCall
    callSignal s = ( methodCall
                    ( objectPath_    "/org/Xmobar/Control" )
                    ( interfaceName_ "org.Xmobar.Control"  )
                    ( memberName_    "SendSignal"          )
                ) { methodCallDestination = Just $ busName_ "org.Xmobar.Control"
                    , methodCallBody        = map toVariant s
                    }

toggleDocksHook _ _ _ = return (All True)

myDocksEventHook :: Event -> X All
myDocksEventHook e = do
    when (et == mapNotify || et == unmapNotify) $
        whenX ((not `fmap` (isClient w)) <&&> runQuery checkDock w) refresh
    return (All True)
    where w  = ev_window e
        et = ev_event_type e