ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
frame_buffer.h File Reference

Buffered terminal frame rendering. More...

Go to the source code of this file.

Typedefs

typedef struct frame_buffer frame_buffer_t
 Opaque frame buffer handle.

Functions

frame_buffer_t * frame_buffer_create (int rows, int cols)
 Create a new frame buffer.
void frame_buffer_destroy (frame_buffer_t *buf)
 Destroy a frame buffer.
void frame_buffer_reset (frame_buffer_t *buf)
 Clear buffer contents while keeping allocation.
void frame_buffer_append (frame_buffer_t *buf, const char *str, size_t len)
 Append raw bytes to the buffer.
void frame_buffer_printf (frame_buffer_t *buf, const char *fmt,...)
 Printf-style append to the buffer.
void frame_buffer_cursor_home (frame_buffer_t *buf)
 Append cursor home escape code (\033[H).
void frame_buffer_clear_screen (frame_buffer_t *buf)
 Append clear screen and home escape codes (\033[2J\033[H).
void frame_buffer_flush (frame_buffer_t *buf)
 Flush the entire buffer to stdout in one atomic write.
size_t frame_buffer_get_length (const frame_buffer_t *buf)
 Get the current content length of the frame buffer.
const char * frame_buffer_get_content (const frame_buffer_t *buf)
 Get a pointer to the buffer content.
void frame_buffer_render_border (frame_buffer_t *buf, int cols, const char *color)
 Render a horizontal border line (used by both splash and status screens).
void frame_buffer_render_divider (frame_buffer_t *buf, int width, bool use_utf8, bool use_colors)
int frame_buffer_render_centered (frame_buffer_t *buf, const char *text, int cols)
 Render centered text (used by both splash and status screens).
void frame_buffer_set_screen_output_fd (int fd)
 Set output file descriptor for terminal screen (splash/status) rendering.
int frame_buffer_get_screen_output_fd (void)
 Get current output file descriptor for terminal screens.

Detailed Description

Buffered terminal frame rendering.

Accumulates terminal output (ANSI codes, text, colors) into a single buffer, then flushes the entire frame in one atomic write. This eliminates the flicker that occurs when clearing the screen and rendering line-by-line.

Usage pattern: frame_buffer_t *buf = frame_buffer_create(rows, cols); frame_buffer_clear_screen(buf); frame_buffer_printf(buf, "Header line 1\n"); frame_buffer_printf(buf, "Header line 2\n"); frame_buffer_flush(buf); // Later, reuse the buffer: frame_buffer_reset(buf); frame_buffer_printf(buf, "New content\n"); frame_buffer_flush(buf);

Definition in file frame_buffer.h.

Typedef Documentation

◆ frame_buffer_t

typedef struct frame_buffer frame_buffer_t

Opaque frame buffer handle.

Definition at line 32 of file frame_buffer.h.

Function Documentation

◆ frame_buffer_append()

void frame_buffer_append ( frame_buffer_t * buf,
const char * str,
size_t len )

Append raw bytes to the buffer.

Parameters
bufFrame buffer
strPointer to data (may contain ANSI codes, not NULL-terminated)
lenNumber of bytes to append

Grows the buffer as needed. Does not add newlines or NULL terminators.

Definition at line 80 of file frame_buffer.c.

80 {
81 if (!buf || !str || len == 0) {
82 return;
83 }
84
85 // Grow buffer if needed
86 if (buf->len + len > buf->capacity) {
87 size_t new_capacity = buf->capacity * 2;
88 while (new_capacity < buf->len + len) {
89 new_capacity *= 2;
90 }
91
92 char *new_data = SAFE_MALLOC(new_capacity, char *);
93 if (!new_data) {
94 return; // Failed to grow, silently ignore
95 }
96
97 if (buf->len > 0 && buf->data) {
98 memcpy(new_data, buf->data, buf->len);
99 }
100
101 SAFE_FREE(buf->data);
102 buf->data = new_data;
103 buf->capacity = new_capacity;
104 }
105
106 // Append the data
107 memcpy(buf->data + buf->len, str, len);
108 buf->len += len;
109}
#define SAFE_FREE(ptr)
Definition common.h:377
#define SAFE_MALLOC(size, cast)
Definition common.h:265
char * data
Allocated buffer.
size_t len
Current content length.
size_t capacity
Allocated capacity.

References frame_buffer::capacity, frame_buffer::data, frame_buffer::len, SAFE_FREE, and SAFE_MALLOC.

Referenced by ascii_create_grid(), frame_buffer_clear_screen(), frame_buffer_cursor_home(), terminal_screen_compose(), ui_controller_write(), ui_error_popup_preserve(), ui_error_popup_render(), ui_input_render(), ui_media_panel_render(), ui_notice_flush_snapshot(), ui_notice_present(), ui_notice_render(), ui_scrollbar_render(), ui_session_media(), ui_session_render(), ui_text_render_values(), and ui_too_small_render().

◆ frame_buffer_clear_screen()

void frame_buffer_clear_screen ( frame_buffer_t * buf)

Append clear screen and home escape codes (\033[2J\033[H).

Parameters
bufFrame buffer

Combines clear screen and cursor home into a single operation for atomicity.

Definition at line 157 of file frame_buffer.c.

157 {
158 if (!buf) {
159 return;
160 }
161
162 // Combine clear screen and home in one operation
163 static const char clear[] = "\033[2J\033[H";
164 frame_buffer_append(buf, clear, sizeof(clear) - 1);
165}
void frame_buffer_append(frame_buffer_t *buf, const char *str, size_t len)
Append raw bytes to the buffer.

References frame_buffer_append().

Referenced by ui_session_render().

◆ frame_buffer_create()

frame_buffer_t * frame_buffer_create ( int rows,
int cols )

Create a new frame buffer.

Parameters
rowsTerminal row count (used for initial capacity estimate)
colsTerminal column count (used for initial capacity estimate)
Returns
Newly allocated frame buffer, or NULL on allocation failure

Initial capacity is set to rows * cols * 16 to account for ANSI escape overhead.

Definition at line 42 of file frame_buffer.c.

42 {
44 if (!buf) {
45 return NULL;
46 }
47
48 // Initial capacity: rows * cols * 16 to account for ANSI codes
49 size_t initial_capacity = (rows > 0 && cols > 0) ? (size_t)rows * cols * 16 : 4096;
50
51 buf->data = SAFE_MALLOC(initial_capacity, char *);
52 if (!buf->data) {
53 SAFE_FREE(buf);
54 return NULL;
55 }
56
57 buf->len = 0;
58 buf->capacity = initial_capacity;
59
60 return buf;
61}
struct frame_buffer frame_buffer_t
Opaque frame buffer handle.

References frame_buffer::capacity, frame_buffer::data, frame_buffer::len, SAFE_FREE, and SAFE_MALLOC.

Referenced by ascii_create_grid(), terminal_screen_compose(), tui_stats_render(), ui_error_popup_preserve(), ui_notice_flush_snapshot(), ui_notice_present(), ui_session_context_help_render(), ui_session_create(), and ui_session_help_render().

◆ frame_buffer_cursor_home()

void frame_buffer_cursor_home ( frame_buffer_t * buf)

Append cursor home escape code (\033[H).

Parameters
bufFrame buffer

Definition at line 149 of file frame_buffer.c.

149 {
150 if (!buf) {
151 return;
152 }
153
154 frame_buffer_append(buf, "\033[H", 3);
155}

References frame_buffer_append().

Referenced by tui_stats_render().

◆ frame_buffer_destroy()

void frame_buffer_destroy ( frame_buffer_t * buf)

Destroy a frame buffer.

Parameters
bufFrame buffer to destroy (may be NULL)

Definition at line 63 of file frame_buffer.c.

63 {
64 if (!buf) {
65 return;
66 }
67
68 SAFE_FREE(buf->data);
69 SAFE_FREE(buf);
70}

References frame_buffer::data, and SAFE_FREE.

Referenced by ascii_create_grid(), terminal_screen_compose(), tui_stats_render(), ui_error_popup_preserve(), ui_notice_flush_snapshot(), ui_notice_present(), ui_session_context_help_render(), ui_session_destroy(), and ui_session_help_render().

◆ frame_buffer_flush()

void frame_buffer_flush ( frame_buffer_t * buf)

Flush the entire buffer to stdout in one atomic write.

Parameters
bufFrame buffer

Writes all accumulated content to stdout via platform_write_all(), bypassing libc buffering. Safe for high-frequency rendering.

Definition at line 170 of file frame_buffer.c.

170 {
171 if (!buf || buf->len == 0 || !buf->data) {
172 return;
173 }
174
175 // Repaint from the top while erasing each line before writing it. A full
176 // screen erase on every animation frame exposes a black frame on Windows
177 // terminals and makes the splash appear to flicker.
178 size_t line_count = 1;
179 for (size_t i = 0; i < buf->len; i++) {
180 if (buf->data[i] == '\n') {
181 line_count++;
182 }
183 }
184
185 size_t output_size = 3 + buf->len + (line_count * 4);
186 char *output = SAFE_MALLOC(output_size, char *);
187 if (!output) {
188 return;
189 }
190
191 size_t output_len = 0;
192 memcpy(output + output_len, "\033[H", 3);
193 output_len += 3;
194 bool at_line_start = true;
195 for (size_t i = 0; i < buf->len; i++) {
196 if (at_line_start) {
197 memcpy(output + output_len, "\033[2K", 4);
198 output_len += 4;
199 at_line_start = false;
200 }
201 output[output_len++] = buf->data[i];
202 if (buf->data[i] == '\n') {
203 at_line_start = true;
204 }
205 }
206
207 ui_output_write(g_terminal_screen_output_fd, output, output_len);
208 SAFE_FREE(output);
209}
asciichat_error_t ui_output_write(int fd, const char *data, size_t length)
Definition output.c:16

References frame_buffer::data, frame_buffer::len, SAFE_FREE, SAFE_MALLOC, and ui_output_write().

◆ frame_buffer_get_content()

const char * frame_buffer_get_content ( const frame_buffer_t * buf)

Get a pointer to the buffer content.

Parameters
bufFrame buffer
Returns
Pointer to the buffer data (NULL if buffer is empty or NULL)

Returns the raw buffer content for reading. The content is NOT null-terminated. Use frame_buffer_get_length() to get the actual size.

Definition at line 227 of file frame_buffer.c.

227 {
228 if (!buf || !buf->data) {
229 return NULL;
230 }
231 return buf->data;
232}

References frame_buffer::data.

Referenced by ascii_create_grid(), terminal_screen_compose(), tui_stats_render(), ui_error_popup_preserve(), ui_notice_flush_snapshot(), ui_notice_present(), ui_session_context_help_render(), ui_session_help_render(), and ui_session_render().

◆ frame_buffer_get_length()

size_t frame_buffer_get_length ( const frame_buffer_t * buf)

Get the current content length of the frame buffer.

Parameters
bufFrame buffer
Returns
Number of bytes currently in the buffer

Useful for debugging and verifying frame consistency.

Definition at line 220 of file frame_buffer.c.

220 {
221 if (!buf) {
222 return 0;
223 }
224 return buf->len;
225}

References frame_buffer::len.

Referenced by ascii_create_grid(), terminal_screen_compose(), tui_stats_render(), ui_error_popup_preserve(), ui_notice_flush_snapshot(), ui_notice_present(), ui_session_context_help_render(), ui_session_frame_length(), ui_session_help_render(), and ui_session_tick().

◆ frame_buffer_get_screen_output_fd()

int frame_buffer_get_screen_output_fd ( void )

Get current output file descriptor for terminal screens.

Returns
File descriptor (STDOUT_FILENO or STDERR_FILENO)

Definition at line 216 of file frame_buffer.c.

216 {
217 return g_terminal_screen_output_fd;
218}

Referenced by ui_buttons_render(), ui_error_popup_render(), ui_media_panel_render(), and ui_status_render_header().

◆ frame_buffer_printf()

void frame_buffer_printf ( frame_buffer_t * buf,
const char * fmt,
... )

Printf-style append to the buffer.

Parameters
bufFrame buffer
fmtFormat string (standard printf syntax)
...Arguments

Formats the string into the buffer using snprintf. Grows buffer as needed.

Definition at line 111 of file frame_buffer.c.

111 {
112 if (!buf || !fmt) {
113 return;
114 }
115
116 // Ensure we have space for a formatted string
117 // Start with a reasonable buffer size
118 size_t remaining = buf->capacity - buf->len;
119 if (remaining < 256) {
120 // Grow buffer to have at least 512 bytes of space
121 size_t new_capacity = buf->capacity + 512;
122 char *new_data = SAFE_MALLOC(new_capacity, char *);
123 if (!new_data) {
124 return;
125 }
126
127 if (buf->len > 0 && buf->data) {
128 memcpy(new_data, buf->data, buf->len);
129 }
130
131 SAFE_FREE(buf->data);
132 buf->data = new_data;
133 buf->capacity = new_capacity;
134 remaining = buf->capacity - buf->len;
135 }
136
137 // Format the string into the buffer
138 va_list args;
139 va_start(args, fmt);
140 int written = vsnprintf(buf->data + buf->len, remaining, fmt, args);
141 va_end(args);
142
143 if (written > 0 && written < (int)remaining) {
144 buf->len += (size_t)written;
145 }
146 // If vsnprintf failed or truncated, we silently ignore (buffer may be full)
147}
action_args_t args
Definition actions.c:78

References args, frame_buffer::capacity, frame_buffer::data, frame_buffer::len, SAFE_FREE, and SAFE_MALLOC.

Referenced by frame_buffer_render_centered(), invitation_render(), terminal_screen_compose(), tui_stats_render(), ui_buttons_render(), ui_error_popup_preserve(), ui_error_popup_render(), ui_input_render(), ui_media_panel_render(), ui_notice_render(), ui_popup_frame(), ui_popup_frame_titled(), ui_popup_render(), ui_popup_rule(), ui_scrollbar_render(), ui_session_render(), ui_session_splash_render(), ui_spinner_render(), ui_status_render_header(), and ui_table_render().

◆ frame_buffer_render_border()

void frame_buffer_render_border ( frame_buffer_t * buf,
int cols,
const char * color )

Render a horizontal border line (used by both splash and status screens).

Parameters
bufFrame buffer to write into
colsTerminal width (number of columns)
colorANSI color code (e.g., "\033[1;36m" for cyan) or NULL for no color

Definition at line 246 of file frame_buffer.c.

246 {
247 render_rule(buf, cols - 1, color, terminal_should_use_utf8(GET_OPTION(force_utf8)));
248}
#define GET_OPTION(field)
Safely get a specific option field (lock-free read).
Definition options.h:1336

References GET_OPTION.

Referenced by tui_stats_render().

◆ frame_buffer_render_centered()

int frame_buffer_render_centered ( frame_buffer_t * buf,
const char * text,
int cols )

Render centered text (used by both splash and status screens).

Parameters
bufFrame buffer to write into
textText to center (may contain ANSI codes)
colsTerminal width
Returns
Padding added on left side (for manual padding if needed)

Automatically centers the text accounting for ANSI escape codes.

Definition at line 254 of file frame_buffer.c.

254 {
255 if (!buf || !text || cols <= 0) {
256 return 0;
257 }
258
259 // Calculate visible width accounting for ANSI codes
260 int visible_width = display_width(text);
261 if (visible_width < 0) {
262 visible_width = (int)strlen(text);
263 }
264
265 int padding = (cols - visible_width) / 2;
266 if (padding < 0) {
267 padding = 0;
268 }
269
270 for (int i = 0; i < padding; i++) {
271 frame_buffer_printf(buf, " ");
272 }
273 frame_buffer_printf(buf, "%s\n", text);
274
275 return padding;
276}
void frame_buffer_printf(frame_buffer_t *buf, const char *fmt,...)
Printf-style append to the buffer.
int display_width(const char *text)
Calculate the visible display width of text with ANSI escape codes.

References display_width(), and frame_buffer_printf().

◆ frame_buffer_render_divider()

void frame_buffer_render_divider ( frame_buffer_t * buf,
int width,
bool use_utf8,
bool use_colors )

Theme-blue divider of exactly width cells, followed by a newline.

Definition at line 250 of file frame_buffer.c.

250 {
251 render_rule(buf, width, use_colors ? ui_text_color_prefix(LOG_COLOR_DEBUG) : NULL, use_utf8);
252}
unsigned int width
Definition fft.c:23
@ LOG_COLOR_DEBUG
Definition log/log.h:149
const char * ui_text_color_prefix(log_color_t color)
Definition text.c:18

References LOG_COLOR_DEBUG, ui_text_color_prefix(), and width.

Referenced by ui_session_splash_render(), and ui_status_render_header().

◆ frame_buffer_reset()

void frame_buffer_reset ( frame_buffer_t * buf)

Clear buffer contents while keeping allocation.

Resets the buffer for a new frame without deallocating the underlying memory. More efficient than destroy/create for repeated frame rendering.

Parameters
bufFrame buffer to reset

Definition at line 72 of file frame_buffer.c.

72 {
73 if (!buf) {
74 return;
75 }
76
77 buf->len = 0;
78}

References frame_buffer::len.

Referenced by ui_session_clear(), ui_session_media(), and ui_session_render().

◆ frame_buffer_set_screen_output_fd()

void frame_buffer_set_screen_output_fd ( int fd)

Set output file descriptor for terminal screen (splash/status) rendering.

Parameters
fdFile descriptor (STDOUT_FILENO for TTY, STDERR_FILENO for piped output)

Controls where splash and status screens write their output. Used internally by terminal_screen_render() for consistent output routing.

Definition at line 211 of file frame_buffer.c.

211 {
212 g_terminal_screen_output_fd = fd;
214}
int colored_string_set_output_fd(int fd)
Definition string.c:274

References colored_string_set_output_fd().

Referenced by terminal_screen_set_output_fd().