fix(core): keep the stash swipe spawn from refilling workspace slots
The four-finger swipe that opens the stash terminal reported a shown workspace, so the empty slots of the workspace on screen were refilled. It now reports none, as the bind does.
- commit
- 2fb23d65c8b78d63d717dd210fbbf89ebac45a2c
- author
- brice · · 2026-10-14 20:41 UTC
- parent
- 835c479
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +30 -5
M internal/core/gesture.go +5 -5
| @@ -452,10 +452,10 @@ func (c *Core) swipeEnd(e ports.SwipeEnd) (shown bool, spawn *Workspace) { | |||
| 452 | 452 | // swipeStash runs toggle-stash-visible for a four-finger swipe down, or up | |
| 453 | 453 | // while the stash is shown, with the overview closed, on the swipe's screen | |
| 454 | 454 | // unless the pointer took the focus to another output meanwhile. It reports | |
| 455 | - | // whether the swipe acted: the stash showed or hid, or an empty stash asked | |
| 456 | - | // for its terminal (stash.spawn-terminal), which spawn names for the caller | |
| 457 | - | // to start, as a bind does. | |
| 458 | - | func (c *Core) swipeStash(g *swipeGesture, now time.Time) (acted bool, spawn *Workspace) { | |
| 455 | + | // whether the stash showed or hid. An empty stash asking for its terminal | |
| 456 | + | // (stash.spawn-terminal) shows no workspace, as with the bind: spawn names the | |
| 457 | + | // workspace for the caller to start it in. | |
| 458 | + | func (c *Core) swipeStash(g *swipeGesture, now time.Time) (shown bool, spawn *Workspace) { | |
| 459 | 459 | if c.cur() != g.screen { | |
| 460 | 460 | return false, nil | |
| 461 | 461 | } | |
| @@ -466,7 +466,7 @@ func (c *Core) swipeStash(g *swipeGesture, now time.Time) (acted bool, spawn *Wo | |||
| 466 | 466 | effect := c.applyAction(ActionToggleStashVisible) | |
| 467 | 467 | c.transition(shots, now) | |
| 468 | 468 | if effect.Spawn { | |
| 469 | - | return true, w | |
| 469 | + | return false, w | |
| 470 | 470 | } | |
| 471 | 471 | return w.stashHidden != hidden || w.stashOver != over, nil | |
| 472 | 472 | } | |
| @@ -452,10 +452,10 @@ func (c *Core) swipeEnd(e ports.SwipeEnd) (shown bool, spawn *Workspace) { | |||||
| 452 | // swipeStash runs toggle-stash-visible for a four-finger swipe down, or up | 452 | // swipeStash runs toggle-stash-visible for a four-finger swipe down, or up | ||
| 453 | // while the stash is shown, with the overview closed, on the swipe's screen | 453 | // while the stash is shown, with the overview closed, on the swipe's screen | ||
| 454 | // unless the pointer took the focus to another output meanwhile. It reports | 454 | // unless the pointer took the focus to another output meanwhile. It reports | ||
| 455 | - | // whether the swipe acted: the stash showed or hid, or an empty stash asked | 455 | + | // whether the stash showed or hid. An empty stash asking for its terminal |
| 456 | - | // for its terminal (stash.spawn-terminal), which spawn names for the caller | 456 | + | // (stash.spawn-terminal) shows no workspace, as with the bind: spawn names the |
| 457 | - | // to start, as a bind does. | 457 | + | // workspace for the caller to start it in. |
| 458 | - | func (c *Core) swipeStash(g *swipeGesture, now time.Time) (acted bool, spawn *Workspace) { | 458 | + | func (c *Core) swipeStash(g *swipeGesture, now time.Time) (shown bool, spawn *Workspace) { |
| 459 | if c.cur() != g.screen { | 459 | if c.cur() != g.screen { | ||
| 460 | return false, nil | 460 | return false, nil | ||
| 461 | } | 461 | } | ||
| @@ -466,7 +466,7 @@ func (c *Core) swipeStash(g *swipeGesture, now time.Time) (acted bool, spawn *Wo | |||||
| 466 | effect := c.applyAction(ActionToggleStashVisible) | 466 | effect := c.applyAction(ActionToggleStashVisible) | ||
| 467 | c.transition(shots, now) | 467 | c.transition(shots, now) | ||
| 468 | if effect.Spawn { | 468 | if effect.Spawn { | ||
| 469 | - | return true, w | 469 | + | return false, w |
| 470 | } | 470 | } | ||
| 471 | return w.stashHidden != hidden || w.stashOver != over, nil | 471 | return w.stashHidden != hidden || w.stashOver != over, nil | ||
| 472 | } | 472 | } | ||
M internal/core/stash_spawn_test.go +25 -0
| @@ -3,6 +3,7 @@ package core_test | |||
| 3 | 3 | import ( | |
| 4 | 4 | "slices" | |
| 5 | 5 | "testing" | |
| 6 | + | "time" | |
| 6 | 7 | ||
| 7 | 8 | "github.com/bnema/neferwl/internal/ports" | |
| 8 | 9 | ) | |
| @@ -201,3 +202,27 @@ func TestFourFingerSwipeEmptyStashRespectsOption(t *testing.T) { | |||
| 201 | 202 | t.Fatal("spawned with stash.spawn-terminal off") | |
| 202 | 203 | } | |
| 203 | 204 | } | |
| 205 | + | ||
| 206 | + | // The terminal of a four-finger swipe shows no workspace: the empty slots of | |
| 207 | + | // the workspace on screen are not refilled, as with the bind. | |
| 208 | + | func TestFourFingerSwipeEmptyStashDoesNotRefillSlots(t *testing.T) { | |
| 209 | + | r := startSlots(t) | |
| 210 | + | r.fill(t) | |
| 211 | + | r.press(t, "d") // dev on screen, its slots filled | |
| 212 | + | r.client <- ports.WindowUnmapped{ID: 2} | |
| 213 | + | sceneMatch(t, r.scenes, func(s ports.Scene) bool { return len(s.Windows) == 1 }) | |
| 214 | + | noSpawn(t, r.spawn) // nothing relaunches on its own | |
| 215 | + | var at time.Duration | |
| 216 | + | r.input <- ports.SwipeBegin{Fingers: 4, Time: at} | |
| 217 | + | for range 10 { | |
| 218 | + | at += 8 * time.Millisecond | |
| 219 | + | r.input <- ports.SwipeUpdate{DY: 40, Time: at} | |
| 220 | + | } | |
| 221 | + | r.input <- ports.SwipeEnd{Time: at} | |
| 222 | + | req := receive(t, r.spawn) | |
| 223 | + | if len(req.Argv) != 1 || req.Argv[0] != "foot" { | |
| 224 | + | t.Fatalf("argv %v, want the stash terminal", req.Argv) | |
| 225 | + | } | |
| 226 | + | r.sync(t) | |
| 227 | + | noSpawn(t, r.spawn) // the empty slot of dev stays empty | |
| 228 | + | } | |
| @@ -3,6 +3,7 @@ package core_test | |||||
| 3 | import ( | 3 | import ( | ||
| 4 | "slices" | 4 | "slices" | ||
| 5 | "testing" | 5 | "testing" | ||
| 6 | + | "time" | |||
| 6 | 7 | ||||
| 7 | "github.com/bnema/neferwl/internal/ports" | 8 | "github.com/bnema/neferwl/internal/ports" | ||
| 8 | ) | 9 | ) | ||
| @@ -201,3 +202,27 @@ func TestFourFingerSwipeEmptyStashRespectsOption(t *testing.T) { | |||||
| 201 | t.Fatal("spawned with stash.spawn-terminal off") | 202 | t.Fatal("spawned with stash.spawn-terminal off") | ||
| 202 | } | 203 | } | ||
| 203 | } | 204 | } | ||
| 205 | + | ||||
| 206 | + | // The terminal of a four-finger swipe shows no workspace: the empty slots of | |||
| 207 | + | // the workspace on screen are not refilled, as with the bind. | |||
| 208 | + | func TestFourFingerSwipeEmptyStashDoesNotRefillSlots(t *testing.T) { | |||
| 209 | + | r := startSlots(t) | |||
| 210 | + | r.fill(t) | |||
| 211 | + | r.press(t, "d") // dev on screen, its slots filled | |||
| 212 | + | r.client <- ports.WindowUnmapped{ID: 2} | |||
| 213 | + | sceneMatch(t, r.scenes, func(s ports.Scene) bool { return len(s.Windows) == 1 }) | |||
| 214 | + | noSpawn(t, r.spawn) // nothing relaunches on its own | |||
| 215 | + | var at time.Duration | |||
| 216 | + | r.input <- ports.SwipeBegin{Fingers: 4, Time: at} | |||
| 217 | + | for range 10 { | |||
| 218 | + | at += 8 * time.Millisecond | |||
| 219 | + | r.input <- ports.SwipeUpdate{DY: 40, Time: at} | |||
| 220 | + | } | |||
| 221 | + | r.input <- ports.SwipeEnd{Time: at} | |||
| 222 | + | req := receive(t, r.spawn) | |||
| 223 | + | if len(req.Argv) != 1 || req.Argv[0] != "foot" { | |||
| 224 | + | t.Fatalf("argv %v, want the stash terminal", req.Argv) | |||
| 225 | + | } | |||
| 226 | + | r.sync(t) | |||
| 227 | + | noSpawn(t, r.spawn) // the empty slot of dev stays empty | |||
| 228 | + | } | |||