mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-13 01:48:42 +00:00
feature: Add ELF metadata support
This commit is contained in:
parent
2498045362
commit
9c600caf45
30 changed files with 714 additions and 16 deletions
5
Makefile
5
Makefile
|
|
@ -22,7 +22,10 @@ USERLAND_COLLOID_ICONS = $(shell { \
|
|||
find $(SRC_DIR)/userland -type f -name '*.c' ! -path '*/third_party/*' -exec grep -hoE '"[^"]+\.png"' {} + 2>/dev/null; \
|
||||
find $(SRC_DIR)/userland -type f -name '*.h' ! -path '*/third_party/*' ! -name 'stb_image.h' -exec grep -hoE '"[^"]+\.png"' {} + 2>/dev/null; \
|
||||
} | sed 's/"//g' | sed 's@.*/@@' | sort -u)
|
||||
COLLOID_ICONS = $(sort $(DOCK_COLLOID_ICONS) $(USERLAND_COLLOID_ICONS))
|
||||
USERLAND_METADATA_ICONS = $(shell { \
|
||||
find $(SRC_DIR)/userland -type f -name '*.c' -exec sed -n 's@^[[:space:]]*//[[:space:]]*BOREDOS_APP_ICONS:[[:space:]]*@@p' {} + 2>/dev/null; \
|
||||
} | tr ';' '\n' | sed 's@.*/@@' | sed '/^[[:space:]]*$$/d' | sort -u)
|
||||
COLLOID_ICONS = $(sort $(DOCK_COLLOID_ICONS) $(USERLAND_COLLOID_ICONS) $(USERLAND_METADATA_ICONS) xterm.png)
|
||||
|
||||
C_SOURCES = $(wildcard $(SRC_DIR)/core/*.c) \
|
||||
$(wildcard $(SRC_DIR)/sys/*.c) \
|
||||
|
|
|
|||
361
src/sys/app_metadata.c
Normal file
361
src/sys/app_metadata.c
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
// 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 "app_metadata.h"
|
||||
|
||||
#include "memory_manager.h"
|
||||
#include "vfs.h"
|
||||
|
||||
#define APP_METADATA_CACHE_SIZE 64
|
||||
|
||||
typedef struct {
|
||||
bool valid;
|
||||
bool has_metadata;
|
||||
char path[VFS_MAX_PATH];
|
||||
boredos_app_metadata_t metadata;
|
||||
} app_metadata_cache_entry_t;
|
||||
|
||||
static app_metadata_cache_entry_t g_app_metadata_cache[APP_METADATA_CACHE_SIZE];
|
||||
static int g_app_metadata_cache_next = 0;
|
||||
|
||||
static size_t am_strlen(const char *str) {
|
||||
size_t len = 0;
|
||||
if (!str) return 0;
|
||||
while (str[len]) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool am_str_eq(const char *a, const char *b) {
|
||||
if (!a || !b) return false;
|
||||
while (*a && *b) {
|
||||
if (*a != *b) return false;
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
return (*a == '\0' && *b == '\0');
|
||||
}
|
||||
|
||||
static bool am_mem_eq(const uint8_t *a, const uint8_t *b, size_t len) {
|
||||
if (!a || !b) return false;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (a[i] != b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void am_mem_copy(uint8_t *dest, const uint8_t *src, size_t len) {
|
||||
if (!dest || !src) return;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
dest[i] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void am_str_copy(char *dest, const char *src, size_t dest_size) {
|
||||
size_t i = 0;
|
||||
if (!dest || dest_size == 0) return;
|
||||
if (!src) {
|
||||
dest[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
while (src[i] && i + 1 < dest_size) {
|
||||
dest[i] = src[i];
|
||||
i++;
|
||||
}
|
||||
dest[i] = '\0';
|
||||
}
|
||||
|
||||
static bool am_seek(vfs_file_t *file, uint64_t offset) {
|
||||
if (!file) return false;
|
||||
if (offset > 0x7FFFFFFFUL) return false;
|
||||
return vfs_seek(file, (int)offset, 0) == 0;
|
||||
}
|
||||
|
||||
static bool am_read_exact(vfs_file_t *file, void *buf, uint32_t size) {
|
||||
uint8_t *dst = (uint8_t *)buf;
|
||||
uint32_t total = 0;
|
||||
|
||||
while (total < size) {
|
||||
int rc = vfs_read(file, dst + total, (int)(size - total));
|
||||
if (rc <= 0) return false;
|
||||
total += (uint32_t)rc;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t am_align4(uint32_t value) {
|
||||
return (value + 3U) & ~3U;
|
||||
}
|
||||
|
||||
static bool am_validate_metadata(const boredos_app_metadata_t *metadata) {
|
||||
if (!metadata) return false;
|
||||
if (metadata->magic != BOREDOS_APP_METADATA_MAGIC) return false;
|
||||
if (metadata->version != BOREDOS_APP_METADATA_VERSION) return false;
|
||||
if (metadata->image_count > BOREDOS_APP_METADATA_MAX_IMAGES) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool am_note_name_matches(const char *name, uint32_t name_size) {
|
||||
size_t expected_len = am_strlen(BOREDOS_APP_NOTE_OWNER);
|
||||
if (!name || name_size == 0) return false;
|
||||
if ((size_t)name_size < expected_len) return false;
|
||||
|
||||
for (size_t i = 0; i < expected_len; i++) {
|
||||
if (name[i] != BOREDOS_APP_NOTE_OWNER[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void am_sanitize_metadata(boredos_app_metadata_t *metadata) {
|
||||
if (!metadata) return;
|
||||
|
||||
metadata->app_name[BOREDOS_APP_METADATA_MAX_APP_NAME - 1] = '\0';
|
||||
metadata->description[BOREDOS_APP_METADATA_MAX_DESCRIPTION - 1] = '\0';
|
||||
|
||||
for (uint32_t i = 0; i < BOREDOS_APP_METADATA_MAX_IMAGES; i++) {
|
||||
metadata->images[i][BOREDOS_APP_METADATA_MAX_IMAGE_PATH - 1] = '\0';
|
||||
}
|
||||
|
||||
if (metadata->image_count > BOREDOS_APP_METADATA_MAX_IMAGES) {
|
||||
metadata->image_count = BOREDOS_APP_METADATA_MAX_IMAGES;
|
||||
}
|
||||
}
|
||||
|
||||
static bool am_parse_note_section(vfs_file_t *file,
|
||||
const Elf64_Shdr *section,
|
||||
boredos_app_metadata_t *out_metadata) {
|
||||
uint32_t offset = 0;
|
||||
|
||||
if (!file || !section || !out_metadata) return false;
|
||||
|
||||
while ((uint64_t)offset + sizeof(Elf64_Nhdr) <= section->sh_size) {
|
||||
Elf64_Nhdr nhdr;
|
||||
if (!am_seek(file, section->sh_offset + offset)) return false;
|
||||
if (!am_read_exact(file, &nhdr, sizeof(Elf64_Nhdr))) return false;
|
||||
|
||||
offset += (uint32_t)sizeof(Elf64_Nhdr);
|
||||
|
||||
if ((uint64_t)offset + nhdr.n_namesz > section->sh_size) return false;
|
||||
if (nhdr.n_namesz > 256U) return false;
|
||||
|
||||
char *name_buf = (char *)kmalloc((size_t)nhdr.n_namesz + 1U);
|
||||
if (!name_buf) return false;
|
||||
|
||||
if (!am_seek(file, section->sh_offset + offset) || !am_read_exact(file, name_buf, nhdr.n_namesz)) {
|
||||
kfree(name_buf);
|
||||
return false;
|
||||
}
|
||||
name_buf[nhdr.n_namesz] = '\0';
|
||||
|
||||
offset += nhdr.n_namesz;
|
||||
offset = am_align4(offset);
|
||||
|
||||
if ((uint64_t)offset + nhdr.n_descsz > section->sh_size) {
|
||||
kfree(name_buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_target_note = (nhdr.n_type == BOREDOS_APP_NOTE_TYPE) && am_note_name_matches(name_buf, nhdr.n_namesz);
|
||||
kfree(name_buf);
|
||||
|
||||
if (is_target_note) {
|
||||
if (nhdr.n_descsz < sizeof(boredos_app_metadata_t)) return false;
|
||||
|
||||
boredos_app_metadata_t metadata;
|
||||
if (!am_seek(file, section->sh_offset + offset) ||
|
||||
!am_read_exact(file, &metadata, (uint32_t)sizeof(boredos_app_metadata_t))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!am_validate_metadata(&metadata)) return false;
|
||||
|
||||
am_sanitize_metadata(&metadata);
|
||||
*out_metadata = metadata;
|
||||
return true;
|
||||
}
|
||||
|
||||
offset += nhdr.n_descsz;
|
||||
offset = am_align4(offset);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool am_scan_raw_notes(vfs_file_t *file, uint32_t file_size, boredos_app_metadata_t *out_metadata) {
|
||||
uint8_t *buf = NULL;
|
||||
size_t owner_len = am_strlen(BOREDOS_APP_NOTE_OWNER);
|
||||
|
||||
if (!file || !out_metadata || file_size < sizeof(Elf64_Nhdr) + owner_len + sizeof(boredos_app_metadata_t)) {
|
||||
return false;
|
||||
}
|
||||
if (file_size > 16U * 1024U * 1024U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
buf = (uint8_t *)kmalloc(file_size);
|
||||
if (!buf) return false;
|
||||
|
||||
if (!am_seek(file, 0) || !am_read_exact(file, buf, file_size)) {
|
||||
kfree(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t off = 0; off + sizeof(Elf64_Nhdr) <= file_size; off++) {
|
||||
Elf64_Nhdr nhdr;
|
||||
uint32_t name_off;
|
||||
uint32_t desc_off;
|
||||
boredos_app_metadata_t metadata;
|
||||
|
||||
am_mem_copy((uint8_t *)&nhdr, buf + off, sizeof(Elf64_Nhdr));
|
||||
if (nhdr.n_type != BOREDOS_APP_NOTE_TYPE) continue;
|
||||
if (nhdr.n_namesz < owner_len) continue;
|
||||
if (nhdr.n_descsz < sizeof(boredos_app_metadata_t)) continue;
|
||||
|
||||
name_off = off + (uint32_t)sizeof(Elf64_Nhdr);
|
||||
if ((uint64_t)name_off + nhdr.n_namesz > file_size) continue;
|
||||
|
||||
if (!am_mem_eq(buf + name_off, (const uint8_t *)BOREDOS_APP_NOTE_OWNER, owner_len)) continue;
|
||||
|
||||
desc_off = name_off + am_align4(nhdr.n_namesz);
|
||||
if ((uint64_t)desc_off + sizeof(boredos_app_metadata_t) > file_size) continue;
|
||||
|
||||
am_mem_copy((uint8_t *)&metadata, buf + desc_off, sizeof(boredos_app_metadata_t));
|
||||
if (!am_validate_metadata(&metadata)) continue;
|
||||
|
||||
am_sanitize_metadata(&metadata);
|
||||
*out_metadata = metadata;
|
||||
kfree(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool app_metadata_read_uncached(const char *path, boredos_app_metadata_t *out_metadata) {
|
||||
bool found = false;
|
||||
vfs_file_t *file = NULL;
|
||||
char *shstrtab = NULL;
|
||||
uint32_t file_size = 0;
|
||||
|
||||
if (!path || !out_metadata) return false;
|
||||
|
||||
file = vfs_open(path, "r");
|
||||
if (!file || !file->valid) goto cleanup;
|
||||
|
||||
file_size = vfs_file_size(file);
|
||||
if (file_size > 0) {
|
||||
found = am_scan_raw_notes(file, file_size, out_metadata);
|
||||
if (found) goto cleanup;
|
||||
}
|
||||
|
||||
Elf64_Ehdr ehdr;
|
||||
if (!am_read_exact(file, &ehdr, sizeof(Elf64_Ehdr))) goto cleanup;
|
||||
|
||||
if (ehdr.e_ident[0] != ELFMAG0 || ehdr.e_ident[1] != ELFMAG1 ||
|
||||
ehdr.e_ident[2] != ELFMAG2 || ehdr.e_ident[3] != ELFMAG3) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ehdr.e_ident[4] != ELFCLASS64 || ehdr.e_ident[5] != ELFDATA2LSB) goto cleanup;
|
||||
if (ehdr.e_shoff == 0 || ehdr.e_shnum == 0 || ehdr.e_shentsize < sizeof(Elf64_Shdr)) goto cleanup;
|
||||
if (ehdr.e_shstrndx == 0 || ehdr.e_shstrndx >= ehdr.e_shnum) goto cleanup;
|
||||
|
||||
Elf64_Shdr shstr_hdr;
|
||||
uint64_t shstr_off = ehdr.e_shoff + ((uint64_t)ehdr.e_shstrndx * ehdr.e_shentsize);
|
||||
if (!am_seek(file, shstr_off) || !am_read_exact(file, &shstr_hdr, sizeof(Elf64_Shdr))) goto cleanup;
|
||||
if (shstr_hdr.sh_size == 0 || shstr_hdr.sh_size > 65536U) goto cleanup;
|
||||
|
||||
shstrtab = (char *)kmalloc((size_t)shstr_hdr.sh_size + 1U);
|
||||
if (!shstrtab) goto cleanup;
|
||||
if (!am_seek(file, shstr_hdr.sh_offset) || !am_read_exact(file, shstrtab, (uint32_t)shstr_hdr.sh_size)) goto cleanup;
|
||||
shstrtab[shstr_hdr.sh_size] = '\0';
|
||||
|
||||
for (uint16_t i = 0; i < ehdr.e_shnum; i++) {
|
||||
Elf64_Shdr shdr;
|
||||
uint64_t shdr_off = ehdr.e_shoff + ((uint64_t)i * ehdr.e_shentsize);
|
||||
if (!am_seek(file, shdr_off) || !am_read_exact(file, &shdr, sizeof(Elf64_Shdr))) goto cleanup;
|
||||
if (shdr.sh_type != SHT_NOTE) continue;
|
||||
if (shdr.sh_name >= shstr_hdr.sh_size) continue;
|
||||
|
||||
const char *section_name = shstrtab + shdr.sh_name;
|
||||
if (!am_str_eq(section_name, BOREDOS_APP_NOTE_SECTION)) continue;
|
||||
|
||||
if (am_parse_note_section(file, &shdr, out_metadata)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && file_size > 0) {
|
||||
found = am_scan_raw_notes(file, file_size, out_metadata);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (shstrtab) kfree(shstrtab);
|
||||
if (file) vfs_close(file);
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool app_metadata_cache_lookup(const char *path, boredos_app_metadata_t *out_metadata, bool *out_found) {
|
||||
if (!path || !out_found) return false;
|
||||
|
||||
for (int i = 0; i < APP_METADATA_CACHE_SIZE; i++) {
|
||||
app_metadata_cache_entry_t *entry = &g_app_metadata_cache[i];
|
||||
if (!entry->valid) continue;
|
||||
if (!am_str_eq(entry->path, path)) continue;
|
||||
|
||||
*out_found = entry->has_metadata;
|
||||
if (entry->has_metadata && out_metadata) {
|
||||
*out_metadata = entry->metadata;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void app_metadata_cache_store(const char *path, const boredos_app_metadata_t *metadata, bool has_metadata) {
|
||||
app_metadata_cache_entry_t *entry;
|
||||
|
||||
if (!path) return;
|
||||
|
||||
entry = &g_app_metadata_cache[g_app_metadata_cache_next];
|
||||
g_app_metadata_cache_next = (g_app_metadata_cache_next + 1) % APP_METADATA_CACHE_SIZE;
|
||||
|
||||
entry->valid = true;
|
||||
entry->has_metadata = has_metadata;
|
||||
am_str_copy(entry->path, path, sizeof(entry->path));
|
||||
if (has_metadata && metadata) {
|
||||
entry->metadata = *metadata;
|
||||
}
|
||||
}
|
||||
|
||||
bool app_metadata_read(const char *path, boredos_app_metadata_t *out_metadata) {
|
||||
bool found = false;
|
||||
|
||||
if (!path || !out_metadata) return false;
|
||||
|
||||
if (app_metadata_cache_lookup(path, out_metadata, &found)) {
|
||||
return found;
|
||||
}
|
||||
|
||||
found = app_metadata_read_uncached(path, out_metadata);
|
||||
app_metadata_cache_store(path, out_metadata, found);
|
||||
return found;
|
||||
}
|
||||
|
||||
bool app_metadata_get_primary_image(const char *path, char *out_path, size_t out_path_size) {
|
||||
boredos_app_metadata_t metadata;
|
||||
|
||||
if (!path || !out_path || out_path_size == 0) return false;
|
||||
out_path[0] = '\0';
|
||||
|
||||
if (!app_metadata_read(path, &metadata)) return false;
|
||||
if (metadata.image_count == 0) return false;
|
||||
if (metadata.images[0][0] == '\0') return false;
|
||||
|
||||
am_str_copy(out_path, metadata.images[0], out_path_size);
|
||||
return out_path[0] != '\0';
|
||||
}
|
||||
14
src/sys/app_metadata.h
Normal file
14
src/sys/app_metadata.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// 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.
|
||||
#ifndef APP_METADATA_H
|
||||
#define APP_METADATA_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "elf.h"
|
||||
|
||||
bool app_metadata_read(const char *path, boredos_app_metadata_t *out_metadata);
|
||||
bool app_metadata_get_primary_image(const char *path, char *out_path, size_t out_path_size);
|
||||
|
||||
#endif
|
||||
|
|
@ -44,6 +44,25 @@ typedef struct {
|
|||
Elf64_Xword p_align; /* Segment alignment */
|
||||
} Elf64_Phdr;
|
||||
|
||||
typedef struct {
|
||||
Elf64_Word sh_name; /* Section name (string tbl index) */
|
||||
Elf64_Word sh_type; /* Section type */
|
||||
Elf64_Xword sh_flags; /* Section flags */
|
||||
Elf64_Addr sh_addr; /* Section virtual addr at execution */
|
||||
Elf64_Off sh_offset; /* Section file offset */
|
||||
Elf64_Xword sh_size; /* Section size in bytes */
|
||||
Elf64_Word sh_link; /* Link to another section */
|
||||
Elf64_Word sh_info; /* Additional section information */
|
||||
Elf64_Xword sh_addralign; /* Section alignment */
|
||||
Elf64_Xword sh_entsize; /* Entry size if section holds table */
|
||||
} Elf64_Shdr;
|
||||
|
||||
typedef struct {
|
||||
Elf64_Word n_namesz; /* Name size in bytes */
|
||||
Elf64_Word n_descsz; /* Descriptor size in bytes */
|
||||
Elf64_Word n_type; /* Note type */
|
||||
} Elf64_Nhdr;
|
||||
|
||||
/* e_ident constants */
|
||||
#define ELFMAG0 0x7f
|
||||
#define ELFMAG1 'E'
|
||||
|
|
@ -63,11 +82,37 @@ typedef struct {
|
|||
/* p_type constants */
|
||||
#define PT_LOAD 1
|
||||
|
||||
/* sh_type constants */
|
||||
#define SHT_NOTE 7
|
||||
|
||||
/* p_flags constants */
|
||||
#define PF_X 1
|
||||
#define PF_W 2
|
||||
#define PF_R 4
|
||||
|
||||
/* BoredOS app metadata note constants */
|
||||
#define BOREDOS_APP_NOTE_OWNER "BOREDOS"
|
||||
#define BOREDOS_APP_NOTE_NAME BOREDOS_APP_NOTE_OWNER
|
||||
#define BOREDOS_APP_NOTE_SECTION ".note.boredos.app"
|
||||
#define BOREDOS_APP_NOTE_TYPE 0x41505031U
|
||||
#define BOREDOS_APP_METADATA_MAGIC 0x414d4431U
|
||||
#define BOREDOS_APP_METADATA_VERSION 1U
|
||||
|
||||
#define BOREDOS_APP_METADATA_MAX_APP_NAME 64
|
||||
#define BOREDOS_APP_METADATA_MAX_DESCRIPTION 192
|
||||
#define BOREDOS_APP_METADATA_MAX_IMAGES 4
|
||||
#define BOREDOS_APP_METADATA_MAX_IMAGE_PATH 160
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t magic;
|
||||
uint16_t version;
|
||||
uint16_t image_count;
|
||||
uint16_t reserved;
|
||||
char app_name[BOREDOS_APP_METADATA_MAX_APP_NAME];
|
||||
char description[BOREDOS_APP_METADATA_MAX_DESCRIPTION];
|
||||
char images[BOREDOS_APP_METADATA_MAX_IMAGES][BOREDOS_APP_METADATA_MAX_IMAGE_PATH];
|
||||
} boredos_app_metadata_t;
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,10 +5,19 @@ CC = x86_64-elf-gcc
|
|||
AS = nasm
|
||||
LD = x86_64-elf-ld
|
||||
|
||||
CFLAGS = -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-red-zone -I. -Ilibc
|
||||
CFLAGS = -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-red-zone -I. -Ilibc -I../sys
|
||||
LDFLAGS = -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start
|
||||
|
||||
BIN_DIR = bin
|
||||
APP_METADATA_TOOL = ../../tools/gen_userland_note.sh
|
||||
APP_ICON_SOURCE_DIR = ../images/icons/colloid
|
||||
APP_METADATA_SOURCE_DOOM = games/doom/doomgeneric_boredos.c
|
||||
APP_METADATA_SOURCE_LUA = cli/third_party/lua/boredos_onelua.c
|
||||
APP_SOURCE_DIRS = . cli gui sys games net cli/third_party
|
||||
|
||||
define app_source_for
|
||||
$(if $(filter doom,$1),$(APP_METADATA_SOURCE_DOOM),$(if $(filter lua,$1),$(APP_METADATA_SOURCE_LUA),$(firstword $(foreach d,$(APP_SOURCE_DIRS),$(wildcard $(d)/$1.c)))))
|
||||
endef
|
||||
|
||||
LIBC_SOURCES = $(wildcard libc/*.c)
|
||||
LIBC_OBJS = $(patsubst libc/%.c, $(BIN_DIR)/%.o, $(LIBC_SOURCES)) $(BIN_DIR)/crt0.o $(BIN_DIR)/libwidget.o
|
||||
|
|
@ -19,6 +28,9 @@ vpath %.c cli gui sys games libc net cli/third_party
|
|||
APP_SOURCES_FULL = $(wildcard cli/*.c gui/*.c sys/*.c games/*.c *.c net/*.c cli/third_party/*.c)
|
||||
APP_SOURCES = $(filter-out stb_image.c, $(APP_SOURCES_FULL))
|
||||
APP_ELFS = $(patsubst %.c, $(BIN_DIR)/%.elf, $(notdir $(APP_SOURCES)))
|
||||
APP_NAMES = $(sort $(basename $(notdir $(APP_SOURCES))) doom lua)
|
||||
APP_NOTE_CSOURCES = $(patsubst %, $(BIN_DIR)/%.note.c, $(APP_NAMES))
|
||||
APP_NOTE_OBJS = $(patsubst %, $(BIN_DIR)/%.note.o, $(APP_NAMES))
|
||||
|
||||
DOOM_SOURCES = $(wildcard games/doom/*.c)
|
||||
DOOM_OBJS = $(patsubst games/doom/%.c, $(BIN_DIR)/%.o, $(DOOM_SOURCES))
|
||||
|
|
@ -43,35 +55,46 @@ $(BIN_DIR)/libwidget.o: ../wm/libwidget.c | $(BIN_DIR)
|
|||
$(BIN_DIR)/stb_image.o: stb_image.c | $(BIN_DIR)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BIN_DIR)/%.note.c: $(APP_METADATA_TOOL) | $(BIN_DIR)
|
||||
src="$(call app_source_for,$*)"; \
|
||||
if [ -z "$$src" ] || [ ! -f "$$src" ]; then \
|
||||
echo "error: metadata source not found for app '$*'" >&2; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
sh $(APP_METADATA_TOOL) "$*" "$$src" "$(APP_ICON_SOURCE_DIR)" "$@"
|
||||
|
||||
$(BIN_DIR)/%.note.o: $(BIN_DIR)/%.note.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BIN_DIR)/%.o: %.c | $(BIN_DIR)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BIN_DIR)/viewer.elf: $(LIBC_OBJS) $(BIN_DIR)/viewer.o $(BIN_DIR)/stb_image.o
|
||||
$(BIN_DIR)/viewer.elf: $(LIBC_OBJS) $(BIN_DIR)/viewer.o $(BIN_DIR)/stb_image.o $(BIN_DIR)/viewer.note.o
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
||||
|
||||
$(BIN_DIR)/settings.elf: $(LIBC_OBJS) $(BIN_DIR)/settings.o $(BIN_DIR)/stb_image.o
|
||||
$(BIN_DIR)/settings.elf: $(LIBC_OBJS) $(BIN_DIR)/settings.o $(BIN_DIR)/stb_image.o $(BIN_DIR)/settings.note.o
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
||||
|
||||
$(BIN_DIR)/browser.elf: $(LIBC_OBJS) $(BIN_DIR)/browser.o $(BIN_DIR)/stb_image.o
|
||||
$(BIN_DIR)/browser.elf: $(LIBC_OBJS) $(BIN_DIR)/browser.o $(BIN_DIR)/stb_image.o $(BIN_DIR)/browser.note.o
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
||||
|
||||
$(BIN_DIR)/screenshot.elf: $(LIBC_OBJS) $(BIN_DIR)/screenshot.o $(BIN_DIR)/stb_image.o
|
||||
$(BIN_DIR)/screenshot.elf: $(LIBC_OBJS) $(BIN_DIR)/screenshot.o $(BIN_DIR)/stb_image.o $(BIN_DIR)/screenshot.note.o
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
||||
|
||||
$(BIN_DIR)/%.o: games/doom/%.c | $(BIN_DIR)
|
||||
$(CC) $(CFLAGS) -Wno-error -DBOREDOS -Igames/doom -c $< -o $@
|
||||
|
||||
$(BIN_DIR)/doom.elf: $(LIBC_OBJS) $(DOOM_OBJS) $(BIN_DIR)/stb_image.o
|
||||
$(BIN_DIR)/doom.elf: $(LIBC_OBJS) $(DOOM_OBJS) $(BIN_DIR)/stb_image.o $(BIN_DIR)/doom.note.o
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
||||
|
||||
$(BIN_DIR)/%.elf: $(LIBC_OBJS) $(BIN_DIR)/%.o
|
||||
$(BIN_DIR)/%.elf: $(LIBC_OBJS) $(BIN_DIR)/%.o $(BIN_DIR)/%.note.o
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
||||
|
||||
# Lua 5.5.0 - compiled as a single translation unit
|
||||
$(BIN_DIR)/lua_onelua.o: $(LUA_DIR)/boredos_onelua.c | $(BIN_DIR)
|
||||
$(CC) $(LUA_CFLAGS) -c $< -o $@
|
||||
|
||||
$(BIN_DIR)/lua.elf: $(LIBC_OBJS) $(BIN_DIR)/lua_onelua.o
|
||||
$(BIN_DIR)/lua.elf: $(LIBC_OBJS) $(BIN_DIR)/lua_onelua.o $(BIN_DIR)/lua.note.o
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
||||
|
||||
clean:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// 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.
|
||||
// BOREDOS_APP_DESC: Show command and system help.
|
||||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// 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.
|
||||
// BOREDOS_APP_DESC: Manual pages CLI utility
|
||||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
** Based on the official onelua.c, adapted for BoredOS freestanding environment.
|
||||
*/
|
||||
|
||||
// BOREDOS_APP_DESC: Lua REPL and scripting runtime.
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// BOREDOS_APP_DESC: 2048 number puzzle game.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/applications-games.png
|
||||
#include "libc/syscall.h"
|
||||
#include "libc/libui.h"
|
||||
#include "libc/stdlib.h"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// BOREDOS_APP_DESC: DOOM game runtime.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/doom-2016.png;/Library/images/icons/colloid/applications-games.png
|
||||
#include "doomgeneric.h"
|
||||
#include "doomkeys.h"
|
||||
#include <libui.h>
|
||||
|
|
|
|||
|
|
@ -1,6 +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.
|
||||
// BOREDOS_APP_DESC: Minesweeper puzzle game.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/gnome-mines.png;/Library/images/icons/colloid/applications-games.png
|
||||
#include "libc/syscall.h"
|
||||
#include "libc/libui.h"
|
||||
#include <stdbool.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// BOREDOS_APP_DESC: Classic snake arcade game.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/cartridges.png
|
||||
#include "libc/syscall.h"
|
||||
#include "libc/libui.h"
|
||||
#include "libc/stdlib.h"
|
||||
|
|
|
|||
|
|
@ -1,6 +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.
|
||||
// BOREDOS_APP_DESC: Shows BoredOS information.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/indicator-cpufreq.png
|
||||
#include "syscall.h"
|
||||
#include "libc/libui.h"
|
||||
#include "libc/stdlib.h"
|
||||
|
|
|
|||
|
|
@ -1,6 +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.
|
||||
// BOREDOS_APP_DESC: Document and PDF viewer/editor.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/libreoffice-writer.png;/Library/images/icons/colloid/text-editor.png
|
||||
#include "libc/syscall.h"
|
||||
#include "libc/libui.h"
|
||||
#include "libc/stdlib.h"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
// Copyright (c) 2023-2026 Chris (boreddevnl)
|
||||
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||
// BOREDOS_APP_DESC: Web browser for internet pages.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/web-browser.png
|
||||
#include "libc/syscall.h"
|
||||
#include "libc/libui.h"
|
||||
#include "stb_image.h"
|
||||
|
|
@ -2134,4 +2136,4 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +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.
|
||||
// BOREDOS_APP_DESC: Graphical calculator utility.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/calc.png
|
||||
#include "syscall.h"
|
||||
#include "libui.h"
|
||||
#include "../../wm/libwidget.h"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
// 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.
|
||||
|
||||
// BOREDOS_APP_DESC: 3/2D Graphing and plotting utility.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/se.sjoerd.Graphs.png;/Library/images/icons/colloid/app-icon-preview.png
|
||||
#include "syscall.h"
|
||||
#include "libui.h"
|
||||
#include "../../wm/libwidget.h"
|
||||
|
|
@ -1765,4 +1767,4 @@ int main(void) {
|
|||
free(graph_fb);
|
||||
sys_exit(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +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.
|
||||
// BOREDOS_APP_DESC: Markdown document viewer.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/text-editor.png
|
||||
#include "libc/syscall.h"
|
||||
#include "libc/libui.h"
|
||||
#include "libc/stdlib.h"
|
||||
|
|
|
|||
|
|
@ -1,6 +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.
|
||||
// BOREDOS_APP_DESC: Jotting down notes and thoughts.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/text-editor.png
|
||||
#include "libc/syscall.h"
|
||||
#include "libc/libui.h"
|
||||
#include "libc/stdlib.h"
|
||||
|
|
|
|||
|
|
@ -1,6 +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.
|
||||
// BOREDOS_APP_DESC: Simple drawing and paint app.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/gnome-paint.png
|
||||
#include "libc/syscall.h"
|
||||
#include "libc/libui.h"
|
||||
#include "libc/stdlib.h"
|
||||
|
|
@ -247,4 +249,4 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// BOREDOS_APP_DESC: Screen capture utility.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/accessories-screenshot.png
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "stdlib.h"
|
||||
|
|
|
|||
|
|
@ -1,6 +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.
|
||||
// BOREDOS_APP_DESC: System configuration and preferences.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/preferences-system.png;/Library/images/icons/colloid/preferences-system-services.png
|
||||
#include "libc/syscall.h"
|
||||
#include "libc/libui.h"
|
||||
#include "libc/stdlib.h"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
// Copyright (c) 2023-2026 Chris (boreddevnl)
|
||||
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||
// BOREDOS_APP_DESC: Task and process manager.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/utilities-system-monitor.png
|
||||
#include "syscall.h"
|
||||
#include "libui.h"
|
||||
#include "stdlib.h"
|
||||
|
|
|
|||
|
|
@ -1,6 +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.
|
||||
// BOREDOS_APP_DESC: BoredOS Terminal shell.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/xterm.png;/Library/images/icons/colloid/utilities-terminal_su.png
|
||||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
#include "libc/libui.h"
|
||||
|
|
|
|||
|
|
@ -1,6 +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.
|
||||
// BOREDOS_APP_DESC: Image viewer utility.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/preferences-desktop-wallpaper.png;/Library/images/icons/colloid/org.gnome.Loupe.png
|
||||
#include "stb_image.h"
|
||||
#include "libc/syscall.h"
|
||||
#include "libc/libui.h"
|
||||
|
|
|
|||
|
|
@ -1,6 +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.
|
||||
// BOREDOS_APP_DESC: Clock and time utility.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/preferences-system-time.png
|
||||
#include "syscall.h"
|
||||
#include "libui.h"
|
||||
#include "stdlib.h"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "wm.h"
|
||||
#include "memory_manager.h"
|
||||
#include "process.h"
|
||||
#include "app_metadata.h"
|
||||
#define EXPLORER_ITEM_HEIGHT 80
|
||||
#define EXPLORER_ITEM_WIDTH 120
|
||||
#define EXPLORER_COLS 4
|
||||
|
|
@ -901,8 +902,6 @@ static void explorer_draw_colloid_slot_icon(int x, int y, int slot_index) {
|
|||
}
|
||||
|
||||
static void explorer_draw_file_icon(int x, int y, bool is_dir, const char *filename, const char *current_path) {
|
||||
(void)current_path;
|
||||
|
||||
if (is_dir) {
|
||||
explorer_draw_colloid_slot_icon(x + 5, y + 5, EXPLORER_DOCK_SLOT_FILES);
|
||||
} else if (explorer_str_ends_with(filename, ".shortcut")) {
|
||||
|
|
@ -948,7 +947,17 @@ static void explorer_draw_file_icon(int x, int y, bool is_dir, const char *filen
|
|||
} else if (explorer_str_ends_with(filename, ".pdf")) {
|
||||
explorer_draw_colloid_slot_icon(x + 5, y + 5, EXPLORER_DOCK_SLOT_WORD);
|
||||
} else if (explorer_str_ends_with(filename, ".elf")) {
|
||||
explorer_draw_colloid_slot_icon(x + 5, y + 5, EXPLORER_DOCK_SLOT_TERMINAL);
|
||||
char app_path[FAT32_MAX_PATH];
|
||||
char icon_path[BOREDOS_APP_METADATA_MAX_IMAGE_PATH];
|
||||
|
||||
explorer_strcpy(app_path, current_path);
|
||||
if (app_path[explorer_strlen(app_path) - 1] != '/') explorer_strcat(app_path, "/");
|
||||
explorer_strcat(app_path, filename);
|
||||
|
||||
if (!(app_metadata_get_primary_image(app_path, icon_path, sizeof(icon_path)) &&
|
||||
draw_icon_path(x + 5, y + 5, icon_path))) {
|
||||
explorer_draw_colloid_slot_icon(x + 5, y + 5, EXPLORER_DOCK_SLOT_TERMINAL);
|
||||
}
|
||||
} else {
|
||||
explorer_draw_colloid_slot_icon(x + 5, y + 5, EXPLORER_DOCK_SLOT_NOTEPAD);
|
||||
}
|
||||
|
|
|
|||
58
src/wm/wm.c
58
src/wm/wm.c
|
|
@ -18,6 +18,7 @@
|
|||
#include "userland/stb_image.h"
|
||||
#include "memory_manager.h"
|
||||
#include "disk.h"
|
||||
#include "app_metadata.h"
|
||||
#include "../sys/work_queue.h"
|
||||
#include "../sys/smp.h"
|
||||
#include "../core/kconsole.h"
|
||||
|
|
@ -1103,6 +1104,39 @@ void draw_image_icon(int x, int y, const char *label) {
|
|||
// Removing the explicit `draw_icon_label` call here to prevent double-text since `wm.c` or Explorer manually draws it as well inside their draw block
|
||||
}
|
||||
|
||||
bool draw_icon_path(int x, int y, const char *path) {
|
||||
uint32_t *icon = NULL;
|
||||
|
||||
if (!path || !path[0]) return false;
|
||||
|
||||
icon = thumb_cache_lookup(path);
|
||||
if (!icon && !thumb_cache_is_failed(path)) {
|
||||
icon = thumb_cache_decode(path);
|
||||
}
|
||||
if (!icon) return false;
|
||||
|
||||
int dx = x + 24;
|
||||
int dy = y + 12;
|
||||
for (int ty = 0; ty < 32; ty++) {
|
||||
for (int tx = 0; tx < 32; tx++) {
|
||||
int src_x = tx * 48 / 32;
|
||||
int src_y = ty * 48 / 32;
|
||||
uint32_t src = icon[src_y * 48 + src_x];
|
||||
uint32_t a = (src >> 24) & 0xFF;
|
||||
if (a == 0) continue;
|
||||
|
||||
if (a == 255) {
|
||||
put_pixel(dx + tx, dy + ty, 0xFF000000 | (src & 0x00FFFFFF));
|
||||
} else {
|
||||
uint32_t dst = graphics_get_pixel(dx + tx, dy + ty);
|
||||
put_pixel(dx + tx, dy + ty, blend_src_over_dst(dst, src));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void draw_notepad_icon(int x, int y, const char *label) {
|
||||
draw_scaled_icon(x, y, draw_dock_notepad);
|
||||
draw_icon_label(x, y, label);
|
||||
|
|
@ -1839,7 +1873,29 @@ static void wm_paint_region(int y_start, int y_end, DirtyRect dirty, int pass) {
|
|||
else if (str_starts_with(icon->name, "Grapher")) draw_grapher_icon(icon->x, icon->y, label);
|
||||
else draw_icon(icon->x, icon->y, label);
|
||||
} else {
|
||||
if (str_ends_with(icon->name, ".elf")) draw_elf_icon(icon->x, icon->y, icon->name);
|
||||
if (str_ends_with(icon->name, ".elf")) {
|
||||
char full_path[128] = "/root/Desktop/";
|
||||
char icon_path[BOREDOS_APP_METADATA_MAX_IMAGE_PATH];
|
||||
bool drew_icon = false;
|
||||
int p = 14;
|
||||
int n = 0;
|
||||
|
||||
while (icon->name[n] && p < 127) full_path[p++] = icon->name[n++];
|
||||
full_path[p] = 0;
|
||||
|
||||
if (app_metadata_get_primary_image(full_path, icon_path, sizeof(icon_path))) {
|
||||
drew_icon = draw_icon_path(icon->x, icon->y, icon_path);
|
||||
}
|
||||
if (!drew_icon) {
|
||||
drew_icon = draw_icon_path(icon->x, icon->y, "/Library/images/icons/colloid/xterm.png");
|
||||
}
|
||||
|
||||
if (drew_icon) {
|
||||
draw_icon_label(icon->x, icon->y, icon->name);
|
||||
} else {
|
||||
draw_elf_icon(icon->x, icon->y, icon->name);
|
||||
}
|
||||
}
|
||||
else if (str_ends_with(icon->name, ".pnt")) draw_paint_icon(icon->x, icon->y, icon->name);
|
||||
else if (is_image_file(icon->name)) {
|
||||
char full_path[128] = "/root/Desktop/"; int p=14; int n=0; while(icon->name[n] && p < 127) full_path[p++] = icon->name[n++]; full_path[p]=0;
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ void draw_document_icon(int x, int y, const char *label);
|
|||
void draw_pdf_icon(int x, int y, const char *label);
|
||||
void draw_elf_icon(int x, int y, const char *label);
|
||||
void draw_image_icon(int x, int y, const char *label);
|
||||
bool draw_icon_path(int x, int y, const char *path);
|
||||
void draw_notepad_icon(int x, int y, const char *label);
|
||||
void draw_calculator_icon(int x, int y, const char *label);
|
||||
void draw_terminal_icon(int x, int y, const char *label);
|
||||
|
|
|
|||
147
tools/gen_userland_note.sh
Normal file
147
tools/gen_userland_note.sh
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
if [ "$#" -ne 4 ]; then
|
||||
echo "usage: gen_userland_note.sh <app-name> <source-file> <icon-source-dir> <output-c>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
APP_NAME="$1"
|
||||
SOURCE_PATH="$2"
|
||||
ICON_SOURCE_DIR="$3"
|
||||
OUT_PATH="$4"
|
||||
|
||||
MAX_APP_NAME=63
|
||||
MAX_DESC=191
|
||||
MAX_IMAGE_PATH=159
|
||||
MAX_IMAGES=4
|
||||
|
||||
DEFAULT_ICON_PATH="/Library/images/icons/colloid/xterm.png"
|
||||
DEFAULT_DESC="BoredOS userspace application."
|
||||
|
||||
escape_c_string() {
|
||||
printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
|
||||
}
|
||||
|
||||
trim_spaces() {
|
||||
printf '%s' "$1" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//'
|
||||
}
|
||||
|
||||
truncate_bytes() {
|
||||
value="$1"
|
||||
max_len="$2"
|
||||
printf '%s' "$value" | cut -c1-"$max_len"
|
||||
}
|
||||
|
||||
if [ ! -f "$SOURCE_PATH" ]; then
|
||||
echo "error: source file '$SOURCE_PATH' not found for app '$APP_NAME'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
app_desc="$DEFAULT_DESC"
|
||||
image_spec="$DEFAULT_ICON_PATH"
|
||||
|
||||
source_desc=$(sed -n 's@^[[:space:]]*//[[:space:]]*BOREDOS_APP_DESC:[[:space:]]*@@p' "$SOURCE_PATH" | head -n 1)
|
||||
source_icons=$(sed -n 's@^[[:space:]]*//[[:space:]]*BOREDOS_APP_ICONS:[[:space:]]*@@p' "$SOURCE_PATH" | head -n 1)
|
||||
|
||||
if [ -n "$source_desc" ]; then
|
||||
app_desc="$source_desc"
|
||||
fi
|
||||
if [ -n "$source_icons" ]; then
|
||||
image_spec="$source_icons"
|
||||
fi
|
||||
|
||||
app_desc=$(trim_spaces "$app_desc")
|
||||
if [ -z "$app_desc" ]; then
|
||||
app_desc="$DEFAULT_DESC"
|
||||
fi
|
||||
|
||||
image_spec=$(trim_spaces "$image_spec")
|
||||
if [ -z "$image_spec" ]; then
|
||||
image_spec="$DEFAULT_ICON_PATH"
|
||||
fi
|
||||
|
||||
app_name_value=$(truncate_bytes "$APP_NAME" "$MAX_APP_NAME")
|
||||
app_desc=$(truncate_bytes "$app_desc" "$MAX_DESC")
|
||||
|
||||
IMAGE_1=""
|
||||
IMAGE_2=""
|
||||
IMAGE_3=""
|
||||
IMAGE_4=""
|
||||
IMAGE_COUNT=0
|
||||
|
||||
saved_ifs="$IFS"
|
||||
IFS=';'
|
||||
for raw_image in $image_spec; do
|
||||
image_path=$(trim_spaces "$raw_image")
|
||||
if [ -z "$image_path" ]; then
|
||||
continue
|
||||
fi
|
||||
image_path=$(truncate_bytes "$image_path" "$MAX_IMAGE_PATH")
|
||||
|
||||
image_file="${image_path##*/}"
|
||||
if [ ! -f "$ICON_SOURCE_DIR/$image_file" ]; then
|
||||
echo "error: icon '$image_file' (from '$image_path') not found in $ICON_SOURCE_DIR for app '$APP_NAME'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IMAGE_COUNT=$((IMAGE_COUNT + 1))
|
||||
if [ "$IMAGE_COUNT" -gt "$MAX_IMAGES" ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
case "$IMAGE_COUNT" in
|
||||
1) IMAGE_1="$image_path" ;;
|
||||
2) IMAGE_2="$image_path" ;;
|
||||
3) IMAGE_3="$image_path" ;;
|
||||
4) IMAGE_4="$image_path" ;;
|
||||
esac
|
||||
done
|
||||
IFS="$saved_ifs"
|
||||
|
||||
if [ "$IMAGE_COUNT" -eq 0 ]; then
|
||||
IMAGE_1="$DEFAULT_ICON_PATH"
|
||||
IMAGE_COUNT=1
|
||||
fi
|
||||
|
||||
app_name_escaped=$(escape_c_string "$app_name_value")
|
||||
app_desc_escaped=$(escape_c_string "$app_desc")
|
||||
image_1_escaped=$(escape_c_string "$IMAGE_1")
|
||||
image_2_escaped=$(escape_c_string "$IMAGE_2")
|
||||
image_3_escaped=$(escape_c_string "$IMAGE_3")
|
||||
image_4_escaped=$(escape_c_string "$IMAGE_4")
|
||||
|
||||
cat > "$OUT_PATH" <<EOF
|
||||
#include <stdint.h>
|
||||
#include "elf.h"
|
||||
|
||||
struct __attribute__((packed, aligned(4))) boredos_app_note_blob {
|
||||
Elf64_Word namesz;
|
||||
Elf64_Word descsz;
|
||||
Elf64_Word type;
|
||||
char name[sizeof(BOREDOS_APP_NOTE_NAME)];
|
||||
boredos_app_metadata_t metadata;
|
||||
};
|
||||
|
||||
__attribute__((used, section(".note.boredos.app"), aligned(4)))
|
||||
static const struct boredos_app_note_blob g_boredos_app_note = {
|
||||
.namesz = sizeof(BOREDOS_APP_NOTE_NAME),
|
||||
.descsz = sizeof(boredos_app_metadata_t),
|
||||
.type = BOREDOS_APP_NOTE_TYPE,
|
||||
.name = BOREDOS_APP_NOTE_NAME,
|
||||
.metadata = {
|
||||
.magic = BOREDOS_APP_METADATA_MAGIC,
|
||||
.version = BOREDOS_APP_METADATA_VERSION,
|
||||
.image_count = ${IMAGE_COUNT},
|
||||
.reserved = 0,
|
||||
.app_name = "${app_name_escaped}",
|
||||
.description = "${app_desc_escaped}",
|
||||
.images = {
|
||||
"${image_1_escaped}",
|
||||
"${image_2_escaped}",
|
||||
"${image_3_escaped}",
|
||||
"${image_4_escaped}",
|
||||
},
|
||||
},
|
||||
};
|
||||
EOF
|
||||
Loading…
Reference in a new issue