summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDon Stewart <dons@cse.unsw.edu.au>2007-06-05 06:30:40 +0200
committerDon Stewart <dons@cse.unsw.edu.au>2007-06-05 06:30:40 +0200
commit8cd2199c6ba396c85e1e09289436d8d02686e217 (patch)
treedca25d1ff5da7a1fd853fa9e28b6fdd3336b03a9
parent5257254d689b9f341d6c5bd151cd868a3966aaed (diff)
downloadmetatile-8cd2199c6ba396c85e1e09289436d8d02686e217.tar
metatile-8cd2199c6ba396c85e1e09289436d8d02686e217.zip
Fix lost eventNotifyMask bug
When resuming, we were (implicitly) relying on 'scan' to find all windows, and reset their event masks and WM_STATE. When we moved to Iconfified hidden workspaces, 'scan' would only find and reset states on the current workspace. The result being that hidden workspace windows no longer received enterNotify events. Fix this by traversing the StackSet serialised during a restart, setting the intial X states for each window, whether visible or hidden. darcs-hash:20070605043040-9c5c1-642f02a61a3e1d4679fde9c38eeb10aec53ea455
-rw-r--r--Main.hs27
-rw-r--r--Operations.hs33
2 files changed, 46 insertions, 14 deletions
diff --git a/Main.hs b/Main.hs
index 79b92bf..89d07e0 100644
--- a/Main.hs
+++ b/Main.hs
@@ -27,8 +27,11 @@ import Graphics.X11.Xinerama (getScreenInfo)
import XMonad
import Config
import StackSet (new, floating, member)
+import qualified StackSet as W
import Operations
+import System.IO
+
--
-- The main entry point
--
@@ -47,6 +50,7 @@ main = do
let winset | ("--resume" : s : _) <- args
, [(x, "")] <- reads s = x
| otherwise = new (fromIntegral workspaces) (fromIntegral $ length xinesc)
+
safeLayouts = case defaultLayouts of [] -> (full, []); (x:xs) -> (x, xs)
cf = XConf
{ display = dpy
@@ -71,14 +75,27 @@ main = do
sync dpy False
- ws <- scan dpy rootw
+ ws <- scan dpy rootw -- on the resume case, will pick up new windows
allocaXEvent $ \e ->
runX cf st $ do
- mapM_ manage ws
+
+ -- walk workspace, resetting X states/mask for windows
+ -- TODO, general iterators for these lists.
+ sequence_ [ setInitialProperties w >> reveal w
+ | wk <- map W.workspace (W.current winset : W.visible winset)
+ , w <- W.integrate (W.stack wk) ]
+
+ sequence_ [ setInitialProperties w >> hide w
+ | wk <- W.hidden winset
+ , w <- W.integrate (W.stack wk) ]
+
+ mapM_ manage ws -- find new windows
-- withWindowSet (io . hPrint stderr) -- uncomment for state logging
-- main loop, for all you HOF/recursion fans out there.
- forever $ handle =<< io (nextEvent dpy e >> getEvent e)
+ forever $ do x <- io (nextEvent dpy e >> getEvent e)
+ io (hPrint stderr (eventName x, x))
+ handle x
where forever a = a >> forever a
@@ -86,12 +103,12 @@ main = do
-- IO stuff. Doesn't require any X state
-- Most of these things run only on startup (bar grabkeys)
--- | scan for any initial windows to manage
+-- | scan for any new windows to manage. If they're already managed,
+-- this should be idempotent.
scan :: Display -> Window -> IO [Window]
scan dpy rootw = do
(_, _, ws) <- queryTree dpy rootw
filterM ok ws
-
where ok w = do wa <- getWindowAttributes dpy w
return $ not (wa_override_redirect wa)
&& wa_map_state wa == waIsViewable
diff --git a/Operations.hs b/Operations.hs
index 4ac14fd..93c0da0 100644
--- a/Operations.hs
+++ b/Operations.hs
@@ -36,13 +36,14 @@ import Graphics.X11.Xlib.Extras
-- Window manager operations
-- | manage. Add a new window to be managed in the current workspace.
--- Bring it into focus. If the window is already managed, nothing happens.
+-- Bring it into focus.
+--
+-- Whether the window is already managed, or not, it is mapped, has its
+-- border set, and its event mask set.
--
manage :: Window -> X ()
manage w = withDisplay $ \d -> do
- io $ selectInput d w $ structureNotifyMask .|. enterWindowMask .|. propertyChangeMask
- io $ mapWindow d w
- io $ setWindowBorderWidth d w borderWidth
+ setInitialProperties w >> reveal w
-- FIXME: This is pretty awkward. We can't can't let "refresh" happen
-- before the call to float, because that will resize the window and
@@ -60,6 +61,9 @@ manage w = withDisplay $ \d -> do
-- FIXME: clearFloating should be taken care of in W.delete, but if we do it
-- there, floating status is lost when moving windows between workspaces,
-- because W.shift calls W.delete.
+--
+-- should also unmap?
+--
unmanage :: Window -> X ()
unmanage w = setWMState w 0 {-withdrawn-} >> windows (W.sink w . W.delete w)
@@ -183,12 +187,25 @@ setWMState w v = withDisplay $ \dpy -> do
a <- atom_WM_STATE
io $ changeProperty32 dpy w a a propModeReplace [fromIntegral v, fromIntegral none]
--- | hide. Hide a window by unmapping it.
+-- | hide. Hide a window by unmapping it, and setting Iconified.
hide :: Window -> X ()
-hide w = withDisplay $ \d -> do
+hide w = withDisplay $ \d -> do
io $ unmapWindow d w
setWMState w 3 --iconic
+-- | reveal. Show a window by mapping it and setting Normal
+-- this is harmless if the window was already visible
+reveal :: Window -> X ()
+reveal w = withDisplay $ \d -> do
+ setWMState w 1 --normal
+ io $ mapWindow d w
+
+-- | Set some properties when we initially gain control of a window
+setInitialProperties :: Window -> X ()
+setInitialProperties w = withDisplay $ \d -> io $ do
+ selectInput d w $ structureNotifyMask .|. enterWindowMask .|. propertyChangeMask
+ setWindowBorderWidth d w borderWidth
+
-- | refresh. Render the currently visible workspaces, as determined by
-- the StackSet. Also, set focus to the focused window.
--
@@ -213,9 +230,7 @@ tileWindow w r = withDisplay $ \d -> do
bw <- (fromIntegral . wa_border_width) `liftM` io (getWindowAttributes d w)
io $ moveResizeWindow d w (rect_x r) (rect_y r)
(rect_width r - bw*2) (rect_height r - bw*2)
- -- this is harmless if the window was already visible
- setWMState w 1 --normal
- io $ mapWindow d w
+ reveal w
-- ---------------------------------------------------------------------