mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
feat(gui,kernel): 1080p HD desktop, polished chrome, ktime clock + live FPS
GUI polish / HD: - Default display mode raised to 1920x1080 (video=1920x1080); make run/vnc use vgamem_mb=64 and -m 512M. The growable heap absorbs the larger backbuffer, shadow and wallpaper (observed: one 16 MB growth to a 48 MB heap). - Wallpaper: three-stop vertical gradient, a soft concentric-frame edge vignette for depth, a finer faint grid, and a centred brand mark. - Window chrome: brighter/saturated titlebar gradient when focused, an accent underline on the active window, and larger/softer drop shadows. - Default session windows are placed and sized for the HD work area. - Live FPS pill in the taskbar tray (green/amber/red by rate); tray widened so FPS + CPU trace + memory badge + clock no longer overlap. Kernel: - kernel/time/ktime.c + include/kernel/ktime.h (new): a unified monotonic high-resolution clock that prefers the HPET (nanosecond) and falls back to the 100 Hz PIT tick. Wired ktime_init() into boot; drives the compositor's FPS sampling. New `ktime` LazyBox applet reports the source and uptime. Verified live (screenshotted): boots to 1920x1080, KTIME reports "source: HPET, nanosecond resolution", the polished desktop renders with the active-window accent and vignette, and the tray shows a live FPS reading. Clean build on x86_64/aarch64/armv8i; 0 panics / 0 OOM. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
This commit is contained in:
1 parent
ef6714a004
commit
4ecf119377
7 files changed
+154
-26
No files matched your search
@@ -126,7 +126,7 @@ CORE_SRCS = kernel/main.c kernel/task.c kernel/sync.c kernel/timer.c kernel/prin
|
||||
kernel/syslog.c kernel/module.c kernel/kobject.c kernel/metrics.c kernel/namespace.c \
|
||||
kernel/signal.c kernel/workqueue.c kernel/tsc.c kernel/vt_art.c \
|
||||
kernel/sub/sub_runtime.c kernel/sub/sub_vm.c kernel/nt/ob.c kernel/nt/reg.c kernel/nt/io.c \
|
||||
kernel/wait.c kernel/futex.c kernel/rcu.c kernel/ktest.c \
|
||||
kernel/wait.c kernel/futex.c kernel/rcu.c kernel/ktest.c kernel/time/ktime.c \
|
||||
kernel/elf.c kernel/exec.c \
|
||||
lib/string.c lib/vsprintf.c lib/bitmap.c lib/rbtree.c lib/kfifo.c lib/hashtable.c lib/font8x8.c \
|
||||
init/cmdline.c init/service.c init/bootlogo.c init/logo_data.c usr/initramfs.c block/block.c block/elevator.c \
|
||||
@@ -451,14 +451,14 @@ $(IMAGE): $(BUILD_DIR)/boot/boot.bin $(BUILD_DIR)/boot/stage2.bin $(BUILD_DIR)/k
|
||||
# -----------------------------------------------------------------------------
|
||||
# -vga std gives the Bochs VBE adapter the kernel drives. vgamem_mb is raised
|
||||
# because a 1280x720 32-bit framebuffer needs more than the 8 MB default.
|
||||
QEMU_VGA = -device VGA,vgamem_mb=32
|
||||
QEMU_VGA = -device VGA,vgamem_mb=64
|
||||
|
||||
# `make run` boots straight into the SUB-OS Graphical Desktop Environment. The
|
||||
# guest window scales with zoom-to-fit; pass `nogui`/`text` on the kernel
|
||||
# command line for the emergency TTY. Use `make run-headless` for serial only.
|
||||
run qemu: $(TARGET)
|
||||
ifeq ($(ARCH), x86_64)
|
||||
qemu-system-x86_64 -drive format=raw,file=$(IMAGE) -m 256M \
|
||||
qemu-system-x86_64 -drive format=raw,file=$(IMAGE) -m 512M \
|
||||
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 \
|
||||
-device e1000,netdev=net0 $(QEMU_VGA) -display gtk,zoom-to-fit=on -serial stdio
|
||||
else ifneq ($(filter $(ARCH), aarch64 arm64),)
|
||||
|
||||
+65
-19
@@ -24,6 +24,7 @@
|
||||
#include <drivers/keyboard.h>
|
||||
#include <drivers/rtc.h>
|
||||
#include <drivers/cpufreq.h>
|
||||
#include <kernel/ktime.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <mm/kmalloc.h>
|
||||
#include <arch/arch.h>
|
||||
@@ -82,6 +83,9 @@ static bool g_clock_seconds = true;
|
||||
static int g_selected_icon = -1;
|
||||
static int g_hover_menu_item = -1;
|
||||
static uint64_t g_frames = 0;
|
||||
static uint32_t g_fps = 0; // frames per second, sampled from ktime
|
||||
static uint64_t g_fps_last_ms = 0;
|
||||
static uint64_t g_fps_last_frames = 0;
|
||||
|
||||
/*
|
||||
* Cached wallpaper.
|
||||
@@ -178,28 +182,50 @@ void gui_desktop_init(void) {
|
||||
// Wallpaper and desktop icons
|
||||
// ===========================================================================
|
||||
|
||||
/* Paint the wallpaper straight into the back buffer. */
|
||||
/* Paint the wallpaper straight into the back buffer. A three-stop vertical
|
||||
* gradient gives the sky depth, a soft edge vignette frames it, and an optional
|
||||
* fine grid adds texture without banding. Painted once and cached. */
|
||||
static void desktop_paint_background(int sw, int wh) {
|
||||
gui_gfx_draw_gradient_v(0, 0, sw, wh, 0xFF0B132B, 0xFF1C2541);
|
||||
// Three-stop vertical gradient: deep space blue -> indigo -> a touch lighter.
|
||||
int mid = wh * 55 / 100;
|
||||
gui_gfx_draw_gradient_v(0, 0, sw, mid, 0xFF070B18, 0xFF141C38);
|
||||
gui_gfx_draw_gradient_v(0, mid, sw, wh - mid, 0xFF141C38, 0xFF1D2A52);
|
||||
|
||||
if (g_show_grid) {
|
||||
// Blend rather than stamp a fixed colour: the gradient's lower half is
|
||||
// lighter than any single grid tone, so a constant colour disappears
|
||||
// there and only shows near the top of the screen.
|
||||
for (int y = 0; y < wh; y += 40) {
|
||||
gui_gfx_fill_rect_blend(0, y, sw, 1, GUI_COLOR_BLACK, 40);
|
||||
// A finer, fainter grid than before reads as texture rather than lines.
|
||||
for (int y = 0; y < wh; y += 48) {
|
||||
gui_gfx_fill_rect_blend(0, y, sw, 1, 0xFF3B4E80, 22);
|
||||
}
|
||||
for (int x = 0; x < sw; x += 40) {
|
||||
gui_gfx_fill_rect_blend(x, 0, 1, wh, GUI_COLOR_BLACK, 40);
|
||||
for (int x = 0; x < sw; x += 48) {
|
||||
gui_gfx_fill_rect_blend(x, 0, 1, wh, 0xFF3B4E80, 22);
|
||||
}
|
||||
}
|
||||
|
||||
// Branding, offset to the right so it clears the icon column.
|
||||
int bx = sw / 2 + 40;
|
||||
int by = wh / 2 - 30;
|
||||
gui_gfx_draw_string_16_shadow(bx - 60, by, "SUB-OS DESKTOP", 0xFF38BDF8, 0xFF0284C7);
|
||||
gui_gfx_draw_string(bx - 76, by + 22, "Modular Monolithic Kernel v0.2.0-LTS", 0xFF64748B);
|
||||
gui_gfx_draw_string(bx - 76, by + 36, "F5 cycle F6 cascade F7 tile F8 max", 0xFF475569);
|
||||
// Soft vignette: concentric 1px frames darkening toward the edges. The
|
||||
// alpha falls off with depth, so the corners recede smoothly.
|
||||
int depth = (wh < sw ? wh : sw) / 6;
|
||||
for (int i = 0; i < depth; i++) {
|
||||
uint8_t a = (uint8_t)(((depth - i) * 42) / depth);
|
||||
if (a == 0) continue;
|
||||
gui_gfx_fill_rect_blend(i, i, sw - 2 * i, 1, GUI_COLOR_BLACK, a); // top
|
||||
gui_gfx_fill_rect_blend(i, wh - 1 - i, sw - 2 * i, 1, GUI_COLOR_BLACK, a); // bottom
|
||||
gui_gfx_fill_rect_blend(i, i, 1, wh - 2 * i, GUI_COLOR_BLACK, a); // left
|
||||
gui_gfx_fill_rect_blend(sw - 1 - i, i, 1, wh - 2 * i, GUI_COLOR_BLACK, a); // right
|
||||
}
|
||||
|
||||
// Centred brand mark with a subtle glow (drawn as a shadowed 16px title).
|
||||
const char* brand = "SUB-OS";
|
||||
int glyph_w = 16; // draw_string_16 advances ~16px per glyph
|
||||
int bw = (int)strlen(brand) * glyph_w;
|
||||
int bx = (sw - bw) / 2;
|
||||
int by = wh / 2 - 40;
|
||||
gui_gfx_draw_string_16_shadow(bx, by, brand, 0xFF7DD3FC, 0xFF0C4A6E);
|
||||
const char* sub = "Modular Monolithic Kernel - v0.2.0-LTS";
|
||||
int sw2 = (int)strlen(sub) * 8;
|
||||
gui_gfx_draw_string((sw - sw2) / 2, by + 24, sub, 0xFF64748B);
|
||||
const char* hint = "F5 cycle F6 cascade F7 tile F8 maximize";
|
||||
int hw = (int)strlen(hint) * 8;
|
||||
gui_gfx_draw_string((sw - hw) / 2, by + 40, hint, 0xFF3E4C6B);
|
||||
}
|
||||
|
||||
void gui_desktop_invalidate_background(void) {
|
||||
@@ -314,7 +340,7 @@ void gui_desktop_render_taskbar(void) {
|
||||
|
||||
// One button per window, in z-order
|
||||
int tab_x = 106;
|
||||
int tray_x = sw - 200;
|
||||
int tray_x = sw - 260; // widened tray: FPS pill + CPU trace + mem + clock
|
||||
for (int i = 0; i < gui_wm_get_window_count() && tab_x < tray_x - 106; i++) {
|
||||
gui_window_t* win = gui_wm_get_window_at_index(i);
|
||||
if (!win || !win->visible) continue;
|
||||
@@ -358,6 +384,14 @@ void gui_desktop_render_taskbar(void) {
|
||||
gui_gfx_draw_string(sw - 140, ty + 12, buf, GUI_COLOR_BLACK);
|
||||
(void)total;
|
||||
|
||||
// Live FPS pill, tinted by how smooth the compositor is running.
|
||||
char fps[16];
|
||||
snprintf(fps, sizeof(fps), "%u FPS", g_fps);
|
||||
uint32_t fps_col = (g_fps >= 45) ? GUI_THEME_SUCCESS
|
||||
: (g_fps >= 20) ? GUI_THEME_WARNING
|
||||
: GUI_THEME_DANGER;
|
||||
gui_gfx_draw_string(sw - 205, ty + 12, fps, fps_col);
|
||||
|
||||
rtc_time_t now;
|
||||
rtc_get_time(&now);
|
||||
if (g_clock_seconds) {
|
||||
@@ -679,9 +713,12 @@ int gui_desktop_run(void) {
|
||||
fbcon_enable(false);
|
||||
gui_desktop_init();
|
||||
|
||||
// Open a default session so the desktop is not empty on first boot.
|
||||
launch_app(2); // System Monitor
|
||||
launch_app(0); // Terminal
|
||||
// Open a default session so the desktop is not empty on first boot. Placed
|
||||
// and sized for the HD work area rather than the old 800x600 defaults.
|
||||
int sw = gui_gfx_get_width();
|
||||
int wh = gui_desktop_workarea_height();
|
||||
gui_app_sysmon_launch(sw - 620, 60, 560, 360);
|
||||
gui_app_terminal_launch(120, 90, sw - 820, wh - 200);
|
||||
|
||||
// Discard anything the console left in the keyboard queue; a stale key
|
||||
// arriving on frame 0 would otherwise act as a desktop shortcut.
|
||||
@@ -764,6 +801,15 @@ int gui_desktop_run(void) {
|
||||
g_frames++;
|
||||
g_pushed_pixels += gui_gfx_last_present_pixels();
|
||||
|
||||
// Sample the frame rate roughly twice a second from the monotonic clock.
|
||||
uint64_t now_ms = ktime_ms();
|
||||
uint64_t dt = now_ms - g_fps_last_ms;
|
||||
if (dt >= 500) {
|
||||
g_fps = (uint32_t)(((g_frames - g_fps_last_frames) * 1000ULL) / dt);
|
||||
g_fps_last_ms = now_ms;
|
||||
g_fps_last_frames = g_frames;
|
||||
}
|
||||
|
||||
if ((g_frames & 0xFF) == 0) {
|
||||
uint64_t full = (uint64_t)gui_gfx_get_width() * (uint64_t)gui_gfx_get_height();
|
||||
uint64_t avg = g_pushed_pixels / 256;
|
||||
|
||||
+12
-3
@@ -616,15 +616,24 @@ void gui_wm_render(void) {
|
||||
gui_window_t* win = gui_wm_get_window(g_window_order[i]);
|
||||
if (!win || !win->visible || win->minimized) continue;
|
||||
|
||||
gui_gfx_draw_shadow(win->x, win->y, win->width, win->height, 6);
|
||||
// A larger, softer drop shadow reads as real depth on the HD desktop.
|
||||
gui_gfx_draw_shadow(win->x, win->y, win->width, win->height,
|
||||
win->active ? 12 : 7);
|
||||
|
||||
uint32_t border = win->active ? GUI_THEME_PRIMARY : GUI_THEME_BORDER;
|
||||
gui_gfx_draw_rect(win->x, win->y, win->width, win->height, border);
|
||||
|
||||
uint32_t top_bg = win->active ? 0xFF1E293B : 0xFF0F172A;
|
||||
uint32_t bot_bg = win->active ? 0xFF0F172A : 0xFF0A0E1A;
|
||||
// Brighter, more saturated titlebar when focused; muted when not.
|
||||
uint32_t top_bg = win->active ? 0xFF24345A : 0xFF141C2E;
|
||||
uint32_t bot_bg = win->active ? 0xFF141E38 : 0xFF0B1120;
|
||||
gui_gfx_draw_gradient_v(win->x + 1, win->y + 1, win->width - 2,
|
||||
GUI_TITLEBAR_HEIGHT - 1, top_bg, bot_bg);
|
||||
|
||||
// Accent underline on the active window's titlebar; plain divider otherwise.
|
||||
if (win->active) {
|
||||
gui_gfx_fill_rect(win->x + 1, win->y + GUI_TITLEBAR_HEIGHT - 1,
|
||||
win->width - 2, 2, GUI_THEME_PRIMARY);
|
||||
}
|
||||
gui_gfx_draw_line(win->x, win->y + GUI_TITLEBAR_HEIGHT,
|
||||
win->x + win->width - 1, win->y + GUI_TITLEBAR_HEIGHT, border);
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef _KERNEL_KTIME_H
|
||||
#define _KERNEL_KTIME_H
|
||||
|
||||
// Unified monotonic high-resolution clock. Prefers the HPET (nanosecond grade)
|
||||
// and falls back to the 100 Hz timer tick when no HPET is present.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void ktime_init(void);
|
||||
uint64_t ktime_ns(void); // nanoseconds since ktime_init
|
||||
uint64_t ktime_us(void);
|
||||
uint64_t ktime_ms(void);
|
||||
const char* ktime_source(void); // "HPET" or "PIT"
|
||||
bool ktime_is_highres(void); // true when backed by the HPET
|
||||
|
||||
#endif // _KERNEL_KTIME_H
|
||||
+3
-1
@@ -76,6 +76,7 @@
|
||||
#include <drivers/hpet.h>
|
||||
#include <drivers/nvram.h>
|
||||
#include <drivers/lpt.h>
|
||||
#include <kernel/ktime.h>
|
||||
#include <drivers/virtio_input.h>
|
||||
#include <gui/gui.h>
|
||||
#include <init/init.h>
|
||||
@@ -135,6 +136,7 @@ static void subos_modular_core_boot(void) {
|
||||
nvram_init();
|
||||
lpt_init();
|
||||
#endif
|
||||
ktime_init();
|
||||
canvas_init();
|
||||
pty_init();
|
||||
virtio_rng_init();
|
||||
@@ -330,7 +332,7 @@ void kernel_main(void* memory_map, uint64_t memory_map_count) {
|
||||
printk(ANSI_BRIGHT_CYAN " SUB-OS 64-Bit [%s] Modular Monolithic Kernel %s\n" ANSI_RESET, arch_get_name(), kernel_get_version());
|
||||
printk(ANSI_BRIGHT_CYAN "=================================================================\n\n" ANSI_RESET);
|
||||
|
||||
init_early("root=/dev/sda console=tty1 init=/bin/lazybox video=1280x720 quiet");
|
||||
init_early("root=/dev/sda console=tty1 init=/bin/lazybox video=1920x1080 quiet");
|
||||
rtc_init();
|
||||
|
||||
printk(KERN_INFO "[1/14] Initializing 64-Bit GDT, IDT, PIC & PIT Timer... ");
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Unified monotonic high-resolution clock for SUB-OS.
|
||||
//
|
||||
// When the HPET is available it provides true nanosecond timing; otherwise the
|
||||
// clock degrades gracefully to the 100 Hz kernel timer tick (10 ms resolution).
|
||||
// Either way the epoch is the moment ktime_init() ran.
|
||||
|
||||
#include <kernel/ktime.h>
|
||||
#include <drivers/hpet.h>
|
||||
#include <arch/arch.h>
|
||||
#include <kernel/printk.h>
|
||||
|
||||
#define TICK_HZ 100ULL
|
||||
#define NS_PER_TICK (1000000000ULL / TICK_HZ) // 10,000,000 ns at 100 Hz
|
||||
|
||||
static bool g_use_hpet = false;
|
||||
static uint64_t g_base_tick = 0;
|
||||
|
||||
void ktime_init(void) {
|
||||
g_use_hpet = hpet_available();
|
||||
g_base_tick = pit_get_ticks();
|
||||
printk(ANSI_BRIGHT_GREEN "KTIME: " ANSI_RESET
|
||||
"Monotonic clock online (source: %s%s)\n",
|
||||
g_use_hpet ? "HPET" : "PIT 100 Hz",
|
||||
g_use_hpet ? ", nanosecond resolution" : "");
|
||||
}
|
||||
|
||||
uint64_t ktime_ns(void) {
|
||||
if (g_use_hpet) {
|
||||
return hpet_get_ns();
|
||||
}
|
||||
uint64_t ticks = pit_get_ticks() - g_base_tick;
|
||||
return ticks * NS_PER_TICK;
|
||||
}
|
||||
|
||||
uint64_t ktime_us(void) { return ktime_ns() / 1000ULL; }
|
||||
uint64_t ktime_ms(void) { return ktime_ns() / 1000000ULL; }
|
||||
|
||||
const char* ktime_source(void) { return g_use_hpet ? "HPET" : "PIT"; }
|
||||
bool ktime_is_highres(void) { return g_use_hpet; }
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <drivers/hpet.h>
|
||||
#include <drivers/nvram.h>
|
||||
#include <drivers/lpt.h>
|
||||
#include <kernel/ktime.h>
|
||||
#include <kernel/sub_lang.h>
|
||||
#include <kernel/cpp_kernel.h>
|
||||
#include <userland/snake.h>
|
||||
@@ -718,6 +719,19 @@ static int applet_iodev(int argc, char** argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_ktime(int argc, char** argv) {
|
||||
(void)argc; (void)argv;
|
||||
uint64_t ns = ktime_ns();
|
||||
printk(ANSI_BRIGHT_CYAN "Monotonic clock (ktime):\n" ANSI_RESET);
|
||||
printk(" Source : %s%s\n", ktime_source(),
|
||||
ktime_is_highres() ? " (nanosecond resolution)" : " (10 ms tick)");
|
||||
printk(" Uptime : %llu.%03llu s (%llu ns)\n",
|
||||
(unsigned long long)(ns / 1000000000ULL),
|
||||
(unsigned long long)((ns / 1000000ULL) % 1000ULL),
|
||||
(unsigned long long)ns);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_hpet(int argc, char** argv) {
|
||||
(void)argc; (void)argv;
|
||||
if (!hpet_available()) {
|
||||
@@ -2465,6 +2479,7 @@ static const lazybox_applet_t applets[] = {
|
||||
{"reg", applet_reg, "reg query|add|set|stats", "NT configuration registry", "Kernel"},
|
||||
{"iodev", applet_iodev, "iodev", "NT I/O Manager devices & IRP","Kernel"},
|
||||
{"hpet", applet_hpet, "hpet", "High Precision Event Timer", "Hardware"},
|
||||
{"ktime", applet_ktime, "ktime", "Monotonic high-res clock", "Kernel"},
|
||||
{"nvram", applet_nvram, "nvram", "Dump CMOS NVRAM bytes", "Hardware"},
|
||||
{"lpt", applet_lpt, "lpt [text]", "Send text to LPT1 parallel", "Hardware"},
|
||||
{"rand", applet_rand, "rand [count]", "Generate random numbers", "Crypto"},
|
||||
|
||||
Reference in new issue
Block a user