mirror of
https://github.com/JannisHeydemann/BoredOS.git
synced 2026-05-30 10:26:59 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0ab5021c4 | ||
|
|
90f86d63dc | ||
|
|
36d7137969 | ||
|
|
e939d50be6 | ||
|
|
9a4b7b05ff | ||
|
|
23972f8951 |
2
Makefile
2
Makefile
@@ -119,4 +119,4 @@ run: $(ISO_IMAGE)
|
|||||||
qemu-system-x86_64 -m 2G -serial stdio -cdrom $(ISO_IMAGE) -boot d \
|
qemu-system-x86_64 -m 2G -serial stdio -cdrom $(ISO_IMAGE) -boot d \
|
||||||
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 \
|
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 \
|
||||||
-netdev user,id=net0,hostfwd=udp::12345-:12345 -device e1000,netdev=net0 \
|
-netdev user,id=net0,hostfwd=udp::12345-:12345 -device e1000,netdev=net0 \
|
||||||
-vga std -global VGA.xres=1280 -global VGA.yres=800
|
-vga std -global VGA.xres=1920 -global VGA.yres=1080
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Brew OS 1.42 Beta
|
# Brew OS 1.45 Beta
|
||||||
BrewOS is now in a Beta stage as i have brought over all apps from brewkernel and have made the DE a lot more usable and stable.
|
BrewOS is now in a Beta stage as i have brought over all apps from brewkernel and have made the DE a lot more usable and stable.
|
||||||
|
|
||||||
## Brewkernel is now BrewOS!
|
## Brewkernel is now BrewOS!
|
||||||
|
|||||||
BIN
brewos.iso
BIN
brewos.iso
Binary file not shown.
BIN
build/about.o
BIN
build/about.o
Binary file not shown.
BIN
build/brewos.elf
BIN
build/brewos.elf
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/editor.o
BIN
build/editor.o
Binary file not shown.
BIN
build/explorer.o
BIN
build/explorer.o
Binary file not shown.
BIN
build/fat32.o
BIN
build/fat32.o
Binary file not shown.
BIN
build/graphics.o
BIN
build/graphics.o
Binary file not shown.
BIN
build/markdown.o
BIN
build/markdown.o
Binary file not shown.
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/tcp.o
BIN
build/tcp.o
Binary file not shown.
BIN
build/wm.o
BIN
build/wm.o
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
# Brew OS 1.42 Beta
|
# Brew OS 1.45 Beta
|
||||||
BrewOS is now in a Beta stage as i have brought over all apps from brewkernel and have made the DE a lot more usable and stable.
|
BrewOS is now in a Beta stage as i have brought over all apps from brewkernel and have made the DE a lot more usable and stable.
|
||||||
|
|
||||||
## Brewkernel is now BrewOS!
|
## Brewkernel is now BrewOS!
|
||||||
|
|||||||
Binary file not shown.
@@ -1,12 +1,8 @@
|
|||||||
# Timeout in seconds that Limine will wait before automatically booting.
|
|
||||||
TIMEOUT=3
|
TIMEOUT=3
|
||||||
|
|
||||||
# The entry name that will be displayed in the boot menu.
|
|
||||||
:BrewOS
|
:BrewOS
|
||||||
# We use the Limine boot protocol.
|
|
||||||
PROTOCOL=limine
|
PROTOCOL=limine
|
||||||
|
|
||||||
# Path to the kernel to boot. boot:/// represents the partition on which limine.cfg is located.
|
|
||||||
KERNEL_PATH=boot:///brewos.elf
|
KERNEL_PATH=boot:///brewos.elf
|
||||||
|
|
||||||
#FRAMEBUFFER_WIDTH=1280
|
#FRAMEBUFFER_WIDTH=1280
|
||||||
|
|||||||
2
limine
2
limine
Submodule limine updated: 9e0258b727...efd130dbb6
@@ -1,12 +1,8 @@
|
|||||||
# Timeout in seconds that Limine will wait before automatically booting.
|
|
||||||
TIMEOUT=3
|
TIMEOUT=3
|
||||||
|
|
||||||
# The entry name that will be displayed in the boot menu.
|
|
||||||
:BrewOS
|
:BrewOS
|
||||||
# We use the Limine boot protocol.
|
|
||||||
PROTOCOL=limine
|
PROTOCOL=limine
|
||||||
|
|
||||||
# Path to the kernel to boot. boot:/// represents the partition on which limine.cfg is located.
|
|
||||||
KERNEL_PATH=boot:///brewos.elf
|
KERNEL_PATH=boot:///brewos.elf
|
||||||
|
|
||||||
#FRAMEBUFFER_WIDTH=1280
|
#FRAMEBUFFER_WIDTH=1280
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
/* Tell the linker that we want an x86_64 ELF64 output file */
|
|
||||||
OUTPUT_FORMAT(elf64-x86-64)
|
OUTPUT_FORMAT(elf64-x86-64)
|
||||||
OUTPUT_ARCH(i386:x86-64)
|
OUTPUT_ARCH(i386:x86-64)
|
||||||
|
|
||||||
/* We want the symbol _start to be our entry point */
|
|
||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
|
|
||||||
/* Define the memory layout for the kernel */
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
/* We want to be loaded in the upper half of memory */
|
|
||||||
. = 0xffffffff80000000;
|
. = 0xffffffff80000000;
|
||||||
|
|
||||||
.text : {
|
.text : {
|
||||||
|
|||||||
@@ -14,9 +14,6 @@ Window win_about;
|
|||||||
#define COLOR_CYAN_LOGO 0xFF368DF7
|
#define COLOR_CYAN_LOGO 0xFF368DF7
|
||||||
|
|
||||||
static void about_paint(Window *win) {
|
static void about_paint(Window *win) {
|
||||||
// Background
|
|
||||||
draw_rect(win->x + 4, win->y + 24, win->w - 8, win->h - 28, COLOR_LTGRAY);
|
|
||||||
|
|
||||||
int offset_x = win->x + 15;
|
int offset_x = win->x + 15;
|
||||||
int offset_y = win->y + 35;
|
int offset_y = win->y + 35;
|
||||||
|
|
||||||
@@ -35,7 +32,7 @@ static void about_paint(Window *win) {
|
|||||||
|
|
||||||
// Version info
|
// Version info
|
||||||
draw_string(offset_x, offset_y + 105, "BrewOS", COLOR_BLACK);
|
draw_string(offset_x, offset_y + 105, "BrewOS", COLOR_BLACK);
|
||||||
draw_string(offset_x, offset_y + 120, "BrewOS Version 1.42", COLOR_BLACK);
|
draw_string(offset_x, offset_y + 120, "BrewOS Version 1.45", COLOR_BLACK);
|
||||||
draw_string(offset_x, offset_y + 135, "Kernel Version 2.3.1", COLOR_BLACK);
|
draw_string(offset_x, offset_y + 135, "Kernel Version 2.3.1", COLOR_BLACK);
|
||||||
|
|
||||||
// Copyright
|
// Copyright
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ _start:
|
|||||||
; Ensure interrupts are disabled
|
; Ensure interrupts are disabled
|
||||||
cli
|
cli
|
||||||
|
|
||||||
; Setup stack is handled by Limine, but we can re-align if paranoid
|
|
||||||
; (Limine guarantees 16-byte alignment)
|
; (Limine guarantees 16-byte alignment)
|
||||||
|
|
||||||
; Call the C kernel entry point
|
; Call the C kernel entry point
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ static void fixed_to_str(long long n, char *buf) {
|
|||||||
}
|
}
|
||||||
frac_buf[f_idx] = 0;
|
frac_buf[f_idx] = 0;
|
||||||
|
|
||||||
// If we have a fraction, add it to buffer (reversed first)
|
|
||||||
if (f_idx > 0) {
|
if (f_idx > 0) {
|
||||||
for (int i = f_idx - 1; i >= 0; i--) {
|
for (int i = f_idx - 1; i >= 0; i--) {
|
||||||
temp[pos++] = frac_buf[i];
|
temp[pos++] = frac_buf[i];
|
||||||
@@ -247,7 +246,7 @@ static void calculator_click(Window *win, int x, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update_display(win);
|
update_display(win);
|
||||||
wm_paint(); // Request repaint
|
wm_mark_dirty(win->x, win->y, win->w, win->h);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
|
|
||||||
void cli_cmd_brewver(char *args) {
|
void cli_cmd_brewver(char *args) {
|
||||||
(void)args;
|
(void)args;
|
||||||
cli_write("BrewOS v1.42 Beta\n");
|
cli_write("BrewOS v1.45 Beta\n");
|
||||||
cli_write("BrewOS Kernel V2.3.1 Beta\n");
|
cli_write("BrewOS Kernel V2.3.1 Beta\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,7 +140,6 @@ void cli_cmd_udptest(char *args){
|
|||||||
|
|
||||||
void cli_cmd_msgrc(char *args) {
|
void cli_cmd_msgrc(char *args) {
|
||||||
(void)args;
|
(void)args;
|
||||||
// Reset message count since we are viewing them
|
|
||||||
cmd_reset_msg_count();
|
cmd_reset_msg_count();
|
||||||
|
|
||||||
FAT32_FileHandle *fh = fat32_open("messages", "r");
|
FAT32_FileHandle *fh = fat32_open("messages", "r");
|
||||||
|
|||||||
@@ -800,7 +800,7 @@ static void cmd_paint(Window *win) {
|
|||||||
int offset_y = win->y + 24;
|
int offset_y = win->y + 24;
|
||||||
|
|
||||||
// Fill background
|
// Fill background
|
||||||
draw_rect(offset_x, offset_y, win->w - 8, win->h - 28, COLOR_BLACK);
|
draw_rect(win->x + 4, win->y + 24, win->w - 8, win->h - 28, COLOR_BLACK);
|
||||||
|
|
||||||
int start_y = offset_y + 4;
|
int start_y = offset_y + 4;
|
||||||
int start_x = offset_x + 4;
|
int start_x = offset_x + 4;
|
||||||
@@ -957,7 +957,7 @@ static void create_test_files(void) {
|
|||||||
fh = fat32_open("README.md", "w");
|
fh = fat32_open("README.md", "w");
|
||||||
if (fh) {
|
if (fh) {
|
||||||
const char *content =
|
const char *content =
|
||||||
"# Brew OS 1.40 Beta\n\n"
|
"# Brew OS 1.44 Beta\n\n"
|
||||||
"BrewOS is now in a Beta stage as i have brought over all apps from brewkernel and have made the DE a lot more usable and stable.\n"
|
"BrewOS is now in a Beta stage as i have brought over all apps from brewkernel and have made the DE a lot more usable and stable.\n"
|
||||||
"## Brewkernel is now BrewOS!\n"
|
"## Brewkernel is now BrewOS!\n"
|
||||||
"Brewkernel will from now on be deprecated as it's core became too messy. I have built a less bloated kernel and wrote a DE above it, which is why it is now an OS instead of a kernel (in my opinion).\n\n"
|
"Brewkernel will from now on be deprecated as it's core became too messy. I have built a less bloated kernel and wrote a DE above it, which is why it is now an OS instead of a kernel (in my opinion).\n\n"
|
||||||
@@ -1056,7 +1056,7 @@ static void create_test_files(void) {
|
|||||||
const char *content =
|
const char *content =
|
||||||
"# All compiled C files in this directory are openable from any other directory by typing in the name of the compiled file by typing in the name of the compiled file.\n\n"
|
"# All compiled C files in this directory are openable from any other directory by typing in the name of the compiled file by typing in the name of the compiled file.\n\n"
|
||||||
"The c file 'wordofgod.c' contains a C program similar to one in TempleOS, which Terry A. Davis (RIP) saw as 'words from god' telling him what to do with his kernel.\n"
|
"The c file 'wordofgod.c' contains a C program similar to one in TempleOS, which Terry A. Davis (RIP) saw as 'words from god' telling him what to do with his kernel.\n"
|
||||||
"I made this file as a tribute to him, as he also inspired me to create this project in '24. If you want to run it you simply do cc (or compc) wordgod.c and then run ./wordgod \n";
|
"I made this file as a tribute to him, as he also inspired me to create this project in '24. If you want to run it you simply do cc (or compc) wordofgod.c and then run ./wordofgod \n";
|
||||||
fat32_write(fh, (void *)content, cmd_strlen(content));
|
fat32_write(fh, (void *)content, cmd_strlen(content));
|
||||||
fat32_close(fh);
|
fat32_close(fh);
|
||||||
}
|
}
|
||||||
@@ -1093,16 +1093,16 @@ static void create_test_files(void) {
|
|||||||
"poke(l+40,\"day \");poke(l+44,\"night \");poke(l+48,\"waters \");poke(l+52,\"firmament \");poke(l+56,\"evening \");poke(l+60,\"morning \");poke(l+64,\"land \");poke(l+68,\"seas \");poke(l+72,\"grass \");poke(l+76,\"herb \");",
|
"poke(l+40,\"day \");poke(l+44,\"night \");poke(l+48,\"waters \");poke(l+52,\"firmament \");poke(l+56,\"evening \");poke(l+60,\"morning \");poke(l+64,\"land \");poke(l+68,\"seas \");poke(l+72,\"grass \");poke(l+76,\"herb \");",
|
||||||
"poke(l+80,\"seed \");poke(l+84,\"fruit \");poke(l+88,\"tree \");poke(l+92,\"sun \");poke(l+96,\"moon \");poke(l+100,\"stars \");poke(l+104,\"signs \");poke(l+108,\"seasons \");poke(l+112,\"days \");poke(l+116,\"years \");",
|
"poke(l+80,\"seed \");poke(l+84,\"fruit \");poke(l+88,\"tree \");poke(l+92,\"sun \");poke(l+96,\"moon \");poke(l+100,\"stars \");poke(l+104,\"signs \");poke(l+108,\"seasons \");poke(l+112,\"days \");poke(l+116,\"years \");",
|
||||||
"poke(l+120,\"creature \");poke(l+124,\"life \");poke(l+128,\"fowl \");poke(l+132,\"whales \");poke(l+136,\"cattle \");poke(l+140,\"creeping \");poke(l+144,\"beast \");poke(l+148,\"man \");poke(l+152,\"image \");poke(l+156,\"likeness \");",
|
"poke(l+120,\"creature \");poke(l+124,\"life \");poke(l+128,\"fowl \");poke(l+132,\"whales \");poke(l+136,\"cattle \");poke(l+140,\"creeping \");poke(l+144,\"beast \");poke(l+148,\"man \");poke(l+152,\"image \");poke(l+156,\"likeness \");",
|
||||||
"poke(l+160,\"dominion \");poke(l+164,\"fish \");poke(l+168,\"air \");poke(l+172,\"every \");poke(l+176,\"CIA \");poke(l+180,\"meat \");poke(l+184,\"holy \");poke(l+188,\"rest \");poke(l+192,\"dust \");poke(l+196,\"breath \");",
|
"poke(l+160,\"dominion \");poke(l+164,\"fish \");poke(l+168,\"air \");poke(l+172,\"every \");poke(l+176,\"CIA \");poke(l+180,\"Epstein Files \");poke(l+184,\"holy \");poke(l+188,\"rest \");poke(l+192,\"dust \");poke(l+196,\"breath \");",
|
||||||
"poke(l+200,\"soul \");poke(l+204,\"garden \");poke(l+208,\"east \");poke(l+212,\"Eden \");poke(l+216,\"ground \");poke(l+220,\"sight \");poke(l+224,\"good \");poke(l+228,\"evil \");poke(l+232,\"river \");poke(l+236,\"gold \");",
|
"poke(l+200,\"soul \");poke(l+204,\"garden \");poke(l+208,\"east \");poke(l+212,\"Eden \");poke(l+216,\"ground \");poke(l+220,\"sight \");poke(l+224,\"good \");poke(l+228,\"evil \");poke(l+232,\"river \");poke(l+236,\"gold \");",
|
||||||
"poke(l+240,\"stone \");poke(l+244,\"woman \");poke(l+248,\"wife \");poke(l+252,\"flesh \");poke(l+256,\"bone \");poke(l+260,\"naked \");poke(l+264,\"serpent \");poke(l+268,\"subtle \");poke(l+272,\"eat \");poke(l+276,\"eyes \");",
|
"poke(l+240,\"stone \");poke(l+244,\"woman \");poke(l+248,\"wife \");poke(l+252,\"flesh \");poke(l+256,\"bone \");poke(l+260,\"naked \");poke(l+264,\"serpent \");poke(l+268,\"subtle \");poke(l+272,\"eat \");poke(l+276,\"eyes \");",
|
||||||
"poke(l+280,\"wise \");poke(l+284,\"cool \");poke(l+288,\"voice \");poke(l+292,\"fear \");poke(l+296,\"hid \");poke(l+300,\"cursed \");poke(l+304,\"belly \");poke(l+308,\"enmity \");poke(l+312,\"sorrow \");poke(l+316,\"conception \");",
|
"poke(l+280,\"wise \");poke(l+284,\"cool \");poke(l+288,\"voice \");poke(l+292,\"fear \");poke(l+296,\"hid \");poke(l+300,\"cursed \");poke(l+304,\"belly \");poke(l+308,\"enmity \");poke(l+312,\"sorrow \");poke(l+316,\"conception \");",
|
||||||
"poke(l+320,\"children \");poke(l+324,\"desire \");poke(l+328,\"husband \");poke(l+332,\"thorns \");poke(l+336,\"thistles \");poke(l+340,\"sweat \");poke(l+344,\"bread \");poke(l+348,\"mother \");poke(l+352,\"skin \");poke(l+356,\"coats \");",
|
"poke(l+320,\"children \");poke(l+324,\"desire \");poke(l+328,\"husband \");poke(l+332,\"lava \");poke(l+336,\"thistles \");poke(l+340,\"sweat \");poke(l+344,\"bread \");poke(l+348,\"mother \");poke(l+352,\"skin \");poke(l+356,\"coats \");",
|
||||||
"poke(l+360,\"cherubims \");poke(l+364,\"sword \");poke(l+368,\"gate \");poke(l+372,\"offering \");poke(l+376,\"respect \");poke(l+380,\"sin \");poke(l+384,\"door \");poke(l+388,\"blood \");poke(l+392,\"brother \");poke(l+396,\"keeper \");",
|
"poke(l+360,\"cherubims \");poke(l+364,\"sword \");poke(l+368,\"gate \");poke(l+372,\"offering \");poke(l+376,\"obsidian \");poke(l+380,\"sin \");poke(l+384,\"door \");poke(l+388,\"blood \");poke(l+392,\"brother \");poke(l+396,\"keeper \");",
|
||||||
"poke(l+400,\"voice \");poke(l+404,\"heard \");poke(l+408,\"walking \");poke(l+412,\"cool \");poke(l+416,\"day \");poke(l+420,\"where \");poke(l+424,\"art \");poke(l+428,\"thou \");poke(l+432,\"told \");poke(l+436,\"thee \");",
|
"poke(l+400,\"voice \");poke(l+404,\"heard \");poke(l+408,\"walking \");poke(l+412,\"cool \");poke(l+416,\"day \");poke(l+420,\"where \");poke(l+424,\"art \");poke(l+428,\"thou \");poke(l+432,\"told \");poke(l+436,\"thee \");",
|
||||||
"poke(l+440,\"hast \");poke(l+444,\"eaten \");poke(l+448,\"tree \");poke(l+452,\"whereof \");poke(l+456,\"commanded \");poke(l+460,\"shouldest \");poke(l+464,\"not \");poke(l+468,\"eat \");poke(l+472,\"gave \");poke(l+476,\"me \");",
|
"poke(l+440,\"hast \");poke(l+444,\"eaten \");poke(l+448,\"tree \");poke(l+452,\"minecraft \");poke(l+456,\"commanded \");poke(l+460,\"shouldest \");poke(l+464,\"not \");poke(l+468,\"eat \");poke(l+472,\"gave \");poke(l+476,\"me \");",
|
||||||
"poke(l+480,\"beguiled \");poke(l+484,\"belly \");poke(l+488,\"go \");poke(l+492,\"dust \");poke(l+496,\"shalt \");poke(l+500,\"eat \");poke(l+504,\"days \");poke(l+508,\"life \");poke(l+512,\"put \");poke(l+516,\"enmity \");",
|
"poke(l+480,\"beguiled \");poke(l+484,\"belly \");poke(l+488,\"go \");poke(l+492,\"dust \");poke(l+496,\"shalt \");poke(l+500,\"eat \");poke(l+504,\"days \");poke(l+508,\"life \");poke(l+512,\"put \");poke(l+516,\"enmity \");",
|
||||||
"poke(l+520,\"between \");poke(l+524,\"seed \");poke(l+528,\"bruise \");poke(l+532,\"head \");poke(l+536,\"heel \");poke(l+540,\"multiply \");poke(l+544,\"sorrow \");poke(l+548,\"conception \");poke(l+552,\"forth \");poke(l+556,\"children \");",
|
"poke(l+520,\"between \");poke(l+524,\"seed \");poke(l+528,\"ICE \");poke(l+532,\"Detainment Facility \");poke(l+536,\"heel \");poke(l+540,\"multiply \");poke(l+544,\"sorrow \");poke(l+548,\"conception \");poke(l+552,\"forth \");poke(l+556,\"children \");",
|
||||||
"poke(l+560,\"desire \");poke(l+564,\"rule \");poke(l+568,\"over \");poke(l+572,\"sake \");poke(l+576,\"sweat \");poke(l+580,\"face \");poke(l+584,\"till \");poke(l+588,\"return \");poke(l+592,\"ground \");poke(l+596,\"taken \");",
|
"poke(l+560,\"desire \");poke(l+564,\"rule \");poke(l+568,\"over \");poke(l+572,\"sake \");poke(l+576,\"sweat \");poke(l+580,\"face \");poke(l+584,\"till \");poke(l+588,\"return \");poke(l+592,\"ground \");poke(l+596,\"taken \");",
|
||||||
"poke(l+600,\"mother \");poke(l+604,\"living \");poke(l+608,\"coats \");poke(l+612,\"skins \");poke(l+616,\"clothed \");poke(l+620,\"become \");poke(l+624,\"one \");poke(l+628,\"us \");poke(l+632,\"know \");poke(l+636,\"good \");",
|
"poke(l+600,\"mother \");poke(l+604,\"living \");poke(l+608,\"coats \");poke(l+612,\"skins \");poke(l+616,\"clothed \");poke(l+620,\"become \");poke(l+624,\"one \");poke(l+628,\"us \");poke(l+632,\"know \");poke(l+636,\"good \");",
|
||||||
"poke(l+640,\"evil \");poke(l+644,\"lest \");poke(l+648,\"put \");poke(l+652,\"hand \");poke(l+656,\"take \");poke(l+660,\"live \");poke(l+664,\"ever \");poke(l+668,\"sent \");poke(l+672,\"garden \");poke(l+676,\"eden \");",
|
"poke(l+640,\"evil \");poke(l+644,\"lest \");poke(l+648,\"put \");poke(l+652,\"hand \");poke(l+656,\"take \");poke(l+660,\"live \");poke(l+664,\"ever \");poke(l+668,\"sent \");poke(l+672,\"garden \");poke(l+676,\"eden \");",
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ static void editor_paint(Window *win) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fill editor background
|
// Fill editor background
|
||||||
draw_rect(offset_x, offset_y + 30, content_width, content_height - 55, COLOR_WHITE);
|
draw_rect(win->x + 4, win->y + 54, win->w - 8, win->h - 58, COLOR_WHITE);
|
||||||
|
|
||||||
// Calculate available width for text (accounting for line numbers)
|
// Calculate available width for text (accounting for line numbers)
|
||||||
int text_start_x = offset_x + 40;
|
int text_start_x = offset_x + 40;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,9 @@
|
|||||||
#define EXPLORER_H
|
#define EXPLORER_H
|
||||||
|
|
||||||
#include "wm.h"
|
#include "wm.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// External windows references (for opening other apps)
|
||||||
extern Window win_explorer;
|
extern Window win_explorer;
|
||||||
extern Window win_editor;
|
extern Window win_editor;
|
||||||
extern Window win_cmd;
|
extern Window win_cmd;
|
||||||
@@ -10,27 +12,73 @@ extern Window win_notepad;
|
|||||||
extern Window win_calculator;
|
extern Window win_calculator;
|
||||||
extern Window win_markdown;
|
extern Window win_markdown;
|
||||||
|
|
||||||
|
#define EXPLORER_MAX_FILES 64
|
||||||
|
#define DIALOG_INPUT_MAX 256
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char name[256];
|
||||||
|
bool is_directory;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t color;
|
||||||
|
} ExplorerItem;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ExplorerItem items[EXPLORER_MAX_FILES];
|
||||||
|
int item_count;
|
||||||
|
int selected_item;
|
||||||
|
char current_path[256];
|
||||||
|
int last_clicked_item;
|
||||||
|
uint32_t last_click_time;
|
||||||
|
int explorer_scroll_row;
|
||||||
|
|
||||||
|
// Dialog state
|
||||||
|
int dialog_state;
|
||||||
|
char dialog_input[DIALOG_INPUT_MAX];
|
||||||
|
int dialog_input_cursor;
|
||||||
|
char dialog_target_path[256];
|
||||||
|
bool dialog_target_is_dir;
|
||||||
|
char dialog_dest_dir[256];
|
||||||
|
char dialog_creation_path[256];
|
||||||
|
char dialog_move_src[256];
|
||||||
|
|
||||||
|
// Dropdown menu state
|
||||||
|
bool dropdown_menu_visible;
|
||||||
|
|
||||||
|
// File context menu state
|
||||||
|
bool file_context_menu_visible;
|
||||||
|
int file_context_menu_x;
|
||||||
|
int file_context_menu_y;
|
||||||
|
int file_context_menu_item;
|
||||||
|
|
||||||
|
} ExplorerState;
|
||||||
|
|
||||||
void explorer_init(void);
|
void explorer_init(void);
|
||||||
void explorer_reset(void);
|
void explorer_reset(void);
|
||||||
void explorer_refresh(void);
|
void explorer_open_directory(const char *path); // Creates a NEW window
|
||||||
void explorer_clear_click_state(void);
|
|
||||||
|
|
||||||
// Drag and Drop support
|
// Drag and Drop support
|
||||||
|
// This now needs to find WHICH explorer window is under the mouse
|
||||||
bool explorer_get_file_at(int screen_x, int screen_y, char *out_path, bool *is_dir);
|
bool explorer_get_file_at(int screen_x, int screen_y, char *out_path, bool *is_dir);
|
||||||
void explorer_import_file(const char *source_path);
|
void explorer_import_file(Window *win, const char *source_path); // To focused or default
|
||||||
void explorer_import_file_to(const char *source_path, const char *dest_dir);
|
void explorer_import_file_to(Window *win, const char *source_path, const char *dest_dir);
|
||||||
|
void explorer_refresh(Window *win);
|
||||||
|
void explorer_refresh_all(void);
|
||||||
|
void explorer_clear_click_state(Window *win);
|
||||||
|
|
||||||
// Clipboard
|
// String Helpers
|
||||||
|
size_t explorer_strlen(const char *str);
|
||||||
|
void explorer_strcpy(char *dest, const char *src);
|
||||||
|
void explorer_strcat(char *dest, const char *src);
|
||||||
|
|
||||||
|
// Clipboard (System-wide)
|
||||||
void explorer_clipboard_copy(const char *path);
|
void explorer_clipboard_copy(const char *path);
|
||||||
void explorer_clipboard_cut(const char *path);
|
void explorer_clipboard_cut(const char *path);
|
||||||
void explorer_clipboard_paste(const char *dest_dir);
|
void explorer_clipboard_paste(Window *win, const char *dest_dir);
|
||||||
bool explorer_clipboard_has_content(void);
|
bool explorer_clipboard_has_content(void);
|
||||||
|
|
||||||
// File Operations
|
// File Operations
|
||||||
bool explorer_delete_permanently(const char *path);
|
bool explorer_delete_permanently(const char *path);
|
||||||
bool explorer_delete_recursive(const char *path);
|
bool explorer_delete_recursive(const char *path);
|
||||||
void explorer_create_shortcut(const char *target_path);
|
void explorer_create_shortcut(Window *win, const char *target_path);
|
||||||
|
|
||||||
void explorer_open_directory(const char *path);
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
#include "fat32.h"
|
#include "fat32.h"
|
||||||
|
#include "memory_manager.h"
|
||||||
|
#include "io.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
@@ -116,6 +118,9 @@ static void extract_parent_path(const char *path, char *parent) {
|
|||||||
|
|
||||||
// Normalize path (remove .., ., etc)
|
// Normalize path (remove .., ., etc)
|
||||||
void fat32_normalize_path(const char *path, char *normalized) {
|
void fat32_normalize_path(const char *path, char *normalized) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
|
|
||||||
char temp[FAT32_MAX_PATH];
|
char temp[FAT32_MAX_PATH];
|
||||||
int temp_len = 0;
|
int temp_len = 0;
|
||||||
|
|
||||||
@@ -173,6 +178,7 @@ void fat32_normalize_path(const char *path, char *normalized) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fs_strcpy(normalized, temp);
|
fs_strcpy(normalized, temp);
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find file entry by path
|
// Find file entry by path
|
||||||
@@ -237,8 +243,10 @@ static bool check_desktop_limit(const char *normalized_path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Count files in /Desktop
|
// Count files in /Desktop
|
||||||
FAT32_FileInfo info[256]; // Temp buffer
|
FAT32_FileInfo *info = (FAT32_FileInfo*)kmalloc(256 * sizeof(FAT32_FileInfo));
|
||||||
|
if (!info) return true;
|
||||||
int count = fat32_list_directory("/Desktop", info, 256);
|
int count = fat32_list_directory("/Desktop", info, 256);
|
||||||
|
kfree(info);
|
||||||
if (count >= desktop_file_limit) return false;
|
if (count >= desktop_file_limit) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -276,6 +284,9 @@ void fat32_set_desktop_limit(int limit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FAT32_FileHandle* fat32_open(const char *path, const char *mode) {
|
FAT32_FileHandle* fat32_open(const char *path, const char *mode) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
|
|
||||||
char normalized[FAT32_MAX_PATH];
|
char normalized[FAT32_MAX_PATH];
|
||||||
fat32_normalize_path(path, normalized);
|
fat32_normalize_path(path, normalized);
|
||||||
|
|
||||||
@@ -284,24 +295,32 @@ FAT32_FileHandle* fat32_open(const char *path, const char *mode) {
|
|||||||
if (mode[0] == 'r') {
|
if (mode[0] == 'r') {
|
||||||
// Read mode
|
// Read mode
|
||||||
if (!entry || (entry->attributes & ATTR_DIRECTORY)) {
|
if (!entry || (entry->attributes & ATTR_DIRECTORY)) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return NULL; // File not found or is directory
|
return NULL; // File not found or is directory
|
||||||
}
|
}
|
||||||
} else if (mode[0] == 'w' || (mode[0] == 'a')) {
|
} else if (mode[0] == 'w' || (mode[0] == 'a')) {
|
||||||
// Write/append mode - create if not exists
|
// Write/append mode - create if not exists
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
if (!check_desktop_limit(normalized)) {
|
if (!check_desktop_limit(normalized)) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = find_free_entry();
|
entry = find_free_entry();
|
||||||
if (!entry) return NULL;
|
if (!entry) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
entry->used = true;
|
entry->used = true;
|
||||||
fs_strcpy(entry->full_path, normalized);
|
fs_strcpy(entry->full_path, normalized);
|
||||||
extract_filename(normalized, entry->filename);
|
extract_filename(normalized, entry->filename);
|
||||||
extract_parent_path(normalized, entry->parent_path);
|
extract_parent_path(normalized, entry->parent_path);
|
||||||
entry->start_cluster = allocate_cluster();
|
entry->start_cluster = allocate_cluster();
|
||||||
if (!entry->start_cluster) return NULL;
|
if (!entry->start_cluster) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
entry->size = 0;
|
entry->size = 0;
|
||||||
entry->attributes = 0; // Regular file
|
entry->attributes = 0; // Regular file
|
||||||
}
|
}
|
||||||
@@ -313,7 +332,10 @@ FAT32_FileHandle* fat32_open(const char *path, const char *mode) {
|
|||||||
|
|
||||||
// Find free handle
|
// Find free handle
|
||||||
FAT32_FileHandle *handle = find_free_handle();
|
FAT32_FileHandle *handle = find_free_handle();
|
||||||
if (!handle) return NULL;
|
if (!handle) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
handle->valid = true;
|
handle->valid = true;
|
||||||
handle->cluster = entry->start_cluster;
|
handle->cluster = entry->start_cluster;
|
||||||
@@ -341,17 +363,24 @@ FAT32_FileHandle* fat32_open(const char *path, const char *mode) {
|
|||||||
handle->cluster = current_cluster;
|
handle->cluster = current_cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fat32_close(FAT32_FileHandle *handle) {
|
void fat32_close(FAT32_FileHandle *handle) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
if (handle) {
|
if (handle) {
|
||||||
handle->valid = false;
|
handle->valid = false;
|
||||||
}
|
}
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
}
|
}
|
||||||
|
|
||||||
int fat32_read(FAT32_FileHandle *handle, void *buffer, int size) {
|
int fat32_read(FAT32_FileHandle *handle, void *buffer, int size) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
if (!handle || !handle->valid || handle->mode != 0) {
|
if (!handle || !handle->valid || handle->mode != 0) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,11 +417,15 @@ int fat32_read(FAT32_FileHandle *handle, void *buffer, int size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return bytes_read;
|
return bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fat32_write(FAT32_FileHandle *handle, const void *buffer, int size) {
|
int fat32_write(FAT32_FileHandle *handle, const void *buffer, int size) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
if (!handle || !handle->valid || (handle->mode != 1 && handle->mode != 2)) {
|
if (!handle || !handle->valid || (handle->mode != 1 && handle->mode != 2)) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,7 +437,10 @@ int fat32_write(FAT32_FileHandle *handle, const void *buffer, int size) {
|
|||||||
uint32_t next = fat_table[handle->cluster];
|
uint32_t next = fat_table[handle->cluster];
|
||||||
if (next >= 0xFFFFFFF8) {
|
if (next >= 0xFFFFFFF8) {
|
||||||
next = allocate_cluster();
|
next = allocate_cluster();
|
||||||
if (!next) return 0;
|
if (!next) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
fat_table[handle->cluster] = next;
|
fat_table[handle->cluster] = next;
|
||||||
}
|
}
|
||||||
handle->cluster = next;
|
handle->cluster = next;
|
||||||
@@ -451,11 +487,15 @@ int fat32_write(FAT32_FileHandle *handle, const void *buffer, int size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return bytes_written;
|
return bytes_written;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fat32_seek(FAT32_FileHandle *handle, int offset, int whence) {
|
int fat32_seek(FAT32_FileHandle *handle, int offset, int whence) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
if (!handle || !handle->valid) {
|
if (!handle || !handle->valid) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,23 +514,31 @@ int fat32_seek(FAT32_FileHandle *handle, int offset, int whence) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handle->position = new_position;
|
handle->position = new_position;
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return new_position;
|
return new_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fat32_mkdir(const char *path) {
|
bool fat32_mkdir(const char *path) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
char normalized[FAT32_MAX_PATH];
|
char normalized[FAT32_MAX_PATH];
|
||||||
fat32_normalize_path(path, normalized);
|
fat32_normalize_path(path, normalized);
|
||||||
|
|
||||||
if (find_file(normalized)) {
|
if (find_file(normalized)) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return false; // Already exists
|
return false; // Already exists
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!check_desktop_limit(normalized)) {
|
if (!check_desktop_limit(normalized)) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileEntry *entry = find_free_entry();
|
FileEntry *entry = find_free_entry();
|
||||||
if (!entry) return false;
|
if (!entry) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
entry->used = true;
|
entry->used = true;
|
||||||
fs_strcpy(entry->full_path, normalized);
|
fs_strcpy(entry->full_path, normalized);
|
||||||
@@ -500,43 +548,58 @@ bool fat32_mkdir(const char *path) {
|
|||||||
entry->size = 0;
|
entry->size = 0;
|
||||||
entry->attributes = ATTR_DIRECTORY;
|
entry->attributes = ATTR_DIRECTORY;
|
||||||
|
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fat32_rmdir(const char *path) {
|
bool fat32_rmdir(const char *path) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
char normalized[FAT32_MAX_PATH];
|
char normalized[FAT32_MAX_PATH];
|
||||||
fat32_normalize_path(path, normalized);
|
fat32_normalize_path(path, normalized);
|
||||||
|
|
||||||
FileEntry *entry = find_file(normalized);
|
FileEntry *entry = find_file(normalized);
|
||||||
if (!entry || !(entry->attributes & ATTR_DIRECTORY)) {
|
if (!entry || !(entry->attributes & ATTR_DIRECTORY)) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->used = false;
|
entry->used = false;
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fat32_delete(const char *path) {
|
bool fat32_delete(const char *path) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
char normalized[FAT32_MAX_PATH];
|
char normalized[FAT32_MAX_PATH];
|
||||||
fat32_normalize_path(path, normalized);
|
fat32_normalize_path(path, normalized);
|
||||||
|
|
||||||
FileEntry *entry = find_file(normalized);
|
FileEntry *entry = find_file(normalized);
|
||||||
if (!entry || (entry->attributes & ATTR_DIRECTORY)) {
|
if (!entry || (entry->attributes & ATTR_DIRECTORY)) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->used = false;
|
entry->used = false;
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fat32_exists(const char *path) {
|
bool fat32_exists(const char *path) {
|
||||||
return find_file(path) != NULL;
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
|
bool res = find_file(path) != NULL;
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fat32_rename(const char *old_path, const char *new_path) {
|
bool fat32_rename(const char *old_path, const char *new_path) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
FileEntry *entry = find_file(old_path);
|
FileEntry *entry = find_file(old_path);
|
||||||
if (!entry) return false;
|
if (!entry) { asm volatile("push %0; popfq" : : "r"(rflags)); return false; }
|
||||||
if (find_file(new_path)) return false; // Destination exists
|
if (find_file(new_path)) { asm volatile("push %0; popfq" : : "r"(rflags)); return false; } // Destination exists
|
||||||
|
|
||||||
int old_len = fs_strlen(old_path);
|
int old_len = fs_strlen(old_path);
|
||||||
|
|
||||||
@@ -572,20 +635,28 @@ bool fat32_rename(const char *old_path, const char *new_path) {
|
|||||||
fs_strcat(files[i].parent_path, suffix);
|
fs_strcat(files[i].parent_path, suffix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fat32_is_directory(const char *path) {
|
bool fat32_is_directory(const char *path) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
FileEntry *entry = find_file(path);
|
FileEntry *entry = find_file(path);
|
||||||
return entry && (entry->attributes & ATTR_DIRECTORY);
|
bool res = entry && (entry->attributes & ATTR_DIRECTORY);
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fat32_list_directory(const char *path, FAT32_FileInfo *entries, int max_entries) {
|
int fat32_list_directory(const char *path, FAT32_FileInfo *entries, int max_entries) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
char normalized[FAT32_MAX_PATH];
|
char normalized[FAT32_MAX_PATH];
|
||||||
fat32_normalize_path(path, normalized);
|
fat32_normalize_path(path, normalized);
|
||||||
|
|
||||||
FileEntry *dir = find_file(normalized);
|
FileEntry *dir = find_file(normalized);
|
||||||
if (!dir || !(dir->attributes & ATTR_DIRECTORY)) {
|
if (!dir || !(dir->attributes & ATTR_DIRECTORY)) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return 0; // Not a directory
|
return 0; // Not a directory
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,23 +671,30 @@ int fat32_list_directory(const char *path, FAT32_FileInfo *entries, int max_entr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fat32_chdir(const char *path) {
|
bool fat32_chdir(const char *path) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
char normalized[FAT32_MAX_PATH];
|
char normalized[FAT32_MAX_PATH];
|
||||||
fat32_normalize_path(path, normalized);
|
fat32_normalize_path(path, normalized);
|
||||||
|
|
||||||
FileEntry *entry = find_file(normalized);
|
FileEntry *entry = find_file(normalized);
|
||||||
if (!entry || !(entry->attributes & ATTR_DIRECTORY)) {
|
if (!entry || !(entry->attributes & ATTR_DIRECTORY)) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs_strcpy(current_dir, normalized);
|
fs_strcpy(current_dir, normalized);
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fat32_get_current_dir(char *buffer, int size) {
|
void fat32_get_current_dir(char *buffer, int size) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
int len = fs_strlen(current_dir);
|
int len = fs_strlen(current_dir);
|
||||||
if (len >= size) len = size - 1;
|
if (len >= size) len = size - 1;
|
||||||
|
|
||||||
@@ -624,4 +702,5 @@ void fat32_get_current_dir(char *buffer, int size) {
|
|||||||
buffer[i] = current_dir[i];
|
buffer[i] = current_dir[i];
|
||||||
}
|
}
|
||||||
buffer[len] = 0;
|
buffer[len] = 0;
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Minimal 8x8 font for ASCII 32-127
|
// Minimal 8x8 font for ASCII 32-127
|
||||||
// Derived from standard VGA font
|
|
||||||
static const uint8_t font8x8_basic[128][8] = {
|
static const uint8_t font8x8_basic[128][8] = {
|
||||||
// 0-31 Control chars (empty)
|
// 0-31 Control chars (empty)
|
||||||
{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
|
{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
static struct limine_framebuffer *g_fb = NULL;
|
static struct limine_framebuffer *g_fb = NULL;
|
||||||
static uint32_t g_bg_color = 0xFF696969; // Dark gray background
|
static uint32_t g_bg_color = 0xFF696969; // Dark gray background
|
||||||
@@ -69,6 +70,9 @@ static void merge_dirty_rect(int x, int y, int w, int h) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void graphics_mark_dirty(int x, int y, int w, int h) {
|
void graphics_mark_dirty(int x, int y, int w, int h) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
|
|
||||||
// Clamp to screen bounds
|
// Clamp to screen bounds
|
||||||
if (x < 0) {
|
if (x < 0) {
|
||||||
w += x;
|
w += x;
|
||||||
@@ -85,9 +89,13 @@ void graphics_mark_dirty(int x, int y, int w, int h) {
|
|||||||
h = get_screen_height() - y;
|
h = get_screen_height() - y;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (w <= 0 || h <= 0) return;
|
if (w <= 0 || h <= 0) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
merge_dirty_rect(x, y, w, h);
|
merge_dirty_rect(x, y, w, h);
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
}
|
}
|
||||||
|
|
||||||
void graphics_mark_screen_dirty(void) {
|
void graphics_mark_screen_dirty(void) {
|
||||||
@@ -103,7 +111,10 @@ DirtyRect graphics_get_dirty_rect(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void graphics_clear_dirty(void) {
|
void graphics_clear_dirty(void) {
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
g_dirty.active = false;
|
g_dirty.active = false;
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
}
|
}
|
||||||
|
|
||||||
void put_pixel(int x, int y, uint32_t color) {
|
void put_pixel(int x, int y, uint32_t color) {
|
||||||
@@ -123,9 +134,29 @@ void put_pixel(int x, int y, uint32_t color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void draw_rect(int x, int y, int w, int h, uint32_t color) {
|
void draw_rect(int x, int y, int w, int h, uint32_t color) {
|
||||||
for (int i = 0; i < h; i++) {
|
if (!g_fb) return;
|
||||||
for (int j = 0; j < w; j++) {
|
|
||||||
put_pixel(x + j, y + i, color);
|
int x1 = x, y1 = y, x2 = x + w, y2 = y + h;
|
||||||
|
|
||||||
|
if (g_clip_enabled) {
|
||||||
|
if (x1 < g_clip_x) x1 = g_clip_x;
|
||||||
|
if (y1 < g_clip_y) y1 = g_clip_y;
|
||||||
|
if (x2 > g_clip_x + g_clip_w) x2 = g_clip_x + g_clip_w;
|
||||||
|
if (y2 > g_clip_y + g_clip_h) y2 = g_clip_y + g_clip_h;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x1 < 0) x1 = 0;
|
||||||
|
if (y1 < 0) y1 = 0;
|
||||||
|
if (x2 > (int)g_fb->width) x2 = g_fb->width;
|
||||||
|
if (y2 > (int)g_fb->height) y2 = g_fb->height;
|
||||||
|
|
||||||
|
if (x1 >= x2 || y1 >= y2) return;
|
||||||
|
|
||||||
|
for (int i = y1; i < y2; i++) {
|
||||||
|
uint32_t *row = &g_back_buffer[i * g_fb->width + x1];
|
||||||
|
int len = x2 - x1;
|
||||||
|
for (int j = 0; j < len; j++) {
|
||||||
|
row[j] = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,6 +164,15 @@ void draw_rect(int x, int y, int w, int h, uint32_t color) {
|
|||||||
void draw_char(int x, int y, char c, uint32_t color) {
|
void draw_char(int x, int y, char c, uint32_t color) {
|
||||||
unsigned char uc = (unsigned char)c;
|
unsigned char uc = (unsigned char)c;
|
||||||
if (uc > 127) return;
|
if (uc > 127) return;
|
||||||
|
|
||||||
|
// Fast rejection: if the character is entirely outside the clipping/dirty rect, skip it
|
||||||
|
if (g_clip_enabled) {
|
||||||
|
if (x + 8 <= g_clip_x || x >= g_clip_x + g_clip_w ||
|
||||||
|
y + 8 <= g_clip_y || y >= g_clip_y + g_clip_h) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const uint8_t *glyph = font8x8_basic[uc];
|
const uint8_t *glyph = font8x8_basic[uc];
|
||||||
|
|
||||||
for (int row = 0; row < 8; row++) {
|
for (int row = 0; row < 8; row++) {
|
||||||
@@ -163,13 +203,18 @@ void draw_desktop_background(void) {
|
|||||||
if (!g_fb) return;
|
if (!g_fb) return;
|
||||||
|
|
||||||
if (g_use_pattern) {
|
if (g_use_pattern) {
|
||||||
// Draw tiled pattern
|
// Optimized tiled pattern: only draw within the clipping/dirty rect
|
||||||
for (int y = 0; y < (int)g_fb->height; y++) {
|
int x1 = 0, y1 = 0, x2 = g_fb->width, y2 = g_fb->height;
|
||||||
for (int x = 0; x < (int)g_fb->width; x++) {
|
if (g_clip_enabled) {
|
||||||
int px = x % PATTERN_SIZE;
|
x1 = g_clip_x; y1 = g_clip_y;
|
||||||
int py = y % PATTERN_SIZE;
|
x2 = g_clip_x + g_clip_w; y2 = g_clip_y + g_clip_h;
|
||||||
uint32_t color = g_bg_pattern[py * PATTERN_SIZE + px];
|
}
|
||||||
put_pixel(x, y, color);
|
|
||||||
|
for (int y = y1; y < y2; y++) {
|
||||||
|
uint32_t *row = &g_back_buffer[y * g_fb->width + x1];
|
||||||
|
int py = y % PATTERN_SIZE;
|
||||||
|
for (int x = x1; x < x2; x++) {
|
||||||
|
*row++ = g_bg_pattern[py * PATTERN_SIZE + (x % PATTERN_SIZE)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -203,20 +248,27 @@ void graphics_clear_back_buffer(uint32_t color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void graphics_flip_buffer(void) {
|
void graphics_flip_buffer(void) {
|
||||||
if (!g_fb) return;
|
if (!g_fb || !g_dirty.active) return;
|
||||||
|
|
||||||
// Copy back buffer to framebuffer
|
int x = g_dirty.x;
|
||||||
uint32_t *src = g_back_buffer;
|
int y = g_dirty.y;
|
||||||
uint8_t *dst = (uint8_t *)g_fb->address;
|
int w = g_dirty.w;
|
||||||
|
int h = g_dirty.h;
|
||||||
for (int y = 0; y < (int)g_fb->height; y++) {
|
|
||||||
// Copy one scanline
|
if (x < 0) { w += x; x = 0; }
|
||||||
uint32_t *dst_row = (uint32_t *)dst;
|
if (y < 0) { h += y; y = 0; }
|
||||||
for (int x = 0; x < (int)g_fb->width; x++) {
|
if (x + w > (int)g_fb->width) w = g_fb->width - x;
|
||||||
dst_row[x] = src[x];
|
if (y + h > (int)g_fb->height) h = g_fb->height - y;
|
||||||
|
|
||||||
|
if (w <= 0 || h <= 0) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < h; i++) {
|
||||||
|
int curr_y = y + i;
|
||||||
|
uint32_t *src_row = &g_back_buffer[curr_y * g_fb->width + x];
|
||||||
|
uint32_t *dst_row = (uint32_t *)((uint8_t *)g_fb->address + curr_y * g_fb->pitch) + x;
|
||||||
|
for (int j = 0; j < w; j++) {
|
||||||
|
dst_row[j] = src_row[j];
|
||||||
}
|
}
|
||||||
src += g_fb->width;
|
|
||||||
dst += g_fb->pitch;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,7 @@ send_eoi:
|
|||||||
push rax
|
push rax
|
||||||
mov al, 0x20
|
mov al, 0x20
|
||||||
out 0x20, al ; Master PIC
|
out 0x20, al ; Master PIC
|
||||||
; If IRQ > 7, send to Slave too (Mouse is IRQ 12)
|
|
||||||
; We'll handle this in the specific wrappers or C code.
|
|
||||||
; Actually, simpler to do EOI in C or here.
|
|
||||||
; Let's just do it in C.
|
|
||||||
pop rax
|
pop rax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|||||||
@@ -116,10 +116,6 @@ static void md_parse_line(const char *raw_line, char *output, MDLineType *type,
|
|||||||
*type = MD_LINE_BLOCKQUOTE;
|
*type = MD_LINE_BLOCKQUOTE;
|
||||||
i++;
|
i++;
|
||||||
if (raw_line[i] == ' ') i++;
|
if (raw_line[i] == ' ') i++;
|
||||||
} else if (raw_line[i] == '`') {
|
|
||||||
// Code block
|
|
||||||
*type = MD_LINE_CODE;
|
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse inline formatting and copy content
|
// Parse inline formatting and copy content
|
||||||
@@ -215,26 +211,36 @@ void markdown_open_file(const char *filename) {
|
|||||||
int line = 0;
|
int line = 0;
|
||||||
int col = 0;
|
int col = 0;
|
||||||
char raw_line[256] = "";
|
char raw_line[256] = "";
|
||||||
|
bool in_code_block = false;
|
||||||
|
|
||||||
for (int i = 0; i < bytes_read && line < MD_MAX_LINES; i++) {
|
for (int i = 0; i < bytes_read && line < MD_MAX_LINES; i++) {
|
||||||
char ch = buffer[i];
|
char ch = buffer[i];
|
||||||
|
|
||||||
if (ch == '\n') {
|
if (ch == '\n') {
|
||||||
raw_line[col] = 0;
|
raw_line[col] = 0;
|
||||||
|
|
||||||
// Parse the raw line
|
if (raw_line[0] == '`' && raw_line[1] == '`' && raw_line[2] == '`') {
|
||||||
char parsed_content[256];
|
in_code_block = !in_code_block;
|
||||||
MDLineType type;
|
} else {
|
||||||
int indent;
|
if (in_code_block) {
|
||||||
md_parse_line(raw_line, parsed_content, &type, &indent);
|
md_strcpy(lines[line].content, raw_line);
|
||||||
|
lines[line].length = md_strlen(raw_line);
|
||||||
// Store parsed line
|
lines[line].type = MD_LINE_CODE;
|
||||||
md_strcpy(lines[line].content, parsed_content);
|
lines[line].indent_level = 0;
|
||||||
lines[line].length = md_strlen(parsed_content);
|
line++;
|
||||||
lines[line].type = type;
|
} else {
|
||||||
lines[line].indent_level = indent;
|
char parsed_content[256];
|
||||||
|
MDLineType type;
|
||||||
line++;
|
int indent;
|
||||||
|
md_parse_line(raw_line, parsed_content, &type, &indent);
|
||||||
|
md_strcpy(lines[line].content, parsed_content);
|
||||||
|
lines[line].length = md_strlen(parsed_content);
|
||||||
|
lines[line].type = type;
|
||||||
|
lines[line].indent_level = indent;
|
||||||
|
line++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
col = 0;
|
col = 0;
|
||||||
raw_line[0] = 0;
|
raw_line[0] = 0;
|
||||||
} else if (col < 255) {
|
} else if (col < 255) {
|
||||||
@@ -245,16 +251,24 @@ void markdown_open_file(const char *filename) {
|
|||||||
// Handle last line if no trailing newline
|
// Handle last line if no trailing newline
|
||||||
if (col > 0 && line < MD_MAX_LINES) {
|
if (col > 0 && line < MD_MAX_LINES) {
|
||||||
raw_line[col] = 0;
|
raw_line[col] = 0;
|
||||||
char parsed_content[256];
|
if (raw_line[0] == '`' && raw_line[1] == '`' && raw_line[2] == '`') {
|
||||||
MDLineType type;
|
} else if (in_code_block) {
|
||||||
int indent;
|
md_strcpy(lines[line].content, raw_line);
|
||||||
md_parse_line(raw_line, parsed_content, &type, &indent);
|
lines[line].length = md_strlen(raw_line);
|
||||||
|
lines[line].type = MD_LINE_CODE;
|
||||||
md_strcpy(lines[line].content, parsed_content);
|
lines[line].indent_level = 0;
|
||||||
lines[line].length = md_strlen(parsed_content);
|
line++;
|
||||||
lines[line].type = type;
|
} else {
|
||||||
lines[line].indent_level = indent;
|
char parsed_content[256];
|
||||||
line++;
|
MDLineType type;
|
||||||
|
int indent;
|
||||||
|
md_parse_line(raw_line, parsed_content, &type, &indent);
|
||||||
|
md_strcpy(lines[line].content, parsed_content);
|
||||||
|
lines[line].length = md_strlen(parsed_content);
|
||||||
|
lines[line].type = type;
|
||||||
|
lines[line].indent_level = indent;
|
||||||
|
line++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
line_count = line;
|
line_count = line;
|
||||||
@@ -293,7 +307,7 @@ static void md_paint(Window *win) {
|
|||||||
int max_display_lines = usable_content_height / MD_LINE_HEIGHT;
|
int max_display_lines = usable_content_height / MD_LINE_HEIGHT;
|
||||||
|
|
||||||
// Draw content background
|
// Draw content background
|
||||||
draw_rect(offset_x, content_start_y, content_width - 20, usable_content_height, COLOR_WHITE);
|
draw_rect(win->x + 4, content_start_y, win->w - 24, usable_content_height, COLOR_WHITE);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -331,7 +345,7 @@ static void md_paint(Window *win) {
|
|||||||
text_color = 0xFF808080; // Gray
|
text_color = 0xFF808080; // Gray
|
||||||
break;
|
break;
|
||||||
case MD_LINE_CODE:
|
case MD_LINE_CODE:
|
||||||
text_color = 0xFF800000; // Dark red
|
text_color = COLOR_WHITE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
text_color = COLOR_BLACK;
|
text_color = COLOR_BLACK;
|
||||||
@@ -371,7 +385,6 @@ static void md_paint(Window *win) {
|
|||||||
}
|
}
|
||||||
line_segment[segment_len] = 0;
|
line_segment[segment_len] = 0;
|
||||||
|
|
||||||
// Word-based wrapping: if we didn't reach end of string, find last space
|
|
||||||
if (char_idx < text_len && segment_len > 0) {
|
if (char_idx < text_len && segment_len > 0) {
|
||||||
// Look for the last space in the segment
|
// Look for the last space in the segment
|
||||||
int last_space = -1;
|
int last_space = -1;
|
||||||
@@ -382,7 +395,6 @@ static void md_paint(Window *win) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we found a space, break there
|
|
||||||
if (last_space > 0) {
|
if (last_space > 0) {
|
||||||
segment_len = last_space;
|
segment_len = last_space;
|
||||||
line_segment[segment_len] = 0;
|
line_segment[segment_len] = 0;
|
||||||
@@ -395,6 +407,10 @@ static void md_paint(Window *win) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line->type == MD_LINE_CODE && segment_len > 0) {
|
||||||
|
draw_rect(x_offset - 2, line_y - 2, (segment_len * MD_CHAR_WIDTH) + 4, 12, COLOR_BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
// Draw special elements for first wrapped line of this markdown line
|
// Draw special elements for first wrapped line of this markdown line
|
||||||
if (local_display_line == 0) {
|
if (local_display_line == 0) {
|
||||||
switch (line->type) {
|
switch (line->type) {
|
||||||
@@ -414,10 +430,6 @@ static void md_paint(Window *win) {
|
|||||||
// Draw left border
|
// Draw left border
|
||||||
draw_rect(x_offset - 4, line_y, 2, line_height, 0xFF404080);
|
draw_rect(x_offset - 4, line_y, 2, line_height, 0xFF404080);
|
||||||
break;
|
break;
|
||||||
case MD_LINE_CODE:
|
|
||||||
// Draw background for code
|
|
||||||
draw_rect(x_offset - 2, line_y, (max_chars_per_line * MD_CHAR_WIDTH) + 4, line_height, 0xFFF0F0F0);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -438,8 +450,7 @@ static void md_paint(Window *win) {
|
|||||||
if (char_idx >= text_len) break;
|
if (char_idx >= text_len) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move display line forward by the actual number of wrapped lines created
|
|
||||||
// Each wrapped line uses one MD_LINE_HEIGHT worth of space
|
|
||||||
display_line += wrapped_line_count;
|
display_line += wrapped_line_count;
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
@@ -451,8 +462,7 @@ static void md_paint(Window *win) {
|
|||||||
static void md_handle_key(Window *win, char c) {
|
static void md_handle_key(Window *win, char c) {
|
||||||
(void)win; // Suppress unused warning
|
(void)win; // Suppress unused warning
|
||||||
|
|
||||||
// Handle scrolling with arrow keys and W/S
|
|
||||||
// 17 = UP arrow, 18 = DOWN arrow (from ps2 keyboard mapping)
|
|
||||||
if (c == 'w' || c == 'W' || c == 17) { // Page up or UP arrow
|
if (c == 'w' || c == 'W' || c == 17) { // Page up or UP arrow
|
||||||
scroll_top -= 3;
|
scroll_top -= 3;
|
||||||
if (scroll_top < 0) scroll_top = 0;
|
if (scroll_top < 0) scroll_top = 0;
|
||||||
|
|||||||
@@ -148,23 +148,30 @@ void* kmalloc(size_t size) {
|
|||||||
memory_manager_init();
|
memory_manager_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
|
|
||||||
if (size == 0 || size > memory_pool_size) {
|
if (size == 0 || size > memory_pool_size) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we can allocate
|
// Check if we can allocate
|
||||||
if (total_allocated + size > memory_pool_size) {
|
if (total_allocated + size > memory_pool_size) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find free space
|
// Find free space
|
||||||
void *ptr = find_free_space(size);
|
void *ptr = find_free_space(size);
|
||||||
if (ptr == NULL) {
|
if (ptr == NULL) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add block entry
|
// Add block entry
|
||||||
if (block_count >= MAX_ALLOCATIONS) {
|
if (block_count >= MAX_ALLOCATIONS) {
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +192,7 @@ void* kmalloc(size_t size) {
|
|||||||
// Clear memory
|
// Clear memory
|
||||||
mem_memset(ptr, 0, size);
|
mem_memset(ptr, 0, size);
|
||||||
|
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,6 +201,9 @@ void kfree(void *ptr) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
|
|
||||||
// Find and free the block
|
// Find and free the block
|
||||||
for (int i = 0; i < block_count; i++) {
|
for (int i = 0; i < block_count; i++) {
|
||||||
if (block_list[i].allocated && block_list[i].address == ptr) {
|
if (block_list[i].allocated && block_list[i].address == ptr) {
|
||||||
@@ -204,9 +215,11 @@ void kfree(void *ptr) {
|
|||||||
block_list[j] = block_list[j + 1];
|
block_list[j] = block_list[j + 1];
|
||||||
}
|
}
|
||||||
block_count--;
|
block_count--;
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
}
|
}
|
||||||
|
|
||||||
void* krealloc(void *ptr, size_t new_size) {
|
void* krealloc(void *ptr, size_t new_size) {
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ static void minesweeper_right_click(Window *win, int x, int y) {
|
|||||||
int cell_y = (y - grid_start_y) / CELL_SIZE;
|
int cell_y = (y - grid_start_y) / CELL_SIZE;
|
||||||
|
|
||||||
flag_cell(cell_x, cell_y);
|
flag_cell(cell_x, cell_y);
|
||||||
wm_paint();
|
wm_mark_dirty(win->x, win->y, win->w, win->h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +211,7 @@ static void minesweeper_click(Window *win, int x, int y) {
|
|||||||
if (x >= grid_start_x && x < grid_start_x + 90 &&
|
if (x >= grid_start_x && x < grid_start_x + 90 &&
|
||||||
y >= btn_y && y < btn_y + 24) {
|
y >= btn_y && y < btn_y + 24) {
|
||||||
init_game();
|
init_game();
|
||||||
wm_paint();
|
wm_mark_dirty(win->x, win->y, win->w, win->h);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +226,7 @@ static void minesweeper_click(Window *win, int x, int y) {
|
|||||||
|
|
||||||
reveal_cell(cell_x, cell_y);
|
reveal_cell(cell_x, cell_y);
|
||||||
|
|
||||||
wm_paint();
|
wm_mark_dirty(win->x, win->y, win->w, win->h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ static void notepad_ensure_cursor_visible(Window *win) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void notepad_paint(Window *win) {
|
static void notepad_paint(Window *win) {
|
||||||
|
// Explicitly draw white background for text
|
||||||
|
draw_rect(win->x + 4, win->y + 24, win->w - 8, win->h - 28, COLOR_WHITE);
|
||||||
|
|
||||||
int visual_line = 0;
|
int visual_line = 0;
|
||||||
int current_x = win->x + 8;
|
int current_x = win->x + 8;
|
||||||
int current_y = win->y + 30;
|
int current_y = win->y + 30;
|
||||||
|
|||||||
@@ -21,9 +21,6 @@ static void paint_strcpy(char *dest, const char *src) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void paint_paint(Window *win) {
|
static void paint_paint(Window *win) {
|
||||||
// Background
|
|
||||||
draw_rect(win->x + 4, win->y + 24, win->w - 8, win->h - 28, COLOR_LTGRAY);
|
|
||||||
|
|
||||||
// Toolbar area
|
// Toolbar area
|
||||||
draw_rect(win->x + 10, win->y + 30, 40, win->h - 40, COLOR_GRAY);
|
draw_rect(win->x + 10, win->y + 30, 40, win->h - 40, COLOR_GRAY);
|
||||||
draw_bevel_rect(win->x + 10, win->y + 30, 40, win->h - 40, true);
|
draw_bevel_rect(win->x + 10, win->y + 30, 40, win->h - 40, true);
|
||||||
|
|||||||
@@ -195,7 +195,6 @@ void tcp_close(tcp_socket_t *sock) {
|
|||||||
|
|
||||||
int tcp_read(tcp_socket_t *sock, char *buffer, int max_len) {
|
int tcp_read(tcp_socket_t *sock, char *buffer, int max_len) {
|
||||||
if (!sock) return 0;
|
if (!sock) return 0;
|
||||||
// Simple copy of what we have
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i = 0; i < sock->rx_pos && i < max_len; i++) {
|
for (int i = 0; i < sock->rx_pos && i < max_len; i++) {
|
||||||
buffer[i] = sock->rx_buffer[i];
|
buffer[i] = sock->rx_buffer[i];
|
||||||
|
|||||||
517
src/kernel/wm.c
517
src/kernel/wm.c
@@ -51,16 +51,17 @@ static int drag_offset_x = 0;
|
|||||||
static int drag_offset_y = 0;
|
static int drag_offset_y = 0;
|
||||||
|
|
||||||
// File Dragging State
|
// File Dragging State
|
||||||
static bool is_dragging_file = false;
|
bool is_dragging_file = false;
|
||||||
static char drag_file_path[256];
|
static char drag_file_path[256];
|
||||||
static int drag_icon_type = 0; // 0=File, 1=Folder, 2=App
|
static int drag_icon_type = 0; // 0=File, 1=Folder, 2=App
|
||||||
static int drag_start_x = 0;
|
static int drag_start_x = 0;
|
||||||
static int drag_start_y = 0;
|
static int drag_start_y = 0;
|
||||||
static int drag_icon_orig_x = 0;
|
static int drag_icon_orig_x = 0;
|
||||||
static int drag_icon_orig_y = 0;
|
static int drag_icon_orig_y = 0;
|
||||||
|
static Window *drag_src_win = NULL;
|
||||||
|
|
||||||
// Windows array for z-order management
|
// Windows array for z-order management
|
||||||
static Window *all_windows[10];
|
static Window *all_windows[32];
|
||||||
static int window_count = 0;
|
static int window_count = 0;
|
||||||
|
|
||||||
// Redraw system
|
// Redraw system
|
||||||
@@ -79,7 +80,6 @@ typedef struct {
|
|||||||
char name[64];
|
char name[64];
|
||||||
int x, y;
|
int x, y;
|
||||||
int type; // 0=File, 1=Folder, 2=App
|
int type; // 0=File, 1=Folder, 2=App
|
||||||
bool selected;
|
|
||||||
} DesktopIcon;
|
} DesktopIcon;
|
||||||
|
|
||||||
static DesktopIcon desktop_icons[MAX_DESKTOP_ICONS];
|
static DesktopIcon desktop_icons[MAX_DESKTOP_ICONS];
|
||||||
@@ -88,8 +88,8 @@ static int desktop_icon_count = 0;
|
|||||||
// Desktop Settings
|
// Desktop Settings
|
||||||
bool desktop_snap_to_grid = true;
|
bool desktop_snap_to_grid = true;
|
||||||
bool desktop_auto_align = true;
|
bool desktop_auto_align = true;
|
||||||
int desktop_max_rows_per_col = 9;
|
int desktop_max_rows_per_col = 13;
|
||||||
int desktop_max_cols = 15;
|
int desktop_max_cols = 23;
|
||||||
|
|
||||||
// Helper to check if string ends with suffix
|
// Helper to check if string ends with suffix
|
||||||
static bool str_ends_with(const char *str, const char *suffix) {
|
static bool str_ends_with(const char *str, const char *suffix) {
|
||||||
@@ -165,8 +165,6 @@ static void refresh_desktop_icons(void) {
|
|||||||
if (files[i].is_directory) dest->type = 1;
|
if (files[i].is_directory) dest->type = 1;
|
||||||
else if (str_ends_with(dest->name, ".shortcut")) dest->type = 2;
|
else if (str_ends_with(dest->name, ".shortcut")) dest->type = 2;
|
||||||
else dest->type = 0;
|
else dest->type = 0;
|
||||||
|
|
||||||
dest->selected = false;
|
|
||||||
dest->x = -1; // Mark as new for layout
|
dest->x = -1; // Mark as new for layout
|
||||||
dest->y = -1;
|
dest->y = -1;
|
||||||
|
|
||||||
@@ -276,49 +274,55 @@ void wm_show_message(const char *title, const char *message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void draw_icon_label(int x, int y, const char *label) {
|
static void draw_icon_label(int x, int y, const char *label) {
|
||||||
char line1[10] = {0};
|
char line1[11] = {0}; // 10 chars + null
|
||||||
char line2[10] = {0};
|
char line2[11] = {0}; // 10 chars + null
|
||||||
int len = 0; while(label[len]) len++;
|
int len = 0; while(label[len]) len++;
|
||||||
|
|
||||||
if (len <= 8) {
|
if (len <= 10) {
|
||||||
int i=0; while(i<len) { line1[i] = label[i]; i++; }
|
for (int i = 0; i < len; i++) line1[i] = label[i];
|
||||||
line1[i] = 0;
|
|
||||||
} else {
|
} else {
|
||||||
int split = 8;
|
// Dot-based wrap: keep extension together if prefix fits
|
||||||
// Smart wrap: look for separator in first 8 chars (backwards)
|
int dot_pos = -1;
|
||||||
// Prioritize keeping extension together (e.g. SEVENCH.MD -> split at 7)
|
for (int i = len - 1; i >= 0; i--) {
|
||||||
int best_split = -1;
|
if (label[i] == '.') { dot_pos = i; break; }
|
||||||
for (int i = 7; i >= 1; i--) {
|
}
|
||||||
if (label[i] == ' ' || label[i] == '.') {
|
|
||||||
best_split = i;
|
int split = -1;
|
||||||
break;
|
if (dot_pos != -1 && dot_pos > 0 && dot_pos <= 10) {
|
||||||
|
split = dot_pos;
|
||||||
|
} else {
|
||||||
|
// Word-based wrap: look for space in the first 11 characters
|
||||||
|
for (int i = 10; i >= 0; i--) {
|
||||||
|
if (label[i] == ' ') {
|
||||||
|
split = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (best_split != -1) {
|
if (split != -1) {
|
||||||
split = best_split;
|
for (int i = 0; i < split; i++) line1[i] = label[i];
|
||||||
}
|
int start2 = (label[split] == ' ') ? split + 1 : split;
|
||||||
|
int j = 0;
|
||||||
// Copy line 1
|
while (label[start2 + j] && j < 10) {
|
||||||
int i;
|
line2[j] = label[start2 + j];
|
||||||
for (i = 0; i < split; i++) line1[i] = label[i];
|
j++;
|
||||||
line1[i] = 0;
|
}
|
||||||
|
if (label[start2 + j] != 0) {
|
||||||
// Copy line 2
|
int t = (j > 8) ? 8 : j;
|
||||||
int start2 = split;
|
line2[t] = '.'; line2[t+1] = '.'; line2[t+2] = 0;
|
||||||
if (label[split] == ' ') start2++; // Skip space at start of line 2
|
}
|
||||||
|
} else {
|
||||||
int j = 0;
|
for (int i = 0; i < 10; i++) line1[i] = label[i];
|
||||||
while (label[start2 + j] && j < 8) {
|
int j = 0;
|
||||||
line2[j] = label[start2 + j];
|
while (label[10 + j] && j < 10) {
|
||||||
j++;
|
line2[j] = label[10 + j];
|
||||||
}
|
j++;
|
||||||
line2[j] = 0;
|
}
|
||||||
|
if (label[10 + j] != 0) {
|
||||||
// Truncate with .. if longer than 16 (or if line 2 overflows)
|
int t = (j > 8) ? 8 : j;
|
||||||
if (label[start2 + j] != 0) {
|
line2[t] = '.'; line2[t+1] = '.'; line2[t+2] = 0;
|
||||||
if (j > 6) { line2[6] = '.'; line2[7] = '.'; line2[8] = 0; }
|
}
|
||||||
else { line2[j++] = '.'; line2[j++] = '.'; line2[j] = 0; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,7 +342,6 @@ static void draw_icon_label(int x, int y, const char *label) {
|
|||||||
|
|
||||||
// --- Drawing Helpers ---
|
// --- Drawing Helpers ---
|
||||||
|
|
||||||
// Draw a bevelled box (Win 3.1 style)
|
|
||||||
void draw_bevel_rect(int x, int y, int w, int h, bool sunken) {
|
void draw_bevel_rect(int x, int y, int w, int h, bool sunken) {
|
||||||
draw_rect(x, y, w, h, COLOR_GRAY);
|
draw_rect(x, y, w, h, COLOR_GRAY);
|
||||||
|
|
||||||
@@ -377,16 +380,14 @@ void draw_coffee_cup(int x, int y, int size) {
|
|||||||
draw_rect(x + cup_w - 2, y + 2, 1, cup_h - 3, COLOR_BLACK); // Right
|
draw_rect(x + cup_w - 2, y + 2, 1, cup_h - 3, COLOR_BLACK); // Right
|
||||||
draw_rect(x + 1, y + cup_h - 1, cup_w - 2, 1, COLOR_BLACK); // Bottom
|
draw_rect(x + 1, y + cup_h - 1, cup_w - 2, 1, COLOR_BLACK); // Bottom
|
||||||
|
|
||||||
// Rounded bottom corners
|
|
||||||
draw_rect(x + 1, y + cup_h - 1, 1, 1, COLOR_LTGRAY);
|
draw_rect(x + 1, y + cup_h - 1, 1, 1, COLOR_LTGRAY);
|
||||||
draw_rect(x + cup_w - 2, y + cup_h - 1, 1, 1, COLOR_LTGRAY);
|
draw_rect(x + cup_w - 2, y + cup_h - 1, 1, 1, COLOR_LTGRAY);
|
||||||
|
|
||||||
// Handle - much bigger (on the right side, pointing inward)
|
|
||||||
draw_rect(x + cup_w, y + 3, 2, 8, COLOR_BLACK);
|
draw_rect(x + cup_w, y + 3, 2, 8, COLOR_BLACK);
|
||||||
draw_rect(x + cup_w - 2, y + 3, 2, 1, COLOR_BLACK);
|
draw_rect(x + cup_w - 2, y + 3, 2, 1, COLOR_BLACK);
|
||||||
draw_rect(x + cup_w - 2, y + 10, 2, 1, COLOR_BLACK);
|
draw_rect(x + cup_w - 2, y + 10, 2, 1, COLOR_BLACK);
|
||||||
|
|
||||||
// Coffee liquid inside - rainbow Apple logo stripes (blue, green, yellow, red, purple, blue)
|
|
||||||
int stripe_height = (cup_h - 5) / 6;
|
int stripe_height = (cup_h - 5) / 6;
|
||||||
int coffee_y = y + 4;
|
int coffee_y = y + 4;
|
||||||
draw_rect(x + 2, coffee_y, cup_w - 4, stripe_height, COLOR_APPLE_BLUE);
|
draw_rect(x + 2, coffee_y, cup_w - 4, stripe_height, COLOR_APPLE_BLUE);
|
||||||
@@ -601,7 +602,7 @@ void draw_window(Window *win) {
|
|||||||
draw_button(win->x + win->w - 20, win->y + 5, 14, 14, "X", false);
|
draw_button(win->x + win->w - 20, win->y + 5, 14, 14, "X", false);
|
||||||
|
|
||||||
// Client Area
|
// Client Area
|
||||||
draw_rect(win->x + 4, win->y + 24, win->w - 8, win->h - 28, COLOR_WHITE);
|
draw_rect(win->x + 4, win->y + 24, win->w - 8, win->h - 28, COLOR_LTGRAY);
|
||||||
|
|
||||||
if (win->paint) {
|
if (win->paint) {
|
||||||
win->paint(win);
|
win->paint(win);
|
||||||
@@ -696,17 +697,26 @@ void wm_paint(void) {
|
|||||||
int sw = get_screen_width();
|
int sw = get_screen_width();
|
||||||
int sh = get_screen_height();
|
int sh = get_screen_height();
|
||||||
|
|
||||||
// First, erase the old cursor (before redrawing anything)
|
|
||||||
if (cursor_visible) {
|
DirtyRect dirty = graphics_get_dirty_rect();
|
||||||
erase_cursor(last_cursor_x, last_cursor_y);
|
if (dirty.active) {
|
||||||
|
graphics_set_clipping(dirty.x, dirty.y, dirty.w, dirty.h);
|
||||||
|
} else {
|
||||||
|
graphics_clear_clipping();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Desktop
|
// 1. Desktop
|
||||||
draw_desktop_background();
|
draw_desktop_background();
|
||||||
|
|
||||||
// Draw Desktop Icons
|
// Draw Desktop Icons
|
||||||
for (int i = 0; i < desktop_icon_count; i++) {
|
for (int i = 0; i < desktop_icon_count; i++) {
|
||||||
DesktopIcon *icon = &desktop_icons[i];
|
DesktopIcon *icon = &desktop_icons[i];
|
||||||
|
if (dirty.active) {
|
||||||
|
if (icon->x + 80 <= dirty.x || icon->x >= dirty.x + dirty.w ||
|
||||||
|
icon->y + 80 <= dirty.y || icon->y >= dirty.y + dirty.h) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (icon->type == 1) draw_folder_icon(icon->x, icon->y, icon->name);
|
if (icon->type == 1) draw_folder_icon(icon->x, icon->y, icon->name);
|
||||||
else if (icon->type == 2) {
|
else if (icon->type == 2) {
|
||||||
// App icon - strip .app for display
|
// App icon - strip .app for display
|
||||||
@@ -734,14 +744,17 @@ void wm_paint(void) {
|
|||||||
else if (str_ends_with(icon->name, ".md")) {
|
else if (str_ends_with(icon->name, ".md")) {
|
||||||
draw_document_icon(icon->x, icon->y, icon->name);
|
draw_document_icon(icon->x, icon->y, icon->name);
|
||||||
draw_string(icon->x + 31, icon->y + 2, "MD", COLOR_BLACK);
|
draw_string(icon->x + 31, icon->y + 2, "MD", COLOR_BLACK);
|
||||||
|
} else if (str_ends_with(icon->name, ".c") || str_ends_with(icon->name, ".C")) {
|
||||||
|
draw_document_icon(icon->x, icon->y, icon->name);
|
||||||
|
draw_string(icon->x + 31, icon->y + 2, "C", COLOR_APPLE_BLUE);
|
||||||
}
|
}
|
||||||
else draw_document_icon(icon->x, icon->y, icon->name);
|
else draw_document_icon(icon->x, icon->y, icon->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Windows - sort by z-index and draw
|
// 3. Windows - sort by z-index and draw
|
||||||
// Simple bubble sort by z-index (5 windows max)
|
// Simple bubble sort by z-index
|
||||||
Window *sorted_windows[6];
|
Window *sorted_windows[32];
|
||||||
for (int i = 0; i < window_count; i++) {
|
for (int i = 0; i < window_count; i++) {
|
||||||
sorted_windows[i] = all_windows[i];
|
sorted_windows[i] = all_windows[i];
|
||||||
}
|
}
|
||||||
@@ -758,7 +771,15 @@ void wm_paint(void) {
|
|||||||
|
|
||||||
// Draw windows in z-order (lowest first)
|
// Draw windows in z-order (lowest first)
|
||||||
for (int i = 0; i < window_count; i++) {
|
for (int i = 0; i < window_count; i++) {
|
||||||
draw_window(sorted_windows[i]);
|
Window *win = sorted_windows[i];
|
||||||
|
if (!win->visible) continue;
|
||||||
|
if (dirty.active) {
|
||||||
|
if (win->x + win->w <= dirty.x || win->x >= dirty.x + dirty.w ||
|
||||||
|
win->y + win->h <= dirty.y || win->y >= dirty.y + dirty.h) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw_window(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Taskbar
|
// 4. Taskbar
|
||||||
@@ -803,30 +824,32 @@ void wm_paint(void) {
|
|||||||
// Desktop Context Menu
|
// Desktop Context Menu
|
||||||
if (desktop_menu_visible) {
|
if (desktop_menu_visible) {
|
||||||
int menu_w = 140;
|
int menu_w = 140;
|
||||||
int menu_h = 125; // 5 items * 25
|
int item_h = 25;
|
||||||
|
int menu_h = (desktop_menu_target_icon != -1) ? 125 : 75;
|
||||||
|
|
||||||
draw_rect(desktop_menu_x, desktop_menu_y, menu_w, menu_h, COLOR_LTGRAY);
|
draw_rect(desktop_menu_x, desktop_menu_y, menu_w, menu_h, COLOR_LTGRAY);
|
||||||
draw_bevel_rect(desktop_menu_x, desktop_menu_y, menu_w, menu_h, true);
|
draw_bevel_rect(desktop_menu_x, desktop_menu_y, menu_w, menu_h, true);
|
||||||
|
|
||||||
bool can_cut_copy = (desktop_menu_target_icon != -1);
|
|
||||||
bool can_paste = explorer_clipboard_has_content();
|
|
||||||
|
|
||||||
// If target is a file (not folder), paste is disabled
|
|
||||||
if (desktop_menu_target_icon != -1) {
|
if (desktop_menu_target_icon != -1) {
|
||||||
|
bool can_paste = explorer_clipboard_has_content();
|
||||||
DesktopIcon *icon = &desktop_icons[desktop_menu_target_icon];
|
DesktopIcon *icon = &desktop_icons[desktop_menu_target_icon];
|
||||||
if (icon->type != 1) can_paste = false; // 1 is folder
|
if (icon->type != 1) can_paste = false; // 1 is folder
|
||||||
|
|
||||||
|
draw_string(desktop_menu_x + 5, desktop_menu_y + 5, "Cut", COLOR_BLACK);
|
||||||
|
draw_string(desktop_menu_x + 5, desktop_menu_y + 5 + item_h, "Copy", COLOR_BLACK);
|
||||||
|
draw_string(desktop_menu_x + 5, desktop_menu_y + 5 + item_h * 2, "Paste", can_paste ? COLOR_BLACK : COLOR_DKGRAY);
|
||||||
|
draw_string(desktop_menu_x + 5, desktop_menu_y + 5 + item_h * 3, "Delete", COLOR_RED);
|
||||||
|
draw_string(desktop_menu_x + 5, desktop_menu_y + 5 + item_h * 4, "Rename", COLOR_BLACK);
|
||||||
|
} else {
|
||||||
|
bool can_paste = explorer_clipboard_has_content();
|
||||||
|
draw_string(desktop_menu_x + 5, desktop_menu_y + 5, "New File", COLOR_BLACK);
|
||||||
|
draw_string(desktop_menu_x + 5, desktop_menu_y + 5 + item_h, "New Folder", COLOR_BLACK);
|
||||||
|
draw_string(desktop_menu_x + 5, desktop_menu_y + 5 + item_h * 2, "Paste", can_paste ? COLOR_BLACK : COLOR_DKGRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
int item_h = 25;
|
|
||||||
draw_string(desktop_menu_x + 5, desktop_menu_y + 5, "Cut", can_cut_copy ? COLOR_BLACK : COLOR_DKGRAY);
|
|
||||||
draw_string(desktop_menu_x + 5, desktop_menu_y + 5 + item_h, "Copy", can_cut_copy ? COLOR_BLACK : COLOR_DKGRAY);
|
|
||||||
draw_string(desktop_menu_x + 5, desktop_menu_y + 5 + item_h * 2, "Paste", can_paste ? COLOR_BLACK : COLOR_DKGRAY);
|
|
||||||
draw_string(desktop_menu_x + 5, desktop_menu_y + 5 + item_h * 3, "Delete", can_cut_copy ? COLOR_RED : COLOR_DKGRAY);
|
|
||||||
draw_string(desktop_menu_x + 5, desktop_menu_y + 5 + item_h * 4, "Rename", can_cut_copy ? COLOR_BLACK : COLOR_DKGRAY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Desktop Rename Dialog
|
// Desktop Dialogs
|
||||||
if (desktop_dialog_state == 8) {
|
if (desktop_dialog_state != 0) {
|
||||||
int dlg_w = 300; int dlg_h = 110;
|
int dlg_w = 300; int dlg_h = 110;
|
||||||
int dlg_x = (sw - dlg_w) / 2;
|
int dlg_x = (sw - dlg_w) / 2;
|
||||||
int dlg_y = (sh - dlg_h) / 2;
|
int dlg_y = (sh - dlg_h) / 2;
|
||||||
@@ -834,13 +857,18 @@ void wm_paint(void) {
|
|||||||
draw_rect(dlg_x - 5, dlg_y - 5, dlg_w + 10, dlg_h + 10, COLOR_LTGRAY);
|
draw_rect(dlg_x - 5, dlg_y - 5, dlg_w + 10, dlg_h + 10, COLOR_LTGRAY);
|
||||||
draw_bevel_rect(dlg_x, dlg_y, dlg_w, dlg_h, true);
|
draw_bevel_rect(dlg_x, dlg_y, dlg_w, dlg_h, true);
|
||||||
|
|
||||||
draw_string(dlg_x + 10, dlg_y + 10, "Rename", COLOR_BLACK);
|
const char *title = "Rename";
|
||||||
|
const char *btn_text = "Rename";
|
||||||
|
if (desktop_dialog_state == 1) { title = "Create New File"; btn_text = "Create"; }
|
||||||
|
else if (desktop_dialog_state == 2) { title = "Create New Folder"; btn_text = "Create"; }
|
||||||
|
|
||||||
|
draw_string(dlg_x + 10, dlg_y + 10, title, COLOR_BLACK);
|
||||||
draw_bevel_rect(dlg_x + 10, dlg_y + 35, 280, 20, false);
|
draw_bevel_rect(dlg_x + 10, dlg_y + 35, 280, 20, false);
|
||||||
draw_string(dlg_x + 15, dlg_y + 40, desktop_dialog_input, COLOR_BLACK);
|
draw_string(dlg_x + 15, dlg_y + 40, desktop_dialog_input, COLOR_BLACK);
|
||||||
// Cursor
|
// Cursor
|
||||||
draw_rect(dlg_x + 15 + desktop_dialog_cursor * 8, dlg_y + 39, 2, 12, COLOR_BLACK);
|
draw_rect(dlg_x + 15 + desktop_dialog_cursor * 8, dlg_y + 39, 2, 12, COLOR_BLACK);
|
||||||
|
|
||||||
draw_button(dlg_x + 50, dlg_y + 65, 80, 25, "Rename", false);
|
draw_button(dlg_x + 50, dlg_y + 65, 80, 25, btn_text, false);
|
||||||
draw_button(dlg_x + 170, dlg_y + 65, 80, 25, "Cancel", false);
|
draw_button(dlg_x + 170, dlg_y + 65, 80, 25, "Cancel", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -888,7 +916,7 @@ bool rect_contains(int x, int y, int w, int h, int px, int py) {
|
|||||||
return px >= x && px < x + w && py >= y && py < y + h;
|
return px >= x && px < x + w && py >= y && py < y + h;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wm_bring_to_front(Window *win) {
|
void wm_bring_to_front(Window *win) {
|
||||||
// Clear focus from all windows
|
// Clear focus from all windows
|
||||||
for (int i = 0; i < window_count; i++) {
|
for (int i = 0; i < window_count; i++) {
|
||||||
all_windows[i]->focused = false;
|
all_windows[i]->focused = false;
|
||||||
@@ -903,6 +931,13 @@ static void wm_bring_to_front(Window *win) {
|
|||||||
win->visible = true;
|
win->visible = true;
|
||||||
win->focused = true;
|
win->focused = true;
|
||||||
win->z_index = max_z + 1;
|
win->z_index = max_z + 1;
|
||||||
|
force_redraw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_add_window(Window *win) {
|
||||||
|
if (window_count < 32) {
|
||||||
|
all_windows[window_count++] = win;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_handle_click(int x, int y) {
|
void wm_handle_click(int x, int y) {
|
||||||
@@ -924,7 +959,8 @@ void wm_handle_click(int x, int y) {
|
|||||||
// Handle Desktop Context Menu Click
|
// Handle Desktop Context Menu Click
|
||||||
if (desktop_menu_visible) {
|
if (desktop_menu_visible) {
|
||||||
int menu_w = 140;
|
int menu_w = 140;
|
||||||
int menu_h = 125;
|
int menu_h = (desktop_menu_target_icon != -1) ? 125 : 75;
|
||||||
|
|
||||||
if (rect_contains(desktop_menu_x, desktop_menu_y, menu_w, menu_h, x, y)) {
|
if (rect_contains(desktop_menu_x, desktop_menu_y, menu_w, menu_h, x, y)) {
|
||||||
int rel_y = y - desktop_menu_y;
|
int rel_y = y - desktop_menu_y;
|
||||||
int item = rel_y / 25;
|
int item = rel_y / 25;
|
||||||
@@ -939,6 +975,14 @@ void wm_handle_click(int x, int y) {
|
|||||||
char path[128] = "/Desktop/";
|
char path[128] = "/Desktop/";
|
||||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||||
explorer_clipboard_copy(path);
|
explorer_clipboard_copy(path);
|
||||||
|
} else if (item == 0 && desktop_menu_target_icon == -1) { // New File
|
||||||
|
desktop_dialog_state = 1;
|
||||||
|
desktop_dialog_input[0] = 0;
|
||||||
|
desktop_dialog_cursor = 0;
|
||||||
|
} else if (item == 1 && desktop_menu_target_icon == -1) { // New Folder
|
||||||
|
desktop_dialog_state = 2;
|
||||||
|
desktop_dialog_input[0] = 0;
|
||||||
|
desktop_dialog_cursor = 0;
|
||||||
} else if (item == 2) { // Paste
|
} else if (item == 2) { // Paste
|
||||||
bool can_paste = explorer_clipboard_has_content();
|
bool can_paste = explorer_clipboard_has_content();
|
||||||
if (desktop_menu_target_icon != -1) {
|
if (desktop_menu_target_icon != -1) {
|
||||||
@@ -947,17 +991,31 @@ void wm_handle_click(int x, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (can_paste) {
|
if (can_paste) {
|
||||||
|
int old_count = desktop_icon_count;
|
||||||
if (desktop_menu_target_icon != -1 && desktop_icons[desktop_menu_target_icon].type == 1) {
|
if (desktop_menu_target_icon != -1 && desktop_icons[desktop_menu_target_icon].type == 1) {
|
||||||
// Paste into folder
|
// Paste into folder
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/Desktop/";
|
||||||
DesktopIcon *icon = &desktop_icons[desktop_menu_target_icon];
|
DesktopIcon *icon = &desktop_icons[desktop_menu_target_icon];
|
||||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||||
explorer_clipboard_paste(path);
|
explorer_clipboard_paste(&win_explorer, path);
|
||||||
} else {
|
} else {
|
||||||
// Paste to desktop
|
// Paste to desktop
|
||||||
explorer_clipboard_paste("/Desktop");
|
explorer_clipboard_paste(&win_explorer, "/Desktop");
|
||||||
}
|
}
|
||||||
refresh_desktop_icons();
|
refresh_desktop_icons();
|
||||||
|
|
||||||
|
if (!desktop_auto_align && desktop_icon_count > old_count && desktop_menu_target_icon == -1) {
|
||||||
|
int new_idx = desktop_icon_count - 1;
|
||||||
|
desktop_icons[new_idx].x = desktop_menu_x - 20;
|
||||||
|
desktop_icons[new_idx].y = desktop_menu_y - 20;
|
||||||
|
if (desktop_snap_to_grid) {
|
||||||
|
int col = (desktop_icons[new_idx].x - 20 + 40) / 80;
|
||||||
|
int row = (desktop_icons[new_idx].y - 20 + 40) / 80;
|
||||||
|
if (col < 0) col = 0; if (row < 0) row = 0;
|
||||||
|
desktop_icons[new_idx].x = 20 + col * 80;
|
||||||
|
desktop_icons[new_idx].y = 20 + row * 80;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (item == 3 && desktop_menu_target_icon != -1) { // Delete
|
else if (item == 3 && desktop_menu_target_icon != -1) { // Delete
|
||||||
@@ -984,15 +1042,35 @@ void wm_handle_click(int x, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle Desktop Dialog Clicks
|
// Handle Desktop Dialog Clicks
|
||||||
if (desktop_dialog_state == 8) {
|
if (desktop_dialog_state != 0) {
|
||||||
int dlg_x = (sw - 300) / 2; int dlg_y = (sh - 110) / 2;
|
int dlg_x = (sw - 300) / 2; int dlg_y = (sh - 110) / 2;
|
||||||
if (rect_contains(dlg_x + 50, dlg_y + 65, 80, 25, x, y)) { // Rename
|
if (rect_contains(dlg_x + 50, dlg_y + 65, 80, 25, x, y)) { // Confirm
|
||||||
char old_path[128] = "/Desktop/";
|
if (desktop_dialog_state == 8) { // Rename
|
||||||
char new_path[128] = "/Desktop/";
|
char old_path[128] = "/Desktop/";
|
||||||
int p=9; int n=0; while(desktop_icons[desktop_dialog_target].name[n]) old_path[p++] = desktop_icons[desktop_dialog_target].name[n++]; old_path[p]=0;
|
char new_path[128] = "/Desktop/";
|
||||||
p=9; n=0; while(desktop_dialog_input[n]) new_path[p++] = desktop_dialog_input[n++]; new_path[p]=0;
|
int p=9; int n=0; while(desktop_icons[desktop_dialog_target].name[n]) old_path[p++] = desktop_icons[desktop_dialog_target].name[n++]; old_path[p]=0;
|
||||||
|
p=9; n=0; while(desktop_dialog_input[n]) new_path[p++] = desktop_dialog_input[n++]; new_path[p]=0;
|
||||||
if (fat32_rename(old_path, new_path)) refresh_desktop_icons();
|
|
||||||
|
if (fat32_rename(old_path, new_path)) {
|
||||||
|
refresh_desktop_icons();
|
||||||
|
explorer_refresh_all();
|
||||||
|
}
|
||||||
|
} else if (desktop_dialog_state == 1 || desktop_dialog_state == 2) { // Create File/Folder
|
||||||
|
if (desktop_icon_count >= desktop_max_cols * desktop_max_rows_per_col) {
|
||||||
|
wm_show_message("Error", "Desktop is full!");
|
||||||
|
} else if (desktop_dialog_input[0] != 0) {
|
||||||
|
char path[128] = "/Desktop/";
|
||||||
|
int p=9; int n=0; while(desktop_dialog_input[n]) path[p++] = desktop_dialog_input[n++]; path[p]=0;
|
||||||
|
if (desktop_dialog_state == 1) {
|
||||||
|
FAT32_FileHandle *fh = fat32_open(path, "w");
|
||||||
|
if (fh) fat32_close(fh);
|
||||||
|
} else {
|
||||||
|
fat32_mkdir(path);
|
||||||
|
}
|
||||||
|
refresh_desktop_icons();
|
||||||
|
explorer_refresh_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
desktop_dialog_state = 0;
|
desktop_dialog_state = 0;
|
||||||
force_redraw = true;
|
force_redraw = true;
|
||||||
return;
|
return;
|
||||||
@@ -1154,7 +1232,7 @@ void wm_handle_right_click(int x, int y) {
|
|||||||
static bool prev_right = false;
|
static bool prev_right = false;
|
||||||
bool left = buttons & 0x01;
|
bool left = buttons & 0x01;
|
||||||
bool right = buttons & 0x02;
|
bool right = buttons & 0x02;
|
||||||
|
|
||||||
if (left && !prev_left) {
|
if (left && !prev_left) {
|
||||||
// Mouse Down
|
// Mouse Down
|
||||||
drag_start_x = mx;
|
drag_start_x = mx;
|
||||||
@@ -1228,7 +1306,7 @@ void wm_handle_right_click(int x, int y) {
|
|||||||
DesktopIcon *icon = &desktop_icons[i];
|
DesktopIcon *icon = &desktop_icons[i];
|
||||||
is_dragging_file = true;
|
is_dragging_file = true;
|
||||||
drag_icon_type = icon->type;
|
drag_icon_type = icon->type;
|
||||||
pending_desktop_icon_click = -1; // Cancel pending click since we are dragging
|
pending_desktop_icon_click = -1;
|
||||||
drag_icon_orig_x = icon->x;
|
drag_icon_orig_x = icon->x;
|
||||||
drag_icon_orig_y = icon->y;
|
drag_icon_orig_y = icon->y;
|
||||||
// Construct path
|
// Construct path
|
||||||
@@ -1242,7 +1320,18 @@ void wm_handle_right_click(int x, int y) {
|
|||||||
if (explorer_get_file_at(drag_start_x, drag_start_y, drag_file_path, &is_dir)) {
|
if (explorer_get_file_at(drag_start_x, drag_start_y, drag_file_path, &is_dir)) {
|
||||||
is_dragging_file = true;
|
is_dragging_file = true;
|
||||||
drag_icon_type = is_dir ? 1 : 0;
|
drag_icon_type = is_dir ? 1 : 0;
|
||||||
explorer_clear_click_state();
|
drag_src_win = NULL;
|
||||||
|
|
||||||
|
// Find which explorer window was clicked to clear its state
|
||||||
|
for (int w = 0; w < window_count; w++) {
|
||||||
|
Window *win = all_windows[w];
|
||||||
|
if (win->visible && rect_contains(win->x, win->y, win->w, win->h, drag_start_x, drag_start_y)) {
|
||||||
|
if (str_starts_with(win->title, "File Explorer")) {
|
||||||
|
drag_src_win = win;
|
||||||
|
explorer_clear_click_state(win);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1260,7 +1349,7 @@ void wm_handle_right_click(int x, int y) {
|
|||||||
if (start_menu_pending_app) {
|
if (start_menu_pending_app) {
|
||||||
// Launch App
|
// Launch App
|
||||||
if (str_starts_with(start_menu_pending_app, "Explorer")) {
|
if (str_starts_with(start_menu_pending_app, "Explorer")) {
|
||||||
explorer_reset(); wm_bring_to_front(&win_explorer);
|
explorer_open_directory("/");
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Notepad")) {
|
} else if (str_starts_with(start_menu_pending_app, "Notepad")) {
|
||||||
wm_bring_to_front(&win_notepad);
|
wm_bring_to_front(&win_notepad);
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Editor")) {
|
} else if (str_starts_with(start_menu_pending_app, "Editor")) {
|
||||||
@@ -1293,49 +1382,52 @@ void wm_handle_right_click(int x, int y) {
|
|||||||
int i = pending_desktop_icon_click;
|
int i = pending_desktop_icon_click;
|
||||||
if (i < desktop_icon_count) {
|
if (i < desktop_icon_count) {
|
||||||
DesktopIcon *icon = &desktop_icons[i];
|
DesktopIcon *icon = &desktop_icons[i];
|
||||||
|
bool handled = false;
|
||||||
if (icon->type == 2) { // App Shortcut
|
if (icon->type == 2) { // App Shortcut
|
||||||
// Check name to launch app
|
// Check name to launch app
|
||||||
if (str_ends_with(icon->name, "Notepad.shortcut")) {
|
if (str_ends_with(icon->name, "Notepad.shortcut")) {
|
||||||
notepad_reset(); wm_bring_to_front(&win_notepad);
|
notepad_reset(); wm_bring_to_front(&win_notepad); handled = true;
|
||||||
} else if (str_ends_with(icon->name, "Calculator.shortcut")) {
|
} else if (str_ends_with(icon->name, "Calculator.shortcut")) {
|
||||||
wm_bring_to_front(&win_calculator);
|
wm_bring_to_front(&win_calculator); handled = true;
|
||||||
} else if (str_ends_with(icon->name, "Minesweeper.shortcut")) {
|
} else if (str_ends_with(icon->name, "Minesweeper.shortcut")) {
|
||||||
wm_bring_to_front(&win_minesweeper);
|
wm_bring_to_front(&win_minesweeper); handled = true;
|
||||||
} else if (str_ends_with(icon->name, "Control Panel.shortcut")) {
|
} else if (str_ends_with(icon->name, "Control Panel.shortcut")) {
|
||||||
wm_bring_to_front(&win_control_panel);
|
wm_bring_to_front(&win_control_panel); handled = true;
|
||||||
} else if (str_ends_with(icon->name, "Terminal.shortcut")) {
|
} else if (str_ends_with(icon->name, "Terminal.shortcut")) {
|
||||||
wm_bring_to_front(&win_cmd);
|
wm_bring_to_front(&win_cmd); handled = true;
|
||||||
} else if (str_ends_with(icon->name, "About.shortcut")) {
|
} else if (str_ends_with(icon->name, "About.shortcut")) {
|
||||||
wm_bring_to_front(&win_about);
|
wm_bring_to_front(&win_about); handled = true;
|
||||||
} else if (str_ends_with(icon->name, "Explorer.shortcut")) {
|
} else if (str_ends_with(icon->name, "Explorer.shortcut")) {
|
||||||
explorer_reset(); wm_bring_to_front(&win_explorer);
|
explorer_open_directory("/"); handled = true;
|
||||||
} else if (str_ends_with(icon->name, "Recycle Bin.shortcut")) {
|
} else if (str_ends_with(icon->name, "Recycle Bin.shortcut")) {
|
||||||
explorer_open_directory("/RecycleBin"); wm_bring_to_front(&win_explorer);
|
explorer_open_directory("/RecycleBin"); handled = true;
|
||||||
} else if (str_ends_with(icon->name, "Paint.shortcut")) {
|
} else if (str_ends_with(icon->name, "Paint.shortcut")) {
|
||||||
wm_bring_to_front(&win_paint);
|
wm_bring_to_front(&win_paint); handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic Shortcut Handling
|
if (!handled) {
|
||||||
char path[128] = "/Desktop/";
|
// Generic Shortcut Handling
|
||||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
char path[128] = "/Desktop/";
|
||||||
|
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||||
if (str_ends_with(icon->name, ".shortcut") && !str_starts_with(icon->name, "Recycle Bin")) {
|
|
||||||
FAT32_FileHandle *fh = fat32_open(path, "r");
|
if (str_ends_with(icon->name, ".shortcut") && !str_starts_with(icon->name, "Recycle Bin")) {
|
||||||
if (fh) {
|
FAT32_FileHandle *fh = fat32_open(path, "r");
|
||||||
char buf[256];
|
if (fh) {
|
||||||
int len = fat32_read(fh, buf, 255);
|
char buf[256];
|
||||||
fat32_close(fh);
|
int len = fat32_read(fh, buf, 255);
|
||||||
if (len > 0) {
|
fat32_close(fh);
|
||||||
buf[len] = 0;
|
if (len > 0) {
|
||||||
if (fat32_is_directory(buf)) {
|
buf[len] = 0;
|
||||||
explorer_open_directory(buf);
|
if (fat32_is_directory(buf)) {
|
||||||
wm_bring_to_front(&win_explorer);
|
explorer_open_directory(buf);
|
||||||
} else {
|
} else {
|
||||||
editor_open_file(buf);
|
editor_open_file(buf);
|
||||||
wm_bring_to_front(&win_editor);
|
wm_bring_to_front(&win_editor);
|
||||||
|
}
|
||||||
|
pending_desktop_icon_click = -1;
|
||||||
|
force_redraw = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
pending_desktop_icon_click = -1;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1343,7 +1435,6 @@ void wm_handle_right_click(int x, int y) {
|
|||||||
char path[128] = "/Desktop/";
|
char path[128] = "/Desktop/";
|
||||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||||
explorer_open_directory(path);
|
explorer_open_directory(path);
|
||||||
wm_bring_to_front(&win_explorer);
|
|
||||||
} else { // File
|
} else { // File
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/Desktop/";
|
||||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||||
@@ -1366,25 +1457,31 @@ void wm_handle_right_click(int x, int y) {
|
|||||||
if (is_dragging_file) {
|
if (is_dragging_file) {
|
||||||
// Drop logic
|
// Drop logic
|
||||||
|
|
||||||
// Check drop target
|
// Check drop target - iterate through all windows to find if dropped on an Explorer
|
||||||
if (win_explorer.visible && rect_contains(win_explorer.x, win_explorer.y, win_explorer.w, win_explorer.h, mx, my)) {
|
Window *drop_win = NULL;
|
||||||
// Dropped on Explorer
|
int topmost_z = -1;
|
||||||
// If source was desktop, we need to refresh desktop to remove the icon
|
for (int w = 0; w < window_count; w++) {
|
||||||
bool from_desktop = str_starts_with(drag_file_path, "/Desktop/");
|
Window *win = all_windows[w];
|
||||||
|
if (win->visible && rect_contains(win->x, win->y, win->w, win->h, mx, my)) {
|
||||||
if (drag_file_path[0] != ':') {
|
if (win->z_index > topmost_z && str_starts_with(win->title, "File Explorer")) {
|
||||||
char target_path[256];
|
drop_win = win;
|
||||||
bool is_dir;
|
topmost_z = win->z_index;
|
||||||
// Check if dropped on a folder inside explorer
|
|
||||||
if (explorer_get_file_at(mx, my, target_path, &is_dir) && is_dir) {
|
|
||||||
explorer_import_file_to(drag_file_path, target_path);
|
|
||||||
} else {
|
|
||||||
// Dropped in current dir
|
|
||||||
explorer_import_file(drag_file_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (from_desktop) {
|
}
|
||||||
|
|
||||||
|
if (drop_win) {
|
||||||
|
char target_path[256];
|
||||||
|
bool is_dir;
|
||||||
|
// Check if dropped on a folder inside this explorer
|
||||||
|
if (explorer_get_file_at(mx, my, target_path, &is_dir) && is_dir) {
|
||||||
|
explorer_import_file_to(drop_win, drag_file_path, target_path);
|
||||||
|
} else {
|
||||||
|
// Dropped in current dir of this explorer
|
||||||
|
explorer_import_file(drop_win, drag_file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_starts_with(drag_file_path, "/Desktop/")) {
|
||||||
refresh_desktop_icons();
|
refresh_desktop_icons();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1396,27 +1493,52 @@ void wm_handle_right_click(int x, int y) {
|
|||||||
// If source was NOT desktop, move to desktop
|
// If source was NOT desktop, move to desktop
|
||||||
// Check if path starts with /Desktop/
|
// Check if path starts with /Desktop/
|
||||||
bool from_desktop = (drag_file_path[0]=='/' && drag_file_path[1]=='D' && drag_file_path[2]=='e');
|
bool from_desktop = (drag_file_path[0]=='/' && drag_file_path[1]=='D' && drag_file_path[2]=='e');
|
||||||
if (!from_desktop) {
|
bool dropped_on_target = false;
|
||||||
|
for (int i = 0; i < desktop_icon_count; i++) {
|
||||||
|
if (from_desktop) {
|
||||||
|
char path[128] = "/Desktop/";
|
||||||
|
int p=9; int n=0; while(desktop_icons[i].name[n]) path[p++] = desktop_icons[i].name[n++]; path[p]=0;
|
||||||
|
if (str_eq(path, drag_file_path) == 0) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rect_contains(desktop_icons[i].x + 20, desktop_icons[i].y, 40, 40, mx, my)) {
|
||||||
|
if (desktop_icons[i].type == 1) {
|
||||||
|
char target_path[256] = "/Desktop/";
|
||||||
|
int p=9; int n=0; while(desktop_icons[i].name[n]) target_path[p++] = desktop_icons[i].name[n++]; target_path[p]=0;
|
||||||
|
explorer_import_file_to(&win_explorer, drag_file_path, target_path);
|
||||||
|
refresh_desktop_icons();
|
||||||
|
dropped_on_target = true;
|
||||||
|
break;
|
||||||
|
} else if (desktop_icons[i].type == 2 && str_starts_with(desktop_icons[i].name, "Recycle Bin")) {
|
||||||
|
explorer_import_file_to(&win_explorer, drag_file_path, "/RecycleBin");
|
||||||
|
refresh_desktop_icons();
|
||||||
|
dropped_on_target = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
dropped_on_target = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dropped_on_target && !from_desktop) {
|
||||||
// Dragged from Explorer to Desktop
|
// Dragged from Explorer to Desktop
|
||||||
// Check limit first
|
// Check limit first
|
||||||
if (desktop_icon_count >= desktop_max_cols * desktop_max_rows_per_col) {
|
if (desktop_icon_count >= desktop_max_cols * desktop_max_rows_per_col) {
|
||||||
wm_show_message("Error", "Desktop is full!");
|
wm_show_message("Error", "Desktop is full!");
|
||||||
} else {
|
} else {
|
||||||
explorer_import_file_to(drag_file_path, "/Desktop");
|
explorer_import_file_to(&win_explorer, drag_file_path, "/Desktop");
|
||||||
refresh_desktop_icons();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle insertion at specific position
|
// Handle insertion at specific position
|
||||||
|
char filename[64];
|
||||||
|
int len = 0; while(drag_file_path[len]) len++;
|
||||||
|
int s = len - 1; while(s >= 0 && drag_file_path[s] != '/') s--;
|
||||||
|
s++;
|
||||||
|
int d = 0; while(drag_file_path[s] && d < 63) filename[d++] = drag_file_path[s++];
|
||||||
|
filename[d] = 0;
|
||||||
|
|
||||||
if (desktop_auto_align && !msg_box_visible) {
|
if (desktop_auto_align && !msg_box_visible) {
|
||||||
// Find the newly added icon (it will be at the end)
|
|
||||||
// Extract filename from drag_file_path
|
|
||||||
char filename[64];
|
|
||||||
int len = 0; while(drag_file_path[len]) len++;
|
|
||||||
int s = len - 1; while(s >= 0 && drag_file_path[s] != '/') s--;
|
|
||||||
s++;
|
|
||||||
int d = 0; while(drag_file_path[s] && d < 63) filename[d++] = drag_file_path[s++];
|
|
||||||
filename[d] = 0;
|
|
||||||
|
|
||||||
int new_idx = -1;
|
int new_idx = -1;
|
||||||
for(int i=0; i<desktop_icon_count; i++) {
|
for(int i=0; i<desktop_icon_count; i++) {
|
||||||
if (str_eq(desktop_icons[i].name, filename) == 0) {
|
if (str_eq(desktop_icons[i].name, filename) == 0) {
|
||||||
@@ -1441,8 +1563,23 @@ void wm_handle_right_click(int x, int y) {
|
|||||||
|
|
||||||
refresh_desktop_icons(); // Re-apply layout
|
refresh_desktop_icons(); // Re-apply layout
|
||||||
}
|
}
|
||||||
|
} else if (!desktop_auto_align && !msg_box_visible) {
|
||||||
|
for(int i=0; i<desktop_icon_count; i++) {
|
||||||
|
if (str_eq(desktop_icons[i].name, filename) == 0) {
|
||||||
|
desktop_icons[i].x = mx - 20;
|
||||||
|
desktop_icons[i].y = my - 20;
|
||||||
|
if (desktop_snap_to_grid) {
|
||||||
|
int col = (desktop_icons[i].x - 20 + 40) / 80;
|
||||||
|
int row = (desktop_icons[i].y - 20 + 40) / 80;
|
||||||
|
if (col < 0) col = 0; if (row < 0) row = 0;
|
||||||
|
desktop_icons[i].x = 20 + col * 80;
|
||||||
|
desktop_icons[i].y = 20 + row * 80;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!dropped_on_target) {
|
||||||
// Moved within desktop
|
// Moved within desktop
|
||||||
// Find which icon was dragged
|
// Find which icon was dragged
|
||||||
int dragged_idx = -1;
|
int dragged_idx = -1;
|
||||||
@@ -1456,32 +1593,7 @@ void wm_handle_right_click(int x, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dragged_idx != -1) {
|
if (dragged_idx != -1) {
|
||||||
// Check for drop on folder (Priority over placement)
|
if (desktop_auto_align) {
|
||||||
bool dropped_on_folder = false;
|
|
||||||
for (int i = 0; i < desktop_icon_count; i++) {
|
|
||||||
if (i == dragged_idx) continue;
|
|
||||||
if (desktop_icons[i].type == 1) { // Folder
|
|
||||||
// Check if mouse is over this folder icon
|
|
||||||
if (rect_contains(desktop_icons[i].x + 20, desktop_icons[i].y, 40, 40, mx, my)) {
|
|
||||||
char target_path[256] = "/Desktop/";
|
|
||||||
int p=9; int n=0; while(desktop_icons[i].name[n]) target_path[p++] = desktop_icons[i].name[n++]; target_path[p]=0;
|
|
||||||
explorer_import_file_to(drag_file_path, target_path);
|
|
||||||
refresh_desktop_icons();
|
|
||||||
dropped_on_folder = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (desktop_icons[i].type == 2 && str_starts_with(desktop_icons[i].name, "Recycle Bin")) {
|
|
||||||
if (rect_contains(desktop_icons[i].x + 20, desktop_icons[i].y, 40, 40, mx, my)) {
|
|
||||||
// Move to Recycle Bin
|
|
||||||
explorer_import_file_to(drag_file_path, "/RecycleBin");
|
|
||||||
refresh_desktop_icons();
|
|
||||||
dropped_on_folder = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dropped_on_folder && desktop_auto_align) {
|
|
||||||
int cell_h = 80;
|
int cell_h = 80;
|
||||||
int rel_y = my - 20;
|
int rel_y = my - 20;
|
||||||
if (rel_y < 0) rel_y = 0;
|
if (rel_y < 0) rel_y = 0;
|
||||||
@@ -1509,7 +1621,7 @@ void wm_handle_right_click(int x, int y) {
|
|||||||
}
|
}
|
||||||
desktop_icons[target_idx] = temp;
|
desktop_icons[target_idx] = temp;
|
||||||
refresh_desktop_icons(); // Re-applies layout
|
refresh_desktop_icons(); // Re-applies layout
|
||||||
} else if (!dropped_on_folder) {
|
} else {
|
||||||
desktop_icons[dragged_idx].x = mx - 20;
|
desktop_icons[dragged_idx].x = mx - 20;
|
||||||
desktop_icons[dragged_idx].y = my - 20;
|
desktop_icons[dragged_idx].y = my - 20;
|
||||||
if (desktop_snap_to_grid) {
|
if (desktop_snap_to_grid) {
|
||||||
@@ -1531,7 +1643,6 @@ void wm_handle_right_click(int x, int y) {
|
|||||||
if (dx < 0) dx = -dx;
|
if (dx < 0) dx = -dx;
|
||||||
if (dy < 0) dy = -dy;
|
if (dy < 0) dy = -dy;
|
||||||
if (dx < 35 && dy < 35) {
|
if (dx < 35 && dy < 35) {
|
||||||
// Collision with non-folder (or we would have handled it)
|
|
||||||
// Revert position
|
// Revert position
|
||||||
desktop_icons[dragged_idx].x = drag_icon_orig_x;
|
desktop_icons[dragged_idx].x = drag_icon_orig_x;
|
||||||
desktop_icons[dragged_idx].y = drag_icon_orig_y;
|
desktop_icons[dragged_idx].y = drag_icon_orig_y;
|
||||||
@@ -1571,14 +1682,34 @@ static volatile int key_head = 0;
|
|||||||
static volatile int key_tail = 0;
|
static volatile int key_tail = 0;
|
||||||
|
|
||||||
static void wm_dispatch_key(char c) {
|
static void wm_dispatch_key(char c) {
|
||||||
if (desktop_dialog_state == 8) {
|
if (desktop_dialog_state != 0) {
|
||||||
int len = 0; while(desktop_dialog_input[len]) len++;
|
int len = 0; while(desktop_dialog_input[len]) len++;
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
char old_path[128] = "/Desktop/";
|
if (desktop_dialog_state == 8) { // Rename
|
||||||
char new_path[128] = "/Desktop/";
|
char old_path[128] = "/Desktop/";
|
||||||
int p=9; int n=0; while(desktop_icons[desktop_dialog_target].name[n]) old_path[p++] = desktop_icons[desktop_dialog_target].name[n++]; old_path[p]=0;
|
char new_path[128] = "/Desktop/";
|
||||||
p=9; n=0; while(desktop_dialog_input[n]) new_path[p++] = desktop_dialog_input[n++]; new_path[p]=0;
|
int p=9; int n=0; while(desktop_icons[desktop_dialog_target].name[n]) old_path[p++] = desktop_icons[desktop_dialog_target].name[n++]; old_path[p]=0;
|
||||||
if (fat32_rename(old_path, new_path)) refresh_desktop_icons();
|
p=9; n=0; while(desktop_dialog_input[n]) new_path[p++] = desktop_dialog_input[n++]; new_path[p]=0;
|
||||||
|
if (fat32_rename(old_path, new_path)) {
|
||||||
|
refresh_desktop_icons();
|
||||||
|
explorer_refresh_all();
|
||||||
|
}
|
||||||
|
} else if (desktop_dialog_state == 1 || desktop_dialog_state == 2) { // Create File/Folder
|
||||||
|
if (desktop_icon_count >= desktop_max_cols * desktop_max_rows_per_col) {
|
||||||
|
wm_show_message("Error", "Desktop is full!");
|
||||||
|
} else if (desktop_dialog_input[0] != 0) {
|
||||||
|
char path[128] = "/Desktop/";
|
||||||
|
int p=9; int n=0; while(desktop_dialog_input[n]) path[p++] = desktop_dialog_input[n++]; path[p]=0;
|
||||||
|
if (desktop_dialog_state == 1) {
|
||||||
|
FAT32_FileHandle *fh = fat32_open(path, "w");
|
||||||
|
if (fh) fat32_close(fh);
|
||||||
|
} else {
|
||||||
|
fat32_mkdir(path);
|
||||||
|
}
|
||||||
|
refresh_desktop_icons();
|
||||||
|
explorer_refresh_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
desktop_dialog_state = 0;
|
desktop_dialog_state = 0;
|
||||||
} else if (c == 27) {
|
} else if (c == 27) {
|
||||||
desktop_dialog_state = 0;
|
desktop_dialog_state = 0;
|
||||||
@@ -1601,13 +1732,12 @@ static void wm_dispatch_key(char c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Window *target = NULL;
|
Window *target = NULL;
|
||||||
if (win_notepad.focused && win_notepad.visible) target = &win_notepad;
|
for (int i = 0; i < window_count; i++) {
|
||||||
else if (win_cmd.focused && win_cmd.visible) target = &win_cmd;
|
if (all_windows[i]->focused && all_windows[i]->visible) {
|
||||||
else if (win_calculator.focused && win_calculator.visible) target = &win_calculator;
|
target = all_windows[i];
|
||||||
else if (win_explorer.focused && win_explorer.visible) target = &win_explorer;
|
break;
|
||||||
else if (win_editor.focused && win_editor.visible) target = &win_editor;
|
}
|
||||||
else if (win_markdown.focused && win_markdown.visible) target = &win_markdown;
|
}
|
||||||
else if (win_control_panel.focused && win_control_panel.visible) target = &win_control_panel;
|
|
||||||
|
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
|
|
||||||
@@ -1711,12 +1841,13 @@ uint32_t wm_get_ticks(void) {
|
|||||||
void wm_timer_tick(void) {
|
void wm_timer_tick(void) {
|
||||||
timer_ticks++;
|
timer_ticks++;
|
||||||
|
|
||||||
// Auto-refresh desktop every second (approx 60 ticks)
|
// Auto-refresh desktop every 5 seconds to save CPU in QEMU
|
||||||
// But NOT if we are currently dragging something, to avoid state conflicts
|
// But NOT if the user is dragging a window or file.
|
||||||
if (!is_dragging && !is_dragging_file) {
|
if (!is_dragging && !is_dragging_file) {
|
||||||
desktop_refresh_timer++;
|
desktop_refresh_timer++;
|
||||||
if (desktop_refresh_timer >= 60) {
|
if (desktop_refresh_timer >= 300) {
|
||||||
refresh_desktop_icons();
|
refresh_desktop_icons();
|
||||||
|
explorer_refresh_all();
|
||||||
desktop_refresh_timer = 0;
|
desktop_refresh_timer = 0;
|
||||||
force_redraw = true;
|
force_redraw = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ struct Window {
|
|||||||
int cursor_pos;
|
int cursor_pos;
|
||||||
bool focused;
|
bool focused;
|
||||||
int z_index; // Layering depth (higher = on top)
|
int z_index; // Layering depth (higher = on top)
|
||||||
|
void *data; // Per-window private data
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
void (*paint)(Window *win);
|
void (*paint)(Window *win);
|
||||||
@@ -47,6 +48,8 @@ void wm_handle_key(char c);
|
|||||||
void wm_handle_click(int x, int y);
|
void wm_handle_click(int x, int y);
|
||||||
void wm_handle_right_click(int x, int y);
|
void wm_handle_right_click(int x, int y);
|
||||||
void wm_process_input(void);
|
void wm_process_input(void);
|
||||||
|
void wm_add_window(Window *win);
|
||||||
|
void wm_bring_to_front(Window *win);
|
||||||
|
|
||||||
// Redraw system
|
// Redraw system
|
||||||
void wm_mark_dirty(int x, int y, int w, int h);
|
void wm_mark_dirty(int x, int y, int w, int h);
|
||||||
|
|||||||
Reference in New Issue
Block a user