9 Commits

Author SHA1 Message Date
boreddevnl
7b7f134e27 feat: centralize OS version info in kernel syscall 2026-03-17 16:06:00 +01:00
boreddevnl
0491c4ad0f TWEAK: change version number for V1.72 and 3.1.2 2026-03-17 15:50:25 +01:00
boreddevnl
c6fe9971d8 BFIX: export bugs in word.c and fixed explorer always ZTop in wm 2026-03-17 15:48:42 +01:00
boreddevnl
88f178e368 checkpoint: BoredWord application 2026-03-17 14:41:13 +01:00
boreddevnl
d824b4610a FIX: Replace blocking k_beep with an asynchronous k_beep 2026-03-16 17:22:42 +01:00
boreddevnl
a4f16b0604 RM: remove broken file artifact 2026-03-16 17:19:06 +01:00
boreddevnl
83413fdd2b fix: Broken script in documentation 2026-03-16 17:16:20 +01:00
boreddevnl
2a918bc7ba Tweak: Updatedscreenshot.jpg and fixed boredos.svg alignment 2026-03-16 15:59:37 +01:00
boreddevnl
2624b4f8df update LICENSE 2026-03-16 15:21:17 +01:00
26 changed files with 2644 additions and 103 deletions

View File

@@ -3,7 +3,7 @@
Copyright(C) Chris (boreddevnl) 2024-2026
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/\>
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

View File

@@ -1,4 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 130" width="100%">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 415 130" width="100%">
<style>
text {
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
disk.img

Binary file not shown.

View File

@@ -13,30 +13,31 @@ Applications reside entirely in the `src/userland/` directory. Create a new file
// src/userland/gui/hello.c
#include <stdlib.h>
#include <libui.h>
#include <syscall.h>
int main(void) {
// Attempt to open a 300x200 window
int wid = ui_create_window("My Custom App", 300, 200, 0);
ui_window_t wid = ui_window_create("My Custom App", 100, 100, 300, 200);
if (wid < 0) {
printf("Error creating window!\n");
return 1;
}
// Write text in center
ui_draw_string(wid, "Hello, BoredOS!!", 50, 90, 0xFFFFFFFF);
ui_draw_string(wid, 50, 90, "Hello, BoredOS!!", 0xFFFFFFFF);
// Commit drawing to screen
ui_swap_buffers(wid);
ui_mark_dirty(wid, 0, 0, 300, 200);
ui_event_t event;
gui_event_t event;
while (1) {
if (ui_poll_event(&event)) {
if (event.window_id == wid && event.type == UI_EVENT_WINDOW_CLOSE) {
if (ui_get_event(wid, &event)) {
if (event.type == GUI_EVENT_CLOSE) {
break; // Exit loop if 'X' is clicked
}
}
syscall1(SYSTEM_CMD_YIELD, 0);
sys_yield();
}
return 0; // Returning 0 smoothly exits the process via crt0.asm

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 KiB

After

Width:  |  Height:  |  Size: 342 KiB

View File

@@ -113,14 +113,35 @@ void k_shutdown(void) {
outw(0x4004, 0x3400); // VirtualBox fallback
}
volatile uint64_t beep_end_tick = 0;
bool beep_active = false;
void k_beep(int freq, int ms) {
if (freq <= 0) return;
if (freq <= 0) {
outb(0x61, inb(0x61) & 0xFC);
beep_active = false;
return;
}
int div = 1193180 / freq;
outb(0x43, 0xB6);
outb(0x42, div & 0xFF);
outb(0x42, (div >> 8) & 0xFF);
outb(0x61, inb(0x61) | 0x03);
k_sleep(ms);
outb(0x61, inb(0x61) & 0xFC);
uint32_t ticks = ms / 16;
if (ticks == 0 && ms > 0) ticks = 1;
extern volatile uint64_t kernel_ticks;
beep_end_tick = kernel_ticks + ticks;
beep_active = true;
}
void k_beep_process(void) {
if (beep_active) {
extern volatile uint64_t kernel_ticks;
if (kernel_ticks >= beep_end_tick) {
outb(0x61, inb(0x61) & 0xFC);
beep_active = false;
}
}
}

View File

@@ -6,6 +6,7 @@
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
// Kernel string utilities
void k_memset(void *dest, int val, size_t len);
@@ -23,5 +24,6 @@ void k_sleep(int ms);
void k_reboot(void);
void k_shutdown(void);
void k_beep(int freq, int ms);
void k_beep_process(void);
#endif

33
src/core/version.c Normal file
View File

@@ -0,0 +1,33 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it is present in, as per the GPL license terms.
#include "syscall.h"
#include <stddef.h>
extern void mem_memcpy(void *dest, const void *src, size_t len);
void get_os_info(os_info_t *info) {
if (!info) return;
char *p = (char *)info;
for (size_t i = 0; i < sizeof(os_info_t); i++) p[i] = 0;
const char *os_name = "BoredOS";
const char *os_version = "1.72";
const char *os_codename = "Retrowave";
const char *kernel_name = "Boredkernel";
const char *kernel_version = "3.1.2";
const char *build_date = __DATE__;
const char *build_time = __TIME__;
const char *build_arch = "x86_64";
int j;
j = 0; while (os_name[j] && j < 63) { info->os_name[j] = os_name[j]; j++; } info->os_name[j] = '\0';
j = 0; while (os_version[j] && j < 63) { info->os_version[j] = os_version[j]; j++; } info->os_version[j] = '\0';
j = 0; while (os_codename[j] && j < 63) { info->os_codename[j] = os_codename[j]; j++; } info->os_codename[j] = '\0';
j = 0; while (kernel_name[j] && j < 63) { info->kernel_name[j] = kernel_name[j]; j++; } info->kernel_name[j] = '\0';
j = 0; while (kernel_version[j] && j < 63) { info->kernel_version[j] = kernel_version[j]; j++; } info->kernel_version[j] = '\0';
j = 0; while (build_date[j] && j < 63) { info->build_date[j] = build_date[j]; j++; } info->build_date[j] = '\0';
j = 0; while (build_time[j] && j < 63) { info->build_time[j] = build_time[j]; j++; } info->build_time[j] = '\0';
j = 0; while (build_arch[j] && j < 63) { info->build_arch[j] = build_arch[j]; j++; } info->build_arch[j] = '\0';
}

View File

@@ -18,6 +18,9 @@ uint64_t timer_handler(registers_t *regs) {
wm_timer_tick();
network_process_frames();
extern void k_beep_process(void);
k_beep_process();
outb(0x20, 0x20); // EOI after processing to prevent nested timer interrupts
extern uint64_t process_schedule(uint64_t current_rsp);
return process_schedule((uint64_t)regs);

View File

@@ -497,6 +497,83 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
}
}
asm volatile("push %0; popfq" : : "r"(rflags));
}
} else if (cmd == 18) { // GUI_CMD_DRAW_STRING_SCALED_SLOPED
Window *win = (Window *)arg2;
uint64_t coords = arg3;
int ux = coords & 0xFFFFFFFF;
int uy = coords >> 32;
const char *user_str = (const char *)arg4;
// Unpack color, scale, slope from arg5
uint64_t packed1 = arg5;
uint32_t color = packed1 & 0xFFFFFFFF;
uint32_t scale_bits = packed1 >> 32;
float scale = *(float*)&scale_bits;
// Slope is passed via arg6 in the system call, but syscall5 only takes 5 args.
// Oh right, we only have syscall5. Let's make a packed struct or just use a generic pointer for coords.
// Even better, let's just make it a pointer to a struct.
// Wait, I will just use `regs->r9` (arg6) directly since the syscall handler has access to all registers:
uint64_t arg6 = regs->r9;
uint32_t slope_bits = arg6 & 0xFFFFFFFF;
float slope = *(float*)&slope_bits;
if (win && user_str) {
extern void draw_string_scaled_sloped(int x, int y, const char *str, uint32_t color, float scale, float slope);
extern void graphics_set_render_target(uint32_t *buffer, int w, int h);
// Copy string safely to kernel stack buffer
char kernel_str[256];
int i = 0;
while (i < 255 && user_str[i]) {
kernel_str[i] = user_str[i];
i++;
}
kernel_str[i] = 0;
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
ttf_font_t *font = win->font ? (ttf_font_t*)win->font : graphics_get_current_ttf();
if (win->pixels) {
if (ux >= -100 && ux < win->w && uy >= -100 && uy < (win->h - 20)) {
graphics_set_render_target(win->pixels, win->w, win->h - 20);
if (font) {
int baseline = uy + font_manager_get_font_ascent_scaled(font, scale) - 2;
int cur_x = ux;
const char *s = kernel_str;
while (*s) {
extern void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, char c, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t));
font_manager_render_char_sloped(font, cur_x, baseline, *s, color, scale, slope, put_pixel);
char buf[2] = {*s, 0};
cur_x += font_manager_get_string_width_scaled(font, buf, scale);
s++;
}
} else {
draw_string_scaled_sloped(ux, uy, kernel_str, color, scale, slope);
}
graphics_set_render_target(NULL, 0, 0);
}
} else {
if (font) {
int baseline = win->y + uy + font_manager_get_font_ascent_scaled(font, scale) - 2;
int cur_x = win->x + ux;
const char *s = kernel_str;
while (*s) {
extern void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, char c, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t));
font_manager_render_char_sloped(font, cur_x, baseline, *s, color, scale, slope, put_pixel);
char buf[2] = {*s, 0};
cur_x += font_manager_get_string_width_scaled(font, buf, scale);
s++;
}
} else {
draw_string_scaled_sloped(win->x + ux, win->y + uy, kernel_str, color, scale, slope);
}
}
asm volatile("push %0; popfq" : : "r"(rflags));
}
} else if (cmd == GUI_CMD_DRAW_IMAGE) {
@@ -929,16 +1006,8 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
} else if (cmd == 14) { // SYSTEM_CMD_BEEP
int freq = (int)arg2;
int ms = (int)arg3;
if (freq > 0) {
int div = 1193180 / freq;
outb(0x43, 0xB6);
outb(0x42, div & 0xFF);
outb(0x42, (div >> 8) & 0xFF);
outb(0x61, inb(0x61) | 0x03);
}
// Sleep - kernel side
k_sleep(ms);
outb(0x61, inb(0x61) & 0xFC);
extern void k_beep(int freq, int ms);
k_beep(freq, ms);
return 0;
} else if (cmd == 15) { // SYSTEM_CMD_MEMINFO
uint64_t *out = (uint64_t *)arg2;
@@ -1189,6 +1258,12 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
return 0;
}
return -1;
} else if (cmd == 49) { // SYSTEM_CMD_GET_OS_INFO
os_info_t *info = (os_info_t *)arg2;
if (!info) return -1;
extern void get_os_info(os_info_t *info);
get_os_info(info);
return 0;
}
return -1;
}

