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

Go to the source code of this file.

Data Structures

struct  ui_session
 This is the handoff point for ui session. Callers fill size, frame, media, logs before passing it on; consumers read the values during the operation and return ownership only where the member contract explicitly says they do. More...

Macros

#define TUI_SESSION_DETAIL_BUFFER_SIZE   256
#define TUI_SESSION_OFFSET_TEXT_BUFFER_SIZE   32
#define PRESENTATION_TIME_HISTORY_COUNT   120

Functions

ui_session_t * ui_session_create (void)
void ui_session_destroy (ui_session_t *s)
void ui_session_resize (ui_session_t *s, int cols, int rows)
void ui_session_loading (ui_session_t *s, bool loading, const char *message)
void ui_session_log (ui_session_t *s, const char *message)
asciichat_error_t ui_session_media (ui_session_t *s, const char *data, size_t length)
ui_session_action_t ui_session_input (ui_session_t *s, keyboard_key_t key)
int ui_session_select_screen (uint32_t visible_screens)
bool ui_session_is_covered (const ui_session_t *s)
size_t ui_session_frame_length (const ui_session_t *s)
uint64_t ui_session_next_frame_ns (const ui_session_t *s)
const char * ui_session_render (ui_session_t *s, const ui_session_view_t *view, uint64_t now_ns)
void ui_session_logs_render (frame_buffer_t *output, terminal_size_t size, ui_session_t *s)
bool ui_session_logs_key (keyboard_key_t key)
const char * ui_session_tick (ui_session_t *s, uint64_t now_ns)
void ui_session_clear (ui_session_t *s)
terminal_size_t ui_session_size (const ui_session_t *s)
void ui_session_redraw (ui_session_t *s)
void ui_session_capture_logs (ui_session_t *s)

Macro Definition Documentation

◆ PRESENTATION_TIME_HISTORY_COUNT

#define PRESENTATION_TIME_HISTORY_COUNT   120

Definition at line 7 of file lib/tui/session.c.

◆ TUI_SESSION_DETAIL_BUFFER_SIZE

#define TUI_SESSION_DETAIL_BUFFER_SIZE   256

Definition at line 3 of file lib/tui/session.c.

Referenced by ui_session_logs_render().

◆ TUI_SESSION_OFFSET_TEXT_BUFFER_SIZE

#define TUI_SESSION_OFFSET_TEXT_BUFFER_SIZE   32

Definition at line 4 of file lib/tui/session.c.

Referenced by ui_session_logs_render().

Function Documentation

◆ ui_session_capture_logs()

void ui_session_capture_logs ( ui_session_t * session)

Attach this instance to the module's existing C logger. Detaches on destruction.

Definition at line 375 of file lib/tui/session.c.

375 {
376 if (s)
378}
void log_set_session_log_buffer(session_log_buffer_t *buf)
Register a session log buffer with the logger.
Definition log.c:2048
session_log_buffer_t * logs

References log_set_session_log_buffer(), and ui_session::logs.

Referenced by SessionUiBinding::SessionUiBinding().

◆ ui_session_clear()

void ui_session_clear ( ui_session_t * s)

Definition at line 357 of file lib/tui/session.c.

357 {
358 if (s) {
360 s->help = false;
361 s->show_logs = false;
362 s->dirty = true;
363 }
364}
void frame_buffer_reset(frame_buffer_t *buf)
Clear buffer contents while keeping allocation.
frame_buffer_t * media

References ui_session::dirty, frame_buffer_reset(), ui_session::help, ui_session::media, and ui_session::show_logs.

Referenced by SessionUiBinding::clear().

◆ ui_session_create()

ui_session_t * ui_session_create ( void )

Definition at line 46 of file lib/tui/session.c.

