xmonad 0.8.1 → 0.9
raw patch · 15 files changed
+419/−166 lines, 15 filesdep +filepathdep ~X11PVP ok
version bump matches the API change (PVP)
Dependencies added: filepath
Dependency ranges changed: X11
API changes (from Hackage documentation)
- XMonad.Core: doubleFork :: (MonadIO m) => IO () -> m ()
+ XMonad.Core: handleEventHook :: XConfig l -> !Event -> X All
+ XMonad.Core: installSignalHandlers :: (MonadIO m) => m ()
+ XMonad.Core: instance Typeable1 X
+ XMonad.Core: mousePosition :: XConf -> !Maybe (Position, Position)
+ XMonad.Core: spawnPID :: (MonadIO m) => String -> m ProcessID
+ XMonad.Core: uninstallSignalHandlers :: (MonadIO m) => m ()
+ XMonad.Core: userCodeDef :: a -> X a -> X a
+ XMonad.Layout: tallNMaster :: Tall a -> !Int
+ XMonad.Layout: tallRatio :: Tall a -> !Rational
+ XMonad.Layout: tallRatioIncrement :: Tall a -> !Rational
+ XMonad.Operations: killWindow :: Window -> X ()
+ XMonad.Operations: pointScreen :: Position -> Position -> X (Maybe (Screen WorkspaceId (Layout Window) Window ScreenId ScreenDetail))
+ XMonad.Operations: pointWithin :: Position -> Position -> Rectangle -> Bool
+ XMonad.Operations: scaleRationalRect :: Rectangle -> RationalRect -> Rectangle
+ XMonad.StackSet: focusDown' :: Stack a -> Stack a
+ XMonad.StackSet: focusUp' :: Stack a -> Stack a
+ XMonad.StackSet: shiftMaster :: StackSet i l a s sd -> StackSet i l a s sd
- XMonad.Core: XConf :: Display -> !XConfig Layout -> !Window -> !Pixel -> !Pixel -> !Map (KeyMask, KeySym) (X ()) -> !Map (KeyMask, Button) (Window -> X ()) -> !Bool -> XConf
+ XMonad.Core: XConf :: Display -> !XConfig Layout -> !Window -> !Pixel -> !Pixel -> !Map (KeyMask, KeySym) (X ()) -> !Map (KeyMask, Button) (Window -> X ()) -> !Bool -> !Maybe (Position, Position) -> XConf
- XMonad.Core: XConfig :: !String -> !String -> !String -> !l Window -> !ManageHook -> ![String] -> !KeyMask -> !KeyMask -> !XConfig Layout -> Map (ButtonMask, KeySym) (X ()) -> !XConfig Layout -> Map (ButtonMask, Button) (Window -> X ()) -> !Dimension -> !X () -> !X () -> !Bool -> XConfig l
+ XMonad.Core: XConfig :: !String -> !String -> !String -> !l Window -> !ManageHook -> !Event -> X All -> ![String] -> !KeyMask -> !KeyMask -> !XConfig Layout -> Map (ButtonMask, KeySym) (X ()) -> !XConfig Layout -> Map (ButtonMask, Button) (Window -> X ()) -> !Dimension -> !X () -> !X () -> !Bool -> XConfig l
- XMonad.Core: userCode :: X () -> X ()
+ XMonad.Core: userCode :: X a -> X (Maybe a)
Files
- Main.hs +20/−4
- XMonad/Config.hs +20/−6
- XMonad/Core.hs +74/−23
- XMonad/Layout.hs +4/−1
- XMonad/Main.hsc +48/−19
- XMonad/ManageHook.hs +5/−2
- XMonad/Operations.hs +58/−35
- XMonad/StackSet.hs +28/−18
- man/xmonad.1 +22/−5
- man/xmonad.1.in +22/−5
- man/xmonad.hs +53/−36
- man/xmonad.html +31/−7
- tests/Properties.hs +17/−0
- util/GenerateManpage.hs +11/−1
- xmonad.cabal +6/−4
Main.hs view
@@ -16,10 +16,12 @@ import XMonad +import Control.Monad (unless) import System.IO import System.Info import System.Environment import System.Posix.Process (executeFile)+import System.Exit (exitFailure) import Paths_xmonad (version) import Data.Version (showVersion)@@ -32,13 +34,15 @@ -- for xmonad, and if it doesn't find one, just launches the default. main :: IO () main = do+ installSignalHandlers -- important to ignore SIGCHLD to avoid zombies args <- getArgs let launch = catchIO buildLaunch >> xmonad defaultConfig case args of [] -> launch ["--resume", _] -> launch ["--help"] -> usage- ["--recompile"] -> recompile True >> return ()+ ["--recompile"] -> recompile True >>= flip unless exitFailure+ ["--restart"] -> sendRestart >> return () ["--version"] -> putStrLn ("xmonad " ++ showVersion version) #ifdef TESTING ("--run-tests":_) -> Properties.main@@ -54,18 +58,19 @@ " --help Print this message" : " --version Print the version number" : " --recompile Recompile your ~/.xmonad/xmonad.hs" :+ " --restart Request a running xmonad process to restart" : #ifdef TESTING " --run-tests Run the test suite" : #endif [] --- | Build "~/.xmonad/xmonad.hs" with ghc, then execute it. If there are no+-- | Build "~\/.xmonad\/xmonad.hs" with ghc, then execute it. If there are no -- errors, this function does not return. An exception is raised in any of -- these cases: -- -- * ghc missing ----- * ~/.xmonad/xmonad.hs missing+-- * both "~\/.xmonad\/xmonad.hs" and "~\/.xmonad\/xmonad-$arch-$os" missing -- -- * xmonad.hs fails to compile --@@ -73,7 +78,7 @@ -- -- ** type error, syntax error, .. ----- * Missing xmonad/XMonadContrib modules due to ghc upgrade+-- * Missing XMonad\/XMonadContrib modules due to ghc upgrade -- buildLaunch :: IO () buildLaunch = do@@ -82,3 +87,14 @@ args <- getArgs executeFile (dir ++ "/xmonad-"++arch++"-"++os) False args Nothing return ()++sendRestart :: IO ()+sendRestart = do+ dpy <- openDisplay ""+ rw <- rootWindow dpy $ defaultScreen dpy+ xmonad_restart <- internAtom dpy "XMONAD_RESTART" False+ allocaXEvent $ \e -> do+ setEventType e clientMessage+ setClientMessageEvent e rw xmonad_restart 32 0 currentTime+ sendEvent dpy rw False structureNotifyMask e+ sync dpy False
XMonad/Config.hs view
@@ -26,19 +26,23 @@ -- import XMonad.Core as XMonad hiding (workspaces,manageHook,numlockMask,keys,logHook,startupHook,borderWidth,mouseBindings- ,layoutHook,modMask,terminal,normalBorderColor,focusedBorderColor,focusFollowsMouse)+ ,layoutHook,modMask,terminal,normalBorderColor,focusedBorderColor,focusFollowsMouse+ ,handleEventHook) import qualified XMonad.Core as XMonad (workspaces,manageHook,numlockMask,keys,logHook,startupHook,borderWidth,mouseBindings- ,layoutHook,modMask,terminal,normalBorderColor,focusedBorderColor,focusFollowsMouse)+ ,layoutHook,modMask,terminal,normalBorderColor,focusedBorderColor,focusFollowsMouse+ ,handleEventHook) import XMonad.Layout import XMonad.Operations import XMonad.ManageHook import qualified XMonad.StackSet as W import Data.Bits ((.|.))+import Data.Monoid import qualified Data.Map as M import System.Exit import Graphics.X11.Xlib+import Graphics.X11.Xlib.Extras -- | The default number of workspaces (virtual screens) and their names. -- By default we use numeric strings, but any string may be used as a@@ -119,6 +123,15 @@ logHook :: X () logHook = return () +------------------------------------------------------------------------+-- Event handling++-- | Defines a custom handler function for X Events. The function should+-- return (All True) if the default handler is to be run afterwards.+-- To combine event hooks, use mappend or mconcat from Data.Monoid.+handleEventHook :: Event -> X All+handleEventHook _ = return (All True)+ -- | Perform an arbitrary action at xmonad startup. startupHook :: X () startupHook = return ()@@ -205,7 +218,7 @@ -- quit, or restart , ((modMask .|. shiftMask, xK_q ), io (exitWith ExitSuccess)) -- %! Quit xmonad- , ((modMask , xK_q ), restart "xmonad" True) -- %! Restart xmonad+ , ((modMask , xK_q ), spawn "xmonad --recompile && xmonad --restart") -- %! Restart xmonad ] ++ -- mod-[1..9] %! Switch to workspace N@@ -226,12 +239,12 @@ mouseBindings (XConfig {XMonad.modMask = modMask}) = M.fromList $ -- mod-button1 %! Set the window to floating mode and move by dragging [ ((modMask, button1), (\w -> focus w >> mouseMoveWindow w- >> windows W.swapMaster))+ >> windows W.shiftMaster)) -- mod-button2 %! Raise the window to the top of the stack- , ((modMask, button2), (\w -> focus w >> windows W.swapMaster))+ , ((modMask, button2), (\w -> focus w >> windows W.shiftMaster)) -- mod-button3 %! Set the window to floating mode and resize by dragging , ((modMask, button3), (\w -> focus w >> mouseResizeWindow w- >> windows W.swapMaster))+ >> windows W.shiftMaster)) -- you may also bind events to the mouse scroll wheel (button4 and button5) ] @@ -250,4 +263,5 @@ , XMonad.startupHook = startupHook , XMonad.mouseBindings = mouseBindings , XMonad.manageHook = manageHook+ , XMonad.handleEventHook = handleEventHook , XMonad.focusFollowsMouse = focusFollowsMouse }
XMonad/Core.hs view
@@ -24,29 +24,36 @@ XConf(..), XConfig(..), LayoutClass(..), Layout(..), readsLayout, Typeable, Message, SomeMessage(..), fromMessage, LayoutMessages(..),- runX, catchX, userCode, io, catchIO, doubleFork,+ runX, catchX, userCode, userCodeDef, io, catchIO, installSignalHandlers, uninstallSignalHandlers, withDisplay, withWindowSet, isRoot, runOnWorkspaces,- getAtom, spawn, getXMonadDir, recompile, trace, whenJust, whenX,+ getAtom, spawn, spawnPID, getXMonadDir, recompile, trace, whenJust, whenX, atom_WM_STATE, atom_WM_PROTOCOLS, atom_WM_DELETE_WINDOW, ManageHook, Query(..), runQuery ) where import XMonad.StackSet hiding (modify) import Prelude hiding ( catch )-import Control.Exception (catch, bracket, throw, Exception(ExitException))+import Control.Exception (catch, try, bracket, throw, finally, Exception(ExitException)) import Control.Applicative import Control.Monad.State import Control.Monad.Reader+import System.FilePath import System.IO import System.Info-import System.Posix.Process (executeFile, forkProcess, getProcessStatus, createSession)+import System.Posix.Process (executeFile, forkProcess, getAnyProcessStatus, createSession)+import System.Posix.Signals+import System.Posix.IO+import System.Posix.Types (ProcessID) import System.Process import System.Directory import System.Exit import Graphics.X11.Xlib import Graphics.X11.Xlib.Extras (Event) import Data.Typeable+import Data.List ((\\))+import Data.Maybe (isJust) import Data.Monoid+import Data.Maybe (fromMaybe) import qualified Data.Map as M import qualified Data.Set as S@@ -70,6 +77,9 @@ , buttonActions :: !(M.Map (KeyMask, Button) (Window -> X ())) -- ^ a mapping of button presses to actions , mouseFocused :: !Bool -- ^ was refocus caused by mouse action?+ , mousePosition :: !(Maybe (Position, Position))+ -- ^ position of the mouse according to+ -- the event currently being processed } -- todo, better name@@ -79,6 +89,9 @@ , terminal :: !String -- ^ The preferred terminal application. Default: \"xterm\" , layoutHook :: !(l Window) -- ^ The available layouts , manageHook :: !ManageHook -- ^ The action to run when a new window is opened+ , handleEventHook :: !(Event -> X All) -- ^ Handle an X event, returns (All True) if the default handler+ -- should also be run afterwards. mappend should be used for combining+ -- event hooks in most cases. , workspaces :: ![String] -- ^ The list of workspaces' names , numlockMask :: !KeyMask -- ^ The numlock modifier , modMask :: !KeyMask -- ^ the mod modifier@@ -117,7 +130,7 @@ -- newtype X a = X (ReaderT XConf (StateT XState IO) a) #ifndef __HADDOCK__- deriving (Functor, Monad, MonadIO, MonadState XState, MonadReader XConf)+ deriving (Functor, Monad, MonadIO, MonadState XState, MonadReader XConf, Typeable) #endif instance Applicative X where@@ -160,9 +173,14 @@ -- | Execute the argument, catching all exceptions. Either this function or -- 'catchX' should be used at all callsites of user customized code.-userCode :: X () -> X ()-userCode a = catchX (a >> return ()) (return ())+userCode :: X a -> X (Maybe a)+userCode a = catchX (Just `liftM` a) (return Nothing) +-- | Same as userCode but with a default argument to return instead of using+-- Maybe, provided for convenience.+userCodeDef :: a -> X a -> X a+userCodeDef def a = fromMaybe def `liftM` userCode a+ -- --------------------------------------------------------------------- -- Convenient wrappers to state @@ -337,19 +355,22 @@ catchIO :: MonadIO m => IO () -> m () catchIO f = io (f `catch` \e -> hPrint stderr e >> hFlush stderr) --- | spawn. Launch an external application+-- | spawn. Launch an external application. Specifically, it double-forks and+-- runs the 'String' you pass as a command to /bin/sh. spawn :: MonadIO m => String -> m ()-spawn x = doubleFork $ executeFile "/bin/sh" False ["-c", x] Nothing+spawn x = spawnPID x >> return () --- | Double fork and execute an 'IO' action (usually one of the exec family of--- functions)-doubleFork :: MonadIO m => IO () -> m ()-doubleFork m = io $ do- pid <- forkProcess $ do- forkProcess (createSession >> m)- exitWith ExitSuccess- getProcessStatus True False pid- return ()+-- | Like 'spawn', but returns the 'ProcessID' of the launched application+spawnPID :: MonadIO m => String -> m ProcessID+spawnPID x = io . forkProcess . finally nullStdin $ do+ uninstallSignalHandlers+ createSession+ executeFile "/bin/sh" False ["-c", x] Nothing+ where+ nullStdin = do+ fd <- openFd "/dev/null" ReadOnly Nothing defaultFileFlags+ dupTo fd stdInput+ closeFd fd -- | This is basically a map function, running a function in the 'X' monad on -- each workspace with the output of that function being the modified workspace.@@ -386,18 +407,25 @@ recompile force = io $ do dir <- getXMonadDir let binn = "xmonad-"++arch++"-"++os- bin = dir ++ "/" ++ binn- base = dir ++ "/" ++ "xmonad"+ bin = dir </> binn+ base = dir </> "xmonad" err = base ++ ".errors" src = base ++ ".hs"+ lib = dir </> "lib"+ libTs <- mapM getModTime . Prelude.filter isSource =<< allFiles lib srcT <- getModTime src binT <- getModTime bin- if (force || srcT > binT)+ if force || any (binT <) (srcT : libTs) then do+ -- temporarily disable SIGCHLD ignoring:+ uninstallSignalHandlers status <- bracket (openFile err WriteMode) hClose $ \h -> do- waitForProcess =<< runProcess "ghc" ["--make", "xmonad.hs", "-i", "-no-recomp", "-v0", "-o",binn] (Just dir)+ waitForProcess =<< runProcess "ghc" ["--make", "xmonad.hs", "-i", "-ilib", "-fforce-recomp", "-v0", "-o",binn] (Just dir) Nothing Nothing Nothing (Just h) + -- re-enable SIGCHLD:+ installSignalHandlers+ -- now, if it fails, run xmessage to let the user know: when (status /= ExitSuccess) $ do ghcErr <- readFile err@@ -407,10 +435,17 @@ -- nb, the ordering of printing, then forking, is crucial due to -- lazy evaluation hPutStrLn stderr msg- doubleFork $ executeFile "xmessage" True ["-default", "okay", msg] Nothing+ forkProcess $ executeFile "xmessage" True ["-default", "okay", msg] Nothing+ return () return (status == ExitSuccess) else return True where getModTime f = catch (Just <$> getModificationTime f) (const $ return Nothing)+ isSource = flip elem [".hs",".lhs",".hsc"]+ allFiles t = do+ let prep = map (t</>) . Prelude.filter (`notElem` [".",".."])+ cs <- prep <$> catch (getDirectoryContents t) (\_ -> return [])+ ds <- filterM doesDirectoryExist cs+ concat . ((cs \\ ds):) <$> mapM allFiles ds -- | Conditionally run an action, using a @Maybe a@ to decide. whenJust :: Monad m => Maybe a -> (a -> m ()) -> m ()@@ -424,3 +459,19 @@ -- be found in your .xsession-errors file trace :: MonadIO m => String -> m () trace = io . hPutStrLn stderr++-- | Ignore SIGPIPE to avoid termination when a pipe is full, and SIGCHLD to+-- avoid zombie processes, and clean up any extant zombie processes.+installSignalHandlers :: MonadIO m => m ()+installSignalHandlers = io $ do+ installHandler openEndedPipe Ignore Nothing+ installHandler sigCHLD Ignore Nothing+ try $ fix $ \more -> do+ x <- getAnyProcessStatus False False+ when (isJust x) more+ return ()++uninstallSignalHandlers :: MonadIO m => m ()+uninstallSignalHandlers = io $ do+ installHandler sigCHLD Default Nothing+ return ()
XMonad/Layout.hs view
@@ -51,7 +51,10 @@ -- | The builtin tiling mode of xmonad. Supports 'Shrink', 'Expand' and -- 'IncMasterN'.-data Tall a = Tall !Int !Rational !Rational deriving (Show, Read)+data Tall a = Tall { tallNMaster :: !Int -- ^ The default number of windows in the master pane (default: 1)+ , tallRatioIncrement :: !Rational -- ^ Percent of screen to increment by when resizing panes (default: 3/100)+ , tallRatio :: !Rational } -- ^ Default proportion of screen occupied by master pane (default: 1/2)+ deriving (Show, Read) -- TODO should be capped [0..1] .. -- a nice pure layout, lots of properties for the layout, and its messages, in Properties.hs
XMonad/Main.hsc view
@@ -22,12 +22,12 @@ import Control.Monad.Reader import Control.Monad.State import Data.Maybe (fromMaybe)+import Data.Monoid (getAll) import Foreign.C import Foreign.Ptr import System.Environment (getArgs)-import System.Posix.Signals import Graphics.X11.Xlib hiding (refreshKeyboardMapping) import Graphics.X11.Xlib.Extras@@ -57,14 +57,27 @@ xmonad initxmc = do -- setup locale information from environment withCString "" $ c_setlocale (#const LC_ALL)- -- ignore SIGPIPE- installHandler openEndedPipe Ignore Nothing+ -- ignore SIGPIPE and SIGCHLD+ installSignalHandlers -- First, wrap the layout in an existential, to keep things pretty: let xmc = initxmc { layoutHook = Layout $ layoutHook initxmc } dpy <- openDisplay "" let dflt = defaultScreen dpy rootw <- rootWindow dpy dflt++ -- If another WM is running, a BadAccess error will be returned. The+ -- default error handler will write the exception to stderr and exit with+ -- an error.+ selectInput dpy rootw $ substructureRedirectMask .|. substructureNotifyMask+ .|. enterWindowMask .|. leaveWindowMask .|. structureNotifyMask+ .|. buttonPressMask+ sync dpy False -- sync to ensure all outstanding errors are delivered++ -- turn off the default handler in favor of one that ignores all errors+ -- (ugly, I know)+ xSetErrorHandler -- in C, I'm too lazy to write the binding: dons+ xinesc <- getCleanedScreenInfo dpy nbc <- do v <- initColor dpy $ normalBorderColor xmc ~(Just nbc_) <- initColor dpy $ normalBorderColor Default.defaultConfig@@ -99,20 +112,14 @@ , focusedBorder = fbc , keyActions = keys xmc xmc , buttonActions = mouseBindings xmc xmc- , mouseFocused = False }+ , mouseFocused = False+ , mousePosition = Nothing } st = XState { windowset = initialWinset , mapped = S.empty , waitingUnmap = M.empty , dragging = Nothing } - xSetErrorHandler -- in C, I'm too lazy to write the binding: dons-- -- setup initial X environment- sync dpy False- selectInput dpy rootw $ substructureRedirectMask .|. substructureNotifyMask- .|. enterWindowMask .|. leaveWindowMask .|. structureNotifyMask- allocaXEvent $ \e -> runX cf st $ do @@ -136,12 +143,28 @@ userCode $ startupHook initxmc -- main loop, for all you HOF/recursion fans out there.- forever_ $ handle =<< io (nextEvent dpy e >> getEvent e)+ forever_ $ prehandle =<< io (nextEvent dpy e >> getEvent e) return ()- where forever_ a = a >> forever_ a+ where+ forever_ a = a >> forever_ a + -- if the event gives us the position of the pointer, set mousePosition+ prehandle e = let mouse = do guard (ev_event_type e `elem` evs)+ return (fromIntegral (ev_x_root e)+ ,fromIntegral (ev_y_root e))+ in local (\c -> c { mousePosition = mouse }) (handleWithHook e)+ evs = [ keyPress, keyRelease, enterNotify, leaveNotify+ , buttonPress, buttonRelease] ++-- | Runs handleEventHook from the configuration and runs the default handler+-- function if it returned True.+handleWithHook :: Event -> X ()+handleWithHook e = do+ evHook <- asks (handleEventHook . config)+ whenX (userCodeDef True $ getAll `fmap` evHook e) (handle e)+ -- --------------------------------------------------------------------- -- | Event handler. Map X events onto calls into Operations.hs, which -- modify our internal model of the window manager state.@@ -160,7 +183,7 @@ s <- io $ keycodeToKeysym dpy code 0 mClean <- cleanMask m ks <- asks keyActions- userCode $ whenJust (M.lookup (mClean, s) ks) id+ userCodeDef () $ whenJust (M.lookup (mClean, s) ks) id -- manage a new window handle (MapRequestEvent {ev_window = w}) = withDisplay $ \dpy -> do@@ -214,16 +237,16 @@ -- grabbed in grabButtons. Otherwise, it's click-to-focus. isr <- isRoot w m <- cleanMask $ ev_state e- ba <- asks buttonActions- if isr then userCode $ whenJust (M.lookup (m, b) ba) ($ ev_subwindow e)- else focus w+ mact <- asks (M.lookup (m, b) . buttonActions)+ case mact of+ (Just act) | isr -> act $ ev_subwindow e+ _ -> focus w broadcastMessage e -- Always send button events. -- entered a normal window: focus it if focusFollowsMouse is set to -- True in the user's config. handle e@(CrossingEvent {ev_window = w, ev_event_type = t}) | t == enterNotify && ev_mode e == notifyNormal- && ev_detail e /= notifyInferior = whenX (asks $ focusFollowsMouse . config) (focus w) -- left a window, check if we need to focus root@@ -263,7 +286,13 @@ -- property notify handle PropertyEvent { ev_event_type = t, ev_atom = a }- | t == propertyNotify && a == wM_NAME = userCode =<< asks (logHook . config)+ | t == propertyNotify && a == wM_NAME = userCodeDef () =<< asks (logHook . config)++handle e@ClientMessageEvent { ev_message_type = mt } = do+ a <- getAtom "XMONAD_RESTART"+ if (mt == a)+ then restart "xmonad" True+ else broadcastMessage e handle e = broadcastMessage e -- trace (eventName e) -- ignoring
XMonad/ManageHook.hs view
@@ -45,6 +45,8 @@ composeAll :: [ManageHook] -> ManageHook composeAll = mconcat +infix 0 -->+ -- | @p --> x@. If @p@ returns 'True', execute the 'ManageHook'. (-->) :: Query Bool -> ManageHook -> ManageHook p --> f = p >>= \b -> if b then f else mempty@@ -71,7 +73,8 @@ getProp = (internAtom d "_NET_WM_NAME" False >>= getTextProperty d w) `catch` \_ -> getTextProperty d w wM_NAME- extract = fmap head . wcTextPropertyToTextList d+ extract prop = do l <- wcTextPropertyToTextList d prop+ return $ if null l then "" else head l io $ bracket getProp (xFree . tp_value) extract `catch` \_ -> return "" -- | Return the application name.@@ -111,4 +114,4 @@ -- | Move the window to a given workspace doShift :: WorkspaceId -> ManageHook-doShift = doF . W.shift+doShift i = doF . W.shiftWin i =<< ask
XMonad/Operations.hs view
@@ -23,7 +23,7 @@ import qualified XMonad.StackSet as W import Data.Maybe-import Data.Monoid (appEndo)+import Data.Monoid (Endo(..)) import Data.List (nub, (\\), find) import Data.Bits ((.|.), (.&.), complement) import Data.Ratio@@ -68,7 +68,7 @@ where i = W.tag $ W.workspace $ W.current ws mh <- asks (manageHook . config)- g <- fmap appEndo (runQuery mh w) `catchX` return id+ g <- fmap appEndo $ userCodeDef (Endo id) (runQuery mh w) windows (g . f) -- | unmanage. A window no longer exists, remove it from the window@@ -77,14 +77,14 @@ unmanage :: Window -> X () unmanage = windows . W.delete --- | Kill the currently focused client. If we do kill it, we'll get a+-- | Kill the specified window. If we do kill it, we'll get a -- delete notify back from X. -- -- There are two ways to delete a window. Either just kill it, or if it -- supports the delete protocol, send a delete event (e.g. firefox) ---kill :: X ()-kill = withDisplay $ \d -> withFocused $ \w -> do+killWindow :: Window -> X ()+killWindow w = withDisplay $ \d -> do wmdelt <- atom_WM_DELETE_WINDOW ; wmprot <- atom_WM_PROTOCOLS protocols <- io $ getWMProtocols d w@@ -95,6 +95,10 @@ sendEvent d w False noEventMask ev else killClient d w >> return () +-- | Kill the currently focused client.+kill :: X ()+kill = withFocused killWindow+ -- --------------------------------------------------------------------- -- Managing windows @@ -120,46 +124,44 @@ -- for each workspace, layout the currently visible workspaces let allscreens = W.screens ws summed_visible = scanl (++) [] $ map (W.integrate' . W.stack . W.workspace) allscreens- visible <- fmap concat $ forM (zip allscreens summed_visible) $ \ (w, vis) -> do+ rects <- fmap concat $ forM (zip allscreens summed_visible) $ \ (w, vis) -> do let wsp = W.workspace w this = W.view n ws n = W.tag wsp- flt = filter (flip M.member (W.floating ws)) (W.index this) tiled = (W.stack . W.workspace . W.current $ this) >>= W.filter (`M.notMember` W.floating ws) >>= W.filter (`notElem` vis)- viewrect@(Rectangle sx sy sw sh) = screenRect $ W.screenDetail w+ viewrect = screenRect $ W.screenDetail w -- just the tiled windows: -- now tile the windows on this workspace, modified by the gap (rs, ml') <- runLayout wsp { W.stack = tiled } viewrect `catchX` runLayout wsp { W.stack = tiled, W.layout = Layout Full } viewrect- mapM_ (uncurry tileWindow) rs updateLayout n ml' - -- now the floating windows:- -- move/resize the floating windows, if there are any- forM_ flt $ \fw -> whenJust (M.lookup fw (W.floating ws)) $- \(W.RationalRect rx ry rw rh) -> do- tileWindow fw $ Rectangle- (sx + floor (toRational sw*rx)) (sy + floor (toRational sh*ry))- (floor (toRational sw*rw)) (floor (toRational sh*rh))+ let m = W.floating ws+ flt = [(fw, scaleRationalRect viewrect r)+ | fw <- filter (flip M.member m) (W.index this)+ , Just r <- [M.lookup fw m]]+ vs = flt ++ rs - let vs = flt ++ map fst rs- io $ restackWindows d vs+ io $ restackWindows d (map fst vs) -- return the visible windows for this workspace: return vs - whenJust (W.peek ws) $ \w -> io $ setWindowBorder d w fbc- asks (logHook . config) >>= userCode+ let visible = map fst rects - mapM_ reveal visible- setTopFocus+ mapM_ (uncurry tileWindow) rects + whenJust (W.peek ws) $ \w -> io $ setWindowBorder d w fbc+ -- hide every window that was potentially visible before, but is not -- given a position by a layout now. mapM_ hide (nub (oldvisible ++ newwindows) \\ visible) + mapM_ reveal visible+ setTopFocus+ -- all windows that are no longer in the windowset are marked as -- withdrawn, it is important to do this after the above, otherwise 'hide' -- will overwrite withdrawnState with iconicState@@ -167,7 +169,14 @@ isMouseFocused <- asks mouseFocused unless isMouseFocused $ clearEvents enterWindowMask+ asks (logHook . config) >>= userCodeDef () +-- | Produce the actual rectangle from a screen and a ratio on that screen.+scaleRationalRect :: Rectangle -> W.RationalRect -> Rectangle+scaleRationalRect (Rectangle sx sy sw sh) (W.RationalRect rx ry rw rh)+ = Rectangle (sx + scale sw rx) (sy + scale sh ry) (scale sw rw) (scale sh rh)+ where scale s r = floor (toRational s * r)+ -- | setWMState. set the WM_STATE property setWMState :: Window -> Int -> X () setWMState w v = withDisplay $ \dpy -> do@@ -294,11 +303,17 @@ -- This happens if X notices we've moved the mouse (and perhaps moved -- the mouse to a new screen). focus :: Window -> X ()-focus w = withWindowSet $ \s -> do- if W.member w s then when (W.peek s /= Just w) $ do- local (\c -> c { mouseFocused = True }) $ do- windows (W.focusWindow w)- else whenX (isRoot w) $ setFocusX w+focus w = local (\c -> c { mouseFocused = True }) $ withWindowSet $ \s -> do+ let stag = W.tag . W.workspace+ curr = stag $ W.current s+ mnew <- maybe (return Nothing) (fmap (fmap stag) . uncurry pointScreen)+ =<< asks mousePosition+ root <- asks theRoot+ case () of+ _ | W.member w s && W.peek s /= Just w -> windows (W.focusWindow w)+ | Just new <- mnew, w == root && curr /= new+ -> windows (W.view new)+ | otherwise -> return () -- | Call X to set the keyboard focus details. setFocusX :: Window -> X ()@@ -412,10 +427,9 @@ ws <- gets windowset wa <- io $ getWindowAttributes d w bw <- fi <$> asks (borderWidth . config)+ sc <- fromMaybe (W.current ws) <$> pointScreen (fi $ wa_x wa) (fi $ wa_y wa) - -- XXX horrible- let sc = fromMaybe (W.current ws) $ find (pointWithin (fi $ wa_x wa) (fi $ wa_y wa) . screenRect . W.screenDetail) $ W.screens ws- sr = screenRect . W.screenDetail $ sc+ let sr = screenRect . W.screenDetail $ sc rr = W.RationalRect ((fi (wa_x wa) - fi (rect_x sr)) % fi (rect_width sr)) ((fi (wa_y wa) - fi (rect_y sr)) % fi (rect_height sr)) (fi (wa_width wa + bw*2) % fi (rect_width sr))@@ -423,11 +437,20 @@ return (W.screen $ sc, rr) where fi x = fromIntegral x- pointWithin :: Integer -> Integer -> Rectangle -> Bool- pointWithin x y r = x >= fi (rect_x r) &&- x < fi (rect_x r) + fi (rect_width r) &&- y >= fi (rect_y r) &&- y < fi (rect_y r) + fi (rect_height r)++-- | Given a point, determine the screen (if any) that contains it.+pointScreen :: Position -> Position+ -> X (Maybe (W.Screen WorkspaceId (Layout Window) Window ScreenId ScreenDetail))+pointScreen x y = withWindowSet $ return . find p . W.screens+ where p = pointWithin x y . screenRect . W.screenDetail++-- | @pointWithin x y r@ returns 'True' if the @(x, y)@ co-ordinate is within+-- @r@.+pointWithin :: Position -> Position -> Rectangle -> Bool+pointWithin x y r = x >= rect_x r &&+ x < rect_x r + fromIntegral (rect_width r) &&+ y >= rect_y r &&+ y < rect_y r + fromIntegral (rect_height r) -- | Make a tiled window floating, using its suggested rectangle float :: Window -> X ()
XMonad/StackSet.hs view
@@ -35,14 +35,14 @@ -- * Operations on the current stack -- $stackOperations peek, index, integrate, integrate', differentiate,- focusUp, focusDown, focusMaster, focusWindow,+ focusUp, focusDown, focusUp', focusDown', focusMaster, focusWindow, tagMember, renameTag, ensureTags, member, findTag, mapWorkspace, mapLayout, -- * Modifying the stackset -- $modifyStackset insertUp, delete, delete', filter, -- * Setting the master window -- $settingMW- swapUp, swapDown, swapMaster, modify, modify', float, sink, -- needed by users+ swapUp, swapDown, swapMaster, shiftMaster, modify, modify', float, sink, -- needed by users -- * Composite operations -- $composite shift, shiftWin,@@ -52,7 +52,7 @@ ) where import Prelude hiding (filter)-import Data.Maybe (listToMaybe,fromJust,isJust)+import Data.Maybe (listToMaybe,isJust) import qualified Data.List as L (deleteBy,find,splitAt,filter,nub) import Data.List ( (\\) ) import qualified Data.Map as M (Map,insert,delete,empty)@@ -194,7 +194,8 @@ -- Xinerama: Virtual workspaces are assigned to physical screens, starting at 0. -- new :: (Integral s) => l -> [i] -> [sd] -> StackSet i l a s sd-new l wids m | not (null wids) && length m <= length wids = StackSet cur visi unseen M.empty+new l wids m | not (null wids) && length m <= length wids && not (null m)+ = StackSet cur visi unseen M.empty where (seen,unseen) = L.splitAt (length m) $ map (\i -> Workspace i l Nothing) wids (cur:visi) = [ Screen i s sd | (i, s, sd) <- zip3 seen [0..] m ] -- now zip up visibles with their screen id@@ -342,15 +343,19 @@ -- focusUp, focusDown, swapUp, swapDown :: StackSet i l a s sd -> StackSet i l a s sd focusUp = modify' focusUp'-focusDown = modify' (reverseStack . focusUp' . reverseStack)+focusDown = modify' focusDown' swapUp = modify' swapUp' swapDown = modify' (reverseStack . swapUp' . reverseStack) -focusUp', swapUp' :: Stack a -> Stack a+-- | Variants of 'focusUp' and 'focusDown' that work on a+-- 'Stack' rather than an entire 'StackSet'.+focusUp', focusDown' :: Stack a -> Stack a focusUp' (Stack t (l:ls) rs) = Stack l ls (t:rs) focusUp' (Stack t [] rs) = Stack x xs [] where (x:xs) = reverse (t:rs)+focusDown' = reverseStack . focusUp' . reverseStack +swapUp' :: Stack a -> Stack a swapUp' (Stack t (l:ls) rs) = Stack t ls (l:rs) swapUp' (Stack t [] rs) = Stack t (reverse rs) [] @@ -508,6 +513,15 @@ -- natural! keep focus, move current to the top, move top to current. +-- | /O(s)/. Set the master window to the focused window.+-- The other windows are kept in order and shifted down on the stack, as if you+-- just hit mod-shift-k a bunch of times.+-- Focus stays with the item moved.+shiftMaster :: StackSet i l a s sd -> StackSet i l a s sd+shiftMaster = modify' $ \c -> case c of+ Stack _ [] _ -> c -- already master.+ Stack t ls rs -> Stack t [] (reverse ls ++ rs)+ -- | /O(s)/. Set focus to the master window. focusMaster :: StackSet i l a s sd -> StackSet i l a s sd focusMaster = modify' $ \c -> case c of@@ -525,10 +539,7 @@ -- element on the current stack, the original stackSet is returned. -- shift :: (Ord a, Eq s, Eq i) => i -> StackSet i l a s sd -> StackSet i l a s sd-shift n s | n `tagMember` s && n /= curtag = maybe s go (peek s)- | otherwise = s- where go w = view curtag . insertUp w . view n . delete' w $ s- curtag = currentTag s+shift n s = maybe s (\w -> shiftWin n w s) (peek s) -- | /O(n)/. shiftWin. Searches for the specified window 'w' on all workspaces -- of the stackSet and moves it to stack 'n', leaving it as the focused@@ -536,13 +547,12 @@ -- focused element on that workspace. -- The actual focused workspace doesn't change. If the window is not -- found in the stackSet, the original stackSet is returned.--- TODO how does this duplicate 'shift's behaviour? shiftWin :: (Ord a, Eq a, Eq s, Eq i) => i -> a -> StackSet i l a s sd -> StackSet i l a s sd-shiftWin n w s | from == Nothing = s -- not found- | n `tagMember` s && (Just n) /= from = go- | otherwise = s- where from = findTag w s-- go = on n (insertUp w) . on (fromJust from) (delete' w) $ s- on i f = view (currentTag s) . f . view i+shiftWin n w s = case findTag w s of+ Just from | n `tagMember` s && n /= from -> go from s+ _ -> s+ where go from = onWorkspace n (insertUp w) . onWorkspace from (delete' w) +onWorkspace :: (Eq i, Eq s) => i -> (StackSet i l a s sd -> StackSet i l a s sd)+ -> (StackSet i l a s sd -> StackSet i l a s sd)+onWorkspace n f s = view (currentTag s) . f . view n $ s
man/xmonad.1 view
@@ -1,15 +1,17 @@ ./" man page created by David Lazar on April 24, 2007 ./" uses ``tmac.an'' macro set-.TH xmonad 1 "18 April 07" xmonad\-1.0 "xmonad manual"+.TH xmonad 1 "8 September 09"\+ xmonad-0.9 \+"xmonad manual" .SH NAME xmonad \- a tiling window manager .SH DESCRIPTION .PP-\fBxmonad\fR is a minimalist tiling window manager for X, written in Haskell. Windows are managed using automatic layout algorithms, which can be dynamically reconfigured. At any time windows are arranged so as to maximise the use of screen real estate. All features of the window manager are accessible purely from the keyboard: a mouse is entirely optional. \fBxmonad\fR is configured in Haskell, and custom layout algorithms may be implemented by the user in config files. A principle of \fBxmonad\fR is predictability: the user should know in advance precisely the window arrangement that will result from any action.+\fBxmonad\fR is a minimalist tiling window manager for X, written in Haskell. Windows are managed using automatic layout algorithms, which can be dynamically reconfigured. At any time windows are arranged so as to maximize the use of screen real estate. All features of the window manager are accessible purely from the keyboard: a mouse is entirely optional. \fBxmonad\fR is configured in Haskell, and custom layout algorithms may be implemented by the user in config files. A principle of \fBxmonad\fR is predictability: the user should know in advance precisely the window arrangement that will result from any action. .PP-By default, \fBxmonad\fR provides three layout algorithms: tall, wide and fullscreen. In tall or wide mode, windows are tiled and arranged to prevent overlap and maximise screen use. Sets of windows are grouped together on virtual screens, and each screen retains its own layout, which may be reconfigured dynamically. Multiple physical monitors are supported via Xinerama, allowing simultaneous display of a number of screens.+By default, \fBxmonad\fR provides three layout algorithms: tall, wide and fullscreen. In tall or wide mode, windows are tiled and arranged to prevent overlap and maximize screen use. Sets of windows are grouped together on virtual screens, and each screen retains its own layout, which may be reconfigured dynamically. Multiple physical monitors are supported via Xinerama, allowing simultaneous display of a number of screens. .PP-By utilising the expressivity of a modern functional language with a rich static type system, \fBxmonad\fR provides a complete, featureful window manager in less than 1200 lines of code, with an emphasis on correctness and robustness. Internal properties of the window manager are checked using a combination of static guarantees provided by the type system, and type-based automated testing. A benefit of this is that the code is simple to understand, and easy to modify.+By utilizing the expressivity of a modern functional language with a rich static type system, \fBxmonad\fR provides a complete, featureful window manager in less than 1200 lines of code, with an emphasis on correctness and robustness. Internal properties of the window manager are checked using a combination of static guarantees provided by the type system, and type-based automated testing. A benefit of this is that the code is simple to understand, and easy to modify. .SH USAGE .PP \fBxmonad\fR places each window into a "workspace". Each workspace can have any number of windows, which you can cycle though with mod-j and mod-k. Windows are either displayed full screen, tiled horizontally, or tiled vertically. You can toggle the layout mode with mod-space, which will cycle through the available modes.@@ -23,6 +25,8 @@ .TP \fB--recompile Recompiles your configuration in ~/.xmonad/xmonad.hs+\fB--restart+Causes the currently running xmonad process to restart .TP \fB--version Display version of \fBxmonad\fR.@@ -121,10 +125,23 @@ .SH EXAMPLES To use \fBxmonad\fR as your window manager add: .RS-xmonad+exec xmonad .RE to your \fI~/.xinitrc\fR file .SH CUSTOMIZATION \fBxmonad\fR is customized in ~/.xmonad/xmonad.hs, and then restarting with mod-q.+.PP+You can find many extensions to the core feature set in the xmonad-contrib package, available through your package manager or from http://xmonad.org/.+.SS "Modular Configuration"+As of \fBxmonad-0.9\fR, any additional Haskell modules may be placed in \fI~/.xmonad/lib/\fR are available in GHC's searchpath. Hierarchical modules are supported: for example, the file \fI~/.xmonad/lib/XMonad/Stack/MyAdditions.hs\fR could contain:+.RS+.nf++module XMonad.Stack.MyAdditions (function1) where+function1 = error "function1: Not implemented yet!"+.fi+.RE+.PP+Your xmonad.hs may then \fBimport XMonad.Stack.MyAdditions\fR as if that module was contained within \fBxmonad\fR or \fBxmonad-contrib\fR. .SH BUGS Probably. If you find any, please report them: http://code.google.com/p/xmonad/issues/list
man/xmonad.1.in view
@@ -1,15 +1,17 @@ ./" man page created by David Lazar on April 24, 2007 ./" uses ``tmac.an'' macro set-.TH xmonad 1 "18 April 07" xmonad\-1.0 "xmonad manual"+.TH xmonad 1 "8 September 09"\+___RELEASE___\+"xmonad manual" .SH NAME xmonad \- a tiling window manager .SH DESCRIPTION .PP-\fBxmonad\fR is a minimalist tiling window manager for X, written in Haskell. Windows are managed using automatic layout algorithms, which can be dynamically reconfigured. At any time windows are arranged so as to maximise the use of screen real estate. All features of the window manager are accessible purely from the keyboard: a mouse is entirely optional. \fBxmonad\fR is configured in Haskell, and custom layout algorithms may be implemented by the user in config files. A principle of \fBxmonad\fR is predictability: the user should know in advance precisely the window arrangement that will result from any action.+\fBxmonad\fR is a minimalist tiling window manager for X, written in Haskell. Windows are managed using automatic layout algorithms, which can be dynamically reconfigured. At any time windows are arranged so as to maximize the use of screen real estate. All features of the window manager are accessible purely from the keyboard: a mouse is entirely optional. \fBxmonad\fR is configured in Haskell, and custom layout algorithms may be implemented by the user in config files. A principle of \fBxmonad\fR is predictability: the user should know in advance precisely the window arrangement that will result from any action. .PP-By default, \fBxmonad\fR provides three layout algorithms: tall, wide and fullscreen. In tall or wide mode, windows are tiled and arranged to prevent overlap and maximise screen use. Sets of windows are grouped together on virtual screens, and each screen retains its own layout, which may be reconfigured dynamically. Multiple physical monitors are supported via Xinerama, allowing simultaneous display of a number of screens.+By default, \fBxmonad\fR provides three layout algorithms: tall, wide and fullscreen. In tall or wide mode, windows are tiled and arranged to prevent overlap and maximize screen use. Sets of windows are grouped together on virtual screens, and each screen retains its own layout, which may be reconfigured dynamically. Multiple physical monitors are supported via Xinerama, allowing simultaneous display of a number of screens. .PP-By utilising the expressivity of a modern functional language with a rich static type system, \fBxmonad\fR provides a complete, featureful window manager in less than 1200 lines of code, with an emphasis on correctness and robustness. Internal properties of the window manager are checked using a combination of static guarantees provided by the type system, and type-based automated testing. A benefit of this is that the code is simple to understand, and easy to modify.+By utilizing the expressivity of a modern functional language with a rich static type system, \fBxmonad\fR provides a complete, featureful window manager in less than 1200 lines of code, with an emphasis on correctness and robustness. Internal properties of the window manager are checked using a combination of static guarantees provided by the type system, and type-based automated testing. A benefit of this is that the code is simple to understand, and easy to modify. .SH USAGE .PP \fBxmonad\fR places each window into a "workspace". Each workspace can have any number of windows, which you can cycle though with mod-j and mod-k. Windows are either displayed full screen, tiled horizontally, or tiled vertically. You can toggle the layout mode with mod-space, which will cycle through the available modes.@@ -23,6 +25,8 @@ .TP \fB--recompile Recompiles your configuration in ~/.xmonad/xmonad.hs+\fB--restart+Causes the currently running xmonad process to restart .TP \fB--version Display version of \fBxmonad\fR.@@ -31,10 +35,23 @@ .SH EXAMPLES To use \fBxmonad\fR as your window manager add: .RS-xmonad+exec xmonad .RE to your \fI~/.xinitrc\fR file .SH CUSTOMIZATION \fBxmonad\fR is customized in ~/.xmonad/xmonad.hs, and then restarting with mod-q.+.PP+You can find many extensions to the core feature set in the xmonad-contrib package, available through your package manager or from http://xmonad.org/.+.SS "Modular Configuration"+As of \fBxmonad-0.9\fR, any additional Haskell modules may be placed in \fI~/.xmonad/lib/\fR are available in GHC's searchpath. Hierarchical modules are supported: for example, the file \fI~/.xmonad/lib/XMonad/Stack/MyAdditions.hs\fR could contain:+.RS+.nf++module XMonad.Stack.MyAdditions (function1) where+function1 = error "function1: Not implemented yet!"+.fi+.RE+.PP+Your xmonad.hs may then \fBimport XMonad.Stack.MyAdditions\fR as if that module was contained within \fBxmonad\fR or \fBxmonad-contrib\fR. .SH BUGS Probably. If you find any, please report them: http://code.google.com/p/xmonad/issues/list
man/xmonad.hs view
@@ -8,6 +8,7 @@ -- import XMonad+import Data.Monoid import System.Exit import qualified XMonad.StackSet as W@@ -18,6 +19,10 @@ -- myTerminal = "xterm" +-- Whether focus follows the mouse pointer.+myFocusFollowsMouse :: Bool+myFocusFollowsMouse = True+ -- Width of the window border in pixels. -- myBorderWidth = 1@@ -63,73 +68,76 @@ ------------------------------------------------------------------------ -- Key bindings. Add, modify or remove key bindings here. ---myKeys conf@(XConfig {XMonad.modMask = modMask}) = M.fromList $+myKeys conf@(XConfig {XMonad.modMask = modm}) = M.fromList $ -- launch a terminal- [ ((modMask .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf)+ [ ((modm .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf) -- launch dmenu- , ((modMask, xK_p ), spawn "exe=`dmenu_path | dmenu` && eval \"exec $exe\"")+ , ((modm, xK_p ), spawn "exe=`dmenu_path | dmenu` && eval \"exec $exe\"") -- launch gmrun- , ((modMask .|. shiftMask, xK_p ), spawn "gmrun")+ , ((modm .|. shiftMask, xK_p ), spawn "gmrun") - -- close focused window - , ((modMask .|. shiftMask, xK_c ), kill)+ -- close focused window+ , ((modm .|. shiftMask, xK_c ), kill) -- Rotate through the available layout algorithms- , ((modMask, xK_space ), sendMessage NextLayout)+ , ((modm, xK_space ), sendMessage NextLayout) -- Reset the layouts on the current workspace to default- , ((modMask .|. shiftMask, xK_space ), setLayout $ XMonad.layoutHook conf)+ , ((modm .|. shiftMask, xK_space ), setLayout $ XMonad.layoutHook conf) -- Resize viewed windows to the correct size- , ((modMask, xK_n ), refresh)+ , ((modm, xK_n ), refresh) -- Move focus to the next window- , ((modMask, xK_Tab ), windows W.focusDown)+ , ((modm, xK_Tab ), windows W.focusDown) -- Move focus to the next window- , ((modMask, xK_j ), windows W.focusDown)+ , ((modm, xK_j ), windows W.focusDown) -- Move focus to the previous window- , ((modMask, xK_k ), windows W.focusUp )+ , ((modm, xK_k ), windows W.focusUp ) -- Move focus to the master window- , ((modMask, xK_m ), windows W.focusMaster )+ , ((modm, xK_m ), windows W.focusMaster ) -- Swap the focused window and the master window- , ((modMask, xK_Return), windows W.swapMaster)+ , ((modm, xK_Return), windows W.swapMaster) -- Swap the focused window with the next window- , ((modMask .|. shiftMask, xK_j ), windows W.swapDown )+ , ((modm .|. shiftMask, xK_j ), windows W.swapDown ) -- Swap the focused window with the previous window- , ((modMask .|. shiftMask, xK_k ), windows W.swapUp )+ , ((modm .|. shiftMask, xK_k ), windows W.swapUp ) -- Shrink the master area- , ((modMask, xK_h ), sendMessage Shrink)+ , ((modm, xK_h ), sendMessage Shrink) -- Expand the master area- , ((modMask, xK_l ), sendMessage Expand)+ , ((modm, xK_l ), sendMessage Expand) -- Push window back into tiling- , ((modMask, xK_t ), withFocused $ windows . W.sink)+ , ((modm, xK_t ), withFocused $ windows . W.sink) -- Increment the number of windows in the master area- , ((modMask , xK_comma ), sendMessage (IncMasterN 1))+ , ((modm , xK_comma ), sendMessage (IncMasterN 1)) -- Deincrement the number of windows in the master area- , ((modMask , xK_period), sendMessage (IncMasterN (-1)))+ , ((modm , xK_period), sendMessage (IncMasterN (-1))) - -- toggle the status bar gap- -- TODO, update this binding with avoidStruts , ((modMask , xK_b ),+ -- Toggle the status bar gap+ -- Use this binding with avoidStruts from Hooks.ManageDocks.+ -- See also the statusBar function from Hooks.DynamicLog.+ --+ -- , ((modm , xK_b ), sendMessage ToggleStruts) -- Quit xmonad- , ((modMask .|. shiftMask, xK_q ), io (exitWith ExitSuccess))+ , ((modm .|. shiftMask, xK_q ), io (exitWith ExitSuccess)) -- Restart xmonad- , ((modMask , xK_q ), restart "xmonad" True)+ , ((modm , xK_q ), spawn "xmonad --recompile; xmonad --restart") ] ++ @@ -137,7 +145,7 @@ -- mod-[1..9], Switch to workspace N -- mod-shift-[1..9], Move client to workspace N --- [((m .|. modMask, k), windows $ f i)+ [((m .|. modm, k), windows $ f i) | (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_9] , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]] ++@@ -146,7 +154,7 @@ -- mod-{w,e,r}, Switch to physical/Xinerama screens 1, 2, or 3 -- mod-shift-{w,e,r}, Move client to screen 1, 2, or 3 --- [((m .|. modMask, key), screenWorkspace sc >>= flip whenJust (windows . f))+ [((m .|. modm, key), screenWorkspace sc >>= flip whenJust (windows . f)) | (key, sc) <- zip [xK_w, xK_e, xK_r] [0..] , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]] @@ -154,16 +162,18 @@ ------------------------------------------------------------------------ -- Mouse bindings: default actions bound to mouse events ---myMouseBindings (XConfig {XMonad.modMask = modMask}) = M.fromList $+myMouseBindings (XConfig {XMonad.modMask = modm}) = M.fromList $ -- mod-button1, Set the window to floating mode and move by dragging- [ ((modMask, button1), (\w -> focus w >> mouseMoveWindow w))+ [ ((modm, button1), (\w -> focus w >> mouseMoveWindow w+ >> windows W.shiftMaster)) -- mod-button2, Raise the window to the top of the stack- , ((modMask, button2), (\w -> focus w >> windows W.swapMaster))+ , ((modm, button2), (\w -> focus w >> windows W.shiftMaster)) -- mod-button3, Set the window to floating mode and resize by dragging- , ((modMask, button3), (\w -> focus w >> mouseResizeWindow w))+ , ((modm, button3), (\w -> focus w >> mouseResizeWindow w+ >> windows W.shiftMaster)) -- you may also bind events to the mouse scroll wheel (button4 and button5) ]@@ -214,10 +224,16 @@ , resource =? "desktop_window" --> doIgnore , resource =? "kdesktop" --> doIgnore ] --- Whether focus follows the mouse pointer.-myFocusFollowsMouse :: Bool-myFocusFollowsMouse = True+------------------------------------------------------------------------+-- Event handling +-- * EwmhDesktops users should change this to ewmhDesktopsEventHook+--+-- Defines a custom handler function for X Events. The function should+-- return (All True) if the default handler is to be run afterwards. To+-- combine event hooks use mappend or mconcat from Data.Monoid.+--+myEventHook = mempty ------------------------------------------------------------------------ -- Status bars and logging@@ -249,9 +265,9 @@ main = xmonad defaults -- A structure containing your configuration settings, overriding--- fields in the default config. Any you don't override, will +-- fields in the default config. Any you don't override, will -- use the defaults defined in xmonad/XMonad/Config.hs--- +-- -- No need to modify this. -- defaults = defaultConfig {@@ -272,6 +288,7 @@ -- hooks, layouts layoutHook = myLayout, manageHook = myManageHook,+ handleEventHook = myEventHook, logHook = myLogHook, startupHook = myStartupHook }
man/xmonad.html view
@@ -2,7 +2,7 @@ <HTML><HEAD><TITLE>Man page of xmonad</TITLE> </HEAD><BODY> <H1>xmonad</H1>-Section: xmonad manual (1)<BR>Updated: 18 April 07<BR><A HREF="#index">Index</A>+Section: xmonad manual (1)<BR>Updated: 8 September 09<BR><A HREF="#index">Index</A> <A HREF="/cgi-bin/man/man2html">Return to Main Contents</A><HR> <A NAME="lbAB"> </A>@@ -14,13 +14,13 @@ <P> -<B>xmonad</B> is a minimalist tiling window manager for X, written in Haskell. Windows are managed using automatic layout algorithms, which can be dynamically reconfigured. At any time windows are arranged so as to maximise the use of screen real estate. All features of the window manager are accessible purely from the keyboard: a mouse is entirely optional. <B>xmonad</B> is configured in Haskell, and custom layout algorithms may be implemented by the user in config files. A principle of <B>xmonad</B> is predictability: the user should know in advance precisely the window arrangement that will result from any action.+<B>xmonad</B> is a minimalist tiling window manager for X, written in Haskell. Windows are managed using automatic layout algorithms, which can be dynamically reconfigured. At any time windows are arranged so as to maximize the use of screen real estate. All features of the window manager are accessible purely from the keyboard: a mouse is entirely optional. <B>xmonad</B> is configured in Haskell, and custom layout algorithms may be implemented by the user in config files. A principle of <B>xmonad</B> is predictability: the user should know in advance precisely the window arrangement that will result from any action. <P> -By default, <B>xmonad</B> provides three layout algorithms: tall, wide and fullscreen. In tall or wide mode, windows are tiled and arranged to prevent overlap and maximise screen use. Sets of windows are grouped together on virtual screens, and each screen retains its own layout, which may be reconfigured dynamically. Multiple physical monitors are supported via Xinerama, allowing simultaneous display of a number of screens.+By default, <B>xmonad</B> provides three layout algorithms: tall, wide and fullscreen. In tall or wide mode, windows are tiled and arranged to prevent overlap and maximize screen use. Sets of windows are grouped together on virtual screens, and each screen retains its own layout, which may be reconfigured dynamically. Multiple physical monitors are supported via Xinerama, allowing simultaneous display of a number of screens. <P> -By utilising the expressivity of a modern functional language with a rich static type system, <B>xmonad</B> provides a complete, featureful window manager in less than 1200 lines of code, with an emphasis on correctness and robustness. Internal properties of the window manager are checked using a combination of static guarantees provided by the type system, and type-based automated testing. A benefit of this is that the code is simple to understand, and easy to modify.+By utilizing the expressivity of a modern functional language with a rich static type system, <B>xmonad</B> provides a complete, featureful window manager in less than 1200 lines of code, with an emphasis on correctness and robustness. Internal properties of the window manager are checked using a combination of static guarantees provided by the type system, and type-based automated testing. A benefit of this is that the code is simple to understand, and easy to modify. <A NAME="lbAD"> </A> <H2>USAGE</H2> @@ -42,6 +42,8 @@ <DL COMPACT> <DT><B>--recompile<DD> Recompiles your configuration in ~/.xmonad/xmonad.hs+--restart+Causes the currently running xmonad process to restart <DT>--version<DD> Display version of xmonad</B>. </DL>@@ -146,7 +148,7 @@ To use <B>xmonad</B> as your window manager add: <DL COMPACT><DT><DD>-xmonad+exec xmonad </DL> to your <I>~/.xinitrc</I> file@@ -154,7 +156,26 @@ <H2>CUSTOMIZATION</H2> <B>xmonad</B> is customized in ~/.xmonad/xmonad.hs, and then restarting with mod-q.+<P>++You can find many extensions to the core feature set in the xmonad-contrib package, available through your package manager or from <A HREF="http://xmonad.org/.">http://xmonad.org/.</A> <A NAME="lbAI"> </A>+<H3>Modular Configuration</H3>++As of <B>xmonad-0.9</B>, any additional Haskell modules may be placed in <I>~/.xmonad/lib/</I> are available in GHC's searchpath. Hierarchical modules are supported: for example, the file <I>~/.xmonad/lib/XMonad/Stack/MyAdditions.hs</I> could contain:+<DL COMPACT><DT><DD>+<PRE>++module XMonad.Stack.MyAdditions (function1) where+function1 = error "function1: Not implemented yet!"+</PRE>++</DL>++<P>++Your xmonad.hs may then <B>import XMonad.Stack.MyAdditions</B> as if that module was contained within <B>xmonad</B> or <B>xmonad-contrib</B>.+<A NAME="lbAJ"> </A> <H2>BUGS</H2> Probably. If you find any, please report them: <A HREF="http://code.google.com/p/xmonad/issues/list">http://code.google.com/p/xmonad/issues/list</A>@@ -172,12 +193,15 @@ </DL> <DT><A HREF="#lbAG">EXAMPLES</A><DD> <DT><A HREF="#lbAH">CUSTOMIZATION</A><DD>-<DT><A HREF="#lbAI">BUGS</A><DD>+<DL>+<DT><A HREF="#lbAI">Modular Configuration</A><DD> </DL>+<DT><A HREF="#lbAJ">BUGS</A><DD>+</DL> <HR> This document was created by <A HREF="/cgi-bin/man/man2html">man2html</A>, using the manual pages.<BR>-Time: 22:47:07 GMT, January 16, 2009+Time: 00:37:30 GMT, October 26, 2009 </BODY> </HTML>
tests/Properties.hs view
@@ -528,6 +528,18 @@ y = swapMaster x n = tag (workspace $ current y) +------------------------------------------------------------------------+-- shiftMaster++-- focus/local/idempotent same as swapMaster:+prop_shift_master_focus (x :: T) = peek x == (peek $ shiftMaster x)+prop_shift_master_local (x :: T) = hidden_spaces x == hidden_spaces (shiftMaster x)+prop_shift_master_idempotent (x :: T) = shiftMaster (shiftMaster x) == shiftMaster x+-- ordering is constant modulo the focused window:+prop_shift_master_ordering (x :: T) = case peek x of+ Nothing -> True+ Just m -> L.delete m (index x) == L.delete m (index $ shiftMaster x)+ -- --------------------------------------------------------------------- -- shiftWin @@ -932,6 +944,11 @@ ,("swapMaster is local" , mytest prop_swap_master_local) ,("swapUp is local" , mytest prop_swap_left_local) ,("swapDown is local" , mytest prop_swap_right_local)++ ,("shiftMaster id on focus", mytest prop_shift_master_focus)+ ,("shiftMaster is local", mytest prop_shift_master_local)+ ,("shiftMaster is idempotent", mytest prop_shift_master_idempotent)+ ,("shiftMaster preserves ordering", mytest prop_shift_master_ordering) ,("shift: invariant" , mytest prop_shift_I) ,("shift is reversible" , mytest prop_shift_reversible)
util/GenerateManpage.hs view
@@ -20,6 +20,13 @@ import Data.Char import Data.List +import Distribution.PackageDescription.Parse+import Distribution.Verbosity+import Distribution.Package+import Distribution.PackageDescription+import Text.PrettyPrint.HughesPJ+import Distribution.Text+ trim :: String -> String trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace @@ -42,6 +49,9 @@ replace x y = map (\a -> if a == x then y else a) main = do+ releaseName <- ((' ':) . (++" \\") . show . disp . package . packageDescription) `liftM` readPackageDescription normal "xmonad.cabal"+ troffBindings <- (concatMap troff . allBindings) `liftM` readFile "./XMonad/Config.hs"- let sed = unlines . replace "___KEYBINDINGS___" troffBindings . lines++ let sed = unlines . replace "___RELEASE___\\" releaseName . replace "___KEYBINDINGS___" troffBindings . lines readFile "./man/xmonad.1.in" >>= return . sed >>= writeFile "./man/xmonad.1"
xmonad.cabal view
@@ -1,5 +1,5 @@ name: xmonad-version: 0.8.1+version: 0.9 homepage: http://xmonad.org synopsis: A tiling window manager description:@@ -18,11 +18,13 @@ author: Spencer Janssen maintainer: xmonad@haskell.org extra-source-files: README TODO CONFIG STYLE tests/loc.hs tests/Properties.hs- man/xmonad.1.in man/xmonad.1 man/xmonad.html man/xmonad.hs+ man/xmonad.1.in man/xmonad.1 man/xmonad.html util/GenerateManpage.hs cabal-version: >= 1.2 build-type: Simple +data-files: man/xmonad.hs+ flag small_base description: Choose the new smaller, split-up base package. @@ -41,10 +43,10 @@ XMonad.StackSet if flag(small_base)- build-depends: base < 4 && >=3, containers, directory, process+ build-depends: base < 4 && >=3, containers, directory, process, filepath else build-depends: base < 3- build-depends: X11>=1.4.3, mtl, unix+ build-depends: X11>=1.4.6.1, mtl, unix ghc-options: -funbox-strict-fields -Wall ghc-prof-options: -prof -auto-all