View File

@@ -10,6 +10,17 @@
typedef struct Window Window;
typedef struct registers_t registers_t;
typedef struct {
char os_name[64];
char os_version[64];
char os_codename[64];
char kernel_name[64];
char kernel_version[64];
char build_date[64];
char build_time[64];
char build_arch[64];
} os_info_t;
// MSRs used for syscalls in x86_64
#define MSR_EFER 0xC0000080
#define MSR_STAR 0xC0000081
@@ -46,6 +57,7 @@ typedef struct registers_t registers_t;
#define SYSTEM_CMD_GET_CPU_MODEL 45
#define SYSTEM_CMD_SLEEP 46
#define SYSTEM_CMD_SET_RESOLUTION 47
#define SYSTEM_CMD_GET_OS_INFO 49
void syscall_init(void);
uint64_t syscall_handler_c(registers_t *regs);

View File

@@ -237,13 +237,29 @@ int main(int argc, char **argv) {
if (config.separator[0]) {
strcpy(info_lines[info_line_count++], config.separator);
}
os_info_t os_info;
sys_get_os_info(&os_info);
if (config.os_label[0]) {
strcpy(info_lines[info_line_count], config.os_label);
strcat(info_lines[info_line_count++], ": BoredOS V1.71 'Retrowave'");
strcat(info_lines[info_line_count], ": ");
strcat(info_lines[info_line_count], os_info.os_name);
strcat(info_lines[info_line_count], " V");
strcat(info_lines[info_line_count], os_info.os_version);
strcat(info_lines[info_line_count], " '");
strcat(info_lines[info_line_count], os_info.os_codename);
strcat(info_lines[info_line_count], "'");
info_line_count++;
}
if (config.kernel_label[0]) {
strcpy(info_lines[info_line_count], config.kernel_label);
strcat(info_lines[info_line_count++], ": Boredkernel V3.1.1 x86_64");
strcat(info_lines[info_line_count], ": ");
strcat(info_lines[info_line_count], os_info.kernel_name);
strcat(info_lines[info_line_count], " V");
strcat(info_lines[info_line_count], os_info.kernel_version);
strcat(info_lines[info_line_count], " ");
strcat(info_lines[info_line_count], os_info.build_arch);
info_line_count++;
}
if (config.uptime_label[0]) {
uint64_t ticks = sys_system(16, 0, 0, 0, 0);

View File

@@ -84,10 +84,9 @@ static void draw_ascii_logo(ui_window_t win, int x, int y) {
}
static void about_paint(ui_window_t win) {
int w = 340;
int h = 240;
int w = 380;
int h = 260;
// Clear background to prevent alpha-blended text from accumulating on repaints
ui_draw_rect(win, 0, 0, w, h, 0xFF1E1E1E);
int offset_x = 15;
@@ -96,19 +95,51 @@ static void about_paint(ui_window_t win) {
draw_ascii_logo(win, 14, offset_y);
int fh = ui_get_font_height();
ui_draw_string(win, offset_x, offset_y + 105, "BoredOS 'Retrowave'", 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 105 + fh, "BoredOS Version 1.71", 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 105 + fh*2, "Kernel Version 3.1.1", 0xFFFFFFFF);
os_info_t os_info;
sys_get_os_info(&os_info);
char os_name_str[128];
os_name_str[0] = 0;
strcat(os_name_str, os_info.os_name);
strcat(os_name_str, " '");
strcat(os_name_str, os_info.os_codename);
strcat(os_name_str, "'");
char os_version_str[128];
os_version_str[0] = 0;
strcat(os_version_str, os_info.os_name);
strcat(os_version_str, " Version ");
strcat(os_version_str, os_info.os_version);
char kernel_version_str[128];
kernel_version_str[0] = 0;
strcat(kernel_version_str, os_info.kernel_name);
strcat(kernel_version_str, " Version ");
strcat(kernel_version_str, os_info.kernel_version);
strcat(kernel_version_str, " ");
strcat(kernel_version_str, os_info.build_arch);
char build_date_str[128];
build_date_str[0] = 0;
strcat(build_date_str, "Build Date: ");
strcat(build_date_str, os_info.build_date);
strcat(build_date_str, " ");
strcat(build_date_str, os_info.build_time);
ui_draw_string(win, offset_x, offset_y + 105, os_name_str, 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 105 + fh, os_version_str, 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 105 + fh*2, kernel_version_str, 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 105 + fh*3, build_date_str, 0xFFFFFFFF);
// Copyright
ui_draw_string(win, offset_x, offset_y + 105 + fh*3, "(C) 2026 boreddevnl.", 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 105 + fh*4, "All rights reserved.", 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 105 + fh*4, "(C) 2026 boreddevnl.", 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 105 + fh*5, "All rights reserved.", 0xFFFFFFFF);
ui_mark_dirty(win, 0, 0, w, h);
}
int main(void) {
ui_window_t win_about = ui_window_create("About BoredOS", 250, 180, 340, 240);
ui_window_t win_about = ui_window_create("About BoredOS", 250, 180, 380, 260);
about_paint(win_about);
@@ -121,7 +152,6 @@ int main(void) {
sys_exit(0);
}
} else {
// Avoid high CPU usage
sleep(10);
}
}

1986
src/userland/gui/word.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@
extern uint64_t syscall3(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3);
extern uint64_t syscall4(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4);
extern uint64_t syscall5(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5);
extern uint64_t syscall6(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6);
// sys_gui uses syscall #3
#define SYS_GUI 3
@@ -71,6 +72,16 @@ void ui_draw_string_scaled(ui_window_t win, int x, int y, const char *str, uint3
syscall5(SYS_GUI, GUI_CMD_DRAW_STRING_SCALED, (uint64_t)win, coords, (uint64_t)str, packed_arg5);
}
void ui_draw_string_scaled_sloped(ui_window_t win, int x, int y, const char *str, uint32_t color, float scale, float slope) {
uint64_t coords = ((uint64_t)x & 0xFFFFFFFF) | ((uint64_t)y << 32);
// Pack color into lower 32, scale (as uint32_t representation) into upper 32
uint32_t scale_bits = *(uint32_t*)&scale;
uint32_t slope_bits = *(uint32_t*)&slope;
uint64_t packed_arg5 = ((uint64_t)scale_bits << 32) | (color & 0xFFFFFFFF);
syscall6(SYS_GUI, GUI_CMD_DRAW_STRING_SCALED_SLOPED, (uint64_t)win, coords, (uint64_t)str, packed_arg5, (uint64_t)slope_bits);
}
uint32_t ui_get_string_width_scaled(const char *str, float scale) {
uint32_t scale_bits = *(uint32_t*)&scale;
return (uint32_t)syscall4(SYS_GUI, GUI_CMD_GET_STRING_WIDTH_SCALED, (uint64_t)str, (uint64_t)scale_bits, 0);

View File

@@ -21,6 +21,7 @@
#define GUI_CMD_GET_FONT_HEIGHT_SCALED 13
#define GUI_CMD_WINDOW_SET_TITLE 15
#define GUI_CMD_SET_FONT 16
#define GUI_CMD_DRAW_STRING_SCALED_SLOPED 18
// Event Types
#define GUI_EVENT_NONE 0
@@ -62,6 +63,7 @@ void ui_get_screen_size(uint64_t *out_w, uint64_t *out_h);
void ui_draw_string_bitmap(ui_window_t win, int x, int y, const char *str, uint32_t color);
void ui_draw_string_scaled(ui_window_t win, int x, int y, const char *str, uint32_t color, float scale);
void ui_draw_string_scaled_sloped(ui_window_t win, int x, int y, const char *str, uint32_t color, float scale, float slope);
uint32_t ui_get_string_width_scaled(const char *str, float scale);
uint32_t ui_get_font_height_scaled(float scale);
void ui_window_set_title(ui_window_t win, const char *title);

View File

@@ -59,6 +59,18 @@ uint64_t syscall5(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
return ret;
}
uint64_t syscall6(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6) {
uint64_t ret;
register uint64_t r10 asm("r10") = arg4;
register uint64_t r8 asm("r8") = arg5;
register uint64_t r9 asm("r9") = arg6;
asm volatile("syscall"
: "=a"(ret)
: "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8), "r"(r9)
: "rcx", "r11", "memory");
return ret;
}
void sys_exit(int status) {
syscall1(SYS_EXIT, (uint64_t)status);
@@ -239,3 +251,7 @@ void sys_yield(void) {
syscall1(SYS_SYSTEM, SYSTEM_CMD_YIELD);
}
int sys_get_os_info(os_info_t *info) {
return (int)syscall5(SYS_SYSTEM, SYSTEM_CMD_GET_OS_INFO, (uint64_t)info, 0, 0, 0);
}

View File

@@ -75,6 +75,7 @@
#define SYSTEM_CMD_SET_RAW_MODE 41
#define SYSTEM_CMD_TCP_RECV_NB 42
#define SYSTEM_CMD_YIELD 43
#define SYSTEM_CMD_GET_OS_INFO 49
// Internal assembly entry into Ring 0
extern uint64_t syscall0(uint64_t sys_num);
@@ -91,6 +92,19 @@ void *sys_sbrk(int incr);
void sys_kill(int pid);
int sys_system(int cmd, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4);
typedef struct {
char os_name[64];
char os_version[64];
char os_codename[64];
char kernel_name[64];
char kernel_version[64];
char build_date[64];
char build_time[64];
char build_arch[64];
} os_info_t;
int sys_get_os_info(os_info_t *info);
// FS API
int sys_open(const char *path, const char *mode);
int sys_read(int fd, void *buf, uint32_t len);

View File

@@ -750,6 +750,8 @@ static void explorer_open_target(const char *path) {
} else {
if (explorer_str_ends_with(path, ".elf")) {
process_create_elf(path, NULL);
} else if (explorer_str_ends_with(path, ".pdf")) {
process_create_elf("A:/bin/word.elf", path);
} else if (explorer_is_markdown_file(path)) {
process_create_elf("A:/bin/markdown.elf", path);
} else if (explorer_str_ends_with(path, ".pnt")) {
@@ -842,6 +844,8 @@ static void explorer_draw_file_icon(int x, int y, bool is_dir, uint32_t color, c
if (full_path[explorer_strlen(full_path) - 1] != '/') explorer_strcat(full_path, "/");
explorer_strcat(full_path, filename);
draw_image_icon(x + 5, y + 5, full_path);
} else if (explorer_str_ends_with(filename, ".pdf")) {
draw_pdf_icon(x + 5, y + 5, "");
} else if (explorer_str_ends_with(filename, ".elf")) {
draw_elf_icon(x + 5, y + 5, "");
} else {

View File

@@ -17,12 +17,10 @@ float kfabsf(float x) {
}
float kpowf(float b, float e) {
// Very simplified pow for stb_truetype's needs
if (e == 0) return 1.0f;
if (e == 1) return b;
if (e == 0.5f) return ksqrtf(b);
// Fallback/log-based would be complex, let's see if this suffices
float res = 1.0f;
for (int i = 0; i < (int)e; i++) res *= b;
return res;
@@ -33,13 +31,11 @@ float kfmodf(float x, float y) {
}
float kcosf(float x) {
// Taylor series for cos(x) around 0
float x2 = x * x;
return 1.0f - (x2 / 2.0f) + (x2 * x2 / 24.0f) - (x2 * x2 * x2 / 720.0f);
}
float kacosf(float x) {
// Very rough approximation for acos(x)
if (x >= 1.0f) return 0;
if (x <= -1.0f) return 3.14159f;
return 1.57079f - x - (x*x*x)/6.0f;
@@ -59,6 +55,15 @@ static inline uint32_t alpha_blend(uint32_t bg, uint32_t fg, uint8_t alpha) {
static ttf_font_t *default_font = NULL;
#define MAX_LOADED_FONTS 8
typedef struct {
char path[128];
ttf_font_t *font;
} loaded_font_t;
static loaded_font_t loaded_fonts[MAX_LOADED_FONTS];
static int loaded_font_count = 0;
#define FONT_CACHE_SIZE 2048
typedef struct {
char c;
@@ -67,15 +72,22 @@ typedef struct {
unsigned char *bitmap;
} font_cache_entry_t;
// Cache is disabled for now due to race conditions and collisions
// static font_cache_entry_t g_font_cache[FONT_CACHE_SIZE];
bool font_manager_init(void) {
// We'll load a default font later if available
return true;
}
ttf_font_t* font_manager_load(const char *path, float size) {
(void)size;
for(int i=0; i<loaded_font_count; i++) {
int match = 1;
for(int j=0; path[j] || loaded_fonts[i].path[j]; j++) {
if (path[j] != loaded_fonts[i].path[j]) { match = 0; break; }
}
if (match) return loaded_fonts[i].font;
}
FAT32_FileHandle *fh = fat32_open(path, "r");
if (!fh || !fh->valid) {
serial_write("[FONT] Failed to open font file: ");
@@ -127,6 +139,13 @@ ttf_font_t* font_manager_load(const char *path, float size) {
if (!default_font) default_font = font;
if (loaded_font_count < MAX_LOADED_FONTS) {
int i=0; while(path[i] && i<127) { loaded_fonts[loaded_font_count].path[i] = path[i]; i++; }
loaded_fonts[loaded_font_count].path[i] = 0;
loaded_fonts[loaded_font_count].font = font;
loaded_font_count++;
}
return font;
}
@@ -145,16 +164,16 @@ void font_manager_render_char_scaled(ttf_font_t *font, int x, int y, char c, uin
unsigned char *bitmap = NULL;
int w, h, xoff, yoff;
float real_scale = stbtt_ScaleForPixelHeight(info, scale); // Convert pixel size back to stbtt scale
float real_scale = stbtt_ScaleForPixelHeight(info, scale);
int codepoint = (unsigned char)c;
if (codepoint == 128) codepoint = 0x2014; // &mdash; (—)
if (codepoint == 129) codepoint = 0x2013; // &ndash; ()
if (codepoint == 130) codepoint = 0x2022; // &bull; (•)
if (codepoint == 131) codepoint = 0x2026; // &hellip; (…)
if (codepoint == 132) codepoint = 0x2122; // &trade; (™)
if (codepoint == 133) codepoint = 0x20AC; // &euro; (€)
if (codepoint == 134) codepoint = 0x00B7; // &middot; (·)
if (codepoint == 128) codepoint = 0x2014;
if (codepoint == 129) codepoint = 0x2013;
if (codepoint == 130) codepoint = 0x2022;
if (codepoint == 131) codepoint = 0x2026;
if (codepoint == 132) codepoint = 0x2122;
if (codepoint == 133) codepoint = 0x20AC;
if (codepoint == 134) codepoint = 0x00B7;
bitmap = stbtt_GetCodepointBitmap(info, 0, real_scale, codepoint, &w, &h, &xoff, &yoff);
@@ -174,6 +193,46 @@ void font_manager_render_char_scaled(ttf_font_t *font, int x, int y, char c, uin
}
}
void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, char c, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t)) {
if (!font) font = default_font;
if (!font) return;
stbtt_fontinfo *info = (stbtt_fontinfo *)font->info;
unsigned char *bitmap = NULL;
int w, h, xoff, yoff;
float real_scale = stbtt_ScaleForPixelHeight(info, scale);
int codepoint = (unsigned char)c;
if (codepoint == 128) codepoint = 0x2014;
if (codepoint == 129) codepoint = 0x2013;
if (codepoint == 130) codepoint = 0x2022;
if (codepoint == 131) codepoint = 0x2026;
if (codepoint == 132) codepoint = 0x2122;
if (codepoint == 133) codepoint = 0x20AC;
if (codepoint == 134) codepoint = 0x00B7;
bitmap = stbtt_GetCodepointBitmap(info, 0, real_scale, codepoint, &w, &h, &xoff, &yoff);
if (bitmap) {
for (int row = 0; row < h; row++) {
int slant_offset = (int)((h - row) * slope);
for (int col = 0; col < w; col++) {
unsigned char alpha = bitmap[row * w + col];
if (alpha > 0) {
int px = x + col + xoff + slant_offset;
int py = y + row + yoff;
uint32_t bg = graphics_get_pixel(px, py);
put_pixel_fn(px, py, alpha_blend(bg, color, alpha));
}
}
}
stbtt_FreeBitmap(bitmap, NULL);
}
}
int font_manager_get_string_width(ttf_font_t *font, const char *s) {
if (!font) font = default_font;
if (!font) return 0;
@@ -211,15 +270,14 @@ int font_manager_get_string_width_scaled(ttf_font_t *font, const char *s, float
while (*s) {
int advance, lsb;
int codepoint = (unsigned char)*s;
if (codepoint == 128) codepoint = 0x2014; // &mdash; (—)
if (codepoint == 129) codepoint = 0x2013; // &ndash; ()
if (codepoint == 130) codepoint = 0x2022; // &bull; (•)
if (codepoint == 131) codepoint = 0x2026; // &hellip; (…)
if (codepoint == 132) codepoint = 0x2122; // &trade; (™)
if (codepoint == 133) codepoint = 0x20AC; // &euro; (€)
if (codepoint == 134) codepoint = 0x00B7; // &middot; (·)
if (codepoint == 128) codepoint = 0x2014;
if (codepoint == 129) codepoint = 0x2013;
if (codepoint == 130) codepoint = 0x2022;
if (codepoint == 131) codepoint = 0x2026;
if (codepoint == 132) codepoint = 0x2122;
if (codepoint == 133) codepoint = 0x20AC;
if (codepoint == 134) codepoint = 0x00B7;
stbtt_GetCodepointHMetrics(info, codepoint, &advance, &lsb);
// Round per-character to match draw_string's accumulation
width += (int)(advance * real_scale + 0.5f);
s++;
}

View File

@@ -5,7 +5,6 @@
#include <stdbool.h>
#include <stddef.h>
// stb_truetype math stubs
extern float ksqrtf(float x);
extern float kpowf(float b, float e);
extern float kfmodf(float x, float y);
@@ -24,21 +23,18 @@ extern float kfabsf(float x);
#define STBTT_assert(x) ((void)0)
// Memory management
#define STBTT_malloc(x,u) kmalloc(x)
#define STBTT_free(x,u) kfree(x)
// String functions
#define STBTT_memcpy mem_memcpy
#define STBTT_memset mem_memset
// Data types
typedef uint64_t STBTT_ptrsize;
typedef struct {
void *data;
size_t size;
void *info; // stbtt_fontinfo
void *info;
float scale;
float pixel_height;
int ascent;
@@ -50,6 +46,7 @@ bool font_manager_init(void);
ttf_font_t* font_manager_load(const char *path, float size);
void font_manager_render_char(ttf_font_t *font, int x, int y, char c, uint32_t color, void (*put_pixel_fn)(int, int, uint32_t));
void font_manager_render_char_scaled(ttf_font_t *font, int x, int y, char c, uint32_t color, float scale, void (*put_pixel_fn)(int, int, uint32_t));
void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, char c, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t));
int font_manager_get_string_width(ttf_font_t *font, const char *s);
int font_manager_get_string_width_scaled(ttf_font_t *font, const char *s, float scale);

View File

@@ -6,6 +6,7 @@
#include "font.h"
#include "io.h"
#include "font_manager.h"
#include "../mem/memory_manager.h"
static struct limine_framebuffer *g_fb = NULL;
static uint32_t g_bg_color = 0xFF696969;
@@ -329,6 +330,128 @@ void draw_rounded_rect_filled(int x, int y, int w, int h, int radius, uint32_t c
}
}
static uint32_t blend_color_alpha(uint32_t bottom, uint32_t top, int alpha) {
if (alpha <= 0) return bottom;
if (alpha >= 255) return top;
int rb = (bottom >> 16) & 0xFF;
int gb = (bottom >> 8) & 0xFF;
int bb = bottom & 0xFF;
int rt = (top >> 16) & 0xFF;
int gt = (top >> 8) & 0xFF;
int bt = top & 0xFF;
int rr = rb + (((rt - rb) * alpha) >> 8);
int gg = gb + (((gt - gb) * alpha) >> 8);
int bb_new = bb + (((bt - bb) * alpha) >> 8);
return (rr << 16) | (gg << 8) | bb_new;
}
void draw_rounded_rect_blurred(int x, int y, int w, int h, int radius, uint32_t tint_color, int blur_radius, int alpha) {
if (!g_fb) return;
int sw = get_screen_width();
int sh = get_screen_height();
if (x < 0) { w += x; x = 0; }
if (y < 0) { h += y; y = 0; }
if (x + w > sw) w = sw - x;
if (y + h > sh) h = sh - y;
if (w <= 0 || h <= 0) return;
if (radius > w / 2) radius = w / 2;
if (radius > h / 2) radius = h / 2;
if (radius < 1) radius = 1;
uint32_t *tmp_buf = (uint32_t *)kmalloc(w * h * sizeof(uint32_t));
if (!tmp_buf) {
draw_rounded_rect_filled(x, y, w, h, radius, tint_color);
return;
}
for (int r = 0; r < h; r++) {
int g_y = y + r;
for (int c = 0; c < w; c++) {
int g_x = x + c;
int r_sum = 0, g_sum = 0, b_sum = 0, count = 0;
int start_kx = g_x - blur_radius;
int end_kx = g_x + blur_radius;
if (start_kx < 0) start_kx = 0;
if (end_kx >= sw) end_kx = sw - 1;
for (int kx = start_kx; kx <= end_kx; kx++) {
uint32_t pixel = g_back_buffer[g_y * sw + kx];
r_sum += (pixel >> 16) & 0xFF;
g_sum += (pixel >> 8) & 0xFF;
b_sum += pixel & 0xFF;
count++;
}
if(count == 0) count = 1;
uint32_t out_pixel = ((r_sum / count) << 16) | ((g_sum / count) << 8) | (b_sum / count);
tmp_buf[r * w + c] = out_pixel;
}
}
for (int c = 0; c < w; c++) {
for (int r = 0; r < h; r++) {
int g_y = y + r;
int g_x = x + c;
if (g_clip_enabled) {
if (g_x < g_clip_x || g_x >= g_clip_x + g_clip_w ||
g_y < g_clip_y || g_y >= g_clip_y + g_clip_h) {
continue;
}
}
bool in_corner = false;
int dx = 0, dy = 0;
if (c < radius && r < radius) {
dx = radius - c - 1; dy = radius - r - 1;
in_corner = true;
} else if (c >= w - radius && r < radius) {
dx = c - (w - radius); dy = radius - r - 1;
in_corner = true;
} else if (c < radius && r >= h - radius) {
dx = radius - c - 1; dy = r - (h - radius);
in_corner = true;
} else if (c >= w - radius && r >= h - radius) {
dx = c - (w - radius); dy = r - (h - radius);
in_corner = true;
}
if (in_corner) {
if (dx*dx + dy*dy >= radius*radius) {
continue;
}
}
int r_sum = 0, g_sum = 0, b_sum = 0, count = 0;
int start_kr = r - blur_radius;
int end_kr = r + blur_radius;
if (start_kr < 0) start_kr = 0;
if (end_kr >= h) end_kr = h - 1;
for (int kr = start_kr; kr <= end_kr; kr++) {
uint32_t pixel = tmp_buf[kr * w + c];
r_sum += (pixel >> 16) & 0xFF;
g_sum += (pixel >> 8) & 0xFF;
b_sum += pixel & 0xFF;
count++;
}
if(count == 0) count = 1;
uint32_t blurred_pixel = ((r_sum / count) << 16) | ((g_sum / count) << 8) | (b_sum / count);
uint32_t final_pixel = blend_color_alpha(blurred_pixel, tint_color, alpha);
g_back_buffer[g_y * sw + g_x] = final_pixel;
}
}
kfree(tmp_buf);
}
void draw_char(int x, int y, char c, uint32_t color) {
if (g_current_ttf) {
font_manager_render_char(g_current_ttf, x, y, c, color, put_pixel);
@@ -463,6 +586,37 @@ void draw_string_scaled(int x, int y, const char *s, uint32_t color, float scale
}
}
void draw_string_sloped(int x, int y, const char *s, uint32_t color, float slope) {
if (g_current_ttf) draw_string_scaled_sloped(x, y, s, color, g_current_ttf->pixel_height, slope);
else draw_string_scaled(x, y, s, color, 15.0f); // Fast fallback if no ttf
}
void draw_string_scaled_sloped(int x, int y, const char *s, uint32_t color, float scale, float slope) {
if (!s) return;
int cur_x = x;
if (g_current_ttf) {
int baseline = y + font_manager_get_font_ascent_scaled(g_current_ttf, scale) - 2;
int line_height = font_manager_get_font_line_height_scaled(g_current_ttf, scale);
while (*s) {
if (*s == '\n') {
cur_x = x;
baseline += line_height;
} else {
font_manager_render_char_sloped(g_current_ttf, cur_x, baseline, *s, color, scale, slope, put_pixel);
char buf[2] = {*s, 0};
cur_x += font_manager_get_string_width_scaled(g_current_ttf, buf, scale);
}
s++;
}
return;
}
// Fallback to normal draw_string_scaled if no TTF
draw_string_scaled(x, y, s, color, scale);
}
void draw_desktop_background(void) {
if (!g_fb) return;

View File

@@ -21,10 +21,13 @@ uint32_t graphics_get_pixel(int x, int y);
void draw_rect(int x, int y, int w, int h, 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_blurred(int x, int y, int w, int h, int radius, uint32_t tint_color, int blur_radius, int alpha);
void draw_char(int x, int y, char c, uint32_t color);
void draw_char_bitmap(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_scaled(int x, int y, const char *s, uint32_t color, float scale);
void draw_string_sloped(int x, int y, const char *s, uint32_t color, float slope);
void draw_string_scaled_sloped(int x, int y, const char *s, uint32_t color, float scale, float slope);
void draw_desktop_background(void);
void graphics_set_bg_color(uint32_t color);
void graphics_set_bg_pattern(const uint32_t *pattern); // 128x128 pattern

View File

@@ -129,6 +129,7 @@ int desktop_max_cols = 23;
int mouse_speed = 10;
static int mouse_accum_x = 0;
static int mouse_accum_y = 0;
Window *active_mouse_capture_win = NULL;
// Helper to check if string ends with suffix
static bool str_ends_with(const char *str, const char *suffix) {
@@ -508,6 +509,33 @@ void draw_document_icon(int x, int y, const char *label) {
draw_icon_label(x, y, label);
}
void draw_pdf_icon(int x, int y, const char *label) {
uint32_t icon_buf[48 * 48];
for (int i = 0; i < 48 * 48; i++) icon_buf[i] = 0xFFFF00FF;
graphics_set_render_target(icon_buf, 48, 48);
// Document shape
draw_rounded_rect_filled(4, 4, 40, 40, 8, 0xFFFFFFFF);
// Red banner
draw_rounded_rect_filled(8, 8, 32, 14, 4, 0xFFDF2020);
// PDF text roughly (simplified to lines for now)
draw_rect(14, 25, 20, 2, 0xFFBBBBBB);
draw_rect(14, 33, 14, 2, 0xFFBBBBBB);
graphics_set_render_target(NULL, 0, 0);
int dx = x + 24, dy = y + 12;
for (int ty = 0; ty < 32; ty++) {
for (int tx = 0; tx < 32; tx++) {
int src_x = tx * 48 / 32;
int src_y = ty * 48 / 32;
uint32_t c1 = icon_buf[src_y * 48 + src_x];
if (c1 != 0xFFFF00FF) put_pixel(dx + tx, dy + ty, c1);
}
}
draw_icon_label(x, y, label);
}
void draw_elf_icon(int x, int y, const char *label) {
uint32_t icon_buf[48 * 48];
for (int i = 0; i < 48 * 48; i++) icon_buf[i] = 0xFFFF00FF;
@@ -912,6 +940,23 @@ static long long isqrt(long long n) {
return x;
}
static void draw_dock_word(int x, int y) {
// Rich blue document style
draw_rounded_rect_filled(x, y, 48, 48, 10, 0xFF4A90E2);
draw_rounded_rect_filled(x + 1, y + 1, 46, 28, 9, 0xFF5D9CE6);
draw_rounded_rect_filled(x + 1, y + 24, 46, 23, 9, 0xFF3A80D2);
// White document page in center
draw_rounded_rect_filled(x + 8, y + 8, 32, 32, 4, 0xFFFFFFFF);
// Blue header edge
draw_rounded_rect_filled(x + 8, y + 8, 32, 8, 4, 0xFF2868B8);
// Text lines using dark grey
draw_rect(x + 14, y + 22, 20, 2, 0xFF666666);
draw_rect(x + 14, y + 27, 20, 2, 0xFF666666);
draw_rect(x + 14, y + 32, 14, 2, 0xFF666666);
}
static void draw_dock_notepad(int x, int y) {
draw_rounded_rect_filled(x, y, 48, 48, 10, 0xFFCC9A00);
draw_rounded_rect_filled(x + 1, y + 1, 46, 28, 9, 0xFFFFD700);
@@ -1225,7 +1270,21 @@ void wm_paint(void) {
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
DirtyRect dirty = graphics_get_dirty_rect();
if (dirty.active) {
int d_h = 60;
int d_y = sh - d_h - 6;
int d_item_sz = 48;
int d_space = 10;
int d_tw = 10 * (d_item_sz + d_space);
int d_bg_x = (sw - d_tw) / 2 - 12;
int d_bg_w = d_tw + 24;
if (!(dirty.x >= d_bg_x + d_bg_w || dirty.x + dirty.w <= d_bg_x ||
dirty.y >= d_y + d_h || dirty.y + dirty.h <= d_y)) {
graphics_mark_dirty(d_bg_x - 10, d_y - 10, d_bg_w + 20, d_h + 20);
dirty = graphics_get_dirty_rect();
}
graphics_set_clipping(dirty.x, dirty.y, dirty.w, dirty.h);
} else {
graphics_clear_clipping();
@@ -1274,6 +1333,7 @@ void wm_paint(void) {
draw_image_icon(icon->x, icon->y, full_path);
draw_icon_label(icon->x, icon->y, icon->name);
}
else if (str_ends_with(icon->name, ".pdf")) draw_pdf_icon(icon->x, icon->y, icon->name);
else draw_document_icon(icon->x, icon->y, icon->name);
}
}
@@ -1324,10 +1384,12 @@ void wm_paint(void) {
int dock_y = sh - dock_h - 6;
int dock_item_size = 48;
int dock_spacing = 10;
int total_dock_width = 10 * (dock_item_size + dock_spacing);
int total_dock_width = 11 * (dock_item_size + dock_spacing);
int dock_bg_x = (sw - total_dock_width) / 2 - 12;
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 blurred dock background with reduced radius and tint
draw_rounded_rect_blurred(dock_bg_x, dock_y, dock_bg_w, dock_h, 18, COLOR_DOCK_BG, 5, 140);
int dock_x = (sw - total_dock_width) / 2;
int dock_item_y = dock_y + 6;
@@ -1351,7 +1413,8 @@ void wm_paint(void) {
draw_dock_taskman(dock_x, dock_item_y);
dock_x += dock_item_size + dock_spacing;
draw_dock_clock(dock_x, dock_item_y);
// Editor removed from dock
dock_x += dock_item_size + dock_spacing;
draw_dock_word(dock_x, dock_item_y);
// Desktop Context Menu (with rounded corners)
if (desktop_menu_visible) {
@@ -1533,6 +1596,10 @@ void wm_remove_window(Window *win) {
}
window_count--;
if (active_mouse_capture_win == win) {
active_mouse_capture_win = NULL;
}
// Mark for redraw while protected
force_redraw = true;
} else {
@@ -1905,7 +1972,7 @@ void wm_handle_right_click(int x, int y) {
int dock_y = sh - dock_h - 6;
int dock_item_size = 48;
int dock_spacing = 10;
int total_dock_width = 10 * (dock_item_size + dock_spacing);
int total_dock_width = 11 * (dock_item_size + dock_spacing);
int dock_bg_x = (sw - total_dock_width) / 2 - 12;
int dock_bg_w = total_dock_width + 24;
@@ -1926,6 +1993,7 @@ void wm_handle_right_click(int x, int y) {
else if (item == 7) start_menu_pending_app = "Browser";
else if (item == 8) start_menu_pending_app = "Task Manager";
else if (item == 9) start_menu_pending_app = "Clock";
else if (item == 10) start_menu_pending_app = "Word Processor";
}
} else {
wm_handle_click(mx, my);
@@ -2002,19 +2070,33 @@ void wm_handle_right_click(int x, int y) {
}
// 2. Check Explorer Items
if (!is_dragging_file) {
bool is_dir;
if (explorer_get_file_at(drag_start_x, drag_start_y, drag_file_path, &is_dir)) {
is_dragging_file = true;
drag_icon_type = is_dir ? 1 : 0;
drag_src_win = NULL;
Window *topmost_at_drag = NULL;
int tops_z = -1;
for (int w = 0; w < window_count; w++) {
Window *w_ptr = all_windows[w];
if (w_ptr->visible && rect_contains(w_ptr->x, w_ptr->y, w_ptr->w, w_ptr->h, drag_start_x, drag_start_y)) {
if (w_ptr->z_index > tops_z) {
topmost_at_drag = w_ptr;
tops_z = w_ptr->z_index;
}
}
}
// Find which explorer window was clicked to clear its state
for (int w = 0; w < window_count; w++) {
Window *win = all_windows[w];
if (win->visible && rect_contains(win->x, win->y, win->w, win->h, drag_start_x, drag_start_y)) {
if (str_starts_with(win->title, "Files")) {
drag_src_win = win;
explorer_clear_click_state(win);
if (!topmost_at_drag || str_starts_with(topmost_at_drag->title, "Files")) {
bool is_dir;
if (explorer_get_file_at(drag_start_x, drag_start_y, drag_file_path, &is_dir)) {
is_dragging_file = true;
drag_icon_type = is_dir ? 1 : 0;
drag_src_win = NULL;
// Find which explorer window was clicked to clear its state
for (int w = 0; w < window_count; w++) {
Window *win = all_windows[w];
if (win->visible && rect_contains(win->x, win->y, win->w, win->h, drag_start_x, drag_start_y)) {
if (str_starts_with(win->title, "Files")) {
drag_src_win = win;
explorer_clear_click_state(win);
}
}
}
}
@@ -2048,6 +2130,10 @@ void wm_handle_right_click(int x, int y) {
Window *existing = wm_find_window_by_title("Txtedit");
if (existing) wm_bring_to_front(existing);
else process_create_elf("/bin/txtedit.elf", NULL);
} else if (str_starts_with(start_menu_pending_app, "Word Processor")) {
Window *existing = wm_find_window_by_title("Word Processor");
if (existing) wm_bring_to_front(existing);
else process_create_elf("/bin/word.elf", NULL);
} else if (str_starts_with(start_menu_pending_app, "Terminal")) {
cmd_reset(); wm_bring_to_front(&win_cmd);
} else if (str_starts_with(start_menu_pending_app, "Calculator")) {
@@ -2160,6 +2246,8 @@ void wm_handle_right_click(int x, int y) {
process_create_elf("/bin/paint.elf", path);
} else if (str_ends_with(icon->name, ".md")) {
process_create_elf("/bin/markdown.elf", path);
} else if (str_ends_with(icon->name, ".pdf")) {
process_create_elf("/bin/word.elf", path);
} else if (is_image_file(icon->name)) {
process_create_elf("/bin/viewer.elf", path);
} else {
@@ -2361,6 +2449,9 @@ void wm_handle_right_click(int x, int y) {
}
}
}
}
if (is_dragging_file) {
is_dragging_file = false;
force_redraw = true;
}
@@ -2385,46 +2476,57 @@ void wm_handle_right_click(int x, int y) {
}
}
if (topmost && topmost->data) {
active_mouse_capture_win = topmost;
if (my >= topmost->y + 20)
syscall_send_mouse_down_event(topmost, mx - topmost->x, my - topmost->y - 20);
} else {
active_mouse_capture_win = NULL;
}
}
if (!left && prev_left) {
// Left button released - send MOUSE_UP event to topmost window
Window *topmost = NULL;
int topmost_z = -1;
for (int w = 0; w < window_count; w++) {
Window *win = all_windows[w];
if (win->visible && rect_contains(win->x, win->y, win->w, win->h, mx, my)) {
if (win->z_index > topmost_z) {
topmost = win;
topmost_z = win->z_index;
// Left button released - send MOUSE_UP event to captured or topmost window
Window *target = active_mouse_capture_win;
if (!target) {
int topmost_z = -1;
for (int w = 0; w < window_count; w++) {
Window *win = all_windows[w];
if (win->visible && rect_contains(win->x, win->y, win->w, win->h, mx, my)) {
if (win->z_index > topmost_z) {
target = win;
topmost_z = win->z_index;
}
}
}
}
if (topmost && topmost->data) {
if (my >= topmost->y + 20)
syscall_send_mouse_up_event(topmost, mx - topmost->x, my - topmost->y - 20);
if (target && target->data) {
int rel_y = my - target->y - 20;
// Provide coordinates clamped if escaping bounds slightly on UP? Usually raw is fine.
syscall_send_mouse_up_event(target, mx - target->x, rel_y);
}
active_mouse_capture_win = NULL;
}
if (dx != 0 || dy != 0) {
// Mouse moved - send MOUSE_MOVE event to topmost window
Window *topmost = NULL;
int topmost_z = -1;
for (int w = 0; w < window_count; w++) {
Window *win = all_windows[w];
if (win->visible && rect_contains(win->x, win->y, win->w, win->h, mx, my)) {
if (win->z_index > topmost_z) {
topmost = win;
topmost_z = win->z_index;
// Mouse moved - send MOUSE_MOVE event to captured window (if dragging) or topmost
Window *target = active_mouse_capture_win;
if (!target) {
int topmost_z = -1;
for (int w = 0; w < window_count; w++) {
Window *win = all_windows[w];
if (win->visible && rect_contains(win->x, win->y, win->w, win->h, mx, my)) {
if (win->z_index > topmost_z) {
target = win;
topmost_z = win->z_index;
}
}
}
}
if (topmost && topmost->data) {
if (my >= topmost->y + 20)
syscall_send_mouse_move_event(topmost, mx - topmost->x, my - topmost->y - 20, buttons);
if (target && target->data) {
int rel_y = my - target->y - 20;
syscall_send_mouse_move_event(target, mx - target->x, rel_y, buttons);
}
}

View File

@@ -99,6 +99,7 @@ void draw_traffic_light(int x, int y);
void draw_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_pdf_icon(int x, int y, const char *label);
void draw_elf_icon(int x, int y, const char *label);
void draw_image_icon(int x, int y, const char *label);
void draw_notepad_icon(int x, int y, const char *label);

View File