uncurses/screen/state.rs
1//! Non-render terminal/input mode state owned by the [`Screen`] facade.
2//!
3//! These modes do not affect how the renderer measures, renders, or
4//! presents a frame — they configure the terminal device and the input
5//! reader. The facade tracks them so it can tear them down on a shell
6//! handoff and re-apply them afterwards.
7//!
8//! [`Screen`]: super::Screen
9
10use std::collections::BTreeMap;
11
12use crate::ansi::cursor::CursorStyle;
13use crate::ansi::kitty::KittyKeyboardFlags;
14use crate::color::Color;
15use crate::event::ModifyOtherKeysMode;
16use crate::layout::Position;
17
18use super::MouseTracking;
19
20/// Tracked non-render mode state for save/restore.
21#[derive(Debug, Clone)]
22pub(super) struct State {
23 /// Cursor style.
24 pub cursor_style: CursorStyle,
25 /// Requested mouse tracking, or `None` when mouse tracking is disabled.
26 pub mouse: Option<MouseTracking>,
27 /// Bracketed paste mode.
28 pub bracketed_paste: bool,
29 /// Focus in/out reporting (DECSET 1004).
30 pub focus_events: bool,
31 /// Color-scheme update notifications (DEC 2031). When `true`, the
32 /// terminal sends unsolicited reports as the user/OS toggles the
33 /// dark/light scheme. Reports the dark/light preference only, not the
34 /// actual colors.
35 pub color_scheme_updates: bool,
36 /// In-band resize notifications (DEC 2048). When `true`, the
37 /// terminal sends a `CSI 48 ; … t` report whenever the surface
38 /// changes size, surfaced as [`Event::Resize`].
39 ///
40 /// [`Event::Resize`]: crate::event::Event::Resize
41 pub in_band_resize: bool,
42 /// Window title set via [`OSC 2`] (or [`OSC 0`], which sets both this and
43 /// [`icon_name`](Self::icon_name)). `None` when no
44 /// [`set_window_title`](super::Screen::set_window_title) or
45 /// [`set_title`](super::Screen::set_title) override has been set.
46 ///
47 /// [`OSC 2`]: crate::ansi::title::write_window_title
48 /// [`OSC 0`]: crate::ansi::title::write_window_title_and_icon
49 pub window_title: Option<String>,
50 /// Icon name set via [`OSC 1`] (or [`OSC 0`], which sets both this and
51 /// [`window_title`](Self::window_title)). `None` when no
52 /// [`set_icon_title`](super::Screen::set_icon_title) or
53 /// [`set_title`](super::Screen::set_title) override has been set.
54 ///
55 /// [`OSC 1`]: crate::ansi::title::write_icon_name
56 /// [`OSC 0`]: crate::ansi::title::write_window_title_and_icon
57 pub icon_name: Option<String>,
58 /// Default foreground color override. `Some(c)` when the facade has
59 /// emitted `OSC 10` to install `c`; `None` when the terminal is
60 /// using its built-in default. Drives `OSC 110` on reset and
61 /// re-emission on restore.
62 pub foreground_color: Option<Color>,
63 /// Default background color override. See [`State::foreground_color`].
64 pub background_color: Option<Color>,
65 /// Cursor color override. See [`State::foreground_color`].
66 pub cursor_color: Option<Color>,
67 /// Indexed palette overrides set via `OSC 4`, keyed by palette index.
68 /// Drives `OSC 104 ; index` on reset and re-emission on restore.
69 pub palette: BTreeMap<u8, Color>,
70 /// Active xterm modifyOtherKeys mode (`CSI > 4 ; n m`). Drives
71 /// `CSI > 4 m` on reset and re-emission on restore.
72 pub modify_other_keys: ModifyOtherKeysMode,
73 /// Pointer (mouse cursor) shape override set via `OSC 22`. `None` when
74 /// using the terminal default. Drives the `OSC 22` reset on reset and
75 /// re-emission on restore.
76 pub pointer_shape: Option<String>,
77 // --- Render-coupled state (formerly tracked by the renderer buffer) -----------
78 /// Whether the alternate screen is currently active.
79 pub alt_screen: bool,
80 /// Cursor visibility.
81 pub cursor_visible: bool,
82 /// Synchronized updates: when `true`, each non-empty frame is wrapped in
83 /// synchronized-output begin/end sequences.
84 pub sync_updates: bool,
85 /// Unicode core / grapheme cluster mode (DEC 2027). When `true`, width is
86 /// calculated per grapheme cluster (UTS-29 + emoji rules); when `false`,
87 /// per code point (wcwidth-style).
88 pub grapheme_clusters: bool,
89 /// Active Kitty keyboard enhancement flag set. The kitty stack is
90 /// per-screen-buffer, so the screen re-emits this onto whichever buffer
91 /// becomes active. `NONE` means no frame is set.
92 pub kitty_keyboard: KittyKeyboardFlags,
93 /// Declarative resting position for the cursor, applied at the end of
94 /// every [`render`](super::Screen::render) via
95 /// [`set_cursor_position`](super::Screen::set_cursor_position). Sticky:
96 /// it persists across frames and is re-applied each render (a no-op when
97 /// the cursor is already there) until changed or cleared. `None` means no
98 /// declarative resting position, so the cursor is left wherever the cell
99 /// diff ended. Visibility is orthogonal — see
100 /// [`show_cursor`](super::Screen::show_cursor) /
101 /// [`hide_cursor`](super::Screen::hide_cursor).
102 pub desired_cursor: Option<Position>,
103}
104
105impl Default for State {
106 fn default() -> Self {
107 Self {
108 cursor_style: CursorStyle::Default,
109 mouse: None,
110 bracketed_paste: false,
111 focus_events: false,
112 color_scheme_updates: false,
113 in_band_resize: false,
114 window_title: None,
115 icon_name: None,
116 foreground_color: None,
117 background_color: None,
118 cursor_color: None,
119 palette: BTreeMap::new(),
120 modify_other_keys: ModifyOtherKeysMode::Disabled,
121 pointer_shape: None,
122 alt_screen: false,
123 cursor_visible: true,
124 sync_updates: false,
125 grapheme_clusters: false,
126 kitty_keyboard: KittyKeyboardFlags::empty(),
127 desired_cursor: None,
128 }
129 }
130}
131
132/// Terminal capabilities detected from the replies to the queries
133/// [`Screen::init`](super::Screen::init) fires. Every field answers a
134/// single question: does the terminal support this? The facade intercepts
135/// the reply events as they flow through
136/// [`read_event`](super::Screen::read_event) / [`try_read_event`](super::Screen::try_read_event),
137/// records support here, and applies the render-affecting ones — the app
138/// never sees the reply events. Read back with
139/// [`Screen::capabilities`](super::Screen::capabilities).
140#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
141pub struct Capabilities {
142 /// Synchronized output (DEC private mode 2026). Applied: frames are
143 /// wrapped in begin/end-synchronized-update markers.
144 pub synchronized_output: bool,
145 /// Unicode core / grapheme-cluster mode (DEC private mode 2027).
146 /// Applied: cell widths are measured per grapheme cluster.
147 pub grapheme_clusters: bool,
148 /// In-band resize notifications (DEC private mode 2048).
149 pub in_band_resize: bool,
150 /// Normal mouse button tracking (DEC private mode 1000).
151 pub mouse_normal: bool,
152 /// Button-event mouse tracking (DEC private mode 1002).
153 pub mouse_button: bool,
154 /// Any-event mouse tracking (DEC private mode 1003).
155 pub mouse_any: bool,
156 /// SGR mouse encoding (DEC private mode 1006).
157 pub mouse_sgr: bool,
158 /// SGR-pixel mouse encoding (DEC private mode 1016).
159 pub mouse_sgr_pixel: bool,
160 /// Sixel graphics (Primary DA attribute 4).
161 pub sixel: bool,
162 /// Clipboard access (Primary DA attribute 52).
163 pub clipboard: bool,
164 /// Kitty keyboard protocol (the terminal answered `CSI ? u`).
165 pub kitty_keyboard: bool,
166 /// xterm modifyOtherKeys (the terminal answered `CSI ? 4 m`).
167 pub modify_other_keys: bool,
168 /// Direct (24-bit) color, confirmed by an XTGETTCAP `RGB`/`Tc` reply.
169 /// Applied: the renderer's color profile is upgraded to
170 /// [`Profile::TrueColor`](crate::color::Profile::TrueColor).
171 pub true_color: bool,
172}