46 {
47 ui_session_t *s = SAFE_CALLOC(1, sizeof(*s), ui_session_t *);
48 if (!s)
49 return NULL;
50 s->frame = frame_buffer_create(24, 80);
51 s->media = frame_buffer_create(24, 80);
53 s->owns_logs = !s->logs;
54 if (s->owns_logs)
56 if (!s->frame || !s->media || !s->logs) {
58 return NULL;
59 }
60 s->started = time(NULL);
62 s->size = (terminal_size_t){.cols = 80, .rows = 24};
63 s->active = -1;
64 s->saved_volume = 1;
65 s->dirty = true;
66 s->splash.use_colors = true;
67 animation_init(&s->animation, "session_splash",
69 .type = ANIMATION_SPLASH_RAINBOW, .fps = 60, .speed = 1, .hidden_policy = ANIMATION_HIDDEN_PAUSE});
70 return s;
71}
frame_buffer_t * frame_buffer_create(int rows, int cols)
Create a new frame buffer.
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275
struct ui_session ui_session_t
void ui_session_destroy(ui_session_t *s)
session_log_buffer_t * log_get_history_buffer(void)
Definition log.c:565
asciichat_error_t log_search_init(void)
Initialize interactive grep subsystem.
Definition search.c:144
session_log_buffer_t * session_log_buffer_create(void)
Create a new session log buffer instance.
frame_buffer_t * frame
ui_splash_view_t splash
animation_t animation
terminal_size_t size
double saved_volume
asciichat_error_t animation_init(animation_t *a, const char *name, animation_config_t config)

References ui_session::active, ui_session::animation, animation_init(), ui_session::dirty, ui_session::frame, frame_buffer_create(), log_get_history_buffer(), log_search_init(), ui_session::logs, ui_session::media, ui_session::owns_logs, SAFE_CALLOC, ui_session::saved_volume, session_log_buffer_create(), ui_session::size, ui_session::splash, ui_session::started, ui_session_destroy(), and ui_splash_view_t::use_colors.

Referenced by SessionUiBinding::SessionUiBinding().

◆ ui_session_destroy()

void ui_session_destroy ( ui_session_t * s)

Definition at line 73 of file lib/tui/session.c.

73 {
74 if (!s)
75 return;
81 if (s->owns_logs)
83 SAFE_FREE(s);
84}
void frame_buffer_destroy(frame_buffer_t *buf)
Destroy a frame buffer.
#define SAFE_FREE(ptr)
Definition common.h:377
session_log_buffer_t * log_get_session_log_buffer(void)
Get the currently registered session log buffer.
Definition log.c:2071
void log_clear_session_log_buffer(void)
Unregister the session log buffer.
Definition log.c:2057
void session_log_buffer_destroy(session_log_buffer_t *buf)
Cleanup session log buffer instance.
void animation_destroy(animation_t *a)

References ui_session::animation, animation_destroy(), ui_session::frame, frame_buffer_destroy(), log_clear_session_log_buffer(), log_get_session_log_buffer(), ui_session::logs, ui_session::media, ui_session::owns_logs, SAFE_FREE, and session_log_buffer_destroy().

Referenced by ui_controller_shutdown(), ui_session_create(), and SessionUiBinding::~SessionUiBinding().

◆ ui_session_frame_length()

size_t ui_session_frame_length ( const ui_session_t * s)

Definition at line 165 of file lib/tui/session.c.

165 {
166 size_t length = s ? frame_buffer_get_length(s->frame) : 0;
167 return length ? length - 1 : 0;
168}
size_t frame_buffer_get_length(const frame_buffer_t *buf)
Get the current content length of the frame buffer.

References ui_session::frame, and frame_buffer_get_length().

◆ ui_session_input()

ui_session_action_t ui_session_input ( ui_session_t * s,
keyboard_key_t key )

Definition at line 129 of file lib/tui/session.c.

129 {
130 if (!s)
131 return UI_ACTION_NONE;
132 if (s->show_logs && ui_session_logs_key_sized(key, s->size)) {
133 s->dirty = true;
134 return UI_ACTION_LOGS;
135 }
137 if (action == UI_ACTION_HELP) {
138 s->help = !s->help;
139 s->show_logs = false;
140 } else if (action == UI_ACTION_LOGS) {
141 s->show_logs = !s->show_logs;
142 s->help = false;
143 } else if (action == UI_ACTION_CLOSE && s->show_logs) {
144 s->show_logs = false;
146 } else if (action == UI_ACTION_CLOSE && s->help) {
147 s->help = false;
149 }
150 s->dirty |= action != UI_ACTION_NONE;
151 return action;
152}
deferred_action_t action
Definition actions.c:77
ui_session_action_t ui_session_key(keyboard_key_t key, double *saved_volume)

