Memory fixes userspace

This commit is contained in:
boreddevnl 2026-02-26 21:09:18 +01:00
parent 786eac0345
commit 2801dbc21f
57 changed files with 215 additions and 183 deletions

2
.gitignore vendored
View file

@ -18,6 +18,6 @@ limine 2/Makefile
limine 2/limine limine 2/limine
limine 2/limine.dSYM/Contents/Resources/DWARF/limine limine 2/limine.dSYM/Contents/Resources/DWARF/limine
limine 2/limine.exe limine 2/limine.exe
build/*
boredos.dump boredos.dump
qemu-debug.log qemu-debug.log
build/

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.

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
disk.img

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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -915,7 +915,7 @@ static void explorer_draw_file_icon(int x, int y, bool is_dir, uint32_t color, c
static void explorer_paint(Window *win) { static void explorer_paint(Window *win) {
ExplorerState *state = (ExplorerState*)win->data; ExplorerState *state = (ExplorerState*)win->data;
int offset_x = win->x + 4; int offset_x = win->x + 4;
int offset_y = win->y + 24; int offset_y = win->y + 20;
DirtyRect dirty = graphics_get_dirty_rect(); DirtyRect dirty = graphics_get_dirty_rect();
// Fill background with dark mode // Fill background with dark mode
@ -1367,7 +1367,7 @@ static void explorer_handle_click(Window *win, int x, int y) {
// Handle Drive Menu Selection // Handle Drive Menu Selection
if (state->drive_menu_visible) { if (state->drive_menu_visible) {
int menu_x = 4; // Window relative int menu_x = 4; // Window relative
int menu_y = 50; // 24+26 int menu_y = 26; // 24+26
int menu_w = 80; int menu_w = 80;
int count = disk_get_count(); int count = disk_get_count();
int menu_h = count * 25; int menu_h = count * 25;
@ -1396,7 +1396,7 @@ static void explorer_handle_click(Window *win, int x, int y) {
// Handle dropdown menu clicks // Handle dropdown menu clicks
if (state->dropdown_menu_visible) { if (state->dropdown_menu_visible) {
int dropdown_btn_x = win->w - 90; // Window-relative int dropdown_btn_x = win->w - 90; // Window-relative
int menu_y = 50; // Window-relative (offset_y + 26, where offset_y = 24) int menu_y = 26; // Window-relative (offset_y + 26, where offset_y = 24)
// New File // New File
if (x >= dropdown_btn_x && x < dropdown_btn_x + DROPDOWN_MENU_WIDTH && if (x >= dropdown_btn_x && x < dropdown_btn_x + DROPDOWN_MENU_WIDTH &&
@ -1434,7 +1434,7 @@ static void explorer_handle_click(Window *win, int x, int y) {
// x, y are already relative to window (0,0 is top-left of window content area) // x, y are already relative to window (0,0 is top-left of window content area)
// Check Drive Button // Check Drive Button
int button_y = 27; int button_y = 3;
if (x >= 4 && x < 64 && y >= button_y && y < button_y + 22) { if (x >= 4 && x < 64 && y >= button_y && y < button_y + 22) {
state->drive_menu_visible = !state->drive_menu_visible; state->drive_menu_visible = !state->drive_menu_visible;
state->dropdown_menu_visible = false; // Close other menu state->dropdown_menu_visible = false; // Close other menu
@ -1476,7 +1476,7 @@ static void explorer_handle_click(Window *win, int x, int y) {
} }
// File items start at y=64 relative to window // File items start at y=64 relative to window
int content_start_y = 54; int content_start_y = 30;
int offset_x = 4; int offset_x = 4;
for (int i = 0; i < state->item_count; i++) { for (int i = 0; i < state->item_count; i++) {
@ -1647,7 +1647,7 @@ static void explorer_handle_key(Window *win, char c) {
static void explorer_handle_right_click(Window *win, int x, int y) { static void explorer_handle_right_click(Window *win, int x, int y) {
ExplorerState *state = (ExplorerState*)win->data; ExplorerState *state = (ExplorerState*)win->data;
// File items start at y=64 relative to window // File items start at y=64 relative to window
int content_start_y = 54; int content_start_y = 30;
int offset_x = 4; int offset_x = 4;
for (int i = 0; i < state->item_count; i++) { for (int i = 0; i < state->item_count; i++) {

View file

@ -46,6 +46,8 @@ typedef struct {
uint32_t total_sectors; uint32_t total_sectors;
uint32_t partition_offset; // LBA offset of partition start uint32_t partition_offset; // LBA offset of partition start
bool mounted; bool mounted;
uint32_t cached_fat_sector;
uint8_t cached_fat_buf[512];
} FAT32_Volume; } FAT32_Volume;
static FAT32_Volume volumes[26]; // A-Z static FAT32_Volume volumes[26]; // A-Z
@ -413,6 +415,7 @@ static bool realfs_mount(char drive) {
volumes[idx].fat_size = bpb->sectors_per_fat_32; volumes[idx].fat_size = bpb->sectors_per_fat_32;
volumes[idx].total_sectors = bpb->total_sectors_32; volumes[idx].total_sectors = bpb->total_sectors_32;
volumes[idx].mounted = true; volumes[idx].mounted = true;
volumes[idx].cached_fat_sector = 0xFFFFFFFF;
fs_serial_str("[FAT32] mounted drive "); fs_serial_str("[FAT32] mounted drive ");
fs_serial_char(drive); fs_serial_char(drive);
@ -456,18 +459,16 @@ static uint32_t realfs_next_cluster(FAT32_Volume *vol, uint32_t cluster) {
uint32_t fat_sector = vol->fat_begin_lba + (cluster * 4) / 512; uint32_t fat_sector = vol->fat_begin_lba + (cluster * 4) / 512;
uint32_t fat_offset = (cluster * 4) % 512; uint32_t fat_offset = (cluster * 4) % 512;
uint8_t *buf = (uint8_t*)kmalloc(512); if (vol->cached_fat_sector != fat_sector) {
if (!buf) return 0xFFFFFFFF; if (vol->disk->read_sector(vol->disk, fat_sector, vol->cached_fat_buf) != 0) {
return 0xFFFFFFFF;
if (vol->disk->read_sector(vol->disk, fat_sector, buf) != 0) { }
kfree(buf); vol->cached_fat_sector = fat_sector;
return 0xFFFFFFFF;
} }
uint32_t next = *(uint32_t*)&buf[fat_offset]; uint32_t next = *(uint32_t*)&vol->cached_fat_buf[fat_offset];
next &= 0x0FFFFFFF; // Mask top 4 bits next &= 0x0FFFFFFF; // Mask top 4 bits
kfree(buf);
return next; return next;
} }
@ -791,6 +792,9 @@ static uint32_t realfs_allocate_cluster(FAT32_Volume *vol) {
if ((val & 0x0FFFFFFF) == 0) { if ((val & 0x0FFFFFFF) == 0) {
*(uint32_t*)&fat_buf[offset] = 0x0FFFFFFF; // EOC *(uint32_t*)&fat_buf[offset] = 0x0FFFFFFF; // EOC
vol->disk->write_sector(vol->disk, sector, fat_buf); vol->disk->write_sector(vol->disk, sector, fat_buf);
if (vol->cached_fat_sector == sector) {
vol->cached_fat_sector = 0xFFFFFFFF;
}
kfree(fat_buf); kfree(fat_buf);
return current; return current;
} }

View file

@ -7,6 +7,7 @@
#define GUI_CMD_MARK_DIRTY 4 #define GUI_CMD_MARK_DIRTY 4
#define GUI_CMD_GET_EVENT 5 #define GUI_CMD_GET_EVENT 5
#define GUI_CMD_DRAW_ROUNDED_RECT_FILLED 6 #define GUI_CMD_DRAW_ROUNDED_RECT_FILLED 6
#define GUI_CMD_DRAW_IMAGE 7
#define GUI_EVENT_NONE 0 #define GUI_EVENT_NONE 0
#define GUI_EVENT_PAINT 1 #define GUI_EVENT_PAINT 1

View file

@ -209,10 +209,18 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
serial_write("Kernel: Dims initialized.\n"); serial_write("Kernel: Dims initialized.\n");
size_t pixel_size = 0;
// Safe allocation // Safe allocation
size_t pixel_size = (size_t)win->w * win->h * 4; size_t client_h = win->h - 20;
win->pixels = kmalloc(pixel_size); if (win->w <= 0 || win->h <= 20) {
win->comp_pixels = kmalloc(pixel_size); // Invalid dimensions, but prevent underflow/bad alloc
win->pixels = NULL;
win->comp_pixels = NULL;
} else {
pixel_size = (size_t)win->w * client_h * 4;
win->pixels = kmalloc(pixel_size);
win->comp_pixels = kmalloc(pixel_size);
}
serial_write("Kernel: Buffers allocated.\n"); serial_write("Kernel: Buffers allocated.\n");
@ -259,10 +267,10 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
if (rx < 0) { rw += rx; rx = 0; } if (rx < 0) { rw += rx; rx = 0; }
if (ry < 0) { rh += ry; ry = 0; } if (ry < 0) { rh += ry; ry = 0; }
if (rx + rw > win->w) rw = win->w - rx; if (rx + rw > win->w) rw = win->w - rx;
if (ry + rh > win->h) rh = win->h - ry; if (ry + rh > (win->h - 20)) rh = (win->h - 20) - ry;
if (rw > 0 && rh > 0) { if (rw > 0 && rh > 0) {
graphics_set_render_target(win->pixels, win->w, win->h); graphics_set_render_target(win->pixels, win->w, win->h - 20);
draw_rect(rx, ry, rw, rh, color); draw_rect(rx, ry, rw, rh, color);
graphics_set_render_target(NULL, 0, 0); graphics_set_render_target(NULL, 0, 0);
} }
@ -293,10 +301,10 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
if (rx < 0) { rw += rx; rx = 0; } if (rx < 0) { rw += rx; rx = 0; }
if (ry < 0) { rh += ry; ry = 0; } if (ry < 0) { rh += ry; ry = 0; }
if (rx + rw > win->w) rw = win->w - rx; if (rx + rw > win->w) rw = win->w - rx;
if (ry + rh > win->h) rh = win->h - ry; if (ry + rh > (win->h - 20)) rh = (win->h - 20) - ry;
if (rw > 0 && rh > 0) { if (rw > 0 && rh > 0) {
graphics_set_render_target(win->pixels, win->w, win->h); graphics_set_render_target(win->pixels, win->w, win->h - 20);
draw_rounded_rect_filled(rx, ry, rw, rh, rr, color); draw_rounded_rect_filled(rx, ry, rw, rh, rr, color);
graphics_set_render_target(NULL, 0, 0); graphics_set_render_target(NULL, 0, 0);
} }
@ -330,8 +338,8 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
if (win->pixels) { if (win->pixels) {
// String clipping is handled by draw_char -> put_pixel, // String clipping is handled by draw_char -> put_pixel,
// but we ensure coordinate sanity here // but we ensure coordinate sanity here
if (ux >= -100 && ux < win->w && uy >= -100 && uy < win->h) { if (ux >= -100 && ux < win->w && uy >= -100 && uy < (win->h - 20)) {
graphics_set_render_target(win->pixels, win->w, win->h); graphics_set_render_target(win->pixels, win->w, win->h - 20);
draw_string(ux, uy, kernel_str, color); draw_string(ux, uy, kernel_str, color);
graphics_set_render_target(NULL, 0, 0); graphics_set_render_target(NULL, 0, 0);
} }
@ -339,6 +347,41 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
draw_string(win->x + ux, win->y + uy, kernel_str, color); draw_string(win->x + ux, win->y + uy, kernel_str, color);
} }
asm volatile("push %0; popfq" : : "r"(rflags));
}
} else if (cmd == GUI_CMD_DRAW_IMAGE) {
Window *win = (Window *)arg2;
uint64_t *u_params = (uint64_t *)arg3;
uint32_t *image_data = (uint32_t *)arg4;
if (win && u_params && image_data) {
uint64_t params[4];
for (int i = 0; i < 4; i++) params[i] = u_params[i];
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
if (win->pixels) {
int rx = (int)params[0]; int ry = (int)params[1];
int rw = (int)params[2]; int rh = (int)params[3];
int src_x_offset = 0;
int src_y_offset = 0;
if (rx < 0) { src_x_offset = -rx; rw += rx; rx = 0; }
if (ry < 0) { src_y_offset = -ry; rh += ry; ry = 0; }
if (rx + rw > win->w) rw = win->w - rx;
if (ry + rh > (win->h - 20)) rh = (win->h - 20) - ry;
if (rw > 0 && rh > 0) {
for (int y = 0; y < rh; y++) {
uint32_t *dest = &win->pixels[(ry + y) * win->w + rx];
uint32_t *src = &image_data[(src_y_offset + y) * (int)params[2] + src_x_offset];
for (int x = 0; x < rw; x++) {
dest[x] = src[x];
}
}
}
}
asm volatile("push %0; popfq" : : "r"(rflags)); asm volatile("push %0; popfq" : : "r"(rflags));
} }
} else if (cmd == GUI_CMD_MARK_DIRTY) { } else if (cmd == GUI_CMD_MARK_DIRTY) {
@ -351,7 +394,7 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
// Dual-buffer commit: copy pixels to comp_pixels // Dual-buffer commit: copy pixels to comp_pixels
if (win->pixels && win->comp_pixels) { if (win->pixels && win->comp_pixels) {
extern void mem_memcpy(void *dest, const void *src, size_t len); extern void mem_memcpy(void *dest, const void *src, size_t len);
mem_memcpy(win->comp_pixels, win->pixels, (size_t)win->w * win->h * 4); mem_memcpy(win->comp_pixels, win->pixels, (size_t)win->w * (win->h - 20) * 4);
} }
wm_mark_dirty(win->x + (int)params[0], win->y + (int)params[1], (int)params[2], (int)params[3]); wm_mark_dirty(win->x + (int)params[0], win->y + (int)params[1], (int)params[2], (int)params[3]);
} }
@ -458,14 +501,19 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
uint64_t start_page = (old_end + 0xFFF) & ~0xFFF; uint64_t start_page = (old_end + 0xFFF) & ~0xFFF;
uint64_t end_page = (new_end + 0xFFF) & ~0xFFF; uint64_t end_page = (new_end + 0xFFF) & ~0xFFF;
for (uint64_t page = start_page; page < end_page; page += 4096) { if (end_page > start_page) {
void *phys = kmalloc_aligned(4096, 4096); uint64_t total_size = end_page - start_page;
if (!phys) return (uint64_t)-1; // Out of memory void *phys_block = kmalloc_aligned(total_size, 4096);
if (!phys_block) return (uint64_t)-1; // Out of memory
extern void mem_memset(void *dest, int val, size_t len); extern void mem_memset(void *dest, int val, size_t len);
mem_memset(phys, 0, 4096); mem_memset(phys_block, 0, total_size);
paging_map_page(proc->pml4_phys, page, v2p((uint64_t)phys), 0x07); // PT_PRESENT | PT_RW | PT_USER uint64_t phys_addr = (uint64_t)phys_block;
for (uint64_t page = start_page; page < end_page; page += 4096) {
paging_map_page(proc->pml4_phys, page, v2p(phys_addr), 0x07); // PT_PRESENT | PT_RW | PT_USER
phys_addr += 4096;
}
} }
} }

View file

@ -86,12 +86,12 @@ static void update_display(void) {
static void calculator_paint(void) { static void calculator_paint(void) {
int w = 180; int w = 180;
int h = 230; int h = 230;
ui_draw_rect(win_calculator, 4, 30, w - 8, h - 34, COLOR_DARK_BG); ui_draw_rect(win_calculator, 4, 4, w - 8, h - 34, COLOR_DARK_BG);
ui_draw_rounded_rect_filled(win_calculator, 10, 36, w - 20, 25, 6, COLOR_DARK_PANEL); ui_draw_rounded_rect_filled(win_calculator, 10, 10, w - 20, 25, 6, COLOR_DARK_PANEL);
int text_w = display_buf_len * 8; int text_w = display_buf_len * 8;
int text_x = w - 15 - text_w; int text_x = w - 15 - text_w;
ui_draw_string(win_calculator, text_x, 44, display_buffer, COLOR_DARK_TEXT); ui_draw_string(win_calculator, text_x, 18, display_buffer, COLOR_DARK_TEXT);
const char *labels[] = { const char *labels[] = {
"C", "sqr", "rt", "/", "C", "sqr", "rt", "/",
@ -105,7 +105,7 @@ static void calculator_paint(void) {
int bh = 25; int bh = 25;
int gap = 5; int gap = 5;
int start_x = 10; int start_x = 10;
int start_y = 70; int start_y = 40;
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
int r = i / 4; int r = i / 4;
@ -136,7 +136,7 @@ static void calculator_click(int x, int y) {
int bh = 25; int bh = 25;
int gap = 5; int gap = 5;
int start_x = 10; int start_x = 10;
int start_y = 65; // Matches the hitboxes int start_y = 35; // Matches the hitboxes
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
int r = i / 4; int r = i / 4;

Binary file not shown.

View file

@ -4,7 +4,6 @@ int main() {
const char* msg = "Attempting to crash via null dereference...\n"; const char* msg = "Attempting to crash via null dereference...\n";
sys_write(1, msg, 45); sys_write(1, msg, 45);
// Null pointer dereference (should not crash the system and instead get this process killed)
volatile int* p = (int*)0; volatile int* p = (int*)0;
*p = 123; *p = 123;

Binary file not shown.

Binary file not shown.

View file

@ -39,3 +39,8 @@ void ui_mark_dirty(ui_window_t win, int x, int y, int w, int h) {
uint64_t params[4] = { (uint64_t)x, (uint64_t)y, (uint64_t)w, (uint64_t)h }; uint64_t params[4] = { (uint64_t)x, (uint64_t)y, (uint64_t)w, (uint64_t)h };
syscall3(SYS_GUI, GUI_CMD_MARK_DIRTY, (uint64_t)win, (uint64_t)params); syscall3(SYS_GUI, GUI_CMD_MARK_DIRTY, (uint64_t)win, (uint64_t)params);
} }
void ui_draw_image(ui_window_t win, int x, int y, int w, int h, uint32_t *image_data) {
uint64_t params[4] = { (uint64_t)x, (uint64_t)y, (uint64_t)w, (uint64_t)h };
syscall4(SYS_GUI, GUI_CMD_DRAW_IMAGE, (uint64_t)win, (uint64_t)params, (uint64_t)image_data);
}

View file

@ -11,6 +11,7 @@
#define GUI_CMD_MARK_DIRTY 4 #define GUI_CMD_MARK_DIRTY 4
#define GUI_CMD_GET_EVENT 5 #define GUI_CMD_GET_EVENT 5
#define GUI_CMD_DRAW_ROUNDED_RECT_FILLED 6 #define GUI_CMD_DRAW_ROUNDED_RECT_FILLED 6
#define GUI_CMD_DRAW_IMAGE 7
// Event Types // Event Types
#define GUI_EVENT_NONE 0 #define GUI_EVENT_NONE 0
@ -42,5 +43,6 @@ void ui_draw_rect(ui_window_t win, int x, int y, int w, int h, uint32_t color);
void ui_draw_rounded_rect_filled(ui_window_t win, int x, int y, int w, int h, int radius, uint32_t color); void ui_draw_rounded_rect_filled(ui_window_t win, int x, int y, int w, int h, int radius, uint32_t color);
void ui_draw_string(ui_window_t win, int x, int y, const char *str, uint32_t color); void ui_draw_string(ui_window_t win, int x, int y, const char *str, uint32_t color);
void ui_mark_dirty(ui_window_t win, int x, int y, int w, int h); void ui_mark_dirty(ui_window_t win, int x, int y, int w, int h);
void ui_draw_image(ui_window_t win, int x, int y, int w, int h, uint32_t *image_data);
#endif #endif

Binary file not shown.

View file

@ -24,9 +24,6 @@ static BlockMeta *find_free_block(BlockMeta **last, size_t size) {
static BlockMeta *request_space(BlockMeta* last, size_t size) { static BlockMeta *request_space(BlockMeta* last, size_t size) {
BlockMeta *block; BlockMeta *block;
block = (BlockMeta *)sys_sbrk(0); block = (BlockMeta *)sys_sbrk(0);
// Ask for space, ensuring everything stays 8-byte aligned if sizes are odd.
// For simplicity, we just request exactly what is needed,
// but typically `size` should be aligned.
size_t align = 8; size_t align = 8;
if (size % align != 0) { if (size % align != 0) {
size += align - (size % align); size += align - (size % align);
@ -70,7 +67,6 @@ void *malloc(size_t size) {
if (!block) return NULL; if (!block) return NULL;
} else { // Found free block } else { // Found free block
block->free = 0; block->free = 0;
// We could split the block here if block->size is much larger than size...
} }
} }

View file

@ -59,11 +59,10 @@ uint64_t syscall5(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
return ret; return ret;
} }
// C-Friendly Wrappers
void sys_exit(int status) { void sys_exit(int status) {
syscall1(SYS_EXIT, (uint64_t)status); syscall1(SYS_EXIT, (uint64_t)status);
while (1); // Halt while (1);
} }
int sys_write(int fd, const char *buf, int len) { int sys_write(int fd, const char *buf, int len) {

View file

@ -235,7 +235,7 @@ static void md_draw_text_bold(ui_window_t win, int x, int y, const char *text, u
static void md_paint(ui_window_t win) { static void md_paint(ui_window_t win) {
int offset_x = 4; int offset_x = 4;
int offset_y = 24; int offset_y = 0;
int content_width = win_w - 8; int content_width = win_w - 8;
int content_height = win_h - 28; int content_height = win_h - 28;
@ -392,7 +392,7 @@ static void md_handle_key(char c) {
static void md_handle_click(int x, int y) { static void md_handle_click(int x, int y) {
int content_width = win_w - 8; int content_width = win_w - 8;
int btn_x_up = 4 + content_width - 50; int btn_x_up = 4 + content_width - 50;
int btn_y = 24 + 2; int btn_y = 2;
if (x >= btn_x_up && x < btn_x_up + 20 && y >= btn_y && y < btn_y + 16) { if (x >= btn_x_up && x < btn_x_up + 20 && y >= btn_y && y < btn_y + 16) {
scroll_top -= 3; scroll_top -= 3;
if (scroll_top < 0) scroll_top = 0; if (scroll_top < 0) scroll_top = 0;
@ -423,15 +423,15 @@ int main(int argc, char **argv) {
if (ui_get_event(win, &ev)) { if (ui_get_event(win, &ev)) {
if (ev.type == GUI_EVENT_PAINT) { if (ev.type == GUI_EVENT_PAINT) {
md_paint(win); md_paint(win);
ui_mark_dirty(win, 0, 0, win_w, win_h); ui_mark_dirty(win, 0, 0, win_w, win_h - 20);
} else if (ev.type == GUI_EVENT_CLICK) { } else if (ev.type == GUI_EVENT_CLICK) {
md_handle_click(ev.arg1, ev.arg2); md_handle_click(ev.arg1, ev.arg2);
md_paint(win); md_paint(win);
ui_mark_dirty(win, 0, 0, win_w, win_h); ui_mark_dirty(win, 0, 0, win_w, win_h - 20);
} else if (ev.type == GUI_EVENT_KEY) { } else if (ev.type == GUI_EVENT_KEY) {
md_handle_key((char)ev.arg1); md_handle_key((char)ev.arg1);
md_paint(win); md_paint(win);
ui_mark_dirty(win, 0, 0, win_w, win_h); ui_mark_dirty(win, 0, 0, win_w, win_h - 20);
} else if (ev.type == GUI_EVENT_CLOSE) { } else if (ev.type == GUI_EVENT_CLOSE) {
sys_exit(0); sys_exit(0);
} }

Binary file not shown.

View file

@ -26,14 +26,13 @@ static void debug_print(const char *msg) {
#define CELL_SIZE 20 #define CELL_SIZE 20
// Game state // Game state
static int grid[GRID_HEIGHT][GRID_WIDTH]; // -1 = mine, 0-8 = adjacent mine count static int grid[GRID_HEIGHT][GRID_WIDTH];
static bool revealed[GRID_HEIGHT][GRID_WIDTH]; static bool revealed[GRID_HEIGHT][GRID_WIDTH];
static bool flagged[GRID_HEIGHT][GRID_WIDTH]; static bool flagged[GRID_HEIGHT][GRID_WIDTH];
static bool game_over = false; static bool game_over = false;
static bool game_won = false; static bool game_won = false;
static int revealed_count = 0; static int revealed_count = 0;
// Helper: Random number generator (simple LCG)
static uint32_t random_seed = 12345; static uint32_t random_seed = 12345;
static uint32_t random_next(void) { static uint32_t random_next(void) {
random_seed = random_seed * 1103515245 + 12345; random_seed = random_seed * 1103515245 + 12345;
@ -120,10 +119,8 @@ static void reveal_cell(int x, int y) {
} }
} }
} else if (grid[y][x] == 0) { } else if (grid[y][x] == 0) {
// Empty cell - flood fill
flood_fill(x, y); flood_fill(x, y);
} else { } else {
// Numbered cell
revealed[y][x] = true; revealed[y][x] = true;
revealed_count++; revealed_count++;
} }
@ -144,21 +141,19 @@ static void flag_cell(int x, int y) {
static void minesweeper_paint(ui_window_t win) { static void minesweeper_paint(ui_window_t win) {
int win_w = 240, win_h = 340; int win_w = 240, win_h = 340;
// Background - dark mode ui_draw_rect(win, 4, 0, win_w - 8, win_h - 34, COLOR_DARK_BG);
ui_draw_rect(win, 4, 30, win_w - 8, win_h - 34, COLOR_DARK_BG);
// Game status
if (game_over) { if (game_over) {
ui_draw_string(win, 10, 36, "Game Over!", COLOR_TRAFFIC_RED); ui_draw_string(win, 10, 6, "Game Over!", COLOR_TRAFFIC_RED);
} else if (game_won) { } else if (game_won) {
ui_draw_string(win, 10, 36, "You Won!", 0xFF00FF00); // Bright green ui_draw_string(win, 10, 6, "You Won!", 0xFF00FF00); // Bright green
} else { } else {
ui_draw_string(win, 10, 36, "", COLOR_DARK_TEXT); ui_draw_string(win, 10, 6, "", COLOR_DARK_TEXT);
} }
// Draw grid // Draw grid
int grid_start_x = 10; int grid_start_x = 10;
int grid_start_y = 56; int grid_start_y = 26;
for (int y = 0; y < GRID_HEIGHT; y++) { for (int y = 0; y < GRID_HEIGHT; y++) {
for (int x = 0; x < GRID_WIDTH; x++) { for (int x = 0; x < GRID_WIDTH; x++) {
@ -196,7 +191,7 @@ static void minesweeper_paint(ui_window_t win) {
static void minesweeper_handle_click(ui_window_t win, int x, int y, int button) { static void minesweeper_handle_click(ui_window_t win, int x, int y, int button) {
int grid_start_x = 10; int grid_start_x = 10;
int grid_start_y = 56; int grid_start_y = 26;
int btn_y = grid_start_y + GRID_HEIGHT * CELL_SIZE + 10; int btn_y = grid_start_y + GRID_HEIGHT * CELL_SIZE + 10;
// Check "New Game" button // Check "New Game" button
@ -231,7 +226,6 @@ int main(int argc, char **argv) {
ui_window_t win = ui_window_create("Minesweeper", 250, 100, 240, 340); ui_window_t win = ui_window_create("Minesweeper", 250, 100, 240, 340);
if (!win) return 1; if (!win) return 1;
// Use current time or something for seed? No syscall for time right now.
random_seed = 987654321; random_seed = 987654321;
init_game(); init_game();
@ -240,17 +234,17 @@ int main(int argc, char **argv) {
if (ui_get_event(win, &ev)) { if (ui_get_event(win, &ev)) {
if (ev.type == GUI_EVENT_PAINT) { if (ev.type == GUI_EVENT_PAINT) {
minesweeper_paint(win); minesweeper_paint(win);
ui_mark_dirty(win, 0, 0, 240, 340); ui_mark_dirty(win, 0, 0, 240, 320);
} else if (ev.type == GUI_EVENT_CLICK) { } else if (ev.type == GUI_EVENT_CLICK) {
debug_print("[MINESWEEPER] LEFT CLICK"); debug_print("[MINESWEEPER] LEFT CLICK");
minesweeper_handle_click(win, ev.arg1, ev.arg2, ev.type); minesweeper_handle_click(win, ev.arg1, ev.arg2, ev.type);
minesweeper_paint(win); minesweeper_paint(win);
ui_mark_dirty(win, 0, 0, 240, 340); ui_mark_dirty(win, 0, 0, 240, 320);
} else if (ev.type == GUI_EVENT_RIGHT_CLICK) { } else if (ev.type == GUI_EVENT_RIGHT_CLICK) {
debug_print("[MINESWEEPER] RIGHT CLICK DETECTED"); debug_print("[MINESWEEPER] RIGHT CLICK DETECTED");
minesweeper_handle_click(win, ev.arg1, ev.arg2, ev.type); minesweeper_handle_click(win, ev.arg1, ev.arg2, ev.type);
minesweeper_paint(win); minesweeper_paint(win);
ui_mark_dirty(win, 0, 0, 240, 340); ui_mark_dirty(win, 0, 0, 240, 320);
} else if (ev.type == GUI_EVENT_CLOSE) { } else if (ev.type == GUI_EVENT_CLOSE) {
sys_exit(0); sys_exit(0);
} }

Binary file not shown.

View file

@ -241,8 +241,7 @@ int main(int argc, char **argv) {
sys_exit(0); sys_exit(0);
} }
} else { } else {
// Optional: sys_yield() or similar to avoid high CPU
// For now, just keep looping but it's better than nothing
for(volatile int i=0; i<10000; i++); for(volatile int i=0; i<10000; i++);
} }
} }

Binary file not shown.

View file

@ -50,24 +50,17 @@ static void paint_reset(void) {
static void paint_paint(ui_window_t win) { static void paint_paint(ui_window_t win) {
int canvas_x = 60; int canvas_x = 60;
int canvas_y = 30; int canvas_y = 0;
// Canvas Area with dark background and rounded corners (draw first so it's behind everything)
ui_draw_rounded_rect_filled(win, canvas_x - 2, canvas_y - 2, CANVAS_W + 4, CANVAS_H + 4, 4, COLOR_DARK_BG); ui_draw_rounded_rect_filled(win, canvas_x - 2, canvas_y - 2, CANVAS_W + 4, CANVAS_H + 4, 4, COLOR_DARK_BG);
ui_draw_rounded_rect_filled(win, 10, 0, 40, 230, 6, COLOR_DARK_PANEL);
// Toolbar area - dark mode
ui_draw_rounded_rect_filled(win, 10, 30, 40, 260 - 40, 6, COLOR_DARK_PANEL);
// Color Palette with rounded corners
uint32_t colors[] = {COLOR_BLACK, COLOR_RED, COLOR_APPLE_GREEN, COLOR_APPLE_BLUE, COLOR_APPLE_YELLOW, COLOR_WHITE}; uint32_t colors[] = {COLOR_BLACK, COLOR_RED, COLOR_APPLE_GREEN, COLOR_APPLE_BLUE, COLOR_APPLE_YELLOW, COLOR_WHITE};
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
int cy = 40 + (i * 25); int cy = 10 + (i * 25);
ui_draw_rounded_rect_filled(win, 15, cy, 30, 20, 3, colors[i]); ui_draw_rounded_rect_filled(win, 15, cy, 30, 20, 3, colors[i]);
// Highlight selected color with border
if (current_color == colors[i]) { if (current_color == colors[i]) {
// Note: libui might not have draw_rounded_rect (hollow), so we just draw four lines simulating it
// or we use ui_draw_rect for hollow border
ui_draw_rect(win, 13, cy - 2, 34, 1, COLOR_DARK_TEXT); ui_draw_rect(win, 13, cy - 2, 34, 1, COLOR_DARK_TEXT);
ui_draw_rect(win, 13, cy - 2 + 24, 34, 1, COLOR_DARK_TEXT); ui_draw_rect(win, 13, cy - 2 + 24, 34, 1, COLOR_DARK_TEXT);
ui_draw_rect(win, 13, cy - 2, 1, 24, COLOR_DARK_TEXT); ui_draw_rect(win, 13, cy - 2, 1, 24, COLOR_DARK_TEXT);
@ -75,12 +68,11 @@ static void paint_paint(ui_window_t win) {
} }
} }
// Toolbar Buttons - dark mode with rounded corners ui_draw_rounded_rect_filled(win, 12, 230 - 65, 36, 20, 4, COLOR_DARK_BORDER);
ui_draw_rounded_rect_filled(win, 12, 260 - 65, 36, 20, 4, COLOR_DARK_BORDER); ui_draw_string(win, 18, 230 - 58, "CLR", COLOR_DARK_TEXT);
ui_draw_string(win, 18, 260 - 58, "CLR", COLOR_DARK_TEXT);
ui_draw_rounded_rect_filled(win, 12, 260 - 40, 36, 20, 4, COLOR_DARK_BORDER); ui_draw_rounded_rect_filled(win, 12, 230 - 40, 36, 20, 4, COLOR_DARK_BORDER);
ui_draw_string(win, 18, 260 - 33, "SAV", COLOR_DARK_TEXT); ui_draw_string(win, 18, 230 - 33, "SAV", COLOR_DARK_TEXT);
// Draw canvas content // Draw canvas content
if (canvas_buffer) { if (canvas_buffer) {
@ -93,7 +85,7 @@ static void paint_paint(ui_window_t win) {
} }
} }
static void paint_put_brush(ui_window_t win, int cx, int cy) { static void paint_put_brush(ui_window_t win, int cx, int cy, int *min_x, int *min_y, int *max_x, int *max_y) {
if (!canvas_buffer) return; if (!canvas_buffer) return;
for (int dy = 0; dy < 2; dy++) { for (int dy = 0; dy < 2; dy++) {
for (int dx = 0; dx < 2; dx++) { for (int dx = 0; dx < 2; dx++) {
@ -101,26 +93,32 @@ static void paint_put_brush(ui_window_t win, int cx, int cy) {
int py = cy + dy; int py = cy + dy;
if (px >= 0 && px < CANVAS_W && py >= 0 && py < CANVAS_H) { if (px >= 0 && px < CANVAS_W && py >= 0 && py < CANVAS_H) {
canvas_buffer[py * CANVAS_W + px] = current_color; canvas_buffer[py * CANVAS_W + px] = current_color;
ui_draw_rect(win, 60 + px, 30 + py, 1, 1, current_color); ui_draw_rect(win, 60 + px, 0 + py, 1, 1, current_color);
if (px < *min_x) *min_x = px;
if (py < *min_y) *min_y = py;
if (px > *max_x) *max_x = px;
if (py > *max_y) *max_y = py;
} }
} }
} }
ui_mark_dirty(win, 60 + cx, 30 + cy, 2, 2);
} }
void paint_handle_mouse(ui_window_t win, int x, int y) { void paint_handle_mouse(ui_window_t win, int x, int y) {
int cx = x - 60; int cx = x - 60;
int cy = y - 30; int cy = y;
if (cx < 0 || cx >= CANVAS_W || cy < 0 || cy >= CANVAS_H) { if (cx < 0 || cx >= CANVAS_W || cy < 0 || cy >= CANVAS_H) {
last_mx = -1; last_mx = -1;
return; return;
} }
int min_x = CANVAS_W, min_y = CANVAS_H;
int max_x = -1, max_y = -1;
if (last_mx == -1) { if (last_mx == -1) {
paint_put_brush(win, cx, cy); paint_put_brush(win, cx, cy, &min_x, &min_y, &max_x, &max_y);
} else { } else {
// Bresenham's line algorithm to fill gaps between points
int x0 = last_mx, y0 = last_my; int x0 = last_mx, y0 = last_my;
int x1 = cx, y1 = cy; int x1 = cx, y1 = cy;
int dx = (x1 - x0 > 0) ? (x1 - x0) : (x0 - x1); int dx = (x1 - x0 > 0) ? (x1 - x0) : (x0 - x1);
@ -130,13 +128,18 @@ void paint_handle_mouse(ui_window_t win, int x, int y) {
int err = dx - dy; int err = dx - dy;
while (1) { while (1) {
paint_put_brush(win, x0, y0); paint_put_brush(win, x0, y0, &min_x, &min_y, &max_x, &max_y);
if (x0 == x1 && y0 == y1) break; if (x0 == x1 && y0 == y1) break;
int e2 = 2 * err; int e2 = 2 * err;
if (e2 > -dy) { err -= dy; x0 += sx; } if (e2 > -dy) { err -= dy; x0 += sx; }
if (e2 < dx) { err += dx; y0 += sy; } if (e2 < dx) { err += dx; y0 += sy; }
} }
} }
if (min_x <= max_x && min_y <= max_y) {
ui_mark_dirty(win, 60 + min_x, 0 + min_y, (max_x - min_x) + 1, (max_y - min_y) + 1);
}
last_mx = cx; last_mx = cx;
last_my = cy; last_my = cy;
} }
@ -146,11 +149,9 @@ void paint_reset_last_pos(void) {
last_my = -1; last_my = -1;
} }
// Simple window message dialog wrapper using syscall
static void wm_show_message(const char *title, const char *msg) { static void wm_show_message(const char *title, const char *msg) {
// Wait, userland doesn't have wm_show_message syscall available yet, or maybe it does?
// We didn't add it or GUI_EVENT doesn't support it directly.
// For now we do nothing, or just open a small window.
} }
static void paint_save(const char *path) { static void paint_save(const char *path) {
@ -181,13 +182,13 @@ void paint_load(const char *path) {
static void paint_click(ui_window_t win, int x, int y) { static void paint_click(ui_window_t win, int x, int y) {
// Check Buttons // Check Buttons
if (x >= 12 && x < 48) { if (x >= 12 && x < 48) {
if (y >= 260 - 65 && y < 260 - 45) { if (y >= 230 - 65 && y < 230 - 45) {
paint_reset(); paint_reset();
paint_paint(win); paint_paint(win);
ui_mark_dirty(win, 0, 0, 380, 260); ui_mark_dirty(win, 0, 0, 380, 230);
return; return;
} }
if (y >= 260 - 40 && y < 260 - 20) { if (y >= 230 - 40 && y < 230 - 20) {
paint_save(current_file_path); paint_save(current_file_path);
return; return;
} }
@ -196,12 +197,12 @@ static void paint_click(ui_window_t win, int x, int y) {
// Check Palette // Check Palette
if (x >= 15 && x < 45) { if (x >= 15 && x < 45) {
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
int cy = 40 + (i * 25); int cy = 10 + (i * 25);
if (y >= cy && y < cy + 20) { if (y >= cy && y < cy + 20) {
uint32_t colors[] = {COLOR_BLACK, COLOR_RED, COLOR_APPLE_GREEN, COLOR_APPLE_BLUE, COLOR_APPLE_YELLOW, COLOR_WHITE}; uint32_t colors[] = {COLOR_BLACK, COLOR_RED, COLOR_APPLE_GREEN, COLOR_APPLE_BLUE, COLOR_APPLE_YELLOW, COLOR_WHITE};
current_color = colors[i]; current_color = colors[i];
paint_paint(win); paint_paint(win);
ui_mark_dirty(win, 0, 0, 380, 260); ui_mark_dirty(win, 0, 0, 380, 230);
return; return;
} }
} }
@ -227,11 +228,9 @@ int main(int argc, char **argv) {
if (ui_get_event(win, &ev)) { if (ui_get_event(win, &ev)) {
if (ev.type == GUI_EVENT_PAINT) { if (ev.type == GUI_EVENT_PAINT) {
paint_paint(win); paint_paint(win);
ui_mark_dirty(win, 0, 0, 380, 260); ui_mark_dirty(win, 0, 0, 380, 240);
} else if (ev.type == GUI_EVENT_CLICK) { } else if (ev.type == GUI_EVENT_CLICK) {
paint_click(win, ev.arg1, ev.arg2); paint_click(win, ev.arg1, ev.arg2);
paint_paint(win);
ui_mark_dirty(win, 0, 0, 380, 260);
} else if (ev.type == GUI_EVENT_MOUSE_DOWN) { } else if (ev.type == GUI_EVENT_MOUSE_DOWN) {
paint_handle_mouse(win, ev.arg1, ev.arg2); paint_handle_mouse(win, ev.arg1, ev.arg2);
} else if (ev.type == GUI_EVENT_MOUSE_UP) { } else if (ev.type == GUI_EVENT_MOUSE_UP) {

Binary file not shown.

View file

@ -689,3 +689,4 @@ int main(int argc, char **argv) {
} }
return 0; return 0;
} }

Binary file not shown.

View file

@ -197,7 +197,7 @@ static void editor_insert_char(char ch) {
static void editor_paint(ui_window_t win) { static void editor_paint(ui_window_t win) {
int offset_x = 4; int offset_x = 4;
int offset_y = 24; int offset_y = 0;
int content_width = win_w - 8; int content_width = win_w - 8;
int content_height = win_h - 28; int content_height = win_h - 28;
@ -390,7 +390,7 @@ static void editor_handle_key(char c) {
static void editor_handle_click(int x, int y) { static void editor_handle_click(int x, int y) {
int content_width = win_w - 8; int content_width = win_w - 8;
int button_x = 4 + content_width - 80; int button_x = 4 + content_width - 80;
int button_y = 24 + 3; int button_y = 3;
if (x >= button_x && x < button_x + 70 && y >= button_y && y < button_y + 20) { if (x >= button_x && x < button_x + 70 && y >= button_y && y < button_y + 20) {
editor_save_file(); editor_save_file();
@ -413,15 +413,15 @@ int main(int argc, char **argv) {
if (ui_get_event(win, &ev)) { if (ui_get_event(win, &ev)) {
if (ev.type == GUI_EVENT_PAINT) { if (ev.type == GUI_EVENT_PAINT) {
editor_paint(win); editor_paint(win);
ui_mark_dirty(win, 0, 0, win_w, win_h); ui_mark_dirty(win, 0, 0, win_w, win_h - 20);
} else if (ev.type == GUI_EVENT_CLICK) { } else if (ev.type == GUI_EVENT_CLICK) {
editor_handle_click(ev.arg1, ev.arg2); editor_handle_click(ev.arg1, ev.arg2);
editor_paint(win); editor_paint(win);
ui_mark_dirty(win, 0, 0, win_w, win_h); ui_mark_dirty(win, 0, 0, win_w, win_h - 20);
} else if (ev.type == GUI_EVENT_KEY) { } else if (ev.type == GUI_EVENT_KEY) {
editor_handle_key((char)ev.arg1); editor_handle_key((char)ev.arg1);
editor_paint(win); editor_paint(win);
ui_mark_dirty(win, 0, 0, win_w, win_h); ui_mark_dirty(win, 0, 0, win_w, win_h - 20);
} else if (ev.type == GUI_EVENT_CLOSE) { } else if (ev.type == GUI_EVENT_CLOSE) {
sys_exit(0); sys_exit(0);
} }

Binary file not shown.

View file

@ -49,7 +49,7 @@ static void viewer_scale_rgb_to_argb(const unsigned char *rgb, int src_w, int sr
static void viewer_paint(ui_window_t win) { static void viewer_paint(ui_window_t win) {
int cx = 4; int cx = 4;
int cy = 24; int cy = 0;
int cw = win_w - 8; int cw = win_w - 8;
int ch = win_h - 28; int ch = win_h - 28;
@ -75,21 +75,25 @@ static void viewer_paint(ui_window_t win) {
int ox = cx + (cw - disp_w) / 2; int ox = cx + (cw - disp_w) / 2;
int oy = cy + (ch - disp_h - 30) / 2; int oy = cy + (ch - disp_h - 30) / 2;
for (int y = 0; y < disp_h; y++) { uint32_t *temp_buf = malloc(disp_w * disp_h * sizeof(uint32_t));
int src_y = y * viewer_img_h / disp_h; if (temp_buf) {
if (src_y >= viewer_img_h) src_y = viewer_img_h - 1; for (int y = 0; y < disp_h; y++) {
for (int x = 0; x < disp_w; x++) { int src_y = y * viewer_img_h / disp_h;
int src_x = x * viewer_img_w / disp_w; if (src_y >= viewer_img_h) src_y = viewer_img_h - 1;
if (src_x >= viewer_img_w) src_x = viewer_img_w - 1; for (int x = 0; x < disp_w; x++) {
uint32_t pixel = viewer_pixels[src_y * viewer_img_w + src_x]; int src_x = x * viewer_img_w / disp_w;
ui_draw_rect(win, ox + x, oy + y, 1, 1, pixel); if (src_x >= viewer_img_w) src_x = viewer_img_w - 1;
temp_buf[y * disp_w + x] = viewer_pixels[src_y * viewer_img_w + src_x];
}
} }
ui_draw_image(win, ox, oy, disp_w, disp_h, temp_buf);
free(temp_buf);
} }
int btn_w = 160; int btn_w = 160;
int btn_h = 22; int btn_h = 22;
int btn_x = cx + (cw - btn_w) / 2; int btn_x = cx + (cw - btn_w) / 2;
int btn_y = win_h - 30; int btn_y = (win_h - 20) - 30;
ui_draw_rounded_rect_filled(win, btn_x, btn_y, btn_w, btn_h, 6, 0xFF2D2D2D); ui_draw_rounded_rect_filled(win, btn_x, btn_y, btn_w, btn_h, 6, 0xFF2D2D2D);
ui_draw_string(win, btn_x + 10, btn_y + 6, "Set as Wallpaper", 0xFFF0F0F0); ui_draw_string(win, btn_x + 10, btn_y + 6, "Set as Wallpaper", 0xFFF0F0F0);
} }
@ -101,7 +105,7 @@ static void viewer_handle_click(ui_window_t win, int x, int y) {
int cw = win_w - 8; int cw = win_w - 8;
int btn_w = 160; int btn_w = 160;
int btn_x = cx + (cw - btn_w) / 2; int btn_x = cx + (cw - btn_w) / 2;
int btn_y = win_h - 30; int btn_y = (win_h - 20) - 30;
if (x >= btn_x && x < btn_x + btn_w && y >= btn_y && y < btn_y + 22) { if (x >= btn_x && x < btn_x + btn_w && y >= btn_y && y < btn_y + 22) {
// SYSTEM_CMD_SET_WALLPAPER is 3 based on syscall.c code // SYSTEM_CMD_SET_WALLPAPER is 3 based on syscall.c code
@ -214,7 +218,7 @@ int main(int argc, char **argv) {
if (ui_get_event(win, &ev)) { if (ui_get_event(win, &ev)) {
if (ev.type == GUI_EVENT_PAINT) { if (ev.type == GUI_EVENT_PAINT) {
viewer_paint(win); viewer_paint(win);
ui_mark_dirty(win, 0, 0, win_w, win_h); ui_mark_dirty(win, 0, 0, win_w, win_h - 20);
} else if (ev.type == GUI_EVENT_CLICK) { } else if (ev.type == GUI_EVENT_CLICK) {
viewer_handle_click(win, ev.arg1, ev.arg2); viewer_handle_click(win, ev.arg1, ev.arg2);
} else if (ev.type == GUI_EVENT_CLOSE) { } else if (ev.type == GUI_EVENT_CLOSE) {

Binary file not shown.

Binary file not shown.

View file

@ -1003,9 +1003,9 @@ void draw_window(Window *win) {
draw_rect(win->x, win->y + 20, win->w, 8, COLOR_DARK_BG); draw_rect(win->x, win->y + 20, win->w, 8, COLOR_DARK_BG);
if (win->comp_pixels) { if (win->comp_pixels) {
graphics_blit_buffer(win->comp_pixels, win->x, win->y, win->w, win->h); graphics_blit_buffer(win->comp_pixels, win->x, win->y + 20, win->w, win->h - 20);
} else if (win->pixels) { } else if (win->pixels) {
graphics_blit_buffer(win->pixels, win->x, win->y, win->w, win->h); graphics_blit_buffer(win->pixels, win->x, win->y + 20, win->w, win->h - 20);
} }
if (win->paint) { if (win->paint) {
@ -1051,12 +1051,9 @@ static void erase_cursor(int x, int y) {
int w = x2 - x1; int w = x2 - x1;
int h = y2 - y1; int h = y2 - y1;
// Check what's underneath the cursor and redraw it
if (y1 < sh - 28) { if (y1 < sh - 28) {
// Desktop or window area - draw teal background
draw_rect(x1, y1, w, h, COLOR_TEAL); draw_rect(x1, y1, w, h, COLOR_TEAL);
} else { } else {
// Taskbar
draw_rect(x1, y1, w, h, COLOR_GRAY); draw_rect(x1, y1, w, h, COLOR_GRAY);
} }
} }
@ -1068,7 +1065,6 @@ static uint8_t rtc_read(uint8_t reg) {
} }
static void draw_clock(int x, int y) { static void draw_clock(int x, int y) {
// Wait for update in progress
while (rtc_read(0x0A) & 0x80); while (rtc_read(0x0A) & 0x80);
uint8_t s = rtc_read(0x00); uint8_t s = rtc_read(0x00);
@ -1168,7 +1164,6 @@ void wm_paint(void) {
} }
} }
// Draw windows in z-order (lowest first)
for (int i = 0; i < window_count; i++) { for (int i = 0; i < window_count; i++) {
Window *win = sorted_windows[i]; Window *win = sorted_windows[i];
if (!win->visible) continue; if (!win->visible) continue;
@ -1182,16 +1177,10 @@ void wm_paint(void) {
draw_window(win); draw_window(win);
} }
// 4. Top Menu Bar
draw_rect(0, 0, sw, 30, COLOR_TOPBAR_BG); draw_rect(0, 0, sw, 30, COLOR_TOPBAR_BG);
// Logo dropdown (top-left)
draw_boredos_logo(8, 8, 1); draw_boredos_logo(8, 8, 1);
// Clock (top-right)
draw_clock(sw - 80, 12); draw_clock(sw - 80, 12);
// Top menu dropdown (if logo clicked)
if (start_menu_open) { if (start_menu_open) {
int menu_h = 85; int menu_h = 85;
draw_rounded_rect_filled(8, 40, 160, menu_h, 8, COLOR_DARK_PANEL); draw_rounded_rect_filled(8, 40, 160, menu_h, 8, COLOR_DARK_PANEL);
@ -1201,17 +1190,15 @@ void wm_paint(void) {
draw_string(20, 108, "Restart", COLOR_DARK_TEXT); draw_string(20, 108, "Restart", COLOR_DARK_TEXT);
} }
// 5. Dock (bottom - macOS style, floating with rounded corners)
int dock_h = 60; int dock_h = 60;
int dock_y = sh - dock_h - 6; // Float above bottom int dock_y = sh - dock_h - 6;
int dock_item_size = 48; int dock_item_size = 48;
int dock_spacing = 10; int dock_spacing = 10;
int total_dock_width = 7 * (dock_item_size + dock_spacing); int total_dock_width = 7 * (dock_item_size + dock_spacing);
int dock_bg_x = (sw - total_dock_width) / 2 - 12; // Rounded background extends beyond icons int dock_bg_x = (sw - total_dock_width) / 2 - 12;
int dock_bg_w = total_dock_width + 24; int dock_bg_w = total_dock_width + 24;
draw_rounded_rect_filled(dock_bg_x, dock_y, dock_bg_w, dock_h, 18, COLOR_DOCK_BG); draw_rounded_rect_filled(dock_bg_x, dock_y, dock_bg_w, dock_h, 18, COLOR_DOCK_BG);
// Draw dock apps (centered)
int dock_x = (sw - total_dock_width) / 2; int dock_x = (sw - total_dock_width) / 2;
int dock_item_y = dock_y + 6; int dock_item_y = dock_y + 6;
@ -1321,6 +1308,8 @@ bool rect_contains(int x, int y, int w, int h, int px, int py) {
} }
void wm_bring_to_front(Window *win) { void wm_bring_to_front(Window *win) {
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
// Clear focus from all windows // Clear focus from all windows
for (int i = 0; i < window_count; i++) { for (int i = 0; i < window_count; i++) {
all_windows[i]->focused = false; all_windows[i]->focused = false;
@ -1336,22 +1325,30 @@ void wm_bring_to_front(Window *win) {
win->focused = true; win->focused = true;
win->z_index = max_z + 1; win->z_index = max_z + 1;
force_redraw = true; force_redraw = true;
asm volatile("push %0; popfq" : : "r"(rflags));
} }
void wm_add_window(Window *win) { void wm_add_window(Window *win) {
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
if (window_count < 32) { if (window_count < 32) {
all_windows[window_count++] = win; all_windows[window_count++] = win;
wm_bring_to_front(win); // Ensure newly added windows are on top wm_bring_to_front(win); // Ensure newly added windows are on top
} }
asm volatile("push %0; popfq" : : "r"(rflags));
} }
Window* wm_find_window_by_title(const char *title) { Window* wm_find_window_by_title(const char *title) {
if (!title) return NULL; if (!title) return NULL;
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
for (int i = 0; i < window_count; i++) { for (int i = 0; i < window_count; i++) {
if (all_windows[i] && all_windows[i]->title && str_eq(all_windows[i]->title, title)) { if (all_windows[i] && all_windows[i]->title && str_eq(all_windows[i]->title, title)) {
asm volatile("push %0; popfq" : : "r"(rflags));
return all_windows[i]; return all_windows[i];
} }
} }
asm volatile("push %0; popfq" : : "r"(rflags));
return NULL; return NULL;
} }
@ -1363,6 +1360,9 @@ void wm_remove_window(Window *win) {
else serial_write("unknown"); else serial_write("unknown");
serial_write("'\n"); serial_write("'\n");
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
int index = -1; int index = -1;
for (int i = 0; i < window_count; i++) { for (int i = 0; i < window_count; i++) {
if (all_windows[i] == win) { if (all_windows[i] == win) {
@ -1378,22 +1378,22 @@ void wm_remove_window(Window *win) {
} }
window_count--; window_count--;
// Free resources // Mark for redraw while protected
if (win->pixels) kfree(win->pixels);
if (win->comp_pixels) kfree(win->comp_pixels);
// If the title was allocated in syscall.c, we should free it,
// but currently we don't know for sure if it was kmalloc'd or a literal.
// In syscall.c it is kmalloc'd. Let's assume we should free it if it's not a known literal.
// Safer to just free it since userland windows always have kmalloc'd titles.
if (win->title && win->handle_close) { // Heuristic: user windows have handle_close set in syscall.c
kfree(win->title);
}
kfree(win);
force_redraw = true; force_redraw = true;
} else { } else {
asm volatile("push %0; popfq" : : "r"(rflags));
serial_write("WM: Window not found in all_windows list!\n"); serial_write("WM: Window not found in all_windows list!\n");
return;
} }
if (win->pixels) kfree(win->pixels);
if (win->comp_pixels) kfree(win->comp_pixels);
if (win->title && win->handle_close) {
kfree(win->title);
}
kfree(win);
asm volatile("push %0; popfq" : : "r"(rflags));
} }
void wm_handle_click(int x, int y) { void wm_handle_click(int x, int y) {
@ -1614,7 +1614,7 @@ void wm_handle_click(int x, int y) {
} else { } else {
// Content click // Content click
if (topmost->handle_click) { if (topmost->handle_click) {
topmost->handle_click(topmost, x - topmost->x, y - topmost->y); topmost->handle_click(topmost, x - topmost->x, y - topmost->y - 20);
} }
} }
pending_desktop_icon_click = -1; pending_desktop_icon_click = -1;
@ -1665,10 +1665,10 @@ void wm_handle_right_click(int x, int y) {
// If a window was clicked // If a window was clicked
if (topmost != NULL) { if (topmost != NULL) {
// Don't process close button or title bar for right click // Don't process close button or title bar for right click
if (y >= topmost->y + 24) { if (y >= topmost->y + 20) {
// Content right click // Content right click
if (topmost->handle_right_click) { if (topmost->handle_right_click) {
topmost->handle_right_click(topmost, x - topmost->x, y - topmost->y); topmost->handle_right_click(topmost, x - topmost->x, y - topmost->y - 20);
} }
} }
} else { } else {
@ -1718,12 +1718,10 @@ void wm_handle_right_click(int x, int y) {
bool right = buttons & 0x02; bool right = buttons & 0x02;
if (left && !prev_left) { if (left && !prev_left) {
// Mouse Down
drag_start_x = mx; drag_start_x = mx;
drag_start_y = my; drag_start_y = my;
// Check Dock for app clicks (bottom of screen, floating)
int dock_h = 60; int dock_h = 60;
int dock_y = sh - dock_h - 6; // Float above bottom int dock_y = sh - dock_h - 6;
int dock_item_size = 48; int dock_item_size = 48;
int dock_spacing = 10; int dock_spacing = 10;
int total_dock_width = 7 * (dock_item_size + dock_spacing); int total_dock_width = 7 * (dock_item_size + dock_spacing);
@ -1778,8 +1776,6 @@ void wm_handle_right_click(int x, int y) {
start_menu_pending_app = NULL; start_menu_pending_app = NULL;
} }
// Mouse moving with left button, check for file drag start
// 1. Check Desktop Icons
if (pending_desktop_icon_click != -1) { if (pending_desktop_icon_click != -1) {
int i = pending_desktop_icon_click; int i = pending_desktop_icon_click;
DesktopIcon *icon = &desktop_icons[i]; DesktopIcon *icon = &desktop_icons[i];
@ -1953,7 +1949,6 @@ void wm_handle_right_click(int x, int y) {
if (is_dragging_file) { if (is_dragging_file) {
// Drop logic // Drop logic
// Check drop target - iterate through all windows to find if dropped on an Explorer
Window *drop_win = NULL; Window *drop_win = NULL;
int topmost_z = -1; int topmost_z = -1;
for (int w = 0; w < window_count; w++) { for (int w = 0; w < window_count; w++) {
@ -1983,11 +1978,8 @@ void wm_handle_right_click(int x, int y) {
} else { } else {
// Dropped on Desktop (or elsewhere) // Dropped on Desktop (or elsewhere)
if (drag_file_path[0] == ':' && drag_file_path[1] == ':' && drag_file_path[2] == 'A') { if (drag_file_path[0] == ':' && drag_file_path[1] == ':' && drag_file_path[2] == 'A') {
// Dropped Start Menu App -> Create Shortcut create_desktop_shortcut(drag_file_path + 7);
create_desktop_shortcut(drag_file_path + 7); // Skip ::APP::
} else { } else {
// If source was NOT desktop, move to desktop
// Check if path starts with /Desktop/
bool from_desktop = (drag_file_path[0]=='/' && drag_file_path[1]=='D' && drag_file_path[2]=='e'); bool from_desktop = (drag_file_path[0]=='/' && drag_file_path[1]=='D' && drag_file_path[2]=='e');
bool dropped_on_target = false; bool dropped_on_target = false;
for (int i = 0; i < desktop_icon_count; i++) { for (int i = 0; i < desktop_icon_count; i++) {
@ -2076,8 +2068,6 @@ void wm_handle_right_click(int x, int y) {
} }
} }
} else if (!dropped_on_target) { } else if (!dropped_on_target) {
// Moved within desktop
// Find which icon was dragged
int dragged_idx = -1; int dragged_idx = -1;
for(int i=0; i<desktop_icon_count; i++) { for(int i=0; i<desktop_icon_count; i++) {
char path[128] = "/Desktop/"; char path[128] = "/Desktop/";
@ -2129,11 +2119,8 @@ void wm_handle_right_click(int x, int y) {
desktop_icons[dragged_idx].y = 20 + row * 80; desktop_icons[dragged_idx].y = 20 + row * 80;
} }
// Check for collision with other icons
// Folders already checked above, this is for overlap prevention
for (int i = 0; i < desktop_icon_count; i++) { for (int i = 0; i < desktop_icon_count; i++) {
if (i == dragged_idx) continue; if (i == dragged_idx) continue;
// Simple distance check or rect overlap
int dx = desktop_icons[i].x - desktop_icons[dragged_idx].x; int dx = desktop_icons[i].x - desktop_icons[dragged_idx].x;
int dy = desktop_icons[i].y - desktop_icons[dragged_idx].y; int dy = desktop_icons[i].y - desktop_icons[dragged_idx].y;
if (dx < 0) dx = -dx; if (dx < 0) dx = -dx;
@ -2174,7 +2161,8 @@ void wm_handle_right_click(int x, int y) {
} }
} }
if (topmost && topmost->data) { if (topmost && topmost->data) {
syscall_send_mouse_down_event(topmost, mx - topmost->x, my - topmost->y); if (my >= topmost->y + 20)
syscall_send_mouse_down_event(topmost, mx - topmost->x, my - topmost->y - 20);
} }
} }
@ -2192,7 +2180,8 @@ void wm_handle_right_click(int x, int y) {
} }
} }
if (topmost && topmost->data) { if (topmost && topmost->data) {
syscall_send_mouse_up_event(topmost, mx - topmost->x, my - topmost->y); if (my >= topmost->y + 20)
syscall_send_mouse_up_event(topmost, mx - topmost->x, my - topmost->y - 20);
} }
} }
@ -2210,7 +2199,8 @@ void wm_handle_right_click(int x, int y) {
} }
} }
if (topmost && topmost->data) { if (topmost && topmost->data) {
syscall_send_mouse_move_event(topmost, mx - topmost->x, my - topmost->y, buttons); if (my >= topmost->y + 20)
syscall_send_mouse_move_event(topmost, mx - topmost->x, my - topmost->y - 20, buttons);
} }
} }
@ -2346,12 +2336,10 @@ void wm_init(void) {
all_windows[2] = &win_about; all_windows[2] = &win_about;
window_count = 3; window_count = 3;
// Only show Explorer on desktop (initially hidden)
win_explorer.visible = false; win_explorer.visible = false;
win_explorer.focused = false; win_explorer.focused = false;
win_explorer.z_index = 10; win_explorer.z_index = 10;
// Rest are hidden initially
win_cmd.visible = false; win_cmd.visible = false;
win_about.visible = false; win_about.visible = false;
@ -2366,8 +2354,6 @@ uint32_t wm_get_ticks(void) {
void wm_timer_tick(void) { void wm_timer_tick(void) {
timer_ticks++; timer_ticks++;
// Auto-refresh desktop every 5 seconds to save CPU in QEMU
// But NOT if the user is dragging a window or file.
if (!is_dragging && !is_dragging_file) { if (!is_dragging && !is_dragging_file) {
desktop_refresh_timer++; desktop_refresh_timer++;
if (desktop_refresh_timer >= 300) { if (desktop_refresh_timer >= 300) {
@ -2378,8 +2364,7 @@ void wm_timer_tick(void) {
} }
} }
// Only redraw if there are dirty areas (clock updates at most every second, cursor rarely moves in timer only)
// Most of the time, nothing changes between ticks
static uint8_t last_second = 0xFF; static uint8_t last_second = 0xFF;
@ -2389,17 +2374,14 @@ void wm_timer_tick(void) {
if (current_sec != last_second) { if (current_sec != last_second) {
last_second = current_sec; last_second = current_sec;
int sw = get_screen_width(); int sw = get_screen_width();
// Mark clock area in the top menu bar (around draw_clock at sw - 80, y=12)
wm_mark_dirty(sw - 110, 6, 110, 24); wm_mark_dirty(sw - 110, 6, 110, 24);
} }
// If force_redraw is set, do a full redraw
if (force_redraw) { if (force_redraw) {
graphics_mark_screen_dirty(); graphics_mark_screen_dirty();
force_redraw = false; force_redraw = false;
} }
// Perform redraw if there are dirty areas
DirtyRect dirty = graphics_get_dirty_rect(); DirtyRect dirty = graphics_get_dirty_rect();
if (dirty.active) { if (dirty.active) {
wm_paint(); wm_paint();

View file

@ -23,7 +23,6 @@
#define COLOR_APPLE_INDIGO 0xFF4B0082 #define COLOR_APPLE_INDIGO 0xFF4B0082
#define COLOR_APPLE_VIOLET 0xFF9400D3 #define COLOR_APPLE_VIOLET 0xFF9400D3
// --- Dark Mode Colors ---
#define COLOR_NOTEPAD_BG 0xFFF5F5DC #define COLOR_NOTEPAD_BG 0xFFF5F5DC
#define COLOR_DARK_BG 0xFF1E1E1E // Main dark background #define COLOR_DARK_BG 0xFF1E1E1E // Main dark background
#define COLOR_DARK_PANEL 0xFF2D2D2D // Slightly lighter panel background #define COLOR_DARK_PANEL 0xFF2D2D2D // Slightly lighter panel background
@ -36,7 +35,7 @@
#define COLOR_TRAFFIC_YELLOW 0xFFFCC02E // Minimize button (not used for now) #define COLOR_TRAFFIC_YELLOW 0xFFFCC02E // Minimize button (not used for now)
#define COLOR_TRAFFIC_GREEN 0xFF5FC038 // Zoom button (not used for now) #define COLOR_TRAFFIC_GREEN 0xFF5FC038 // Zoom button (not used for now)
#define DESKTOP_TOP_DEADSPACE_HEIGHT 80 // Height of the dead space at the top of the desktop grid #define DESKTOP_TOP_DEADSPACE_HEIGHT 80 // stops files from being rendered under menu bar
typedef struct Window Window; typedef struct Window Window;
struct Window { struct Window {
char *title; char *title;
@ -46,10 +45,10 @@ struct Window {
int buf_len; int buf_len;
int cursor_pos; int cursor_pos;
bool focused; bool focused;
int z_index; // Layering depth (higher = on top) int z_index;
void *data; // Per-window private data void *data;
uint32_t *pixels; // Pointer to backing buffer for UI events (Back Buffer) uint32_t *pixels;
uint32_t *comp_pixels; // Pointer to composition buffer (Front Buffer) uint32_t *comp_pixels;
// Callbacks // Callbacks
void (*paint)(Window *win); void (*paint)(Window *win);
@ -88,7 +87,7 @@ void draw_bevel_rect(int x, int y, int w, int h, bool sunken);
void draw_button(int x, int y, int w, int h, const char *text, bool pressed); void draw_button(int x, int y, int w, int h, const char *text, bool pressed);
void draw_rounded_rect(int x, int y, int w, int h, int radius, uint32_t color); void draw_rounded_rect(int x, int y, int w, int h, int radius, uint32_t color);
void draw_rounded_rect_filled(int x, int y, int w, int h, int radius, uint32_t color); void draw_rounded_rect_filled(int x, int y, int w, int h, int radius, uint32_t color);
void draw_traffic_light(int x, int y); // Red close button only void draw_traffic_light(int x, int y);
void draw_icon(int x, int y, const char *label); void draw_icon(int x, int y, const char *label);
void draw_folder_icon(int x, int y, const char *label); void draw_folder_icon(int x, int y, const char *label);
void draw_document_icon(int x, int y, const char *label); void draw_document_icon(int x, int y, const char *label);