mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-07-31 20:21:51 -07:00
174 lines
6.7 KiB
Haskell
174 lines
6.7 KiB
Haskell
-----------------------------------------------------------------------------
|
|
-- |
|
|
-- Module : XMonad.Hooks.ServerMode
|
|
-- Copyright : (c) Peter Olson 2013 and Andrea Rossato and David Roundy 2007
|
|
-- License : BSD-style (see xmonad/LICENSE)
|
|
--
|
|
-- Maintainer : polson2@hawk.iit.edu
|
|
-- Stability : unstable
|
|
-- Portability : unportable
|
|
--
|
|
-- This is an 'EventHook' that will receive commands from an external
|
|
-- client. Also consider "XMonad.Hooks.EwmhDesktops" together with
|
|
-- @wmctrl@.
|
|
--
|
|
-- This is the example of a client:
|
|
--
|
|
-- > import Graphics.X11.Xlib
|
|
-- > import Graphics.X11.Xlib.Extras
|
|
-- > import System.Environment
|
|
-- > import System.IO
|
|
-- > import Data.Char
|
|
-- >
|
|
-- > main :: IO ()
|
|
-- > main = parse True "XMONAD_COMMAND" =<< getArgs
|
|
-- >
|
|
-- > parse :: Bool -> String -> [String] -> IO ()
|
|
-- > parse input addr args = case args of
|
|
-- > ["--"] | input -> repl addr
|
|
-- > | otherwise -> return ()
|
|
-- > ("--":xs) -> sendAll addr xs
|
|
-- > ("-a":a:xs) -> parse input a xs
|
|
-- > ("-h":_) -> showHelp
|
|
-- > ("--help":_) -> showHelp
|
|
-- > ("-?":_) -> showHelp
|
|
-- > (a@('-':_):_) -> hPutStrLn stderr ("Unknown option " ++ a)
|
|
-- >
|
|
-- > (x:xs) -> sendCommand addr x >> parse False addr xs
|
|
-- > [] | input -> repl addr
|
|
-- > | otherwise -> return ()
|
|
-- >
|
|
-- >
|
|
-- > repl :: String -> IO ()
|
|
-- > repl addr = do e <- isEOF
|
|
-- > case e of
|
|
-- > True -> return ()
|
|
-- > False -> do l <- getLine
|
|
-- > sendCommand addr l
|
|
-- > repl addr
|
|
-- >
|
|
-- > sendAll :: String -> [String] -> IO ()
|
|
-- > sendAll addr ss = foldr (\a b -> sendCommand addr a >> b) (return ()) ss
|
|
-- >
|
|
-- > sendCommand :: String -> String -> IO ()
|
|
-- > sendCommand addr s = do
|
|
-- > d <- openDisplay ""
|
|
-- > rw <- rootWindow d $ defaultScreen d
|
|
-- > a <- internAtom d addr False
|
|
-- > m <- internAtom d s False
|
|
-- > allocaXEvent $ \e -> do
|
|
-- > setEventType e clientMessage
|
|
-- > setClientMessageEvent e rw a 32 m currentTime
|
|
-- > sendEvent d rw False structureNotifyMask e
|
|
-- > sync d False
|
|
-- >
|
|
-- > showHelp :: IO ()
|
|
-- > showHelp = do pn <- getProgName
|
|
-- > putStrLn ("Send commands to a running instance of xmonad. xmonad.hs must be configured with XMonad.Hooks.ServerMode to work.\n-a atomname can be used at any point in the command line arguments to change which atom it is sending on.\nIf sent with no arguments or only -a atom arguments, it will read commands from stdin.\nEx:\n" ++ pn ++ " cmd1 cmd2\n" ++ pn ++ " -a XMONAD_COMMAND cmd1 cmd2 cmd3 -a XMONAD_PRINT hello world\n" ++ pn ++ " -a XMONAD_PRINT # will read data from stdin.\nThe atom defaults to XMONAD_COMMAND.")
|
|
--
|
|
--
|
|
-- compile with: @ghc --make xmonadctl.hs@
|
|
--
|
|
-- run with
|
|
--
|
|
-- > xmonadctl command
|
|
--
|
|
-- or with
|
|
--
|
|
-- > $ xmonadctl
|
|
-- > command1
|
|
-- > command2
|
|
-- > .
|
|
-- > .
|
|
-- > .
|
|
-- > ^D
|
|
--
|
|
-- Usage will change depending on which event hook(s) you use. More examples are shown below.
|
|
--
|
|
-----------------------------------------------------------------------------
|
|
|
|
module XMonad.Hooks.ServerMode
|
|
( -- * Usage
|
|
-- $usage
|
|
serverModeEventHook
|
|
, serverModeEventHook'
|
|
, serverModeEventHookCmd
|
|
, serverModeEventHookCmd'
|
|
, serverModeEventHookF
|
|
) where
|
|
|
|
import Control.Monad (when)
|
|
import Data.Maybe
|
|
import Data.Monoid
|
|
import System.IO
|
|
|
|
import XMonad
|
|
import XMonad.Actions.Commands
|
|
|
|
-- $usage
|
|
-- You can use this module with the following in your
|
|
-- @~\/.xmonad\/xmonad.hs@:
|
|
--
|
|
-- > import XMonad.Hooks.ServerMode
|
|
--
|
|
-- Then edit your @handleEventHook@ by adding the appropriate event hook from below
|
|
|
|
-- | Executes a command of the list when receiving its index via a special ClientMessageEvent
|
|
-- (indexing starts at 1). Sending index 0 will ask xmonad to print the list of command numbers
|
|
-- in stderr (so that you can read it in @~\/.xsession-errors@). Uses "XMonad.Actions.Commands#defaultCommands" as the default.
|
|
--
|
|
-- > main = xmonad def { handleEventHook = serverModeEventHook }
|
|
--
|
|
-- > xmonadctl 0 # tells xmonad to output command list
|
|
-- > xmonadctl 1 # tells xmonad to switch to workspace 1
|
|
--
|
|
serverModeEventHook :: Event -> X All
|
|
serverModeEventHook = serverModeEventHook' defaultCommands
|
|
|
|
-- | serverModeEventHook' additionally takes an action to generate the list of
|
|
-- commands.
|
|
serverModeEventHook' :: X [(String,X ())] -> Event -> X All
|
|
serverModeEventHook' cmdAction ev = serverModeEventHookF "XMONAD_COMMAND" (sequence_ . map helper . words) ev
|
|
where helper cmd = do cl <- cmdAction
|
|
case lookup cmd (zip (map show [1 :: Integer ..]) cl) of
|
|
Just (_,action) -> action
|
|
Nothing -> mapM_ (io . hPutStrLn stderr) . listOfCommands $ cl
|
|
listOfCommands cl = map (uncurry (++)) $ zip (map show ([1..] :: [Int])) $ map ((++) " - " . fst) cl
|
|
|
|
|
|
-- | Executes a command of the list when receiving its name via a special ClientMessageEvent.
|
|
-- Uses "XMonad.Actions.Commands#defaultCommands" as the default.
|
|
--
|
|
-- > main = xmonad def { handleEventHook = serverModeEventHookCmd }
|
|
--
|
|
-- > xmonadctl run # Tells xmonad to generate a run prompt
|
|
--
|
|
serverModeEventHookCmd :: Event -> X All
|
|
serverModeEventHookCmd = serverModeEventHookCmd' defaultCommands
|
|
|
|
-- | Additionally takes an action to generate the list of commands
|
|
serverModeEventHookCmd' :: X [(String,X ())] -> Event -> X All
|
|
serverModeEventHookCmd' cmdAction ev = serverModeEventHookF "XMONAD_COMMAND" (sequence_ . map helper . words) ev
|
|
where helper cmd = do cl <- cmdAction
|
|
fromMaybe (io $ hPutStrLn stderr ("Couldn't find command " ++ cmd)) (lookup cmd cl)
|
|
|
|
-- | Listens for an atom, then executes a callback function whenever it hears it.
|
|
-- A trivial example that prints everything supplied to it on xmonad's standard out:
|
|
--
|
|
-- > main = xmonad def { handleEventHook = serverModeEventHookF "XMONAD_PRINT" (io . putStrLn) }
|
|
--
|
|
-- > xmonadctl -a XMONAD_PRINT "hello world"
|
|
--
|
|
serverModeEventHookF :: String -> (String -> X ()) -> Event -> X All
|
|
serverModeEventHookF key func (ClientMessageEvent {ev_message_type = mt, ev_data = dt}) = do
|
|
d <- asks display
|
|
atm <- io $ internAtom d key False
|
|
when (mt == atm && dt /= []) $ do
|
|
let atom = fromIntegral $ toInteger $ foldr1 (\a b -> a + (b*2^(32::Int))) dt
|
|
cmd <- io $ getAtomName d atom
|
|
case cmd of
|
|
Just command -> func command
|
|
Nothing -> io $ hPutStrLn stderr ("Couldn't retrieve atom " ++ (show atom))
|
|
return (All True)
|
|
serverModeEventHookF _ _ _ = return (All True)
|