mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
Stability improvements
This commit is contained in:
parent
2801dbc21f
commit
fcc290f3f9
32 changed files with 171 additions and 97 deletions
BIN
boredos.iso
BIN
boredos.iso
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
build/cmd.o
BIN
build/cmd.o
Binary file not shown.
Binary file not shown.
BIN
build/explorer.o
BIN
build/explorer.o
Binary file not shown.
BIN
build/fat32.o
BIN
build/fat32.o
Binary file not shown.
BIN
build/graphics.o
BIN
build/graphics.o
Binary file not shown.
BIN
build/icmp.o
BIN
build/icmp.o
Binary file not shown.
BIN
build/idt.o
BIN
build/idt.o
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
build/ps2.o
BIN
build/ps2.o
Binary file not shown.
BIN
build/tcp.o
BIN
build/tcp.o
Binary file not shown.
BIN
build/vm.o
BIN
build/vm.o
Binary file not shown.
Binary file not shown.
BIN
build/wm.o
BIN
build/wm.o
Binary file not shown.
BIN
disk.img
BIN
disk.img
Binary file not shown.
Binary file not shown.
|
|
@ -287,6 +287,7 @@ void draw_char(int x, int y, char c, uint32_t color) {
|
|||
}
|
||||
|
||||
void draw_string(int x, int y, const char *s, uint32_t color) {
|
||||
if (!s) return;
|
||||
int cur_x = x;
|
||||
int cur_y = y;
|
||||
while (*s) {
|
||||
|
|
@ -370,22 +371,22 @@ void graphics_set_bg_image(uint32_t *pixels, int w, int h) {
|
|||
void draw_boredos_logo(int x, int y, int scale) {
|
||||
|
||||
static const uint8_t brewos_bmp[] = {
|
||||
0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0, // 0: Ears
|
||||
0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0, // 1: Ears
|
||||
1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1, // 2: Ears (Separated)
|
||||
1,1,1,1,2,2,2,2,2,2,2,2,1,1,1,1, // 3: Forehead / Ears
|
||||
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1, // 4: Face
|
||||
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1, // 5: Eyes start
|
||||
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1, // 6: Eyes
|
||||
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1, // 7: Eyes
|
||||
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1, // 8: Eyes
|
||||
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1, // 9: Under eyes
|
||||
1,1,2,2,2,2,2,1,1,2,2,2,2,2,1,1, // 10: Nose
|
||||
1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,1, // 11: Cheeks
|
||||
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1, // 12: Jaw
|
||||
0,1,1,1,2,2,2,2,2,2,2,2,1,1,1,0, // 13: Chin
|
||||
0,0,1,1,1,2,2,2,2,2,2,1,1,1,0,0, // 14: Chin outline
|
||||
0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0 // 15: Bottom
|
||||
0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,
|
||||
0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,
|
||||
1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,
|
||||
1,1,1,1,2,2,2,2,2,2,2,2,1,1,1,1,
|
||||
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1,
|
||||
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1,
|
||||
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,
|
||||
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,
|
||||
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,
|
||||
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1,
|
||||
1,1,2,2,2,2,2,1,1,2,2,2,2,2,1,1,
|
||||
1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,1,
|
||||
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1,
|
||||
0,1,1,1,2,2,2,2,2,2,2,2,1,1,1,0,
|
||||
0,0,1,1,1,2,2,2,2,2,2,1,1,1,0,0,
|
||||
0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0
|
||||
};
|
||||
|
||||
for (int r = 0; r < 16; r++) {
|
||||
|
|
@ -435,6 +436,15 @@ void graphics_flip_buffer(void) {
|
|||
}
|
||||
|
||||
void graphics_set_clipping(int x, int y, int w, int h) {
|
||||
if (x < 0) { w += x; x = 0; }
|
||||
if (y < 0) { h += y; y = 0; }
|
||||
int sw = get_screen_width();
|
||||
int sh = get_screen_height();
|
||||
if (x + w > sw) w = sw - x;
|
||||
if (y + h > sh) h = sh - y;
|
||||
if (w < 0) w = 0;
|
||||
if (h < 0) h = 0;
|
||||
|
||||
g_clip_x = x;
|
||||
g_clip_y = y;
|
||||
g_clip_w = w;
|
||||
|
|
@ -459,9 +469,7 @@ void graphics_blit_buffer(uint32_t *src, int dst_x, int dst_y, int w, int h) {
|
|||
if (vx < 0 || vx >= sw) continue;
|
||||
|
||||
uint32_t pcol = src[y * w + x];
|
||||
// Alpha blending support:
|
||||
// If the alpha byte is 0, we treat it as transparent ONLY if the color is also 0.
|
||||
// This handles common 0xRRGGBB as opaque.
|
||||
|
||||
if ((pcol & 0xFF000000) != 0 || (pcol & 0xFFFFFF) != 0) {
|
||||
g_back_buffer[vy * sw + vx] = pcol;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,32 @@ void kmain(void) {
|
|||
platform_init();
|
||||
serial_write("[DEBUG] platform_init OK\n");
|
||||
|
||||
// 1. Graphics Init
|
||||
// 1. Memory Detection and Heap Init
|
||||
uint64_t heap_phys_addr = 0;
|
||||
size_t heap_size = 0;
|
||||
if (memmap_request.response != NULL) {
|
||||
for (uint64_t i = 0; i < memmap_request.response->entry_count; i++) {
|
||||
struct limine_memmap_entry *entry = memmap_request.response->entries[i];
|
||||
if (entry->type == LIMINE_MEMMAP_USABLE) {
|
||||
if (entry->length > heap_size) {
|
||||
heap_size = entry->length;
|
||||
heap_phys_addr = entry->base;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (heap_size > 512 * 1024 * 1024) heap_size = 512 * 1024 * 1024; // Cap at 512MB
|
||||
|
||||
if (heap_phys_addr != 0) {
|
||||
memory_manager_init_at((void*)p2v(heap_phys_addr), heap_size);
|
||||
serial_write("[DEBUG] memory_manager_init OK\n");
|
||||
} else {
|
||||
serial_write("[DEBUG] ERROR: No usable memory for heap!\n");
|
||||
hcf();
|
||||
}
|
||||
|
||||
// 2. Graphics Init
|
||||
if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) {
|
||||
serial_write("[DEBUG] No framebuffer! Halting.\n");
|
||||
hcf();
|
||||
|
|
@ -94,20 +119,19 @@ void kmain(void) {
|
|||
graphics_init(fb);
|
||||
serial_write("[DEBUG] graphics_init OK\n");
|
||||
|
||||
// 1.5 GDT & TSS Init
|
||||
// 3. GDT & TSS Init
|
||||
gdt_init();
|
||||
serial_write("[DEBUG] gdt_init OK\n");
|
||||
|
||||
// 1.6 Paging Init
|
||||
// 4. Paging Init
|
||||
paging_init();
|
||||
serial_write("[DEBUG] paging_init OK\n");
|
||||
|
||||
// 1.7 Syscall Init
|
||||
// 5. Syscall Init
|
||||
syscall_init();
|
||||
serial_write("[DEBUG] syscall_init OK\n");
|
||||
|
||||
// Set up a user page and jump to user space
|
||||
// 2. Interrupts Init
|
||||
// 6. Interrupts Init
|
||||
idt_init();
|
||||
idt_register_interrupts();
|
||||
idt_load();
|
||||
|
|
@ -115,33 +139,8 @@ void kmain(void) {
|
|||
|
||||
process_init();
|
||||
|
||||
|
||||
serial_write("[DEBUG] Skipping user mode test, proceeding with normal boot.\n");
|
||||
|
||||
// 2.5 Memory Manager Init - Calculate available RAM from Limine
|
||||
size_t total_usable_memory = 0;
|
||||
if (memmap_request.response != NULL) {
|
||||
for (uint64_t i = 0; i < memmap_request.response->entry_count; i++) {
|
||||
struct limine_memmap_entry *entry = memmap_request.response->entries[i];
|
||||
|
||||
|
||||
// Count usable memory regions
|
||||
if (entry->type == LIMINE_MEMMAP_USABLE) {
|
||||
total_usable_memory += entry->length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize memory manager with available memory (cap at 2GB for practical reasons)
|
||||
size_t pool_size = total_usable_memory > (2 * 1024 * 1024 * 1024) ?
|
||||
(2 * 1024 * 1024 * 1024) : total_usable_memory;
|
||||
|
||||
if (pool_size == 0) {
|
||||
pool_size = 512 * 1024 * 1024; // Fallback to 512MB if detection fails
|
||||
}
|
||||
|
||||
memory_manager_init_with_size(pool_size);
|
||||
|
||||
// Initialize FAT32 RAMFS and mount Limine modules
|
||||
fat32_init();
|
||||
if (module_request.response != NULL) {
|
||||
|
|
@ -181,6 +180,7 @@ void kmain(void) {
|
|||
// Timer interrupt will drive the redraw system
|
||||
while (1) {
|
||||
wm_process_input();
|
||||
wm_process_deferred_thumbs();
|
||||
wallpaper_process_pending();
|
||||
asm("hlt");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
#include <stdint.h>
|
||||
|
||||
// --- Internal State ---
|
||||
#define KERNEL_HEAP_SIZE (32 * 1024 * 1024) // 32MB Static Heap
|
||||
static uint8_t memory_pool_buffer[KERNEL_HEAP_SIZE];
|
||||
static uint8_t *memory_pool = memory_pool_buffer;
|
||||
static size_t memory_pool_size = KERNEL_HEAP_SIZE;
|
||||
static uint8_t *memory_pool = NULL;
|
||||
static size_t memory_pool_size = 0;
|
||||
static MemBlock block_list[MAX_ALLOCATIONS];
|
||||
static int block_count = 0;
|
||||
static size_t total_allocated = 0;
|
||||
|
|
@ -137,9 +135,11 @@ static size_t calculate_fragmentation(void) {
|
|||
|
||||
// --- Public API ---
|
||||
|
||||
void memory_manager_init_with_size(size_t pool_size) {
|
||||
void memory_manager_init_at(void *pool_address, size_t pool_size) {
|
||||
if (initialized) return;
|
||||
|
||||
memory_pool = (uint8_t *)pool_address;
|
||||
memory_pool_size = pool_size;
|
||||
|
||||
// Clear metadata
|
||||
mem_memset(block_list, 0, sizeof(block_list));
|
||||
|
|
@ -158,6 +158,14 @@ void memory_manager_init_with_size(size_t pool_size) {
|
|||
initialized = true;
|
||||
}
|
||||
|
||||
void memory_manager_init_with_size(size_t pool_size) {
|
||||
// This is now just a wrapper if init_at wasn't called.
|
||||
// However, in BoredOS we now prefer explicit init_at.
|
||||
if (initialized) return;
|
||||
// Fallback: we still need a buffer if no address is provided?
|
||||
// Let's assume for now that BoredOS always calls init_at.
|
||||
}
|
||||
|
||||
void memory_manager_init(void) {
|
||||
memory_manager_init_with_size(DEFAULT_POOL_SIZE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
// Memory Manager Configuration
|
||||
#define DEFAULT_POOL_SIZE (512 * 1024 * 1024) // 512MB default (can be overridden)
|
||||
#define MAX_ALLOCATIONS 4096 // Increased for larger pools
|
||||
#define DEFAULT_POOL_SIZE (128 * 1024 * 1024) // 128MB default
|
||||
#define MAX_ALLOCATIONS 16384 // Increased for larger pools
|
||||
#define MAX_FRAGMENTATION_SLOTS 2048
|
||||
|
||||
// Allocation block metadata
|
||||
|
|
@ -35,6 +35,7 @@ typedef struct {
|
|||
// Public API
|
||||
void memory_manager_init(void);
|
||||
void memory_manager_init_with_size(size_t pool_size);
|
||||
void memory_manager_init_at(void *pool_address, size_t pool_size);
|
||||
|
||||
// Allocation/Deallocation
|
||||
void* kmalloc(size_t size);
|
||||
|
|
|
|||
|
|
@ -239,6 +239,8 @@ void process_create_elf(const char* filepath, const char* args_str) {
|
|||
*(--stack_ptr) = 0; // R15
|
||||
|
||||
new_proc->kernel_stack = (uint64_t)kernel_stack + 16384;
|
||||
new_proc->kernel_stack_alloc = kernel_stack;
|
||||
new_proc->user_stack_alloc = stack;
|
||||
new_proc->rsp = (uint64_t)stack_ptr;
|
||||
|
||||
// We only increment process_count after success
|
||||
|
|
@ -333,6 +335,13 @@ uint64_t process_terminate_current(void) {
|
|||
|
||||
paging_switch_directory(current_process->pml4_phys);
|
||||
|
||||
// 5. Actually free the memory (after switching state to avoid issues)
|
||||
if (to_delete->kernel_stack_alloc) kfree(to_delete->kernel_stack_alloc);
|
||||
if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc);
|
||||
|
||||
// NOTE: In a real system we would also free all physical pages
|
||||
// used by the user page table. For now we just free the stacks.
|
||||
|
||||
return current_process->rsp;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ typedef struct process {
|
|||
|
||||
void *fds[MAX_PROCESS_FDS];
|
||||
|
||||
void *kernel_stack_alloc; // Original pointer from kmalloc for freeing
|
||||
void *user_stack_alloc; // Original pointer from kmalloc for freeing
|
||||
|
||||
struct process *next;
|
||||
} process_t;
|
||||
|
||||
|
|
|
|||
124
src/kernel/wm.c
124
src/kernel/wm.c
|
|
@ -27,20 +27,20 @@ static bool str_eq(const char *s1, const char *s2) {
|
|||
}
|
||||
|
||||
// --- State ---
|
||||
static int mx = 400, my = 300; // Mouse Pos
|
||||
static int prev_mx = 400, prev_my = 300; // Previous mouse position
|
||||
static int mx = 400, my = 300;
|
||||
static int prev_mx = 400, prev_my = 300;
|
||||
static bool start_menu_open = false;
|
||||
static char *start_menu_pending_app = NULL; // For click vs drag detection
|
||||
static int pending_desktop_icon_click = -1; // For desktop icon click vs drag
|
||||
static char *start_menu_pending_app = NULL;
|
||||
static int pending_desktop_icon_click = -1;
|
||||
|
||||
// Desktop Context Menu
|
||||
static bool desktop_menu_visible = false;
|
||||
static int desktop_menu_x = 0;
|
||||
static int desktop_menu_y = 0;
|
||||
static int desktop_menu_target_icon = -1; // -1 for background
|
||||
static int desktop_menu_target_icon = -1;
|
||||
|
||||
// Desktop Dialog State
|
||||
static int desktop_dialog_state = 0; // 0=None, 8=Rename
|
||||
static int desktop_dialog_state = 0;
|
||||
static char desktop_dialog_input[64];
|
||||
static int desktop_dialog_cursor = 0;
|
||||
static int desktop_dialog_target = -1;
|
||||
|
|
@ -62,7 +62,7 @@ static int drag_offset_y = 0;
|
|||
// File Dragging State
|
||||
bool is_dragging_file = false;
|
||||
static char drag_file_path[256];
|
||||
static int drag_icon_type = 0; // 0=File, 1=Folder, 2=App
|
||||
static int drag_icon_type = 0;
|
||||
static int drag_start_x = 0;
|
||||
static int drag_start_y = 0;
|
||||
static int drag_icon_orig_x = 0;
|
||||
|
|
@ -74,7 +74,7 @@ static Window *all_windows[32];
|
|||
static int window_count = 0;
|
||||
|
||||
// Redraw system
|
||||
static bool force_redraw = true; // Force full redraw on next tick
|
||||
static bool force_redraw = true;
|
||||
static uint32_t timer_ticks = 0;
|
||||
static int desktop_refresh_timer = 0;
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ static int last_cursor_y = 300;
|
|||
typedef struct {
|
||||
char name[64];
|
||||
int x, y;
|
||||
int type; // 0=File, 1=Folder, 2=App
|
||||
int type;
|
||||
} DesktopIcon;
|
||||
|
||||
static DesktopIcon desktop_icons[MAX_DESKTOP_ICONS];
|
||||
|
|
@ -101,7 +101,7 @@ int desktop_max_rows_per_col = 13;
|
|||
int desktop_max_cols = 23;
|
||||
|
||||
// Mouse Settings
|
||||
int mouse_speed = 10; // Default 1.0x (range 1-50)
|
||||
int mouse_speed = 10;
|
||||
static int mouse_accum_x = 0;
|
||||
static int mouse_accum_y = 0;
|
||||
|
||||
|
|
@ -141,9 +141,7 @@ static void refresh_desktop_icons(void) {
|
|||
bool file_processed[MAX_DESKTOP_ICONS];
|
||||
for(int i=0; i<MAX_DESKTOP_ICONS; i++) file_processed[i] = false;
|
||||
|
||||
// 1. Preserve existing icons in their current order
|
||||
for (int i = 0; i < desktop_icon_count; i++) {
|
||||
// Find if this icon still exists in the file list
|
||||
int found_idx = -1;
|
||||
for (int j = 0; j < file_count; j++) {
|
||||
if (!file_processed[j] && str_eq(desktop_icons[i].name, files[j].name) != 0) {
|
||||
|
|
@ -162,10 +160,9 @@ static void refresh_desktop_icons(void) {
|
|||
}
|
||||
}
|
||||
|
||||
// 2. Add new files (not currently on desktop) to the end
|
||||
for (int i = 0; i < file_count; i++) {
|
||||
if (!file_processed[i]) {
|
||||
if (files[i].name[0] == '.') continue; // Skip . and ..
|
||||
if (files[i].name[0] == '.') continue;
|
||||
if (new_count >= MAX_DESKTOP_ICONS) break;
|
||||
|
||||
DesktopIcon *dest = &new_icons[new_count];
|
||||
|
|
@ -186,14 +183,12 @@ static void refresh_desktop_icons(void) {
|
|||
for(int i=0; i<new_count; i++) desktop_icons[i] = new_icons[i];
|
||||
kfree(files);
|
||||
|
||||
// 3. Layout Icons
|
||||
if (desktop_auto_align) {
|
||||
int start_x = 20;
|
||||
int start_y = 30;
|
||||
int grid_x = 0;
|
||||
int grid_y = 0;
|
||||
|
||||
// Find Recycle Bin index
|
||||
int recycle_idx = -1;
|
||||
for (int i = 0; i < desktop_icon_count; i++) {
|
||||
if (str_starts_with(desktop_icons[i].name, "Recycle Bin")) {
|
||||
|
|
@ -521,6 +516,42 @@ static struct {
|
|||
} thumb_cache[THUMB_CACHE_SIZE];
|
||||
static int thumb_cache_next = 0; // Round-robin eviction
|
||||
|
||||
// Deferred Thumbnail Request Queue
|
||||
#define THUMB_QUEUE_SIZE 16
|
||||
static char thumb_request_queue[THUMB_QUEUE_SIZE][256];
|
||||
static int thumb_queue_head = 0;
|
||||
static int thumb_queue_tail = 0;
|
||||
|
||||
static void thumb_request_push(const char *path) {
|
||||
if (!path) return;
|
||||
|
||||
// Check if already in queue
|
||||
int curr = thumb_queue_head;
|
||||
while (curr != thumb_queue_tail) {
|
||||
if (str_eq(thumb_request_queue[curr], path) != 0) return;
|
||||
curr = (curr + 1) % THUMB_QUEUE_SIZE;
|
||||
}
|
||||
|
||||
// Push if space
|
||||
int next_tail = (thumb_queue_tail + 1) % THUMB_QUEUE_SIZE;
|
||||
if (next_tail != thumb_queue_head) {
|
||||
int i = 0;
|
||||
while (path[i] && i < 255) {
|
||||
thumb_request_queue[thumb_queue_tail][i] = path[i];
|
||||
i++;
|
||||
}
|
||||
thumb_request_queue[thumb_queue_tail][i] = 0;
|
||||
thumb_queue_tail = next_tail;
|
||||
}
|
||||
}
|
||||
|
||||
static bool thumb_cache_is_failed(const char *path) {
|
||||
for (int i = 0; i < THUMB_CACHE_SIZE; i++) {
|
||||
if (thumb_cache[i].failed && str_eq(thumb_cache[i].path, path) != 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint32_t* thumb_cache_lookup(const char *path) {
|
||||
for (int i = 0; i < THUMB_CACHE_SIZE; i++) {
|
||||
if (thumb_cache[i].valid && str_eq(thumb_cache[i].path, path) != 0) {
|
||||
|
|
@ -530,14 +561,7 @@ static uint32_t* thumb_cache_lookup(const char *path) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static bool thumb_cache_is_failed(const char *path) {
|
||||
for (int i = 0; i < THUMB_CACHE_SIZE; i++) {
|
||||
if (thumb_cache[i].failed && str_eq(thumb_cache[i].path, path) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t* thumb_cache_decode(const char *path) {
|
||||
// Open and read the JPG file
|
||||
|
|
@ -566,11 +590,14 @@ static uint32_t* thumb_cache_decode(const char *path) {
|
|||
// Decode JPEG
|
||||
njInit();
|
||||
if (njDecode(buf, total) != NJ_OK) {
|
||||
serial_write("[WM] njDecode failed for deferred thumb\n");
|
||||
njDone();
|
||||
kfree(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
serial_write("[WM] njDecode OK for deferred thumb\n");
|
||||
|
||||
int img_w = njGetWidth();
|
||||
int img_h = njGetHeight();
|
||||
unsigned char *img = njGetImage();
|
||||
|
|
@ -627,22 +654,8 @@ void draw_image_icon(int x, int y, const char *label) {
|
|||
if (!thumb && !thumb_cache_is_failed(label)) {
|
||||
thumb = thumb_cache_lookup(label);
|
||||
if (!thumb) {
|
||||
// Try to decode and cache
|
||||
graphics_set_render_target(NULL, 0, 0); // Restore before file I/O
|
||||
thumb = thumb_cache_decode(label);
|
||||
if (!thumb) {
|
||||
// Mark as failed so we don't retry every frame
|
||||
int slot = thumb_cache_next;
|
||||
int p = 0;
|
||||
while (label[p] && p < 255) { thumb_cache[slot].path[p] = label[p]; p++; }
|
||||
thumb_cache[slot].path[p] = 0;
|
||||
thumb_cache[slot].valid = false;
|
||||
thumb_cache[slot].failed = true;
|
||||
thumb_cache_next = (thumb_cache_next + 1) % THUMB_CACHE_SIZE;
|
||||
}
|
||||
// Re-set render target for icon drawing
|
||||
for (int i = 0; i < 48 * 48; i++) icon_buf[i] = 0xFFFF00FF;
|
||||
graphics_set_render_target(icon_buf, 48, 48);
|
||||
// Queue for background decoding
|
||||
thumb_request_push(label);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1097,6 +1110,9 @@ void wm_paint(void) {
|
|||
int sw = get_screen_width();
|
||||
int sh = get_screen_height();
|
||||
|
||||
uint64_t rflags;
|
||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||
|
||||
DirtyRect dirty = graphics_get_dirty_rect();
|
||||
if (dirty.active) {
|
||||
graphics_set_clipping(dirty.x, dirty.y, dirty.w, dirty.h);
|
||||
|
|
@ -1299,6 +1315,9 @@ void wm_paint(void) {
|
|||
|
||||
// Flip the buffer - display the rendered frame atomically
|
||||
graphics_flip_buffer();
|
||||
|
||||
// Restore IRQs
|
||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||
}
|
||||
|
||||
// --- Input Handling ---
|
||||
|
|
@ -2299,11 +2318,14 @@ void wm_handle_key(char c) {
|
|||
}
|
||||
|
||||
void wm_process_input(void) {
|
||||
uint64_t rflags;
|
||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||
while (key_head != key_tail) {
|
||||
char c = key_queue[key_tail];
|
||||
key_tail = (key_tail + 1) % INPUT_QUEUE_SIZE;
|
||||
wm_dispatch_key(c);
|
||||
}
|
||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||
}
|
||||
|
||||
void wm_mark_dirty(int x, int y, int w, int h) {
|
||||
|
|
@ -2314,6 +2336,28 @@ void wm_refresh(void) {
|
|||
force_redraw = true;
|
||||
}
|
||||
|
||||
void wm_process_deferred_thumbs(void) {
|
||||
if (thumb_queue_head == thumb_queue_tail) return;
|
||||
|
||||
char path[256];
|
||||
int i = 0;
|
||||
while (thumb_request_queue[thumb_queue_head][i]) {
|
||||
path[i] = thumb_request_queue[thumb_queue_head][i];
|
||||
i++;
|
||||
}
|
||||
path[i] = 0;
|
||||
|
||||
serial_write("[WM] Processing deferred thumb: ");
|
||||
serial_write(path);
|
||||
serial_write("\n");
|
||||
|
||||
// Pop from queue
|
||||
thumb_queue_head = (thumb_queue_head + 1) % THUMB_QUEUE_SIZE;
|
||||
|
||||
// Process (this takes time but it's okay because we are in the main loop with IRQs enabled)
|
||||
thumb_cache_decode(path);
|
||||
}
|
||||
|
||||
void wm_init(void) {
|
||||
disk_manager_init();
|
||||
disk_manager_scan();
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ void wm_handle_key(char c);
|
|||
void wm_handle_click(int x, int y);
|
||||
void wm_handle_right_click(int x, int y);
|
||||
void wm_process_input(void);
|
||||
void wm_process_deferred_thumbs(void);
|
||||
void wm_add_window(Window *win);
|
||||
void wm_remove_window(Window *win);
|
||||
void wm_bring_to_front(Window *win);
|
||||
|
|
|
|||
Loading…
Reference in a new issue