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) {
|
void draw_string(int x, int y, const char *s, uint32_t color) {
|
||||||
|
if (!s) return;
|
||||||
int cur_x = x;
|
int cur_x = x;
|
||||||
int cur_y = y;
|
int cur_y = y;
|
||||||
while (*s) {
|
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) {
|
void draw_boredos_logo(int x, int y, int scale) {
|
||||||
|
|
||||||
static const uint8_t brewos_bmp[] = {
|
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,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: Ears
|
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, // 2: Ears (Separated)
|
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, // 3: Forehead / Ears
|
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, // 4: Face
|
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, // 5: Eyes start
|
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, // 6: Eyes
|
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, // 7: Eyes
|
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, // 8: Eyes
|
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, // 9: Under eyes
|
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, // 10: Nose
|
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, // 11: Cheeks
|
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, // 12: Jaw
|
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, // 13: Chin
|
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, // 14: Chin outline
|
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 // 15: Bottom
|
0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int r = 0; r < 16; r++) {
|
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) {
|
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_x = x;
|
||||||
g_clip_y = y;
|
g_clip_y = y;
|
||||||
g_clip_w = w;
|
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;
|
if (vx < 0 || vx >= sw) continue;
|
||||||
|
|
||||||
uint32_t pcol = src[y * w + x];
|
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) {
|
if ((pcol & 0xFF000000) != 0 || (pcol & 0xFFFFFF) != 0) {
|
||||||
g_back_buffer[vy * sw + vx] = pcol;
|
g_back_buffer[vy * sw + vx] = pcol;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,32 @@ void kmain(void) {
|
||||||
platform_init();
|
platform_init();
|
||||||
serial_write("[DEBUG] platform_init OK\n");
|
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) {
|
if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) {
|
||||||
serial_write("[DEBUG] No framebuffer! Halting.\n");
|
serial_write("[DEBUG] No framebuffer! Halting.\n");
|
||||||
hcf();
|
hcf();
|
||||||
|
|
@ -94,20 +119,19 @@ void kmain(void) {
|
||||||
graphics_init(fb);
|
graphics_init(fb);
|
||||||
serial_write("[DEBUG] graphics_init OK\n");
|
serial_write("[DEBUG] graphics_init OK\n");
|
||||||
|
|
||||||
// 1.5 GDT & TSS Init
|
// 3. GDT & TSS Init
|
||||||
gdt_init();
|
gdt_init();
|
||||||
serial_write("[DEBUG] gdt_init OK\n");
|
serial_write("[DEBUG] gdt_init OK\n");
|
||||||
|
|
||||||
// 1.6 Paging Init
|
// 4. Paging Init
|
||||||
paging_init();
|
paging_init();
|
||||||
serial_write("[DEBUG] paging_init OK\n");
|
serial_write("[DEBUG] paging_init OK\n");
|
||||||
|
|
||||||
// 1.7 Syscall Init
|
// 5. Syscall Init
|
||||||
syscall_init();
|
syscall_init();
|
||||||
serial_write("[DEBUG] syscall_init OK\n");
|
serial_write("[DEBUG] syscall_init OK\n");
|
||||||
|
|
||||||
// Set up a user page and jump to user space
|
// 6. Interrupts Init
|
||||||
// 2. Interrupts Init
|
|
||||||
idt_init();
|
idt_init();
|
||||||
idt_register_interrupts();
|
idt_register_interrupts();
|
||||||
idt_load();
|
idt_load();
|
||||||
|
|
@ -115,33 +139,8 @@ void kmain(void) {
|
||||||
|
|
||||||
process_init();
|
process_init();
|
||||||
|
|
||||||
|
|
||||||
serial_write("[DEBUG] Skipping user mode test, proceeding with normal boot.\n");
|
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
|
// Initialize FAT32 RAMFS and mount Limine modules
|
||||||
fat32_init();
|
fat32_init();
|
||||||
if (module_request.response != NULL) {
|
if (module_request.response != NULL) {
|
||||||
|
|
@ -181,6 +180,7 @@ void kmain(void) {
|
||||||
// Timer interrupt will drive the redraw system
|
// Timer interrupt will drive the redraw system
|
||||||
while (1) {
|
while (1) {
|
||||||
wm_process_input();
|
wm_process_input();
|
||||||
|
wm_process_deferred_thumbs();
|
||||||
wallpaper_process_pending();
|
wallpaper_process_pending();
|
||||||
asm("hlt");
|
asm("hlt");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,8 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// --- Internal State ---
|
// --- Internal State ---
|
||||||
#define KERNEL_HEAP_SIZE (32 * 1024 * 1024) // 32MB Static Heap
|
static uint8_t *memory_pool = NULL;
|
||||||
static uint8_t memory_pool_buffer[KERNEL_HEAP_SIZE];
|
static size_t memory_pool_size = 0;
|
||||||
static uint8_t *memory_pool = memory_pool_buffer;
|
|
||||||
static size_t memory_pool_size = KERNEL_HEAP_SIZE;
|
|
||||||
static MemBlock block_list[MAX_ALLOCATIONS];
|
static MemBlock block_list[MAX_ALLOCATIONS];
|
||||||
static int block_count = 0;
|
static int block_count = 0;
|
||||||
static size_t total_allocated = 0;
|
static size_t total_allocated = 0;
|
||||||
|
|
@ -137,9 +135,11 @@ static size_t calculate_fragmentation(void) {
|
||||||
|
|
||||||
// --- Public API ---
|
// --- 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;
|
if (initialized) return;
|
||||||
|
|
||||||
|
memory_pool = (uint8_t *)pool_address;
|
||||||
|
memory_pool_size = pool_size;
|
||||||
|
|
||||||
// Clear metadata
|
// Clear metadata
|
||||||
mem_memset(block_list, 0, sizeof(block_list));
|
mem_memset(block_list, 0, sizeof(block_list));
|
||||||
|
|
@ -158,6 +158,14 @@ void memory_manager_init_with_size(size_t pool_size) {
|
||||||
initialized = true;
|
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) {
|
void memory_manager_init(void) {
|
||||||
memory_manager_init_with_size(DEFAULT_POOL_SIZE);
|
memory_manager_init_with_size(DEFAULT_POOL_SIZE);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
// Memory Manager Configuration
|
// Memory Manager Configuration
|
||||||
#define DEFAULT_POOL_SIZE (512 * 1024 * 1024) // 512MB default (can be overridden)
|
#define DEFAULT_POOL_SIZE (128 * 1024 * 1024) // 128MB default
|
||||||
#define MAX_ALLOCATIONS 4096 // Increased for larger pools
|
#define MAX_ALLOCATIONS 16384 // Increased for larger pools
|
||||||
#define MAX_FRAGMENTATION_SLOTS 2048
|
#define MAX_FRAGMENTATION_SLOTS 2048
|
||||||
|
|
||||||
// Allocation block metadata
|
// Allocation block metadata
|
||||||
|
|
@ -35,6 +35,7 @@ typedef struct {
|
||||||
// Public API
|
// Public API
|
||||||
void memory_manager_init(void);
|
void memory_manager_init(void);
|
||||||
void memory_manager_init_with_size(size_t pool_size);
|
void memory_manager_init_with_size(size_t pool_size);
|
||||||
|
void memory_manager_init_at(void *pool_address, size_t pool_size);
|
||||||
|
|
||||||
// Allocation/Deallocation
|
// Allocation/Deallocation
|
||||||
void* kmalloc(size_t size);
|
void* kmalloc(size_t size);
|
||||||
|
|
|
||||||
|
|
@ -239,6 +239,8 @@ void process_create_elf(const char* filepath, const char* args_str) {
|
||||||
*(--stack_ptr) = 0; // R15
|
*(--stack_ptr) = 0; // R15
|
||||||
|
|
||||||
new_proc->kernel_stack = (uint64_t)kernel_stack + 16384;
|
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;
|
new_proc->rsp = (uint64_t)stack_ptr;
|
||||||
|
|
||||||
// We only increment process_count after success
|
// We only increment process_count after success
|
||||||
|
|
@ -333,6 +335,13 @@ uint64_t process_terminate_current(void) {
|
||||||
|
|
||||||
paging_switch_directory(current_process->pml4_phys);
|
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;
|
return current_process->rsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,9 @@ typedef struct process {
|
||||||
|
|
||||||
void *fds[MAX_PROCESS_FDS];
|
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;
|
struct process *next;
|
||||||
} process_t;
|
} 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 ---
|
// --- State ---
|
||||||
static int mx = 400, my = 300; // Mouse Pos
|
static int mx = 400, my = 300;
|
||||||
static int prev_mx = 400, prev_my = 300; // Previous mouse position
|
static int prev_mx = 400, prev_my = 300;
|
||||||
static bool start_menu_open = false;
|
static bool start_menu_open = false;
|
||||||
static char *start_menu_pending_app = NULL; // For click vs drag detection
|
static char *start_menu_pending_app = NULL;
|
||||||
static int pending_desktop_icon_click = -1; // For desktop icon click vs drag
|
static int pending_desktop_icon_click = -1;
|
||||||
|
|
||||||
// Desktop Context Menu
|
// Desktop Context Menu
|
||||||
static bool desktop_menu_visible = false;
|
static bool desktop_menu_visible = false;
|
||||||
static int desktop_menu_x = 0;
|
static int desktop_menu_x = 0;
|
||||||
static int desktop_menu_y = 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
|
// 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 char desktop_dialog_input[64];
|
||||||
static int desktop_dialog_cursor = 0;
|
static int desktop_dialog_cursor = 0;
|
||||||
static int desktop_dialog_target = -1;
|
static int desktop_dialog_target = -1;
|
||||||
|
|
@ -62,7 +62,7 @@ static int drag_offset_y = 0;
|
||||||
// File Dragging State
|
// File Dragging State
|
||||||
bool is_dragging_file = false;
|
bool is_dragging_file = false;
|
||||||
static char drag_file_path[256];
|
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_x = 0;
|
||||||
static int drag_start_y = 0;
|
static int drag_start_y = 0;
|
||||||
static int drag_icon_orig_x = 0;
|
static int drag_icon_orig_x = 0;
|
||||||
|
|
@ -74,7 +74,7 @@ static Window *all_windows[32];
|
||||||
static int window_count = 0;
|
static int window_count = 0;
|
||||||
|
|
||||||
// Redraw system
|
// 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 uint32_t timer_ticks = 0;
|
||||||
static int desktop_refresh_timer = 0;
|
static int desktop_refresh_timer = 0;
|
||||||
|
|
||||||
|
|
@ -88,7 +88,7 @@ static int last_cursor_y = 300;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[64];
|
char name[64];
|
||||||
int x, y;
|
int x, y;
|
||||||
int type; // 0=File, 1=Folder, 2=App
|
int type;
|
||||||
} DesktopIcon;
|
} DesktopIcon;
|
||||||
|
|
||||||
static DesktopIcon desktop_icons[MAX_DESKTOP_ICONS];
|
static DesktopIcon desktop_icons[MAX_DESKTOP_ICONS];
|
||||||
|
|
@ -101,7 +101,7 @@ int desktop_max_rows_per_col = 13;
|
||||||
int desktop_max_cols = 23;
|
int desktop_max_cols = 23;
|
||||||
|
|
||||||
// Mouse Settings
|
// 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_x = 0;
|
||||||
static int mouse_accum_y = 0;
|
static int mouse_accum_y = 0;
|
||||||
|
|
||||||
|
|
@ -141,9 +141,7 @@ static void refresh_desktop_icons(void) {
|
||||||
bool file_processed[MAX_DESKTOP_ICONS];
|
bool file_processed[MAX_DESKTOP_ICONS];
|
||||||
for(int i=0; i<MAX_DESKTOP_ICONS; i++) file_processed[i] = false;
|
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++) {
|
for (int i = 0; i < desktop_icon_count; i++) {
|
||||||
// Find if this icon still exists in the file list
|
|
||||||
int found_idx = -1;
|
int found_idx = -1;
|
||||||
for (int j = 0; j < file_count; j++) {
|
for (int j = 0; j < file_count; j++) {
|
||||||
if (!file_processed[j] && str_eq(desktop_icons[i].name, files[j].name) != 0) {
|
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++) {
|
for (int i = 0; i < file_count; i++) {
|
||||||
if (!file_processed[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;
|
if (new_count >= MAX_DESKTOP_ICONS) break;
|
||||||
|
|
||||||
DesktopIcon *dest = &new_icons[new_count];
|
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];
|
for(int i=0; i<new_count; i++) desktop_icons[i] = new_icons[i];
|
||||||
kfree(files);
|
kfree(files);
|
||||||
|
|
||||||
// 3. Layout Icons
|
|
||||||
if (desktop_auto_align) {
|
if (desktop_auto_align) {
|
||||||
int start_x = 20;
|
int start_x = 20;
|
||||||
int start_y = 30;
|
int start_y = 30;
|
||||||
int grid_x = 0;
|
int grid_x = 0;
|
||||||
int grid_y = 0;
|
int grid_y = 0;
|
||||||
|
|
||||||
// Find Recycle Bin index
|
|
||||||
int recycle_idx = -1;
|
int recycle_idx = -1;
|
||||||
for (int i = 0; i < desktop_icon_count; i++) {
|
for (int i = 0; i < desktop_icon_count; i++) {
|
||||||
if (str_starts_with(desktop_icons[i].name, "Recycle Bin")) {
|
if (str_starts_with(desktop_icons[i].name, "Recycle Bin")) {
|
||||||
|
|
@ -521,6 +516,42 @@ static struct {
|
||||||
} thumb_cache[THUMB_CACHE_SIZE];
|
} thumb_cache[THUMB_CACHE_SIZE];
|
||||||
static int thumb_cache_next = 0; // Round-robin eviction
|
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) {
|
static uint32_t* thumb_cache_lookup(const char *path) {
|
||||||
for (int i = 0; i < THUMB_CACHE_SIZE; i++) {
|
for (int i = 0; i < THUMB_CACHE_SIZE; i++) {
|
||||||
if (thumb_cache[i].valid && str_eq(thumb_cache[i].path, path) != 0) {
|
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;
|
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) {
|
static uint32_t* thumb_cache_decode(const char *path) {
|
||||||
// Open and read the JPG file
|
// Open and read the JPG file
|
||||||
|
|
@ -566,11 +590,14 @@ static uint32_t* thumb_cache_decode(const char *path) {
|
||||||
// Decode JPEG
|
// Decode JPEG
|
||||||
njInit();
|
njInit();
|
||||||
if (njDecode(buf, total) != NJ_OK) {
|
if (njDecode(buf, total) != NJ_OK) {
|
||||||
|
serial_write("[WM] njDecode failed for deferred thumb\n");
|
||||||
njDone();
|
njDone();
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serial_write("[WM] njDecode OK for deferred thumb\n");
|
||||||
|
|
||||||
int img_w = njGetWidth();
|
int img_w = njGetWidth();
|
||||||
int img_h = njGetHeight();
|
int img_h = njGetHeight();
|
||||||
unsigned char *img = njGetImage();
|
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)) {
|
if (!thumb && !thumb_cache_is_failed(label)) {
|
||||||
thumb = thumb_cache_lookup(label);
|
thumb = thumb_cache_lookup(label);
|
||||||
if (!thumb) {
|
if (!thumb) {
|
||||||
// Try to decode and cache
|
// Queue for background decoding
|
||||||
graphics_set_render_target(NULL, 0, 0); // Restore before file I/O
|
thumb_request_push(label);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1097,6 +1110,9 @@ void wm_paint(void) {
|
||||||
int sw = get_screen_width();
|
int sw = get_screen_width();
|
||||||
int sh = get_screen_height();
|
int sh = get_screen_height();
|
||||||
|
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
|
|
||||||
DirtyRect dirty = graphics_get_dirty_rect();
|
DirtyRect dirty = graphics_get_dirty_rect();
|
||||||
if (dirty.active) {
|
if (dirty.active) {
|
||||||
graphics_set_clipping(dirty.x, dirty.y, dirty.w, dirty.h);
|
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
|
// Flip the buffer - display the rendered frame atomically
|
||||||
graphics_flip_buffer();
|
graphics_flip_buffer();
|
||||||
|
|
||||||
|
// Restore IRQs
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Input Handling ---
|
// --- Input Handling ---
|
||||||
|
|
@ -2299,11 +2318,14 @@ void wm_handle_key(char c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_process_input(void) {
|
void wm_process_input(void) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
while (key_head != key_tail) {
|
while (key_head != key_tail) {
|
||||||
char c = key_queue[key_tail];
|
char c = key_queue[key_tail];
|
||||||
key_tail = (key_tail + 1) % INPUT_QUEUE_SIZE;
|
key_tail = (key_tail + 1) % INPUT_QUEUE_SIZE;
|
||||||
wm_dispatch_key(c);
|
wm_dispatch_key(c);
|
||||||
}
|
}
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_mark_dirty(int x, int y, int w, int h) {
|
void wm_mark_dirty(int x, int y, int w, int h) {
|
||||||
|
|
@ -2314,6 +2336,28 @@ void wm_refresh(void) {
|
||||||
force_redraw = true;
|
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) {
|
void wm_init(void) {
|
||||||
disk_manager_init();
|
disk_manager_init();
|
||||||
disk_manager_scan();
|
disk_manager_scan();
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ void wm_handle_key(char c);
|
||||||
void wm_handle_click(int x, int y);
|
void wm_handle_click(int x, int y);
|
||||||
void wm_handle_right_click(int x, int y);
|
void wm_handle_right_click(int x, int y);
|
||||||
void wm_process_input(void);
|
void wm_process_input(void);
|
||||||
|
void wm_process_deferred_thumbs(void);
|
||||||
void wm_add_window(Window *win);
|
void wm_add_window(Window *win);
|
||||||
void wm_remove_window(Window *win);
|
void wm_remove_window(Window *win);
|
||||||
void wm_bring_to_front(Window *win);
|
void wm_bring_to_front(Window *win);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue