mirror of
https://github.com/JannisHeydemann/BoredOS.git
synced 2026-05-30 02:16:58 +00:00
Stability improvements
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user