{-# LANGUAGE TupleSections #-} ----------------------------------------------------------------------------- -- | -- Module : XMonad.Actions.WindowBringer -- Copyright : Devin Mullins <me@twifkak.com> -- License : BSD-style (see LICENSE) -- -- Maintainer : Devin Mullins <me@twifkak.com> -- Stability : stable -- Portability : unportable -- -- dmenu operations to bring windows to you, and bring you to windows. -- That is to say, it pops up a dmenu with window names, in case you forgot -- where you left your XChat. -- ----------------------------------------------------------------------------- module XMonad.Actions.WindowBringer ( -- * Usage -- $usage WindowBringerConfig(..), gotoMenu, gotoMenuConfig, gotoMenu', gotoMenuArgs, gotoMenuArgs', bringMenu, bringMenuConfig, bringMenu', bringMenuArgs, bringMenuArgs', windowMap, windowMap', bringWindow, actionMenu ) where import Control.Applicative((<$>)) import qualified Data.Map as M import qualified XMonad.StackSet as W import XMonad import qualified XMonad as X import XMonad.Util.Dmenu (menuMapArgs) import XMonad.Util.NamedWindows (getName) -- $usage -- -- Import the module into your @~\/.xmonad\/xmonad.hs@: -- -- > import XMonad.Actions.WindowBringer -- -- and define appropriate key bindings: -- -- > , ((modm .|. shiftMask, xK_g ), gotoMenu) -- > , ((modm .|. shiftMask, xK_b ), bringMenu) -- -- For detailed instructions on editing your key bindings, see -- "XMonad.Doc.Extending#Editing_key_bindings". data WindowBringerConfig = WindowBringerConfig { menuCommand :: String -- ^ The shell command that will handle window selection , menuArgs :: [String] -- ^ Arguments to be passed to menuCommand , windowTitler :: X.WindowSpace -> Window -> X String -- ^ A function that produces window titles given a workspace and a window } instance Default WindowBringerConfig where def = WindowBringerConfig{ menuCommand = "dmenu" , menuArgs = ["-i"] , windowTitler = decorateName } -- | Pops open a dmenu with window titles. Choose one, and you will be -- taken to the corresponding workspace. gotoMenu :: X () gotoMenu = gotoMenuConfig def -- | Pops open a dmenu with window titles. Choose one, and you will be -- taken to the corresponding workspace. This version accepts a configuration -- object. gotoMenuConfig :: WindowBringerConfig -> X () gotoMenuConfig wbConfig = actionMenu wbConfig W.focusWindow -- | Pops open a dmenu with window titles. Choose one, and you will be -- taken to the corresponding workspace. This version takes a list of -- arguments to pass to dmenu. gotoMenuArgs :: [String] -> X () gotoMenuArgs args = gotoMenuConfig def { menuArgs = args } -- | Pops open an application with window titles given over stdin. Choose one, -- and you will be taken to the corresponding workspace. gotoMenu' :: String -> X () gotoMenu' cmd = gotoMenuConfig def { menuArgs = [], menuCommand = cmd } -- | Pops open an application with window titles given over stdin. Choose one, -- and you will be taken to the corresponding workspace. This version takes a -- list of arguments to pass to dmenu. gotoMenuArgs' :: String -> [String] -> X () gotoMenuArgs' cmd args = gotoMenuConfig def { menuCommand = cmd, menuArgs = args } -- | Pops open a dmenu with window titles. Choose one, and it will be -- dragged, kicking and screaming, into your current workspace. bringMenu :: X () bringMenu = bringMenuArgs def -- | Pops open a dmenu with window titles. Choose one, and it will be -- dragged, kicking and screaming, into your current workspace. This version -- accepts a configuration object. bringMenuConfig :: WindowBringerConfig -> X () bringMenuConfig wbConfig = actionMenu wbConfig bringWindow -- | Pops open a dmenu with window titles. Choose one, and it will be -- dragged, kicking and screaming, into your current workspace. This version -- takes a list of arguments to pass to dmenu. bringMenuArgs :: [String] -> X () bringMenuArgs args = bringMenuConfig def { menuArgs = args } -- | Pops open an application with window titles given over stdin. Choose one, -- and it will be dragged, kicking and screaming, into your current -- workspace. bringMenu' :: String -> X () bringMenu' cmd = bringMenuConfig def { menuArgs = [], menuCommand = cmd } -- | Pops open an application with window titles given over stdin. Choose one, -- and it will be dragged, kicking and screaming, into your current -- workspace. This version allows arguments to the chooser to be specified. bringMenuArgs' :: String -> [String] -> X () bringMenuArgs' cmd args = bringMenuConfig def { menuArgs = args, menuCommand = cmd } -- | Brings the specified window into the current workspace. bringWindow :: Window -> X.WindowSet -> X.WindowSet bringWindow w ws = W.shiftWin (W.currentTag ws) w ws -- | Calls dmenuMap to grab the appropriate Window, and hands it off to action -- if found. actionMenu :: WindowBringerConfig -> (Window -> X.WindowSet -> X.WindowSet) -> X () actionMenu WindowBringerConfig{ menuCommand = cmd , menuArgs = args , windowTitler = titler } action = windowMap' titler >>= menuMapFunction >>= flip X.whenJust (windows . action) where menuMapFunction :: M.Map String a -> X (Maybe a) menuMapFunction = menuMapArgs cmd args -- | A map from window names to Windows. windowMap :: X (M.Map String Window) windowMap = windowMap' decorateName -- | A map from window names to Windows, given a windowTitler function. windowMap' :: (X.WindowSpace -> Window -> X String) -> X (M.Map String Window) windowMap' titler = do ws <- gets X.windowset M.fromList . concat <$> mapM keyValuePairs (W.workspaces ws) where keyValuePairs ws = mapM (keyValuePair ws) $ W.integrate' (W.stack ws) keyValuePair ws w = flip (,) w <$> titler ws w -- | Returns the window name as will be listed in dmenu. -- Tagged with the workspace ID, to guarantee uniqueness, and to let the user -- know where he's going. decorateName :: X.WindowSpace -> Window -> X String decorateName ws w = do name <- show <$> getName w return $ name ++ " [" ++ W.tag ws ++ "]"