mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
feat(taskman): implement scrollbar and UI optimizations
This commit is contained in:
parent
d3a353c9f8
commit
309f68df48
2 changed files with 166 additions and 77 deletions
|
|
@ -5,7 +5,7 @@ CC = x86_64-elf-gcc
|
||||||
AS = nasm
|
AS = nasm
|
||||||
LD = x86_64-elf-ld
|
LD = x86_64-elf-ld
|
||||||
|
|
||||||
CFLAGS = -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-red-zone -I. -Ilibc -I../sys
|
CFLAGS = -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-red-zone -I. -Ilibc -I../sys -I../wm
|
||||||
LDFLAGS = -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start
|
LDFLAGS = -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start
|
||||||
|
|
||||||
BIN_DIR = bin
|
BIN_DIR = bin
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "libui.h"
|
#include "libui.h"
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
|
#include "libwidget.h"
|
||||||
|
|
||||||
#define COLOR_DARK_BG 0xFF121212
|
#define COLOR_DARK_BG 0xFF121212
|
||||||
#define COLOR_DARK_PANEL 0xFF1E1E1E
|
#define COLOR_DARK_PANEL 0xFF1E1E1E
|
||||||
|
|
@ -20,7 +21,7 @@
|
||||||
#define GRAPH_POINTS 60
|
#define GRAPH_POINTS 60
|
||||||
|
|
||||||
static ui_window_t win_taskman;
|
static ui_window_t win_taskman;
|
||||||
static ProcessInfo proc_list[32];
|
static ProcessInfo proc_list[64];
|
||||||
static int proc_count = 0;
|
static int proc_count = 0;
|
||||||
static int selected_proc = -1;
|
static int selected_proc = -1;
|
||||||
|
|
||||||
|
|
@ -36,14 +37,49 @@ static uint64_t used_mem_system = 0;
|
||||||
static char cpu_model_name[64] = "Unknown CPU";
|
static char cpu_model_name[64] = "Unknown CPU";
|
||||||
static int cpu_cores = 1;
|
static int cpu_cores = 1;
|
||||||
|
|
||||||
|
// libwidget integration
|
||||||
|
static widget_context_t ctx;
|
||||||
|
static widget_scrollbar_t proc_sb;
|
||||||
|
static int scroll_offset = 0;
|
||||||
|
|
||||||
|
static void ctx_draw_rect(void *user_data, int x, int y, int w, int h, uint32_t color) {
|
||||||
|
ui_draw_rect((ui_window_t)(uintptr_t)user_data, x, y, w, h, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ctx_draw_rounded_rect_filled(void *user_data, int x, int y, int w, int h, int r, uint32_t color) {
|
||||||
|
ui_draw_rounded_rect_filled((ui_window_t)(uintptr_t)user_data, x, y, w, h, r, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ctx_draw_string(void *user_data, int x, int y, const char *str, uint32_t color) {
|
||||||
|
ui_draw_string((ui_window_t)(uintptr_t)user_data, x, y, str, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ctx_measure_string_width(void *user_data, const char *str) {
|
||||||
|
(void)user_data;
|
||||||
|
return (int)ui_get_string_width(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ctx_mark_dirty(void *user_data, int x, int y, int w, int h) {
|
||||||
|
ui_mark_dirty((ui_window_t)(uintptr_t)user_data, x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_scroll_proc(void *user_data, int new_scroll_y) {
|
||||||
|
(void)user_data;
|
||||||
|
scroll_offset = new_scroll_y;
|
||||||
|
}
|
||||||
|
|
||||||
static int find_value(const char *buf, const char *key) {
|
static int find_value(const char *buf, const char *key) {
|
||||||
char *p = (char*)buf;
|
char *p = (char*)buf;
|
||||||
int key_len = strlen(key);
|
int key_len = strlen(key);
|
||||||
while (*p) {
|
while (*p) {
|
||||||
if (memcmp(p, key, key_len) == 0 && p[key_len] == ':') {
|
if (memcmp(p, key, key_len) == 0) {
|
||||||
p += key_len + 1;
|
char *tp = p + key_len;
|
||||||
while (*p == ' ') p++;
|
while (*tp == ' ' || *tp == '\t') tp++;
|
||||||
return atoi(p);
|
if (*tp == ':') {
|
||||||
|
tp++;
|
||||||
|
while (*tp == ' ' || *tp == '\t') tp++;
|
||||||
|
return atoi(tp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (*p && *p != '\n') p++;
|
while (*p && *p != '\n') p++;
|
||||||
if (*p == '\n') p++;
|
if (*p == '\n') p++;
|
||||||
|
|
@ -55,15 +91,19 @@ static void find_string(const char *buf, const char *key, char *out, int max_len
|
||||||
char *p = (char*)buf;
|
char *p = (char*)buf;
|
||||||
int key_len = strlen(key);
|
int key_len = strlen(key);
|
||||||
while (*p) {
|
while (*p) {
|
||||||
if (memcmp(p, key, key_len) == 0 && p[key_len] == ':') {
|
if (memcmp(p, key, key_len) == 0) {
|
||||||
p += key_len + 1;
|
char *tp = p + key_len;
|
||||||
while (*p == ' ') p++;
|
while (*tp == ' ' || *tp == '\t') tp++;
|
||||||
int i = 0;
|
if (*tp == ':') {
|
||||||
while (*p && *p != '\n' && i < max_len - 1) {
|
tp++;
|
||||||
out[i++] = *p++;
|
while (*tp == ' ' || *tp == '\t') tp++;
|
||||||
|
int i = 0;
|
||||||
|
while (*tp && *tp != '\n' && i < max_len - 1) {
|
||||||
|
out[i++] = *tp++;
|
||||||
|
}
|
||||||
|
out[i] = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
out[i] = 0;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
while (*p && *p != '\n') p++;
|
while (*p && *p != '\n') p++;
|
||||||
if (*p == '\n') p++;
|
if (*p == '\n') p++;
|
||||||
|
|
@ -72,8 +112,8 @@ static void find_string(const char *buf, const char *key, char *out, int max_len
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_proc_list(void) {
|
static void update_proc_list(void) {
|
||||||
FAT32_FileInfo entries[64];
|
FAT32_FileInfo entries[128];
|
||||||
int count = sys_list("/proc", entries, 64);
|
int count = sys_list("/proc", entries, 128);
|
||||||
if (count < 0) return;
|
if (count < 0) return;
|
||||||
|
|
||||||
proc_count = 0;
|
proc_count = 0;
|
||||||
|
|
@ -105,18 +145,20 @@ static void update_proc_list(void) {
|
||||||
sys_close(fd);
|
sys_close(fd);
|
||||||
if (bytes > 0) {
|
if (bytes > 0) {
|
||||||
buf[bytes] = 0;
|
buf[bytes] = 0;
|
||||||
proc_list[proc_count].pid = pid;
|
|
||||||
find_string(buf, "Name", proc_list[proc_count].name, 64);
|
|
||||||
proc_list[proc_count].used_memory = (size_t)find_value(buf, "Memory") * 1024;
|
|
||||||
uint64_t ticks = (uint64_t)find_value(buf, "Ticks");
|
uint64_t ticks = (uint64_t)find_value(buf, "Ticks");
|
||||||
proc_list[proc_count].ticks = ticks;
|
bool is_idle = find_value(buf, "Idle") == 1;
|
||||||
|
|
||||||
total_ticks_now += ticks;
|
total_ticks_now += ticks;
|
||||||
|
|
||||||
proc_list[proc_count].is_idle = find_value(buf, "Idle") == 1;
|
if (proc_count < 64 && !is_idle) {
|
||||||
|
proc_list[proc_count].pid = pid;
|
||||||
if (!proc_list[proc_count].is_idle) user_ticks_now += ticks;
|
find_string(buf, "Name", proc_list[proc_count].name, 64);
|
||||||
proc_count++;
|
proc_list[proc_count].used_memory = (size_t)find_value(buf, "Memory") * 1024;
|
||||||
if (proc_count >= 32) break;
|
proc_list[proc_count].ticks = ticks;
|
||||||
|
proc_list[proc_count].is_idle = is_idle;
|
||||||
|
user_ticks_now += ticks;
|
||||||
|
proc_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -268,18 +310,39 @@ static void draw_taskman(void) {
|
||||||
ui_draw_string(win_taskman, 60, 125, "NAME", COLOR_DIM_TEXT);
|
ui_draw_string(win_taskman, 60, 125, "NAME", COLOR_DIM_TEXT);
|
||||||
ui_draw_string(win_taskman, 250, 125, "MEMORY", COLOR_DIM_TEXT);
|
ui_draw_string(win_taskman, 250, 125, "MEMORY", COLOR_DIM_TEXT);
|
||||||
|
|
||||||
// Process Rows
|
|
||||||
int row = 0;
|
int list_x = 10;
|
||||||
for (int i = 0; i < proc_count && row < MAX_VISIBLE_PROCS; i++) {
|
int list_y = 150;
|
||||||
|
int list_w = 380;
|
||||||
|
int list_h = 480 - 150 - 80; // Leave space for kill button
|
||||||
|
int row_h = 26;
|
||||||
|
|
||||||
|
int content_h = proc_count * row_h;
|
||||||
|
widget_scrollbar_update(&proc_sb, content_h, scroll_offset);
|
||||||
|
|
||||||
|
// Draw scrollbar if content exceeds height
|
||||||
|
if (content_h > list_h) {
|
||||||
|
proc_sb.h = list_h;
|
||||||
|
proc_sb.x = list_x + list_w - 12;
|
||||||
|
proc_sb.y = list_y;
|
||||||
|
widget_scrollbar_draw(&ctx, &proc_sb);
|
||||||
|
list_w -= 15; // Shrink list area to make room for scrollbar
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clipping and Drawing rows
|
||||||
|
for (int i = 0; i < proc_count; i++) {
|
||||||
if (proc_list[i].pid == 0xFFFFFFFF) continue;
|
if (proc_list[i].pid == 0xFFFFFFFF) continue;
|
||||||
|
|
||||||
int ry = 150 + row * 26;
|
int ry = list_y + (i * row_h) - scroll_offset;
|
||||||
uint32_t bg = (selected_proc == row) ? 0xFF334455 : COLOR_DARK_PANEL;
|
|
||||||
ui_draw_rounded_rect_filled(win_taskman, 10, ry, 380, 24, 4, bg);
|
if (ry + row_h <= list_y || ry >= list_y + list_h) continue;
|
||||||
|
|
||||||
|
uint32_t bg = (selected_proc == i) ? 0xFF334455 : COLOR_DARK_PANEL;
|
||||||
|
ui_draw_rounded_rect_filled(win_taskman, list_x, ry, list_w, row_h - 2, 4, bg);
|
||||||
|
|
||||||
char pid_str[16];
|
char pid_str[16];
|
||||||
itoa(proc_list[i].pid, pid_str);
|
itoa(proc_list[i].pid, pid_str);
|
||||||
ui_draw_string(win_taskman, 20, ry + 6, pid_str, COLOR_DARK_TEXT);
|
ui_draw_string(win_taskman, list_x + 10, ry + 6, pid_str, COLOR_DARK_TEXT);
|
||||||
|
|
||||||
char name_disp[28];
|
char name_disp[28];
|
||||||
if (strlen(proc_list[i].name) > 22) {
|
if (strlen(proc_list[i].name) > 22) {
|
||||||
|
|
@ -288,13 +351,11 @@ static void draw_taskman(void) {
|
||||||
} else {
|
} else {
|
||||||
strcpy(name_disp, proc_list[i].name);
|
strcpy(name_disp, proc_list[i].name);
|
||||||
}
|
}
|
||||||
ui_draw_string(win_taskman, 65, ry + 6, name_disp, COLOR_DARK_TEXT);
|
ui_draw_string(win_taskman, list_x + 55, ry + 6, name_disp, COLOR_DARK_TEXT);
|
||||||
|
|
||||||
char m_str[32];
|
char m_str[32];
|
||||||
format_mem_smart(proc_list[i].used_memory, m_str);
|
format_mem_smart(proc_list[i].used_memory, m_str);
|
||||||
ui_draw_string(win_taskman, 255, ry + 6, m_str, COLOR_DARK_TEXT);
|
ui_draw_string(win_taskman, list_x + 245, ry + 6, m_str, COLOR_DARK_TEXT);
|
||||||
|
|
||||||
row++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kill button (Positioned relative to window height)
|
// Kill button (Positioned relative to window height)
|
||||||
|
|
@ -329,6 +390,18 @@ static void draw_taskman(void) {
|
||||||
int main(void) {
|
int main(void) {
|
||||||
win_taskman = ui_window_create("Task Manager", 100, 100, 400, 480);
|
win_taskman = ui_window_create("Task Manager", 100, 100, 400, 480);
|
||||||
|
|
||||||
|
// Initialize libwidget context
|
||||||
|
ctx.user_data = (void*)(uintptr_t)win_taskman;
|
||||||
|
ctx.draw_rect = ctx_draw_rect;
|
||||||
|
ctx.draw_rounded_rect_filled = ctx_draw_rounded_rect_filled;
|
||||||
|
ctx.draw_string = ctx_draw_string;
|
||||||
|
ctx.measure_string_width = ctx_measure_string_width;
|
||||||
|
ctx.mark_dirty = ctx_mark_dirty;
|
||||||
|
ctx.use_light_theme = false;
|
||||||
|
|
||||||
|
widget_scrollbar_init(&proc_sb, 388, 150, 12, 250);
|
||||||
|
proc_sb.on_scroll = on_scroll_proc;
|
||||||
|
|
||||||
int fd_c = sys_open("/proc/cpuinfo", "r");
|
int fd_c = sys_open("/proc/cpuinfo", "r");
|
||||||
if (fd_c >= 0) {
|
if (fd_c >= 0) {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
|
|
@ -336,8 +409,8 @@ int main(void) {
|
||||||
sys_close(fd_c);
|
sys_close(fd_c);
|
||||||
if (bytes > 0) {
|
if (bytes > 0) {
|
||||||
buf[bytes] = 0;
|
buf[bytes] = 0;
|
||||||
find_string(buf, "Processor", cpu_model_name, 64);
|
find_string(buf, "model name", cpu_model_name, 64);
|
||||||
int cores = find_value(buf, "Cores");
|
int cores = find_value(buf, "cpu cores");
|
||||||
if (cores > 0) cpu_cores = cores;
|
if (cores > 0) cpu_cores = cores;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -346,60 +419,76 @@ int main(void) {
|
||||||
|
|
||||||
gui_event_t ev;
|
gui_event_t ev;
|
||||||
|
|
||||||
|
uint64_t last_update = 30; // Force update on start
|
||||||
while (1) {
|
while (1) {
|
||||||
|
bool needs_redraw = false;
|
||||||
// Drain events
|
// Drain events
|
||||||
while (ui_get_event(win_taskman, &ev)) {
|
while (ui_get_event(win_taskman, &ev)) {
|
||||||
if (ev.type == GUI_EVENT_CLOSE) {
|
if (ev.type == GUI_EVENT_CLOSE) {
|
||||||
sys_exit(0);
|
sys_exit(0);
|
||||||
} else if (ev.type == GUI_EVENT_CLICK) {
|
} else if (ev.type == GUI_EVENT_CLICK || ev.type == GUI_EVENT_MOUSE_DOWN) {
|
||||||
int mx = ev.arg1;
|
int mx = ev.arg1;
|
||||||
int my = ev.arg2;
|
int my = ev.arg2;
|
||||||
|
bool clicked = (ev.type == GUI_EVENT_CLICK);
|
||||||
|
bool down = (ev.type == GUI_EVENT_MOUSE_DOWN);
|
||||||
|
|
||||||
if (mx >= 10 && mx < 390 && my >= 150 && my < 150 + MAX_VISIBLE_PROCS * 26) {
|
// Handle scrollbar
|
||||||
int idx = (my - 150) / 26;
|
if (widget_scrollbar_handle_mouse(&proc_sb, mx, my, down, NULL)) {
|
||||||
int valid_count = 0;
|
needs_redraw = true;
|
||||||
int target_i = -1;
|
} else if (clicked) {
|
||||||
for (int i = 0; i < proc_count; i++) {
|
// Handle process selection
|
||||||
if (proc_list[i].pid != 0xFFFFFFFF) {
|
int list_x = 10;
|
||||||
if (valid_count == idx) { target_i = i; break; }
|
int list_y = 150;
|
||||||
valid_count++;
|
int list_h = 480 - 150 - 80;
|
||||||
}
|
int row_h = 26;
|
||||||
}
|
|
||||||
if (target_i != -1) selected_proc = idx;
|
|
||||||
else selected_proc = -1;
|
|
||||||
|
|
||||||
draw_taskman();
|
if (mx >= list_x && mx < list_x + 380 && my >= list_y && my < list_y + list_h) {
|
||||||
ui_mark_dirty(win_taskman, 0, 0, 400, 480);
|
int idx = (my - list_y + scroll_offset) / row_h;
|
||||||
} else if (mx >= 290 && mx < 390 && my >= 410 && my < 440) {
|
if (idx >= 0 && idx < proc_count) {
|
||||||
if (selected_proc != -1) {
|
selected_proc = idx;
|
||||||
int valid_count = 0;
|
} else {
|
||||||
for (int i = 0; i < proc_count; i++) {
|
selected_proc = -1;
|
||||||
if (proc_list[i].pid != 0xFFFFFFFF) {
|
}
|
||||||
if (valid_count == selected_proc) {
|
needs_redraw = true;
|
||||||
if (proc_list[i].pid != 0) sys_kill(proc_list[i].pid);
|
} else if (mx >= 290 && mx < 390 && my >= 410 && my < 440) {
|
||||||
break;
|
// Kill button
|
||||||
}
|
if (selected_proc != -1) {
|
||||||
valid_count++;
|
if (proc_list[selected_proc].pid != 0) sys_kill(proc_list[selected_proc].pid);
|
||||||
}
|
selected_proc = -1;
|
||||||
|
update_proc_list();
|
||||||
|
needs_redraw = true;
|
||||||
}
|
}
|
||||||
selected_proc = -1;
|
|
||||||
update_proc_list();
|
|
||||||
draw_taskman();
|
|
||||||
ui_mark_dirty(win_taskman, 0, 0, 400, 480);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (ev.type == GUI_EVENT_MOUSE_MOVE) {
|
||||||
|
if (proc_sb.is_dragging) {
|
||||||
|
widget_scrollbar_handle_mouse(&proc_sb, ev.arg1, ev.arg2, true, NULL);
|
||||||
|
needs_redraw = true;
|
||||||
|
}
|
||||||
|
} else if (ev.type == GUI_EVENT_MOUSE_WHEEL) {
|
||||||
|
scroll_offset -= (ev.arg1 * 20); // 20px per notch
|
||||||
|
if (scroll_offset < 0) scroll_offset = 0;
|
||||||
|
int max_scroll = (proc_count * 26) - (480 - 150 - 80);
|
||||||
|
if (max_scroll < 0) max_scroll = 0;
|
||||||
|
if (scroll_offset > max_scroll) scroll_offset = max_scroll;
|
||||||
|
needs_redraw = true;
|
||||||
} else if (ev.type == GUI_EVENT_PAINT) {
|
} else if (ev.type == GUI_EVENT_PAINT) {
|
||||||
draw_taskman();
|
needs_redraw = true;
|
||||||
ui_mark_dirty(win_taskman, 0, 0, 400, 480);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update_proc_list();
|
if (last_update++ >= 30) {
|
||||||
draw_taskman();
|
update_proc_list();
|
||||||
ui_mark_dirty(win_taskman, 0, 0, 400, 480);
|
needs_redraw = true;
|
||||||
|
last_update = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Proper blocking sleep (200ms)
|
if (needs_redraw) {
|
||||||
sys_system(SYSTEM_CMD_SLEEP, 200, 0, 0, 0);
|
draw_taskman();
|
||||||
|
ui_mark_dirty(win_taskman, 0, 0, 400, 480);
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_system(SYSTEM_CMD_SLEEP, 16, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue