feat(overview): darken the background behind overview previews (#110)
* feat(overview): darken the background behind overview previews * fix(overview): set DimBehind only with a veil and update the plane veil comment
- commit
- db3364d27d9cd464bc798048ab67c07d600315d1
- author
- bnema · · 2026-10-03 17:28 UTC
- committer
- GitHub · · 2026-10-03 17:28 UTC
- parent
- 1c6cce9
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown
7 files · +77 -8
M docs/config.md +2 -2
| @@ -22,7 +22,7 @@ NeferWL reads `$XDG_CONFIG_HOME/neferwl/config` (or `~/.config/neferwl/config`). | |||
| 22 | 22 | | `xwayland` | `xwayland-satellite` | X11 support; `off` disables it | | |
| 23 | 23 | | `background` | `#111111` | Solid background color | | |
| 24 | 24 | | `border.width` | `2` | Lines between visible neighboring tiles and around non-fullscreen floats, in logical pixels; `0` hides them | | |
| 25 | - | | `floating.dim` | `0.3` | Black veil over tiles and lower layers when a native floating window above the tiles or the stash is visible; opacity 0 to 1 | | |
| 25 | + | | `floating.dim` | `0.3` | Black veil over tiles and lower layers when a native floating window above the tiles or the stash is visible, and over the background and lower layers behind the overview; opacity 0 to 1 | | |
| 26 | 26 | | `stash.width` | `80` | Width of the selected stashed window, over the tiles, in percent of the usable width; 10 to 90 (`80%` works too). The rest is split between both sides, where the neighbors show. Its height is 80% of the usable height | | |
| 27 | 27 | | `stash.gap` | `2` | Space between the selected stashed window and its neighbors, in percent of the usable width; 0 to 10. The neighbors show from there to the screen edge: with the defaults, 8% of each. A gap as wide as the side margin hides them | | |
| 28 | 28 | | `stash.dim` | `0.5` | Black veil over the stash neighbors, borders included; opacity 0 to 1 | | |
| @@ -236,7 +236,7 @@ The drop can be on another monitor; focus follows the window. There, the middle | |||
| 236 | 236 | ||
| 237 | 237 | ### Overview | |
| 238 | 238 | ||
| 239 | - | `toggle-overview` shows scaled previews of the current workspace, including over fullscreen windows. Windows keep their size and previews show their last frames. Covering floats and windows hidden behind a maximized column in `fixed` overflow appear as cards: the on-screen item is in front, hidden columns share one spiral-layout card, up to two cards behind peek above it, and passed cards peek below. Neighbor workspaces show dimmed stacks. Each monitor has one vertical overview. A named workspace appears directly below the numbered workspace from which its `workspace <name>` bind was invoked. Invoking it from another numbered workspace updates this placement; browsing the overview does not. Several named workspaces attached to the same numbered workspace follow configuration order, with horizontal rules separating their group from numbered rows. Named-to-named binds reuse the source's numbered attachment. Unattached named workspaces follow the last occupied numbered row, or the first row if all numbered workspaces are empty. The selected workspace stays centred and its immediate neighbors appear above and below; rows and stash previews keep their full width. Empty workspaces are skipped unless currently selected or serving as the invocation anchor of a visible named row. Named workspaces remain outside the numbered list and normal workspace up/down navigation. Smaller floats, such as dialogs, stay hidden. A fullscreen floating window, or any fullscreen window with `fixed` overflow, is its workspace's front card, with the windows it hides behind it; `scroll` overflow keeps its columns selectable in one card. Choosing the fullscreen window keeps it fullscreen; choosing another window leaves fullscreen. | |
| 239 | + | `toggle-overview` shows scaled previews of the current workspace, including over fullscreen windows, over a background darkened by `floating.dim`. Windows keep their size and previews show their last frames. Covering floats and windows hidden behind a maximized column in `fixed` overflow appear as cards: the on-screen item is in front, hidden columns share one spiral-layout card, up to two cards behind peek above it, and passed cards peek below. Neighbor workspaces show dimmed stacks. Each monitor has one vertical overview. A named workspace appears directly below the numbered workspace from which its `workspace <name>` bind was invoked. Invoking it from another numbered workspace updates this placement; browsing the overview does not. Several named workspaces attached to the same numbered workspace follow configuration order, with horizontal rules separating their group from numbered rows. Named-to-named binds reuse the source's numbered attachment. Unattached named workspaces follow the last occupied numbered row, or the first row if all numbered workspaces are empty. The selected workspace stays centred and its immediate neighbors appear above and below; rows and stash previews keep their full width. Empty workspaces are skipped unless currently selected or serving as the invocation anchor of a visible named row. Named workspaces remain outside the numbered list and normal workspace up/down navigation. Smaller floats, such as dialogs, stay hidden. A fullscreen floating window, or any fullscreen window with `fixed` overflow, is its workspace's front card, with the windows it hides behind it; `scroll` overflow keeps its columns selectable in one card. Choosing the fullscreen window keeps it fullscreen; choosing another window leaves fullscreen. | |
| 240 | 240 | ||
| 241 | 241 | | Key | Action | | |
| 242 | 242 | | --- | --- | | |
| @@ -22,7 +22,7 @@ NeferWL reads `$XDG_CONFIG_HOME/neferwl/config` (or `~/.config/neferwl/config`). | |||||
| 22 | | `xwayland` | `xwayland-satellite` | X11 support; `off` disables it | | 22 | | `xwayland` | `xwayland-satellite` | X11 support; `off` disables it | | ||
| 23 | | `background` | `#111111` | Solid background color | | 23 | | `background` | `#111111` | Solid background color | | ||
| 24 | | `border.width` | `2` | Lines between visible neighboring tiles and around non-fullscreen floats, in logical pixels; `0` hides them | | 24 | | `border.width` | `2` | Lines between visible neighboring tiles and around non-fullscreen floats, in logical pixels; `0` hides them | | ||
| 25 | - | | `floating.dim` | `0.3` | Black veil over tiles and lower layers when a native floating window above the tiles or the stash is visible; opacity 0 to 1 | | 25 | + | | `floating.dim` | `0.3` | Black veil over tiles and lower layers when a native floating window above the tiles or the stash is visible, and over the background and lower layers behind the overview; opacity 0 to 1 | |
| 26 | | `stash.width` | `80` | Width of the selected stashed window, over the tiles, in percent of the usable width; 10 to 90 (`80%` works too). The rest is split between both sides, where the neighbors show. Its height is 80% of the usable height | | 26 | | `stash.width` | `80` | Width of the selected stashed window, over the tiles, in percent of the usable width; 10 to 90 (`80%` works too). The rest is split between both sides, where the neighbors show. Its height is 80% of the usable height | | ||
| 27 | | `stash.gap` | `2` | Space between the selected stashed window and its neighbors, in percent of the usable width; 0 to 10. The neighbors show from there to the screen edge: with the defaults, 8% of each. A gap as wide as the side margin hides them | | 27 | | `stash.gap` | `2` | Space between the selected stashed window and its neighbors, in percent of the usable width; 0 to 10. The neighbors show from there to the screen edge: with the defaults, 8% of each. A gap as wide as the side margin hides them | | ||
| 28 | | `stash.dim` | `0.5` | Black veil over the stash neighbors, borders included; opacity 0 to 1 | | 28 | | `stash.dim` | `0.5` | Black veil over the stash neighbors, borders included; opacity 0 to 1 | | ||
| @@ -236,7 +236,7 @@ The drop can be on another monitor; focus follows the window. There, the middle | |||||
| 236 | 236 | ||||
| 237 | ### Overview | 237 | ### Overview | ||
| 238 | 238 | ||||
| 239 | - | `toggle-overview` shows scaled previews of the current workspace, including over fullscreen windows. Windows keep their size and previews show their last frames. Covering floats and windows hidden behind a maximized column in `fixed` overflow appear as cards: the on-screen item is in front, hidden columns share one spiral-layout card, up to two cards behind peek above it, and passed cards peek below. Neighbor workspaces show dimmed stacks. Each monitor has one vertical overview. A named workspace appears directly below the numbered workspace from which its `workspace <name>` bind was invoked. Invoking it from another numbered workspace updates this placement; browsing the overview does not. Several named workspaces attached to the same numbered workspace follow configuration order, with horizontal rules separating their group from numbered rows. Named-to-named binds reuse the source's numbered attachment. Unattached named workspaces follow the last occupied numbered row, or the first row if all numbered workspaces are empty. The selected workspace stays centred and its immediate neighbors appear above and below; rows and stash previews keep their full width. Empty workspaces are skipped unless currently selected or serving as the invocation anchor of a visible named row. Named workspaces remain outside the numbered list and normal workspace up/down navigation. Smaller floats, such as dialogs, stay hidden. A fullscreen floating window, or any fullscreen window with `fixed` overflow, is its workspace's front card, with the windows it hides behind it; `scroll` overflow keeps its columns selectable in one card. Choosing the fullscreen window keeps it fullscreen; choosing another window leaves fullscreen. | 239 | + | `toggle-overview` shows scaled previews of the current workspace, including over fullscreen windows, over a background darkened by `floating.dim`. Windows keep their size and previews show their last frames. Covering floats and windows hidden behind a maximized column in `fixed` overflow appear as cards: the on-screen item is in front, hidden columns share one spiral-layout card, up to two cards behind peek above it, and passed cards peek below. Neighbor workspaces show dimmed stacks. Each monitor has one vertical overview. A named workspace appears directly below the numbered workspace from which its `workspace <name>` bind was invoked. Invoking it from another numbered workspace updates this placement; browsing the overview does not. Several named workspaces attached to the same numbered workspace follow configuration order, with horizontal rules separating their group from numbered rows. Named-to-named binds reuse the source's numbered attachment. Unattached named workspaces follow the last occupied numbered row, or the first row if all numbered workspaces are empty. The selected workspace stays centred and its immediate neighbors appear above and below; rows and stash previews keep their full width. Empty workspaces are skipped unless currently selected or serving as the invocation anchor of a visible named row. Named workspaces remain outside the numbered list and normal workspace up/down navigation. Smaller floats, such as dialogs, stay hidden. A fullscreen floating window, or any fullscreen window with `fixed` overflow, is its workspace's front card, with the windows it hides behind it; `scroll` overflow keeps its columns selectable in one card. Choosing the fullscreen window keeps it fullscreen; choosing another window leaves fullscreen. |
| 240 | 240 | ||||
| 241 | | Key | Action | | 241 | | Key | Action | | ||
| 242 | | --- | --- | | 242 | | --- | --- | | ||
M internal/adapters/drm/overlay.go +2 -2
| @@ -91,8 +91,8 @@ func overlayCandidate(s ports.Scene, surfaces map[ports.WindowID]ports.SurfaceCo | |||
| 91 | 91 | return ports.SceneWindow{}, ports.SurfaceContent{}, "no_candidate" | |
| 92 | 92 | } | |
| 93 | 93 | if s.Dim > 0 { | |
| 94 | - | // The renderer draws the veil under the first float it composes: a | |
| 95 | - | // float on the plane would take the veil with it. | |
| 94 | + | // The renderer composes the veil (under the first float, or under | |
| 95 | + | // every window with DimBehind): a window on the plane would skip it. | |
| 96 | 96 | return ports.SceneWindow{}, ports.SurfaceContent{}, "dim" | |
| 97 | 97 | } | |
| 98 | 98 | if len(s.DropHints) > 0 { | |
| @@ -91,8 +91,8 @@ func overlayCandidate(s ports.Scene, surfaces map[ports.WindowID]ports.SurfaceCo | |||||
| 91 | return ports.SceneWindow{}, ports.SurfaceContent{}, "no_candidate" | 91 | return ports.SceneWindow{}, ports.SurfaceContent{}, "no_candidate" | ||
| 92 | } | 92 | } | ||
| 93 | if s.Dim > 0 { | 93 | if s.Dim > 0 { | ||
| 94 | - | // The renderer draws the veil under the first float it composes: a | 94 | + | // The renderer composes the veil (under the first float, or under |
| 95 | - | // float on the plane would take the veil with it. | 95 | + | // every window with DimBehind): a window on the plane would skip it. |
| 96 | return ports.SceneWindow{}, ports.SurfaceContent{}, "dim" | 96 | return ports.SceneWindow{}, ports.SurfaceContent{}, "dim" | ||
| 97 | } | 97 | } | ||
| 98 | if len(s.DropHints) > 0 { | 98 | if len(s.DropHints) > 0 { | ||
M internal/adapters/vulkan/scene.go +6 -2
| @@ -160,8 +160,12 @@ func (w *sceneWalk) layers(afterWindows bool) { | |||
| 160 | 160 | ||
| 161 | 161 | // windows draws ordered placements with borders. Tile lines go after | |
| 162 | 162 | // the column group, before the first float above it; an overview preview | |
| 163 | - | // of a float is not one. | |
| 163 | + | // of a float is not one. The veil goes under that float, or under every | |
| 164 | + | // window with DimBehind. | |
| 164 | 165 | func (w *sceneWalk) windows() { | |
| 166 | + | if w.s.DimBehind && w.s.Dim > 0 { | |
| 167 | + | w.dim(w.bounds, w.s.Dim) | |
| 168 | + | } | |
| 165 | 169 | tileLines := false | |
| 166 | 170 | for _, win := range w.s.Windows { | |
| 167 | 171 | if win.Hidden || win.Popup || win.Rect.W <= 0 || win.Rect.H <= 0 { | |
| @@ -170,7 +174,7 @@ func (w *sceneWalk) windows() { | |||
| 170 | 174 | if !win.Below && win.Floating && win.Preview == 0 && !tileLines { | |
| 171 | 175 | w.separators(0) | |
| 172 | 176 | tileLines = true | |
| 173 | - | if w.s.Dim > 0 { | |
| 177 | + | if w.s.Dim > 0 && !w.s.DimBehind { | |
| 174 | 178 | w.dim(w.bounds, w.s.Dim) | |
| 175 | 179 | } | |
| 176 | 180 | } | |
| @@ -160,8 +160,12 @@ func (w *sceneWalk) layers(afterWindows bool) { | |||||
| 160 | 160 | ||||
| 161 | // windows draws ordered placements with borders. Tile lines go after | 161 | // windows draws ordered placements with borders. Tile lines go after | ||
| 162 | // the column group, before the first float above it; an overview preview | 162 | // the column group, before the first float above it; an overview preview | ||
| 163 | - | // of a float is not one. | 163 | + | // of a float is not one. The veil goes under that float, or under every |
| 164 | + | // window with DimBehind. | |||
| 164 | func (w *sceneWalk) windows() { | 165 | func (w *sceneWalk) windows() { | ||
| 166 | + | if w.s.DimBehind && w.s.Dim > 0 { | |||
| 167 | + | w.dim(w.bounds, w.s.Dim) | |||
| 168 | + | } | |||
| 165 | tileLines := false | 169 | tileLines := false | ||
| 166 | for _, win := range w.s.Windows { | 170 | for _, win := range w.s.Windows { | ||
| 167 | if win.Hidden || win.Popup || win.Rect.W <= 0 || win.Rect.H <= 0 { | 171 | if win.Hidden || win.Popup || win.Rect.W <= 0 || win.Rect.H <= 0 { | ||
| @@ -170,7 +174,7 @@ func (w *sceneWalk) windows() { | |||||
| 170 | if !win.Below && win.Floating && win.Preview == 0 && !tileLines { | 174 | if !win.Below && win.Floating && win.Preview == 0 && !tileLines { | ||
| 171 | w.separators(0) | 175 | w.separators(0) | ||
| 172 | tileLines = true | 176 | tileLines = true | ||
| 173 | - | if w.s.Dim > 0 { | 177 | + | if w.s.Dim > 0 && !w.s.DimBehind { |
| 174 | w.dim(w.bounds, w.s.Dim) | 178 | w.dim(w.bounds, w.s.Dim) | ||
| 175 | } | 179 | } | ||
| 176 | } | 180 | } | ||
M internal/adapters/vulkan/scene_dim_test.go +20 -0
| @@ -64,6 +64,26 @@ func TestSceneDimOrder(t *testing.T) { | |||
| 64 | 64 | } | |
| 65 | 65 | } | |
| 66 | 66 | ||
| 67 | + | // DimBehind puts the veil first, under every window, floats included, and | |
| 68 | + | // only once. | |
| 69 | + | func TestSceneDimBehind(t *testing.T) { | |
| 70 | + | r := &Renderer{width: 80, height: 60} | |
| 71 | + | s := ports.Scene{Dim: 0.3, DimBehind: true, Windows: []ports.SceneWindow{ | |
| 72 | + | {ID: 1, Preview: 0.5, Rect: ports.Rect{X: 10, W: 20, H: 20}}, | |
| 73 | + | {ID: 2, Floating: true, Rect: ports.Rect{X: 40, W: 20, H: 20}}, | |
| 74 | + | }} | |
| 75 | + | ds := r.draws(s, nil, newDamage(&target{}, s, image.Rect(0, 0, 80, 60))) | |
| 76 | + | if len(ds) != 3 { // veil, two windows | |
| 77 | + | t.Fatalf("draws = %d, want 3", len(ds)) | |
| 78 | + | } | |
| 79 | + | if v := ds[0].pc; v.rect != [4]int32{0, 0, 80, 60} || v.color != [4]float32{0, 0, 0, 0.3} { | |
| 80 | + | t.Fatalf("veil = %+v", v) | |
| 81 | + | } | |
| 82 | + | if ds[1].pc.rect[0] != 10 || ds[2].pc.rect[0] != 40 { | |
| 83 | + | t.Fatalf("windows not over the veil: %+v", ds) | |
| 84 | + | } | |
| 85 | + | } | |
| 86 | + | ||
| 67 | 87 | // A dimmed window gets a veil over its own rect, border included, right | |
| 68 | 88 | // after it: windows drawn later stay bright. | |
| 69 | 89 | func TestSceneWindowDim(t *testing.T) { | |
| @@ -64,6 +64,26 @@ func TestSceneDimOrder(t *testing.T) { | |||||
| 64 | } | 64 | } | ||
| 65 | } | 65 | } | ||
| 66 | 66 | ||||
| 67 | + | // DimBehind puts the veil first, under every window, floats included, and | |||
| 68 | + | // only once. | |||
| 69 | + | func TestSceneDimBehind(t *testing.T) { | |||
| 70 | + | r := &Renderer{width: 80, height: 60} | |||
| 71 | + | s := ports.Scene{Dim: 0.3, DimBehind: true, Windows: []ports.SceneWindow{ | |||
| 72 | + | {ID: 1, Preview: 0.5, Rect: ports.Rect{X: 10, W: 20, H: 20}}, | |||
| 73 | + | {ID: 2, Floating: true, Rect: ports.Rect{X: 40, W: 20, H: 20}}, | |||
| 74 | + | }} | |||
| 75 | + | ds := r.draws(s, nil, newDamage(&target{}, s, image.Rect(0, 0, 80, 60))) | |||
| 76 | + | if len(ds) != 3 { // veil, two windows | |||
| 77 | + | t.Fatalf("draws = %d, want 3", len(ds)) | |||
| 78 | + | } | |||
| 79 | + | if v := ds[0].pc; v.rect != [4]int32{0, 0, 80, 60} || v.color != [4]float32{0, 0, 0, 0.3} { | |||
| 80 | + | t.Fatalf("veil = %+v", v) | |||
| 81 | + | } | |||
| 82 | + | if ds[1].pc.rect[0] != 10 || ds[2].pc.rect[0] != 40 { | |||
| 83 | + | t.Fatalf("windows not over the veil: %+v", ds) | |||
| 84 | + | } | |||
| 85 | + | } | |||
| 86 | + | ||||
| 67 | // A dimmed window gets a veil over its own rect, border included, right | 87 | // A dimmed window gets a veil over its own rect, border included, right | ||
| 68 | // after it: windows drawn later stay bright. | 88 | // after it: windows drawn later stay bright. | ||
| 69 | func TestSceneWindowDim(t *testing.T) { | 89 | func TestSceneWindowDim(t *testing.T) { | ||
M internal/core/core.go +5 -0
| @@ -561,6 +561,11 @@ func (c *Core) publish(ctx context.Context) error { | |||
| 561 | 561 | } | |
| 562 | 562 | } | |
| 563 | 563 | scene.Dim = floatDim(layout, frame, c.cfg.Floating.Dim) | |
| 564 | + | if sc.mon.ov.open { | |
| 565 | + | // Darken the wallpaper around the previews. | |
| 566 | + | scene.Dim = c.cfg.Floating.Dim | |
| 567 | + | scene.DimBehind = scene.Dim > 0 | |
| 568 | + | } | |
| 564 | 569 | if d := c.drag; d != nil && d.target.screen == sc && d.target.kind != dropNone { | |
| 565 | 570 | scene.DropHints = slices.Clone(d.target.hints) | |
| 566 | 571 | } | |
| @@ -561,6 +561,11 @@ func (c *Core) publish(ctx context.Context) error { | |||||
| 561 | } | 561 | } | ||
| 562 | } | 562 | } | ||
| 563 | scene.Dim = floatDim(layout, frame, c.cfg.Floating.Dim) | 563 | scene.Dim = floatDim(layout, frame, c.cfg.Floating.Dim) | ||
| 564 | + | if sc.mon.ov.open { | |||
| 565 | + | // Darken the wallpaper around the previews. | |||
| 566 | + | scene.Dim = c.cfg.Floating.Dim | |||
| 567 | + | scene.DimBehind = scene.Dim > 0 | |||
| 568 | + | } | |||
| 564 | if d := c.drag; d != nil && d.target.screen == sc && d.target.kind != dropNone { | 569 | if d := c.drag; d != nil && d.target.screen == sc && d.target.kind != dropNone { | ||
| 565 | scene.DropHints = slices.Clone(d.target.hints) | 570 | scene.DropHints = slices.Clone(d.target.hints) | ||
| 566 | } | 571 | } | ||
M internal/core/float_core_test.go +37 -0
| @@ -60,4 +60,41 @@ func TestCoreCoveringFloatSceneAndHit(t *testing.T) { | |||
| 60 | 60 | } | |
| 61 | 61 | w.FocusID(2) | |
| 62 | 62 | check(0.3, 1, 2, 3) | |
| 63 | + | m.ToggleOverview() | |
| 64 | + | if err := c.publish(ctx); err != nil { | |
| 65 | + | t.Fatal(err) | |
| 66 | + | } | |
| 67 | + | if s := (<-scenes)[0]; s.Dim != 0.3 || !s.DimBehind { | |
| 68 | + | t.Fatalf("overview dim %v behind %v", s.Dim, s.DimBehind) | |
| 69 | + | } | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // The overview darkens the wallpaper behind its previews, tiles only too. | |
| 73 | + | func TestCoreOverviewDimsBehind(t *testing.T) { | |
| 74 | + | cfg := ports.Config{} | |
| 75 | + | cfg.Keyboard.CmdKey = "super" | |
| 76 | + | cfg.Layout.MaxColumns = 2 | |
| 77 | + | cfg.Floating.Dim = 0.3 | |
| 78 | + | scenes := make(chan []ports.Scene, 1) | |
| 79 | + | c, err := New(cfg, Channels{Scenes: scenes, Commands: make(chan ports.ClientCommand, 128)}) | |
| 80 | + | if err != nil { | |
| 81 | + | t.Fatal(err) | |
| 82 | + | } | |
| 83 | + | c.cur().info = ports.OutputInfo{Name: "OUT", Width: 100, Height: 80} | |
| 84 | + | m := c.cur().mon | |
| 85 | + | m.SetOutput(100, 80) | |
| 86 | + | m.Current().AddWindow(1) | |
| 87 | + | ctx := context.Background() | |
| 88 | + | for _, tc := range []struct { | |
| 89 | + | dim float64 | |
| 90 | + | behind bool | |
| 91 | + | }{{0, false}, {0.3, true}, {0, false}} { | |
| 92 | + | if err := c.publish(ctx); err != nil { | |
| 93 | + | t.Fatal(err) | |
| 94 | + | } | |
| 95 | + | if s := (<-scenes)[0]; s.Dim != tc.dim || s.DimBehind != tc.behind { | |
| 96 | + | t.Fatalf("dim %v behind %v, want %v %v", s.Dim, s.DimBehind, tc.dim, tc.behind) | |
| 97 | + | } | |
| 98 | + | m.ToggleOverview() | |
| 99 | + | } | |
| 63 | 100 | } | |
| @@ -60,4 +60,41 @@ func TestCoreCoveringFloatSceneAndHit(t *testing.T) { | |||||
| 60 | } | 60 | } | ||
| 61 | w.FocusID(2) | 61 | w.FocusID(2) | ||
| 62 | check(0.3, 1, 2, 3) | 62 | check(0.3, 1, 2, 3) | ||
| 63 | + | m.ToggleOverview() | |||
| 64 | + | if err := c.publish(ctx); err != nil { | |||
| 65 | + | t.Fatal(err) | |||
| 66 | + | } | |||
| 67 | + | if s := (<-scenes)[0]; s.Dim != 0.3 || !s.DimBehind { | |||
| 68 | + | t.Fatalf("overview dim %v behind %v", s.Dim, s.DimBehind) | |||
| 69 | + | } | |||
| 70 | + | } | |||
| 71 | + | ||||
| 72 | + | // The overview darkens the wallpaper behind its previews, tiles only too. | |||
| 73 | + | func TestCoreOverviewDimsBehind(t *testing.T) { | |||
| 74 | + | cfg := ports.Config{} | |||
| 75 | + | cfg.Keyboard.CmdKey = "super" | |||
| 76 | + | cfg.Layout.MaxColumns = 2 | |||
| 77 | + | cfg.Floating.Dim = 0.3 | |||
| 78 | + | scenes := make(chan []ports.Scene, 1) | |||
| 79 | + | c, err := New(cfg, Channels{Scenes: scenes, Commands: make(chan ports.ClientCommand, 128)}) | |||
| 80 | + | if err != nil { | |||
| 81 | + | t.Fatal(err) | |||
| 82 | + | } | |||
| 83 | + | c.cur().info = ports.OutputInfo{Name: "OUT", Width: 100, Height: 80} | |||
| 84 | + | m := c.cur().mon | |||
| 85 | + | m.SetOutput(100, 80) | |||
| 86 | + | m.Current().AddWindow(1) | |||
| 87 | + | ctx := context.Background() | |||
| 88 | + | for _, tc := range []struct { | |||
| 89 | + | dim float64 | |||
| 90 | + | behind bool | |||
| 91 | + | }{{0, false}, {0.3, true}, {0, false}} { | |||
| 92 | + | if err := c.publish(ctx); err != nil { | |||
| 93 | + | t.Fatal(err) | |||
| 94 | + | } | |||
| 95 | + | if s := (<-scenes)[0]; s.Dim != tc.dim || s.DimBehind != tc.behind { | |||
| 96 | + | t.Fatalf("dim %v behind %v, want %v %v", s.Dim, s.DimBehind, tc.dim, tc.behind) | |||
| 97 | + | } | |||
| 98 | + | m.ToggleOverview() | |||
| 99 | + | } | |||
| 63 | } | 100 | } | ||
M internal/ports/scene.go +5 -2
| @@ -27,8 +27,11 @@ type Scene struct { | |||
| 27 | 27 | // included) inside WorkspaceClip when set, with black at this opacity, | |
| 28 | 28 | // 0 to 1, under the first | |
| 29 | 29 | // visible float. 0 draws nothing. | |
| 30 | - | Dim float64 | |
| 31 | - | Windows []SceneWindow | |
| 30 | + | Dim float64 | |
| 31 | + | // DimBehind draws the Dim veil under every window instead, right over | |
| 32 | + | // the background and bottom layers (the overview). | |
| 33 | + | DimBehind bool | |
| 34 | + | Windows []SceneWindow | |
| 32 | 35 | // Separators are the lines between windows, drawn in slice order with | |
| 33 | 36 | // the Border colors: tile lines over the tiles, under the floats; a | |
| 34 | 37 | // float's border right after the float. | |
| @@ -27,8 +27,11 @@ type Scene struct { | |||||
| 27 | // included) inside WorkspaceClip when set, with black at this opacity, | 27 | // included) inside WorkspaceClip when set, with black at this opacity, | ||
| 28 | // 0 to 1, under the first | 28 | // 0 to 1, under the first | ||
| 29 | // visible float. 0 draws nothing. | 29 | // visible float. 0 draws nothing. | ||
| 30 | - | Dim float64 | 30 | + | Dim float64 |
| 31 | - | Windows []SceneWindow | 31 | + | // DimBehind draws the Dim veil under every window instead, right over |
| 32 | + | // the background and bottom layers (the overview). | |||
| 33 | + | DimBehind bool | |||
| 34 | + | Windows []SceneWindow | |||
| 32 | // Separators are the lines between windows, drawn in slice order with | 35 | // Separators are the lines between windows, drawn in slice order with | ||
| 33 | // the Border colors: tile lines over the tiles, under the floats; a | 36 | // the Border colors: tile lines over the tiles, under the floats; a | ||
| 34 | // float's border right after the float. | 37 | // float's border right after the float. | ||