
26 Mar
2023
26 Mar
'23
12:59 p.m.
That makes sense, thanks again. I've revisited my initial approach, but might also take a stab at storing a cursors-like tree in extensibleState. In case it's of interest, this is a somewhat minimal config demonstrating the approach I'm revisiting: https://github.com/ivanbrennan/xmonad-testing/commit/8ff9e594d55885b0b2915fee71b1cd5f61598aa0#diff-74b618a2356f7943b297a5769de732a94848295a4bd563c68f998eafb843dd36 On Sun, Mar 26, 2023 at 12:21 AM Platon Pronkowrote: > Yes, you are right, my original analysis was incorrect. WorkspaceCursors > does indeed store a tree of cursors, and that is not derivable from the > current workspace id. > > However I still think that storing cursors state in LayoutModifier is > incorrect - layout information is local for every workspace, while cursors > state should be global, not duplicated per every workspace (I can't prove > it, but I definitely feel that there are bugs lurking in WorkspaceCursors > because of that duplication). > > I think you can achieve what you need without using WorkspaceCursors as a > layout modifier. You can store cursors state in a global variable and work > with it yourself. Something like: > > cursors = unsafePerformIO $ newIORef $ makeCursors [nominalIds, groupIds] > > (if you don't like unsafePerformIO, you also store cursors inside XMonad's > XState.extensibleState) > > Unfortunately you won't be able to reuse most of WorkspaceCursors stack > management functions, because they are either private or call modifyCursors > directly or indirectly. You'll have to copy them and adapt them to work on > your cursors state. > > -- > Best regards, > Platon Pronko > PGP 2A62D77A7A2CB94E > > On 2023-03-26 09:49, ivan wrote: > > Following up on this: > > > >> In my opinion WorkspaceCursors doesn't need to be a LayoutModifier at > all > > - current state can be derived from the list of cursors and currently > > focused workspace, no need to store it somewhere. > > > > I've been using WorkspaceCursors to switch between (simulated) groups of > > workspaces, relying on the Cursors state to remember which workspace has > > focus within each group. So switching to group G will focus whichever > > workspace was focused last time I visited that group. (Or, if it's the > > first time I've visited that group, its first workspace gets focus). > > > > The Cursors state feels like a natural way to implement that, but it's > not > > the only way. My initial implementation treated StackSet.workspaces as a > > recency list, and switching to group G meant finding the first workspace > in > > that list that was a member of G. When I started using Cursors state > > instead, I ran into the problem you explained. > > > > For now, I'll revisit my initial approach. > > > > Thanks again! > > > > On Sat, Mar 25, 2023 at 8:15 AM ivan wrote: > > > >> Amazing! Thank you so much for the clear explanation. > >> > >> On Sat, Mar 25, 2023 at 4:26 AM Platon Pronko > >> wrote: > >> > >>> Hi! > >>> > >>> WorkspaceCursors doesn't introduce any groups, it's just a glorified > >>> workspace switcher - underneath all the chrome it uses the standard > flat > >>> workspaces list. In essense it just defines some helper functions that > >>> allow user to imagine that workspaces are arranged as a > multidimensional > >>> cube and navigate along axes of said cube. But it still does it using > the > >>> usual StackSet.greedyView function. > >>> > >>> MultiToggle is irrelevant in this case, the same effect can be seen > with > >>> the boring Choose layout combinator (i.e. `Tall ||| Full`) - the layout > >>> state is "spilling" over to other workspaces. > >>> > >>> It seems that the problem arises because WorspaceCursors calls > `windows $ > >>> greedyView` inside LayoutClass.handleMessage function - current > workspace > >>> is switched at the same time as layout is updated, and Xmonad assigns > the > >>> updated layout to the new workspace. > >>> > >>> Here's a reproducer (should work on all configs that have a workspace > >>> with id "4"): > >>> > >>> ``` > >>> -- necessary language pragmas > >>> {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} > >>> > >>> -- imports > >>> import qualified XMonad.StackSet as W > >>> import XMonad.Layout.LayoutModifier(ModifiedLayout(..), > >>> LayoutModifier(handleMess)) > >>> import XMonad(Message, X, windows, sendMessage, fromMessage) > >>> > >>> -- Example LayoutModifier that showcases the issue. > >>> -- It does nothing except calling `greedyView "4"` upon reciept of > >>> SwitchWorkspace message > >>> data BadLayoutModifier a = BadLayoutModifier deriving (Read, Show) > >>> > >>> data SwitchWorkspace = SwitchWorkspace > >>> instance Message SwitchWorkspace > >>> > >>> instance LayoutModifier BadLayoutModifier a where > >>> handleMess BadLayoutModifier m = do > >>> case fromMessage m of > >>> Just SwitchWorkspace -> do > >>> windows $ W.greedyView "4" > >>> return $ Just BadLayoutModifier > >>> Nothing -> return Nothing > >>> > >>> -- add to keys (tweak the keybinding to your taste) > >>> , ((modm, xK_v), sendMessage SwitchWorkspace) > >>> > >>> -- prepend BadLayoutModifier to layoutHook > >>> layoutHook = > >>> ModifiedLayout BadLayoutModifier $ > >>> (Tall 1 (3/100) (1/2) ||| Full) > >>> ``` > >>> > >>> Steps to reproduce: > >>> > >>> 1. Recompile and restart Xmonad. > >>> 2. Toggle workspace "2" to "Tall" layout, toggle workspace "4" to > "Full" > >>> layout. > >>> 3. Switch to workspace "2". > >>> 4. Press keybinding to send the SwitchWorkspace message (Super-v in my > >>> case). > >>> 5. Observe that Xmonad switches to workspace "4", and layout on that > >>> workspace is now "Tall" instead of "Full" as set up originally. > >>> > >>> In my opinion WorkspaceCursors doesn't need to be a LayoutModifier at > all > >>> - current state can be derived from the list of cursors and currently > >>> focused workspace, no need to store it somewhere. This will sidestep > the > >>> problem of calling `greedyView` during layout update. > >>> > >>> -- > >>> Best regards, > >>> Platon Pronko > >>> PGP 2A62D77A7A2CB94E > >>> > >>> On 2023-03-24 23:27, Brandon Allbery wrote: > >>>> My guess is that MultiToggle doesn't and can't know about > >>>> WorkspaceCursors, and WorkspaceCursors doesn't and can't know that it > >>>> needs to duplicate the layout state for each group it introduces, so > >>>> any layout state change applies to all groups. > >>>> > >>>> On Fri, Mar 24, 2023 at 11:22 AM ivan wrote: > >>>>> > >>>>> Hi, I'm trying to get MultiToggle and WorkspaceCursors to play nicely > >>> with each other. > >>>>> > >>>>> Ordinarily, MultiToggle lets you apply a layout transformation to the > >>> current workspace without affecting the layouts of other workspaces. > E.g. > >>> if I toggle workspace 1 to Full layout, it won't impact the layouts > being > >>> used on workspaces 2, 3, etc. > >>>>> > >>>>> I've started using WorkspaceCursors (XMonad.Actions.WorkspaceCursors) > >>> to manage independent groups of workspaces, and noticed that if I use > it's > >>> functions (e.g. modifyLayer) to navigate between workspaces, layout > toggle > >>> states seem to bleed across workspaces rather than remaining > independent > >>> per workspace. > >>>>> > >>>>> For example, starting on workspace 1 with my regular Tall layout, I > >>> navigate to workspace 2 and toggle it to Full layout. Then I go back to > >>> workspace 1 and see that it, too, has been toggled to Full layout. > >>>>> > >>>>> I can't figure out exactly what's causing this, or how to fix it so > >>> that workspace layouts toggle independently. I'm hoping someone here > sees > >>> what I'm missing. > >>>>> > >>>>> I put together a minimal config to reproduce the problem: > >>>>> > >>> > https://github.com/ivanbrennan/xmonad-testing/commit/2e9541b0937eee31ae7f300e130dc55a9c5933af#diff-61bfccbc988708bd118b33f9299c64aa8b3e532e25cc8eaa3b716f53215fb196 > >>>>> > >>>>> The config provides two groups (A and B) of nine workspaces. > >>>>> > >>>>> group A: 1A 2A 3A 4A 5A 6A 7A 8A 9A > >>>>> group B: 1B 2B 3B 4B 5B 6B 7B 8B 9B > >>>>> > >>>>> Its layoutHook consists of: > >>>>> > >>>>> myLayoutHook = > >>>>> workspaceCursors cursors > >>>>> . avoidStruts > >>>>> . mkToggle1 FULL > >>>>> $ Tall 1 (3/100) (1/2) > >>>>> > >>>>> Keys super+1 .. super+9 use WorkspaceCursors functions to switch > >>> between workspaces within the currently active group. > >>>>> > >>>>> Keys super+ctrl+1 .. super+ctrl+2 use WorkspaceCursors functions to > >>> switch between groups A and B. > >>>>> > >>>>> Additionally, keys super+meta+1 .. super+meta+9 use traditional > >>> StackSet functions to switch between workspaces 1A .. 9A. I added > these for > >>> comparison, showing that MultiToggle state is recognized per-workspace > when > >>> using this form of navigation. > >>>>> > >>>>> I can't figure out the root cause. I suspect the most relevant pieces > >>> of code from WorkspaceCursors and MultiToggle are the following: > >>>>> > >>>>> > >>> > https://github.com/xmonad/xmonad-contrib/blob/e60805bd45ca2feb9ef3335d023daae5d02dbf4f/XMonad/Actions/WorkspaceCursors.hs#L204-L215 > >>>>> > >>>>> > >>> > https://github.com/xmonad/xmonad-contrib/blob/e60805bd45ca2feb9ef3335d023daae5d02dbf4f/XMonad/Layout/MultiToggle.hs#L193-L218 > >>>>> > >>>>> Does anyone know what I might be missing, or how I could debug > further > >>> to get to the root of the problem? > >>>>> > >>>>> Thanks! > >>>>> Ivan > >>>>> _______________________________________________ > >>>>> xmonad mailing list > >>>>> xmonad@haskell.org > >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/xmonad > >>>> > >>>> > >>>> > >>> > >> > > >