1package core
2
3import (
4 "context"
5 "testing"
6
7 "github.com/bnema/neferwl/internal/ports"
8)
9
10// Every window's configure says whether it is on its output: hidden
11// workspaces, scrolled-off columns, maximized neighbors and hidden floats
12// are not visible, and keep their size and output.
13func TestConfigureVisible(t *testing.T) {
14 cfg := ports.Config{}
15 cfg.Keyboard.CmdKey = "super"
16 cfg.Layout.MaxColumns = 1
17 commands := make(chan ports.ClientCommand, 256)
18 scenes := make(chan []ports.Scene, 1)
19 c, err := New(cfg, Channels{Commands: commands, Scenes: scenes})
20 if err != nil {
21 t.Fatal(err)
22 }
23 c.addScreen(ports.OutputInfo{Name: "OUT-1", Width: 100, Height: 80})
24 m := c.cur().mon
25 w := m.Current()
26 ctx := context.Background()
27 sent := map[WindowID]ports.ConfigureWindow{}
28 publish := func() {
29 t.Helper()
30 if err := c.publish(ctx); err != nil {
31 t.Fatal(err)
32 }
33 <-scenes
34 for len(commands) > 0 {
35 if v, ok := (<-commands).(ports.ConfigureWindow); ok {
36 sent[v.ID] = v
37 }
38 }
39 }
40 visible := func(want map[WindowID]bool) {
41 t.Helper()
42 publish()
43 state := map[WindowID]bool{}
44 for _, s := range c.state().Windows {
45 state[s.ID] = s.Visible
46 }
47 for id, vis := range want {
48 v := sent[id]
49 if v.Visible != vis || v.Output == "" || v.Width <= 0 {
50 t.Fatalf("window %d: %+v, want visible %v", id, v, vis)
51 }
52 if state[id] != vis {
53 t.Fatalf("window %d: state visible %v, want %v", id, state[id], vis)
54 }
55 }
56 }
57 // One column per screen: the second scrolls the first off.
58 m.AddWindow(1)
59 visible(map[WindowID]bool{1: true})
60 m.AddWindow(2)
61 visible(map[WindowID]bool{1: false, 2: true})
62 w.FocusColumn(-1)
63 visible(map[WindowID]bool{1: true, 2: false})
64 // A floated window is visible until the floats are hidden.
65 w.FocusID(2)
66 w.ToggleWindowStash()
67 visible(map[WindowID]bool{1: true, 2: true})
68 w.ToggleStashVisible()
69 visible(map[WindowID]bool{1: true, 2: false})
70 w.ToggleStashVisible()
71 // Another workspace hides them all; coming back shows them.
72 if len(m.Workspaces) < 2 {
73 t.Fatal("no spare workspace")
74 }
75 m.Focus(1)
76 visible(map[WindowID]bool{1: false, 2: false})
77 m.Focus(0)
78 visible(map[WindowID]bool{1: true, 2: true})
79 // A window mapped on a hidden workspace is told it is invisible at
80 // once, sized by the client.
81 m.Workspaces[1].AddWindow(3)
82 publish()
83 if v, ok := sent[3]; !ok || v.Visible || v.Width != 0 || v.Output != "OUT-1" {
84 t.Fatalf("hidden map: %+v %v", v, ok)
85 }
86 // A column scrolled off takes its popups off screen with it.
87 c.popups[10] = &popupState{id: 10, parent: 1, mapped: true, rect: Rect{W: 5, H: 5}}
88 c.popupOrder = append(c.popupOrder, 10)
89 w.FocusID(1)
90 if !c.visible(10) {
91 t.Fatal("popup of a visible window not on screen")
92 }
93 m.AddWindow(4)
94 if c.visible(1) || c.visible(10) {
95 t.Fatal("popup of a scrolled-off window still on screen")
96 }
97}