Re: [xmonad] Strange workspace switching bug in my config

On Sun, May 13, 2012 at 8:45 AM, Norbert Zeh
Leo Alekseyev [2012.05.13 0127 -0400]:
Hi all, A couple of years back I made the following addition to my xmonad.hs: instead of 10 workspaces, it admits 20 workspaces, logically arranged in two rows of 10. I think of it as having a "scratch" workspace for every main workspace, and I use up/down arrows to switch between the main and the scratch workspace. For instance, if you are on workspace 4, Mod4-<down> will move to workspace 4SCR and Mod4-<up> will move back to workspace 4.
Recently this config started misbehaving (without any changes to xmonad.hs, but with possible changes in xmonad/GHC version to 0.10 and 7.4.1 as my system was upgraded). In particular, in the example above, now Mod4-<down> moves from workspace 4 to workspace 3SCR and Mod4-<up> then moves from 3SCR to 2. To fix it, I have to log in and out of X, but the problem always reoccurs, possibly after sleep/resume cycle(?).
The embarrassing thing here is that I haven't touched Haskell in a while, and barely grok my config anymore, so I don't know where to start troubleshooting. The code I described seems straightforward enough, so it's my hope that maybe someone here can tell me what is going on without too much effort...
The relevant parts of my config are below, and the full file in its horrifying glory is at http://hpaste.org/68453. If someone seems something obviously amiss, please shout...
--leo
myWorkspaces = ["1:terminals", "2:emacs", "3:web", "4", "5", "6", "7","8","9","0"] ++ map (\x -> show x ++ "SCR") ([1..9]++[0]) .....
zeroSub 0 = 10 zeroSub x = x
jumpToMain = gets windowset >>= \W.StackSet { W.current = W.Screen { W.workspace = w } } -> withNthWorkspace W.greedyView (-1+(zeroSub $ read [head(W.tag w)])) jumpToScratch = gets windowset >>= \W.StackSet { W.current = W.Screen { W.workspace = w } } -> withNthWorkspace W.greedyView (9+(zeroSub $ read [head(W.tag w)]))
The math here looks all wrong, and I'm surprised that it worked at all before. What you want, I think, is the following:
jumpToMain = gets (W.tag . W.workspace . W.current . windowset) >>= W.greedyView . toMain where toMain ws = [head ws]
jumpToScratch = gets (W.tag . W.workspace . W.current . windowset) >>= W.greedyView . toScratch where toScratch ws | length ws == 1 = ws ++ "SCR" | otherwise = ws
The idea here is that you simply want to add or take away the "SCR" suffix in the workspace tag or, in the latter case, do nothing if it's already present.
Hi Norbert, Yes, my original math was kind of dodgy... Your solution seems better, but it doesn't compile for me... any ideas? xmonad.hs:452:14: No instance for (MonadState XState ((->) (W.StackSet [Char] l3 a3 s3 sd3))) arising from a use of `gets' Possible fix: add an instance declaration for (MonadState XState ((->) (W.StackSet [Char] l3 a3 s3 sd3))) In the first argument of `(>>=)', namely `gets (tag . W.workspace . W.current . windowset)' In the expression: gets (tag . W.workspace . W.current . windowset) >>= W.greedyView . toMain In an equation for `jumpToMain': jumpToMain = gets (tag . W.workspace . W.current . windowset) >>= W.greedyView . toMain where toMain ws = [head ws] xmonad.hs:456:17: No instance for (MonadState XState ((->) (W.StackSet [Char] l1 a1 s1 sd1))) arising from a use of `gets' Possible fix: add an instance declaration for (MonadState XState ((->) (W.StackSet [Char] l1 a1 s1 sd1))) In the first argument of `(>>=)', namely `gets (tag . W.workspace . W.current . windowset)' In the expression: gets (tag . W.workspace . W.current . windowset) >>= W.greedyView . toScratch In an equation for `jumpToScratch': jumpToScratch = gets (tag . W.workspace . W.current . windowset) >>= W.greedyView . toScratch where toScratch ws | length ws == 1 = ws ++ "SCR" | otherwise = ws

Leo Alekseyev [2012.05.13 1923 -0400]:
Hi Norbert, Yes, my original math was kind of dodgy... Your solution seems better, but it doesn't compile for me... any ideas?
xmonad.hs:452:14: No instance for (MonadState XState ((->) (W.StackSet [Char] l3 a3 s3 sd3))) arising from a use of `gets' Possible fix: add an instance declaration for (MonadState XState ((->) (W.StackSet [Char] l3 a3 s3 sd3))) In the first argument of `(>>=)', namely `gets (tag . W.workspace . W.current . windowset)' In the expression: gets (tag . W.workspace . W.current . windowset) >>= W.greedyView . toMain In an equation for `jumpToMain': jumpToMain = gets (tag . W.workspace . W.current . windowset) >>= W.greedyView . toMain where toMain ws = [head ws]
xmonad.hs:456:17: No instance for (MonadState XState ((->) (W.StackSet [Char] l1 a1 s1 sd1))) arising from a use of `gets' Possible fix: add an instance declaration for (MonadState XState ((->) (W.StackSet [Char] l1 a1 s1 sd1))) In the first argument of `(>>=)', namely `gets (tag . W.workspace . W.current . windowset)' In the expression: gets (tag . W.workspace . W.current . windowset) >>= W.greedyView . toScratch In an equation for `jumpToScratch': jumpToScratch = gets (tag . W.workspace . W.current . windowset) >>= W.greedyView . toScratch where toScratch ws | length ws == 1 = ws ++ "SCR" | otherwise = ws
Sorry. I didn't check whether it compiles and got the type of greedyView wrong. Here's a correct (and slightly cleaner version): jumpToMain = withWindowSet (windows . W.greedyView . toMain . W.tag . W.workspace . W.current) where toMain ws = [head ws] jumpToScratch = withWindowSet (windows . W.greedyView . toScratch . W.tag . W.workspace . W.current) where toScratch ws | length ws == 1 = ws ++ "SCR" | otherwise = ws

On Sun, May 13, 2012 at 7:45 PM, Norbert Zeh
Leo Alekseyev [2012.05.13 1923 -0400]:
Hi Norbert, Yes, my original math was kind of dodgy... Your solution seems better, but it doesn't compile for me... any ideas?
Sorry. I didn't check whether it compiles and got the type of greedyView wrong. Here's a correct (and slightly cleaner version):
jumpToMain = withWindowSet (windows . W.greedyView . toMain . W.tag . W.workspace . W.current) where toMain ws = [head ws]
jumpToScratch = withWindowSet (windows . W.greedyView . toScratch . W.tag . W.workspace . W.current) where toScratch ws | length ws == 1 = ws ++ "SCR" | otherwise = ws
Yes, this is simpler and compiles, but doesn't seem to work here :( These functions appear to not do anything in my config...

Quoting Leo Alekseyev
On Sun, May 13, 2012 at 8:45 AM, Norbert Zeh
wrote: myWorkspaces = ["1:terminals", "2:emacs", "3:web", "4", "5", "6", "7","8","9","0"] ++ map (\x -> show x ++ "SCR") ([1..9]++[0]) .....
zeroSub 0 = 10 zeroSub x = x
jumpToMain = gets windowset >>= \W.StackSet { W.current = W.Screen { W.workspace = w } } -> withNthWorkspace W.greedyView (-1+(zeroSub $ read [head(W.tag w)])) jumpToScratch = gets windowset >>= \W.StackSet { W.current = W.Screen { W.workspace = w } } -> withNthWorkspace W.greedyView (9+(zeroSub $ read [head(W.tag w)]))
The math here looks all wrong, and I'm surprised that it worked at all before.
The math looks fine to me, and in fact your suggestion:
What you want, I think, is the following:
jumpToMain = gets (W.tag . W.workspace . W.current . windowset) >>= W.greedyView . toMain where toMain ws = [head ws]
jumpToScratch = gets (W.tag . W.workspace . W.current . windowset) >>= W.greedyView . toScratch where toScratch ws | length ws == 1 = ws ++ "SCR" | otherwise = ws
is the one that looks dodgy to me. Notice that his main workspace names are things like "3:web", but the SCR-version is just "3SCR"! In fact, I would humbly suggest that this paragraph:
Recently this config started misbehaving (without any changes to xmonad.hs, but with possible changes in xmonad/GHC version to 0.10 and 7.4.1 as my system was upgraded). In particular, in the example above, now Mod4-<down> moves from workspace 4 to workspace 3SCR and Mod4-<up> then moves from 3SCR to 2. To fix it, I have to log in and out of X, but the problem always reoccurs, possibly after sleep/resume cycle(?).
...suggests that the problem won't be divined just by looking at his config. Something deeper is going wrong than his Haskell abilities. I can't say I have a better suggestion, but you could check: 1. if downgrading to older display drivers fixes the problem 2. if the permissions of ~/.xmonad and its contents look reasonable (and there's free disk space there) 3. how xmonad's $PATH and your shell's $PATH compare (and hence how the ghc that xmonad sees and the ghc that your shell sees compare) You might also want to check the output of ghc-pkg check. (I don't include this in the list because I can't see a way that a broken package could lead to the behavior he's seeing.) Good luck! ~d

On Mon, May 14, 2012 at 10:19 PM,
Quoting Leo Alekseyev
: On Sun, May 13, 2012 at 8:45 AM, Norbert Zeh
wrote: The math here looks all wrong, and I'm surprised that it worked at all before.
The math looks fine to me, and in fact your suggestion:
Same here; I also note that the math would not cause it to change behavior *after suspend/resume* as reported. Something else is going on somewhere, and probably not in xmonad itself (although xmonad may be reacting to garbage reported by Xinerama by a buggy driver on resume). -- brandon s allbery allbery.b@gmail.com wandering unix systems administrator (available) (412) 475-9364 vm/sms

wagnerdm@seas.upenn.edu [2012.05.14 2219 -0400]:
Quoting Leo Alekseyev
: On Sun, May 13, 2012 at 8:45 AM, Norbert Zeh
wrote: myWorkspaces = ["1:terminals", "2:emacs", "3:web", "4", "5", "6", "7","8","9","0"] ++ map (\x -> show x ++ "SCR") ([1..9]++[0]) .....
zeroSub 0 = 10 zeroSub x = x
jumpToMain = gets windowset >>= \W.StackSet { W.current = W.Screen { W.workspace = w } } -> withNthWorkspace W.greedyView (-1+(zeroSub $ read [head(W.tag w)])) jumpToScratch = gets windowset >>= \W.StackSet { W.current = W.Screen { W.workspace = w } } -> withNthWorkspace W.greedyView (9+(zeroSub $ read [head(W.tag w)]))
The math here looks all wrong, and I'm surprised that it worked at all before.
The math looks fine to me, and in fact your suggestion:
What you want, I think, is the following:
jumpToMain = gets (W.tag . W.workspace . W.current . windowset) >>= W.greedyView . toMain where toMain ws = [head ws]
jumpToScratch = gets (W.tag . W.workspace . W.current . windowset) >>= W.greedyView . toScratch where toScratch ws | length ws == 1 = ws ++ "SCR" | otherwise = ws
is the one that looks dodgy to me. Notice that his main workspace names are things like "3:web", but the SCR-version is just "3SCR"! In fact, I would humbly suggest that this paragraph:
Oops. I overlooked that the primary workspaces were not just numbered. My bad. I still don't get the math in the original code snippet. zeroSub has an effect only when its argument is 0. So, for any starting workspace except "0" or "0SCR", say its number is x, the above code goes to workspace x-1 or x+9. It should, however, go to workspace x-10 or x+10 and that conditionally on whether the main/scratch workspace is already visible. What is it I don't understand here? Cheers, Norbert

Quoting Norbert Zeh
for any starting workspace except "0" or "0SCR", say its number is x, the above code goes to workspace x-1 or x+9. ... What is it I don't understand here?
The workspace at index 0 in the list of workspaces is "1:blah", at index 1 is "2:blah", etc. ~d

On Tue, May 15, 2012 at 4:22 PM,
Quoting Norbert Zeh
: for any starting workspace except "0" or "0SCR", say its number is x, the above code goes to workspace x-1 or x+9. ...
What is it I don't understand here?
The workspace at index 0 in the list of workspaces is "1:blah", at index 1 is "2:blah", etc.
...and it seems that this ordering gets screwed up for me! Everything works fine, then I head over to a cafe, resume my laptop from sleep, and bam, the workspace offsets are wrong again. This only started happening after an upgrade to Ubuntu 12.04, although I'm not sure how that would make a difference. --l

On Tue, May 15, 2012 at 5:32 PM, Leo Alekseyev
On Tue, May 15, 2012 at 4:22 PM,
wrote: Quoting Norbert Zeh
: for any starting workspace except "0" or "0SCR", say its number is x, the above code goes to workspace x-1 or x+9. ...
What is it I don't understand here?
The workspace at index 0 in the list of workspaces is "1:blah", at index 1 is "2:blah", etc.
Well, if anyone is curious, I've isolated the breakage to the floating scratchpad workspace. It appears that after the first time the scratchpad is spawned, its workspace (with the tag NSP) is inserted at index 0 in the workspace array. I'm assuming that it used to not be the case with older Xmonad versions...

Leo Alekseyev [2012.05.18 0228 -0400]:
On Tue, May 15, 2012 at 5:32 PM, Leo Alekseyev
wrote: On Tue, May 15, 2012 at 4:22 PM,
wrote: Quoting Norbert Zeh
: for any starting workspace except "0" or "0SCR", say its number is x, the above code goes to workspace x-1 or x+9. ...
What is it I don't understand here?
The workspace at index 0 in the list of workspaces is "1:blah", at index 1 is "2:blah", etc.
Well, if anyone is curious, I've isolated the breakage to the floating scratchpad workspace. It appears that after the first time the scratchpad is spawned, its workspace (with the tag NSP) is inserted at index 0 in the workspace array. I'm assuming that it used to not be the case with older Xmonad versions...
Ah, that explains it. Here's a piece of code that makes the whole process independent of the actual ordering of the workspaces (something that my previous broken suggestion also tried to do). jumpToMain = do num <- gets (head . W.tag . W.workspace . W.current . windowset) ws <- asks (workspaces . config) let m = find (\w -> head w == num && w /= (num : "SCR")) ws windows (W.greedyView $ fromJust m) jumpToScratch = do num <- gets (head . W.tag . W.workspace . W.current . windowset) windows (W.greedyView $ num : "SCR") This should work whenever you have pairs of workspaces of the form "<x>SCR" and "<x><something else>" and these are the only workspaces that start with <x>. It will do nothing for workspaces that are not paired with a corresponding "<x>SCR". If you modify your config so you have an "<x>SCR" and no other workspace that starts with <x>, then the last line of jumpToMain will throw an error. In that situation, you should change this line to "maybe (return ()) (windows . W.greedyView) m". jumpToMain then quietly does nothing if it cannot find a workspace starting with <x> other than "<x>SCR". I hope I didn't once again overlook something, as I didn't have the time to actually set up my environment to test this. At least it compiled once I added it to my xmonad.hs. Cheers, Norbert
participants (4)
-
Brandon Allbery
-
Leo Alekseyev
-
Norbert Zeh
-
wagnerdm@seas.upenn.edu