mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
Notepad port to userspace and bug fixes
This commit is contained in:
parent
23ec181f29
commit
c2ead0d6a7
67 changed files with 828 additions and 399 deletions
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.
BIN
disk.img
BIN
disk.img
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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
|
|
@ -1 +1 @@
|
|||
Subproject commit efd130dbb649983cd3a7667b6cfa4f6e5d8a3da6
|
||||
Subproject commit 38ff2c855aabb92e4cfa2cc7ef0c8af665ecba94
|
||||
|
|
@ -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,22 +134,107 @@ 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
|
||||
*(--stack_ptr) = entry_point; // RIP
|
||||
*(--stack_ptr) = 0; // int_no
|
||||
*(--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;
|
||||
while (title[title_len] && title_len < 255) title_len++;
|
||||
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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue