basic xinerama support (depends on Graphics.X11.Xinerama in X11-extras)

This commit is contained in:
Jason Creighton
2007-03-17 23:49:04 +00:00
parent 397cdbda0e
commit bb43b2ad6f
3 changed files with 47 additions and 19 deletions

53
Main.hs
View File

@@ -14,6 +14,7 @@
-- --
import Data.List import Data.List
import Data.Maybe
import Data.Bits hiding (rotate) import Data.Bits hiding (rotate)
import qualified Data.Map as M import qualified Data.Map as M
@@ -22,6 +23,7 @@ import System.Exit
import Graphics.X11.Xlib import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras import Graphics.X11.Xlib.Extras
import Graphics.X11.Xinerama
import Control.Monad.State import Control.Monad.State
@@ -69,10 +71,13 @@ main = do
rootw <- rootWindow dpy dflt rootw <- rootWindow dpy dflt
wmdelt <- internAtom dpy "WM_DELETE_WINDOW" False wmdelt <- internAtom dpy "WM_DELETE_WINDOW" False
wmprot <- internAtom dpy "WM_PROTOCOLS" False wmprot <- internAtom dpy "WM_PROTOCOLS" False
xinesc <- getScreenInfo dpy
let st = XState let st = XState
{ display = dpy { display = dpy
, screen = dflt , screen = dflt
, xineScreens = xinesc
, wsOnScreen = M.fromList $ map ((\n -> (n,n)) . fromIntegral . xsi_screen_number) xinesc
, theRoot = rootw , theRoot = rootw
, wmdelete = wmdelt , wmdelete = wmdelt
, wmprotocols = wmprot , wmprotocols = wmprot
@@ -176,10 +181,11 @@ handle e@(MappingNotifyEvent {window = w}) = do
handle e@(CrossingEvent {window = w, event_type = t}) handle e@(CrossingEvent {window = w, event_type = t})
| t == enterNotify && mode e == notifyNormal && detail e /= notifyInferior | t == enterNotify && mode e == notifyNormal && detail e /= notifyInferior
= do ws <- gets workspace = do ws <- gets workspace
if W.member w ws case W.lookup w ws of
then setFocus w Just n -> do setFocus w
else do b <- isRoot w windows $ W.view n
when b setTopFocus Nothing -> do b <- isRoot w
when b setTopFocus
-- left a window, check if we need to focus root -- left a window, check if we need to focus root
handle e@(CrossingEvent {event_type = t}) handle e@(CrossingEvent {event_type = t})
@@ -217,10 +223,17 @@ handle e = trace (eventName e) -- ignoring
refresh :: X () refresh :: X ()
refresh = do refresh = do
ws <- gets workspace ws <- gets workspace
whenJust (W.peek ws) $ \w -> withDisplay $ \d -> do ws2sc <- gets wsOnScreen
(sw,sh) <- gets dimensions xinesc <- gets xineScreens
io $ do moveResizeWindow d w 0 0 (fromIntegral sw) (fromIntegral sh) -- fullscreen forM_ (M.assocs ws2sc) $ \(n, scn) ->
raiseWindow d w whenJust (listToMaybe $ W.index n ws) $ \w -> withDisplay $ \d -> do
let sc = xinesc !! scn
io $ do moveResizeWindow d w (fromIntegral $ xsi_x_org sc)
(fromIntegral $ xsi_y_org sc)
(fromIntegral $ xsi_width sc)
(fromIntegral $ xsi_height sc) -- fullscreen
raiseWindow d w
whenJust (W.peek ws) setFocus
-- | windows. Modify the current window list with a pure function, and refresh -- | windows. Modify the current window list with a pure function, and refresh
windows :: (WorkSpace -> WorkSpace) -> X () windows :: (WorkSpace -> WorkSpace) -> X ()
@@ -230,16 +243,12 @@ windows f = do
ws <- gets workspace ws <- gets workspace
trace (show ws) -- log state changes to stderr trace (show ws) -- log state changes to stderr
-- | hide. Hide a list of windows by moving them offscreen. -- | hide. Hide a window by moving it offscreen.
hide :: Window -> X () hide :: Window -> X ()
hide w = withDisplay $ \d -> do hide w = withDisplay $ \d -> do
(sw,sh) <- gets dimensions (sw,sh) <- gets dimensions
io $ moveWindow d w (2*fromIntegral sw) (2*fromIntegral sh) io $ moveWindow d w (2*fromIntegral sw) (2*fromIntegral sh)
-- | reveal. Expose a list of windows, moving them on screen
reveal :: Window -> X ()
reveal w = withDisplay $ \d -> io $ moveWindow d w 0 0
-- --------------------------------------------------------------------- -- ---------------------------------------------------------------------
-- Window operations -- Window operations
@@ -312,7 +321,7 @@ tag o = do
let m = W.current ws let m = W.current ws
when (n /= m) $ when (n /= m) $
whenJust (W.peek ws) $ \w -> do whenJust (W.peek ws) $ \w -> do
hide w hide w
windows $ W.shift n windows $ W.shift n
where n = o-1 where n = o-1
@@ -320,14 +329,22 @@ tag o = do
view :: Int -> X () view :: Int -> X ()
view o = do view o = do
ws <- gets workspace ws <- gets workspace
ws2sc <- gets wsOnScreen
let m = W.current ws let m = W.current ws
when (n /= m) $ do when (n /= m) $ do
mapM_ reveal (W.index n ws) -- is the workspace we want to switch to currently visible?
mapM_ hide (W.index m ws) if M.member n ws2sc
windows $ W.view n then windows $ W.view n
else do
-- This assumes that the current workspace is visible.
-- Is that always going to be true?
let Just curscreen = M.lookup m ws2sc
modify $ \s -> s { wsOnScreen = M.insert n curscreen (M.delete m ws2sc) }
windows $ W.view n
mapM_ hide (W.index m ws)
setTopFocus
where n = o-1 where n = o-1
-- | True if window is under management by us -- | True if window is under management by us
isClient :: Window -> X Bool isClient :: Window -> X Bool
isClient w = liftM (W.member w) (gets workspace) isClient w = liftM (W.member w) (gets workspace)

View File

@@ -61,6 +61,10 @@ empty n = StackSet { current = 0
member :: Ord a => a -> StackSet a -> Bool member :: Ord a => a -> StackSet a -> Bool
member a w = M.member a (cache w) member a w = M.member a (cache w)
-- | /O(log n)/. Looks up the stack that x is in, if it is in the StackSet
lookup :: (Monad m, Ord a) => a -> StackSet a -> m Int
lookup x w = M.lookup x (cache w)
-- | /O(n)/. Number of stacks -- | /O(n)/. Number of stacks
size :: StackSet a -> Int size :: StackSet a -> Int
size = M.size . stacks size = M.size . stacks

View File

@@ -15,7 +15,7 @@
-- --
module XMonad ( module XMonad (
X, WorkSpace, XState(..),runX, X, WorkSpace, XState(..), runX,
io, withDisplay, isRoot, io, withDisplay, isRoot,
spawn, trace, whenJust spawn, trace, whenJust
) where ) where
@@ -28,11 +28,18 @@ import System.Posix.Process (executeFile, forkProcess, getProcessStatus)
import System.Exit import System.Exit
import Graphics.X11.Xlib import Graphics.X11.Xlib
import Graphics.X11.Xinerama
import qualified Data.Map as M
-- | XState, the window manager state. -- | XState, the window manager state.
-- Just the display, width, height and a window list -- Just the display, width, height and a window list
data XState = XState data XState = XState
{ display :: Display { display :: Display
, screen :: {-# UNPACK #-} !ScreenNumber , screen :: {-# UNPACK #-} !ScreenNumber
, xineScreens :: {-# UNPACK #-} ![XineramaScreenInfo]
-- a mapping of workspaces to xinerama screen numbers
, wsOnScreen :: {-# UNPACK #-} !(M.Map Int Int)
, theRoot :: {-# UNPACK #-} !Window , theRoot :: {-# UNPACK #-} !Window
, wmdelete :: {-# UNPACK #-} !Atom , wmdelete :: {-# UNPACK #-} !Atom
, wmprotocols :: {-# UNPACK #-} !Atom , wmprotocols :: {-# UNPACK #-} !Atom