1package vulkan
2
3import (
4 "image"
5 "image/color"
6 "testing"
7
8 "github.com/bnema/neferwl/internal/ports"
9)
10
11func TestWorkspaceClipWindowsPopupsAndLayers(t *testing.T) {
12 r, err := New(64, 48)
13 if err != nil {
14 t.Skipf("Vulkan unavailable: %v", err)
15 }
16 defer r.Close()
17 red := color.RGBA{255, 0, 0, 255}
18 green := color.RGBA{0, 255, 0, 255}
19 contents := map[ports.WindowID]ports.SurfaceContent{1: solidContent(t, 64, 48, red), 2: solidContent(t, 8, 8, green)}
20 clip := ports.Rect{X: 16, Y: 12, W: 32, H: 24}
21 scene := ports.Scene{Seq: 1, OutputWidth: 64, OutputHeight: 48, Background: "#000000", WorkspaceClip: clip,
22 Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: 64, H: 48}}},
23 Layers: []ports.SceneLayer{{ID: 2, Rect: ports.Rect{W: 8, H: 8}, Layer: ports.LayerTop}},
24 }
25 if err := render(r, scene, contents); err != nil {
26 t.Fatal(err)
27 }
28 pixels := readPixels(t, r)
29 for point, want := range map[image.Point]color.RGBA{{0, 0}: green, {10, 10}: {0, 0, 0, 255}, {16, 12}: red, {47, 35}: red, {48, 36}: {0, 0, 0, 255}} {
30 if got := pixels.RGBAAt(point.X, point.Y); got != want {
31 t.Errorf("pixel %v=%v, want %v", point, got, want)
32 }
33 }
34 // Content-only damage at the same scene sequence must remain clipped.
35 changed := contents[1]
36 changed.Seq++
37 changed.DamageHistory = []ports.SeqDamage{{Seq: changed.Seq, Full: true}}
38 if _, err := changed.SHM.File.WriteAt([]byte{255, 255, 255, 255}, 0); err != nil {
39 t.Fatal(err)
40 }
41 contents[1] = changed
42 if err := render(r, scene, contents); err != nil {
43 t.Fatal(err)
44 }
45 if got := readPixels(t, r).RGBAAt(10, 10); got != (color.RGBA{0, 0, 0, 255}) {
46 t.Fatalf("damage escaped clip: %v", got)
47 }
48 // A popup from a workspace surface is clipped too; input popups over
49 // layers retain output-wide bounds.
50 scene.Seq++
51 scene.Windows = []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: 64, H: 48}, Popup: true}}
52 if err := render(r, scene, contents); err != nil {
53 t.Fatal(err)
54 }
55 if got := readPixels(t, r).RGBAAt(10, 10); got != (color.RGBA{0, 0, 0, 255}) {
56 t.Fatalf("popup escaped clip: %v", got)
57 }
58 // Popups above layers belong to output-wide controls, not the workspace.
59 // Scenes are immutable snapshots (the target holds the previous one):
60 // a changed window goes in a fresh slice, as core publishes it.
61 scene.Seq++
62 scene.Windows = []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: 64, H: 48}, Popup: true, OverLayers: true}}
63 if err := render(r, scene, contents); err != nil {
64 t.Fatal(err)
65 }
66 if got := readPixels(t, r).RGBAAt(10, 10); got != red {
67 t.Fatalf("output-wide popup clipped: %v", got)
68 }
69 scene.Windows = []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: 64, H: 48}, Popup: true}}
70 // Switching back to inherited geometry repaints the margins.
71 scene.Seq++
72 scene.WorkspaceClip = ports.Rect{}
73 if err := render(r, scene, contents); err != nil {
74 t.Fatal(err)
75 }
76 if got := readPixels(t, r).RGBAAt(10, 10); got != red {
77 t.Fatalf("stale clip after inheritance: %v", got)
78 }
79}