feat: desktop environment improvements

This commit is contained in:
2026-02-20 09:03:30 +01:00
parent 987a85da27
commit f018ab6e4d
23 changed files with 2479 additions and 644 deletions
+151
View File
@@ -0,0 +1,151 @@
/*
* app_klog.cpp
* ZenithOS Desktop - Kernel Log viewer (tails the kernel ring buffer)
* Copyright (c) 2026 Daniel Hammer
*/
#include "apps_common.hpp"
// ============================================================================
// Kernel Log state
// ============================================================================
static constexpr int KLOG_READ_SIZE = 65536; // matches kernel ring buffer size
static constexpr int KLOG_POLL_MS = 250;
struct KlogState {
TerminalState term;
char* klog_buf;
int last_len;
char last_tail_byte;
uint64_t last_poll_ms;
};
// ============================================================================
// Re-feed the last screenful of log into the terminal
// ============================================================================
static void klog_refeed(KlogState* klog, int n) {
// Find start of last `rows` lines from the end of the buffer
int lines_needed = klog->term.rows;
int start = 0;
for (int i = n - 1; i >= 0 && lines_needed > 0; i--) {
if (klog->klog_buf[i] == '\n') {
lines_needed--;
if (lines_needed == 0) { start = i + 1; break; }
}
}
// Clear terminal
int total = klog->term.cols * klog->term.rows;
for (int i = 0; i < total; i++)
klog->term.cells[i] = {' ', colors::TERM_FG, colors::TERM_BG};
klog->term.cursor_x = 0;
klog->term.cursor_y = 0;
klog->term.current_fg = colors::TERM_FG;
klog->term.current_bg = colors::TERM_BG;
terminal_feed(&klog->term, klog->klog_buf + start, n - start);
}
// ============================================================================
// Callbacks
// ============================================================================
static void klog_on_draw(Window* win, Framebuffer& fb) {
KlogState* klog = (KlogState*)win->app_data;
if (!klog) return;
Rect cr = win->content_rect();
terminal_render(&klog->term, win->content, cr.w, cr.h);
}
static void klog_on_mouse(Window* win, MouseEvent& ev) {
// Read-only viewer — no mouse interaction needed
}
static void klog_on_key(Window* win, const Zenith::KeyEvent& key) {
// Read-only viewer — no keyboard input
}
static void klog_on_poll(Window* win) {
KlogState* klog = (KlogState*)win->app_data;
if (!klog) return;
uint64_t now = zenith::get_milliseconds();
if (now - klog->last_poll_ms < KLOG_POLL_MS) return;
klog->last_poll_ms = now;
int n = (int)zenith::read_klog(klog->klog_buf, KLOG_READ_SIZE);
if (n <= 0 && klog->last_len <= 0) return;
if (n > klog->last_len) {
// Buffer grew — feed only the new portion
terminal_feed(&klog->term, klog->klog_buf + klog->last_len, n - klog->last_len);
} else if (n == klog->last_len && n > 0) {
// Same size — check if the tail changed (ring buffer wrapped)
if (klog->klog_buf[n - 1] != klog->last_tail_byte) {
klog_refeed(klog, n);
} else {
return; // nothing changed
}
} else if (n < klog->last_len) {
// Unexpected shrink — full re-render
klog_refeed(klog, n);
}
klog->last_len = n;
if (n > 0) klog->last_tail_byte = klog->klog_buf[n - 1];
}
static void klog_on_close(Window* win) {
KlogState* klog = (KlogState*)win->app_data;
if (klog) {
if (klog->term.cells) zenith::mfree(klog->term.cells);
if (klog->term.alt_cells) zenith::mfree(klog->term.alt_cells);
if (klog->klog_buf) zenith::mfree(klog->klog_buf);
zenith::mfree(klog);
win->app_data = nullptr;
}
}
// ============================================================================
// Kernel Log launcher
// ============================================================================
void open_klog(DesktopState* ds) {
int idx = desktop_create_window(ds, "Kernel Log", 160, 60, 720, 480);
if (idx < 0) return;
Window* win = &ds->windows[idx];
Rect cr = win->content_rect();
int cols = cr.w / FONT_WIDTH;
int rows = cr.h / FONT_HEIGHT;
KlogState* klog = (KlogState*)zenith::malloc(sizeof(KlogState));
zenith::memset(klog, 0, sizeof(KlogState));
// Initialize the terminal cell grid (reuse terminal infrastructure)
terminal_init_cells(&klog->term, cols, rows);
// Allocate klog read buffer
klog->klog_buf = (char*)zenith::malloc(KLOG_READ_SIZE);
klog->last_len = 0;
klog->last_tail_byte = 0;
klog->last_poll_ms = 0;
// Do an initial read to show existing log content
int n = (int)zenith::read_klog(klog->klog_buf, KLOG_READ_SIZE);
if (n > 0) {
klog_refeed(klog, n);
klog->last_len = n;
klog->last_tail_byte = klog->klog_buf[n - 1];
}
win->app_data = klog;
win->on_draw = klog_on_draw;
win->on_mouse = klog_on_mouse;
win->on_key = klog_on_key;
win->on_close = klog_on_close;
win->on_poll = klog_on_poll;
}