1package drm
2
3import (
4 "testing"
5
6 "github.com/bnema/neferwl/internal/adapters/outputkit/surfaces"
7 "github.com/bnema/neferwl/internal/ports"
8)
9
10// A window drawn from a content its client withdrew (it closed and fades
11// out) never goes on a plane: wayland has released its buffer, so the
12// client may already draw into it. The first leaving scene carries Fade 0
13// and Zoom 0 (the fade starts at opaque), so the kept flag alone refuses it.
14func TestLeavingWindowNeverOnAPlane(t *testing.T) {
15 t.Run("overlay plane, a single leaving tile", func(t *testing.T) {
16 o, _, _ := overlayOutput(t)
17 o.overlay.formats = []ports.DMABufFormat{{Format: fourccXRGB}}
18 table := surfaces.New()
19 o.kept = table.Kept
20 s, c := overlayScene()
21 table.Update(c[2], s)
22 // Window 2 unmaps: its empty content keeps the last one, Acquire
23 // dropped, while the scene lists it.
24 table.Update(ports.SurfaceContent{ID: 2}, s)
25 if !table.Kept(2) {
26 t.Fatal("setup: content not kept")
27 }
28 if _, _, _, reason := overlayCandidate(s, table.Map(), false, nil, o.kept); reason != "leaving" {
29 t.Fatalf("overlay reason %q, want leaving", reason)
30 }
31 ov, rest := o.overlayFrame(s, table.Map())
32 if ov.fb != 0 || len(rest.Windows) != 2 || o.overlayReason != "leaving" {
33 t.Fatalf("leaving window put on the overlay: %+v rest %d reason %q", ov, len(rest.Windows), o.overlayReason)
34 }
35 // Without the kept flag the same scene goes on the plane: the
36 // refusal is the flag's.
37 if _, _, _, reason := overlayCandidate(s, c, false, nil, nil); reason != "" {
38 t.Fatalf("control: reason %q", reason)
39 }
40 // A new content of a remapped window frees it again.
41 table.Update(c[2], s)
42 if _, _, _, reason := overlayCandidate(s, table.Map(), false, nil, o.kept); reason != "" {
43 t.Fatalf("remapped window refused: %q", reason)
44 }
45 })
46 t.Run("direct scanout of a lone leaving fullscreen window", func(t *testing.T) {
47 s, c := fullscreenScene()
48 table := surfaces.New()
49 for _, cc := range c {
50 table.Update(cc, s)
51 }
52 id := s.Windows[0].ID
53 if _, reason := scanoutCandidate(s, table.Map(), 200, 100, table.Kept); reason != "" {
54 t.Fatalf("control: reason %q", reason)
55 }
56 table.Update(ports.SurfaceContent{ID: id}, s)
57 if _, reason := scanoutCandidate(s, table.Map(), 200, 100, table.Kept); reason != "leaving" {
58 t.Fatalf("scanout reason %q, want leaving", reason)
59 }
60 // Through the output: composed, reason logged.
61 o, _, _ := testOutput(t)
62 o.kept = table.Kept
63 o.scanout = true
64 if fb, _, _ := o.scanoutFrame(s, table.Map()); fb != 0 || o.reason != "leaving" {
65 t.Fatalf("direct scanout of a leaving window: fb %d reason %q", fb, o.reason)
66 }
67 })
68 t.Run("not reported shown", func(t *testing.T) {
69 o, _, _ := testOutput(t)
70 table := surfaces.New()
71 o.kept = table.Kept
72 s, c := overlayScene()
73 table.Update(c[2], s)
74 seen := map[ports.WindowID]uint64{2: 3}
75 if shows := o.shownBy(s, seen); shows[2] != 3 {
76 t.Fatalf("control: shows %v", shows)
77 }
78 table.Update(ports.SurfaceContent{ID: 2, Seq: 4}, s)
79 seen[2] = 4
80 if shows := o.shownBy(s, seen); len(shows) != 0 {
81 t.Fatalf("a leaving window is reported shown: %v", shows)
82 }
83 })
84}