References action, ui_session::dirty, ui_session::help, ui_session::saved_volume, ui_session::show_logs, ui_session::size, UI_ACTION_CLOSE, UI_ACTION_HELP, UI_ACTION_LOGS, UI_ACTION_NONE, and ui_session_key().

Referenced by SessionUiBinding::key().

◆ ui_session_is_covered()

bool ui_session_is_covered ( const ui_session_t * s)

Definition at line 161 of file lib/tui/session.c.

161 {
162 return s && s->covered;
163}

References ui_session::covered.

◆ ui_session_loading()

void ui_session_loading ( ui_session_t * s,
bool loading,
const char * message )

Definition at line 97 of file lib/tui/session.c.

97 {
98 if (!s)
99 return;
100 if (loading != s->loading) {
101 s->loading = loading;
103 s->dirty = true;
104 }
105 if (message && strcmp(message, s->splash.connection_target)) {
107 s->dirty = true;
108 }
109}
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:423
void animation_reset(animation_t *a)

References ui_session::animation, animation_reset(), ui_splash_view_t::connection_target, ui_session::dirty, ui_session::loading, SAFE_STRNCPY, and ui_session::splash.

Referenced by SessionUiBinding::loading().

◆ ui_session_log()

void ui_session_log ( ui_session_t * s,
const char * message )

Definition at line 111 of file lib/tui/session.c.

111 {
112 if (s && message) {
113 session_log_buffer_append(s->logs, message);
114 s->dirty = true;
115 }
116}
void session_log_buffer_append(session_log_buffer_t *buf, const char *message)
Append a log message to the buffer.

References ui_session::dirty, ui_session::logs, and session_log_buffer_append().

Referenced by SessionUiBinding::log().

◆ ui_session_logs_key()

bool ui_session_logs_key ( keyboard_key_t key)

Existing server log-search controls; true when consumed.

Definition at line 296 of file lib/tui/session.c.

296 {
297 return ui_session_logs_key_sized(key, ui_controller_size());
298}
terminal_size_t ui_controller_size(void)

References ui_controller_size().

◆ ui_session_logs_render()

void ui_session_logs_render ( frame_buffer_t * output,
terminal_size_t size,
ui_session_t * session )

Shared live log view, used by the native adapter and browser compositor.

Definition at line 244 of file lib/tui/session.c.

244 {
246 size_t offset = terminal_screen_logs_offset();
247 char offset_text[TUI_SESSION_OFFSET_TEXT_BUFFER_SIZE];
248 snprintf(offset_text, sizeof(offset_text), "%zu", offset);
249 const char *colored_offset = colored_string(LOG_COLOR_FATAL, offset_text);
250 snprintf(detail, sizeof(detail), "%s | %s rows from tail", ui_status_log_controls(), colored_offset);
251 ui_status_t status = {.mode_name = "", .start_time = s->started, .detail = detail};
252 terminal_screen_config_t config = {
253 .fixed_header_lines = 4, .render_header = ui_status_render_header, .user_data = &status, .show_logs = true};
254 terminal_screen_compose(output, size, &config, s->logs);
255}
@ LOG_COLOR_FATAL
Definition log/log.h:153
const char * colored_string(log_color_t color, const char *text)
Build a colored string for terminal output.
Definition string.c:284
#define TUI_SESSION_DETAIL_BUFFER_SIZE
#define TUI_SESSION_OFFSET_TEXT_BUFFER_SIZE
void ui_status_render_header(frame_buffer_t *buf, terminal_size_t term_size, void *user_data)
void terminal_screen_compose(frame_buffer_t *output, terminal_size_t size, const terminal_screen_config_t *config, session_log_buffer_t *logs)
const char * ui_status_log_controls(void)
Definition status.c:34
Configuration for terminal screen rendering.
Status information for server/discovery service modes.
Definition status.h:38
size_t terminal_screen_logs_offset(void)

