This commit is contained in:
boreddevnl 2026-03-01 06:06:43 +01:00
parent c5c77ce734
commit 05c1f37a86
27 changed files with 581 additions and 15399 deletions

BIN
.DS_Store vendored

Binary file not shown.

View file

@ -107,8 +107,15 @@ $(ISO_IMAGE): $(KERNEL_ELF) limine.cfg limine-setup
# Copy README
@if [ -f README.md ]; then cp README.md $(ISO_DIR)/; fi
# Copy Wallpaper (if it exists)
@if [ -f src/kernel/wallpaper.ppm ]; then cp src/kernel/wallpaper.ppm $(ISO_DIR)/; fi
# Copy Wallpapers
mkdir -p $(ISO_DIR)/Library/images/Wallpapers
@for f in $(SRC_DIR)/images/wallpapers/*.jpg; do \
if [ -f "$$f" ]; then \
basename=$$(basename "$$f"); \
cp "$$f" $(ISO_DIR)/Library/images/Wallpapers/; \
echo " MODULE_PATH=boot:///Library/images/Wallpapers/$$basename" >> $(ISO_DIR)/limine.cfg; \
fi \
done
@if [ -f splash.jpg ]; then cp splash.jpg $(ISO_DIR)/; fi
# Copy Limine Bootloader Files (flat structure in binary branch)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/kernel/.DS_Store vendored

Binary file not shown.

View file

@ -1880,6 +1880,47 @@ static void create_ramfs_files(void) {
}
}
// Create default sysfetch configuration file
if (!fat32_exists("Library/conf/sysfetch.cfg")) {
FAT32_FileHandle *cfg = fat32_open("Library/conf/sysfetch.cfg", "w");
if (cfg) {
const char *config_content =
"// BoredOS System Fetch Configuration\n"
"// ----------------------------------\n"
"// To use custom ascii art, uncomment the line below and point it to your file.\n"
"ascii_art_file=A:/Library/art/boredos.txt\n"
"user_host_string=root@boredos\n"
"separator=------------\n"
"\n"
"// Labels (leave empty to hide a line)\n"
"os_label=OS\n"
"kernel_label=Kernel\n"
"uptime_label=Uptime\n"
"shell_label=Shell\n"
"memory_label=Memory\n";
fat32_write(cfg, (void *)config_content, cmd_strlen(config_content));
fat32_close(cfg);
}
}
// Create default art directory and file
if (!fat32_exists("Library/art")) {
fat32_mkdir("Library/art");
}
if (!fat32_exists("Library/art/boredos.txt")) {
FAT32_FileHandle *art = fat32_open("Library/art/boredos.txt", "w");
if (art) {
const char *art_content =
"\033[35m==================== \033[97m__ ____ ____ \033[0m\n"
"\033[35m=================== \033[97m/ /_ / __ \\/ ___\\\033[0m\n"
"\033[34m================== \033[97m/ __ \\/ / / /\\___ \\\033[0m\n"
"\033[34m================= \033[97m/ /_/ / /_/ /____/ /\033[0m\n"
"\033[36m================ \033[97m/_.___/\\____//_____/ \033[0m\n"
"\033[36m=============== \033[0m\n";
fat32_write(art, (void *)art_content, cmd_strlen(art_content));
fat32_close(art);
}
}

View file

@ -1539,6 +1539,11 @@ int fat32_list_directory(const char *path, FAT32_FileInfo *entries, int max_entr
char normalized[FAT32_MAX_PATH];
fat32_normalize_path(p, normalized);
extern void serial_write(const char *str);
serial_write("[DEBUG] fat32_list_directory (RAMFS) path: ");
serial_write(normalized);
serial_write("\n");
for (int i = 0; i < MAX_FILES && count < max_entries; i++) {
if (files[i].used && fs_strcmp(files[i].parent_path, normalized) == 0) {
fs_strcpy(entries[count].name, files[i].filename);
@ -1548,6 +1553,10 @@ int fat32_list_directory(const char *path, FAT32_FileInfo *entries, int max_entr
count++;
}
}
serial_write("[DEBUG] fat32_list_directory (RAMFS) found count: ");
extern void serial_write_num(uint32_t n);
serial_write_num(count);
serial_write("\n");
} else {
count = realfs_list_directory(drive, p, entries, max_entries);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View file

@ -148,12 +148,13 @@ void kmain(void) {
process_init();
serial_write("[DEBUG] Skipping user mode test, proceeding with normal boot.\n");
fat32_init();
serial_write("[DEBUG] fat32_init OK\n");
fat32_mkdir("/bin");
serial_write("[DEBUG] /bin directory created/checked\n");
fat32_mkdir("/Library");
fat32_mkdir("/Library/images");
fat32_mkdir("/Library/images/Wallpapers");
if (module_request.response == NULL) {
serial_write("[DEBUG] ERROR: Limine Module Response is NULL!\n");

View file

@ -55,7 +55,7 @@ void create_man_entries(void) {
write_man_file("touch", "TOUCH - Create empty file\n\nUsage: touch <filename>\n\nCreates a new empty file if it doesn't exist.");
write_man_file("cc", "CC - C Compiler\n\nUsage: cc <file.c>\n\nThe BoredOS C Compiler. Compiles C source files into executables. (execute these with ./>file<)");
write_man_file("crash", "CRASH - Trigger kernel exception\n\nUsage: crash\n\nIntentionally triggers a null pointer dereference to test handlers.");
write_man_file("boredver", "BOREDVER - Show OS version\n\nUsage: boredver\n\nDisplays current BoredOS version and kernel build information.");
write_man_file("sysfetch", "SYSFETCH - Show OS information\n\nUsage: sysfetch\n\nDisplays system information in a neofetch-like layout. Configurable via A:/Library/conf/sysfetch.cfg.");
write_man_file("meminfo", "MEMINFO - Memory usage stats\n\nUsage: meminfo\n\nDisplays current physical and virtual memory allocation statistics.");
write_man_file("pci_list", "PCI_LIST - Scan PCI bus\n\nUsage: pci_list\n\nScans the PCI bus and lists all detected hardware devices.");
write_man_file("reboot", "REBOOT - Restart system\n\nUsage: reboot\n\nRestarts the computer immediately.");

View file

@ -233,17 +233,17 @@ process_t* process_create_elf(const char* filepath, const char* args_str) {
*(--stack_ptr) = 0x202; // RFLAGS (Interrupts Enabled)
*(--stack_ptr) = 0x23; // CS (User Mode Code)
*(--stack_ptr) = entry_point; // RIP
*(--stack_ptr) = 0; // int_no
*(--stack_ptr) = 0; // err_code
*(--stack_ptr) = 0; // int_no
// 15 General purpose registers
*(--stack_ptr) = 0; // RAX
*(--stack_ptr) = 0; // RBX
*(--stack_ptr) = 0; // RCX
*(--stack_ptr) = 0; // RDX
*(--stack_ptr) = 0; // RBP
*(--stack_ptr) = argc; // RDI = argc
*(--stack_ptr) = actual_argv_ptr; // RSI = actual argv array
*(--stack_ptr) = argc; // RDI = argc
*(--stack_ptr) = 0; // RBP
*(--stack_ptr) = 0; // R8
*(--stack_ptr) = 0; // R9
*(--stack_ptr) = 0; // R10

View file

@ -550,11 +550,8 @@ static uint64_t syscall_handler_inner(uint64_t syscall_num, uint64_t arg1, uint6
extern void wm_refresh(void);
wm_refresh();
return 0;
} else if (cmd == 3) { // SYSTEM_CMD_SET_WALLPAPER
int wp_id = (int)arg2;
extern void wallpaper_request_set(int index);
wallpaper_request_set(wp_id);
return 0;
} else if (cmd == 3) { // SYSTEM_CMD_SET_WALLPAPER (Obsolete)
return -1;
} else if (cmd == 4) { // SYSTEM_CMD_SET_DESKTOP_PROP
int prop = (int)arg2;
int val = (int)arg3;
@ -590,17 +587,8 @@ static uint64_t syscall_handler_inner(uint64_t syscall_num, uint64_t arg1, uint6
} else if (cmd == 8) { // SYSTEM_CMD_GET_MOUSE_SPEED
extern int mouse_speed;
return mouse_speed;
} else if (cmd == 9) { // SYSTEM_CMD_GET_WALLPAPER_THUMB
int id = (int)arg2;
uint32_t *dest = (uint32_t *)arg3;
if (!dest) return -1;
extern uint32_t* wallpaper_get_thumb(int index);
extern _Bool wallpaper_thumb_valid(int index);
if (!wallpaper_thumb_valid(id)) return -1;
uint32_t *thumb = wallpaper_get_thumb(id);
if (!thumb) return -1;
for (int i=0; i<100*60; i++) dest[i] = thumb[i];
return 0;
} else if (cmd == 9) { // SYSTEM_CMD_GET_WALLPAPER_THUMB (Obsolete)
return -1;
} else if (cmd == 10) { // SYSTEM_CMD_CLEAR_SCREEN
extern void cmd_screen_clear(void);
cmd_screen_clear();
@ -721,6 +709,22 @@ static uint64_t syscall_handler_inner(uint64_t syscall_num, uint64_t arg1, uint6
uint32_t color = (uint32_t)arg2;
cmd_set_current_color(color);
return 0;
} else if (cmd == 31) { // SYSTEM_CMD_SET_WALLPAPER_PATH
const char *user_path = (const char *)arg2;
if (!user_path) return -1;
// Copy path safely to kernel buffer
char kernel_path[256];
int i = 0;
while (i < 255 && user_path[i]) {
kernel_path[i] = user_path[i];
i++;
}
kernel_path[i] = 0;
extern void wallpaper_request_set_from_file(const char *path);
wallpaper_request_set_from_file(kernel_path);
return 0;
}
return -1;
}

View file

@ -36,6 +36,9 @@ $(BIN_DIR)/%.o: %.c
$(BIN_DIR)/viewer.elf: $(LIBC_OBJS) $(BIN_DIR)/viewer.o $(BIN_DIR)/nanojpeg.o
$(LD) $(LDFLAGS) $^ -o $@
$(BIN_DIR)/settings.elf: $(LIBC_OBJS) $(BIN_DIR)/settings.o $(BIN_DIR)/nanojpeg.o
$(LD) $(LDFLAGS) $^ -o $@
$(BIN_DIR)/%.elf: $(LIBC_OBJS) $(BIN_DIR)/%.o
$(LD) $(LDFLAGS) $^ -o $@

View file

@ -5,52 +5,97 @@
#include "libui.h"
#include <stddef.h>
static void draw_boredos_logo(ui_window_t win, 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,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,
1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,
1,1,1,1,2,2,2,2,2,2,2,2,1,1,1,1,
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1,
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1,
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1,
1,1,2,2,2,2,2,1,1,2,2,2,2,2,1,1,
1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,1,
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1,
0,1,1,1,2,2,2,2,2,2,2,2,1,1,1,0,
0,0,1,1,1,2,2,2,2,2,2,1,1,1,0,0,
0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0
static uint32_t ansi_to_boredos_color(int code) {
uint32_t default_color = 0xFFFFFFFF;
switch (code) {
case 0: return default_color;
case 30: return 0xFF000000; // Black
case 31: return 0xFFFF4444; // Red
case 32: return 0xFF6A9955; // Green
case 33: return 0xFFFFFF00; // Yellow
case 34: return 0xFF569CD6; // Blue
case 35: return 0xFFB589D6; // Magenta
case 36: return 0xFF4EC9B0; // Cyan
case 37: return 0xFFCCCCCC; // White
case 90: return 0xFF808080; // Bright Black (Gray)
case 91: return 0xFFFF6B6B; // Bright Red
case 92: return 0xFF78DE78; // Bright Green
case 93: return 0xFFFFFF55; // Bright Yellow
case 94: return 0xFF87CEEB; // Bright Blue
case 95: return 0xFFFF77FF; // Bright Magenta
case 96: return 0xFF66D9EF; // Bright Cyan
case 97: return 0xFFFFFFFF; // Bright White
default: return default_color;
}
}
static void draw_ansi_string(ui_window_t win, int x, int y, const char *str) {
uint32_t current_color = 0xFFFFFFFF;
int current_x = x;
char segment[256];
int seg_idx = 0;
while (*str) {
if (*str == '\033' && *(str + 1) == '[') {
if (seg_idx > 0) {
segment[seg_idx] = 0;
ui_draw_string(win, current_x, y, segment, current_color);
current_x += seg_idx * 8;
seg_idx = 0;
}
str += 2;
int code = 0;
while (*str >= '0' && *str <= '9') {
code = code * 10 + (*str - '0');
str++;
}
if (*str == 'm') {
current_color = ansi_to_boredos_color(code);
str++;
}
} else {
segment[seg_idx++] = *str++;
}
}
if (seg_idx > 0) {
segment[seg_idx] = 0;
ui_draw_string(win, current_x, y, segment, current_color);
}
}
static void draw_ascii_logo(ui_window_t win, int x, int y) {
const char *logo[] = {
"\033[35m==================== \033[97m__ ____ ____ \033[0m",
"\033[35m=================== \033[97m/ /_ / __ \\/ ___\\\033[0m",
"\033[34m================== \033[97m/ __ \\/ / / /\\___ \\\033[0m",
"\033[34m================= \033[97m/ /_/ / /_/ /____/ /\033[0m",
"\033[36m================ \033[97m/_.___/\\____//_____/ \033[0m",
"\033[36m=============== \033[0m",
NULL
};
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) {
ui_draw_rect(win, x + c * scale, y + r * scale, scale, scale, 0xFF1A1A1A);
} else if (p == 2) {
ui_draw_rect(win, x + c * scale, y + r * scale, scale, scale, 0xFFFEFEFE);
}
}
for (int i = 0; logo[i] != NULL; i++) {
draw_ansi_string(win, x, y + (i * 10), logo[i]);
}
}
static void about_paint(ui_window_t win) {
int w = 185;
int w = 340;
int h = 240;
int offset_x = 15;
int offset_y = 35;
draw_boredos_logo(win, 60, offset_y, 4);
draw_ascii_logo(win, 14, offset_y);
// Version info
ui_draw_string(win, offset_x, offset_y + 105, "BoredOS 'Panda'", 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 120, "BoredOS Version 1.64", 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 135, "Kernel Version 3.0.0", 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 105, "BoredOS 'Retrowave'", 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 120, "BoredOS Version 1.65", 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 135, "Kernel Version 3.0.1", 0xFFFFFFFF);
// Copyright
ui_draw_string(win, offset_x, offset_y + 150, "(C) 2026 boreddevnl.", 0xFFFFFFFF);
@ -60,7 +105,7 @@ static void about_paint(ui_window_t win) {
}
int main(void) {
ui_window_t win_about = ui_window_create("About BoredOS", 250, 180, 185, 240);
ui_window_t win_about = ui_window_create("About BoredOS", 250, 180, 340, 240);
about_paint(win_about);

View file

@ -1,12 +0,0 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it is present in, as per the GPL license terms.
#include <stdlib.h>
#include <syscall.h>
int main(int argc, char **argv) {
(void)argc; (void)argv;
printf("BoredOS v1.64\n");
printf("BoredOS Kernel V3.0.0\n");
return 0;
}

View file

@ -28,7 +28,7 @@ int main(int argc, char **argv) {
printf("beep - Make a beep sound\n");
printf("reboot - Reboot the system\n");
printf("shutdown - Shutdown the system\n");
printf("boredver - Show BoredOS version\n");
printf("sysfetch - Show system information\n");
printf("cc <file.c> - C Compiler\n");
printf("man <cmd> - Show manual page\n");
printf("clear - Clear the screen\n");

View file

@ -59,6 +59,7 @@
#define SYSTEM_CMD_NETWORK_HAS_IP 30
#define SYSTEM_CMD_GET_SHELL_CONFIG 28
#define SYSTEM_CMD_SET_TEXT_COLOR 29
#define SYSTEM_CMD_SET_WALLPAPER_PATH 31
// Internal assembly entry into Ring 0
extern uint64_t syscall0(uint64_t sys_num);

View file

@ -3,7 +3,9 @@
// This header needs to maintain in any file it is present in, as per the GPL license terms.
#include "libc/syscall.h"
#include "libc/libui.h"
#include "nanojpeg.h"
#include <stddef.h>
#include <stdint.h>
#define COLOR_COFFEE 0xFF6B4423
#define COLOR_TEAL 0xFF008080
@ -40,12 +42,19 @@ static char net_status[64] = "";
static uint32_t pattern_lumberjack[PATTERN_SIZE * PATTERN_SIZE];
static uint32_t pattern_blue_diamond[PATTERN_SIZE * PATTERN_SIZE];
#define WALLPAPER_THUMB_W 100
#define WALLPAPER_THUMB_H 60
static uint32_t moon_thumb[WALLPAPER_THUMB_W * WALLPAPER_THUMB_H];
static uint32_t mtn_thumb[WALLPAPER_THUMB_W * WALLPAPER_THUMB_H];
static _Bool moon_thumb_valid = 0;
static _Bool mtn_thumb_valid = 0;
#define MAX_WALLPAPERS 10
#define WALLPAPER_THUMB_W 80
#define WALLPAPER_THUMB_H 50
typedef struct {
char path[128];
char name[64];
uint32_t thumb[WALLPAPER_THUMB_W * WALLPAPER_THUMB_H];
_Bool valid;
} wallpaper_entry_t;
static wallpaper_entry_t wallpapers[MAX_WALLPAPERS];
static int wallpaper_count = 0;
static _Bool desktop_snap_to_grid = 1;
static _Bool desktop_auto_align = 1;
@ -92,32 +101,67 @@ static void generate_lumberjack_pattern(void) {
}
}
static void generate_blue_diamond_pattern(void) {
uint32_t bg_color = 0xFFADD8E6;
uint32_t diamond_color = 0xFF0000CD;
static void scale_rgb_to_argb(const unsigned char *rgb, int src_w, int src_h, uint32_t *dst, int dst_w, int dst_h) {
for (int y = 0; y < dst_h; y++) {
int src_y = y * src_h / dst_h;
for (int x = 0; x < dst_w; x++) {
int src_x = x * src_w / dst_w;
int idx = (src_y * src_w + src_x) * 3;
dst[y * dst_w + x] = 0xFF000000 | (rgb[idx] << 16) | (rgb[idx + 1] << 8) | rgb[idx + 2];
}
}
}
for (int y = 0; y < PATTERN_SIZE; y++) {
for (int x = 0; x < PATTERN_SIZE; x++) {
pattern_blue_diamond[y * PATTERN_SIZE + x] = bg_color;
}
}
for (int dy = -24; dy <= 24; dy++) {
for (int dx = -24; dx <= 24; dx++) {
int abs_dx = dx < 0 ? -dx : dx;
int abs_dy = dy < 0 ? -dy : dy;
if (abs_dx + abs_dy <= 24) {
int x1 = 32 + dx;
int y1 = 32 + dy;
if (x1 >= 0 && x1 < PATTERN_SIZE && y1 >= 0 && y1 < PATTERN_SIZE) {
pattern_blue_diamond[y1 * PATTERN_SIZE + x1] = diamond_color;
}
int x2 = 96 + dx;
int y2 = 96 + dy;
if (x2 >= 0 && x2 < PATTERN_SIZE && y2 >= 0 && y2 < PATTERN_SIZE) {
pattern_blue_diamond[y2 * PATTERN_SIZE + x2] = diamond_color;
static void load_wallpapers(void) {
wallpaper_count = 0;
FAT32_FileInfo info[MAX_WALLPAPERS];
int count = sys_list("/Library/images/Wallpapers", info, MAX_WALLPAPERS);
if (count < 0) return;
for (int i = 0; i < count && wallpaper_count < MAX_WALLPAPERS; i++) {
if (info[i].is_directory) continue; // Skip directories
// check if .jpg (case-insensitive)
int len = 0; while (info[i].name[len]) len++;
if (len < 4) continue;
char c1 = info[i].name[len-1]; if (c1 >= 'A' && c1 <= 'Z') c1 += 32;
char c2 = info[i].name[len-2]; if (c2 >= 'A' && c2 <= 'Z') c2 += 32;
char c3 = info[i].name[len-3]; if (c3 >= 'A' && c3 <= 'Z') c3 += 32;
if (c1 != 'g' || c2 != 'p' || c3 != 'j') continue;
wallpaper_entry_t *wp = &wallpapers[wallpaper_count];
// Set path
char *pref = "/Library/images/Wallpapers/";
int pl = 0; while (pref[pl]) { wp->path[pl] = pref[pl]; pl++; }
int nl = 0; while (info[i].name[nl]) { wp->path[pl+nl] = info[i].name[nl]; nl++; }
wp->path[pl+nl] = 0;
// Set name (strip .jpg)
for (int j = 0; j < nl - 4 && j < 63; j++) wp->name[j] = info[i].name[j];
wp->name[(nl-4 < 63) ? nl-4 : 63] = 0;
// Load and generate thumbnail
int fd = sys_open(wp->path, "r");
if (fd >= 0) {
int size = sys_seek(fd, 0, 2); // SEEK_END
sys_seek(fd, 0, 0); // SEEK_SET
if (size > 0 && size < 1024 * 1024) {
unsigned char *buf = (unsigned char *)sys_sbrk(size);
if (buf) {
sys_read(fd, buf, size);
njInit();
if (njDecode(buf, size) == NJ_OK) {
scale_rgb_to_argb(njGetImage(), njGetWidth(), njGetHeight(), wp->thumb, WALLPAPER_THUMB_W, WALLPAPER_THUMB_H);
wp->valid = 1;
}
njDone();
sys_sbrk(-size); // Release memory
}
}
sys_close(fd);
}
wallpaper_count++;
}
}
@ -286,30 +330,20 @@ static void control_panel_paint_wallpaper(ui_window_t win) {
ui_draw_string(win, offset_x, button_y, "Wallpapers:", COLOR_DARK_TEXT);
button_y += 20;
ui_draw_rounded_rect_filled(win, button_x, button_y, WALLPAPER_THUMB_W + 8, WALLPAPER_THUMB_H + 24, 6, COLOR_DARK_PANEL);
if (moon_thumb_valid) {
for (int ty = 0; ty < WALLPAPER_THUMB_H; ty++) {
for (int tx = 0; tx < WALLPAPER_THUMB_W; tx++) {
ui_draw_rect(win, button_x + 4 + tx, button_y + 4 + ty, 1, 1, moon_thumb[ty * WALLPAPER_THUMB_W + tx]);
}
}
} else {
ui_draw_string(win, button_x + 20, button_y + 30, "Error", 0xFFFF4444);
}
ui_draw_string(win, button_x + 30, button_y + WALLPAPER_THUMB_H + 8, "Moon", COLOR_DARK_TEXT);
for (int i = 0; i < wallpaper_count; i++) {
int tx = (i % 3) * (WALLPAPER_THUMB_W + 15);
int ty = (i / 3) * (WALLPAPER_THUMB_H + 25);
int thumb2_x = button_x + WALLPAPER_THUMB_W + 20;
ui_draw_rounded_rect_filled(win, thumb2_x, button_y, WALLPAPER_THUMB_W + 8, WALLPAPER_THUMB_H + 24, 6, COLOR_DARK_PANEL);
if (mtn_thumb_valid) {
for (int ty = 0; ty < WALLPAPER_THUMB_H; ty++) {
for (int tx = 0; tx < WALLPAPER_THUMB_W; tx++) {
ui_draw_rect(win, thumb2_x + 4 + tx, button_y + 4 + ty, 1, 1, mtn_thumb[ty * WALLPAPER_THUMB_W + tx]);
ui_draw_rounded_rect_filled(win, button_x + tx, button_y + ty, WALLPAPER_THUMB_W + 8, WALLPAPER_THUMB_H + 20, 6, COLOR_DARK_PANEL);
if (wallpapers[i].valid) {
for (int py = 0; py < WALLPAPER_THUMB_H; py++) {
for (int px = 0; px < WALLPAPER_THUMB_W; px++) {
ui_draw_rect(win, button_x + tx + 4 + px, button_y + ty + 4 + py, 1, 1, wallpapers[i].thumb[py * WALLPAPER_THUMB_W + px]);
}
}
} else {
ui_draw_string(win, thumb2_x + 20, button_y + 30, "Error", 0xFFFF4444);
}
ui_draw_string(win, thumb2_x + 16, button_y + WALLPAPER_THUMB_H + 8, "Mountain", COLOR_DARK_TEXT);
ui_draw_string(win, button_x + tx + 8, button_y + ty + WALLPAPER_THUMB_H + 6, wallpapers[i].name, COLOR_DARK_TEXT);
}
}
static void control_panel_paint_network(ui_window_t win) {
@ -429,12 +463,7 @@ static void fetch_kernel_state(void) {
desktop_max_cols = sys_system(7, 4, 0, 0, 0);
mouse_speed = sys_system(8 /*GET_MOUSE_SPEED*/, 0, 0, 0, 0);
if (sys_system(9, 0, (uint64_t)moon_thumb, 0, 0) == 0) {
moon_thumb_valid = 1;
}
if (sys_system(9, 1, (uint64_t)mtn_thumb, 0, 0) == 0) {
mtn_thumb_valid = 1;
}
load_wallpapers();
}
static void control_panel_handle_click(int x, int y) {
@ -533,14 +562,14 @@ static void control_panel_handle_click(int x, int y) {
}
button_y += 80;
if (x >= button_x && x < button_x + WALLPAPER_THUMB_W + 8 && y >= button_y && y < button_y + WALLPAPER_THUMB_H + 24) {
sys_system(3, 0, 0, 0, 0);
for (int i = 0; i < wallpaper_count; i++) {
int tx = (i % 3) * (WALLPAPER_THUMB_W + 15);
int ty = (i / 3) * (WALLPAPER_THUMB_H + 25);
if (x >= button_x + tx && x < button_x + tx + WALLPAPER_THUMB_W + 8 &&
y >= button_y + ty && y < button_y + ty + WALLPAPER_THUMB_H + 20) {
sys_system(31, (uint64_t)wallpapers[i].path, 0, 0, 0);
return;
}
int thumb2_x = button_x + WALLPAPER_THUMB_W + 20;
if (x >= thumb2_x && x < thumb2_x + WALLPAPER_THUMB_W + 8 && y >= button_y && y < button_y + WALLPAPER_THUMB_H + 24) {
sys_system(3, 1, 0, 0, 0);
return;
}
} else if (current_view == VIEW_NETWORK) {
int offset_x = 8;
@ -667,7 +696,6 @@ int main(int argc, char **argv) {
if (!win) return 1;
generate_lumberjack_pattern();
generate_blue_diamond_pattern();
fetch_kernel_state();

View file

@ -0,0 +1,300 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it is present in, as per the GPL license terms.
#include <stdlib.h>
#include <syscall.h>
#include <stdbool.h>
#define MAX_ASCII_LINES 32
#define MAX_ASCII_WIDTH 80
#define MAX_INFO_LINES 10
static char* strchr(const char *s, int c) {
while (*s != (char)c) {
if (!*s++) {
return 0;
}
}
return (char *)s;
}
static char* strncpy(char *dest, const char *src, size_t n) {
size_t i;
for (i = 0; i < n && src[i] != '\0'; i++) dest[i] = src[i];
for ( ; i < n; i++) dest[i] = '\0';
return dest;
}
typedef struct {
char ascii_art_file[256];
char user_host_string[64];
char separator[64];
char os_label[32];
char kernel_label[32];
char uptime_label[32];
char shell_label[32];
char memory_label[32];
} SysfetchConfig;
static SysfetchConfig config;
static char ascii_lines[MAX_ASCII_LINES][MAX_ASCII_WIDTH];
static int ascii_line_count = 0;
static uint32_t ansi_to_boredos_color(int code) {
uint32_t default_color = sys_get_shell_config("default_text_color");
if (default_color == 0) default_color = 0xFFCCCCCC;
switch (code) {
case 0: return default_color;
case 30: return 0xFF000000; // Black
case 31: return 0xFFFF4444; // Red
case 32: return 0xFF6A9955; // Green
case 33: return 0xFFFFFF00; // Yellow
case 34: return 0xFF569CD6; // Blue
case 35: return 0xFFB589D6; // Magenta
case 36: return 0xFF4EC9B0; // Cyan
case 37: return 0xFFCCCCCC; // White
case 90: return 0xFF808080; // Bright Black (Gray)
case 91: return 0xFFFF6B6B; // Bright Red
case 92: return 0xFF78DE78; // Bright Green
case 93: return 0xFFFFFF55; // Bright Yellow
case 94: return 0xFF87CEEB; // Bright Blue
case 95: return 0xFFFF77FF; // Bright Magenta
case 96: return 0xFF66D9EF; // Bright Cyan
case 97: return 0xFFFFFFFF; // Bright White
default: return default_color;
}
}
static void printf_ansi(const char *str) {
uint32_t original_color = sys_get_shell_config("default_text_color");
if (original_color == 0) original_color = 0xFFCCCCCC;
while (*str) {
if (*str == '\033' && *(str + 1) == '[') {
str += 2; // Skip escape and [
int code = 0;
while (*str >= '0' && *str <= '9') {
code = code * 10 + (*str - '0');
str++;
}
if (*str == 'm') {
sys_set_text_color(ansi_to_boredos_color(code));
str++;
}
} else {
char c[2] = {*str, 0};
sys_write(1, c, 1);
str++;
}
}
sys_set_text_color(original_color);
}
static int strlen_ansi(const char *str) {
int len = 0;
while (*str) {
if (*str == '\033' && *(str + 1) == '[') {
str += 2;
while (*str && *str != 'm') str++;
if (*str == 'm') str++;
} else {
len++;
str++;
}
}
return len;
}
static char* trim(char *str) {
char *end;
while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r') str++;
if (*str == 0) return str;
end = str + strlen(str) - 1;
while (end > str && (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r')) end--;
*(end + 1) = 0;
return str;
}
static void set_config_defaults() {
strcpy(config.ascii_art_file, "A:/Library/art/boredos.txt");
strcpy(config.user_host_string, "root@boredos");
strcpy(config.separator, "------------");
strcpy(config.os_label, "OS");
strcpy(config.kernel_label, "Kernel");
strcpy(config.uptime_label, "Uptime");
strcpy(config.shell_label, "Shell");
strcpy(config.memory_label, "Memory");
}
static void parse_config(char* buffer) {
char *line = buffer;
while (*line) {
char *next_line = strchr(line, '\n');
if (next_line) *next_line = 0;
if (line[0] != '/' && line[0] != '\0') {
char *key = line;
char *val = strchr(line, '=');
if (val) {
*val = 0;
val++;
key = trim(key);
val = trim(val);
if (strcmp(key, "ascii_art_file") == 0) strcpy(config.ascii_art_file, val);
else if (strcmp(key, "user_host_string") == 0) strcpy(config.user_host_string, val);
else if (strcmp(key, "separator") == 0) strcpy(config.separator, val);
else if (strcmp(key, "os_label") == 0) strcpy(config.os_label, val);
else if (strcmp(key, "kernel_label") == 0) strcpy(config.kernel_label, val);
else if (strcmp(key, "uptime_label") == 0) strcpy(config.uptime_label, val);
else if (strcmp(key, "shell_label") == 0) strcpy(config.shell_label, val);
else if (strcmp(key, "memory_label") == 0) strcpy(config.memory_label, val);
}
}
if (next_line) line = next_line + 1;
else break;
}
}
static void load_config() {
set_config_defaults();
int fd = sys_open("A:/Library/conf/sysfetch.cfg", "r");
if (fd < 0) return;
char *buffer = malloc(4096);
if (!buffer) {
sys_close(fd);
return;
}
int bytes = sys_read(fd, buffer, 4095);
sys_close(fd);
if (bytes > 0) {
buffer[bytes] = 0;
parse_config(buffer);
}
free(buffer);
}
static void load_ascii_art() {
int fd = sys_open(config.ascii_art_file, "r");
if (fd < 0) {
strcpy(ascii_lines[0], "\033[35m====================== \033[97m__ ____ ____ \033[0m");
strcpy(ascii_lines[1], "\033[35m===================== \033[97m/ /_ / __ \\/ ___\\\033[0m");
strcpy(ascii_lines[2], "\033[34m==================== \033[97m/ __ \\/ / / /\\___ \\\033[0m");
strcpy(ascii_lines[3], "\033[34m=================== \033[97m/ /_/ / /_/ /____/ /\033[0m");
strcpy(ascii_lines[4], "\033[36m================== \033[97m/_.___/\\____//_____/ \033[0m");
strcpy(ascii_lines[5], "\033[36m================= \033[0m");
ascii_line_count = 6;
return;
}
char *buffer = malloc(4096);
if (!buffer) {
sys_close(fd);
return;
}
int bytes = sys_read(fd, buffer, 4095);
sys_close(fd);
if (bytes > 0) {
buffer[bytes] = 0;
char *line = buffer;
while (*line && ascii_line_count < MAX_ASCII_LINES) {
char *next_line = strchr(line, '\n');
if (next_line) *next_line = 0;
strncpy(ascii_lines[ascii_line_count], line, MAX_ASCII_WIDTH - 1);
ascii_lines[ascii_line_count][MAX_ASCII_WIDTH - 1] = 0;
ascii_line_count++;
if (next_line) line = next_line + 1;
else break;
}
}
free(buffer);
}
int main(int argc, char **argv) {
(void)argc; (void)argv;
load_config();
load_ascii_art();
char info_lines[MAX_INFO_LINES][128];
char temp_buf[32];
int info_line_count = 0;
if (config.user_host_string[0]) {
strcpy(info_lines[info_line_count++], config.user_host_string);
}
if (config.separator[0]) {
strcpy(info_lines[info_line_count++], config.separator);
}
if (config.os_label[0]) {
strcpy(info_lines[info_line_count], config.os_label);
strcat(info_lines[info_line_count++], ": BoredOS V1.65");
}
if (config.kernel_label[0]) {
strcpy(info_lines[info_line_count], config.kernel_label);
strcat(info_lines[info_line_count++], ": Boredkernel V3.0.1 x86_64");
}
if (config.uptime_label[0]) {
uint64_t ticks = sys_system(16, 0, 0, 0, 0);
int minutes = ticks / 3600; // 60Hz timer
strcpy(info_lines[info_line_count], config.uptime_label);
strcat(info_lines[info_line_count], ": ");
itoa(minutes, temp_buf);
strcat(info_lines[info_line_count], temp_buf);
strcat(info_lines[info_line_count++], " mins");
}
if (config.shell_label[0]) {
strcpy(info_lines[info_line_count], config.shell_label);
strcat(info_lines[info_line_count++], ": bsh");
}
if (config.memory_label[0]) {
uint64_t mem[2];
if (sys_system(15, (uint64_t)mem, 0, 0, 0) == 0) {
strcpy(info_lines[info_line_count], config.memory_label);
strcat(info_lines[info_line_count], ": ");
itoa((int)(mem[1] / 1024 / 1024), temp_buf);
strcat(info_lines[info_line_count], temp_buf);
strcat(info_lines[info_line_count], "MiB / ");
itoa((int)(mem[0] / 1024 / 1024), temp_buf);
strcat(info_lines[info_line_count], temp_buf);
strcat(info_lines[info_line_count++], "MiB");
}
}
int max_lines = (ascii_line_count > info_line_count) ? ascii_line_count : info_line_count;
int ascii_width = 0;
for (int i = 0; i < ascii_line_count; i++) {
int len = strlen_ansi(ascii_lines[i]);
if (len > ascii_width) ascii_width = len;
}
for (int i = 0; i < max_lines; i++) {
if (i < ascii_line_count) {
printf_ansi(ascii_lines[i]);
int padding = ascii_width - strlen_ansi(ascii_lines[i]);
for(int j=0; j<padding; j++) printf(" ");
} else {
for(int j=0; j<ascii_width; j++) printf(" ");
}
printf(" ");
if (i < info_line_count) {
printf_ansi(info_lines[i]);
}
printf("\n");
}
return 0;
}

View file

@ -108,11 +108,11 @@ static void viewer_handle_click(ui_window_t win, int x, int y) {
int cw = win_w - 8;
int btn_w = 160;
int btn_x = cx + (cw - btn_w) / 2;
int btn_y = (win_h - 20) - 30;
int btn_y = (win_h - 25) - 30; // Matches the hitboxes
if (x >= btn_x && x < btn_x + btn_w && y >= btn_y && y < btn_y + 22) {
// SYSTEM_CMD_SET_WALLPAPER is 3 based on syscall.c code
sys_system(3, (uint64_t)viewer_file_path, 0, 0, 0);
// SYSTEM_CMD_SET_WALLPAPER_PATH is 31
sys_system(31, (uint64_t)viewer_file_path, 0, 0, 0);
}
}

View file

@ -1,13 +1,8 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it is present in, as per the GPL license terms.
// wallpaper.c - Wallpaper management for BoredOS
#include "wallpaper.h"
#include "nanojpeg.h"
#include "graphics.h"
#include "fat32.h"
#include "memory_manager.h"
#include "wallpaper_data.h"
#include "wm.h"
#include "io.h"
#include <stddef.h>
@ -19,21 +14,10 @@ static uint32_t wp_pixels[MAX_WP_WIDTH * MAX_WP_HEIGHT];
static int wp_width = 0;
static int wp_height = 0;
// Pre-generated thumbnails
static uint32_t thumb_moon[WALLPAPER_THUMB_W * WALLPAPER_THUMB_H];
static uint32_t thumb_mountain[WALLPAPER_THUMB_W * WALLPAPER_THUMB_H];
static bool thumbs_valid[WALLPAPER_COUNT] = {false, false};
// Deferred wallpaper action (set from interrupt context, processed in main loop)
static volatile int pending_wallpaper_index = -1;
static volatile const char *pending_wallpaper_path = NULL;
static char pending_path_buf[256];
const char *wallpaper_names[WALLPAPER_COUNT] = {
"Moon",
"Mountain"
};
// Simple nearest-neighbor scale from decoded RGB to ARGB pixel buffer
static void scale_rgb_to_argb(const unsigned char *rgb, int src_w, int src_h,
uint32_t *dst, int dst_w, int dst_h) {
@ -102,83 +86,6 @@ static void serial_num(int n) {
serial_char('0' + (n % 10));
}
static void serial_hex(unsigned int n) {
const char hex[] = "0123456789ABCDEF";
serial_str("0x");
for (int i = 28; i >= 0; i -= 4) {
serial_char(hex[(n >> i) & 0xF]);
}
}
// Decode JPEG and generate a thumbnail (MUST be called from non-interrupt context)
static int decode_thumbnail(const unsigned char *jpg_data, unsigned int jpg_size,
uint32_t *out_pixels, int thumb_w, int thumb_h) {
serial_str("[WP] decode_thumbnail: data=");
serial_hex((unsigned int)(unsigned long)jpg_data);
serial_str(" size=");
serial_num((int)jpg_size);
serial_str(" first bytes: ");
for (int i = 0; i < 4 && i < (int)jpg_size; i++) {
serial_hex(jpg_data[i]);
serial_char(' ');
}
serial_str("\n");
njInit();
serial_str("[WP] njInit done, calling njDecode...\n");
nj_result_t result = njDecode(jpg_data, (int)jpg_size);
serial_str("[WP] njDecode returned: ");
serial_num((int)result);
serial_str("\n");
if (result != NJ_OK) {
njDone();
// Fill with error indicator color based on error code
uint32_t err_color;
switch (result) {
case NJ_NO_JPEG: err_color = 0xFF880000; break; // dark red
case NJ_UNSUPPORTED: err_color = 0xFF888800; break; // dark yellow
case NJ_OUT_OF_MEM: err_color = 0xFF008800; break; // dark green
case NJ_INTERNAL_ERR: err_color = 0xFF000088; break; // dark blue
case NJ_SYNTAX_ERROR: err_color = 0xFF880088; break; // dark magenta
default: err_color = 0xFF444444; break; // grey
}
for (int i = 0; i < thumb_w * thumb_h; i++) {
out_pixels[i] = err_color;
}
return 1; // Return 1 (valid) so the colored diagnostic is visible!
}
int img_w = njGetWidth();
int img_h = njGetHeight();
unsigned char *rgb = njGetImage();
serial_str("[WP] decoded: ");
serial_num(img_w);
serial_str("x");
serial_num(img_h);
serial_str("\n");
if (!rgb || img_w <= 0 || img_h <= 0) {
njDone();
for (int i = 0; i < thumb_w * thumb_h; i++) {
out_pixels[i] = 0xFF444444;
}
return 1; // visible
}
scale_rgb_to_argb(rgb, img_w, img_h, out_pixels, thumb_w, thumb_h);
njDone();
return 1;
}
// Request wallpaper change by index (safe to call from interrupt context)
void wallpaper_request_set(int index) {
pending_wallpaper_index = index;
}
// Request wallpaper change by file path (safe to call from interrupt context)
void wallpaper_request_set_from_file(const char *path) {
// Copy path to buffer
@ -193,34 +100,19 @@ void wallpaper_request_set_from_file(const char *path) {
// Process deferred wallpaper actions (called from main loop, NOT interrupt context)
void wallpaper_process_pending(void) {
if (pending_wallpaper_index >= 0) {
int idx = pending_wallpaper_index;
pending_wallpaper_index = -1;
const unsigned char *data = NULL;
unsigned int size = 0;
if (idx == 0) {
data = wallpaper_moon_jpg;
size = wallpaper_moon_jpg_len;
} else if (idx == 1) {
data = wallpaper_mountain_jpg;
size = wallpaper_mountain_jpg_len;
}
if (data) {
decode_and_set_wallpaper(data, size);
wm_refresh();
}
}
if (pending_wallpaper_path) {
const char *path = (const char *)pending_wallpaper_path;
pending_wallpaper_path = NULL;
serial_str("[WP] Processing wallpaper: ");
serial_str(path);
serial_str("\n");
// Read file from filesystem
FAT32_FileHandle *fh = fat32_open(path, "r");
if (fh) {
uint32_t file_size = fh->size;
if (file_size > 0 && file_size <= 2 * 1024 * 1024) {
if (file_size > 0 && file_size <= 4 * 1024 * 1024) {
unsigned char *buf = (unsigned char*)kmalloc(file_size);
if (buf) {
int total_read = 0;
@ -246,50 +138,16 @@ void wallpaper_process_pending(void) {
}
}
// Get pre-generated thumbnail data
uint32_t* wallpaper_get_thumb(int index) {
if (index == 0) return thumb_moon;
if (index == 1) return thumb_mountain;
return NULL;
}
bool wallpaper_thumb_valid(int index) {
if (index < 0 || index >= WALLPAPER_COUNT) return false;
return thumbs_valid[index];
}
uint32_t* wallpaper_get_pixels(void) { return wp_pixels; }
int wallpaper_get_width(void) { return wp_width; }
int wallpaper_get_height(void) { return wp_height; }
void wallpaper_init(void) {
// Create /Wallpapers directory
fat32_mkdir("/Wallpapers");
// Write moon.jpg to /Wallpapers/moon.jpg
if (!fat32_exists("/Wallpapers/moon.jpg")) {
FAT32_FileHandle *fh = fat32_open("/Wallpapers/moon.jpg", "w");
if (fh) {
fat32_write(fh, wallpaper_moon_jpg, wallpaper_moon_jpg_len);
fat32_close(fh);
// We expect Limine modules to have been copied to /Library/images/Wallpapers/ by main.c
// Set a default wallpaper if one exists
if (fat32_exists("/Library/images/Wallpapers/mountain.jpg")) {
wallpaper_request_set_from_file("/Library/images/Wallpapers/mountain.jpg");
} else if (fat32_exists("/Library/images/Wallpapers/moon.jpg")) {
wallpaper_request_set_from_file("/Library/images/Wallpapers/moon.jpg");
}
}
// Write mountain.jpg to /Wallpapers/mountain.jpg
if (!fat32_exists("/Wallpapers/mountain.jpg")) {
FAT32_FileHandle *fh = fat32_open("/Wallpapers/mountain.jpg", "w");
if (fh) {
fat32_write(fh, wallpaper_mountain_jpg, wallpaper_mountain_jpg_len);
fat32_close(fh);
}
}
// Pre-generate thumbnails at boot time (non-interrupt context!)
thumbs_valid[0] = decode_thumbnail(wallpaper_moon_jpg, wallpaper_moon_jpg_len,
thumb_moon, WALLPAPER_THUMB_W, WALLPAPER_THUMB_H);
thumbs_valid[1] = decode_thumbnail(wallpaper_mountain_jpg, wallpaper_mountain_jpg_len,
thumb_mountain, WALLPAPER_THUMB_W, WALLPAPER_THUMB_H);
// Set mountain.jpg as the default wallpaper
decode_and_set_wallpaper(wallpaper_mountain_jpg, wallpaper_mountain_jpg_len);
}

View file

@ -8,28 +8,15 @@
#include <stdint.h>
#include <stdbool.h>
// Initialize wallpaper subsystem (creates /Wallpapers dir, writes JPEGs, pre-generates thumbnails)
// Initialize wallpaper subsystem
void wallpaper_init(void);
// Request wallpaper change by embedded index (safe from interrupt context)
void wallpaper_request_set(int index);
// Request wallpaper change by file path (safe from interrupt context)
void wallpaper_request_set_from_file(const char *path);
// Process pending wallpaper actions (call from main loop only!)
void wallpaper_process_pending(void);
// Get pre-generated thumbnail pixel buffer (index 0=moon, 1=mountain)
#define WALLPAPER_THUMB_W 100
#define WALLPAPER_THUMB_H 60
uint32_t* wallpaper_get_thumb(int index);
bool wallpaper_thumb_valid(int index);
// Wallpaper info
#define WALLPAPER_COUNT 2
extern const char *wallpaper_names[WALLPAPER_COUNT];
// Get decoded wallpaper pixel buffer
uint32_t* wallpaper_get_pixels(void);
int wallpaper_get_width(void);

File diff suppressed because it is too large Load diff

View file

@ -1,18 +0,0 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it is present in, as per the GPL license terms.
// wallpaper_data.h - Embedded JPEG wallpaper data (declarations only)
#ifndef WALLPAPER_DATA_H
#define WALLPAPER_DATA_H
#include <stdint.h>
// moon.jpg
extern const unsigned char wallpaper_moon_jpg[];
extern const unsigned int wallpaper_moon_jpg_len;
// mountain.jpg
extern const unsigned char wallpaper_mountain_jpg[];
extern const unsigned int wallpaper_mountain_jpg_len;
#endif // WALLPAPER_DATA_H

View file

@ -643,19 +643,9 @@ void draw_image_icon(int x, int y, const char *label) {
graphics_set_render_target(icon_buf, 48, 48);
uint32_t *thumb = NULL;
// Fast path: check hardcoded wallpaper names
if (str_eq(label, "moon.jpg") != 0) thumb = wallpaper_get_thumb(0);
else if (str_eq(label, "mountain.jpg") != 0) thumb = wallpaper_get_thumb(1);
else if (str_eq(label, "moon") != 0) thumb = wallpaper_get_thumb(0);
else if (str_eq(label, "mountain") != 0) thumb = wallpaper_get_thumb(1);
if (!thumb) {
if (str_ends_with(label, "moon.jpg")) thumb = wallpaper_get_thumb(0);
else if (str_ends_with(label, "mountain.jpg")) thumb = wallpaper_get_thumb(1);
}
// Dynamic path: try thumbnail cache for any JPG file path
if (!thumb && !thumb_cache_is_failed(label)) {
if (!thumb_cache_is_failed(label)) {
thumb = thumb_cache_lookup(label);
if (!thumb) {
// Queue for background decoding
@ -666,25 +656,13 @@ void draw_image_icon(int x, int y, const char *label) {
if (thumb) {
// White border
draw_rounded_rect_filled(0, 0, 48, 48, 4, 0xFFFFFFFF);
// Draw thumbnail into icon - handle both 100x60 wallpaper thumbs and 48x48 dynamic thumbs
bool is_wallpaper_thumb = false;
if (str_ends_with(label, "moon.jpg") || str_ends_with(label, "mountain.jpg") ||
str_eq(label, "moon") != 0 || str_eq(label, "mountain") != 0) {
is_wallpaper_thumb = true;
}
// Draw thumbnail into icon - handle 48x48 dynamic thumbs
int dst_w = 44, dst_h = 44;
for (int ty = 0; ty < dst_h; ty++) {
for (int tx = 0; tx < dst_w; tx++) {
uint32_t pixel;
if (is_wallpaper_thumb) {
int sx = tx * 100 / dst_w;
int sy = ty * 60 / dst_h;
pixel = thumb[sy * 100 + sx];
} else {
int sx = tx * 48 / dst_w;
int sy = ty * 48 / dst_h;
pixel = thumb[sy * 48 + sx];
}
uint32_t pixel = thumb[sy * 48 + sx];
put_pixel(2 + tx, 2 + ty, pixel);
}
}