{-| Copyright : (c) 2015 Javran Cheng License : MIT Maintainer : Javran.C@gmail.com Stability : unstable Portability : non-portable (requires X11) Configuration for EntryHelper -} module XMonad.Util.EntryHelper.Config ( Config(..) , defaultConfig , withHelper , withCustomHelper ) where import System.Environment import System.Exit import System.Info import Data.Version (showVersion) import Graphics.X11.Xinerama (compiledWithXinerama) import XMonad.Main import XMonad.Core hiding (recompile) import qualified XMonad.Config as XMC import XMonad.Util.EntryHelper.Generated import XMonad.Util.EntryHelper.Util import XMonad.Util.EntryHelper.Compile -- | the configuration for EntryHelper. -- -- * @run@ should execute XMonad using a customized configuration. -- * @compile force@ should compile the source file and return a value which -- will lately be consumed by @postCompile@. @force@ is just a hint about whether -- the compilation should be forced. @compile@ is free to ignore it and do up-to-date check -- on its own. -- * @postCompile val@ should take action according to the @val@, usually produced by @compile@ -- -- Note that: -- -- * @compile@ should create a new process for compilation, as otherwise things like `executeFile` -- will replace the current process image with a new process image, make it impossible -- for @postCompile@ to invoke. -- * @force@ is just a hint about whether the compilation should be forced. -- and @compile@ is free to ignore it and do up-to-date checking on its own. -- * don't remove the binary file when the compilation has failed, as XMonad restart relies -- on it. data Config a = Config { run :: IO () -- ^ the action for executing XMonad , compile :: Bool -> IO a -- ^ the action for compiling XMonad , postCompile :: a -> IO () -- ^ the action after compiling XMonad } -- | default config for xmonad-entryhelper, -- invokes xmonad with its default config file defaultConfig :: Config ExitCode defaultConfig = Config { run = xmonad XMC.defaultConfig , compile = defaultCompile , postCompile = defaultPostCompile } {- -- I don't think this is necessary, -- as users can use "xmonad config" or just their main entries for "run" -- depending on their needs. class Executable r where execute :: r -> IO () instance (LayoutClass l Window, Read (l Window)) => Executable (XConfig l) where execute = xmonad instance Executable a => Executable (IO a) where execute a = a >>= execute instance Executable () where execute = const (return ()) -} -- | @withHelper e@ is the same as calling `withCustomHelper` with default -- @compile@ and @postCompile actions@ -- -- Either of the following will work: -- -- * replace your main entry with @main = withHelper yourOldMain@ -- * use @main = withHelper (xmonad cfg)@ if you have only customized your `XConfig` withHelper :: IO () -> IO () withHelper e = withCustomHelper defaultConfig { run = e } -- | simulates the way that XMonad handles its command line arguments. -- -- * when called with no argument, the action in @run@ will be used -- * when called with a string prefixed with @"--resume"@, or when called with -- @"--replace"@, the action in @run@ will be used -- * when called with @"--recompile"@ or @"--restart"@, 'compile' will be called. And 'postCompile' -- will handle the results from compliation. -- * additionally when called with @"--restart"@ a restart request will be sent to the current -- XMonad instance after the compilation regardless of the compilation result. withCustomHelper :: Config a -> IO () withCustomHelper cfg = do -- since XMonad has hard-coded to call "xmonad --resume{..}" on restart -- I guess there isn't much we can do to have more command line functionalities -- TODO: a pontential plan might be: -- try to simulate "xmonad" when the program name is "xmonad", -- and otherwise an alternative command line argument parsing strategy will be applied. args <- getArgs let launch = installSignalHandlers >> run cfg recompile force = compile cfg force >>= postCompile cfg case args of [] -> launch ("--resume":_) -> launch ["--help"] -> printHelp ["--recompile"] -> recompile True ["--replace"] -> launch ["--restart"] -> safeIO () (recompile False) >> sendRestart ["--version"] -> putStrLn $ unwords shortVersion ["--verbose-version"] -> putStrLn . unwords $ shortVersion ++ longVersion _ -> printHelp >> exitFailure where shortVersion = [ "xmonad", xmonadVersion ] longVersion = [ "compiled by", compilerName, showVersion compilerVersion , "for", arch ++ "-" ++ os , "\nXinerama:", show compiledWithXinerama ] printHelp :: IO () printHelp = do self <- getProgName putStr . unlines $ [ "xmonad-entryhelper - XMonad config entry point wrapper" , "" , "Usage: " ++ self ++ " [OPTION]" , "Options:" , " --help Print this message" , " --version Print XMonad's version number" , " --recompile Recompile XMonad" , " --replace Replace the running window manager with XMonad" , " --restart Request a running XMonad process to restart" ]