References colored_string(), LOG_COLOR_FATAL, ui_session::logs, ui_session::started, terminal_screen_compose(), terminal_screen_logs_offset(), TUI_SESSION_DETAIL_BUFFER_SIZE, TUI_SESSION_OFFSET_TEXT_BUFFER_SIZE, ui_status_log_controls(), and ui_status_render_header().

◆ ui_session_media()

asciichat_error_t ui_session_media ( ui_session_t * s,
const char * data,
size_t length )

Definition at line 118 of file lib/tui/session.c.

118 {
119 if (!s || !data || length > UI_CONTROLLER_MAX_FRAME_BYTES)
120 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid session media frame");
122 frame_buffer_append(s->media, data, length);
123 s->dirty = true;
124 return ASCIICHAT_OK;
125}
#define SET_ERRNO(code,...)
void frame_buffer_append(frame_buffer_t *buf, const char *str, size_t len)
Append raw bytes to the buffer.
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
#define UI_CONTROLLER_MAX_FRAME_BYTES

References ASCIICHAT_OK, ui_session::dirty, ERROR_INVALID_PARAM, frame_buffer_append(), frame_buffer_reset(), ui_session::media, SET_ERRNO, and UI_CONTROLLER_MAX_FRAME_BYTES.

Referenced by SessionUiBinding::media().

◆ ui_session_next_frame_ns()

uint64_t ui_session_next_frame_ns ( const ui_session_t * session)

Next visible animation deadline, or UINT64_MAX while animation is paused/hidden.

Definition at line 170 of file lib/tui/session.c.

170 {
171 return s && s->animation.started ? s->splash.animation.next_frame_ns : UINT64_MAX;
172}

References ui_session::animation, ui_splash_view_t::animation, animation_sample_t::next_frame_ns, ui_session::splash, and animation_t::started.

◆ ui_session_redraw()

void ui_session_redraw ( ui_session_t * s)

Definition at line 370 of file lib/tui/session.c.

370 {
371 if (s)
372 s->dirty = true;
373}

References ui_session::dirty.

Referenced by SessionUiBinding::redraw(), and ui_controller_redraw().

◆ ui_session_render()

const char * ui_session_render ( ui_session_t * session,
const ui_session_view_t * view,
uint64_t now_ns )

Present a host view through the same compositor used by ui_session_tick(). A screen of -1 hides presentation. NULL means no redraw is required.

Definition at line 174 of file lib/tui/session.c.

