graphics_state.go RawHistoryFolder
1package vt
2
3import (
4 "github.com/bnema/vev-vt/graphics"
5 "github.com/bnema/vev-vt/protocol/kittygraphics"
6)
7
8// screenGraphicsState owns the protocol adapter and scene for one VT screen
9// buffer. It is allocated only after the first Kitty graphics APC reaches the
10// screen, so ordinary text writes do not pay for graphics state.
11type screenGraphicsState struct {
12 scene *graphics.Scene
13 kitty *kittygraphics.Session
14}
15
16func newScreenGraphicsState() *screenGraphicsState {
17 scene := graphics.NewScene(graphics.Limits{})
18 return &screenGraphicsState{
19 scene: scene,
20 kitty: kittygraphics.NewSession(scene),
21 }
22}
23
24func (g *screenGraphicsState) snapshot() *graphics.Snapshot {
25 if g == nil || g.scene == nil {
26 return nil
27 }
28 return g.scene.Snapshot()
29}
30
31// clearPlacements applies the ordinary full-screen erase policy without
32// discarding uploaded image mappings. The protocol session owns those
33// mappings, so the operation goes through Kitty's delete-all-visible command
34// rather than mutating the scene directly.
35func (g *screenGraphicsState) clearPlacements() {
36 if g == nil || g.kitty == nil {
37 return
38 }
39 g.kitty.AbortPendingUpload()
40 _, _ = g.kitty.Process(kittygraphics.Command{Controls: kittygraphics.Controls{
41 Action: kittygraphics.ActionDelete,
42 HasAction: true,
43 Delete: kittygraphics.DeleteAll,
44 HasDelete: true,
45 Quiet: kittygraphics.QuietAll,
46 HasQuiet: true,
47 }})
48}
49
50func (s *Screen) graphicsClearPlacements() {
51 if s == nil {
52 return
53 }
54 if s.graphics != nil {
55 s.graphics.clearPlacements()
56 }
57 s.kittyPendingDisplay = nil
58}
59
60func (s *Screen) abortKittyPendingDisplay() {
61 if s == nil {
62 return
63 }
64 s.kittyPendingDisplay = nil
65 if s.graphics != nil && s.graphics.kitty != nil {
66 s.graphics.kitty.AbortPendingUpload()
67 }
68}
69
70func (s *Screen) abortAllKittyPending() {
71 if s == nil {
72 return
73 }
74 s.abortKittyPendingDisplay()
75 if state := s.alternate; state != nil {
76 state.kittyPendingDisplay = nil
77 if state.graphics != nil && state.graphics.kitty != nil {
78 state.graphics.kitty.AbortPendingUpload()
79 }
80 }
81}
82
83// GraphicsSnapshot returns an immutable snapshot of the active screen
84// buffer's graphics scene, or nil before graphics has been used. The returned
85// reference remains valid after subsequent Screen mutations.
86func (s *Screen) GraphicsSnapshot() *graphics.Snapshot {
87 if s == nil || s.graphics == nil {
88 return nil
89 }
90 return s.graphics.snapshot()
91}