mirror of
https://github.com/JannisHeydemann/BoredOS.git
synced 2026-05-30 10:26:59 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3e4432a3a | ||
|
|
df5c117f65 | ||
|
|
1842ea3b67 | ||
|
|
8dcc3ff40c | ||
|
|
5bdbb59200 | ||
|
|
f06940f21f | ||
|
|
d0ab5021c4 | ||
|
|
90f86d63dc | ||
|
|
36d7137969 | ||
|
|
e939d50be6 | ||
|
|
9a4b7b05ff | ||
|
|
23972f8951 |
8
Makefile
8
Makefile
@@ -1,4 +1,4 @@
|
|||||||
# BrewOS Makefile
|
# BoredOS Makefile
|
||||||
# Target Architecture: x86_64
|
# Target Architecture: x86_64
|
||||||
# Host: macOS
|
# Host: macOS
|
||||||
|
|
||||||
@@ -11,8 +11,8 @@ SRC_DIR = src/kernel
|
|||||||
BUILD_DIR = build
|
BUILD_DIR = build
|
||||||
ISO_DIR = iso_root
|
ISO_DIR = iso_root
|
||||||
|
|
||||||
KERNEL_ELF = $(BUILD_DIR)/brewos.elf
|
KERNEL_ELF = $(BUILD_DIR)/boredos.elf
|
||||||
ISO_IMAGE = brewos.iso
|
ISO_IMAGE = boredos.iso
|
||||||
|
|
||||||
C_SOURCES = $(wildcard $(SRC_DIR)/*.c)
|
C_SOURCES = $(wildcard $(SRC_DIR)/*.c)
|
||||||
CLI_APP_SOURCES = $(wildcard $(SRC_DIR)/cli_apps/*.c)
|
CLI_APP_SOURCES = $(wildcard $(SRC_DIR)/cli_apps/*.c)
|
||||||
@@ -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
|
||||||
|
|||||||
38
README.md
38
README.md
@@ -1,32 +1,35 @@
|
|||||||
# Brew OS 1.42 Beta
|
# BoredOS 1.50
|
||||||
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.
|
BoredOS has now exited Beta stage and is "stable enough" to be put out as a "stable" product.
|
||||||
|
|
||||||
## Brewkernel is now BrewOS!
|
<img src="bored.svg" width="200" /> </br>
|
||||||
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).
|
BoredOS is a simple x86_64 hobbyist operating system.
|
||||||
|
|
||||||
|
|
||||||
<img src="asciiart.png" width="200" /> </br>
|
|
||||||
Brew Kernel is a simple x86_64 hobbyist operating system.
|
|
||||||
It features a DE (and WM), a FAT32 filesystem, customizable UI and much much more!
|
It features a DE (and WM), a FAT32 filesystem, customizable UI and much much more!
|
||||||
|
|
||||||
|

|
||||||
|
*this screenshot might be outdated*
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- Drag and drop mouse centered UI
|
- Drag and drop mouse centered UI
|
||||||
- Customizable UI
|
- Customizable UI
|
||||||
- Basic Networking Stack
|
- Basic Networking Stack
|
||||||
- Brew WM
|
- Bored WM
|
||||||
- Fat 32 FS
|
- Fat 32 FS
|
||||||
- 64-bit long mode support
|
- 64-bit long mode support
|
||||||
- Multiboot2 compliant
|
- Multiboot2 compliant
|
||||||
- Text editor
|
- Text editor
|
||||||
- Markdown Viewer
|
- Markdown Viewer
|
||||||
- Minesweeper
|
- Minesweeper
|
||||||
|
- Markdown Viewer
|
||||||
|
- GUI Text editor
|
||||||
|
- Paint application
|
||||||
- IDT
|
- IDT
|
||||||
- Ability to run on actual x86_64 hardware
|
- Ability to run on actual x86_64 hardware
|
||||||
- CLI
|
- CLI
|
||||||
|
- (Limited) C Compiler
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
To build BrewOS, you'll need the following tools installed:
|
To build BoredOS, you'll need the following tools installed:
|
||||||
|
|
||||||
- **x86_64 ELF Toolchain**: `x86_64-elf-gcc`, `x86_64-elf-ld`
|
- **x86_64 ELF Toolchain**: `x86_64-elf-gcc`, `x86_64-elf-ld`
|
||||||
- **NASM**: Netwide Assembler for compiling assembly code
|
- **NASM**: Netwide Assembler for compiling assembly code
|
||||||
@@ -49,12 +52,12 @@ make
|
|||||||
This will:
|
This will:
|
||||||
1. Compile all kernel C sources and assembly files
|
1. Compile all kernel C sources and assembly files
|
||||||
2. Link the kernel ELF binary
|
2. Link the kernel ELF binary
|
||||||
3. Generate a bootable ISO image (`brewos.iso`)
|
3. Generate a bootable ISO image (`boredos.iso`)
|
||||||
|
|
||||||
The build output is organized as follows:
|
The build output is organized as follows:
|
||||||
- Compiled object files: `build/`
|
- Compiled object files: `build/`
|
||||||
- ISO root filesystem: `iso_root/`
|
- ISO root filesystem: `iso_root/`
|
||||||
- Final ISO image: `brewos.iso`
|
- Final ISO image: `boredos.iso`
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
@@ -68,14 +71,14 @@ make run
|
|||||||
|
|
||||||
Or manually:
|
Or manually:
|
||||||
```sh
|
```sh
|
||||||
qemu-system-x86_64 -m 2G -serial stdio -cdrom brewos.iso -boot d
|
qemu-system-x86_64 -m 2G -serial stdio -cdrom boredos.iso -boot d
|
||||||
```
|
```
|
||||||
|
|
||||||
### Running on Real Hardware
|
### Running on Real Hardware
|
||||||
|
|
||||||
*Warning: This is at YOUR OWN RISK. This software comes with ZERO warranty and may break your system.*
|
*Warning: This is at YOUR OWN RISK. This software comes with ZERO warranty and may break your system.*
|
||||||
|
|
||||||
1. **Create bootable USB**: Use [Balena Etcher](https://www.balena.io/etcher/) to flash `brewos.iso` to a USB drive
|
1. **Create bootable USB**: Use [Balena Etcher](https://www.balena.io/etcher/) to flash `boredos.iso` to a USB drive
|
||||||
|
|
||||||
2. **Prepare the system**:
|
2. **Prepare the system**:
|
||||||
- Enable legacy (BIOS) boot in your system BIOS/UEFI settings
|
- Enable legacy (BIOS) boot in your system BIOS/UEFI settings
|
||||||
@@ -126,6 +129,11 @@ qemu-system-x86_64 -m 2G -serial stdio -cdrom brewos.iso -boot d
|
|||||||
###
|
###
|
||||||
|
|
||||||
|
|
||||||
|
## This project was previously labeled as "BrewKernel"
|
||||||
|
Brewkernel was a text only very simple (and messy) project i started 3 years ago. It was my first work in OSDev and i absolutely loved it. It sadly just got too messy and i myself couldn't understand my own code anymore. About a year ago i started work on BoredOS, and pushed a *"working"* version of it a few days ago as of writing this *(Feb. 10 2026)*
|
||||||
|
Brewkernel has already been deprecated and will not be accepting any pull requests or fix any issues as it is now a public archive.
|
||||||
|
Thanks to everyone who helped me with Brewkernel, even if it were just ideas, and intend to keep working on this for the forseeable future!
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (C) 2024-2026 boreddevnl
|
Copyright (C) 2024-2026 boreddevnl
|
||||||
@@ -135,7 +143,7 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||||||
NOTICE
|
NOTICE
|
||||||
------
|
------
|
||||||
|
|
||||||
This product includes software developed by Chris ("boreddevnl") as part of the BrewKernel project.
|
This product includes software developed by Chris ("boreddevnl") as part of the BoredOS (Previously Brewkernel/BrewOS) project.
|
||||||
|
|
||||||
Copyright (C) 2024–2026 Chris / boreddevnl (previously boreddevhq)
|
Copyright (C) 2024–2026 Chris / boreddevnl (previously boreddevhq)
|
||||||
|
|
||||||
|
|||||||
6
bored.svg
Normal file
6
bored.svg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="364" height="323" viewBox="0 0 364 323">
|
||||||
|
<g>
|
||||||
|
<path d="M 214.21 252.46 C206.89,254.00 191.49,255.09 186.50,254.42 C174.91,252.87 168.37,251.35 160.60,248.37 C131.04,237.05 110.95,215.05 101.36,183.50 C98.88,175.35 98.62,173.03 98.62,159.00 C98.62,144.97 98.88,142.65 101.36,134.50 C102.86,129.55 105.39,122.71 106.97,119.29 L 109.85 113.09 L 107.81 110.48 C105.03,106.95 102.00,98.70 102.00,94.67 C102.00,83.87 109.64,72.78 119.64,69.03 C130.66,64.91 141.50,67.22 149.75,75.46 C155.89,81.59 156.51,84.69 152.25,87.96 C150.74,89.13 146.31,92.51 142.41,95.48 C120.32,112.27 107.85,145.44 113.38,172.69 C117.57,193.40 127.18,209.55 142.78,222.09 C182.22,253.83 239.30,243.11 264.90,199.16 C272.19,186.63 276.79,166.84 275.57,153.25 C273.24,127.38 261.78,107.28 240.25,91.30 C231.06,84.48 230.86,82.84 238.25,75.45 C244.57,69.13 252.04,66.41 260.67,67.31 C274.35,68.72 286.00,81.01 286.00,94.02 C286.00,98.35 283.36,105.84 280.53,109.55 L 277.90 113.00 L 280.83 119.25 C297.85,155.52 289.63,198.90 260.39,227.11 C247.18,239.85 230.45,249.04 214.21,252.46 ZM 248.58 185.10 C246.34,186.12 244.05,186.93 243.50,186.89 C240.22,186.68 236.44,184.60 230.84,179.94 C227.35,177.03 221.35,172.62 217.50,170.14 C209.66,165.10 207.76,163.26 206.01,159.02 C202.91,151.53 213.38,143.02 226.75,142.17 C244.76,141.02 257.91,150.18 258.82,164.52 C259.48,174.91 256.11,181.68 248.58,185.10 ZM 148.72 186.01 C148.05,186.02 146.60,186.24 145.50,186.50 C143.24,187.03 137.53,184.77 134.64,182.21 C131.66,179.56 128.02,170.93 128.02,166.50 C128.02,161.61 131.74,153.45 135.62,149.80 C141.20,144.58 147.51,142.52 158.00,142.51 C166.46,142.50 168.11,142.81 173.08,145.33 C181.97,149.83 184.53,156.84 179.47,162.85 C178.08,164.50 173.18,168.33 168.58,171.36 C163.97,174.40 157.89,178.93 155.07,181.44 C152.24,183.95 149.39,186.01 148.72,186.01 ZM 201.14 210.27 C198.36,212.87 195.15,215.00 194.00,215.00 C189.68,215.00 178.00,201.55 178.00,196.58 C178.00,193.75 182.20,192.69 193.47,192.68 C199.54,192.67 205.49,192.98 206.70,193.38 C211.98,195.11 209.59,202.37 201.14,210.27 Z" fill="rgb(255,255,255)"/>
|
||||||
|
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
BIN
build/about.o
BIN
build/about.o
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
build/cli_apps/boredver.o
Normal file
BIN
build/cli_apps/boredver.o
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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/dns.o
BIN
build/dns.o
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/http.o
BIN
build/http.o
Binary file not shown.
BIN
build/icmp.o
BIN
build/icmp.o
Binary file not shown.
BIN
build/main.o
BIN
build/main.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/network.o
BIN
build/network.o
Binary file not shown.
BIN
build/notepad.o
BIN
build/notepad.o
Binary file not shown.
BIN
build/paint.o
BIN
build/paint.o
Binary file not shown.
BIN
build/ps2.o
BIN
build/ps2.o
Binary file not shown.
BIN
build/tcp.o
BIN
build/tcp.o
Binary file not shown.
BIN
build/vm.o
BIN
build/vm.o
Binary file not shown.
BIN
build/wm.o
BIN
build/wm.o
Binary file not shown.
@@ -1,32 +1,35 @@
|
|||||||
# Brew OS 1.42 Beta
|
# BoredOS 1.50 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.
|
BoredOS 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!
|
<img src="bored.svg" width="200" /> </br>
|
||||||
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).
|
BoredOS is a simple x86_64 hobbyist operating system.
|
||||||
|
|
||||||
|
|
||||||
<img src="asciiart.png" width="200" /> </br>
|
|
||||||
Brew Kernel is a simple x86_64 hobbyist operating system.
|
|
||||||
It features a DE (and WM), a FAT32 filesystem, customizable UI and much much more!
|
It features a DE (and WM), a FAT32 filesystem, customizable UI and much much more!
|
||||||
|
|
||||||
|

|
||||||
|
*this screenshot might be outdated*
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- Drag and drop mouse centered UI
|
- Drag and drop mouse centered UI
|
||||||
- Customizable UI
|
- Customizable UI
|
||||||
- Basic Networking Stack
|
- Basic Networking Stack
|
||||||
- Brew WM
|
- Bored WM
|
||||||
- Fat 32 FS
|
- Fat 32 FS
|
||||||
- 64-bit long mode support
|
- 64-bit long mode support
|
||||||
- Multiboot2 compliant
|
- Multiboot2 compliant
|
||||||
- Text editor
|
- Text editor
|
||||||
- Markdown Viewer
|
- Markdown Viewer
|
||||||
- Minesweeper
|
- Minesweeper
|
||||||
|
- Markdown Viewer
|
||||||
|
- GUI Text editor
|
||||||
|
- Paint application
|
||||||
- IDT
|
- IDT
|
||||||
- Ability to run on actual x86_64 hardware
|
- Ability to run on actual x86_64 hardware
|
||||||
- CLI
|
- CLI
|
||||||
|
- (Limited) C Compiler
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
To build BrewOS, you'll need the following tools installed:
|
To build BoredOS, you'll need the following tools installed:
|
||||||
|
|
||||||
- **x86_64 ELF Toolchain**: `x86_64-elf-gcc`, `x86_64-elf-ld`
|
- **x86_64 ELF Toolchain**: `x86_64-elf-gcc`, `x86_64-elf-ld`
|
||||||
- **NASM**: Netwide Assembler for compiling assembly code
|
- **NASM**: Netwide Assembler for compiling assembly code
|
||||||
@@ -49,12 +52,12 @@ make
|
|||||||
This will:
|
This will:
|
||||||
1. Compile all kernel C sources and assembly files
|
1. Compile all kernel C sources and assembly files
|
||||||
2. Link the kernel ELF binary
|
2. Link the kernel ELF binary
|
||||||
3. Generate a bootable ISO image (`brewos.iso`)
|
3. Generate a bootable ISO image (`boredos.iso`)
|
||||||
|
|
||||||
The build output is organized as follows:
|
The build output is organized as follows:
|
||||||
- Compiled object files: `build/`
|
- Compiled object files: `build/`
|
||||||
- ISO root filesystem: `iso_root/`
|
- ISO root filesystem: `iso_root/`
|
||||||
- Final ISO image: `brewos.iso`
|
- Final ISO image: `boredos.iso`
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
@@ -68,14 +71,14 @@ make run
|
|||||||
|
|
||||||
Or manually:
|
Or manually:
|
||||||
```sh
|
```sh
|
||||||
qemu-system-x86_64 -m 2G -serial stdio -cdrom brewos.iso -boot d
|
qemu-system-x86_64 -m 2G -serial stdio -cdrom boredos.iso -boot d
|
||||||
```
|
```
|
||||||
|
|
||||||
### Running on Real Hardware
|
### Running on Real Hardware
|
||||||
|
|
||||||
*Warning: This is at YOUR OWN RISK. This software comes with ZERO warranty and may break your system.*
|
*Warning: This is at YOUR OWN RISK. This software comes with ZERO warranty and may break your system.*
|
||||||
|
|
||||||
1. **Create bootable USB**: Use [Balena Etcher](https://www.balena.io/etcher/) to flash `brewos.iso` to a USB drive
|
1. **Create bootable USB**: Use [Balena Etcher](https://www.balena.io/etcher/) to flash `boredos.iso` to a USB drive
|
||||||
|
|
||||||
2. **Prepare the system**:
|
2. **Prepare the system**:
|
||||||
- Enable legacy (BIOS) boot in your system BIOS/UEFI settings
|
- Enable legacy (BIOS) boot in your system BIOS/UEFI settings
|
||||||
@@ -126,6 +129,11 @@ qemu-system-x86_64 -m 2G -serial stdio -cdrom brewos.iso -boot d
|
|||||||
###
|
###
|
||||||
|
|
||||||
|
|
||||||
|
## This project was previously labeled as "BrewKernel"
|
||||||
|
Brewkernel was a text only very simple (and messy) project i started 3 years ago. It was my first work in OSDev and i absolutely loved it. It sadly just got too messy and i myself couldn't understand my own code anymore. About a year ago i started work on BoredOS, and pushed a *"working"* version of it a few days ago as of writing this *(Feb. 10 2026)*
|
||||||
|
Brewkernel has already been deprecated and will not be accepting any pull requests or fix any issues as it is now a public archive.
|
||||||
|
Thanks to everyone who helped me with Brewkernel, even if it were just ideas, and intend to keep working on this for the forseeable future!
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (C) 2024-2026 boreddevnl
|
Copyright (C) 2024-2026 boreddevnl
|
||||||
@@ -135,7 +143,7 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||||||
NOTICE
|
NOTICE
|
||||||
------
|
------
|
||||||
|
|
||||||
This product includes software developed by Chris ("boreddevnl") as part of the BrewKernel project.
|
This product includes software developed by Chris ("boreddevnl") as part of the BoredOS (Previously Brewkernel/BrewOS) project.
|
||||||
|
|
||||||
Copyright (C) 2024–2026 Chris / boreddevnl (previously boreddevhq)
|
Copyright (C) 2024–2026 Chris / boreddevnl (previously boreddevhq)
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -1,13 +1,9 @@
|
|||||||
# 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.
|
:BoredOS
|
||||||
: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:///boredos.elf
|
||||||
KERNEL_PATH=boot:///brewos.elf
|
|
||||||
|
|
||||||
#FRAMEBUFFER_WIDTH=1280
|
#FRAMEBUFFER_WIDTH=1280
|
||||||
#FRAMEBUFFER_HEIGHT=720
|
#FRAMEBUFFER_HEIGHT=720
|
||||||
|
|||||||
2
limine
2
limine
Submodule limine updated: 9e0258b727...efd130dbb6
@@ -1,13 +1,9 @@
|
|||||||
# 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.
|
:BoredOS
|
||||||
: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:///boredos.elf
|
||||||
KERNEL_PATH=boot:///brewos.elf
|
|
||||||
|
|
||||||
#FRAMEBUFFER_WIDTH=1280
|
#FRAMEBUFFER_WIDTH=1280
|
||||||
#FRAMEBUFFER_HEIGHT=720
|
#FRAMEBUFFER_HEIGHT=720
|
||||||
|
|||||||
@@ -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 : {
|
||||||
|
|||||||
BIN
screenshot.jpg
Normal file
BIN
screenshot.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 897 KiB |
@@ -5,38 +5,17 @@
|
|||||||
|
|
||||||
Window win_about;
|
Window win_about;
|
||||||
|
|
||||||
// Color definitions
|
|
||||||
#define COLOR_BLUE_LOGO 0xFF1E8AF5
|
|
||||||
#define COLOR_GREEN_LOGO 0xFF6DD651
|
|
||||||
#define COLOR_YELLOW_LOGO 0xFFF5BE34
|
|
||||||
#define COLOR_RED_LOGO 0xFFF05456
|
|
||||||
#define COLOR_PURPLE_LOGO 0xFFA65DC2
|
|
||||||
#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;
|
||||||
|
|
||||||
// Draw brewkernel ASCII logo
|
|
||||||
draw_string(offset_x, offset_y, "( (", COLOR_BLUE_LOGO);
|
|
||||||
|
|
||||||
draw_string(offset_x, offset_y + 15, " ) )", COLOR_GREEN_LOGO);
|
draw_boredos_logo(win->x + 60, offset_y, 4);
|
||||||
|
|
||||||
draw_string(offset_x, offset_y + 30, " ........", COLOR_YELLOW_LOGO);
|
|
||||||
|
|
||||||
draw_string(offset_x, offset_y + 45, " | |]", COLOR_RED_LOGO);
|
|
||||||
|
|
||||||
draw_string(offset_x, offset_y + 60, " \\ /", COLOR_PURPLE_LOGO);
|
|
||||||
|
|
||||||
draw_string(offset_x, offset_y + 75, " `----'", COLOR_CYAN_LOGO);
|
|
||||||
|
|
||||||
// Version info
|
// Version info
|
||||||
draw_string(offset_x, offset_y + 105, "BrewOS", COLOR_BLACK);
|
draw_string(offset_x, offset_y + 105, "BoredOS", COLOR_BLACK);
|
||||||
draw_string(offset_x, offset_y + 120, "BrewOS Version 1.42", COLOR_BLACK);
|
draw_string(offset_x, offset_y + 120, "BoredOS Version 1.50", 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.4.0", COLOR_BLACK);
|
||||||
|
|
||||||
// Copyright
|
// Copyright
|
||||||
draw_string(offset_x, offset_y + 150, "(C) 2026 boreddevnl.", COLOR_BLACK);
|
draw_string(offset_x, offset_y + 150, "(C) 2026 boreddevnl.", COLOR_BLACK);
|
||||||
@@ -51,7 +30,7 @@ static void about_click(Window *win, int x, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void about_init(void) {
|
void about_init(void) {
|
||||||
win_about.title = "About BrewOS";
|
win_about.title = "About BoredOS";
|
||||||
win_about.x = 250;
|
win_about.x = 250;
|
||||||
win_about.y = 180;
|
win_about.y = 180;
|
||||||
win_about.w = 185;
|
win_about.w = 185;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
; brew-os/src/kernel/boot.asm
|
; 64-bit Entry Point for BoredOS
|
||||||
; 64-bit Entry Point for BrewOS
|
|
||||||
|
|
||||||
section .text
|
section .text
|
||||||
global _start
|
global _start
|
||||||
@@ -11,7 +10,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
#include "cli_utils.h"
|
|
||||||
|
|
||||||
void cli_cmd_brewver(char *args) {
|
|
||||||
(void)args;
|
|
||||||
cli_write("BrewOS v1.42 Beta\n");
|
|
||||||
cli_write("BrewOS Kernel V2.3.1 Beta\n");
|
|
||||||
}
|
|
||||||
7
src/kernel/cli_apps/boredver.c
Normal file
7
src/kernel/cli_apps/boredver.c
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include "cli_utils.h"
|
||||||
|
|
||||||
|
void cli_cmd_boredver(char *args) {
|
||||||
|
(void)args;
|
||||||
|
cli_write("BrewOS v1.50 Beta\n");
|
||||||
|
cli_write("BrewOS Kernel V2.4.0 Beta\n");
|
||||||
|
}
|
||||||
@@ -11,11 +11,10 @@ void cli_cmd_reboot(char *args);
|
|||||||
void cli_cmd_shutdown(char *args);
|
void cli_cmd_shutdown(char *args);
|
||||||
void cli_cmd_uptime(char *args);
|
void cli_cmd_uptime(char *args);
|
||||||
void cli_cmd_man(char *args);
|
void cli_cmd_man(char *args);
|
||||||
void cli_cmd_license(char *args);
|
|
||||||
void cli_cmd_txtedit(char *args);
|
void cli_cmd_txtedit(char *args);
|
||||||
void cli_cmd_blind(char *args);
|
void cli_cmd_blind(char *args);
|
||||||
void cli_cmd_readtheman(char *args);
|
void cli_cmd_readtheman(char *args);
|
||||||
void cli_cmd_brewver(char *args);
|
void cli_cmd_boredver(char *args);
|
||||||
void cli_cmd_clear(char *args);
|
void cli_cmd_clear(char *args);
|
||||||
void cli_cmd_exit(char *args);
|
void cli_cmd_exit(char *args);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "cli_utils.h"
|
#include "cli_utils.h"
|
||||||
|
|
||||||
void cli_cmd_cowsay(char *args) {
|
void cli_cmd_cowsay(char *args) {
|
||||||
if (!args || !*args) args = (char*)"Brew!";
|
if (!args || !*args) args = (char*)"Bored!";
|
||||||
size_t len = cli_strlen(args);
|
size_t len = cli_strlen(args);
|
||||||
|
|
||||||
cli_write(" ");
|
cli_write(" ");
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ void cli_cmd_help(char *args) {
|
|||||||
cli_write(" HELP - Display this help message\n");
|
cli_write(" HELP - Display this help message\n");
|
||||||
cli_write(" DATE - Display current date and time\n");
|
cli_write(" DATE - Display current date and time\n");
|
||||||
cli_write(" CLEAR - Clear the screen\n");
|
cli_write(" CLEAR - Clear the screen\n");
|
||||||
cli_write(" BREWVER - Gives version info\n");
|
cli_write(" BOREDVER - Gives version info\n");
|
||||||
cli_write(" MATH - math <op> <a> <b> (e.g. math + 1 2)\n");
|
cli_write(" MATH - math <op> <a> <b> (e.g. math + 1 2)\n");
|
||||||
cli_write(" MAN - Show user manual (interactive)\n");
|
cli_write(" MAN - Show user manual (interactive)\n");
|
||||||
cli_write(" LICENSE - Show license (interactive)\n");
|
cli_write(" LICENSE - Show license (interactive)\n");
|
||||||
@@ -16,4 +16,5 @@ void cli_cmd_help(char *args) {
|
|||||||
cli_write(" REBOOT - Reboot system\n");
|
cli_write(" REBOOT - Reboot system\n");
|
||||||
cli_write(" SHUTDOWN - Shutdown system\n");
|
cli_write(" SHUTDOWN - Shutdown system\n");
|
||||||
cli_write(" MEMINFO - Gives memory info\n");
|
cli_write(" MEMINFO - Gives memory info\n");
|
||||||
|
cli_write(" CC - C compiler\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
#include "cli_utils.h"
|
|
||||||
|
|
||||||
// Forward declaration from cmd.c
|
|
||||||
extern void pager_wrap_content(const char **lines, int count);
|
|
||||||
extern void pager_set_mode(void);
|
|
||||||
|
|
||||||
const char* license_pages[] = {
|
|
||||||
" GNU GENERAL PUBLIC LICENSE",
|
|
||||||
" Version 3, 29 June 2007",
|
|
||||||
" Copyright (C) 2024-2026 boreddevnl",
|
|
||||||
"",
|
|
||||||
" (License text abbreviated for build size. See https://www.gnu.org/licenses/gpl-3.0.txt)",
|
|
||||||
"--- End of License ---"
|
|
||||||
};
|
|
||||||
const int license_num_lines = sizeof(license_pages) / sizeof(char*);
|
|
||||||
|
|
||||||
void cli_cmd_license(char *args) {
|
|
||||||
(void)args;
|
|
||||||
pager_wrap_content(license_pages, license_num_lines);
|
|
||||||
pager_set_mode();
|
|
||||||
}
|
|
||||||
@@ -5,37 +5,8 @@ extern void pager_wrap_content(const char **lines, int count);
|
|||||||
extern void pager_set_mode(void);
|
extern void pager_set_mode(void);
|
||||||
|
|
||||||
const char* manual_pages[] = {
|
const char* manual_pages[] = {
|
||||||
"BrewKernel User Manual",
|
"No manual round here pal",
|
||||||
"----------------------",
|
|
||||||
"",
|
|
||||||
"Welcome to the BrewKernel.",
|
|
||||||
"",
|
|
||||||
"== Features ==",
|
|
||||||
"* Ramdisk-based Filesystem: A simple in-memory filesystem.",
|
|
||||||
"* VGA Text Mode Driver: Full control over text/colors.",
|
|
||||||
"* PS/2 Keyboard Driver: Handles key presses.",
|
|
||||||
"* Simple CLI: A basic shell.",
|
|
||||||
"",
|
|
||||||
"== Available Commands ==",
|
|
||||||
"HELP: Displays a short list of available commands.",
|
|
||||||
"MAN: Shows this detailed user manual.",
|
|
||||||
"ABOUT: Displays information about the kernel.",
|
|
||||||
"MATH: A simple calculator.",
|
|
||||||
"DATE: Displays the current date and time.",
|
|
||||||
"TXTEDIT: A simple text editor with file path support.",
|
|
||||||
" USAGE: txtedit <filename>",
|
|
||||||
" EXAMPLES:",
|
|
||||||
" txtedit file.txt (relative path in current directory)",
|
|
||||||
" txtedit /file.txt (absolute path in root)",
|
|
||||||
" txtedit /docs/note.txt (absolute path with subdirectories)",
|
|
||||||
" FEATURES: Create/Edit files, Save (to RAM), Navigation.",
|
|
||||||
"CLEAR: Clears the entire screen.",
|
|
||||||
"EXIT: Exits the CLI mode.",
|
|
||||||
"LICENSE: Displays the full GNU GPL v3.",
|
|
||||||
"COWSAY: Moo!",
|
|
||||||
"UPTIME: Shows how long the system has been running.",
|
|
||||||
"BEEP: Makes a beep sound.",
|
|
||||||
"--- End of Manual ---"
|
|
||||||
};
|
};
|
||||||
const int manual_num_lines = sizeof(manual_pages) / sizeof(char*);
|
const int manual_num_lines = sizeof(manual_pages) / sizeof(char*);
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -380,14 +380,12 @@ static const CommandEntry commands[] = {
|
|||||||
{"date", cli_cmd_date},
|
{"date", cli_cmd_date},
|
||||||
{"CLEAR", cli_cmd_clear},
|
{"CLEAR", cli_cmd_clear},
|
||||||
{"clear", cli_cmd_clear},
|
{"clear", cli_cmd_clear},
|
||||||
{"BREWVER", cli_cmd_brewver},
|
{"BOREDVER", cli_cmd_boredver},
|
||||||
{"brewver", cli_cmd_brewver},
|
{"boredver", cli_cmd_boredver},
|
||||||
{"MATH", cli_cmd_math},
|
{"MATH", cli_cmd_math},
|
||||||
{"math", cli_cmd_math},
|
{"math", cli_cmd_math},
|
||||||
{"MAN", cli_cmd_man},
|
{"MAN", cli_cmd_man},
|
||||||
{"man", cli_cmd_man},
|
{"man", cli_cmd_man},
|
||||||
{"LICENSE", cli_cmd_license},
|
|
||||||
{"license", cli_cmd_license},
|
|
||||||
{"TXTEDIT", cli_cmd_txtedit},
|
{"TXTEDIT", cli_cmd_txtedit},
|
||||||
{"txtedit", cli_cmd_txtedit},
|
{"txtedit", cli_cmd_txtedit},
|
||||||
{"UPTIME", cli_cmd_uptime},
|
{"UPTIME", cli_cmd_uptime},
|
||||||
@@ -800,7 +798,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;
|
||||||
@@ -924,7 +922,7 @@ static void cmd_key(Window *target, char c) {
|
|||||||
void cmd_reset(void) {
|
void cmd_reset(void) {
|
||||||
// Reset terminal to fresh state
|
// Reset terminal to fresh state
|
||||||
cmd_screen_clear();
|
cmd_screen_clear();
|
||||||
cmd_write("BrewOS Command Prompt\n");
|
cmd_write("BoredOS Command Prompt\n");
|
||||||
if (msg_count > 0) {
|
if (msg_count > 0) {
|
||||||
cmd_write("You have ");
|
cmd_write("You have ");
|
||||||
cmd_write_int(msg_count);
|
cmd_write_int(msg_count);
|
||||||
@@ -957,14 +955,14 @@ 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"
|
"# Bored OS 1.50\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"
|
"BoredOS is now in a Beta stage as i have brought over all apps from boredkernel and have made the DE a lot more usable and stable.\n"
|
||||||
"## Brewkernel is now BrewOS!\n"
|
"## Boredkernel is now BoredOS!\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"
|
"Boredkernel 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"
|
||||||
"Brew Kernel is a simple x86_64 hobbyist operating system.\n"
|
"Bored Kernel is a simple x86_64 hobbyist operating system.\n"
|
||||||
"It features a DE (and WM), a FAT32 filesystem, customizable UI and much much more!\n\n"
|
"It features a DE (and WM), a FAT32 filesystem, customizable UI and much much more!\n\n"
|
||||||
"## Features\n"
|
"## Features\n"
|
||||||
"- Brew WM\n"
|
"- Bored WM\n"
|
||||||
"- Fat 32 FS\n"
|
"- Fat 32 FS\n"
|
||||||
"- 64-bit long mode support\n"
|
"- 64-bit long mode support\n"
|
||||||
"- Multiboot2 compliant\n"
|
"- Multiboot2 compliant\n"
|
||||||
@@ -973,7 +971,7 @@ static void create_test_files(void) {
|
|||||||
"- Ability to run on actual x86_64 hardware\n"
|
"- Ability to run on actual x86_64 hardware\n"
|
||||||
"- CLI\n\n"
|
"- CLI\n\n"
|
||||||
"## Prerequisites\n\n"
|
"## Prerequisites\n\n"
|
||||||
"To build BrewOS, you'll need the following tools installed:\n\n"
|
"To build BoredOS, you'll need the following tools installed:\n\n"
|
||||||
"- **x86_64 ELF Toolchain**: `x86_64-elf-gcc`, `x86_64-elf-ld`\n"
|
"- **x86_64 ELF Toolchain**: `x86_64-elf-gcc`, `x86_64-elf-ld`\n"
|
||||||
"- **NASM**: Netwide Assembler for compiling assembly code\n"
|
"- **NASM**: Netwide Assembler for compiling assembly code\n"
|
||||||
"- **xorriso**: For creating bootable ISO images\n"
|
"- **xorriso**: For creating bootable ISO images\n"
|
||||||
@@ -990,11 +988,11 @@ static void create_test_files(void) {
|
|||||||
"This will:\n"
|
"This will:\n"
|
||||||
"1. Compile all kernel C sources and assembly files\n"
|
"1. Compile all kernel C sources and assembly files\n"
|
||||||
"2. Link the kernel ELF binary\n"
|
"2. Link the kernel ELF binary\n"
|
||||||
"3. Generate a bootable ISO image (`brewos.iso`)\n\n"
|
"3. Generate a bootable ISO image (`boredos.iso`)\n\n"
|
||||||
"The build output is organized as follows:\n"
|
"The build output is organized as follows:\n"
|
||||||
"- Compiled object files: `build/`\n"
|
"- Compiled object files: `build/`\n"
|
||||||
"- ISO root filesystem: `iso_root/`\n"
|
"- ISO root filesystem: `iso_root/`\n"
|
||||||
"- Final ISO image: `brewos.iso`\n\n"
|
"- Final ISO image: `boredos.iso`\n\n"
|
||||||
"## Running\n\n"
|
"## Running\n\n"
|
||||||
"### QEMU Emulation\n\n"
|
"### QEMU Emulation\n\n"
|
||||||
"Run the kernel in QEMU:\n\n"
|
"Run the kernel in QEMU:\n\n"
|
||||||
@@ -1003,11 +1001,11 @@ static void create_test_files(void) {
|
|||||||
"```\n\n"
|
"```\n\n"
|
||||||
"Or manually:\n"
|
"Or manually:\n"
|
||||||
"```sh\n"
|
"```sh\n"
|
||||||
"qemu-system-x86_64 -m 2G -serial stdio -cdrom brewos.iso -boot d\n"
|
"qemu-system-x86_64 -m 2G -serial stdio -cdrom boredos.iso -boot d\n"
|
||||||
"```\n\n"
|
"```\n\n"
|
||||||
"### Running on Real Hardware\n\n"
|
"### Running on Real Hardware\n\n"
|
||||||
"*Warning: This is at YOUR OWN RISK. This software comes with ZERO warranty and may break your system.*\n\n"
|
"*Warning: This is at YOUR OWN RISK. This software comes with ZERO warranty and may break your system.*\n\n"
|
||||||
"1. **Create bootable USB**: Use [Balena Etcher](https://www.balena.io/etcher/) to flash `brewos.iso` to a USB drive\n\n"
|
"1. **Create bootable USB**: Use [Balena Etcher](https://www.balena.io/etcher/) to flash `boredos.iso` to a USB drive\n\n"
|
||||||
"2. **Prepare the system**:\n"
|
"2. **Prepare the system**:\n"
|
||||||
" - Enable legacy (BIOS) boot in your system BIOS/UEFI settings\n"
|
" - Enable legacy (BIOS) boot in your system BIOS/UEFI settings\n"
|
||||||
" - Disable Secure Boot if needed\n\n"
|
" - Disable Secure Boot if needed\n\n"
|
||||||
@@ -1033,7 +1031,7 @@ static void create_test_files(void) {
|
|||||||
"This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\n"
|
"This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\n"
|
||||||
"NOTICE\n"
|
"NOTICE\n"
|
||||||
"------\n\n"
|
"------\n\n"
|
||||||
"This product includes software developed by Chris (\"boreddevnl\") as part of the BrewKernel project.\n\n"
|
"This product includes software developed by Chris (\"boreddevnl\") as part of the BoredOS project.\n\n"
|
||||||
"Copyright (C) 2024–2026 Chris / boreddevnl (previously boreddevhq)\n\n"
|
"Copyright (C) 2024–2026 Chris / boreddevnl (previously boreddevhq)\n\n"
|
||||||
"All source files in this repository contain copyright and license\n"
|
"All source files in this repository contain copyright and license\n"
|
||||||
"headers that must be preserved in redistributions and derivative works.\n\n"
|
"headers that must be preserved in redistributions and derivative works.\n\n"
|
||||||
@@ -1056,7 +1054,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 +1091,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 \");",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "wm.h"
|
#include "wm.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
#include "cli_apps/cli_utils.h"
|
||||||
|
|
||||||
Window win_control_panel;
|
Window win_control_panel;
|
||||||
|
|
||||||
@@ -12,12 +13,14 @@ Window win_control_panel;
|
|||||||
#define COLOR_BLUE_BG 0xFF000080
|
#define COLOR_BLUE_BG 0xFF000080
|
||||||
#define COLOR_PURPLE 0xFF800080
|
#define COLOR_PURPLE 0xFF800080
|
||||||
#define COLOR_GREY 0xFF454545
|
#define COLOR_GREY 0xFF454545
|
||||||
|
#define MOUSE_BEIGE 0xFFD6D2C4
|
||||||
|
|
||||||
// Control panel state
|
// Control panel state
|
||||||
#define VIEW_MAIN 0
|
#define VIEW_MAIN 0
|
||||||
#define VIEW_WALLPAPER 1
|
#define VIEW_WALLPAPER 1
|
||||||
#define VIEW_NETWORK 2
|
#define VIEW_NETWORK 2
|
||||||
#define VIEW_DESKTOP 3
|
#define VIEW_DESKTOP 3
|
||||||
|
#define VIEW_MOUSE 4
|
||||||
|
|
||||||
static int current_view = VIEW_MAIN;
|
static int current_view = VIEW_MAIN;
|
||||||
static char rgb_r[4] = "";
|
static char rgb_r[4] = "";
|
||||||
@@ -208,6 +211,22 @@ static void control_panel_paint_main(Window *win) {
|
|||||||
draw_rect(offset_x + 5, desk_offset_y + 6, 24, 1, COLOR_BLACK);
|
draw_rect(offset_x + 5, desk_offset_y + 6, 24, 1, COLOR_BLACK);
|
||||||
draw_rect(offset_x + 5, desk_offset_y + 6, 1, 14, COLOR_BLACK);
|
draw_rect(offset_x + 5, desk_offset_y + 6, 1, 14, COLOR_BLACK);
|
||||||
draw_string(offset_x + 40, desk_offset_y + 8, "Desktop", 0xFF000000);
|
draw_string(offset_x + 40, desk_offset_y + 8, "Desktop", 0xFF000000);
|
||||||
|
|
||||||
|
// Draw Mouse Icon
|
||||||
|
int mouse_offset_y = desk_offset_y + 35;
|
||||||
|
// Mouse body
|
||||||
|
draw_rect(offset_x + 17, mouse_offset_y, 1, 2, COLOR_BLACK);
|
||||||
|
draw_rect(offset_x + 16, mouse_offset_y - 2, 1, 2, COLOR_BLACK);
|
||||||
|
draw_rect(offset_x + 10, mouse_offset_y + 2, 15, 20, MOUSE_BEIGE);
|
||||||
|
draw_rect(offset_x + 10, mouse_offset_y + 2, 15, 1, COLOR_BLACK);
|
||||||
|
draw_rect(offset_x + 10, mouse_offset_y + 2, 1, 20, COLOR_BLACK);
|
||||||
|
draw_rect(offset_x + 24, mouse_offset_y + 2, 1, 20, COLOR_BLACK);
|
||||||
|
draw_rect(offset_x + 10, mouse_offset_y + 21, 15, 1, COLOR_BLACK);
|
||||||
|
// Buttons separator
|
||||||
|
draw_rect(offset_x + 10, mouse_offset_y + 8, 15, 1, COLOR_BLACK);
|
||||||
|
draw_rect(offset_x + 17, mouse_offset_y + 2, 1, 6, COLOR_BLACK);
|
||||||
|
|
||||||
|
draw_string(offset_x + 40, mouse_offset_y + 8, "Mouse", 0xFF000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void control_panel_paint_wallpaper(Window *win) {
|
static void control_panel_paint_wallpaper(Window *win) {
|
||||||
@@ -468,6 +487,30 @@ static void control_panel_paint_desktop(Window *win) {
|
|||||||
draw_button(offset_x + 180, section_y, 20, 20, "+", false);
|
draw_button(offset_x + 180, section_y, 20, 20, "+", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void control_panel_paint_mouse(Window *win) {
|
||||||
|
int offset_x = win->x + 8;
|
||||||
|
int offset_y = win->y + 30;
|
||||||
|
|
||||||
|
// Back button
|
||||||
|
draw_string(offset_x, offset_y, "< Back", 0xFF000080);
|
||||||
|
draw_string(offset_x, offset_y + 25, "Mouse Settings:", 0xFF000000);
|
||||||
|
|
||||||
|
int section_y = offset_y + 60;
|
||||||
|
draw_string(offset_x, section_y, "Speed:", COLOR_BLACK);
|
||||||
|
|
||||||
|
// Slider track
|
||||||
|
draw_rect(offset_x + 60, section_y + 8, 200, 2, COLOR_DKGRAY);
|
||||||
|
|
||||||
|
// Slider knob (range 1-50, default 10)
|
||||||
|
int knob_x = offset_x + 60 + (mouse_speed - 1) * 190 / 49;
|
||||||
|
draw_button(knob_x, section_y, 10, 18, "", false);
|
||||||
|
|
||||||
|
draw_string(offset_x + 270, section_y + 4, "x", COLOR_BLACK);
|
||||||
|
char speed_str[4];
|
||||||
|
cli_itoa(mouse_speed, speed_str);
|
||||||
|
draw_string(offset_x + 280, section_y + 4, speed_str, COLOR_BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
static void control_panel_paint(Window *win) {
|
static void control_panel_paint(Window *win) {
|
||||||
if (current_view == VIEW_MAIN) {
|
if (current_view == VIEW_MAIN) {
|
||||||
control_panel_paint_main(win);
|
control_panel_paint_main(win);
|
||||||
@@ -477,6 +520,8 @@ static void control_panel_paint(Window *win) {
|
|||||||
control_panel_paint_network(win);
|
control_panel_paint_network(win);
|
||||||
} else if (current_view == VIEW_DESKTOP) {
|
} else if (current_view == VIEW_DESKTOP) {
|
||||||
control_panel_paint_desktop(win);
|
control_panel_paint_desktop(win);
|
||||||
|
} else if (current_view == VIEW_MOUSE) {
|
||||||
|
control_panel_paint_mouse(win);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,6 +553,13 @@ static void control_panel_handle_click(Window *win, int x, int y) {
|
|||||||
y >= desk_offset_y && y < desk_offset_y + 25) {
|
y >= desk_offset_y && y < desk_offset_y + 25) {
|
||||||
current_view = VIEW_DESKTOP;
|
current_view = VIEW_DESKTOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check mouse button
|
||||||
|
int mouse_offset_y = desk_offset_y + 35;
|
||||||
|
if (x >= offset_x + 5 && x < offset_x + 120 &&
|
||||||
|
y >= mouse_offset_y && y < mouse_offset_y + 25) {
|
||||||
|
current_view = VIEW_MOUSE;
|
||||||
|
}
|
||||||
} else if (current_view == VIEW_WALLPAPER) {
|
} else if (current_view == VIEW_WALLPAPER) {
|
||||||
int offset_x = 8;
|
int offset_x = 8;
|
||||||
int offset_y = 30;
|
int offset_y = 30;
|
||||||
@@ -862,6 +914,25 @@ static void control_panel_handle_click(Window *win, int x, int y) {
|
|||||||
desktop_max_cols++;
|
desktop_max_cols++;
|
||||||
wm_refresh_desktop();
|
wm_refresh_desktop();
|
||||||
}
|
}
|
||||||
|
} else if (current_view == VIEW_MOUSE) {
|
||||||
|
int offset_x = 8;
|
||||||
|
int offset_y = 30;
|
||||||
|
|
||||||
|
// Back button
|
||||||
|
if (x >= offset_x && x < offset_x + 40 && y >= offset_y && y < offset_y + 15) {
|
||||||
|
current_view = VIEW_MAIN;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int section_y = offset_y + 60;
|
||||||
|
// Slider interaction
|
||||||
|
if (x >= offset_x + 60 && x <= offset_x + 260 && y >= section_y && y <= section_y + 20) {
|
||||||
|
int new_speed = 1 + (x - (offset_x + 60)) * 49 / 200;
|
||||||
|
if (new_speed < 1) new_speed = 1;
|
||||||
|
if (new_speed > 50) new_speed = 50;
|
||||||
|
mouse_speed = new_speed;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
@@ -193,6 +238,39 @@ void graphics_set_bg_pattern(const uint32_t *pattern) {
|
|||||||
g_use_pattern = true;
|
g_use_pattern = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void draw_boredos_logo(int x, int y, int scale) {
|
||||||
|
|
||||||
|
static const uint8_t brewos_bmp[] = {
|
||||||
|
0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0, // 0: Ears
|
||||||
|
0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0, // 1: Ears
|
||||||
|
1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1, // 2: Ears (Separated)
|
||||||
|
1,1,1,1,2,2,2,2,2,2,2,2,1,1,1,1, // 3: Forehead / Ears
|
||||||
|
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1, // 4: Face
|
||||||
|
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1, // 5: Eyes start
|
||||||
|
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1, // 6: Eyes
|
||||||
|
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1, // 7: Eyes
|
||||||
|
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1, // 8: Eyes
|
||||||
|
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1, // 9: Under eyes
|
||||||
|
1,1,2,2,2,2,2,1,1,2,2,2,2,2,1,1, // 10: Nose
|
||||||
|
1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,1, // 11: Cheeks
|
||||||
|
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1, // 12: Jaw
|
||||||
|
0,1,1,1,2,2,2,2,2,2,2,2,1,1,1,0, // 13: Chin
|
||||||
|
0,0,1,1,1,2,2,2,2,2,2,1,1,1,0,0, // 14: Chin outline
|
||||||
|
0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0 // 15: Bottom
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int r = 0; r < 16; r++) {
|
||||||
|
for (int c = 0; c < 16; c++) {
|
||||||
|
uint8_t p = brewos_bmp[r * 16 + c];
|
||||||
|
if (p == 1) {
|
||||||
|
draw_rect(x + c * scale, y + r * scale, scale, scale, 0xFF1A1A1A); // rgb(26,26,26)
|
||||||
|
} else if (p == 2) {
|
||||||
|
draw_rect(x + c * scale, y + r * scale, scale, scale, 0xFFFEFEFE); // rgb(254,254,254)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Double buffering functions
|
// Double buffering functions
|
||||||
void graphics_clear_back_buffer(uint32_t color) {
|
void graphics_clear_back_buffer(uint32_t color) {
|
||||||
if (!g_fb) return;
|
if (!g_fb) return;
|
||||||
@@ -203,20 +281,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++) {
|
if (x < 0) { w += x; x = 0; }
|
||||||
// Copy one scanline
|
if (y < 0) { h += y; y = 0; }
|
||||||
uint32_t *dst_row = (uint32_t *)dst;
|
if (x + w > (int)g_fb->width) w = g_fb->width - x;
|
||||||
for (int x = 0; x < (int)g_fb->width; x++) {
|
if (y + h > (int)g_fb->height) h = g_fb->height - y;
|
||||||
dst_row[x] = src[x];
|
|
||||||
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ void draw_desktop_background(void);
|
|||||||
void graphics_set_bg_color(uint32_t color);
|
void graphics_set_bg_color(uint32_t color);
|
||||||
void graphics_set_bg_pattern(const uint32_t *pattern); // 128x128 pattern
|
void graphics_set_bg_pattern(const uint32_t *pattern); // 128x128 pattern
|
||||||
|
|
||||||
|
|
||||||
|
void draw_boredos_logo(int x, int y, int scale);
|
||||||
|
|
||||||
// Get screen dimensions
|
// Get screen dimensions
|
||||||
int get_screen_width(void);
|
int get_screen_width(void);
|
||||||
int get_screen_height(void);
|
int get_screen_height(void);
|
||||||
|
|||||||
@@ -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,6 +211,7 @@ 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];
|
||||||
@@ -222,19 +219,28 @@ void markdown_open_file(const char *filename) {
|
|||||||
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);
|
||||||
|
lines[line].type = MD_LINE_CODE;
|
||||||
|
lines[line].indent_level = 0;
|
||||||
|
line++;
|
||||||
|
} else {
|
||||||
|
char parsed_content[256];
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Store parsed line
|
|
||||||
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);
|
||||||
@@ -149,6 +146,7 @@ static void paint_click(Window *win, int x, int y) {
|
|||||||
if (x >= 12 && x < 48) {
|
if (x >= 12 && x < 48) {
|
||||||
if (y >= win->h - 65 && y < win->h - 45) {
|
if (y >= win->h - 65 && y < win->h - 45) {
|
||||||
paint_reset();
|
paint_reset();
|
||||||
|
wm_mark_dirty(win->x, win->y, win->w, win->h);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (y >= win->h - 40 && y < win->h - 20) {
|
if (y >= win->h - 40 && y < win->h - 20) {
|
||||||
@@ -164,6 +162,7 @@ static void paint_click(Window *win, int x, int y) {
|
|||||||
if (y >= cy && y < cy + 20) {
|
if (y >= cy && y < cy + 20) {
|
||||||
uint32_t colors[] = {COLOR_BLACK, COLOR_RED, COLOR_APPLE_GREEN, COLOR_APPLE_BLUE, COLOR_APPLE_YELLOW, COLOR_WHITE};
|
uint32_t colors[] = {COLOR_BLACK, COLOR_RED, COLOR_APPLE_GREEN, COLOR_APPLE_BLUE, COLOR_APPLE_YELLOW, COLOR_WHITE};
|
||||||
current_color = colors[i];
|
current_color = colors[i];
|
||||||
|
wm_mark_dirty(win->x, win->y, win->w, win->h);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,6 +170,15 @@ static void paint_click(Window *win, int x, int y) {
|
|||||||
paint_handle_mouse(x, y);
|
paint_handle_mouse(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void paint_mouse_move(Window *win, int x, int y, uint8_t buttons) {
|
||||||
|
if (buttons & 0x01) { // Left button down
|
||||||
|
paint_handle_mouse(x, y);
|
||||||
|
wm_mark_dirty(win->x, win->y, win->w, win->h);
|
||||||
|
} else {
|
||||||
|
paint_reset_last_pos();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void paint_init(void) {
|
void paint_init(void) {
|
||||||
win_paint.title = "Paint";
|
win_paint.title = "Paint";
|
||||||
win_paint.x = 150;
|
win_paint.x = 150;
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
// Simple Stack-Based VM
|
// Simple Stack-Based VM
|
||||||
// Header: "BREWEXE" (7 bytes) + Version (1 byte)
|
// Header: "BORDEXE" (7 bytes) + Version (1 byte)
|
||||||
|
|
||||||
#define VM_MAGIC "BREWEXE"
|
#define VM_MAGIC "BORDEXE"
|
||||||
#define VM_STACK_SIZE 256
|
#define VM_STACK_SIZE 256
|
||||||
#define VM_MEMORY_SIZE (64 * 1024) // 64KB
|
#define VM_MEMORY_SIZE (64 * 1024) // 64KB
|
||||||
|
|
||||||
|
|||||||
565
src/kernel/wm.c
565
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,13 @@ 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;
|
||||||
|
|
||||||
|
// Mouse Settings
|
||||||
|
int mouse_speed = 10; // Default 1.0x (range 1-50)
|
||||||
|
static int mouse_accum_x = 0;
|
||||||
|
static int mouse_accum_y = 0;
|
||||||
|
|
||||||
// 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 +170,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 +279,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 +347,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);
|
||||||
|
|
||||||
@@ -365,38 +373,6 @@ void draw_button(int x, int y, int w, int h, const char *text, bool pressed) {
|
|||||||
draw_string(tx, ty, text, COLOR_BLACK);
|
draw_string(tx, ty, text, COLOR_BLACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_coffee_cup(int x, int y, int size) {
|
|
||||||
int cup_w = size;
|
|
||||||
int cup_h = size - 2;
|
|
||||||
|
|
||||||
draw_rect(x + 1, y + 2, cup_w - 2, cup_h - 3, COLOR_LTGRAY);
|
|
||||||
|
|
||||||
// Cup outline
|
|
||||||
draw_rect(x + 1, y + 2, cup_w - 2, 1, COLOR_BLACK); // Top
|
|
||||||
draw_rect(x + 1, y + 2, 1, cup_h - 3, COLOR_BLACK); // Left
|
|
||||||
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
|
|
||||||
|
|
||||||
// Rounded bottom corners
|
|
||||||
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);
|
|
||||||
|
|
||||||
// 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 - 2, y + 3, 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 coffee_y = y + 4;
|
|
||||||
draw_rect(x + 2, coffee_y, cup_w - 4, stripe_height, COLOR_APPLE_BLUE);
|
|
||||||
draw_rect(x + 2, coffee_y + stripe_height, cup_w - 4, stripe_height, COLOR_APPLE_GREEN);
|
|
||||||
draw_rect(x + 2, coffee_y + stripe_height * 2, cup_w - 4, stripe_height, COLOR_APPLE_YELLOW);
|
|
||||||
draw_rect(x + 2, coffee_y + stripe_height * 3, cup_w - 4, stripe_height, COLOR_APPLE_RED);
|
|
||||||
draw_rect(x + 2, coffee_y + stripe_height * 4, cup_w - 4, stripe_height, COLOR_APPLE_VIOLET);
|
|
||||||
draw_rect(x + 2, coffee_y + stripe_height * 5, cup_w - 4, stripe_height, COLOR_APPLE_BLUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_icon(int x, int y, const char *label) {
|
void draw_icon(int x, int y, const char *label) {
|
||||||
// Simple "File" Icon
|
// Simple "File" Icon
|
||||||
draw_rect(x + 29, y, 20, 25, COLOR_WHITE);
|
draw_rect(x + 29, y, 20, 25, COLOR_WHITE);
|
||||||
@@ -601,7 +577,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,9 +672,12 @@ 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
|
||||||
@@ -707,6 +686,12 @@ void wm_paint(void) {
|
|||||||
// 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 +719,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 +746,17 @@ 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 && !win->focused) {
|
||||||
|
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
|
||||||
@@ -767,10 +765,10 @@ void wm_paint(void) {
|
|||||||
|
|
||||||
// 5. Start Button
|
// 5. Start Button
|
||||||
draw_bevel_rect(2, sh - 26, 90, 24, start_menu_open);
|
draw_bevel_rect(2, sh - 26, 90, 24, start_menu_open);
|
||||||
// Draw BrewOS logo
|
// Draw Boredos logo
|
||||||
draw_coffee_cup(5, sh - 24, 20);
|
draw_boredos_logo(6, sh - 22, 1);
|
||||||
// Draw BrewOS text
|
// Draw BoredOS text
|
||||||
draw_string(35, sh - 18, "BrewOS", COLOR_BLACK);
|
draw_string(35, sh - 18, "BoredOS", COLOR_BLACK);
|
||||||
|
|
||||||
// Clock
|
// Clock
|
||||||
draw_clock(sw - 80, sh - 20);
|
draw_clock(sw - 80, sh - 20);
|
||||||
@@ -790,7 +788,7 @@ void wm_paint(void) {
|
|||||||
draw_string(8, menu_y + 108, "Minesweeper", COLOR_BLACK);
|
draw_string(8, menu_y + 108, "Minesweeper", COLOR_BLACK);
|
||||||
draw_string(8, menu_y + 128, "Control Panel", COLOR_BLACK);
|
draw_string(8, menu_y + 128, "Control Panel", COLOR_BLACK);
|
||||||
draw_string(8, menu_y + 148, "Paint", COLOR_BLACK);
|
draw_string(8, menu_y + 148, "Paint", COLOR_BLACK);
|
||||||
draw_string(8, menu_y + 168, "About BrewOS", COLOR_BLACK);
|
draw_string(8, menu_y + 168, "About BoredOS", COLOR_BLACK);
|
||||||
|
|
||||||
// Separator line
|
// Separator line
|
||||||
draw_rect(5, menu_y + 185, 110, 1, COLOR_BLACK);
|
draw_rect(5, menu_y + 185, 110, 1, COLOR_BLACK);
|
||||||
@@ -803,30 +801,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
|
||||||
}
|
|
||||||
|
|
||||||
int item_h = 25;
|
draw_string(desktop_menu_x + 5, desktop_menu_y + 5, "Cut", COLOR_BLACK);
|
||||||
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", COLOR_BLACK);
|
||||||
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 * 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 * 3, "Delete", can_cut_copy ? COLOR_RED : COLOR_DKGRAY);
|
draw_string(desktop_menu_x + 5, desktop_menu_y + 5 + item_h * 4, "Rename", COLOR_BLACK);
|
||||||
draw_string(desktop_menu_x + 5, desktop_menu_y + 5 + item_h * 4, "Rename", can_cut_copy ? COLOR_BLACK : COLOR_DKGRAY);
|
} 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 +834,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 +893,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 +908,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 +936,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 +952,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 +968,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 +1019,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;
|
||||||
@@ -1142,8 +1197,17 @@ void wm_handle_right_click(int x, int y) {
|
|||||||
prev_mx = mx;
|
prev_mx = mx;
|
||||||
prev_my = my;
|
prev_my = my;
|
||||||
|
|
||||||
mx += dx;
|
mouse_accum_x += dx * mouse_speed;
|
||||||
my += dy;
|
mouse_accum_y += dy * mouse_speed;
|
||||||
|
|
||||||
|
int move_x = mouse_accum_x / 10;
|
||||||
|
int move_y = mouse_accum_y / 10;
|
||||||
|
|
||||||
|
mouse_accum_x -= move_x * 10;
|
||||||
|
mouse_accum_y -= move_y * 10;
|
||||||
|
|
||||||
|
mx += move_x;
|
||||||
|
my += move_y;
|
||||||
|
|
||||||
if (mx < 0) mx = 0;
|
if (mx < 0) mx = 0;
|
||||||
if (my < 0) my = 0;
|
if (my < 0) my = 0;
|
||||||
@@ -1228,7 +1292,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 +1306,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 +1335,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 +1368,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")) {
|
if (str_ends_with(icon->name, ".shortcut") && !str_starts_with(icon->name, "Recycle Bin")) {
|
||||||
FAT32_FileHandle *fh = fat32_open(path, "r");
|
FAT32_FileHandle *fh = fat32_open(path, "r");
|
||||||
if (fh) {
|
if (fh) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
int len = fat32_read(fh, buf, 255);
|
int len = fat32_read(fh, buf, 255);
|
||||||
fat32_close(fh);
|
fat32_close(fh);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
buf[len] = 0;
|
buf[len] = 0;
|
||||||
if (fat32_is_directory(buf)) {
|
if (fat32_is_directory(buf)) {
|
||||||
explorer_open_directory(buf);
|
explorer_open_directory(buf);
|
||||||
wm_bring_to_front(&win_explorer);
|
} 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 +1421,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 +1443,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 +1479,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
|
||||||
if (desktop_auto_align && !msg_box_visible) {
|
char filename[64];
|
||||||
// Find the newly added icon (it will be at the end)
|
int len = 0; while(drag_file_path[len]) len++;
|
||||||
// Extract filename from drag_file_path
|
int s = len - 1; while(s >= 0 && drag_file_path[s] != '/') s--;
|
||||||
char filename[64];
|
s++;
|
||||||
int len = 0; while(drag_file_path[len]) len++;
|
int d = 0; while(drag_file_path[s] && d < 63) filename[d++] = drag_file_path[s++];
|
||||||
int s = len - 1; while(s >= 0 && drag_file_path[s] != '/') s--;
|
filename[d] = 0;
|
||||||
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) {
|
||||||
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 +1549,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 +1579,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 +1607,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 +1629,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 +1668,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 +1718,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 +1827,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);
|
||||||
@@ -82,4 +85,7 @@ extern bool desktop_auto_align;
|
|||||||
extern int desktop_max_rows_per_col;
|
extern int desktop_max_rows_per_col;
|
||||||
extern int desktop_max_cols;
|
extern int desktop_max_cols;
|
||||||
|
|
||||||
|
// Mouse Settings
|
||||||
|
extern int mouse_speed;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user