ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
splash.c File Reference

Intro and status screen display implementation with animated rainbow effects. More...

Go to the source code of this file.

Data Structures

struct  splash_header_ctx_t
 Context data for splash header rendering. More...
 

Macros

#define ASCII_LOGO_LINES   7
 
#define ASCII_LOGO_WIDTH   36
 
#define RAINBOW_COLOR_COUNT   7
 

Functions

bool splash_should_display (bool is_intro)
 
int splash_intro_start (session_display_ctx_t *ctx)
 
int splash_intro_done (void)
 
int splash_display_status (int mode)
 
void splash_set_update_notification (const char *notification)
 

Detailed Description

Intro and status screen display implementation with animated rainbow effects.

Implements splash screen functionality including:

  • TTY detection with stdin/stdout checks
  • Animated rainbow color generation and cycling
  • UTF-8 box drawing character support with ASCII fallback
  • Non-blocking animation that runs while app initializes
  • Clean integration with main frame rendering
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
February 2026

Definition in file splash.c.

Macro Definition Documentation

◆ ASCII_LOGO_LINES

#define ASCII_LOGO_LINES   7

Definition at line 46 of file splash.c.

◆ ASCII_LOGO_WIDTH

#define ASCII_LOGO_WIDTH   36

Definition at line 47 of file splash.c.

◆ RAINBOW_COLOR_COUNT

#define RAINBOW_COLOR_COUNT   7

Definition at line 62 of file splash.c.

Function Documentation

◆ splash_display_status()

int splash_display_status ( int  mode)

Definition at line 546 of file splash.c.

546 {
547 // Pre-checks
548 if (!splash_should_display(false)) {
549 return 0;
550 }
551
552 // Check mode validity
553 if (mode != 0 && mode != 3) { // MODE_SERVER=0, MODE_DISCOVERY_SERVICE=3
554 log_error("Status screen only for server/discovery modes");
555 return 1; // ERROR
556 }
557
558 // Check terminal size
559 int width = GET_OPTION(width);
560 int height = GET_OPTION(height);
561 if (width < 50 || height < 15) {
562 log_debug("Terminal too small for status screen");
563 return 0;
564 }
565
566 // Get terminal capabilities for UTF-8
567 bool has_utf8 = (GET_OPTION(force_utf8) >= 0);
568 (void)has_utf8; // Suppress unused warning
569
570 // Build and display status box
571 terminal_clear_screen();
572
573 char buffer[4096] = {0};
574 snprintf(buffer, sizeof(buffer), "\n");
575
576 if (mode == 0) {
577 // Server mode
578 snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), " Server Status\n");
579 snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), " Address: %s:%d\n", GET_OPTION(address),
580 GET_OPTION(port));
581 snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), " Max clients: %d\n", GET_OPTION(max_clients));
582 snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), " Encryption: %s\n",
583 GET_OPTION(no_encrypt) ? "Disabled" : "Enabled");
584 } else if (mode == 3) {
585 // Discovery service mode
586 snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), " Discovery Service\n");
587 snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), " Address: %s:%d\n", GET_OPTION(address),
588 GET_OPTION(discovery_port));
589 }
590
591 // Add update notification if available
592 static bool mutex_initialized_for_status = false;
593 if (!mutex_initialized_for_status) {
594 mutex_init(&g_update_notification_mutex);
595 mutex_initialized_for_status = true;
596 }
597 mutex_lock(&g_update_notification_mutex);
598 if (g_update_notification[0] != '\0') {
599 snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "\n %s\n",
600 colored_string(LOG_COLOR_WARN, g_update_notification));
601 }
602 mutex_unlock(&g_update_notification_mutex);
603
604 snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "\n");
605
606 printf("%s", buffer);
607 fflush(stdout);
608
609 return 0; // ASCIICHAT_OK
610}
bool splash_should_display(bool is_intro)
Definition splash.c:372
int mutex_init(mutex_t *mutex)
Definition threading.c:16
const char * colored_string(log_color_t color, const char *text)

References colored_string(), mutex_init(), and splash_should_display().

◆ splash_intro_done()

int splash_intro_done ( void  )

Definition at line 526 of file splash.c.

