ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
display.c
Go to the documentation of this file.
1
72#include "display.h"
73#include "main.h"
74
76#include "platform/util.h"
77#include "options/options.h"
78#include "options/rcu.h" // For RCU-based options access
79#include "video/ascii.h"
80
81#include <fcntl.h>
82#include <string.h>
83#include <stdio.h>
84#include <stdatomic.h>
85
86/* ============================================================================
87 * TTY Management
88 * ============================================================================ */
89
102tty_info_t g_tty_info = {-1, NULL, false};
103
113static bool g_has_tty = false;
114
124static atomic_bool g_is_first_frame_of_connection = true;
125
126/* ============================================================================
127 * TTY Detection and Initialization
128 * ============================================================================ */
129
149static tty_info_t display_get_current_tty(void) {
150 // Use the platform abstraction layer function
151 return get_current_tty();
152}
153
172static void full_terminal_reset(int fd) {
173 // Skip terminal control sequences in snapshot mode - just print raw ASCII
174 if (!GET_OPTION(snapshot_mode)) {
175 terminal_reset(fd); // Reset using the proper TTY fd
176 console_clear(fd); // This calls terminal_clear_screen() + terminal_cursor_home(fd)
177 terminal_clear_scrollback(fd); // Clear scrollback using the proper TTY fd
178 terminal_hide_cursor(fd, true); // Hide cursor on the specific TTY
179 terminal_flush(fd); // Flush the specific TTY fd
180 }
181}
182
183/* ============================================================================
184 * Frame Rendering Functions
185 * ============================================================================ */
186
204static void write_frame_to_output(const char *frame_data, bool use_direct_tty) {
205 // Validate parameters
206 if (!frame_data) {
207 SET_ERRNO(ERROR_INVALID_PARAM, "write_frame_to_output: NULL frame_data");
208 return;
209 }
210
211 // Calculate length safely to avoid potential segfault in strlen
212 size_t frame_len = strnlen(frame_data, 1024 * 1024); // Max 1MB frame
213 if (frame_len == 0) {
214 SET_ERRNO(ERROR_INVALID_PARAM, "write_frame_to_output: Empty frame data");
215 return;
216 }
217
218 if (use_direct_tty) {
219 // Direct TTY for interactive use
220 if (g_tty_info.fd >= 0) {
221 // Always position cursor for TTY output (even in snapshot mode)
223 platform_write(g_tty_info.fd, frame_data, frame_len);
224 // Flush terminal buffer to ensure immediate visibility
226 } else {
227 log_error("Failed to open TTY: %s", g_tty_info.path ? g_tty_info.path : "unknown");
228 }
229 } else {
230 // stdout for pipes/redirection/testing
231 // Skip cursor reset in snapshot mode - just print raw ASCII
232 if (!GET_OPTION(snapshot_mode)) {
233 cursor_reset(STDOUT_FILENO);
234 }
235 platform_write(STDOUT_FILENO, frame_data, frame_len);
236 // Flush stdout to ensure immediate visibility
237 (void)fflush(stdout);
238 // Only fsync if we have a valid file descriptor and not on Windows console
239 if (!platform_isatty(STDOUT_FILENO)) {
240 platform_fsync(STDOUT_FILENO);
241 }
242 }
243}
244
245/* ============================================================================
246 * Public Interface Functions
247 * ============================================================================ */
248
266 // Get TTY info for direct terminal access (if needed for interactive mode)
267 g_tty_info = display_get_current_tty();
268
269 // Determine if we should use interactive TTY output
270 // For output routing: only consider stdout status (not controlling terminal)
271 // Additional TTY validation: if stdout is redirected but we have a controlling TTY,
272 // we can still show interactive output on the terminal
273 if (g_tty_info.fd >= 0) {
274 g_has_tty = platform_isatty(g_tty_info.fd) != 0; // We have a valid controlling terminal
275 // Initialize ASCII output for this connection (only if we have a valid TTY)
277 }
278
279 return 0;
280}
281
290 return g_has_tty;
291}
292
302 if (g_tty_info.fd >= 0 && !should_exit()) {
303 full_terminal_reset(g_tty_info.fd);
304 }
305}
306
316 atomic_store(&g_is_first_frame_of_connection, true);
317}
318
328 // Disable terminal logging before clearing display and rendering first frame
329 if (atomic_load(&g_is_first_frame_of_connection)) {
331 atomic_store(&g_is_first_frame_of_connection, false);
332 }
333}
334
353void display_render_frame(const char *frame_data, bool is_snapshot_frame) {
354 if (!frame_data) {
355 SET_ERRNO(ERROR_INVALID_PARAM, "Attempted to render NULL frame data");
356 return;
357 }
358
359 // For terminal: print every frame until final snapshot
360 // For non-terminal: only print the final snapshot frame
361 if (g_has_tty || (!g_has_tty && GET_OPTION(snapshot_mode) && is_snapshot_frame)) {
362 if (is_snapshot_frame) {
363 // Write the final frame to the terminal as well, not just to stdout
364 write_frame_to_output(frame_data, true);
365 }
366
367 // The real ASCII data frame write call
368 write_frame_to_output(frame_data, g_has_tty && !is_snapshot_frame);
369
370 if (GET_OPTION(snapshot_mode) && is_snapshot_frame) {
371 // A newline at the end of the snapshot of ASCII art to end the file
372 printf("\n");
373 }
374 }
375}
376
386 // Cleanup ASCII rendering
388
389 // Close the controlling terminal if we opened it
390 if (g_tty_info.owns_fd && g_tty_info.fd >= 0) {
392 g_tty_info.fd = -1;
393 g_tty_info.owns_fd = false;
394 }
395
396 g_has_tty = false;
397}
🔌 Cross-platform abstraction layer umbrella header for ascii-chat
🖼️ ASCII Art Conversion and Output Interface
bool should_exit()
Check if client should exit.
ascii-chat Client Display Management Interface
bool display_has_tty()
Check if display has TTY capability.
Definition display.c:289
int display_init()
Initialize what is necessary to display ascii frames.
Definition display.c:265
void display_full_reset()
Perform full display reset.
Definition display.c:301
tty_info_t g_tty_info
Global TTY information structure.
Definition display.c:102
void display_cleanup()
Cleanup display subsystem.
Definition display.c:385
void display_disable_logging_for_first_frame()
Disable terminal logging for first frame.
Definition display.c:327
void display_render_frame(const char *frame_data, bool is_snapshot_frame)
Render ASCII frame to display.
Definition display.c:353
void display_reset_for_new_connection()
Reset display state for new connection.
Definition display.c:315
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
@ ERROR_INVALID_PARAM
#define log_error(...)
Log an ERROR message.
void log_set_terminal_output(bool enabled)
Control stderr output to terminal.
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
Definition options.h:644
asciichat_error_t terminal_reset(int fd)
Reset terminal to default state.
asciichat_error_t terminal_clear_scrollback(int fd)
Clear terminal scrollback buffer.
int platform_fsync(int fd)
Synchronize a file descriptor to disk.
int platform_isatty(int fd)
Check if a file descriptor is a terminal.
tty_info_t get_current_tty(void)
Get current TTY information.
int platform_close(int fd)
Safe file close (close replacement)
asciichat_error_t terminal_flush(int fd)
Flush terminal output.
ssize_t platform_write(int fd, const void *buf, size_t count)
Platform-safe write function.
asciichat_error_t terminal_hide_cursor(int fd, bool hide)
Hide or show cursor.
asciichat_error_t ascii_write_init(int fd, bool reset_terminal)
Initialize ASCII write subsystem.
Definition ascii.c:40
void ascii_write_destroy(int fd, bool reset_terminal)
Destroy ASCII write subsystem.
Definition ascii.c:334
#define console_clear(fd)
Clear console and move cursor to home position.
Definition ascii.h:524
#define cursor_reset(fd)
Reset cursor to home position.
Definition ascii.h:535
⚙️ Command-line options parsing and configuration management for ascii-chat
Public platform utility API for string, memory, and file operations.
ascii-chat Server Mode Entry Point Header
TTY detection and management structure.
Definition terminal.h:523
bool owns_fd
True if we opened the FD and should close it, false otherwise.
Definition terminal.h:529
int fd
File descriptor for TTY access.
Definition terminal.h:525
const char * path
Path to TTY device (e.g., "/dev/tty", "CON", etc.)
Definition terminal.h:527