mirror of
https://github.com/JannisHeydemann/BoredOS.git
synced 2026-05-30 02:16:58 +00:00
Notepad port to userspace and bug fixes
This commit is contained in:
10
Makefile
10
Makefile
@@ -32,7 +32,7 @@ LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \
|
||||
NASMFLAGS = -f elf64
|
||||
|
||||
# Limine Version
|
||||
LIMINE_VERSION = 7.0.0
|
||||
LIMINE_VERSION = 10.8.2
|
||||
LIMINE_URL_BASE = https://github.com/limine-bootloader/limine/raw/v$(LIMINE_VERSION)
|
||||
|
||||
.PHONY: all clean run limine-setup
|
||||
@@ -86,21 +86,21 @@ $(KERNEL_ELF): $(OBJ_FILES)
|
||||
$(MAKE) -C $(SRC_DIR)/userland
|
||||
|
||||
# Create ISO
|
||||
$(ISO_IMAGE): $(KERNEL_ELF) limine.cfg limine-setup
|
||||
$(ISO_IMAGE): $(KERNEL_ELF) limine.conf limine-setup
|
||||
rm -rf $(ISO_DIR)
|
||||
mkdir -p $(ISO_DIR)
|
||||
mkdir -p $(ISO_DIR)/EFI/BOOT
|
||||
|
||||
# Copy Kernel and Config
|
||||
cp $(KERNEL_ELF) $(ISO_DIR)/
|
||||
# Build ISO limine.cfg natively with modules
|
||||
cp limine.cfg $(ISO_DIR)/
|
||||
# Build ISO limine.conf natively with modules
|
||||
cp limine.conf $(ISO_DIR)/
|
||||
mkdir -p $(ISO_DIR)/bin
|
||||
@for f in $(SRC_DIR)/userland/*.elf; do \
|
||||
if [ -f "$$f" ]; then \
|
||||
basename=$$(basename "$$f"); \
|
||||
cp "$$f" $(ISO_DIR)/bin/; \
|
||||
echo " MODULE_PATH=boot:///bin/$$basename" >> $(ISO_DIR)/limine.cfg; \
|
||||
echo " module_path: boot():/bin/$$basename" >> $(ISO_DIR)/limine.conf; \
|
||||
fi \
|
||||
done
|
||||
|
||||
|
||||
BIN
boredos.iso
BIN
boredos.iso
Binary file not shown.
BIN
build/about.o
BIN
build/about.o
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
build/cmd.o
BIN
build/cmd.o
Binary file not shown.
Binary file not shown.
BIN
build/explorer.o
BIN
build/explorer.o
Binary file not shown.
BIN
build/icmp.o
BIN
build/icmp.o
Binary file not shown.
BIN
build/idt.o
BIN
build/idt.o
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
Binary file not shown.
BIN
build/notepad.o
BIN
build/notepad.o
Binary file not shown.
BIN
build/paint.o
BIN
build/paint.o
Binary file not shown.
BIN
build/ps2.o
BIN
build/ps2.o
Binary file not shown.
BIN
build/vm.o
BIN
build/vm.o
Binary file not shown.
Binary file not shown.
BIN
build/wm.o
BIN
build/wm.o
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
iso_root/bin/notepad.elf
Executable file
BIN
iso_root/bin/notepad.elf
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,11 +0,0 @@
|
||||
TIMEOUT=3
|
||||
|
||||
:BoredOS
|
||||
PROTOCOL=limine
|
||||
|
||||
KERNEL_PATH=boot:///boredos.elf
|
||||
#FRAMEBUFFER_WIDTH=1280
|
||||
#FRAMEBUFFER_HEIGHT=720
|
||||
MODULE_PATH=boot:///bin/calculator.elf
|
||||
MODULE_PATH=boot:///bin/crash.elf
|
||||
MODULE_PATH=boot:///bin/hello.elf
|
||||
11
iso_root/limine.conf
Normal file
11
iso_root/limine.conf
Normal file
@@ -0,0 +1,11 @@
|
||||
timeout: 3
|
||||
|
||||
/BoredOS
|
||||
protocol: limine
|
||||
|
||||
kernel_path: boot():/boredos.elf
|
||||
#resolution: 1280x720
|
||||
module_path: boot():/bin/calculator.elf
|
||||
module_path: boot():/bin/crash.elf
|
||||
module_path: boot():/bin/hello.elf
|
||||
module_path: boot():/bin/notepad.elf
|
||||
2
limine
2
limine
Submodule limine updated: efd130dbb6...38ff2c855a
@@ -1,8 +0,0 @@
|
||||
TIMEOUT=3
|
||||
|
||||
:BoredOS
|
||||
PROTOCOL=limine
|
||||
|
||||
KERNEL_PATH=boot:///boredos.elf
|
||||
#FRAMEBUFFER_WIDTH=1280
|
||||
#FRAMEBUFFER_HEIGHT=720
|
||||
7
limine.conf
Normal file
7
limine.conf
Normal file
@@ -0,0 +1,7 @@
|
||||
timeout: 3
|
||||
|
||||
/BoredOS
|
||||
protocol: limine
|
||||
|
||||
kernel_path: boot():/boredos.elf
|
||||
#resolution: 1280x720
|
||||
@@ -8,7 +8,6 @@ extern void editor_init(void);
|
||||
extern Window win_editor;
|
||||
extern Window win_explorer;
|
||||
extern Window win_cmd;
|
||||
extern Window win_notepad;
|
||||
|
||||
void cli_cmd_txtedit(char *args) {
|
||||
// Parse the file path argument
|
||||
@@ -50,7 +49,6 @@ void cli_cmd_txtedit(char *args) {
|
||||
int max_z = 0;
|
||||
if (win_explorer.z_index > max_z) max_z = win_explorer.z_index;
|
||||
if (win_cmd.z_index > max_z) max_z = win_cmd.z_index;
|
||||
if (win_notepad.z_index > max_z) max_z = win_notepad.z_index;
|
||||
win_editor.z_index = max_z + 1;
|
||||
|
||||
cli_write("Opening: ");
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "wm.h"
|
||||
#include "io.h"
|
||||
#include "rtc.h"
|
||||
#include "notepad.h"
|
||||
|
||||
#include "fat32.h"
|
||||
#include "disk.h"
|
||||
#include "cli_apps/cli_apps.h"
|
||||
@@ -554,7 +554,6 @@ static void internal_cmd_txtedit(char *args) {
|
||||
// Make editor window visible and focused, bring to front
|
||||
extern Window win_explorer;
|
||||
extern Window win_cmd;
|
||||
extern Window win_notepad;
|
||||
|
||||
win_editor.visible = true;
|
||||
win_editor.focused = true;
|
||||
@@ -563,7 +562,6 @@ static void internal_cmd_txtedit(char *args) {
|
||||
int max_z = 0;
|
||||
if (win_explorer.z_index > max_z) max_z = win_explorer.z_index;
|
||||
if (win_cmd.z_index > max_z) max_z = win_cmd.z_index;
|
||||
if (win_notepad.z_index > max_z) max_z = win_notepad.z_index;
|
||||
win_editor.z_index = max_z + 1;
|
||||
|
||||
cmd_write("Opening: ");
|
||||
@@ -646,7 +644,7 @@ void cmd_exec_elf(char *args) {
|
||||
}
|
||||
|
||||
cmd_is_waiting_for_process = true;
|
||||
process_create_elf(full_exec_path);
|
||||
process_create_elf(full_exec_path, args);
|
||||
}
|
||||
|
||||
// Public API for syscall exit
|
||||
@@ -1176,7 +1174,7 @@ static void cmd_exec_single(char *cmd) {
|
||||
if (fh) {
|
||||
fat32_close(fh);
|
||||
cmd_is_waiting_for_process = true;
|
||||
process_create_elf(search_path);
|
||||
process_create_elf(search_path, args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1197,7 +1195,7 @@ static void cmd_exec_single(char *cmd) {
|
||||
if (fh) {
|
||||
fat32_close(fh);
|
||||
cmd_is_waiting_for_process = true;
|
||||
process_create_elf(search_path);
|
||||
process_create_elf(search_path, args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,10 +59,6 @@ uint64_t elf_load(const char *path, uint64_t user_pml4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
serial_write("[ELF] Number of program headers: ");
|
||||
print_hex(ehdr.e_phnum);
|
||||
serial_write("\n");
|
||||
|
||||
// Iterate Over Program Headers
|
||||
for (int i = 0; i < ehdr.e_phnum; i++) {
|
||||
fat32_seek(file, ehdr.e_phoff + (i * ehdr.e_phentsize), 0);
|
||||
@@ -72,10 +68,6 @@ uint64_t elf_load(const char *path, uint64_t user_pml4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
serial_write("[ELF] Header type parsed: ");
|
||||
print_hex(phdr.p_type);
|
||||
serial_write("\n");
|
||||
|
||||
// Only load segments with type PT_LOAD
|
||||
if (phdr.p_type == PT_LOAD) {
|
||||
uint64_t p_vaddr = phdr.p_vaddr;
|
||||
@@ -83,10 +75,6 @@ uint64_t elf_load(const char *path, uint64_t user_pml4) {
|
||||
uint64_t p_filesz = phdr.p_filesz;
|
||||
uint64_t p_offset = phdr.p_offset;
|
||||
|
||||
serial_write("[ELF] Loaded PT_LOAD segment vaddr=");
|
||||
print_hex(p_vaddr);
|
||||
serial_write("\n");
|
||||
|
||||
if (p_memsz == 0) continue;
|
||||
|
||||
// Calculate page-aligned boundaries
|
||||
@@ -103,36 +91,32 @@ uint64_t elf_load(const char *path, uint64_t user_pml4) {
|
||||
fat32_close(file);
|
||||
return 0;
|
||||
}
|
||||
// Determine Flags
|
||||
uint64_t flags = 0x07; // Present, RW, User
|
||||
|
||||
paging_map_page(user_pml4, vaddr, v2p((uint64_t)phys), flags);
|
||||
// Map page to user space (Present, RW, User)
|
||||
paging_map_page(user_pml4, vaddr, v2p((uint64_t)phys), 0x07);
|
||||
|
||||
// Initialize page memory
|
||||
// Zero out the entire page (handles BSS and padding)
|
||||
uint8_t* dest = (uint8_t*)phys;
|
||||
for (int j=0; j<4096; j++) dest[j] = 0; // zero memory (handles BSS)
|
||||
for (int j=0; j<4096; j++) dest[j] = 0;
|
||||
|
||||
// If loading from file
|
||||
if (p_filesz > 0) {
|
||||
uint64_t copy_start_offset = 0;
|
||||
uint64_t file_seek_pos = p_offset;
|
||||
uint64_t bytes_to_copy = 4096;
|
||||
// Copy data from file if available for this page
|
||||
uint64_t page_vaddr_start = vaddr;
|
||||
uint64_t page_vaddr_end = vaddr + 4096;
|
||||
|
||||
if (p == 0) {
|
||||
copy_start_offset = align_offset;
|
||||
bytes_to_copy = 4096 - align_offset;
|
||||
} else {
|
||||
file_seek_pos += (p * 4096) - align_offset;
|
||||
}
|
||||
// What part of the segment (p_vaddr to p_vaddr + p_filesz) overlaps this page?
|
||||
uint64_t overlap_vaddr_start = p_vaddr;
|
||||
if (page_vaddr_start > overlap_vaddr_start) overlap_vaddr_start = page_vaddr_start;
|
||||
|
||||
if (bytes_to_copy > p_filesz) {
|
||||
bytes_to_copy = p_filesz;
|
||||
}
|
||||
if (bytes_to_copy > 0) {
|
||||
fat32_seek(file, file_seek_pos, 0);
|
||||
fat32_read(file, dest + copy_start_offset, bytes_to_copy);
|
||||
p_filesz -= bytes_to_copy;
|
||||
}
|
||||
uint64_t overlap_vaddr_end = p_vaddr + p_filesz;
|
||||
if (page_vaddr_end < overlap_vaddr_end) overlap_vaddr_end = page_vaddr_end;
|
||||
|
||||
if (overlap_vaddr_start < overlap_vaddr_end) {
|
||||
uint64_t copy_size = overlap_vaddr_end - overlap_vaddr_start;
|
||||
uint64_t dest_offset = overlap_vaddr_start - page_vaddr_start;
|
||||
uint64_t file_offset = p_offset + (overlap_vaddr_start - p_vaddr);
|
||||
|
||||
fat32_seek(file, file_offset, 0);
|
||||
fat32_read(file, dest + dest_offset, (uint32_t)copy_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "editor.h"
|
||||
#include "markdown.h"
|
||||
#include "cmd.h"
|
||||
#include "notepad.h"
|
||||
|
||||
#include "process.h"
|
||||
#include "minesweeper.h"
|
||||
#include "viewer.h"
|
||||
@@ -817,7 +817,7 @@ static void explorer_open_target(const char *path) {
|
||||
explorer_open_directory(path);
|
||||
} else {
|
||||
if (explorer_str_ends_with(path, ".elf")) {
|
||||
process_create_elf(path);
|
||||
process_create_elf(path, NULL);
|
||||
} else if (explorer_is_markdown_file(path)) {
|
||||
wm_bring_to_front(&win_markdown);
|
||||
markdown_open_file(path);
|
||||
@@ -853,9 +853,9 @@ static void explorer_open_item(Window *win, int index) {
|
||||
if (explorer_str_ends_with(state->items[index].name, ".shortcut")) {
|
||||
Window *target = NULL;
|
||||
if (explorer_strcmp(state->items[index].name, "Notepad.shortcut") == 0) {
|
||||
target = &win_notepad;
|
||||
process_create_elf("/bin/notepad.elf", NULL); return;
|
||||
} else if (explorer_strcmp(state->items[index].name, "Calculator.shortcut") == 0) {
|
||||
process_create_elf("/bin/calculator.elf"); return;
|
||||
process_create_elf("/bin/calculator.elf", NULL); return;
|
||||
} else if (explorer_strcmp(state->items[index].name, "Terminal.shortcut") == 0) {
|
||||
target = &win_cmd; cmd_reset();
|
||||
} else if (explorer_strcmp(state->items[index].name, "Minesweeper.shortcut") == 0) {
|
||||
@@ -1785,7 +1785,6 @@ static void explorer_handle_file_context_menu_click(Window *win, int x, int y) {
|
||||
int max_z = 0;
|
||||
for (int i = 0; i < explorer_win_count; i++) if (explorer_wins[i]->z_index > max_z) max_z = explorer_wins[i]->z_index;
|
||||
if (win_cmd.z_index > max_z) max_z = win_cmd.z_index;
|
||||
if (win_notepad.z_index > max_z) max_z = win_notepad.z_index;
|
||||
if (win_editor.z_index > max_z) max_z = win_editor.z_index;
|
||||
if (win_markdown.z_index > max_z) max_z = win_markdown.z_index;
|
||||
if (win_control_panel.z_index > max_z) max_z = win_control_panel.z_index;
|
||||
|
||||
@@ -6,7 +6,7 @@ section .text
|
||||
gdt_flush:
|
||||
lgdt [rdi] ; Load GDT from the pointer passed in RDI
|
||||
|
||||
mov ax, 0x10 ; 0x10 is our offset in the GDT to our data segment
|
||||
mov ax, 0x10 ; 0x10 is the offset in the GDT to data segment
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
@@ -14,7 +14,7 @@ gdt_flush:
|
||||
mov ss, ax
|
||||
|
||||
; Far jump to update CS
|
||||
push 0x08 ; 0x08 is our offset to the code segment
|
||||
push 0x08 ; 0x08 is the offset to the code segment
|
||||
lea rax, [rel .flush]
|
||||
push rax
|
||||
retfq
|
||||
@@ -23,6 +23,6 @@ gdt_flush:
|
||||
ret
|
||||
|
||||
tss_flush:
|
||||
mov ax, 0x28 ; 0x28 is our offset in the GDT to the TSS
|
||||
mov ax, 0x28 ; 0x28 is the offset in the GDT to the TSS
|
||||
ltr ax
|
||||
ret
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define GUI_EVENT_CLICK 2
|
||||
#define GUI_EVENT_RIGHT_CLICK 3
|
||||
#define GUI_EVENT_CLOSE 4
|
||||
#define GUI_EVENT_KEY 5
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
#include "notepad.h"
|
||||
#include "graphics.h"
|
||||
#include <stddef.h>
|
||||
|
||||
Window win_notepad;
|
||||
static int notepad_scroll_line = 0;
|
||||
|
||||
static void notepad_ensure_cursor_visible(Window *win) {
|
||||
int visible_lines = (win->h - 40) / 10 + 3;
|
||||
if (visible_lines < 1) visible_lines = 1;
|
||||
|
||||
int cursor_line = 0;
|
||||
for (int i = 0; i < win->cursor_pos && i < win->buf_len; i++) {
|
||||
if (win->buffer[i] == '\n') cursor_line++;
|
||||
}
|
||||
|
||||
if (cursor_line < notepad_scroll_line) {
|
||||
notepad_scroll_line = cursor_line;
|
||||
}
|
||||
|
||||
if (cursor_line >= notepad_scroll_line + visible_lines) {
|
||||
notepad_scroll_line = cursor_line - visible_lines + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void notepad_paint(Window *win) {
|
||||
// Dark mode background for text
|
||||
draw_rect(win->x + 4, win->y + 30, win->w - 8, win->h - 34, COLOR_NOTEPAD_BG);
|
||||
|
||||
int visual_line = 0;
|
||||
int current_x = win->x + 8;
|
||||
int current_y = win->y + 36;
|
||||
int window_right = win->x + win->w - 16;
|
||||
|
||||
for (int i = 0; i < win->buf_len; i++) {
|
||||
if (visual_line < notepad_scroll_line) {
|
||||
if (win->buffer[i] == '\n') {
|
||||
visual_line++;
|
||||
current_x = win->x + 8;
|
||||
current_y = win->y + 36;
|
||||
} else {
|
||||
if (current_x >= window_right) {
|
||||
visual_line++;
|
||||
current_x = win->x + 8;
|
||||
current_y += 10;
|
||||
}
|
||||
current_x += 8;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (visual_line >= notepad_scroll_line + (win->h - 40) / 10) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (win->buffer[i] == '\n') {
|
||||
current_x = win->x + 8;
|
||||
current_y += 10;
|
||||
visual_line++;
|
||||
} else {
|
||||
if (current_x >= window_right) {
|
||||
current_x = win->x + 8;
|
||||
current_y += 10;
|
||||
visual_line++;
|
||||
|
||||
if (visual_line >= notepad_scroll_line + (win->h - 40) / 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char ch[2] = {win->buffer[i], 0};
|
||||
draw_string(current_x, current_y, ch, COLOR_BLACK);
|
||||
current_x += 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Cursor
|
||||
if (win->focused) {
|
||||
int cx = win->x + 8;
|
||||
int cy = win->y + 36;
|
||||
int visual_line = 0;
|
||||
int window_right = win->x + win->w - 16; // Right boundary with padding
|
||||
|
||||
for (int i = 0; i < win->cursor_pos; i++) {
|
||||
if (win->buffer[i] == '\n') {
|
||||
cx = win->x + 8;
|
||||
cy += 10;
|
||||
visual_line++;
|
||||
} else {
|
||||
if (cx >= window_right) {
|
||||
cx = win->x + 8;
|
||||
cy += 10;
|
||||
visual_line++;
|
||||
}
|
||||
cx += 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (visual_line >= notepad_scroll_line &&
|
||||
visual_line < notepad_scroll_line + (win->h - 40) / 10) {
|
||||
draw_rect(cx, cy, 2, 8, COLOR_BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void notepad_key(Window *target, char c) {
|
||||
if (c == 17) { // UP
|
||||
if (target->cursor_pos > 0) {
|
||||
int curr = target->cursor_pos;
|
||||
int line_start = curr;
|
||||
while (line_start > 0 && target->buffer[line_start - 1] != '\n') {
|
||||
line_start--;
|
||||
}
|
||||
int col = curr - line_start;
|
||||
|
||||
if (line_start > 0) {
|
||||
int prev_line_end = line_start - 1;
|
||||
int prev_line_start = prev_line_end;
|
||||
while (prev_line_start > 0 && target->buffer[prev_line_start - 1] != '\n') {
|
||||
prev_line_start--;
|
||||
}
|
||||
int prev_line_len = prev_line_end - prev_line_start;
|
||||
if (col > prev_line_len) col = prev_line_len;
|
||||
target->cursor_pos = prev_line_start + col;
|
||||
}
|
||||
}
|
||||
notepad_ensure_cursor_visible(target);
|
||||
} else if (c == 18) { // DOWN
|
||||
int len = target->buf_len;
|
||||
if (target->cursor_pos < len) {
|
||||
int curr = target->cursor_pos;
|
||||
int line_start = curr;
|
||||
while (line_start > 0 && target->buffer[line_start - 1] != '\n') {
|
||||
line_start--;
|
||||
}
|
||||
int col = curr - line_start;
|
||||
|
||||
int next_line_start = curr;
|
||||
while (next_line_start < len && target->buffer[next_line_start] != '\n') {
|
||||
next_line_start++;
|
||||
}
|
||||
|
||||
if (next_line_start < len) {
|
||||
next_line_start++; // Skip newline
|
||||
int next_line_end = next_line_start;
|
||||
while (next_line_end < len && target->buffer[next_line_end] != '\n') {
|
||||
next_line_end++;
|
||||
}
|
||||
int next_line_len = next_line_end - next_line_start;
|
||||
if (col > next_line_len) col = next_line_len;
|
||||
target->cursor_pos = next_line_start + col;
|
||||
} else {
|
||||
target->cursor_pos = len;
|
||||
}
|
||||
}
|
||||
notepad_ensure_cursor_visible(target);
|
||||
} else if (c == 19) { // LEFT
|
||||
if (target->cursor_pos > 0) target->cursor_pos--;
|
||||
notepad_ensure_cursor_visible(target);
|
||||
} else if (c == 20) { // RIGHT
|
||||
if (target->cursor_pos < target->buf_len) target->cursor_pos++;
|
||||
notepad_ensure_cursor_visible(target);
|
||||
} else if (c == '\b') { // Backspace
|
||||
if (target->cursor_pos > 0) {
|
||||
// Shift left
|
||||
for (int i = target->cursor_pos; i < target->buf_len; i++) {
|
||||
target->buffer[i - 1] = target->buffer[i];
|
||||
}
|
||||
target->buf_len--;
|
||||
target->cursor_pos--;
|
||||
target->buffer[target->buf_len] = 0;
|
||||
notepad_ensure_cursor_visible(target);
|
||||
}
|
||||
} else if (c == '\n') { // Enter
|
||||
if (target->buf_len < 1023) {
|
||||
// Shift right
|
||||
for (int i = target->buf_len; i > target->cursor_pos; i--) {
|
||||
target->buffer[i] = target->buffer[i - 1];
|
||||
}
|
||||
target->buffer[target->cursor_pos] = c;
|
||||
target->buf_len++;
|
||||
target->cursor_pos++;
|
||||
target->buffer[target->buf_len] = 0;
|
||||
notepad_ensure_cursor_visible(target);
|
||||
}
|
||||
} else {
|
||||
// Printable char
|
||||
if (target->buf_len < 1023) {
|
||||
for (int i = target->buf_len; i > target->cursor_pos; i--) {
|
||||
target->buffer[i] = target->buffer[i - 1];
|
||||
}
|
||||
target->buffer[target->cursor_pos] = c;
|
||||
target->buf_len++;
|
||||
target->cursor_pos++;
|
||||
target->buffer[target->buf_len] = 0;
|
||||
notepad_ensure_cursor_visible(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void notepad_init(void) {
|
||||
win_notepad.title = "Notepad";
|
||||
win_notepad.x = 100;
|
||||
win_notepad.y = 100;
|
||||
win_notepad.w = 400;
|
||||
win_notepad.h = 300;
|
||||
win_notepad.visible = false;
|
||||
win_notepad.buf_len = 0;
|
||||
win_notepad.cursor_pos = 0;
|
||||
win_notepad.focused = false;
|
||||
win_notepad.z_index = 0;
|
||||
win_notepad.paint = notepad_paint;
|
||||
win_notepad.handle_key = notepad_key;
|
||||
win_notepad.handle_click = NULL;
|
||||
win_notepad.handle_right_click = NULL;
|
||||
|
||||
notepad_scroll_line = 0;
|
||||
|
||||
for(int i=0; i<1024; i++) win_notepad.buffer[i] = 0;
|
||||
}
|
||||
|
||||
void notepad_reset(void) {
|
||||
// Clear notepad buffer and reset cursor on close/reopen
|
||||
win_notepad.buf_len = 0;
|
||||
win_notepad.cursor_pos = 0;
|
||||
win_notepad.focused = false;
|
||||
notepad_scroll_line = 0;
|
||||
|
||||
for(int i=0; i<1024; i++) win_notepad.buffer[i] = 0;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef NOTEPAD_H
|
||||
#define NOTEPAD_H
|
||||
|
||||
#include "wm.h"
|
||||
|
||||
extern Window win_notepad;
|
||||
|
||||
void notepad_init(void);
|
||||
void notepad_reset(void);
|
||||
|
||||
#endif
|
||||
@@ -28,6 +28,8 @@ void process_init(void) {
|
||||
kernel_proc->pml4_phys = paging_get_pml4_phys();
|
||||
kernel_proc->kernel_stack = 0;
|
||||
|
||||
for (int i = 0; i < MAX_PROCESS_FDS; i++) kernel_proc->fds[i] = NULL;
|
||||
|
||||
kernel_proc->next = kernel_proc; // Circular linked list
|
||||
current_process = kernel_proc;
|
||||
}
|
||||
@@ -102,7 +104,7 @@ void process_create(void* entry_point, bool is_user) {
|
||||
current_process->next = new_proc;
|
||||
}
|
||||
|
||||
void process_create_elf(const char* filepath) {
|
||||
void process_create_elf(const char* filepath, const char* args_str) {
|
||||
if (process_count >= MAX_PROCESSES) return;
|
||||
|
||||
process_t *new_proc = &processes[process_count];
|
||||
@@ -113,6 +115,11 @@ void process_create_elf(const char* filepath) {
|
||||
new_proc->pml4_phys = paging_create_user_pml4_phys();
|
||||
if (!new_proc->pml4_phys) return;
|
||||
|
||||
for (int i = 0; i < MAX_PROCESS_FDS; i++) new_proc->fds[i] = NULL;
|
||||
new_proc->gui_event_head = 0;
|
||||
new_proc->gui_event_tail = 0;
|
||||
new_proc->ui_window = NULL;
|
||||
|
||||
// 2. Load ELF executable
|
||||
uint64_t entry_point = elf_load(filepath, new_proc->pml4_phys);
|
||||
if (entry_point == 0) {
|
||||
@@ -127,14 +134,85 @@ void process_create_elf(const char* filepath) {
|
||||
void* stack = kmalloc_aligned(4096, 4096);
|
||||
void* kernel_stack = kmalloc_aligned(16384, 16384);
|
||||
|
||||
// Map User stack to 0x800000 -> Note: ELFs might overwrite this if they load there!
|
||||
// But our ELF loader defaults 0x400000 for standard code.
|
||||
// Map User stack to 0x800000
|
||||
paging_map_page(new_proc->pml4_phys, 0x800000, v2p((uint64_t)stack), PT_PRESENT | PT_RW | PT_USER);
|
||||
|
||||
// 4. Build Stack Frame
|
||||
// Parse arguments and push them to the user stack
|
||||
// We'll place the strings at the very high end of the user stack
|
||||
int argc = 1;
|
||||
char *args_buf = (char *)stack + 4096;
|
||||
uint64_t user_args_buf = 0x800000 + 4096;
|
||||
|
||||
// Copy filepath as argv[0]
|
||||
int path_len = 0;
|
||||
while (filepath[path_len]) path_len++;
|
||||
args_buf -= (path_len + 1);
|
||||
user_args_buf -= (path_len + 1);
|
||||
for (int i = 0; i <= path_len; i++) args_buf[i] = filepath[i];
|
||||
|
||||
uint64_t argv_ptrs[32];
|
||||
argv_ptrs[0] = user_args_buf;
|
||||
|
||||
if (args_str) {
|
||||
int i = 0;
|
||||
while (args_str[i] && argc < 31) {
|
||||
// Skip spaces
|
||||
while (args_str[i] == ' ') i++;
|
||||
if (!args_str[i]) break;
|
||||
|
||||
int arg_start = i;
|
||||
bool in_quotes = false;
|
||||
|
||||
if (args_str[i] == '"') {
|
||||
in_quotes = true;
|
||||
i++;
|
||||
arg_start = i;
|
||||
while (args_str[i] && args_str[i] != '"') i++;
|
||||
} else {
|
||||
while (args_str[i] && args_str[i] != ' ') i++;
|
||||
}
|
||||
|
||||
int arg_len = i - arg_start;
|
||||
|
||||
args_buf -= (arg_len + 1);
|
||||
user_args_buf -= (arg_len + 1);
|
||||
|
||||
for (int k = 0; k < arg_len; k++) {
|
||||
args_buf[k] = args_str[arg_start + k];
|
||||
}
|
||||
args_buf[arg_len] = '\0';
|
||||
|
||||
argv_ptrs[argc++] = user_args_buf;
|
||||
|
||||
if (in_quotes && args_str[i] == '"') i++; // Skip closing quote
|
||||
}
|
||||
}
|
||||
argv_ptrs[argc] = 0; // Null terminator for argv
|
||||
|
||||
// Align stack to 8 bytes before pushing argv array
|
||||
uint64_t current_user_sp = user_args_buf;
|
||||
current_user_sp &= ~7ULL;
|
||||
args_buf = (char *)((uint64_t)stack + (current_user_sp - 0x800000));
|
||||
|
||||
// Push argv array
|
||||
int argv_size = (argc + 1) * sizeof(uint64_t);
|
||||
args_buf -= argv_size;
|
||||
current_user_sp -= argv_size;
|
||||
|
||||
uint64_t actual_argv_ptr = current_user_sp; // Store the true pointer to argv array
|
||||
|
||||
uint64_t *user_argv_array = (uint64_t *)args_buf;
|
||||
for (int i = 0; i <= argc; i++) {
|
||||
user_argv_array[i] = argv_ptrs[i];
|
||||
}
|
||||
|
||||
// Align stack to 16 bytes. crt0.asm does `and rsp, -16`, but it's good practice
|
||||
current_user_sp &= ~15ULL;
|
||||
|
||||
// 4. Build Stack Frame for context switch via IRETQ
|
||||
uint64_t* stack_ptr = (uint64_t*)((uint64_t)kernel_stack + 16384);
|
||||
*(--stack_ptr) = 0x1B; // SS (User Mode Data)
|
||||
*(--stack_ptr) = 0x800000 + 4096; // RSP
|
||||
*(--stack_ptr) = current_user_sp; // RSP (Updated user stack pointer)
|
||||
*(--stack_ptr) = 0x202; // RFLAGS (Interrupts Enabled)
|
||||
*(--stack_ptr) = 0x23; // CS (User Mode Code)
|
||||
*(--stack_ptr) = entry_point; // RIP
|
||||
@@ -142,7 +220,21 @@ void process_create_elf(const char* filepath) {
|
||||
*(--stack_ptr) = 0; // err_code
|
||||
|
||||
// 15 General purpose registers
|
||||
for (int i = 0; i < 15; i++) *(--stack_ptr) = 0;
|
||||
*(--stack_ptr) = 0; // RAX
|
||||
*(--stack_ptr) = 0; // RBX
|
||||
*(--stack_ptr) = 0; // RCX
|
||||
*(--stack_ptr) = 0; // RDX
|
||||
*(--stack_ptr) = 0; // RBP
|
||||
*(--stack_ptr) = argc; // RDI = argc
|
||||
*(--stack_ptr) = actual_argv_ptr; // RSI = actual argv array
|
||||
*(--stack_ptr) = 0; // R8
|
||||
*(--stack_ptr) = 0; // R9
|
||||
*(--stack_ptr) = 0; // R10
|
||||
*(--stack_ptr) = 0; // R11
|
||||
*(--stack_ptr) = 0; // R12
|
||||
*(--stack_ptr) = 0; // R13
|
||||
*(--stack_ptr) = 0; // R14
|
||||
*(--stack_ptr) = 0; // R15
|
||||
|
||||
new_proc->kernel_stack = (uint64_t)kernel_stack + 16384;
|
||||
new_proc->rsp = (uint64_t)stack_ptr;
|
||||
@@ -193,10 +285,20 @@ uint64_t process_terminate_current(void) {
|
||||
|
||||
// 1. Cleanup side effects
|
||||
if (current_process->ui_window) {
|
||||
extern void serial_write(const char *str);
|
||||
serial_write("PROC: Terminating proc with window\n");
|
||||
wm_remove_window((Window *)current_process->ui_window);
|
||||
current_process->ui_window = NULL;
|
||||
}
|
||||
|
||||
extern void fat32_close(struct FAT32_FileHandle *fh);
|
||||
for (int i = 0; i < MAX_PROCESS_FDS; i++) {
|
||||
if (current_process->fds[i]) {
|
||||
fat32_close(current_process->fds[i]);
|
||||
current_process->fds[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
extern void cmd_process_finished(void);
|
||||
cmd_process_finished();
|
||||
|
||||
@@ -234,9 +336,23 @@ uint64_t process_terminate_current(void) {
|
||||
|
||||
void process_push_gui_event(process_t *proc, gui_event_t *ev) {
|
||||
if (!proc) return;
|
||||
|
||||
// Coalesce PAINT events: if a PAINT event is already in the queue, don't add another
|
||||
if (ev->type == 1) { // GUI_EVENT_PAINT
|
||||
int curr = proc->gui_event_head;
|
||||
while (curr != proc->gui_event_tail) {
|
||||
if (proc->gui_events[curr].type == 1) {
|
||||
return; // Already has a paint event pending
|
||||
}
|
||||
curr = (curr + 1) % MAX_GUI_EVENTS;
|
||||
}
|
||||
}
|
||||
|
||||
int next_tail = (proc->gui_event_tail + 1) % MAX_GUI_EVENTS;
|
||||
// Drop event if queue is full
|
||||
if (next_tail == proc->gui_event_head) {
|
||||
extern void serial_write(const char *str);
|
||||
serial_write("PROC: GUI event queue full, dropping event!\n");
|
||||
return;
|
||||
}
|
||||
proc->gui_events[proc->gui_event_tail] = *ev;
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include "gui_ipc.h"
|
||||
|
||||
#define MAX_GUI_EVENTS 32
|
||||
#define MAX_PROCESS_FDS 16
|
||||
|
||||
struct FAT32_FileHandle;
|
||||
|
||||
// Registers saved on the stack by interrupts/exceptions
|
||||
typedef struct {
|
||||
@@ -27,12 +30,14 @@ typedef struct process {
|
||||
int gui_event_tail;
|
||||
void *ui_window; // Pointer to the active Window
|
||||
|
||||
void *fds[MAX_PROCESS_FDS];
|
||||
|
||||
struct process *next;
|
||||
} process_t;
|
||||
|
||||
void process_init(void);
|
||||
void process_create(void* entry_point, bool is_user);
|
||||
void process_create_elf(const char* filepath);
|
||||
void process_create_elf(const char* filepath, const char* args_str);
|
||||
process_t* process_get_current(void);
|
||||
uint64_t process_schedule(uint64_t current_rsp);
|
||||
uint64_t process_terminate_current(void);
|
||||
|
||||
@@ -34,3 +34,28 @@ process_jump_usermode:
|
||||
|
||||
; Jump to Ring 3!
|
||||
iretq
|
||||
|
||||
; void context_switch_to(uint64_t rsp)
|
||||
; Restores context from isr frame and jumps
|
||||
global context_switch_to
|
||||
context_switch_to:
|
||||
mov rsp, rdi
|
||||
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
pop rbp
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rbx
|
||||
pop rax
|
||||
|
||||
add rsp, 16 ; drop int_no and err_code
|
||||
iretq
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "gui_ipc.h"
|
||||
#include "process.h"
|
||||
#include "wm.h"
|
||||
#include "fat32.h"
|
||||
#include "fat32.h"
|
||||
|
||||
// Read MSR
|
||||
static inline uint64_t rdmsr(uint32_t msr) {
|
||||
@@ -67,6 +69,14 @@ static void user_window_click(Window *win, int x, int y) {
|
||||
process_push_gui_event(proc, &ev);
|
||||
}
|
||||
|
||||
static void user_window_key(Window *win, char c) {
|
||||
process_t *proc = (process_t *)win->data;
|
||||
if (!proc) return;
|
||||
gui_event_t ev = { .type = GUI_EVENT_KEY, .arg1 = (int)c };
|
||||
process_push_gui_event(proc, &ev);
|
||||
}
|
||||
|
||||
|
||||
uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) {
|
||||
extern void cmd_write(const char *str);
|
||||
extern void serial_write(const char *str);
|
||||
@@ -76,37 +86,60 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
||||
// arg2 is the buffer based on our user_test logic
|
||||
cmd_write((const char*)arg2);
|
||||
serial_write((const char*)arg2);
|
||||
} else if (syscall_num == 0) { // SYS_EXIT
|
||||
process_t *proc = process_get_current();
|
||||
if (proc && proc->ui_window) {
|
||||
wm_remove_window((Window *)proc->ui_window);
|
||||
proc->ui_window = NULL;
|
||||
}
|
||||
cmd_process_finished();
|
||||
// The actual process termination and scheduling will be handled later
|
||||
// For now this just releases the CMD prompt lock.
|
||||
// We will eventually need to mark the process_t as DEAD here.
|
||||
} else if (syscall_num == 0 || syscall_num == 60) { // SYS_EXIT
|
||||
serial_write("Kernel: SYS_EXIT called\n");
|
||||
uint64_t next_rsp = process_terminate_current();
|
||||
extern void context_switch_to(uint64_t rsp);
|
||||
context_switch_to(next_rsp);
|
||||
|
||||
// This point is never reached
|
||||
while(1);
|
||||
} else if (syscall_num == 3) { // SYS_GUI
|
||||
int cmd = (int)arg1;
|
||||
process_t *proc = process_get_current();
|
||||
|
||||
if (cmd == GUI_CMD_WINDOW_CREATE) {
|
||||
extern void serial_write(const char *str);
|
||||
serial_write("Kernel: GUI_CMD_WINDOW_CREATE\n");
|
||||
|
||||
const char *title = (const char *)arg2;
|
||||
uint64_t *params = (uint64_t *)arg3;
|
||||
if (!params) return 0;
|
||||
uint64_t *u_params = (uint64_t *)arg3;
|
||||
if (!u_params) {
|
||||
serial_write("Kernel: Error - params is NULL\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy params from user space to kernel space for safety
|
||||
uint64_t params[4];
|
||||
for (int i = 0; i < 4; i++) params[i] = u_params[i];
|
||||
|
||||
serial_write("Kernel: Window params copied.\n");
|
||||
|
||||
Window *win = kmalloc(sizeof(Window));
|
||||
if (!win) return 0;
|
||||
if (!win) {
|
||||
serial_write("Kernel: Error - kmalloc failed for Window\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
serial_write("Kernel: Window allocated.\n");
|
||||
|
||||
// Copy title from user space to kernel space so wm.c can access it safely
|
||||
int title_len = 0;
|
||||
if (title) {
|
||||
while (title[title_len] && title_len < 255) title_len++;
|
||||
}
|
||||
|
||||
char *kernel_title = kmalloc(title_len + 1);
|
||||
if (kernel_title) {
|
||||
for (int i = 0; i < title_len; i++) {
|
||||
kernel_title[i] = title[i];
|
||||
}
|
||||
kernel_title[title_len] = '\0';
|
||||
serial_write("Kernel: Title copied: ");
|
||||
serial_write(kernel_title);
|
||||
serial_write("\n");
|
||||
} else {
|
||||
serial_write("Kernel: Warning - kernel_title kmalloc failed\n");
|
||||
}
|
||||
|
||||
// Basic initialization
|
||||
@@ -116,6 +149,8 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
||||
win->w = (int)params[2];
|
||||
win->h = (int)params[3];
|
||||
|
||||
serial_write("Kernel: Init win dims.\n");
|
||||
|
||||
// Sanity checks for dimensions
|
||||
if (win->w <= 0 || win->w > 4096) win->w = 400;
|
||||
if (win->h <= 0 || win->h > 4096) win->h = 400;
|
||||
@@ -127,10 +162,15 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
||||
win->buffer[0] = 0;
|
||||
win->data = proc;
|
||||
|
||||
serial_write("Kernel: Dims initialized.\n");
|
||||
|
||||
// Safe allocation
|
||||
size_t pixel_size = (size_t)win->w * win->h * 4;
|
||||
win->pixels = kmalloc(pixel_size);
|
||||
win->comp_pixels = kmalloc(pixel_size);
|
||||
|
||||
serial_write("Kernel: Buffers allocated.\n");
|
||||
|
||||
if (win->pixels) {
|
||||
extern void mem_memset(void *dest, int val, size_t len);
|
||||
mem_memset(win->pixels, 0, pixel_size);
|
||||
@@ -140,10 +180,13 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
||||
mem_memset(win->comp_pixels, 0, pixel_size);
|
||||
}
|
||||
|
||||
serial_write("Kernel: Buffers cleared.\n");
|
||||
|
||||
// Set callbacks
|
||||
win->paint = user_window_paint;
|
||||
win->handle_click = user_window_click;
|
||||
win->handle_close = user_window_close;
|
||||
win->handle_key = NULL;
|
||||
win->handle_key = user_window_key;
|
||||
win->handle_right_click = NULL;
|
||||
|
||||
proc->ui_window = win;
|
||||
@@ -152,9 +195,12 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
||||
return (uint64_t)win;
|
||||
} else if (cmd == GUI_CMD_DRAW_RECT) {
|
||||
Window *win = (Window *)arg2;
|
||||
uint64_t *p = (uint64_t *)arg3;
|
||||
uint64_t *u_params = (uint64_t *)arg3;
|
||||
uint32_t color = (uint32_t)arg4;
|
||||
if (win && p) {
|
||||
if (win && u_params) {
|
||||
uint64_t params[4];
|
||||
for (int i = 0; i < 4; i++) params[i] = u_params[i];
|
||||
|
||||
extern void draw_rect(int x, int y, int w, int h, uint32_t color);
|
||||
extern void graphics_set_render_target(uint32_t *buffer, int w, int h);
|
||||
|
||||
@@ -163,8 +209,8 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
||||
|
||||
if (win->pixels) {
|
||||
// Strict user-to-window relative clamping
|
||||
int rx = (int)p[0]; int ry = (int)p[1];
|
||||
int rw = (int)p[2]; int rh = (int)p[3];
|
||||
int rx = (int)params[0]; int ry = (int)params[1];
|
||||
int rw = (int)params[2]; int rh = (int)params[3];
|
||||
if (rx < 0) { rw += rx; rx = 0; }
|
||||
if (ry < 0) { rh += ry; ry = 0; }
|
||||
if (rx + rw > win->w) rw = win->w - rx;
|
||||
@@ -176,16 +222,19 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
||||
graphics_set_render_target(NULL, 0, 0);
|
||||
}
|
||||
} else {
|
||||
draw_rect(win->x + p[0], win->y + p[1], p[2], p[3], color);
|
||||
draw_rect(win->x + params[0], win->y + params[1], params[2], params[3], color);
|
||||
}
|
||||
|
||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||
}
|
||||
} else if (cmd == GUI_CMD_DRAW_ROUNDED_RECT_FILLED) {
|
||||
Window *win = (Window *)arg2;
|
||||
uint64_t *p = (uint64_t *)arg3;
|
||||
uint64_t *u_params = (uint64_t *)arg3;
|
||||
uint32_t color = (uint32_t)arg4;
|
||||
if (win && p) {
|
||||
if (win && u_params) {
|
||||
uint64_t params[5];
|
||||
for (int i = 0; i < 5; i++) params[i] = u_params[i];
|
||||
|
||||
extern void draw_rounded_rect_filled(int x, int y, int w, int h, int radius, uint32_t color);
|
||||
extern void graphics_set_render_target(uint32_t *buffer, int w, int h);
|
||||
|
||||
@@ -193,9 +242,9 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||
|
||||
if (win->pixels) {
|
||||
int rx = (int)p[0]; int ry = (int)p[1];
|
||||
int rw = (int)p[2]; int rh = (int)p[3];
|
||||
int rr = (int)p[4];
|
||||
int rx = (int)params[0]; int ry = (int)params[1];
|
||||
int rw = (int)params[2]; int rh = (int)params[3];
|
||||
int rr = (int)params[4];
|
||||
if (rx < 0) { rw += rx; rx = 0; }
|
||||
if (ry < 0) { rh += ry; ry = 0; }
|
||||
if (rx + rw > win->w) rw = win->w - rx;
|
||||
@@ -206,8 +255,6 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
||||
draw_rounded_rect_filled(rx, ry, rw, rh, rr, color);
|
||||
graphics_set_render_target(NULL, 0, 0);
|
||||
}
|
||||
} else {
|
||||
draw_rounded_rect_filled(win->x + p[0], win->y + p[1], p[2], p[3], p[4], color);
|
||||
}
|
||||
|
||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||
@@ -251,14 +298,17 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
||||
}
|
||||
} else if (cmd == GUI_CMD_MARK_DIRTY) {
|
||||
Window *win = (Window *)arg2;
|
||||
uint64_t *p = (uint64_t *)arg3;
|
||||
if (win && p) {
|
||||
uint64_t *u_params = (uint64_t *)arg3;
|
||||
if (win && u_params) {
|
||||
uint64_t params[4];
|
||||
for (int i = 0; i < 4; i++) params[i] = u_params[i];
|
||||
|
||||
// Dual-buffer commit: copy pixels to comp_pixels
|
||||
if (win->pixels && win->comp_pixels) {
|
||||
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);
|
||||
}
|
||||
wm_mark_dirty(win->x + p[0], win->y + p[1], p[2], p[3]);
|
||||
wm_mark_dirty(win->x + (int)params[0], win->y + (int)params[1], (int)params[2], (int)params[3]);
|
||||
}
|
||||
} else if (cmd == GUI_CMD_GET_EVENT) {
|
||||
Window *win = (Window *)arg2;
|
||||
@@ -271,6 +321,83 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} else if (syscall_num == SYS_FS) {
|
||||
int cmd = (int)arg1;
|
||||
process_t *proc = process_get_current();
|
||||
|
||||
if (cmd == FS_CMD_OPEN) {
|
||||
const char *path = (const char *)arg2;
|
||||
const char *mode = (const char *)arg3;
|
||||
if (!path || !mode) return -1;
|
||||
|
||||
FAT32_FileHandle *fh = fat32_open(path, mode);
|
||||
if (!fh) return -1;
|
||||
|
||||
for (int i = 0; i < MAX_PROCESS_FDS; i++) {
|
||||
if (proc->fds[i] == NULL) {
|
||||
proc->fds[i] = fh;
|
||||
return (uint64_t)i;
|
||||
}
|
||||
}
|
||||
fat32_close(fh);
|
||||
return -1;
|
||||
} else if (cmd == FS_CMD_READ) {
|
||||
int fd = (int)arg2;
|
||||
void *buf = (void *)arg3;
|
||||
uint32_t len = (uint32_t)arg4;
|
||||
if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1;
|
||||
return (uint64_t)fat32_read((FAT32_FileHandle*)proc->fds[fd], buf, (int)len);
|
||||
} else if (cmd == FS_CMD_WRITE) {
|
||||
int fd = (int)arg2;
|
||||
const void *buf = (const void *)arg3;
|
||||
uint32_t len = (uint32_t)arg4;
|
||||
if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1;
|
||||
return (uint64_t)fat32_write((FAT32_FileHandle*)proc->fds[fd], buf, (int)len);
|
||||
} else if (cmd == FS_CMD_CLOSE) {
|
||||
int fd = (int)arg2;
|
||||
if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1;
|
||||
fat32_close((FAT32_FileHandle*)proc->fds[fd]);
|
||||
proc->fds[fd] = NULL;
|
||||
return 0;
|
||||
} else if (cmd == FS_CMD_SEEK) {
|
||||
int fd = (int)arg2;
|
||||
int offset = (int)arg3;
|
||||
int whence = (int)arg4; // 0=SET, 1=CUR, 2=END
|
||||
if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1;
|
||||
return (uint64_t)fat32_seek((FAT32_FileHandle*)proc->fds[fd], offset, whence);
|
||||
} else if (cmd == FS_CMD_TELL) {
|
||||
int fd = (int)arg2;
|
||||
if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1;
|
||||
return (uint64_t)((FAT32_FileHandle*)proc->fds[fd])->position;
|
||||
} else if (cmd == FS_CMD_SIZE) {
|
||||
int fd = (int)arg2;
|
||||
if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1;
|
||||
return (uint64_t)((FAT32_FileHandle*)proc->fds[fd])->size;
|
||||
}
|
||||
else if (cmd == FS_CMD_LIST) {
|
||||
const char *path = (const char *)arg2;
|
||||
FAT32_FileInfo *entries = (FAT32_FileInfo *)arg3;
|
||||
int max_entries = (int)arg4;
|
||||
if (!path || !entries) return -1;
|
||||
return (uint64_t)fat32_list_directory(path, entries, max_entries);
|
||||
} else if (cmd == FS_CMD_DELETE) {
|
||||
const char *path = (const char *)arg2;
|
||||
if (!path) return -1;
|
||||
return fat32_delete(path) ? 0 : -1;
|
||||
} else if (cmd == FS_CMD_MKDIR) {
|
||||
const char *path = (const char *)arg2;
|
||||
if (!path) return -1;
|
||||
return fat32_mkdir(path) ? 0 : -1;
|
||||
} else if (cmd == FS_CMD_EXISTS) {
|
||||
const char *path = (const char *)arg2;
|
||||
if (!path) return 0;
|
||||
return fat32_exists(path) ? 1 : 0;
|
||||
}
|
||||
return 0;
|
||||
} else if (syscall_num == 8) { // DEBUG_SERIAL_WRITE
|
||||
extern void serial_write(const char *str);
|
||||
serial_write((const char *)arg2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -12,8 +12,23 @@
|
||||
|
||||
// Syscall Numbers
|
||||
#define SYS_WRITE 1
|
||||
#define SYS_GUI 3
|
||||
#define SYS_FS 4
|
||||
#define SYS_EXIT 60
|
||||
|
||||
// FS Commands
|
||||
#define FS_CMD_OPEN 1
|
||||
#define FS_CMD_READ 2
|
||||
#define FS_CMD_WRITE 3
|
||||
#define FS_CMD_CLOSE 4
|
||||
#define FS_CMD_SEEK 5
|
||||
#define FS_CMD_TELL 6
|
||||
#define FS_CMD_LIST 7
|
||||
#define FS_CMD_DELETE 8
|
||||
#define FS_CMD_SIZE 9
|
||||
#define FS_CMD_MKDIR 10
|
||||
#define FS_CMD_EXISTS 11
|
||||
|
||||
void syscall_init(void);
|
||||
uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5);
|
||||
|
||||
|
||||
@@ -257,6 +257,9 @@ int main(void) {
|
||||
} else if (ev.type == GUI_EVENT_CLOSE) {
|
||||
sys_exit(0);
|
||||
}
|
||||
} else {
|
||||
// Avoid high CPU usage
|
||||
for(volatile int i=0; i<10000; i++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -12,9 +12,6 @@ _start:
|
||||
and rsp, -16
|
||||
|
||||
; Call main(argc, argv)
|
||||
; We don't have argc or argv yet, pass 0
|
||||
xor rdi, rdi
|
||||
xor rsi, rsi
|
||||
call main
|
||||
|
||||
; If main returns, call exit(status)
|
||||
|
||||
Binary file not shown.
@@ -1,7 +1,42 @@
|
||||
#include "syscall.h"
|
||||
|
||||
int main() {
|
||||
int strlen(const char* str) {
|
||||
int len = 0;
|
||||
while(str[len]) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
void print_int(int n) {
|
||||
char buf[16];
|
||||
if (n == 0) {
|
||||
sys_write(1, "0", 1);
|
||||
return;
|
||||
}
|
||||
int i = 0;
|
||||
while(n > 0) {
|
||||
buf[i++] = (n % 10) + '0';
|
||||
n /= 10;
|
||||
}
|
||||
for(int j = i - 1; j >= 0; j--) {
|
||||
sys_write(1, &buf[j], 1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char* msg = "Hello from Userland ELF!\n";
|
||||
sys_write(1, msg, 25);
|
||||
|
||||
sys_write(1, "argc: ", 6);
|
||||
print_int(argc);
|
||||
sys_write(1, "\n", 1);
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
sys_write(1, "argv[", 5);
|
||||
print_int(i);
|
||||
sys_write(1, "]: ", 3);
|
||||
sys_write(1, argv[i], strlen(argv[i]));
|
||||
sys_write(1, "\n", 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,6 @@
|
||||
#include "libui.h"
|
||||
#include "syscall.h"
|
||||
#include "syscall_user.h"
|
||||
#include <stddef.h>
|
||||
|
||||
extern uint64_t syscall3(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define GUI_EVENT_CLICK 2
|
||||
#define GUI_EVENT_RIGHT_CLICK 3
|
||||
#define GUI_EVENT_CLOSE 4
|
||||
#define GUI_EVENT_KEY 5
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
@@ -26,7 +27,7 @@ typedef struct {
|
||||
} gui_event_t;
|
||||
|
||||
// Window Handle
|
||||
typedef int ui_window_t;
|
||||
typedef uint64_t ui_window_t;
|
||||
|
||||
// libui API
|
||||
ui_window_t ui_window_create(const char *title, int x, int y, int w, int h);
|
||||
|
||||
@@ -69,3 +69,48 @@ void sys_exit(int status) {
|
||||
int sys_write(int fd, const char *buf, int len) {
|
||||
return (int)syscall3(SYS_WRITE, (uint64_t)fd, (uint64_t)buf, (uint64_t)len);
|
||||
}
|
||||
|
||||
int sys_open(const char *path, const char *mode) {
|
||||
return (int)syscall3(SYS_FS, FS_CMD_OPEN, (uint64_t)path, (uint64_t)mode);
|
||||
}
|
||||
|
||||
int sys_read(int fd, void *buf, uint32_t len) {
|
||||
return (int)syscall4(SYS_FS, FS_CMD_READ, (uint64_t)fd, (uint64_t)buf, (uint64_t)len);
|
||||
}
|
||||
|
||||
int sys_write_fs(int fd, const void *buf, uint32_t len) {
|
||||
return (int)syscall4(SYS_FS, FS_CMD_WRITE, (uint64_t)fd, (uint64_t)buf, (uint64_t)len);
|
||||
}
|
||||
|
||||
void sys_close(int fd) {
|
||||
syscall2(SYS_FS, FS_CMD_CLOSE, (uint64_t)fd);
|
||||
}
|
||||
|
||||
int sys_seek(int fd, int offset, int whence) {
|
||||
return (int)syscall4(SYS_FS, FS_CMD_SEEK, (uint64_t)fd, (uint64_t)offset, (uint64_t)whence);
|
||||
}
|
||||
|
||||
uint32_t sys_tell(int fd) {
|
||||
return (uint32_t)syscall2(SYS_FS, FS_CMD_TELL, (uint64_t)fd);
|
||||
}
|
||||
|
||||
uint32_t sys_size(int fd) {
|
||||
return (uint32_t)syscall2(SYS_FS, FS_CMD_SIZE, (uint64_t)fd);
|
||||
}
|
||||
|
||||
int sys_list(const char *path, struct FAT32_FileInfo *entries, int max_entries) {
|
||||
return (int)syscall4(SYS_FS, FS_CMD_LIST, (uint64_t)path, (uint64_t)entries, (uint64_t)max_entries);
|
||||
}
|
||||
|
||||
int sys_delete(const char *path) {
|
||||
return (int)syscall2(SYS_FS, FS_CMD_DELETE, (uint64_t)path);
|
||||
}
|
||||
|
||||
int sys_mkdir(const char *path) {
|
||||
return (int)syscall2(SYS_FS, FS_CMD_MKDIR, (uint64_t)path);
|
||||
}
|
||||
|
||||
int sys_exists(const char *path) {
|
||||
return (int)syscall2(SYS_FS, FS_CMD_EXISTS, (uint64_t)path);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,21 @@
|
||||
// Standard syscalls available from Kernel mode
|
||||
#define SYS_EXIT 0
|
||||
#define SYS_WRITE 1
|
||||
#define SYS_GUI 3
|
||||
#define SYS_FS 4
|
||||
|
||||
// FS Commands
|
||||
#define FS_CMD_OPEN 1
|
||||
#define FS_CMD_READ 2
|
||||
#define FS_CMD_WRITE 3
|
||||
#define FS_CMD_CLOSE 4
|
||||
#define FS_CMD_SEEK 5
|
||||
#define FS_CMD_TELL 6
|
||||
#define FS_CMD_LIST 7
|
||||
#define FS_CMD_DELETE 8
|
||||
#define FS_CMD_SIZE 9
|
||||
#define FS_CMD_MKDIR 10
|
||||
#define FS_CMD_EXISTS 11
|
||||
|
||||
// Internal assembly entry into Ring 0
|
||||
extern uint64_t syscall0(uint64_t sys_num);
|
||||
@@ -19,4 +34,19 @@ extern uint64_t syscall5(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_
|
||||
void sys_exit(int status);
|
||||
int sys_write(int fd, const char *buf, int len);
|
||||
|
||||
// FS API
|
||||
int sys_open(const char *path, const char *mode);
|
||||
int sys_read(int fd, void *buf, uint32_t len);
|
||||
int sys_write_fs(int fd, const void *buf, uint32_t len);
|
||||
void sys_close(int fd);
|
||||
int sys_seek(int fd, int offset, int whence);
|
||||
uint32_t sys_tell(int fd);
|
||||
uint32_t sys_size(int fd);
|
||||
int sys_delete(const char *path);
|
||||
int sys_mkdir(const char *path);
|
||||
int sys_exists(const char *path);
|
||||
|
||||
struct FAT32_FileInfo;
|
||||
int sys_list(const char *path, struct FAT32_FileInfo *entries, int max_entries);
|
||||
|
||||
#endif
|
||||
|
||||
Binary file not shown.
11
src/kernel/userland/libc/syscall_user.h
Normal file
11
src/kernel/userland/libc/syscall_user.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef SYSCALL_USER_H
|
||||
#define SYSCALL_USER_H
|
||||
|
||||
#include "syscall.h"
|
||||
#include <stddef.h>
|
||||
|
||||
static inline void sys_serial_write(const char *str) {
|
||||
syscall2(8, 0, (uint64_t)str);
|
||||
}
|
||||
|
||||
#endif
|
||||
251
src/kernel/userland/notepad.c
Normal file
251
src/kernel/userland/notepad.c
Normal file
@@ -0,0 +1,251 @@
|
||||
#include "libc/syscall.h"
|
||||
#include "libc/libui.h"
|
||||
#include "libc/syscall_user.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#define COLOR_NOTEPAD_BG 0xFFFFFFFF
|
||||
#define COLOR_BLACK 0xFF000000
|
||||
|
||||
#define NOTEPAD_BUF_SIZE (64 * 1024)
|
||||
static char buffer[NOTEPAD_BUF_SIZE];
|
||||
static int buf_len = 0;
|
||||
static int cursor_pos = 0;
|
||||
static int notepad_scroll_line = 0;
|
||||
|
||||
static void notepad_ensure_cursor_visible(int h) {
|
||||
int visible_lines = (h - 40) / 10 + 3;
|
||||
if (visible_lines < 1) visible_lines = 1;
|
||||
|
||||
int cursor_line = 0;
|
||||
for (int i = 0; i < cursor_pos && i < buf_len; i++) {
|
||||
if (buffer[i] == '\n') cursor_line++;
|
||||
}
|
||||
|
||||
if (cursor_line < notepad_scroll_line) {
|
||||
notepad_scroll_line = cursor_line;
|
||||
}
|
||||
|
||||
if (cursor_line >= notepad_scroll_line + visible_lines) {
|
||||
notepad_scroll_line = cursor_line - visible_lines + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void notepad_load_state() {
|
||||
int fd = sys_open("A:/tmp/notepad_state.txt", "r");
|
||||
if (fd >= 0) {
|
||||
sys_serial_write("Notepad: Loading state...\n");
|
||||
buf_len = sys_read(fd, buffer, NOTEPAD_BUF_SIZE - 1);
|
||||
if (buf_len < 0) buf_len = 0;
|
||||
buffer[buf_len] = 0;
|
||||
sys_close(fd);
|
||||
}
|
||||
cursor_pos = buf_len;
|
||||
}
|
||||
|
||||
static void notepad_save_state() {
|
||||
// Ensure dir exists
|
||||
sys_mkdir("A:/tmp");
|
||||
int fd = sys_open("A:/tmp/notepad_state.txt", "w");
|
||||
if (fd >= 0) {
|
||||
sys_write_fs(fd, buffer, buf_len);
|
||||
sys_close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void notepad_paint(ui_window_t win, int w, int h) {
|
||||
ui_draw_rect(win, 4, 30, w - 8, h - 34, COLOR_NOTEPAD_BG);
|
||||
|
||||
int visual_line = 0;
|
||||
int current_x = 8;
|
||||
int current_y = 36;
|
||||
int window_right = w - 16;
|
||||
|
||||
for (int i = 0; i < buf_len; i++) {
|
||||
if (visual_line < notepad_scroll_line) {
|
||||
if (buffer[i] == '\n') {
|
||||
visual_line++;
|
||||
current_x = 8;
|
||||
current_y = 36;
|
||||
} else {
|
||||
if (current_x >= window_right) {
|
||||
visual_line++;
|
||||
current_x = 8;
|
||||
current_y += 10;
|
||||
}
|
||||
current_x += 8;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (visual_line >= notepad_scroll_line + (h - 40) / 10) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (buffer[i] == '\n') {
|
||||
current_x = 8;
|
||||
current_y += 10;
|
||||
visual_line++;
|
||||
} else {
|
||||
if (current_x >= window_right) {
|
||||
current_x = 8;
|
||||
current_y += 10;
|
||||
visual_line++;
|
||||
|
||||
if (visual_line >= notepad_scroll_line + (h - 40) / 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char ch[2] = {buffer[i], 0};
|
||||
ui_draw_string(win, current_x, current_y, ch, COLOR_BLACK);
|
||||
current_x += 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Cursor
|
||||
int cx = 8;
|
||||
int cy = 36;
|
||||
int c_visual_line = 0;
|
||||
|
||||
for (int i = 0; i < cursor_pos; i++) {
|
||||
if (buffer[i] == '\n') {
|
||||
cx = 8;
|
||||
cy += 10;
|
||||
c_visual_line++;
|
||||
} else {
|
||||
if (cx >= window_right) {
|
||||
cx = 8;
|
||||
cy += 10;
|
||||
c_visual_line++;
|
||||
}
|
||||
cx += 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (c_visual_line >= notepad_scroll_line &&
|
||||
c_visual_line < notepad_scroll_line + (h - 40) / 10) {
|
||||
ui_draw_rect(win, cx, cy, 2, 8, COLOR_BLACK);
|
||||
}
|
||||
|
||||
ui_mark_dirty(win, 0, 0, w, h);
|
||||
}
|
||||
|
||||
static void notepad_key(ui_window_t win, int h, char c) {
|
||||
if (c == 17) { // UP
|
||||
if (cursor_pos > 0) {
|
||||
int curr = cursor_pos;
|
||||
int line_start = curr;
|
||||
while (line_start > 0 && buffer[line_start - 1] != '\n') {
|
||||
line_start--;
|
||||
}
|
||||
int col = curr - line_start;
|
||||
|
||||
if (line_start > 0) {
|
||||
int prev_line_end = line_start - 1;
|
||||
int prev_line_start = prev_line_end;
|
||||
while (prev_line_start > 0 && buffer[prev_line_start - 1] != '\n') {
|
||||
prev_line_start--;
|
||||
}
|
||||
int prev_line_len = prev_line_end - prev_line_start;
|
||||
if (col > prev_line_len) col = prev_line_len;
|
||||
cursor_pos = prev_line_start + col;
|
||||
}
|
||||
}
|
||||
} else if (c == 18) { // DOWN
|
||||
if (cursor_pos < buf_len) {
|
||||
int curr = cursor_pos;
|
||||
int line_start = curr;
|
||||
while (line_start > 0 && buffer[line_start - 1] != '\n') {
|
||||
line_start--;
|
||||
}
|
||||
int col = curr - line_start;
|
||||
|
||||
int next_line_start = curr;
|
||||
while (next_line_start < buf_len && buffer[next_line_start] != '\n') {
|
||||
next_line_start++;
|
||||
}
|
||||
|
||||
if (next_line_start < buf_len) {
|
||||
next_line_start++; // Skip newline
|
||||
int next_line_end = next_line_start;
|
||||
while (next_line_end < buf_len && buffer[next_line_end] != '\n') {
|
||||
next_line_end++;
|
||||
}
|
||||
int next_line_len = next_line_end - next_line_start;
|
||||
if (col > next_line_len) col = next_line_len;
|
||||
cursor_pos = next_line_start + col;
|
||||
} else {
|
||||
cursor_pos = buf_len;
|
||||
}
|
||||
}
|
||||
} else if (c == 19) { // LEFT
|
||||
if (cursor_pos > 0) cursor_pos--;
|
||||
} else if (c == 20) { // RIGHT
|
||||
if (cursor_pos < buf_len) cursor_pos++;
|
||||
} else if (c == '\b') { // Backspace
|
||||
if (cursor_pos > 0) {
|
||||
for (int i = cursor_pos; i < buf_len; i++) {
|
||||
buffer[i - 1] = buffer[i];
|
||||
}
|
||||
buf_len--;
|
||||
cursor_pos--;
|
||||
buffer[buf_len] = 0;
|
||||
}
|
||||
} else if (c == '\n') { // Enter
|
||||
if (buf_len < 1023) {
|
||||
for (int i = buf_len; i > cursor_pos; i--) {
|
||||
buffer[i] = buffer[i - 1];
|
||||
}
|
||||
buffer[cursor_pos] = c;
|
||||
buf_len++;
|
||||
cursor_pos++;
|
||||
buffer[buf_len] = 0;
|
||||
}
|
||||
} else {
|
||||
if (buf_len < NOTEPAD_BUF_SIZE - 1) {
|
||||
for (int i = buf_len; i > cursor_pos; i--) {
|
||||
buffer[i] = buffer[i - 1];
|
||||
}
|
||||
buffer[cursor_pos] = c;
|
||||
buf_len++;
|
||||
cursor_pos++;
|
||||
buffer[buf_len] = 0;
|
||||
}
|
||||
}
|
||||
notepad_ensure_cursor_visible(h);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
sys_serial_write("Notepad: Starting userspace main...\n");
|
||||
ui_window_t win = ui_window_create("Notepad", 100, 100, 400, 300);
|
||||
if (win == 0) {
|
||||
sys_serial_write("Notepad: Failed to create window!\n");
|
||||
return 1;
|
||||
}
|
||||
sys_serial_write("Notepad: Window created successfully.\n");
|
||||
|
||||
notepad_load_state();
|
||||
|
||||
gui_event_t ev;
|
||||
sys_serial_write("Notepad: Entering event loop...\n");
|
||||
while (1) {
|
||||
if (ui_get_event(win, &ev)) {
|
||||
if (ev.type == GUI_EVENT_PAINT) {
|
||||
notepad_paint(win, 400, 300);
|
||||
} else if (ev.type == GUI_EVENT_KEY) {
|
||||
notepad_key(win, 300, (char)ev.arg1);
|
||||
notepad_paint(win, 400, 300);
|
||||
} else if (ev.type == GUI_EVENT_CLOSE) {
|
||||
sys_serial_write("Notepad: CLOSE\n");
|
||||
notepad_save_state();
|
||||
sys_exit(0);
|
||||
}
|
||||
} 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++);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
src/kernel/userland/notepad.elf
Executable file
BIN
src/kernel/userland/notepad.elf
Executable file
Binary file not shown.
100
src/kernel/wm.c
100
src/kernel/wm.c
@@ -9,7 +9,7 @@
|
||||
#include "markdown.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "notepad.h"
|
||||
|
||||
#include "viewer.h"
|
||||
#include "wallpaper.h"
|
||||
#include "control_panel.h"
|
||||
@@ -21,6 +21,17 @@
|
||||
#include "paint.h"
|
||||
#include "disk.h"
|
||||
|
||||
extern void serial_write(const char *str);
|
||||
|
||||
static bool str_eq(const char *s1, const char *s2) {
|
||||
if (!s1 || !s2) return false;
|
||||
while (*s1 && *s2) {
|
||||
if (*s1 != *s2) return false;
|
||||
s1++; s2++;
|
||||
}
|
||||
return (*s1 == *s2);
|
||||
}
|
||||
|
||||
// --- State ---
|
||||
static int mx = 400, my = 300; // Mouse Pos
|
||||
static int prev_mx = 400, prev_my = 300; // Previous mouse position
|
||||
@@ -120,10 +131,6 @@ static bool str_starts_with(const char *str, const char *prefix) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int str_eq(const char *s1, const char *s2) {
|
||||
while (*s1 && (*s1 == *s2)) { s1++; s2++; }
|
||||
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
|
||||
}
|
||||
|
||||
static void refresh_desktop_icons(void) {
|
||||
// Update limit in FS
|
||||
@@ -1344,9 +1351,24 @@ void wm_add_window(Window *win) {
|
||||
}
|
||||
}
|
||||
|
||||
Window* wm_find_window_by_title(const char *title) {
|
||||
if (!title) return NULL;
|
||||
for (int i = 0; i < window_count; i++) {
|
||||
if (all_windows[i] && all_windows[i]->title && str_eq(all_windows[i]->title, title)) {
|
||||
return all_windows[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void wm_remove_window(Window *win) {
|
||||
if (!win) return;
|
||||
|
||||
serial_write("WM: Removing window '");
|
||||
if (win->title) serial_write(win->title);
|
||||
else serial_write("unknown");
|
||||
serial_write("'\n");
|
||||
|
||||
int index = -1;
|
||||
for (int i = 0; i < window_count; i++) {
|
||||
if (all_windows[i] == win) {
|
||||
@@ -1375,6 +1397,8 @@ void wm_remove_window(Window *win) {
|
||||
|
||||
kfree(win);
|
||||
force_redraw = true;
|
||||
} else {
|
||||
serial_write("WM: Window not found in all_windows list!\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1824,13 +1848,23 @@ void wm_handle_right_click(int x, int y) {
|
||||
if (str_starts_with(start_menu_pending_app, "Files")) {
|
||||
explorer_open_directory("/");
|
||||
} else if (str_starts_with(start_menu_pending_app, "Notepad")) {
|
||||
wm_bring_to_front(&win_notepad);
|
||||
Window *existing = wm_find_window_by_title("Notepad");
|
||||
if (existing) {
|
||||
wm_bring_to_front(existing);
|
||||
} else {
|
||||
process_create_elf("/bin/notepad.elf", NULL);
|
||||
}
|
||||
} else if (str_starts_with(start_menu_pending_app, "Editor")) {
|
||||
wm_bring_to_front(&win_editor);
|
||||
} 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")) {
|
||||
process_create_elf("/bin/calculator.elf");
|
||||
Window *existing = wm_find_window_by_title("Calculator");
|
||||
if (existing) {
|
||||
wm_bring_to_front(existing);
|
||||
} else {
|
||||
process_create_elf("/bin/calculator.elf", NULL);
|
||||
}
|
||||
} else if (str_starts_with(start_menu_pending_app, "Minesweeper")) {
|
||||
wm_bring_to_front(&win_minesweeper);
|
||||
} else if (str_starts_with(start_menu_pending_app, "Settings")) {
|
||||
@@ -1858,9 +1892,9 @@ void wm_handle_right_click(int x, int y) {
|
||||
if (icon->type == 2) { // App Shortcut
|
||||
// Check name to launch app
|
||||
if (str_ends_with(icon->name, "Notepad.shortcut")) {
|
||||
wm_bring_to_front(&win_notepad); handled = true;
|
||||
process_create_elf("/bin/notepad.elf", NULL); handled = true;
|
||||
} else if (str_ends_with(icon->name, "Calculator.shortcut")) {
|
||||
process_create_elf("/bin/calculator.elf"); handled = true;
|
||||
process_create_elf("/bin/calculator.elf", NULL); handled = true;
|
||||
} else if (str_ends_with(icon->name, "Minesweeper.shortcut")) {
|
||||
wm_bring_to_front(&win_minesweeper); handled = true;
|
||||
} else if (str_ends_with(icon->name, "Settings.shortcut")) {
|
||||
@@ -1912,7 +1946,7 @@ void wm_handle_right_click(int x, int y) {
|
||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||
|
||||
if (str_ends_with(icon->name, ".elf")) {
|
||||
process_create_elf(path);
|
||||
process_create_elf(path, NULL);
|
||||
} else if (str_ends_with(icon->name, ".pnt")) {
|
||||
paint_load(path);
|
||||
wm_bring_to_front(&win_paint);
|
||||
@@ -2254,7 +2288,6 @@ void wm_init(void) {
|
||||
disk_manager_scan();
|
||||
// Drives are now dynamically managed - only real drives are registered
|
||||
|
||||
notepad_init();
|
||||
cmd_init();
|
||||
explorer_init();
|
||||
editor_init();
|
||||
@@ -2269,37 +2302,32 @@ void wm_init(void) {
|
||||
refresh_desktop_icons();
|
||||
|
||||
// Initialize z-indices
|
||||
win_notepad.z_index = 0;
|
||||
win_cmd.z_index = 1;
|
||||
win_explorer.z_index = 2;
|
||||
win_editor.z_index = 3;
|
||||
win_markdown.z_index = 4;
|
||||
win_control_panel.z_index = 5;
|
||||
win_about.z_index = 6;
|
||||
win_minesweeper.z_index = 7;
|
||||
win_paint.z_index = 8;
|
||||
win_cmd.z_index = 0;
|
||||
win_explorer.z_index = 1;
|
||||
win_editor.z_index = 2;
|
||||
win_markdown.z_index = 3;
|
||||
win_control_panel.z_index = 4;
|
||||
win_about.z_index = 5;
|
||||
win_minesweeper.z_index = 6;
|
||||
win_paint.z_index = 7;
|
||||
win_viewer.z_index = 8;
|
||||
|
||||
all_windows[0] = &win_notepad;
|
||||
all_windows[1] = &win_cmd;
|
||||
all_windows[2] = &win_explorer;
|
||||
all_windows[3] = &win_editor;
|
||||
all_windows[4] = &win_markdown;
|
||||
all_windows[5] = &win_control_panel;
|
||||
all_windows[6] = &win_about;
|
||||
all_windows[7] = &win_minesweeper;
|
||||
all_windows[8] = &win_paint;
|
||||
all_windows[9] = &win_viewer;
|
||||
window_count = 10;
|
||||
all_windows[0] = &win_cmd;
|
||||
all_windows[1] = &win_explorer;
|
||||
all_windows[2] = &win_editor;
|
||||
all_windows[3] = &win_markdown;
|
||||
all_windows[4] = &win_control_panel;
|
||||
all_windows[5] = &win_about;
|
||||
all_windows[6] = &win_minesweeper;
|
||||
all_windows[7] = &win_paint;
|
||||
all_windows[8] = &win_viewer;
|
||||
window_count = 9;
|
||||
|
||||
// Only show Explorer and Notepad on desktop (Explorer on top)
|
||||
// Only show Explorer on desktop (initially hidden)
|
||||
win_explorer.visible = false;
|
||||
win_explorer.focused = false;
|
||||
win_explorer.z_index = 10;
|
||||
|
||||
win_notepad.visible = false;
|
||||
win_notepad.focused = false;
|
||||
win_notepad.z_index = 9;
|
||||
|
||||
// Rest are hidden initially
|
||||
win_cmd.visible = false;
|
||||
win_editor.visible = false;
|
||||
|
||||
@@ -68,6 +68,7 @@ void wm_process_input(void);
|
||||
void wm_add_window(Window *win);
|
||||
void wm_remove_window(Window *win);
|
||||
void wm_bring_to_front(Window *win);
|
||||
Window* wm_find_window_by_title(const char *title);
|
||||
|
||||
// Redraw system
|
||||
void wm_mark_dirty(int x, int y, int w, int h);
|
||||
|
||||
Reference in New Issue
Block a user