174 {
175 if (!s || !view)
176 return NULL;
177 bool changed = s->active != view->screen;
178 s->active = view->screen;
179 bool covered = view->screen >= 0 && ui_too_small(s->size, view->minimum);
180 bool transition = changed || covered != s->covered || s->size.cols != s->presented_size.cols ||
181 s->size.rows != s->presented_size.rows || view->minimum.cols != s->minimum.cols ||
182 view->minimum.rows != s->minimum.rows;
183 s->covered = covered;
184 bool visible =
185 (view->screen == UI_SCREEN_SPLASH || view->screen == UI_SCREEN_HELP || view->screen == UI_SCREEN_MDNS) &&
186 !covered;
187 if (visible != s->animation.visible) {
188 // Account for the elapsed interval under the old visibility before changing
189 // it, so resuming after an idle modal does not advance a paused animation.
190 if (animation_update(&s->animation, now_ns, &s->splash.animation) != ASCIICHAT_OK)
191 return NULL;
192 animation_set_visible(&s->animation, visible);
193 }
194 if (animation_update(&s->animation, now_ns, &s->splash.animation) != ASCIICHAT_OK)
195 return NULL;
196 if (view->screen < 0 || !view->draw)
197 return NULL;
198 bool animated = visible && s->splash.animation.changed;
199 bool refresh = view->refresh_ns && now_ns - s->last_render_ns >= view->refresh_ns;
200 if (covered ? !(transition || s->dirty) : !(transition || s->dirty || view->dirty || animated || refresh))
201 return NULL;
202 s->dirty = false;
203 s->presented_size = s->size;
204 s->minimum = view->minimum;
205 s->last_render_ns = now_ns;
207 if (transition || view->clear) {
208 frame_buffer_append(s->frame, "\033[0m", 4);
210 }
211 if (covered)
212 ui_too_small_render(s->frame, s->size, view->minimum);
213 else {
214 if (view->screen == UI_SCREEN_HELP) {
215 int top = (s->size.rows - view->minimum.rows) / 2;
216 terminal_color_mode_t mode = GET_OPTION(color_mode);
217 bool colors = mode != TERM_COLOR_NONE && GET_OPTION(color) != COLOR_SETTING_FALSE && !GET_OPTION(strip_ansi) &&
218 (mode != TERM_COLOR_AUTO ||
219 detect_terminal_capabilities(options_terminal_settings()).color_level != TERM_COLOR_NONE);
220 frame_buffer_printf(s->frame, "\033[%d;1H", top + 2);
221 invitation_render_logo(s->frame, s->size.cols, (int)(s->splash.animation.seconds * 60), colors, false);
222 }
223 view->draw(s->frame, s->size, &s->splash.animation, view->context);
224 }
225 frame_buffer_append(s->frame, "\0", 1);
227}
int color_mode
Definition fft.c:25
unsigned char colors[(512 *256 *2) *3]
Definition fft.c:22
const char * frame_buffer_get_content(const frame_buffer_t *buf)
Get a pointer to the buffer content.
void frame_buffer_printf(frame_buffer_t *buf, const char *fmt,...)
Printf-style append to the buffer.
void frame_buffer_clear_screen(frame_buffer_t *buf)
Append clear screen and home escape codes (\033[2J\033[H).
#define GET_OPTION(field)
Safely get a specific option field (lock-free read).
Definition options.h:1336
#define options_terminal_settings()
Definition options.h:1296
@ COLOR_SETTING_FALSE
Force colors OFF: disable all colors and logging colors.
Definition options.h:249
void invitation_render_logo(frame_buffer_t *buf, int cols, int frame, bool colors, bool compact)
Definition invitation.c:34
uint64_t last_render_ns
terminal_size_t minimum
terminal_size_t presented_size
void ui_too_small_render(frame_buffer_t *buffer, terminal_size_t actual, terminal_size_t minimum)
Definition too_small.c:38
bool ui_too_small(terminal_size_t actual, terminal_size_t minimum)
Definition too_small.c:10
@ UI_SCREEN_SPLASH
@ UI_SCREEN_MDNS
@ UI_SCREEN_HELP
asciichat_error_t animation_update(animation_t *a, uint64_t now, animation_sample_t *out)
void animation_set_visible(animation_t *a, bool visible)

References ui_session::active, ui_session::animation, ui_splash_view_t::animation, animation_set_visible(), animation_update(), ASCIICHAT_OK, animation_sample_t::changed, ui_session_view_t::clear, color_mode, COLOR_SETTING_FALSE, colors, ui_session_view_t::context, ui_session::covered, ui_session::dirty, ui_session_view_t::dirty, ui_session_view_t::draw, ui_session::frame, frame_buffer_append(), frame_buffer_clear_screen(), frame_buffer_get_content(), frame_buffer_printf(), frame_buffer_reset(), GET_OPTION, invitation_render_logo(), ui_session::last_render_ns, ui_session::minimum, ui_session_view_t::minimum, options_terminal_settings, ui_session::presented_size, ui_session_view_t::refresh_ns, ui_session_view_t::screen, animation_sample_t::seconds, ui_session::size, ui_session::splash, UI_SCREEN_HELP, UI_SCREEN_MDNS, UI_SCREEN_SPLASH, ui_too_small(), ui_too_small_render(), and animation_t::visible.

Referenced by ui_session_tick().

◆ ui_session_resize()

void ui_session_resize ( ui_session_t * s,
int cols,
int rows )

Definition at line 86 of file lib/tui/session.c.

86 {
87 if (!s || cols < 1 || rows < 1 || cols > 4096 || rows > 4096) {
88 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid TUI session or terminal dimensions");
89 return;
90 }
91 if (cols != s->size.cols || rows != s->size.rows) {
92 s->size = (terminal_size_t){.cols = cols, .rows = rows};
93 s->dirty = true;
94 }
95}

References ui_session::dirty, ERROR_INVALID_PARAM, SET_ERRNO, and ui_session::size.

Referenced by SessionUiBinding::resize().

◆ ui_session_select_screen()

int ui_session_select_screen ( uint32_t visible_screens)

Highest visible screen from the common priority order, or -1.

Definition at line 154 of file lib/tui/session.c.

154 {
155 for (int screen = UI_SCREEN_COUNT - 1; screen >= 0; --screen)
156 if (visible_screens & (1u << screen))
157 return screen;
158 return -1;
159}
@ UI_SCREEN_COUNT

References UI_SCREEN_COUNT.

Referenced by ui_session_tick().

◆ ui_session_size()

terminal_size_t ui_session_size ( const ui_session_t * s)

Definition at line 366 of file lib/tui/session.c.

366 {
367 return s ? s->size : (terminal_size_t){.cols = 80, .rows = 24};
368}

References ui_session::size.

Referenced by ui_controller_size().

◆ ui_session_tick()

const char * ui_session_tick ( ui_session_t * session,
uint64_t now_ns )

No sleeps or I/O. Returned frame remains valid until the next call. NULL means unchanged.

Definition at line 319 of file lib/tui/session.c.

319 {
320 if (!s)
321 return NULL;
322 if (!s->dirty && !s->show_logs && !s->help && !s->loading && s->active == UI_SCREEN_MEDIA)
323 return NULL;
324 uint32_t visible = 1u << UI_SCREEN_MEDIA;
325 if (s->loading)
326 visible |= 1u << UI_SCREEN_SPLASH;
327 if (s->show_logs)
328 visible |= 1u << UI_SCREEN_LOGS;
329 if (s->help)
330 visible |= 1u << UI_SCREEN_HELP;
331 ui_session_view_t view = {
332 .screen = ui_session_select_screen(visible), .minimum = {1, 1}, .clear = !s->help, .context = s};
333 char *help = NULL;
334 if (view.screen == UI_SCREEN_HELP) {
335 help = ui_session_help_render(s->size, true, true, &view.minimum);
336 if (!help)
337 return NULL;
338 view.draw = draw_help;
339 view.context = help;
340 } else if (view.screen == UI_SCREEN_LOGS) {
341 view.minimum = (terminal_size_t){.cols = 40, .rows = 6};
342 view.refresh_ns = 100000000;
343 view.draw = draw_logs;
344 } else if (view.screen == UI_SCREEN_SPLASH) {
345 view.minimum = (terminal_size_t){.cols = 52, .rows = 10};
346 view.draw = draw_splash;
347 } else {
348 view.draw = draw_media;
349 if (s->dirty && frame_buffer_get_length(s->media))
350 s->presentation_times[s->presentation_index++ % 120] = now_ns;
351 }
352 const char *frame = ui_session_render(s, &view, now_ns);
354 return frame;
355}
unsigned int uint32_t
Definition common.h:62
int ui_session_select_screen(uint32_t visible_screens)
const char * ui_session_render(ui_session_t *s, const ui_session_view_t *view, uint64_t now_ns)
void ui_session_help_free(char *text)
char * ui_session_help_render(terminal_size_t size, bool has_media, bool browser, terminal_size_t *minimum)
uint64_t presentation_times[120]
unsigned presentation_index
@ UI_SCREEN_LOGS
@ UI_SCREEN_MEDIA

References ui_session::active, ui_session_view_t::context, ui_session::dirty, ui_session_view_t::draw, frame_buffer_get_length(), ui_session::help, ui_session::loading, ui_session::media, ui_session_view_t::minimum, ui_session::presentation_index, ui_session::presentation_times, ui_session_view_t::refresh_ns, ui_session_view_t::screen, ui_session::show_logs, ui_session::size, UI_SCREEN_HELP, UI_SCREEN_LOGS, UI_SCREEN_MEDIA, UI_SCREEN_SPLASH, ui_session_help_free(), ui_session_help_render(), ui_session_render(), and ui_session_select_screen().

Referenced by SessionUiBinding::tick().