Is there a way to merge a newly spawned window into a sublayout/group? Preferably if already focued on the group.
Problem Description
Someone made a reddit post asking something very similar 11 days ago, with no responses (except me and himself): https://www.reddit.com/r/xmonad/comments/ib0mx7/merge_spawned_window_into_sublayout/ He specifically wanted to make a keybinding that basically does this behavior for his terminal using subtabbed.
Personally, I would want it where if you're already focused on a group of tabs, then any newly spawned windows (whether it be terminals or whatever) would immediately get added to the tabbed group.
Is there any way currently to do either of these ideas?
Configuration File
Here's the parts of my config file that are related to my subtabbed layout, both the keybindings (that are related) and layout hook:
, ("M-h", windows W.swapUp) -- Move up in stack
, ("M-j", focusUp)-- Focus down in stack (skips any tabs)
, ("M-k", focusDown) -- Focus up in stack (skips any tabs)
, ("M-l", windows W.swapDown) -- Move down in stack
, ("M-C-h", withFocused (sendMessage . mergeDir W.focusUp')) -- Merge up
, ("M-C-j", onGroup W.focusUp') -- Switch focus up tabs
, ("M-C-k", onGroup W.focusDown') -- Switch focus down tabs
, ("M-C-l", withFocused (sendMessage . mergeDir W.focusDown')) -- Merge Down
, ("M-C-t", withFocused (sendMessage . UnMerge)) -- Untab current window
myLayout =
--spacingRaw False (Border 10 0 10 0) True (Border 0 10 0 10) True $
addTabs shrinkText myTabConfig $
subLayout [0] (Simplest) $
boringWindows $
ResizableTall 1 (3/100) (1/2) []
where
myTabConfig = def { fontName = "xft:monospace:size=10" }
So, to update this issue, the OP of that reddit thread came up with something that almost works:
, ("M-<Return>", spawn (terminal c) >> withFocused (sendMessage . mergeDir W.focusUp'))
The issue with this is, for whatever reason, the mergeDir gets run then the new terminal window spawns. Very strange to me that it works like that.
I was wondering if there was a hook module that would help run this. Like there is this module: https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Hooks-InsertPosition.html for controlling what position a new window starts in. Is there not a module that can run the mergeDir command for every new window? Maybe this module: https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Hooks-ManageHelpers.html
I'm hoping that running this with a hook solves the issue of the mergeDir occurring before the new window spawns (since obviously we want it to happen afterwards).
The spawn is run in the background, so it will run at an indeterminate time relative to anything else.
The closest you will get to what you want is to add a flag to ExtensibleState and check the flag in the manageHook and run your code there with liftX.
On Sat, Sep 5, 2020, 13:15 copper4eva [email protected] wrote:
So, to update this issue, the OP of that reddit thread came up with something that almost works: , ("M-<Return>", spawn (terminal c) >> withFocused (sendMessage . mergeDir W.focusUp')) The issue with this is, for whatever reason, the mergeDir gets run then the new terminal window spawns. Very strange to me that it works like that.
I was wondering if there was a hook module that would help run this. Like there is this module:
https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Hooks-InsertPosition.html for controlling what position a new window starts in. Is there not a module that can run the mergeDir command for every new window? Maybe this module:
https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Hooks-ManageHelpers.html
I'm hoping that running this with a hook solves the issue of the mergeDir occurring before the new window spawns (since obviously we want it to happen afterwards).
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/xmonad/xmonad-contrib/issues/372#issuecomment-687637726, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAPRFIAV7DTCVTTCBB5IPFDSEJWZHANCNFSM4QNTCIIA .
The spawn is run in the background, so it will run at an indeterminate time relative to anything else. The closest you will get to what you want is to add a flag to ExtensibleState and check the flag in the manageHook and run your code there with liftX.
Can you elaborate on this at all? Sorry for extremely late reply, I've been busy with other stuff. But I'm motivated to attempt getting XMonad to automatically tab newly spawned windows together.
I don't know how to use liftX. I tried using it in my managehook first and failed. Here's a reddit post I made about it: https://www.reddit.com/r/xmonad/comments/jbuj9k/how_do_i_use_liftx/
Take a look at XMonad.Actions.SpawnOn. In fact the spawnAndDo function
in there might already be useful to you.
On Thu, Oct 15, 2020 at 11:05 PM copper4eva [email protected] wrote:
The spawn is run in the background, so it will run at an indeterminate time relative to anything else. The closest you will get to what you want is to add a flag to ExtensibleState and check the flag in the manageHook and run your code there with liftX.
Can you elaborate on this at all? Sorry for extremely late reply, I've been busy with other stuff. But I'm motivated to attempt getting XMonad to automatically tab newly spawned windows together.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/xmonad/xmonad-contrib/issues/372#issuecomment-709702860, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAPRFICINPFQD3P5VTI6WITSK6Z6LANCNFSM4QNTCIIA .
-- brandon s allbery kf8nh [email protected]
Take a look at
XMonad.Actions.SpawnOn. In fact thespawnAndDofunction in there might already be useful to you.
myManageHook = composeAll
[ resource =? "lxqt" --> doIgnore
--, className =? "XTerm" --> doFloat
--, className =? "XTerm" --> (liftX (withFocused (sendMessage . mergeDir W.focusUp')) >> doFloat)
--, className =? "XTerm" --> (withFocused (sendMessage . mergeDir W.focusUp'))
, spawnAndDo (withFocused (sendMessage . mergeDir W.focusUp')) "XTerm"
, resource =? "lxqt-panel" --> doIgnore ]
So I tried different things and this is what I've gotten. If I uncomment the one with liftX, that actually compiles and "works". I'm not entirely sure with liftX is supposed to do lol, but I don't think it's what I want. I do not want the "doFloat" to run, and that is of course what ultimately happens to xterm. I only put the doFloat in there while trying to get liftX to do anything without running an error. I think if I replaced doFloat with something that does nothing (say for example if there was literally a doNothing command) then I think that line might work correctly.
spawnAndDo sounds more like what I want. But right now I get an error when trying to use it:
xmonad.hs:157:7: error:
* Couldn't match expected type `Query (Endo WindowSet)'
with actual type `X ()'
* In the expression:
spawnAndDo
(withFocused (sendMessage . mergeDir W.focusUp')) "XTerm"
In the first argument of `composeAll', namely
`[resource =? "lxqt" --> doIgnore,
spawnAndDo
(withFocused (sendMessage . mergeDir W.focusUp')) "XTerm",
resource =? "lxqt-panel" --> doIgnore]'
In the expression:
composeAll
[resource =? "lxqt" --> doIgnore,
spawnAndDo
(withFocused (sendMessage . mergeDir W.focusUp')) "XTerm",
resource =? "lxqt-panel" --> doIgnore]
|
157 | , spawnAndDo (withFocused (sendMessage . mergeDir W.focusUp')) "XTerm"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xmonad.hs:157:19: error:
* Couldn't match type `X ()' with `Query (Endo WindowSet)'
Expected type: ManageHook
Actual type: X ()
* In the first argument of `spawnAndDo', namely
`(withFocused (sendMessage . mergeDir W.focusUp'))'
In the expression:
spawnAndDo
(withFocused (sendMessage . mergeDir W.focusUp')) "XTerm"
In the first argument of `composeAll', namely
`[resource =? "lxqt" --> doIgnore,
spawnAndDo
(withFocused (sendMessage . mergeDir W.focusUp')) "XTerm",
resource =? "lxqt-panel" --> doIgnore]'
|
157 | , spawnAndDo (withFocused (sendMessage . mergeDir W.focusUp')) "XTerm"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
spawnAndDo takes a manageHook, not an action. liftX permits an action
to be run in a manageHook. So you don't want liftX in the commented-out
ones, but need it in the spawnAndDo.
As for the doFloat, you want to remove it and the preceding >>.
(I'm having trouble responding to these on github, all I get is a file dialog instead of text entry.)
On Fri, Oct 16, 2020 at 3:25 PM copper4eva [email protected] wrote:
Take a look at XMonad.Actions.SpawnOn. In fact the spawnAndDo function in there might already be useful to you. <#m_5952601485855953100_>
myManageHook = composeAll [ resource =? "lxqt" --> doIgnore --, className =? "XTerm" --> doFloat --, className =? "XTerm" --> (liftX (withFocused (sendMessage . mergeDir W.focusUp')) >> doFloat) --, className =? "XTerm" --> (withFocused (sendMessage . mergeDir W.focusUp')) , spawnAndDo (withFocused (sendMessage . mergeDir W.focusUp')) "XTerm" , resource =? "lxqt-panel" --> doIgnore ]So I tried different things and this is what I've gotten. If I uncomment the one with liftX, that actually compiles and "works". I'm not entirely sure with liftX is supposed to do lol, but I don't think it's what I want. I do not want the "doFloat" to run, and that is of course what ultimately happens to xterm. I only put the doFloat in there while trying to get liftX to do anything without running an error. I think if I replaced doFloat with something that does nothing (say for example if there was literally a doNothing command) then I think that line might work correctly.
spawnAndDo sounds more like what I want. But right now I get an error when trying to use it:
xmonad.hs:157:7: error: * Couldn't match expected type `Query (Endo WindowSet)' with actual type `X ()' * In the expression: spawnAndDo (withFocused (sendMessage . mergeDir W.focusUp')) "XTerm" In the first argument of `composeAll', namely `[resource =? "lxqt" --> doIgnore, spawnAndDo (withFocused (sendMessage . mergeDir W.focusUp')) "XTerm", resource =? "lxqt-panel" --> doIgnore]' In the expression: composeAll [resource =? "lxqt" --> doIgnore, spawnAndDo (withFocused (sendMessage . mergeDir W.focusUp')) "XTerm", resource =? "lxqt-panel" --> doIgnore] |157 | , spawnAndDo (withFocused (sendMessage . mergeDir W.focusUp')) "XTerm" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^xmonad.hs:157:19: error: * Couldn't match type
X ()' withQuery (Endo WindowSet)' Expected type: ManageHook Actual type: X () * In the first argument ofspawnAndDo', namely(withFocused (sendMessage . mergeDir W.focusUp'))' In the expression: spawnAndDo (withFocused (sendMessage . mergeDir W.focusUp')) "XTerm" In the first argument ofcomposeAll', namely[resource =? "lxqt" --> doIgnore, spawnAndDo (withFocused (sendMessage . mergeDir W.focusUp')) "XTerm", resource =? "lxqt-panel" --> doIgnore]' |157 | , spawnAndDo (withFocused (sendMessage . mergeDir W.focusUp')) "XTerm" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/xmonad/xmonad-contrib/issues/372#issuecomment-710472117, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAPRFIBP2ZAZ5UU6G6BKP7LSLCMY3ANCNFSM4QNTCIIA .
-- brandon s allbery kf8nh [email protected]
spawnAndDotakes amanageHook, not an action.liftXpermits an action to be run in amanageHook. So you don't wantliftXin the commented-out ones, but need it in thespawnAndDo. As for thedoFloat, you want to remove it and the preceding>>. (I'm having trouble responding to these on github, all I get is a file dialog instead of text entry.)
, spawnAndDo (liftX (withFocused (sendMessage . mergeDir W.focusUp')) ) "XTerm"
Alright, I tried this. Which I believe is basically what you asked me to put together. Unfortunately still gives the same kind of error:
xmonad.hs:158:7: error:
* Couldn't match expected type `Query (Endo WindowSet)'
with actual type `X ()'
* In the expression:
spawnAndDo
(liftX (withFocused (sendMessage . mergeDir W.focusUp'))) "XTerm"
In the first argument of `composeAll', namely
`[resource =? "lxqt" --> doIgnore,
spawnAndDo
(liftX (withFocused (sendMessage . mergeDir W.focusUp'))) "XTerm",
resource =? "lxqt-panel" --> doIgnore]'
In the expression:
composeAll
[resource =? "lxqt" --> doIgnore,
spawnAndDo
(liftX (withFocused (sendMessage . mergeDir W.focusUp'))) "XTerm",
resource =? "lxqt-panel" --> doIgnore]
|
158 | , spawnAndDo (liftX (withFocused (sendMessage . mergeDir W.focusUp')) ) "XTerm"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xmonad.hs:158:19: error:
* Couldn't match type `()' with `Endo WindowSet'
Expected type: ManageHook
Actual type: Query ()
* In the first argument of `spawnAndDo', namely
`(liftX (withFocused (sendMessage . mergeDir W.focusUp')))'
In the expression:
spawnAndDo
(liftX (withFocused (sendMessage . mergeDir W.focusUp'))) "XTerm"
In the first argument of `composeAll', namely
`[resource =? "lxqt" --> doIgnore,
spawnAndDo
(liftX (withFocused (sendMessage . mergeDir W.focusUp'))) "XTerm",
resource =? "lxqt-panel" --> doIgnore]'
|
158 | , spawnAndDo (liftX (withFocused (sendMessage . mergeDir W.focusUp')) ) "XTerm"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Oh, I see, you're doing this in the wrong place. spawnAndDo replaces the
spawn action via keybinding or whatever. If you want to capture any window
in the manageHook, you just want the inside of the spawnAndDo. But I'm
unclear as to what exactly you're trying to accomplish at this point.
On Fri, Oct 16, 2020 at 3:44 PM copper4eva [email protected] wrote:
spawnAndDo takes a manageHook, not an action. liftX permits an action to be run in a manageHook. So you don't want liftX in the commented-out ones, but need it in the spawnAndDo. As for the doFloat, you want to remove it and the preceding >>. (I'm having trouble responding to these on github, all I get is a file dialog instead of text entry.)
, spawnAndDo (liftX (withFocused (sendMessage . mergeDir W.focusUp')) ) "XTerm"Alright, I tried this. Which I believe is basically what you asked me to put together. Unfortunately still gives the same kind of error:
xmonad.hs:158:7: error: * Couldn't match expected type
Query (Endo WindowSet)' with actual typeX ()' * In the expression: spawnAndDo (liftX (withFocused (sendMessage . mergeDir W.focusUp'))) "XTerm" In the first argument ofcomposeAll', namely[resource =? "lxqt" --> doIgnore, spawnAndDo (liftX (withFocused (sendMessage . mergeDir W.focusUp'))) "XTerm", resource =? "lxqt-panel" --> doIgnore]' In the expression: composeAll [resource =? "lxqt" --> doIgnore, spawnAndDo (liftX (withFocused (sendMessage . mergeDir W.focusUp'))) "XTerm", resource =? "lxqt-panel" --> doIgnore] |158 | , spawnAndDo (liftX (withFocused (sendMessage . mergeDir W.focusUp')) ) "XTerm" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^xmonad.hs:158:19: error: * Couldn't match type
()' withEndo WindowSet' Expected type: ManageHook Actual type: Query () * In the first argument ofspawnAndDo', namely(liftX (withFocused (sendMessage . mergeDir W.focusUp')))' In the expression: spawnAndDo (liftX (withFocused (sendMessage . mergeDir W.focusUp'))) "XTerm" In the first argument ofcomposeAll', namely[resource =? "lxqt" --> doIgnore, spawnAndDo (liftX (withFocused (sendMessage . mergeDir W.focusUp'))) "XTerm", resource =? "lxqt-panel" --> doIgnore]' |158 | , spawnAndDo (liftX (withFocused (sendMessage . mergeDir W.focusUp')) ) "XTerm" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/xmonad/xmonad-contrib/issues/372#issuecomment-710502972, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAPRFID4SPW6OYKWKB2OOXLSLCPBFANCNFSM4QNTCIIA .
-- brandon s allbery kf8nh [email protected]
Oh, I see, you're doing this in the wrong place.
spawnAndDoreplaces the spawn action via keybinding or whatever. If you want to capture any window in themanageHook, you just want the inside of thespawnAndDo. But I'm unclear as to what exactly you're trying to accomplish at this point.
If you're unclear on what I'm trying to accomplish then rereading the OP hopefully makes things clear.
I originally just wanted some way to have newly spawned windows merge into a sublayout. In this case, the sublayout is a tabbed grouping. It would be nice if there was some simple way of doing this, to just have any window become part of the subtabbed automatically.
At the moment, I can't get anything to work. I'm thinking I might finally bite the bullet and learn how haskell actually works, and hopefully in that process I can come up with something. Since it appears no one has an easy solution to getting this to work.
Thanks for the help regardless btw.
@copper4eva any updates; did you figure this out?
The same problem with manageHooks being run before managing the window was recently encountered in the context of window swallowing: https://github.com/xmonad/xmonad-contrib/issues/416#issuecomment-777400194 and a solution that works is to have a handleEventHook that replaces xmonad core handling of the event, calls manage and then performs some additional action (in this case sendMessage (Merge …)). This is implemented here: https://github.com/xmonad/xmonad-contrib/pull/562
So what I think we can quite easily do is to add a generic afterManageHook for this. It's totally doable in -contrib, too, just extract https://github.com/xmonad/xmonad/blob/e08ddc9f04c1bd23a5126ef400e9a5b2d6a32541/src/XMonad/Main.hs#L310-L314 into a handleEventHook that invoked the hook afterwards and then returns All False to replace the core handling of the event. See also https://github.com/xmonad/xmonad-contrib/commit/4a6f21604fddfcf570fd5dc1b5307e0a1d4f995b#diff-d62d3a0de30d0cd68e38b6316053c90d9d99762e6a361526c47ca6f7b87f6737 for how to create custom extensible hooks in -contrib.
@copper4eva any updates; did you figure this out?
I switched to bspwm. So no, I did not. But it looks like from liskin's comment that XMonad has added a feature that would help with his.
So, to update this issue, the OP of that reddit thread came up with something that almost works:
, ("M-<Return>", spawn (terminal c) >> withFocused (sendMessage . mergeDir W.focusUp'))The issue with this is, for whatever reason, the mergeDir gets run then the new terminal window spawns. Very strange to me that it works like that.I was wondering if there was a hook module that would help run this. Like there is this module: https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Hooks-InsertPosition.html for controlling what position a new window starts in. Is there not a module that can run the mergeDir command for every new window? Maybe this module: https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Hooks-ManageHelpers.html
I'm hoping that running this with a hook solves the issue of the mergeDir occurring before the new window spawns (since obviously we want it to happen afterwards).
IIRC the only issue with this was the order of the spawn terminal and mergeDir were random. Obviously you want the terminal to spawn, then to run the merge command. It sounds like from liskin's comment that there's a new function or something that can help control this order of events. Which was implemented for the sake of swallowing, which would make sense. I could see how window swallowing would run into the same issue.
Random rant below, don't have to read it:
I don't have a great understanding of Haskell at all, and now that I've switched off of xmonad I likely never will. But dealing with this issue was quite frustrating. You wouldn't think that something as trivial as the order in which two commands decide to run would be such a problem. This would never be a problem in bspwm. With xmonad, whenever I wanted to do something really out of the box, and there wasn't a convenient contrib for it, it was very difficult to get things done. And sometimes would require more hacky methods, rather than more fundamentally foolproof methods. With bspwm I have never felt limited like this. They just kind of did an amazing job of just giving you the tools you need to do whatever you want in bspwm.
Sorry if that last paragraph comes off as overly negative. It was an attempt at being critically constructive. Again, I don't understand haskell very well, so this is probably more of a me issue. I just feel like something like merging subtabs automatically shouldn't have been such a freaking ordeal. With bspwm, you can subscribe to any event that happens in the window manager. And you can easily control the order at which commands are ran. So for this problem, you would just subscribe to a node being added, then you can do whatever you want to it very easily. bspwm does not have groupings or subtabs though. But you could still do this with the suckless program tabbed. Maybe one day bspwm will add the ability for monocle layout as a child node.
Hi, I've also ran into this, but I have no intention moving away from XMonad. What I'm trying to accomplish is to spawn any kind of window from rofi (dmenu) to a currently focused sublayout with a keyboard shortcut.
here's the shortcut which does not compile currently:
("M-S-p", spawnAndDo (liftX (withFocused (sendMessage $ pullGroup L))) "rofi -show drun"),
compiler tells me this error:
• Couldn't match type ‘()’
with ‘Data.Semigroup.Internal.Endo XMonad.Core.WindowSet’
Expected type: XMonad.Core.ManageHook
Actual type: XMonad.Core.Query ()
• In the first argument of ‘spawnAndDo’, namely
‘(liftX (withFocused (sendMessage $ pullGroup L)))’
In the expression:
spawnAndDo
(liftX (withFocused (sendMessage $ pullGroup L))) "rofi -show drun"
In the expression:
("M-S-p",
spawnAndDo
(liftX (withFocused (sendMessage $ pullGroup L)))
"rofi -show drun")
Could you help me with it?
What I've understand from the error is that the ManageHook needs an Endo WindowSet rather than an unit (). I'm fairly good with Haskell but I don't know much about the XMonad internals. What should I input here?
Try appending >> idHook:
("M-S-p", spawnAndDo (liftX (withFocused (sendMessage $ pullGroup L)) >> idHook) "rofi -show drun"),
But this too has a problem: xmonad won't have focused the window until after this runs. And pullGroup does not use withFocused, it determines the focused window itself — but as I said, at this point it's not focused yet. I am not sure you can do this from a manageHook.
Thanks for the quick reply! :)
My fellow XMonader friend said that this could be solved with tracking the last focused window/group in a state, and use that state here to be able to determine which group should be the newly spawned window be merged to. Although I don't really know how could I accomplish this. Do you have any suggestion for this?
Well. I know what they're talking about, but I don't know SubLayouts well enough to know how to do it properly. I can say the "state" they're talking about is https://hackage.haskell.org/package/xmonad-contrib-0.17.0/docs/XMonad-Util-ExtensibleState.html; you would define your own ExtensibleState instance to hold the group.
Thanks, will look into it!