fix(vulkan): draw background instead of colored placeholder before first buffer (#50)
- commit
- 4ef9a1d75f6579ebee1e00c2c9d7f36fbac275a7
- author
- bnema · · 2026-09-28 18:11 UTC
- committer
- GitHub · · 2026-09-28 18:11 UTC
- parent
- 3d61f9d
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown
2 files · +23 -45
M internal/adapters/vulkan/renderer_test.go +20 -17
| @@ -46,9 +46,13 @@ func TestRendererRender(t *testing.T) { | |||
| 46 | 46 | } | |
| 47 | 47 | defer r.Close() | |
| 48 | 48 | bg := color.RGBA{16, 32, 48, 255} | |
| 49 | + | wc, c2, fc := color.RGBA{200, 10, 10, 255}, color.RGBA{10, 200, 10, 255}, color.RGBA{10, 10, 200, 255} | |
| 50 | + | contents := map[ports.WindowID]ports.SurfaceContent{ | |
| 51 | + | 1: solidContent(t, 64, 48, wc), 2: solidContent(t, 64, 48, c2), 3: solidContent(t, 64, 48, fc), | |
| 52 | + | } | |
| 49 | 53 | check := func(s ports.Scene, expected map[image.Point]color.RGBA) { | |
| 50 | 54 | t.Helper() | |
| 51 | - | if err := render(r, s, nil); err != nil { | |
| 55 | + | if err := render(r, s, contents); err != nil { | |
| 52 | 56 | t.Fatal(err) | |
| 53 | 57 | } | |
| 54 | 58 | for p, want := range expected { | |
| @@ -60,8 +64,6 @@ func TestRendererRender(t *testing.T) { | |||
| 60 | 64 | // The client sits inside its inset sides; separators are drawn over | |
| 61 | 65 | // the windows in order, with the border colors. | |
| 62 | 66 | win := ports.SceneWindow{ID: 1, Rect: ports.Rect{X: 8, Y: 8, W: 16, H: 16}, Inset: ports.SideAll} | |
| 63 | - | c := windowColor(1) | |
| 64 | - | wc := color.RGBA{c[0], c[1], c[2], 255} | |
| 65 | 67 | gray, lit := color.RGBA{0x31, 0x32, 0x44, 255}, color.RGBA{0xb4, 0xbe, 0xfe, 255} | |
| 66 | 68 | s := ports.Scene{Background: "#102030", Border: ports.Border{Width: 2, Active: "#b4befe", Inactive: "#313244"}, Windows: []ports.SceneWindow{win}} | |
| 67 | 69 | check(s, map[image.Point]color.RGBA{{0, 0}: bg, {9, 9}: bg, {10, 10}: wc, {16, 16}: wc, {21, 21}: wc, {22, 22}: bg, {24, 24}: bg}) | |
| @@ -78,16 +80,14 @@ func TestRendererRender(t *testing.T) { | |||
| 78 | 80 | {Rect: ports.Rect{X: 8, Y: 8, W: 16, H: 2}, Active: true}, | |
| 79 | 81 | {Rect: ports.Rect{X: 12, Y: 4, W: 8, H: 1}, Active: true, Window: 3}, | |
| 80 | 82 | } | |
| 81 | - | fc := windowColor(3) | |
| 82 | - | check(s, map[image.Point]color.RGBA{{9, 9}: lit, {14, 9}: {fc[0], fc[1], fc[2], 255}, {14, 4}: lit}) | |
| 83 | + | check(s, map[image.Point]color.RGBA{{9, 9}: lit, {14, 9}: fc, {14, 4}: lit}) | |
| 83 | 84 | s.Windows = []ports.SceneWindow{win} | |
| 84 | 85 | s.Separators, s.Border.Inactive = nil, "#313244" | |
| 85 | 86 | s.Windows[0].Fullscreen = true | |
| 86 | 87 | check(s, map[image.Point]color.RGBA{{9, 9}: wc}) | |
| 87 | 88 | s.Windows[0].Fullscreen = false | |
| 88 | 89 | s.Windows[0] = ports.SceneWindow{ID: 2, Rect: ports.Rect{X: -10, Y: 0, W: 20, H: 10}} | |
| 89 | - | c = windowColor(2) | |
| 90 | - | check(s, map[image.Point]color.RGBA{{5, 5}: {c[0], c[1], c[2], 255}, {15, 5}: bg}) | |
| 90 | + | check(s, map[image.Point]color.RGBA{{5, 5}: c2, {15, 5}: bg}) | |
| 91 | 91 | s.Windows[0].Hidden = true | |
| 92 | 92 | check(s, map[image.Point]color.RGBA{{5, 5}: bg}) | |
| 93 | 93 | } | |
| @@ -130,9 +130,9 @@ func TestRendererContents(t *testing.T) { | |||
| 130 | 130 | copy(padded[8:12], []byte{7, 11, 23, 255}) | |
| 131 | 131 | render(shmContent(t, 4, 4, 20, padded)) | |
| 132 | 132 | check(0, 0, color.RGBA{23, 11, 7, 255}) | |
| 133 | + | // A window without a buffer yet shows the background, not a color. | |
| 133 | 134 | render(nil) | |
| 134 | - | c := windowColor(1) | |
| 135 | - | check(0, 0, color.RGBA{c[0], c[1], c[2], 255}) | |
| 135 | + | check(0, 0, bg) | |
| 136 | 136 | } | |
| 137 | 137 | ||
| 138 | 138 | func TestRendererUploadOrderAndOpaque(t *testing.T) { | |
| @@ -145,11 +145,16 @@ func TestRendererUploadOrderAndOpaque(t *testing.T) { | |||
| 145 | 145 | {ID: 1, Rect: ports.Rect{X: 2, Y: 2, W: 16, H: 16}}, | |
| 146 | 146 | {ID: 2, Rect: ports.Rect{X: 8, Y: 8, W: 16, H: 16}}, | |
| 147 | 147 | }} | |
| 148 | - | if err := render(r, scene, nil); err != nil { | |
| 148 | + | top := color.RGBA{10, 200, 10, 255} | |
| 149 | + | upper := map[ports.WindowID]ports.SurfaceContent{1: solidContent(t, 16, 16, color.RGBA{200, 10, 10, 255}), 2: solidContent(t, 16, 16, top)} | |
| 150 | + | for id, c := range upper { | |
| 151 | + | c.Version = 1 // the opaque buffer below is another commit | |
| 152 | + | upper[id] = c | |
| 153 | + | } | |
| 154 | + | if err := render(r, scene, upper); err != nil { | |
| 149 | 155 | t.Fatal(err) | |
| 150 | 156 | } | |
| 151 | - | c := windowColor(2) | |
| 152 | - | if got, want := r.Pixels().RGBAAt(10, 10), (color.RGBA{c[0], c[1], c[2], 255}); got != want { | |
| 157 | + | if got, want := r.Pixels().RGBAAt(10, 10), top; got != want { | |
| 153 | 158 | t.Errorf("overlap = %v, want %v", got, want) | |
| 154 | 159 | } | |
| 155 | 160 | scene.Border = ports.Border{Width: 4, Active: "#ffffff"} | |
| @@ -189,8 +194,7 @@ func TestRendererLayers(t *testing.T) { | |||
| 189 | 194 | layer.ID, layer.Opaque = 2, true | |
| 190 | 195 | contents := map[ports.WindowID]ports.SurfaceContent{2: *layer} | |
| 191 | 196 | scene := ports.Scene{Background: "#102030", Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: 64, H: 48}}}, Layers: []ports.SceneLayer{{ID: 2, Layer: ports.LayerTop, Rect: ports.Rect{W: 64, H: 8}}}} | |
| 192 | - | wc := windowColor(1) | |
| 193 | - | window := color.RGBA{wc[0], wc[1], wc[2], 255} | |
| 197 | + | window := color.RGBA{16, 32, 48, 255} // no buffer yet: background | |
| 194 | 198 | check := func(want color.RGBA) { | |
| 195 | 199 | t.Helper() | |
| 196 | 200 | if err := render(r, scene, contents); err != nil { | |
| @@ -368,11 +372,10 @@ func TestRendererTallFill(t *testing.T) { | |||
| 368 | 372 | } | |
| 369 | 373 | defer r.Close() | |
| 370 | 374 | scene := ports.Scene{Background: "#102030", Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{X: 1, Y: 0, W: 6, H: h}}}} | |
| 371 | - | if err := render(r, scene, nil); err != nil { | |
| 375 | + | wc := color.RGBA{200, 10, 10, 255} | |
| 376 | + | if err := render(r, scene, map[ports.WindowID]ports.SurfaceContent{1: solidContent(t, 6, h, wc)}); err != nil { | |
| 372 | 377 | t.Fatal(err) | |
| 373 | 378 | } | |
| 374 | - | c := windowColor(1) | |
| 375 | - | wc := color.RGBA{c[0], c[1], c[2], 255} | |
| 376 | 379 | bg := color.RGBA{16, 32, 48, 255} | |
| 377 | 380 | px := r.Pixels() | |
| 378 | 381 | for y := 0; y < h; y++ { | |
| @@ -46,9 +46,13 @@ func TestRendererRender(t *testing.T) { | |||||
| 46 | } | 46 | } | ||
| 47 | defer r.Close() | 47 | defer r.Close() | ||
| 48 | bg := color.RGBA{16, 32, 48, 255} | 48 | bg := color.RGBA{16, 32, 48, 255} | ||
| 49 | + | wc, c2, fc := color.RGBA{200, 10, 10, 255}, color.RGBA{10, 200, 10, 255}, color.RGBA{10, 10, 200, 255} | |||
| 50 | + | contents := map[ports.WindowID]ports.SurfaceContent{ | |||
| 51 | + | 1: solidContent(t, 64, 48, wc), 2: solidContent(t, 64, 48, c2), 3: solidContent(t, 64, 48, fc), | |||
| 52 | + | } | |||
| 49 | check := func(s ports.Scene, expected map[image.Point]color.RGBA) { | 53 | check := func(s ports.Scene, expected map[image.Point]color.RGBA) { | ||
| 50 | t.Helper() | 54 | t.Helper() | ||
| 51 | - | if err := render(r, s, nil); err != nil { | 55 | + | if err := render(r, s, contents); err != nil { |
| 52 | t.Fatal(err) | 56 | t.Fatal(err) | ||
| 53 | } | 57 | } | ||
| 54 | for p, want := range expected { | 58 | for p, want := range expected { | ||
| @@ -60,8 +64,6 @@ func TestRendererRender(t *testing.T) { | |||||
| 60 | // The client sits inside its inset sides; separators are drawn over | 64 | // The client sits inside its inset sides; separators are drawn over | ||
| 61 | // the windows in order, with the border colors. | 65 | // the windows in order, with the border colors. | ||
| 62 | win := ports.SceneWindow{ID: 1, Rect: ports.Rect{X: 8, Y: 8, W: 16, H: 16}, Inset: ports.SideAll} | 66 | win := ports.SceneWindow{ID: 1, Rect: ports.Rect{X: 8, Y: 8, W: 16, H: 16}, Inset: ports.SideAll} | ||
| 63 | - | c := windowColor(1) | |||
| 64 | - | wc := color.RGBA{c[0], c[1], c[2], 255} | |||
| 65 | gray, lit := color.RGBA{0x31, 0x32, 0x44, 255}, color.RGBA{0xb4, 0xbe, 0xfe, 255} | 67 | gray, lit := color.RGBA{0x31, 0x32, 0x44, 255}, color.RGBA{0xb4, 0xbe, 0xfe, 255} | ||
| 66 | s := ports.Scene{Background: "#102030", Border: ports.Border{Width: 2, Active: "#b4befe", Inactive: "#313244"}, Windows: []ports.SceneWindow{win}} | 68 | s := ports.Scene{Background: "#102030", Border: ports.Border{Width: 2, Active: "#b4befe", Inactive: "#313244"}, Windows: []ports.SceneWindow{win}} | ||
| 67 | check(s, map[image.Point]color.RGBA{{0, 0}: bg, {9, 9}: bg, {10, 10}: wc, {16, 16}: wc, {21, 21}: wc, {22, 22}: bg, {24, 24}: bg}) | 69 | check(s, map[image.Point]color.RGBA{{0, 0}: bg, {9, 9}: bg, {10, 10}: wc, {16, 16}: wc, {21, 21}: wc, {22, 22}: bg, {24, 24}: bg}) | ||
| @@ -78,16 +80,14 @@ func TestRendererRender(t *testing.T) { | |||||
| 78 | {Rect: ports.Rect{X: 8, Y: 8, W: 16, H: 2}, Active: true}, | 80 | {Rect: ports.Rect{X: 8, Y: 8, W: 16, H: 2}, Active: true}, | ||
| 79 | {Rect: ports.Rect{X: 12, Y: 4, W: 8, H: 1}, Active: true, Window: 3}, | 81 | {Rect: ports.Rect{X: 12, Y: 4, W: 8, H: 1}, Active: true, Window: 3}, | ||
| 80 | } | 82 | } | ||
| 81 | - | fc := windowColor(3) | 83 | + | check(s, map[image.Point]color.RGBA{{9, 9}: lit, {14, 9}: fc, {14, 4}: lit}) |
| 82 | - | check(s, map[image.Point]color.RGBA{{9, 9}: lit, {14, 9}: {fc[0], fc[1], fc[2], 255}, {14, 4}: lit}) | |||
| 83 | s.Windows = []ports.SceneWindow{win} | 84 | s.Windows = []ports.SceneWindow{win} | ||
| 84 | s.Separators, s.Border.Inactive = nil, "#313244" | 85 | s.Separators, s.Border.Inactive = nil, "#313244" | ||
| 85 | s.Windows[0].Fullscreen = true | 86 | s.Windows[0].Fullscreen = true | ||
| 86 | check(s, map[image.Point]color.RGBA{{9, 9}: wc}) | 87 | check(s, map[image.Point]color.RGBA{{9, 9}: wc}) | ||
| 87 | s.Windows[0].Fullscreen = false | 88 | s.Windows[0].Fullscreen = false | ||
| 88 | s.Windows[0] = ports.SceneWindow{ID: 2, Rect: ports.Rect{X: -10, Y: 0, W: 20, H: 10}} | 89 | s.Windows[0] = ports.SceneWindow{ID: 2, Rect: ports.Rect{X: -10, Y: 0, W: 20, H: 10}} | ||
| 89 | - | c = windowColor(2) | 90 | + | check(s, map[image.Point]color.RGBA{{5, 5}: c2, {15, 5}: bg}) |
| 90 | - | check(s, map[image.Point]color.RGBA{{5, 5}: {c[0], c[1], c[2], 255}, {15, 5}: bg}) | |||
| 91 | s.Windows[0].Hidden = true | 91 | s.Windows[0].Hidden = true | ||
| 92 | check(s, map[image.Point]color.RGBA{{5, 5}: bg}) | 92 | check(s, map[image.Point]color.RGBA{{5, 5}: bg}) | ||
| 93 | } | 93 | } | ||
| @@ -130,9 +130,9 @@ func TestRendererContents(t *testing.T) { | |||||
| 130 | copy(padded[8:12], []byte{7, 11, 23, 255}) | 130 | copy(padded[8:12], []byte{7, 11, 23, 255}) | ||
| 131 | render(shmContent(t, 4, 4, 20, padded)) | 131 | render(shmContent(t, 4, 4, 20, padded)) | ||
| 132 | check(0, 0, color.RGBA{23, 11, 7, 255}) | 132 | check(0, 0, color.RGBA{23, 11, 7, 255}) | ||
| 133 | + | // A window without a buffer yet shows the background, not a color. | |||
| 133 | render(nil) | 134 | render(nil) | ||
| 134 | - | c := windowColor(1) | 135 | + | check(0, 0, bg) |
| 135 | - | check(0, 0, color.RGBA{c[0], c[1], c[2], 255}) | |||
| 136 | } | 136 | } | ||
| 137 | 137 | ||||
| 138 | func TestRendererUploadOrderAndOpaque(t *testing.T) { | 138 | func TestRendererUploadOrderAndOpaque(t *testing.T) { | ||
| @@ -145,11 +145,16 @@ func TestRendererUploadOrderAndOpaque(t *testing.T) { | |||||
| 145 | {ID: 1, Rect: ports.Rect{X: 2, Y: 2, W: 16, H: 16}}, | 145 | {ID: 1, Rect: ports.Rect{X: 2, Y: 2, W: 16, H: 16}}, | ||
| 146 | {ID: 2, Rect: ports.Rect{X: 8, Y: 8, W: 16, H: 16}}, | 146 | {ID: 2, Rect: ports.Rect{X: 8, Y: 8, W: 16, H: 16}}, | ||
| 147 | }} | 147 | }} | ||
| 148 | - | if err := render(r, scene, nil); err != nil { | 148 | + | top := color.RGBA{10, 200, 10, 255} |
| 149 | + | upper := map[ports.WindowID]ports.SurfaceContent{1: solidContent(t, 16, 16, color.RGBA{200, 10, 10, 255}), 2: solidContent(t, 16, 16, top)} | |||
| 150 | + | for id, c := range upper { | |||
| 151 | + | c.Version = 1 // the opaque buffer below is another commit | |||
| 152 | + | upper[id] = c | |||
| 153 | + | } | |||
| 154 | + | if err := render(r, scene, upper); err != nil { | |||
| 149 | t.Fatal(err) | 155 | t.Fatal(err) | ||
| 150 | } | 156 | } | ||
| 151 | - | c := windowColor(2) | 157 | + | if got, want := r.Pixels().RGBAAt(10, 10), top; got != want { |
| 152 | - | if got, want := r.Pixels().RGBAAt(10, 10), (color.RGBA{c[0], c[1], c[2], 255}); got != want { | |||
| 153 | t.Errorf("overlap = %v, want %v", got, want) | 158 | t.Errorf("overlap = %v, want %v", got, want) | ||
| 154 | } | 159 | } | ||
| 155 | scene.Border = ports.Border{Width: 4, Active: "#ffffff"} | 160 | scene.Border = ports.Border{Width: 4, Active: "#ffffff"} | ||
| @@ -189,8 +194,7 @@ func TestRendererLayers(t *testing.T) { | |||||
| 189 | layer.ID, layer.Opaque = 2, true | 194 | layer.ID, layer.Opaque = 2, true | ||
| 190 | contents := map[ports.WindowID]ports.SurfaceContent{2: *layer} | 195 | contents := map[ports.WindowID]ports.SurfaceContent{2: *layer} | ||
| 191 | scene := ports.Scene{Background: "#102030", Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: 64, H: 48}}}, Layers: []ports.SceneLayer{{ID: 2, Layer: ports.LayerTop, Rect: ports.Rect{W: 64, H: 8}}}} | 196 | scene := ports.Scene{Background: "#102030", Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: 64, H: 48}}}, Layers: []ports.SceneLayer{{ID: 2, Layer: ports.LayerTop, Rect: ports.Rect{W: 64, H: 8}}}} | ||
| 192 | - | wc := windowColor(1) | 197 | + | window := color.RGBA{16, 32, 48, 255} // no buffer yet: background |
| 193 | - | window := color.RGBA{wc[0], wc[1], wc[2], 255} | |||
| 194 | check := func(want color.RGBA) { | 198 | check := func(want color.RGBA) { | ||
| 195 | t.Helper() | 199 | t.Helper() | ||
| 196 | if err := render(r, scene, contents); err != nil { | 200 | if err := render(r, scene, contents); err != nil { | ||
| @@ -368,11 +372,10 @@ func TestRendererTallFill(t *testing.T) { | |||||
| 368 | } | 372 | } | ||
| 369 | defer r.Close() | 373 | defer r.Close() | ||
| 370 | scene := ports.Scene{Background: "#102030", Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{X: 1, Y: 0, W: 6, H: h}}}} | 374 | scene := ports.Scene{Background: "#102030", Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{X: 1, Y: 0, W: 6, H: h}}}} | ||
| 371 | - | if err := render(r, scene, nil); err != nil { | 375 | + | wc := color.RGBA{200, 10, 10, 255} |
| 376 | + | if err := render(r, scene, map[ports.WindowID]ports.SurfaceContent{1: solidContent(t, 6, h, wc)}); err != nil { | |||
| 372 | t.Fatal(err) | 377 | t.Fatal(err) | ||
| 373 | } | 378 | } | ||
| 374 | - | c := windowColor(1) | |||
| 375 | - | wc := color.RGBA{c[0], c[1], c[2], 255} | |||
| 376 | bg := color.RGBA{16, 32, 48, 255} | 379 | bg := color.RGBA{16, 32, 48, 255} | ||
| 377 | px := r.Pixels() | 380 | px := r.Pixels() | ||
| 378 | for y := 0; y < h; y++ { | 381 | for y := 0; y < h; y++ { | ||
M internal/adapters/vulkan/scene.go +3 -28
| @@ -97,10 +97,9 @@ func (w *sceneWalk) windows() { | |||
| 97 | 97 | body := w.physRect(c.X, c.Y, c.W, c.H) | |
| 98 | 98 | content := w.contents[win.ID] | |
| 99 | 99 | w.dmg.window(win.ID, content, w.physRect(win.Rect.X, win.Rect.Y, win.Rect.W, win.Rect.H)) | |
| 100 | - | if content.Empty() { | |
| 101 | - | w.fill(body, windowColor(win.ID)) | |
| 102 | - | } else { | |
| 103 | - | w.fill(body, parseColor(w.s.Background)) | |
| 100 | + | // Until its first buffer, a window shows the background: no flash. | |
| 101 | + | w.fill(body, parseColor(w.s.Background)) | |
| 102 | + | if !content.Empty() { | |
| 104 | 103 | w.place(win.ID, &content, c.X, c.Y, c.W, c.H) | |
| 105 | 104 | } | |
| 106 | 105 | if win.Floating { | |
| @@ -335,27 +334,3 @@ func parseColor(s string) [3]uint8 { | |||
| 335 | 334 | } | |
| 336 | 335 | return c | |
| 337 | 336 | } | |
| 338 | - | ||
| 339 | - | // windowColor is the placeholder color of a window with no content yet. | |
| 340 | - | func windowColor(id ports.WindowID) [3]uint8 { | |
| 341 | - | h := math.Mod(float64(id)*0.618034, 1) * 6 | |
| 342 | - | sector := int(h) | |
| 343 | - | f := h - float64(sector) | |
| 344 | - | p, q, t := 0.4, 0.8*(1-0.5*f), 0.8*(1-0.5*(1-f)) | |
| 345 | - | var a, b, c float64 | |
| 346 | - | switch sector { | |
| 347 | - | case 0: | |
| 348 | - | a, b, c = 0.8, t, p | |
| 349 | - | case 1: | |
| 350 | - | a, b, c = q, 0.8, p | |
| 351 | - | case 2: | |
| 352 | - | a, b, c = p, 0.8, t | |
| 353 | - | case 3: | |
| 354 | - | a, b, c = p, q, 0.8 | |
| 355 | - | case 4: | |
| 356 | - | a, b, c = t, p, 0.8 | |
| 357 | - | default: | |
| 358 | - | a, b, c = 0.8, p, q | |
| 359 | - | } | |
| 360 | - | return [3]uint8{uint8(a * 255), uint8(b * 255), uint8(c * 255)} | |
| 361 | - | } | |
| @@ -97,10 +97,9 @@ func (w *sceneWalk) windows() { | |||||
| 97 | body := w.physRect(c.X, c.Y, c.W, c.H) | 97 | body := w.physRect(c.X, c.Y, c.W, c.H) | ||
| 98 | content := w.contents[win.ID] | 98 | content := w.contents[win.ID] | ||
| 99 | w.dmg.window(win.ID, content, w.physRect(win.Rect.X, win.Rect.Y, win.Rect.W, win.Rect.H)) | 99 | w.dmg.window(win.ID, content, w.physRect(win.Rect.X, win.Rect.Y, win.Rect.W, win.Rect.H)) | ||
| 100 | - | if content.Empty() { | 100 | + | // Until its first buffer, a window shows the background: no flash. |
| 101 | - | w.fill(body, windowColor(win.ID)) | 101 | + | w.fill(body, parseColor(w.s.Background)) |
| 102 | - | } else { | 102 | + | if !content.Empty() { |
| 103 | - | w.fill(body, parseColor(w.s.Background)) | |||
| 104 | w.place(win.ID, &content, c.X, c.Y, c.W, c.H) | 103 | w.place(win.ID, &content, c.X, c.Y, c.W, c.H) | ||
| 105 | } | 104 | } | ||
| 106 | if win.Floating { | 105 | if win.Floating { | ||
| @@ -335,27 +334,3 @@ func parseColor(s string) [3]uint8 { | |||||
| 335 | } | 334 | } | ||
| 336 | return c | 335 | return c | ||
| 337 | } | 336 | } | ||
| 338 | - | ||||
| 339 | - | // windowColor is the placeholder color of a window with no content yet. | |||
| 340 | - | func windowColor(id ports.WindowID) [3]uint8 { | |||
| 341 | - | h := math.Mod(float64(id)*0.618034, 1) * 6 | |||
| 342 | - | sector := int(h) | |||
| 343 | - | f := h - float64(sector) | |||
| 344 | - | p, q, t := 0.4, 0.8*(1-0.5*f), 0.8*(1-0.5*(1-f)) | |||
| 345 | - | var a, b, c float64 | |||
| 346 | - | switch sector { | |||
| 347 | - | case 0: | |||
| 348 | - | a, b, c = 0.8, t, p | |||
| 349 | - | case 1: | |||
| 350 | - | a, b, c = q, 0.8, p | |||
| 351 | - | case 2: | |||
| 352 | - | a, b, c = p, 0.8, t | |||
| 353 | - | case 3: | |||
| 354 | - | a, b, c = p, q, 0.8 | |||
| 355 | - | case 4: | |||
| 356 | - | a, b, c = t, p, 0.8 | |||
| 357 | - | default: | |||
| 358 | - | a, b, c = 0.8, p, q | |||
| 359 | - | } | |||
| 360 | - | return [3]uint8{uint8(a * 255), uint8(b * 255), uint8(c * 255)} | |||
| 361 | - | } | |||