526 {
527 // Signal animation thread to stop
528 atomic_store(&g_splash_state.should_stop, true);
529
530 // Wait for animation thread to finish
531 if (atomic_load(&g_splash_state.is_running)) {
532 asciichat_thread_join(&g_splash_state.anim_thread, NULL);
533 }
534
535 atomic_store(&g_splash_state.is_running, false);
536
537 // Don't clear screen here - first frame will do it
538 // Clearing here can cause a brief scroll artifact during transition
539
540 // NOTE: Do NOT cleanup session_log_buffer here - it may be used by status screen
541 // Status screen will call session_log_buffer_destroy() when appropriate
542
543 return 0; // ASCIICHAT_OK
544}
int asciichat_thread_join(asciichat_thread_t *thread, void **retval)
Definition threading.c:46

References asciichat_thread_join().

Referenced by display_disable_logging_for_first_frame(), and session_client_like_run().

◆ splash_intro_start()

int splash_intro_start ( session_display_ctx_t ctx)

Definition at line 482 of file splash.c.

482 {
483 (void)ctx; // Parameter not used currently
484
485 // Pre-checks
486 if (!splash_should_display(true)) {
487 return 0; // ASCIICHAT_OK equivalent
488 }
489
490 // Don't initialize log buffer in non-interactive mode - logs go directly to stdout/stderr
492 return 0;
493 }
494
495 // Check terminal size
496 int width = GET_OPTION(width);
497 int height = GET_OPTION(height);
498 if (width < 50 || height < 20) {
499 return 0;
500 }
501
502 // Initialize log buffer for capturing logs during animation
504 log_warn("Failed to initialize splash log buffer");
505 return 0;
506 }
507
508 // Clear screen
509 terminal_clear_screen();
510 fflush(stdout);
511
512 // Set running flag
513 atomic_store(&g_splash_state.is_running, true);
514 atomic_store(&g_splash_state.should_stop, false);
515 g_splash_state.frame = 0;
516
517 // Start animation thread
518 if (asciichat_thread_create(&g_splash_state.anim_thread, splash_animation_thread, NULL) != ASCIICHAT_OK) {
519 log_warn("Failed to create splash animation thread");
520 return 0;
521 }
522
523 return 0; // ASCIICHAT_OK
524}
bool terminal_is_interactive(void)
bool session_log_buffer_init(void)
int asciichat_thread_create(asciichat_thread_t *thread, void *(*start_routine)(void *), void *arg)
Definition threading.c:42

References asciichat_thread_create(), session_log_buffer_init(), splash_should_display(), and terminal_is_interactive().

Referenced by session_client_like_run().

◆ splash_set_update_notification()

void splash_set_update_notification ( const char *  notification)

Definition at line 612 of file splash.c.

612 {
613 static bool mutex_initialized = false;
614 if (!mutex_initialized) {
615 mutex_init(&g_update_notification_mutex);
616 mutex_initialized = true;
617 }
618
619 mutex_lock(&g_update_notification_mutex);
620
621 if (!notification || notification[0] == '\0') {
622 g_update_notification[0] = '\0';
623 log_debug("Cleared update notification for splash/status screens");
624 } else {
625 SAFE_STRNCPY(g_update_notification, notification, sizeof(g_update_notification));
626 log_debug("Set update notification for splash/status screens: %s", notification);
627 }
628
629 mutex_unlock(&g_update_notification_mutex);
630}

References mutex_init().

Referenced by main().

◆ splash_should_display()

bool splash_should_display ( bool  is_intro)

Definition at line 372 of file splash.c.

372 {
373 // Check option flags (display splash if enabled, regardless of TTY for testing)
374 if (is_intro) {
375 // Allow splash in snapshot mode if loading from URL/file (has loading time)
376 // Skip splash only for quick webcam snapshots
377 bool is_snapshot = GET_OPTION(snapshot_mode);
378 bool has_media = (GET_OPTION(media_url) && strlen(GET_OPTION(media_url)) > 0) ||
379 (GET_OPTION(media_file) && strlen(GET_OPTION(media_file)) > 0);
380
381 // Show splash if:
382 // 1. Not in snapshot mode, OR
383 // 2. In snapshot mode but loading from URL/file (needs splash during load)
384 return GET_OPTION(splash) && (!is_snapshot || has_media);
385 } else {
386 return GET_OPTION(status_screen);
387 }
388}

Referenced by splash_display_status(), and splash_intro_start().