aboutsummaryrefslogtreecommitdiffstats
path: root/XMonad/Util/Run.hs
diff options
context:
space:
mode:
Diffstat (limited to 'XMonad/Util/Run.hs')
-rw-r--r--XMonad/Util/Run.hs114
1 files changed, 114 insertions, 0 deletions
diff --git a/XMonad/Util/Run.hs b/XMonad/Util/Run.hs
new file mode 100644
index 0000000..39a653a
--- /dev/null
+++ b/XMonad/Util/Run.hs
@@ -0,0 +1,114 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module : XMonad.Util.Run
+-- Copyright : (C) 2007 Spencer Janssen, Andrea Rossato, glasser@mit.edu
+-- License : BSD-style (see LICENSE)
+--
+-- Maintainer : Christian Thiemann <mail@christian-thiemann.de>
+-- Stability : unstable
+-- Portability : unportable
+--
+-- This modules provides several commands to run an external process.
+-- It is composed of functions formerly defined in XMonad.Util.Dmenu (by
+-- Spenver Jannsen), XMonad.Util.Dzen (by glasser@mit.edu) and
+-- XMonad.Util.RunInXTerm (by Andrea Rossato).
+--
+-----------------------------------------------------------------------------
+
+module XMonad.Util.Run (
+ -- * Usage
+ -- $usage
+ runProcessWithInput,
+ runProcessWithInputAndWait,
+ safeSpawn,
+ unsafeSpawn,
+ runInTerm,
+ safeRunInTerm,
+ seconds
+ ) where
+
+import Control.Monad.Reader
+import System.Posix.Process (createSession, forkProcess, executeFile,
+ getProcessStatus)
+import Control.Concurrent (threadDelay)
+import Control.Exception (try)
+import System.Exit (ExitCode(ExitSuccess), exitWith)
+import System.IO (IO, FilePath, hPutStr, hGetContents, hFlush, hClose)
+import System.Process (runInteractiveProcess, waitForProcess)
+import XMonad
+
+-- $usage
+-- For an example usage of runInTerm see XMonad.Prompt.Ssh
+--
+-- For an example usage of runProcessWithInput see
+-- XMonad.Prompt.{DirectoryPrompt,Dmenu,ShellPrompt,WmiiActions,WorkspaceDir}
+--
+-- For an example usage of runProcessWithInputAndWait see XMonad.Util.Dzen
+
+-- | Returns Just output if the command succeeded, and Nothing if it didn't.
+-- This corresponds to dmenu's notion of exit code 1 for a cancelled invocation.
+runProcessWithInput :: FilePath -> [String] -> String -> IO String
+runProcessWithInput cmd args input = do
+ (pin, pout, perr, ph) <- runInteractiveProcess cmd args Nothing Nothing
+ hPutStr pin input
+ hClose pin
+ output <- hGetContents pout
+ when (output==output) $ return ()
+ hClose pout
+ hClose perr
+ waitForProcess ph
+ return output
+
+-- wait is in us
+runProcessWithInputAndWait :: FilePath -> [String] -> String -> Int -> IO ()
+runProcessWithInputAndWait cmd args input timeout = do
+ pid <- forkProcess $ do
+ forkProcess $ do -- double fork it over to init
+ createSession
+ (pin, pout, perr, ph) <- runInteractiveProcess cmd args Nothing Nothing
+ hPutStr pin input
+ hFlush pin
+ threadDelay timeout
+ hClose pin
+ hClose pout
+ hClose perr
+ waitForProcess ph
+ return ()
+ exitWith ExitSuccess
+ return ()
+ getProcessStatus True False pid
+ return ()
+
+{- | Multiplies by ONE MILLION, for use with runProcessWithInputAndWait.
+ Use like:
+ > (5.5 `seconds`)
+-}
+seconds :: Rational -> Int
+seconds = fromEnum . (* 1000000)
+
+{- | safeSpawn bypasses XMonad's 'spawn' command, because spawn passes strings to /bin/sh to be interpreted as shell
+ commands. This is often what one wants, but in many cases the passed string will contain shell metacharacters
+ which one does not want interpreted as such (URLs particularly often have shell metacharacters like '&' in them).
+ In this case, it is more useful to specify a file or program to be run and a string to give it as an argument so
+ as to bypass the shell and be certain the program will receive the string as you typed it.
+ unsafeSpawn is an alias for XMonad's 'spawn', to remind one that use of it can be, well, unsafe.
+ Examples:
+ > , ((modMask, xK_Print ), unsafeSpawn "import -window root png:$HOME/xwd-$(date +%s)$$.png")
+ > , ((modMask, xK_d ), safeSpawn "firefox" "")
+
+ Note that the unsafeSpawn example must be unsafe and not safe because it makes use of shell interpretation by relying on
+ $HOME and interpolation, whereas the safeSpawn example can be safe because Firefox doesn't need any arguments if it is
+ just being started.
+-}
+safeSpawn :: FilePath -> String -> X ()
+safeSpawn prog arg = io (try (forkProcess $ executeFile prog True [arg] Nothing) >> return ())
+unsafeSpawn :: String -> X ()
+unsafeSpawn = spawn
+
+-- | Run a given program in the preferred terminal emulator. This uses safeSpawn.
+safeRunInTerm :: String -> X ()
+safeRunInTerm command = asks (terminal . config) >>= \t -> safeSpawn t ("-e " ++ command)
+
+unsafeRunInTerm, runInTerm :: String -> X ()
+unsafeRunInTerm command = asks (terminal . config) >>= \t -> unsafeSpawn $ t ++ " -e " ++ command
+runInTerm = unsafeRunInTerm