diff --git a/kernel/src/Api/BuildNo.hpp b/kernel/src/Api/BuildNo.hpp index 2acf12d..961f425 100644 --- a/kernel/src/Api/BuildNo.hpp +++ b/kernel/src/Api/BuildNo.hpp @@ -12,4 +12,4 @@ #pragma once -#define MONTAUK_BUILD_NUMBER 223 +#define MONTAUK_BUILD_NUMBER 236 diff --git a/programs/GNUmakefile b/programs/GNUmakefile index 05480d8..1e93775 100644 --- a/programs/GNUmakefile +++ b/programs/GNUmakefile @@ -49,7 +49,7 @@ BINDIR := bin PROGRAMS := $(notdir $(wildcard src/*)) # Programs with custom Makefiles (built separately). -CUSTOM_BUILDS := 2048 fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display keyboard sshserver terminal syslog procmgr powermgr calculator charmap desktop login shell paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs libloader crashpad sshd rtlsdr sdr +CUSTOM_BUILDS := 2048 fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display capabilities keyboard sshserver terminal syslog procmgr powermgr calculator charmap desktop login shell paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs libloader crashpad sshd rtlsdr sdr SYSTEM_PROGRAMS := $(filter-out $(CUSTOM_BUILDS),$(PROGRAMS)) # Build targets: system programs go to bin/os/, apps go to bin/apps//. @@ -58,7 +58,7 @@ TARGETS := $(addprefix $(BINDIR)/os/,$(addsuffix .elf,$(SYSTEM_PROGRAMS))) # Man pages source directory. MANDIR := man MANSRC := $(wildcard $(MANDIR)/*.*) -MANDST := $(patsubst $(MANDIR)/%,$(BINDIR)/man/%,$(MANSRC)) +MANDST := $(patsubst $(MANDIR)/%,$(BINDIR)/os/man/%,$(MANSRC)) # Web content source directory. WWWDIR := www @@ -96,9 +96,9 @@ WPDIR := data/wallpapers WPSRC := $(wildcard $(WPDIR)/*.jpg) WPDST := $(patsubst $(WPDIR)/%,$(BINDIR)/os/wallpapers/%,$(WPSRC)) -.PHONY: all clean 2048 fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display keyboard sshserver sshd terminal syslog procmgr powermgr calculator charmap login desktop shell paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs icons fonts configs osdata bearssl libc tls libjpeg libjpegwrite install-apps libloader crashpad rtlsdr sdr check-syscalls gen-syscalls +.PHONY: all clean 2048 fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display capabilities keyboard sshserver sshd terminal syslog procmgr powermgr calculator charmap login desktop shell paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs icons fonts configs osdata bearssl libc tls libjpeg libjpegwrite install-apps libloader crashpad rtlsdr sdr check-syscalls gen-syscalls -all: bearssl libc libjpeg libjpegwrite tls libloader rtlsdr sdr devkit $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display sshserver terminal syslog procmgr powermgr calculator charmap 2048 paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs login desktop shell sshd icons fonts install-apps crashpad $(MANDST) $(WWWDST) $(CA_CERTS) $(CONFIGDST) $(OSDATADST) $(FWDST) $(LICDST) $(WPDST) +all: bearssl libc libjpeg libjpegwrite tls libloader rtlsdr sdr devkit $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display capabilities sshserver terminal syslog procmgr powermgr calculator charmap 2048 paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs login desktop shell sshd icons fonts install-apps crashpad $(MANDST) $(WWWDST) $(CA_CERTS) $(CONFIGDST) $(OSDATADST) $(FWDST) $(LICDST) $(WPDST) # Build BearSSL static library (cross-compiled for freestanding x86_64). BEARSSL_INCLUDES := -isystem $(shell cd .. && pwd)/kernel/freestnd-c-hdrs/x86_64/include -isystem $(abspath include/libc) @@ -225,6 +225,10 @@ network: libc display: libc $(MAKE) -C src/display +# Build capability grant viewer (depends on libc). +capabilities: libc + $(MAKE) -C src/capabilities + # Build keyboard layout settings applet (depends on libc). keyboard: libc $(MAKE) -C src/keyboard @@ -281,11 +285,11 @@ shell: desktop: libc libjpeg bearssl libloader dialogs configs $(MAKE) -C src/desktop -# Copy SVG icons for the desktop into bin/icons/. +# Copy SVG icons for the desktop into bin/os/icons/. icons: ../scripts/copy_icons.sh -# Copy TTF fonts for the desktop into bin/fonts/. +# Copy TTF fonts for the desktop into bin/os/fonts/. fonts: ../scripts/copy_fonts.sh @@ -357,12 +361,12 @@ crashpad: libc $(MAKE) -C src/crashpad # Install app bundles (manifests, icons, data files) into bin/apps//. -install-apps: 2048 paint spreadsheet wordprocessor weather wikipedia imageviewer fontpreview pdfviewer disks devexplorer installer audio music video bluetooth network display keyboard sshserver terminal syslog procmgr powermgr calculator charmap screenshot texteditor mandelbrot printers timezone crashpad +install-apps: 2048 paint spreadsheet wordprocessor weather wikipedia imageviewer fontpreview pdfviewer disks devexplorer installer audio music video bluetooth network display capabilities keyboard sshserver terminal syslog procmgr powermgr calculator charmap screenshot texteditor mandelbrot printers timezone crashpad ../scripts/install_apps.sh -# Copy man pages into bin/man/ so mkramdisk.sh picks them up. -$(BINDIR)/man/%: $(MANDIR)/% - mkdir -p $(BINDIR)/man +# Copy man pages into bin/os/man/ so mkramdisk.sh picks them up. +$(BINDIR)/os/man/%: $(MANDIR)/% + mkdir -p $(BINDIR)/os/man cp $< $@ # Copy web content into bin/www/ so mkramdisk.sh picks them up. @@ -458,7 +462,6 @@ ifneq ($(wildcard ../toolchain/native-gcc/sdk/bin/gcc),) $(BINDIR)/sdk/lib/gcc/x86_64-montauk/14.2.0/ cp ../toolchain/native/sdk/bin/ld $(BINDIR)/sdk/libexec/gcc/x86_64-montauk/14.2.0/ld mkdir -p $(BINDIR)/tmp - printf 'scratch space for compiler intermediates\n' > $(BINDIR)/tmp/readme.txt else @echo "======================================================================" @echo "devkit: WARNING: toolchain/native-gcc/ not built." diff --git a/programs/include/gui/truetype.hpp b/programs/include/gui/truetype.hpp index edf3593..f7d877e 100644 --- a/programs/include/gui/truetype.hpp +++ b/programs/include/gui/truetype.hpp @@ -483,10 +483,10 @@ namespace fonts { return f; }; - system_font = load("0:/fonts/Roboto-Medium.ttf"); - system_bold = load("0:/fonts/Roboto-Bold.ttf"); - mono = load("0:/fonts/JetBrainsMono-Regular.ttf"); - mono_bold = load("0:/fonts/JetBrainsMono-Bold.ttf"); + system_font = load("0:/os/fonts/Roboto-Medium.ttf"); + system_bold = load("0:/os/fonts/Roboto-Bold.ttf"); + mono = load("0:/os/fonts/JetBrainsMono-Regular.ttf"); + mono_bold = load("0:/os/fonts/JetBrainsMono-Bold.ttf"); return system_font != nullptr; } diff --git a/programs/include/print/print.hpp b/programs/include/print/print.hpp index 49f5817..09f117e 100644 --- a/programs/include/print/print.hpp +++ b/programs/include/print/print.hpp @@ -23,17 +23,17 @@ namespace print { static constexpr const char* CONFIG_DIR = "0:/config/printing"; static constexpr const char* DEFAULT_PRINTER_PATH = "0:/config/printing/default-printer-uri"; -static constexpr const char* SPOOL_ROOT = "0:/spool/print"; -static constexpr const char* SPOOL_QUEUE_DIR = "0:/spool/print/queue"; -static constexpr const char* SPOOL_ACTIVE_DIR = "0:/spool/print/active"; -static constexpr const char* SPOOL_DONE_DIR = "0:/spool/print/done"; -static constexpr const char* SPOOL_FAILED_DIR = "0:/spool/print/failed"; -static constexpr const char* SPOOL_DOCS_DIR = "0:/spool/print/docs"; -static constexpr const char* SPOOL_TMP_DIR = "0:/spool/print/tmp"; -static constexpr const char* SPOOL_PRINTERS_DIR = "0:/spool/print/printers"; -static constexpr const char* SPOOL_DAEMON_PID_PATH = "0:/spool/print/daemon.pid"; -static constexpr const char* SPOOL_DAEMON_STATE_PATH = "0:/spool/print/daemon.state"; -static constexpr const char* SPOOL_PROBE_STATE_PATH = "0:/spool/print/printer-probe.state"; +static constexpr const char* SPOOL_ROOT = "0:/state/spool/print"; +static constexpr const char* SPOOL_QUEUE_DIR = "0:/state/spool/print/queue"; +static constexpr const char* SPOOL_ACTIVE_DIR = "0:/state/spool/print/active"; +static constexpr const char* SPOOL_DONE_DIR = "0:/state/spool/print/done"; +static constexpr const char* SPOOL_FAILED_DIR = "0:/state/spool/print/failed"; +static constexpr const char* SPOOL_DOCS_DIR = "0:/state/spool/print/docs"; +static constexpr const char* SPOOL_TMP_DIR = "0:/state/spool/print/tmp"; +static constexpr const char* SPOOL_PRINTERS_DIR = "0:/state/spool/print/printers"; +static constexpr const char* SPOOL_DAEMON_PID_PATH = "0:/state/spool/print/daemon.pid"; +static constexpr const char* SPOOL_DAEMON_STATE_PATH = "0:/state/spool/print/daemon.state"; +static constexpr const char* SPOOL_PROBE_STATE_PATH = "0:/state/spool/print/printer-probe.state"; static constexpr const char* PRINTD_BINARY = "0:/os/printd.elf"; static constexpr int MAX_PATH_LEN = 256; static constexpr int MAX_JOB_NAME_LEN = 128; @@ -244,7 +244,8 @@ inline bool ensure_dir(const char* path) { inline bool ensure_spool_dirs() { return ensure_dir("0:/config") && ensure_dir(CONFIG_DIR) - && ensure_dir("0:/spool") + && ensure_dir("0:/state") + && ensure_dir("0:/state/spool") && ensure_dir(SPOOL_ROOT) && ensure_dir(SPOOL_QUEUE_DIR) && ensure_dir(SPOOL_ACTIVE_DIR) diff --git a/programs/src/capabilities/Makefile b/programs/src/capabilities/Makefile new file mode 100644 index 0000000..f2ab451 --- /dev/null +++ b/programs/src/capabilities/Makefile @@ -0,0 +1,66 @@ +# Makefile for capabilities (capability grant viewer) on MontaukOS +# Copyright (c) 2026 Daniel Hammer + +MAKEFLAGS += -rR +.SUFFIXES: + +TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) + CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) +else + CXX := $(TOOLCHAIN_PREFIX)g++ +endif + +PROG_INC := ../../include +LINK_LD := ../../link.ld +BINDIR := ../../bin +OBJDIR := obj +LIBDIR := ../../lib + +CXXFLAGS := \ + -std=gnu++20 \ + -g -O2 -pipe \ + -Wall \ + -Wextra \ + -Wno-unused-parameter \ + -Wno-unused-function \ + -ffreestanding \ + -fno-stack-protector \ + -fno-stack-check \ + -fno-rtti \ + -fno-exceptions \ + -ffunction-sections \ + -fdata-sections \ + -msse \ + -msse2 \ + -MMD -MP \ + -I $(PROG_INC) \ + -isystem $(PROG_INC)/libc + +LDFLAGS := \ + -nostdlib \ + -Wl,--gc-sections \ + -T $(LINK_LD) + +SRCS := main.cpp stb_truetype_impl.cpp +OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) + +TARGET := $(BINDIR)/apps/capabilities/capabilities.elf +LIBS := $(LIBDIR)/libc/liblibc.a + +.PHONY: all clean + +all: $(TARGET) + +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBS) + mkdir -p $(BINDIR)/apps/capabilities + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ + +$(OBJDIR)/%.o: %.cpp Makefile + mkdir -p $(dir $@) + $(CXX) $(CXXFLAGS) -c $< -o $@ + +-include $(OBJS:.o=.d) + +clean: + rm -rf $(OBJDIR) $(TARGET) diff --git a/programs/src/capabilities/main.cpp b/programs/src/capabilities/main.cpp new file mode 100644 index 0000000..9559819 --- /dev/null +++ b/programs/src/capabilities/main.cpp @@ -0,0 +1,744 @@ +/* + * main.cpp + * MontaukOS capability grant viewer + * Copyright (c) 2026 Daniel Hammer + */ + +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +using namespace gui; + +static constexpr int WIN_W = 760; +static constexpr int WIN_H = 560; +static constexpr int TAB_H = 36; +static constexpr int FOOTER_H = 44; +static constexpr int PAD = 18; +static constexpr int BUTTON_W = 88; +static constexpr int LIST_W = 200; +static constexpr int LIST_ROW_H = 30; +static constexpr int GRID_ROW_H = 22; +static constexpr int GRID_COL_W = 86; +static constexpr int MAX_GRANTS = 64; +static constexpr int MAX_ISSUES = 4; + +static constexpr int CAP_COUNT = + (int)(sizeof(montauk::caps::NAMES) / sizeof(montauk::caps::NAMES[0])); + +enum Tab { + TAB_PROGRAMS = 0, + TAB_CAPS = 1, + TAB_COUNT = 2, +}; + +static const char* const kTabLabels[TAB_COUNT] = { + "Programs", + "Capabilities", +}; + +// What each capability gates, in the order of montauk::caps::NAMES. +static const char* const kCapDescriptions[CAP_COUNT] = { + "Inspect and terminate other processes", + "Ask the session to shut down or restart", + "Power the machine off or reset it directly", + "Put the machine to sleep (S3)", + "Format, mount and manage volumes", + "Read and write raw block devices", + "Configure network interfaces, DHCP and Wi-Fi", + "Set the system clock", + "Manage user accounts and session identities", + "Change display modes and panel brightness", + "Manage hardware devices (Bluetooth, radio)", + "Read the kernel log", + "Write to 0:/os and 0:/apps (never part of \"all\")", +}; + +// ==== Grant table model ==== + +enum Field { + FIELD_EFFECTIVE = 0, + FIELD_DELEGABLE = 1, + FIELD_PERMITTED = 2, + FIELD_COUNT = 3, +}; + +static const char* const kFieldKeys[FIELD_COUNT] = { + "effective", "delegable", "permitted", +}; + +static const char* const kFieldLabels[FIELD_COUNT] = { + "Effective", "Delegable", "Permitted", +}; + +struct Grant { + char id[32]; + char path[96]; + uint64_t mask[FIELD_COUNT]; + bool declared[FIELD_COUNT]; + bool uses_all[FIELD_COUNT]; + bool binary_present; + char issues[MAX_ISSUES][96]; + int issue_count; +}; + +static Grant g_grants[MAX_GRANTS]; +static int g_grant_count = 0; +static bool g_file_present = false; +static bool g_truncated = false; + +static WsWindow g_win; +static Tab g_tab = TAB_PROGRAMS; +static int g_mouse_x = -1; +static int g_mouse_y = -1; +static Color g_accent = colors::ACCENT; +static bool g_is_admin = false; +static int g_selected_grant = 0; +static int g_selected_cap = 0; +static int g_list_scroll = 0; +static bool g_list_sb_dragging = false; +static int g_list_sb_drag_offset = 0; +static char g_status[128] = {}; +static uint64_t g_status_time = 0; + +// Same test as montauk::user::is_admin(), without pulling in its BearSSL +// password-hashing dependency. +static bool session_is_admin() { + char user[64] = {}; + if (montauk::getuser(user, sizeof(user)) <= 0 || !user[0]) return false; + + char key[96]; + snprintf(key, sizeof(key), "users.%s.role", user); + montauk::toml::Doc doc = montauk::config::load("users"); + bool admin = montauk::streq(doc.get_string(key, ""), "admin"); + doc.destroy(); + return admin; +} + +static void add_issue(Grant& g, const char* fmt, const char* a = "", const char* b = "") { + if (g.issue_count >= MAX_ISSUES) return; + snprintf(g.issues[g.issue_count++], sizeof(g.issues[0]), fmt, a, b); +} + +static Grant* find_or_add_grant(const char* id, int idLen) { + for (int i = 0; i < g_grant_count; i++) { + const char* have = g_grants[i].id; + int k = 0; + while (k < idLen && have[k] == id[k]) k++; + if (k == idLen && have[k] == '\0') return &g_grants[i]; + } + if (g_grant_count >= MAX_GRANTS) { + g_truncated = true; + return nullptr; + } + Grant* g = &g_grants[g_grant_count++]; + montauk::memset(g, 0, sizeof(*g)); + int n = idLen < (int)sizeof(g->id) - 1 ? idLen : (int)sizeof(g->id) - 1; + montauk::memcpy(g->id, id, n); + g->id[n] = '\0'; + return g; +} + +static void read_field(Grant& g, int field, montauk::toml::Value* v) { + g.declared[field] = true; + if (v->type != montauk::toml::Type::Array) { + add_issue(g, "'%s' is not a list of capability names", kFieldKeys[field]); + return; + } + for (int i = 0; i < v->array.count; i++) { + montauk::toml::Value* item = v->array.items[i]; + if (item == nullptr || item->type != montauk::toml::Type::String) continue; + uint64_t bit = montauk::caps::bit_for_name(item->str); + if (bit == 0) { + add_issue(g, "Unknown capability \"%s\" in %s (ignored)", + item->str, kFieldKeys[field]); + continue; + } + if (montauk::streq(item->str, "all")) g.uses_all[field] = true; + g.mask[field] |= bit; + } +} + +// Mirrors montauk::caps::lookup(), but keeps everything the launcher would +// silently discard so it can be shown. +static void load_grants() { + g_grant_count = 0; + g_truncated = false; + + int fh = montauk::open("0:/config/capabilities.toml"); + g_file_present = fh >= 0; + if (fh >= 0) montauk::close(fh); + + montauk::toml::Doc doc = montauk::config::load(montauk::caps::GRANT_CONFIG); + int prefixLen = montauk::slen(montauk::caps::GRANT_PREFIX); + + for (int i = 0; i < doc.entries.count; i++) { + montauk::toml::Value* entry = doc.entries.items[i]; + if (entry == nullptr || entry->key == nullptr) continue; + if (!montauk::starts_with(entry->key, montauk::caps::GRANT_PREFIX)) continue; + + const char* rest = entry->key + prefixLen; + int lastDot = -1; + for (int k = 0; rest[k]; k++) + if (rest[k] == '.') lastDot = k; + if (lastDot <= 0) continue; + + Grant* g = find_or_add_grant(rest, lastDot); + if (g == nullptr) continue; + const char* field = rest + lastDot + 1; + + if (montauk::streq(field, "path")) { + if (entry->type == montauk::toml::Type::String) + snprintf(g->path, sizeof(g->path), "%s", entry->str); + continue; + } + bool known = false; + for (int f = 0; f < FIELD_COUNT; f++) { + if (montauk::streq(field, kFieldKeys[f])) { + read_field(*g, f, entry); + known = true; + } + } + if (!known) add_issue(*g, "Unknown key '%s' (ignored)", field); + } + doc.destroy(); + + for (int i = 0; i < g_grant_count; i++) { + Grant& g = g_grants[i]; + uint64_t* m = g.mask; + + // Same rule as caps::lookup(): an undeclared permitted set is exactly + // what the grant can use or pass on. + if (!g.declared[FIELD_PERMITTED] || m[FIELD_PERMITTED] == 0) + m[FIELD_PERMITTED] = m[FIELD_EFFECTIVE] | m[FIELD_DELEGABLE]; + else if ((m[FIELD_EFFECTIVE] | m[FIELD_DELEGABLE]) & ~m[FIELD_PERMITTED]) + add_issue(g, "Effective/delegable exceed permitted; the excess is dropped at launch"); + + if (g.path[0] == '\0') { + add_issue(g, "No path; this grant never applies"); + continue; + } + int bh = montauk::open(g.path); + g.binary_present = bh >= 0; + if (bh >= 0) montauk::close(bh); + if (!g.binary_present) add_issue(g, "Binary not found on this system"); + + for (int j = 0; j < i; j++) { + if (montauk::streq(g_grants[j].path, g.path)) { + add_issue(g, "Shadowed by [grant.%s]; the first entry for a path wins", + g_grants[j].id); + break; + } + } + } + + if (g_selected_grant >= g_grant_count) g_selected_grant = 0; +} + +// ==== Layout ==== + +static mtk::Theme app_theme() { + return mtk::make_theme(g_accent); +} + +static Rect tab_bar_rect() { + return {0, 0, g_win.width, TAB_H}; +} + +static Rect footer_rect() { + return {0, g_win.height - FOOTER_H, g_win.width, FOOTER_H}; +} + +static constexpr int LIST_TOP_INSET = 10; + +static int sidebar_w() { + return PAD + LIST_W + PAD; +} + +// The whole left column, from the tab bar to the footer. The scrollbar runs +// its full height against the divider, like a pane scrollbar. +static Rect list_rect() { + return {0, TAB_H, sidebar_w(), footer_rect().y - TAB_H}; +} + +static int list_count() { + return g_tab == TAB_PROGRAMS ? g_grant_count : CAP_COUNT; +} + +static int list_visible_rows() { + return (list_rect().h - LIST_TOP_INSET) / LIST_ROW_H; +} + +static int list_view_extent() { + return list_visible_rows() * LIST_ROW_H; +} + +static int list_content_extent() { + return list_count() * LIST_ROW_H; +} + +static bool list_scrollbar_visible() { + return mtk::scrollbar_needed(list_content_extent(), list_view_extent()); +} + +static Rect list_scrollbar_track() { + if (!list_scrollbar_visible()) return {0, 0, 0, 0}; + return mtk::scrollbar_track_rect(list_rect()); +} + +static Rect list_scrollbar_thumb() { + Rect track = list_scrollbar_track(); + if (track.empty()) return {0, 0, 0, 0}; + return mtk::scrollbar_thumb_rect(track, list_content_extent(), + list_view_extent(), g_list_scroll * LIST_ROW_H); +} + +static Rect list_row_rect(int visibleIndex) { + Rect list = list_rect(); + int right = list.w - (list_scrollbar_visible() ? mtk::SCROLLBAR_W + 6 : PAD); + return {PAD, list.y + LIST_TOP_INSET + visibleIndex * LIST_ROW_H, + right - PAD, LIST_ROW_H}; +} + +static int pane_x() { + return sidebar_w() + 1 + PAD; +} + +static int pane_w() { + return g_win.width - pane_x() - PAD; +} + +static Rect reload_button() { + Rect foot = footer_rect(); + return {foot.x + foot.w - PAD - BUTTON_W, foot.y + 7, BUTTON_W, 30}; +} + +static bool mouse_in(const Rect& rect) { + return rect.contains(g_mouse_x, g_mouse_y); +} + +static void clamp_list_scroll() { + int max_scroll = list_count() - list_visible_rows(); + if (max_scroll < 0) max_scroll = 0; + if (g_list_scroll > max_scroll) g_list_scroll = max_scroll; + if (g_list_scroll < 0) g_list_scroll = 0; +} + +static void set_status(const char* msg) { + snprintf(g_status, sizeof(g_status), "%s", msg ? msg : ""); + g_status_time = montauk::get_milliseconds(); +} + +static bool status_visible() { + return g_status[0] && montauk::get_milliseconds() - g_status_time < 5000; +} + +// ==== Drawing ==== + +static void fit_text(char* out, int outCap, const char* text, int maxWidth) { + if (!out || outCap <= 0) return; + out[0] = '\0'; + if (!text || !text[0] || maxWidth <= 0) return; + if (text_width(text) <= maxWidth) { + snprintf(out, outCap, "%s", text); + return; + } + + static const char* ellipsis = "..."; + int len = 0; + while (text[len] && len < outCap - 4) { + out[len] = text[len]; + out[len + 1] = '\0'; + if (text_width(out) + text_width(ellipsis) > maxWidth) break; + len++; + } + out[len++] = '.'; + out[len++] = '.'; + out[len++] = '.'; + out[len] = '\0'; +} + +static void draw_text_fit(Canvas& c, int x, int y, const char* text, + int maxWidth, Color color) { + char fitted[160]; + fit_text(fitted, sizeof(fitted), text, maxWidth); + c.text(x, y, fitted, color); +} + +static void draw_list(Canvas& c, const mtk::Theme& theme) { + int fh = system_font_height(); + int count = list_count(); + int visible = list_visible_rows(); + for (int row = 0; row < visible; row++) { + int index = g_list_scroll + row; + if (index >= count) break; + Rect r = list_row_rect(row); + bool selected = index == (g_tab == TAB_PROGRAMS ? g_selected_grant : g_selected_cap); + mtk::draw_list_row(c, r, selected, false, theme); + if (!selected && mouse_in(r)) + c.fill_rounded_rect(r.x, r.y, r.w, r.h, theme.radius_md, theme.surface_hover); + + const char* label = g_tab == TAB_PROGRAMS + ? g_grants[index].id : montauk::caps::NAMES[index].name; + Color fg = selected ? theme.accent_fg : theme.text; + int ty = r.y + (r.h - fh) / 2; + draw_text_fit(c, r.x + 10, ty, label, r.w - 34, fg); + + if (g_tab == TAB_PROGRAMS && g_grants[index].issue_count > 0) { + Color dot = selected ? theme.accent_fg : theme.danger; + fill_circle(c, r.x + r.w - 14, r.y + r.h / 2, 4, dot); + } + } + + if (list_scrollbar_visible()) { + Rect track = list_scrollbar_track(); + bool hovered = track.contains(g_mouse_x, g_mouse_y) || g_list_sb_dragging; + mtk::draw_scrollbar(c, track, list_scrollbar_thumb(), hovered, + g_list_sb_dragging, theme); + } + + int sx = sidebar_w(); + c.fill_rect(sx, TAB_H, 1, footer_rect().y - TAB_H, theme.border); +} + +static void draw_mark(Canvas& c, int cx, int cy, bool on, const mtk::Theme& theme) { + Rect cell = {cx - 8, cy - 8, 16, 16}; + mtk::draw_checkbox(c, cell, "", mtk::check_state(on), theme, true, false); +} + +static void draw_programs_pane(Canvas& c, const mtk::Theme& theme) { + int x = pane_x(); + int w = pane_w(); + int fh = system_font_height(); + int y = TAB_H + PAD; + + if (g_grant_count == 0) { + c.text(x, y, g_file_present ? "No grants are declared." + : "0:/config/capabilities.toml was not found.", + theme.text_subtle); + c.text(x, y + fh + 8, "Programs without a grant run with no capabilities.", + theme.text_muted); + return; + } + + const Grant& g = g_grants[g_selected_grant]; + char title[64]; + snprintf(title, sizeof(title), "[grant.%s]", g.id); + c.text(x, y, title, theme.text); + + if (g.issue_count > 0) { + const char* state = "Needs attention"; + c.text(x + w - text_width(state), y, state, theme.danger); + } + + y += fh + 6; + draw_text_fit(c, x, y, g.path[0] ? g.path : "(no path)", w, theme.text_subtle); + + y += fh + 14; + mtk::draw_separator(c, x, y, w, theme); + y += 12; + + // Grid: one row per capability, one column per mask. + int colX = x + w - GRID_COL_W * FIELD_COUNT; + c.text(x, y, "CAPABILITY", theme.text_muted); + for (int f = 0; f < FIELD_COUNT; f++) { + const char* label = kFieldLabels[f]; + int cx = colX + f * GRID_COL_W + GRID_COL_W / 2; + c.text(cx - text_width(label) / 2, y, label, theme.text_muted); + } + y += fh + 4; + for (int f = 0; f < FIELD_COUNT; f++) { + const char* note = nullptr; + if (g.uses_all[f]) note = "(all)"; + else if (f == FIELD_PERMITTED && !g.declared[f]) note = "(implied)"; + if (!note) continue; + int cx = colX + f * GRID_COL_W + GRID_COL_W / 2; + c.text(cx - text_width(note) / 2, y, note, theme.text_muted); + } + y += fh + 4; + + for (int i = 0; i < CAP_COUNT; i++) { + uint64_t bit = montauk::caps::NAMES[i].bit; + bool any = (g.mask[FIELD_PERMITTED] & bit) != 0; + if (i % 2 == 1) + c.fill_rect(x, y, w, GRID_ROW_H, theme.surface_alt); + c.text(x + 6, y + (GRID_ROW_H - fh) / 2, montauk::caps::NAMES[i].name, + any ? theme.text : theme.text_muted); + for (int f = 0; f < FIELD_COUNT; f++) { + int cx = colX + f * GRID_COL_W + GRID_COL_W / 2; + draw_mark(c, cx, y + GRID_ROW_H / 2, (g.mask[f] & bit) != 0, theme); + } + y += GRID_ROW_H; + } + + y += 10; + for (int i = 0; i < g.issue_count; i++) { + draw_text_fit(c, x, y, g.issues[i], w, theme.danger); + y += fh + 4; + } +} + +static int draw_holder_list(Canvas& c, int x, int y, int w, int bottom, + const char* heading, int field, uint64_t bit, + const mtk::Theme& theme) { + int fh = system_font_height(); + c.text(x, y, heading, theme.text_muted); + y += fh + 8; + + int total = 0; + for (int i = 0; i < g_grant_count; i++) + if (g_grants[i].mask[field] & bit) total++; + if (total == 0) { + c.text(x + 10, y, "No program", theme.text_subtle); + return y + fh + 16; + } + + int shown = 0; + for (int i = 0; i < g_grant_count; i++) { + const Grant& g = g_grants[i]; + if (!(g.mask[field] & bit)) continue; + if (y + (fh + 6) * 2 > bottom && shown < total - 1) { + char more[48]; + snprintf(more, sizeof(more), "+%d more", total - shown); + c.text(x + 10, y, more, theme.text_muted); + return y + fh + 16; + } + c.text(x + 10, y, g.id, theme.text); + draw_text_fit(c, x + 130, y, g.path, w - 130, theme.text_subtle); + y += fh + 6; + shown++; + } + return y + 12; +} + +static void draw_caps_pane(Canvas& c, const mtk::Theme& theme) { + int x = pane_x(); + int w = pane_w(); + int fh = system_font_height(); + int y = TAB_H + PAD; + int bottom = footer_rect().y - PAD; + + const auto& cap = montauk::caps::NAMES[g_selected_cap]; + c.text(x, y, cap.name, theme.text); + y += fh + 6; + draw_text_fit(c, x, y, kCapDescriptions[g_selected_cap], w, theme.text_subtle); + y += fh + 14; + mtk::draw_separator(c, x, y, w, theme); + y += 14; + + y = draw_holder_list(c, x, y, w, bottom - (fh + 6) * 4, + "USES IT (EFFECTIVE)", FIELD_EFFECTIVE, cap.bit, theme); + draw_holder_list(c, x, y, w, bottom, + "MAY PASS IT ON (DELEGABLE)", FIELD_DELEGABLE, cap.bit, theme); +} + +static void draw_locked(Canvas& c, const mtk::Theme& theme) { + int fh = system_font_height(); + int y = TAB_H + 60; + const char* title = "Administrator access required"; + c.text((g_win.width - text_width(title)) / 2, y, title, theme.text); + const char* body = "Only administrators can review the capability grant table."; + c.text((g_win.width - text_width(body)) / 2, y + fh + 10, body, theme.text_subtle); +} + +static void draw_footer(Canvas& c, const mtk::Theme& theme) { + Rect foot = footer_rect(); + c.fill_rect(foot.x, foot.y, foot.w, foot.h, theme.surface); + mtk::draw_separator(c, 0, foot.y, g_win.width, theme); + + char summary[128]; + if (status_visible()) { + snprintf(summary, sizeof(summary), "%s", g_status); + } else if (!g_is_admin) { + snprintf(summary, sizeof(summary), "Read-only"); + } else { + int flagged = 0; + for (int i = 0; i < g_grant_count; i++) + if (g_grants[i].issue_count > 0) flagged++; + snprintf(summary, sizeof(summary), "%d grant%s%s, %d flagged - read-only view", + g_grant_count, g_grant_count == 1 ? "" : "s", + g_truncated ? " (list truncated)" : "", flagged); + } + c.text(PAD, foot.y + (foot.h - system_font_height()) / 2, summary, theme.text_subtle); + + if (g_is_admin) { + Rect reload = reload_button(); + mtk::draw_button(c, reload, "Reload", mtk::BUTTON_SECONDARY, + mtk::widget_state(false, mouse_in(reload), true), theme); + } +} + +static void render() { + mtk::StandaloneHost host(&g_win); + Canvas c = host.canvas(); + mtk::Theme theme = app_theme(); + c.fill(theme.window_bg); + if (g_is_admin) { + mtk::draw_tab_bar(c, tab_bar_rect(), kTabLabels, TAB_COUNT, (int)g_tab, theme); + draw_list(c, theme); + if (g_tab == TAB_PROGRAMS) draw_programs_pane(c, theme); + else draw_caps_pane(c, theme); + } else { + draw_locked(c, theme); + } + draw_footer(c, theme); + host.present(); +} + +// ==== Input ==== + +static void reload() { + load_grants(); + clamp_list_scroll(); + set_status("Reloaded 0:/config/capabilities.toml"); +} + +static void select_index(int index) { + int count = list_count(); + if (count <= 0) return; + if (index < 0) index = 0; + if (index >= count) index = count - 1; + if (g_tab == TAB_PROGRAMS) g_selected_grant = index; + else g_selected_cap = index; + + int visible = list_visible_rows(); + if (index < g_list_scroll) g_list_scroll = index; + else if (index >= g_list_scroll + visible) g_list_scroll = index - visible + 1; + clamp_list_scroll(); +} + +static void switch_tab(Tab tab) { + g_tab = tab; + g_list_scroll = 0; + select_index(tab == TAB_PROGRAMS ? g_selected_grant : g_selected_cap); +} + +static void handle_mouse(const montauk::abi::WinEvent& ev) { + if (!g_is_admin) return; + int mx = ev.mouse.x; + int my = ev.mouse.y; + bool pressed = (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1); + + Rect track = list_scrollbar_track(); + Rect thumb = list_scrollbar_thumb(); + if (g_list_sb_dragging) { + if ((ev.mouse.buttons & 1) && !track.empty()) { + int offset = mtk::scrollbar_offset_from_thumb_top( + track, list_content_extent(), list_view_extent(), + thumb.h, my - g_list_sb_drag_offset); + g_list_scroll = offset / LIST_ROW_H; + clamp_list_scroll(); + return; + } + g_list_sb_dragging = false; + } + + if (ev.mouse.scroll != 0 && list_rect().contains(mx, my)) { + g_list_scroll += ev.mouse.scroll > 0 ? -1 : 1; + clamp_list_scroll(); + return; + } + if (!pressed) return; + + int tab = mtk::hit_tab_bar(tab_bar_rect(), TAB_COUNT, mx, my); + if (tab >= 0) { + switch_tab((Tab)tab); + return; + } + if (!track.empty() && track.contains(mx, my)) { + if (thumb.contains(mx, my)) { + g_list_sb_dragging = true; + g_list_sb_drag_offset = my - thumb.y; + } else { + int visible = list_visible_rows(); + int page = visible > 1 ? visible - 1 : 1; + g_list_scroll += my < thumb.y ? -page : page; + clamp_list_scroll(); + } + return; + } + for (int row = 0; row < list_visible_rows(); row++) { + int index = g_list_scroll + row; + if (index >= list_count()) break; + if (list_row_rect(row).contains(mx, my)) { + select_index(index); + return; + } + } + if (reload_button().contains(mx, my)) reload(); +} + +static bool handle_key(const montauk::abi::KeyEvent& key) { + if (!key.pressed) return false; + if (key.scancode == 0x01) { + g_win.closed = true; + return true; + } + if (!g_is_admin) return false; + if (key.ascii == '\t') { + switch_tab(g_tab == TAB_PROGRAMS ? TAB_CAPS : TAB_PROGRAMS); + return true; + } + int current = g_tab == TAB_PROGRAMS ? g_selected_grant : g_selected_cap; + if (key.scancode == 0x48) { select_index(current - 1); return true; } // Up + if (key.scancode == 0x50) { select_index(current + 1); return true; } // Down + if (key.ascii == 'r' || key.ascii == 'R') { + reload(); + return true; + } + return false; +} + +extern "C" void _start() { + if (!fonts::init()) montauk::exit(1); + g_accent = mtk::load_system_accent(); + + g_is_admin = session_is_admin(); + if (g_is_admin) load_grants(); + + if (!g_win.create("Capabilities", WIN_W, WIN_H)) montauk::exit(1); + render(); + + while (g_win.id >= 0 && !g_win.closed) { + montauk::abi::WinEvent ev; + int result = g_win.poll(&ev); + if (result < 0) break; + if (result == 0) { + // Keep drawing while a status message is up, plus once more to + // clear it when it expires. + static bool status_drawn = false; + if (status_visible() || status_drawn) { + status_drawn = status_visible(); + render(); + } + montauk::sleep_ms(16); + continue; + } + + bool redraw = false; + if (ev.type == 3) break; + if (ev.type == 2 || ev.type == 4) { + clamp_list_scroll(); + redraw = true; + } else if (ev.type == 1) { + g_mouse_x = ev.mouse.x; + g_mouse_y = ev.mouse.y; + handle_mouse(ev); + redraw = true; + } else if (ev.type == 0) { + redraw = handle_key(ev.key); + } + if (redraw) render(); + } + + g_win.destroy(); + montauk::exit(0); +} diff --git a/programs/src/capabilities/manifest.toml b/programs/src/capabilities/manifest.toml new file mode 100644 index 0000000..eff84f9 --- /dev/null +++ b/programs/src/capabilities/manifest.toml @@ -0,0 +1,13 @@ +[app] +id = "capabilities" +name = "Capabilities" +binary = "capabilities.elf" +icon = "stock_lock.svg" + +[menu] +category = "System" +visible = false + +[desktop] +section = "settings" +admin_only = true diff --git a/programs/src/capabilities/stb_truetype_impl.cpp b/programs/src/capabilities/stb_truetype_impl.cpp new file mode 100644 index 0000000..8a37089 --- /dev/null +++ b/programs/src/capabilities/stb_truetype_impl.cpp @@ -0,0 +1,30 @@ +/* + * stb_truetype_impl.cpp + * Single compilation unit for stb_truetype in MontaukOS freestanding environment + * Copyright (c) 2026 Daniel Hammer + */ + +#include +#include +#include +#include +#include + +#define STBTT_ifloor(x) ((int) stb_floor(x)) +#define STBTT_iceil(x) ((int) stb_ceil(x)) +#define STBTT_sqrt(x) stb_sqrt(x) +#define STBTT_pow(x,y) stb_pow(x,y) +#define STBTT_fmod(x,y) stb_fmod(x,y) +#define STBTT_cos(x) stb_cos(x) +#define STBTT_acos(x) stb_acos(x) +#define STBTT_fabs(x) stb_fabs(x) + +#define STBTT_malloc(x,u) ((void)(u), montauk::malloc(x)) +#define STBTT_free(x,u) ((void)(u), montauk::mfree(x)) +#define STBTT_memcpy(d,s,n) montauk::memcpy(d,s,n) +#define STBTT_memset(d,v,n) montauk::memset(d,v,n) +#define STBTT_strlen(x) montauk::slen(x) +#define STBTT_assert(x) ((void)(x)) + +#define STB_TRUETYPE_IMPLEMENTATION +#include diff --git a/programs/src/desktop/apps/filemanager/app.cpp b/programs/src/desktop/apps/filemanager/app.cpp index e046328..6ffab89 100644 --- a/programs/src/desktop/apps/filemanager/app.cpp +++ b/programs/src/desktop/apps/filemanager/app.cpp @@ -78,33 +78,33 @@ void ensure_filemanager_icons_loaded(DesktopState* ds) { if (!ds || ds->icon_drive.pixels) return; Color defColor = colors::ICON_COLOR; - ds->icon_drive = svg_load("0:/icons/drive-harddisk.svg", 16, 16, defColor); - ds->icon_drive_lg = svg_load("0:/icons/drive-harddisk.svg", 48, 48, defColor); - ds->icon_drive_usb = svg_load("0:/icons/drive-harddisk-usb.svg", 16, 16, defColor); - ds->icon_drive_usb_lg = svg_load("0:/icons/drive-harddisk-usb.svg", 48, 48, defColor); - ds->icon_home_folder = svg_load("0:/icons/folder-blue-home.svg", 16, 16, defColor); - ds->icon_home_folder_lg = svg_load("0:/icons/folder-blue-home.svg", 48, 48, defColor); - ds->icon_apps = svg_load("0:/icons/folder-blue-development.svg", 16, 16, defColor); - ds->icon_apps_lg = svg_load("0:/icons/folder-blue-development.svg", 48, 48, defColor); + ds->icon_drive = svg_load("0:/os/icons/drive-harddisk.svg", 16, 16, defColor); + ds->icon_drive_lg = svg_load("0:/os/icons/drive-harddisk.svg", 48, 48, defColor); + ds->icon_drive_usb = svg_load("0:/os/icons/drive-harddisk-usb.svg", 16, 16, defColor); + ds->icon_drive_usb_lg = svg_load("0:/os/icons/drive-harddisk-usb.svg", 48, 48, defColor); + ds->icon_home_folder = svg_load("0:/os/icons/folder-blue-home.svg", 16, 16, defColor); + ds->icon_home_folder_lg = svg_load("0:/os/icons/folder-blue-home.svg", 48, 48, defColor); + ds->icon_apps = svg_load("0:/os/icons/folder-blue-development.svg", 16, 16, defColor); + ds->icon_apps_lg = svg_load("0:/os/icons/folder-blue-development.svg", 48, 48, defColor); ds->icon_system_configuration_menu = - svg_load("0:/icons/preferences-system.svg", 20, 20, defColor); + svg_load("0:/os/icons/preferences-system.svg", 20, 20, defColor); ds->icon_system_configuration = - svg_load("0:/icons/preferences-system.svg", 16, 16, defColor); + svg_load("0:/os/icons/preferences-system.svg", 16, 16, defColor); ds->icon_system_configuration_lg = - svg_load("0:/icons/preferences-system.svg", 48, 48, defColor); + svg_load("0:/os/icons/preferences-system.svg", 48, 48, defColor); for (int sf = 0; sf < filemanager::SF_COUNT; sf++) { char icon_path[128]; - snprintf(icon_path, 128, "0:/icons/%s", filemanager::sf_icons[sf]); + snprintf(icon_path, 128, "0:/os/icons/%s", filemanager::sf_icons[sf]); ds->icon_special_folder[sf] = svg_load(icon_path, 16, 16, defColor); ds->icon_special_folder_lg[sf] = svg_load(icon_path, 48, 48, defColor); } - ds->icon_delete = svg_load("0:/icons/trash-empty.svg", 16, 16, defColor); - ds->icon_copy = svg_load("0:/icons/edit-copy.svg", 16, 16, defColor); - ds->icon_cut = svg_load("0:/icons/edit-cut.svg", 16, 16, defColor); - ds->icon_paste = svg_load("0:/icons/edit-paste.svg", 16, 16, defColor); - ds->icon_rename = svg_load("0:/icons/edit-rename.svg", 16, 16, defColor); - ds->icon_folder_new = svg_load("0:/icons/folder-new.svg", 16, 16, defColor); + ds->icon_delete = svg_load("0:/os/icons/trash-empty.svg", 16, 16, defColor); + ds->icon_copy = svg_load("0:/os/icons/edit-copy.svg", 16, 16, defColor); + ds->icon_cut = svg_load("0:/os/icons/edit-cut.svg", 16, 16, defColor); + ds->icon_paste = svg_load("0:/os/icons/edit-paste.svg", 16, 16, defColor); + ds->icon_rename = svg_load("0:/os/icons/edit-rename.svg", 16, 16, defColor); + ds->icon_folder_new = svg_load("0:/os/icons/folder-new.svg", 16, 16, defColor); } void open_filemanager(DesktopState* ds) { diff --git a/programs/src/desktop/battery.cpp b/programs/src/desktop/battery.cpp index 179b28f..b570f0c 100644 --- a/programs/src/desktop/battery.cpp +++ b/programs/src/desktop/battery.cpp @@ -63,7 +63,7 @@ static void battery_icon_path(const DesktopState* ds, char* out, int cap) { const montauk::abi::BatteryInfo& b = ds->battery_info; if (!b.present) { - montauk::strncpy(out, "0:/icons/battery-missing-symbolic.svg", cap); + montauk::strncpy(out, "0:/os/icons/battery-missing-symbolic.svg", cap); return; } @@ -72,11 +72,11 @@ static void battery_icon_path(const DesktopState* ds, char* out, int cap) { // A full battery on the charger gets the "charged" glyph; the pack has no // 100% charging variant, and "charged" is what that state means anyway. if (b.charging && bucket >= 100) { - montauk::strncpy(out, "0:/icons/battery-level-100-charged-symbolic.svg", cap); + montauk::strncpy(out, "0:/os/icons/battery-level-100-charged-symbolic.svg", cap); return; } - snprintf(out, cap, "0:/icons/battery-level-%d%s-symbolic.svg", + snprintf(out, cap, "0:/os/icons/battery-level-%d%s-symbolic.svg", bucket, b.charging ? "-charging" : ""); } diff --git a/programs/src/desktop/desktop_builtin.cpp b/programs/src/desktop/desktop_builtin.cpp index 03f90e8..efb885a 100644 --- a/programs/src/desktop/desktop_builtin.cpp +++ b/programs/src/desktop/desktop_builtin.cpp @@ -8,13 +8,13 @@ #include static const DesktopBuiltinEntry builtin_entries[] = { - { DESKTOP_BUILTIN_FILES, "Files", 0, false, nullptr, "0:/icons/system-file-manager.svg" }, + { DESKTOP_BUILTIN_FILES, "Files", 0, false, nullptr, "0:/os/icons/system-file-manager.svg" }, { DESKTOP_BUILTIN_DESKTOP_SETTINGS, "Desktop Settings", -1, false, "desktop-settings", - "0:/icons/preferences-desktop-apps.svg" }, + "0:/os/icons/preferences-desktop-apps.svg" }, { DESKTOP_BUILTIN_SYSTEM_CONFIGURATION, "Settings", -1, true, nullptr, - "0:/icons/preferences-system.svg" }, + "0:/os/icons/preferences-system.svg" }, { DESKTOP_BUILTIN_USER_MANAGEMENT, "User Management", -1, false, "user-management", - "0:/icons/user-home.svg" }, + "0:/os/icons/user-home.svg" }, { DESKTOP_BUILTIN_LOCK_SCREEN, "Lock Screen", -1, true, nullptr, nullptr }, { DESKTOP_BUILTIN_LOG_OUT, "Log Out", -1, true, nullptr, nullptr }, { DESKTOP_BUILTIN_SLEEP, "Sleep", -1, true, nullptr, nullptr }, diff --git a/programs/src/desktop/main.cpp b/programs/src/desktop/main.cpp index 83fef69..c12f933 100644 --- a/programs/src/desktop/main.cpp +++ b/programs/src/desktop/main.cpp @@ -269,33 +269,33 @@ void gui::desktop_init(DesktopState* ds) { // Load SVG icons — scalable (colorful) for app menu, symbolic for toolbar/panel Color defColor = colors::ICON_COLOR; - ds->icon_terminal = svg_load("0:/icons/utilities-terminal.svg", 20, 20, defColor); - ds->icon_filemanager = svg_load("0:/icons/system-file-manager.svg", 20, 20, defColor); - ds->icon_appmenu = svg_load("0:/icons/view-app-grid-symbolic.svg", 20, 20, colors::PANEL_TEXT); - ds->icon_folder = svg_load("0:/icons/folder.svg", 16, 16, defColor); - ds->icon_file = svg_load("0:/icons/text-x-generic.svg", 16, 16, defColor); - ds->icon_network = svg_load("0:/icons/network-wired-symbolic.svg", 16, 16, colors::PANEL_TEXT); - ds->icon_wifi = svg_load("0:/icons/network-wireless-symbolic.svg", 16, 16, colors::PANEL_TEXT); - ds->icon_go_up = svg_load("0:/icons/go-up-symbolic.svg", 16, 16, defColor); - ds->icon_go_back = svg_load("0:/icons/go-previous-symbolic.svg", 16, 16, defColor); - ds->icon_go_forward = svg_load("0:/icons/go-next-symbolic.svg", 16, 16, defColor); - ds->icon_home = svg_load("0:/icons/user-home.svg", 16, 16, defColor); - ds->icon_refresh = svg_load("0:/icons/view-refresh-symbolic.svg", 16, 16, defColor); - ds->icon_exec = svg_load("0:/icons/utilities-terminal.svg", 16, 16, defColor); + ds->icon_terminal = svg_load("0:/os/icons/utilities-terminal.svg", 20, 20, defColor); + ds->icon_filemanager = svg_load("0:/os/icons/system-file-manager.svg", 20, 20, defColor); + ds->icon_appmenu = svg_load("0:/os/icons/view-app-grid-symbolic.svg", 20, 20, colors::PANEL_TEXT); + ds->icon_folder = svg_load("0:/os/icons/folder.svg", 16, 16, defColor); + ds->icon_file = svg_load("0:/os/icons/text-x-generic.svg", 16, 16, defColor); + ds->icon_network = svg_load("0:/os/icons/network-wired-symbolic.svg", 16, 16, colors::PANEL_TEXT); + ds->icon_wifi = svg_load("0:/os/icons/network-wireless-symbolic.svg", 16, 16, colors::PANEL_TEXT); + ds->icon_go_up = svg_load("0:/os/icons/go-up-symbolic.svg", 16, 16, defColor); + ds->icon_go_back = svg_load("0:/os/icons/go-previous-symbolic.svg", 16, 16, defColor); + ds->icon_go_forward = svg_load("0:/os/icons/go-next-symbolic.svg", 16, 16, defColor); + ds->icon_home = svg_load("0:/os/icons/user-home.svg", 16, 16, defColor); + ds->icon_refresh = svg_load("0:/os/icons/view-refresh-symbolic.svg", 16, 16, defColor); + ds->icon_exec = svg_load("0:/os/icons/utilities-terminal.svg", 16, 16, defColor); - ds->icon_folder_lg = svg_load("0:/icons/folder.svg", 48, 48, defColor); - ds->icon_file_lg = svg_load("0:/icons/text-x-generic.svg", 48, 48, defColor); - ds->icon_exec_lg = svg_load("0:/icons/utilities-terminal.svg", 48, 48, defColor); + ds->icon_folder_lg = svg_load("0:/os/icons/folder.svg", 48, 48, defColor); + ds->icon_file_lg = svg_load("0:/os/icons/text-x-generic.svg", 48, 48, defColor); + ds->icon_exec_lg = svg_load("0:/os/icons/utilities-terminal.svg", 48, 48, defColor); // drive icons loaded lazily by file manager to reduce startup heap pressure - ds->icon_settings = svg_load("0:/icons/preferences-desktop-apps.svg", 20, 20, defColor); - ds->icon_reboot = svg_load("0:/icons/system-reboot.svg", 20, 20, defColor); - ds->icon_shutdown = svg_load("0:/icons/system-shutdown.svg", 20, 20, defColor); - ds->icon_sleep = svg_load("0:/icons/sleep.svg", 20, 20, defColor); - ds->icon_logout = svg_load("0:/icons/gnome-logout.svg", 20, 20, defColor); + ds->icon_settings = svg_load("0:/os/icons/preferences-desktop-apps.svg", 20, 20, defColor); + ds->icon_reboot = svg_load("0:/os/icons/system-reboot.svg", 20, 20, defColor); + ds->icon_shutdown = svg_load("0:/os/icons/system-shutdown.svg", 20, 20, defColor); + ds->icon_sleep = svg_load("0:/os/icons/sleep.svg", 20, 20, defColor); + ds->icon_logout = svg_load("0:/os/icons/gnome-logout.svg", 20, 20, defColor); - ds->icon_volume = svg_load("0:/icons/audio-volume-high-symbolic.svg", 16, 16, colors::PANEL_TEXT); - ds->icon_lock = svg_load("0:/icons/lock.svg", 20, 20, defColor); + ds->icon_volume = svg_load("0:/os/icons/audio-volume-high-symbolic.svg", 16, 16, colors::PANEL_TEXT); + ds->icon_lock = svg_load("0:/os/icons/lock.svg", 20, 20, defColor); // Scan 0:/apps/ for external app manifests and build the menu desktop_scan_apps(ds); diff --git a/programs/src/dialogs/filedialog.cpp b/programs/src/dialogs/filedialog.cpp index 7e489c8..ed465a5 100644 --- a/programs/src/dialogs/filedialog.cpp +++ b/programs/src/dialogs/filedialog.cpp @@ -381,21 +381,21 @@ int special_folder_index(const char* name) { void load_file_icons(FileDialogState* st) { Color def = colors::ICON_COLOR; - st->icons.icon_go_back = svg_load("0:/icons/go-previous-symbolic.svg", 16, 16, def); - st->icons.icon_go_forward = svg_load("0:/icons/go-next-symbolic.svg", 16, 16, def); - st->icons.icon_go_up = svg_load("0:/icons/go-up-symbolic.svg", 16, 16, def); - st->icons.icon_home = svg_load("0:/icons/user-home.svg", 16, 16, def); - st->icons.icon_folder = svg_load("0:/icons/folder.svg", 16, 16, def); - st->icons.icon_folder_lg = svg_load("0:/icons/folder.svg", 48, 48, def); - st->icons.icon_file = svg_load("0:/icons/text-x-generic.svg", 16, 16, def); - st->icons.icon_file_lg = svg_load("0:/icons/text-x-generic.svg", 48, 48, def); - st->icons.icon_drive = svg_load("0:/icons/drive-harddisk.svg", 16, 16, def); - st->icons.icon_drive_lg = svg_load("0:/icons/drive-harddisk.svg", 48, 48, def); - st->icons.icon_home_folder = svg_load("0:/icons/folder-blue-home.svg", 16, 16, def); - st->icons.icon_home_folder_lg = svg_load("0:/icons/folder-blue-home.svg", 48, 48, def); + st->icons.icon_go_back = svg_load("0:/os/icons/go-previous-symbolic.svg", 16, 16, def); + st->icons.icon_go_forward = svg_load("0:/os/icons/go-next-symbolic.svg", 16, 16, def); + st->icons.icon_go_up = svg_load("0:/os/icons/go-up-symbolic.svg", 16, 16, def); + st->icons.icon_home = svg_load("0:/os/icons/user-home.svg", 16, 16, def); + st->icons.icon_folder = svg_load("0:/os/icons/folder.svg", 16, 16, def); + st->icons.icon_folder_lg = svg_load("0:/os/icons/folder.svg", 48, 48, def); + st->icons.icon_file = svg_load("0:/os/icons/text-x-generic.svg", 16, 16, def); + st->icons.icon_file_lg = svg_load("0:/os/icons/text-x-generic.svg", 48, 48, def); + st->icons.icon_drive = svg_load("0:/os/icons/drive-harddisk.svg", 16, 16, def); + st->icons.icon_drive_lg = svg_load("0:/os/icons/drive-harddisk.svg", 48, 48, def); + st->icons.icon_home_folder = svg_load("0:/os/icons/folder-blue-home.svg", 16, 16, def); + st->icons.icon_home_folder_lg = svg_load("0:/os/icons/folder-blue-home.svg", 48, 48, def); for (int i = 0; i < SPECIAL_FOLDER_COUNT; i++) { char path[128]; - snprintf(path, sizeof(path), "0:/icons/%s", SPECIAL_FOLDER_ICONS[i]); + snprintf(path, sizeof(path), "0:/os/icons/%s", SPECIAL_FOLDER_ICONS[i]); st->icons.icon_special[i] = svg_load(path, 16, 16, def); st->icons.icon_special_lg[i] = svg_load(path, 48, 48, def); } diff --git a/programs/src/dialogs/printdialog.cpp b/programs/src/dialogs/printdialog.cpp index f483011..7e7685f 100644 --- a/programs/src/dialogs/printdialog.cpp +++ b/programs/src/dialogs/printdialog.cpp @@ -279,7 +279,7 @@ void init_print_dialog(const gui::dialogs::Request& req) { PrintDialogState* st = &g_print; montauk::memset(st, 0, sizeof(*st)); Color def = colors::ICON_COLOR; - st->printer_icon = svg_load("0:/icons/printer-symbolic.svg", 24, 24, def); + st->printer_icon = svg_load("0:/os/icons/printer-symbolic.svg", 24, 24, def); safe_copy(st->source_path, sizeof(st->source_path), req.source_path); safe_copy(st->job_name, sizeof(st->job_name), req.job_name); st->submit_mode = req.mode == gui::dialogs::PRINT_DIALOG_SUBMIT; diff --git a/programs/src/fontpreview/main.cpp b/programs/src/fontpreview/main.cpp index 54bc128..8857eb1 100644 --- a/programs/src/fontpreview/main.cpp +++ b/programs/src/fontpreview/main.cpp @@ -327,7 +327,7 @@ extern "C" void _start() { if (!f->init(path)) { montauk::mfree(f); return nullptr; } return f; }; - g_ui_font = load_font("0:/fonts/Roboto-Medium.ttf"); + g_ui_font = load_font("0:/os/fonts/Roboto-Medium.ttf"); // Window title from filename char title[64] = "Font Preview"; diff --git a/programs/src/imageviewer/main.cpp b/programs/src/imageviewer/main.cpp index 5bdec59..ad6bdb8 100644 --- a/programs/src/imageviewer/main.cpp +++ b/programs/src/imageviewer/main.cpp @@ -539,7 +539,7 @@ extern "C" void _start() { TrueTypeFont* f = (TrueTypeFont*)montauk::malloc(sizeof(TrueTypeFont)); if (f) { montauk::memset(f, 0, sizeof(TrueTypeFont)); - if (!f->init("0:/fonts/Roboto-Medium.ttf")) { montauk::mfree(f); f = nullptr; } + if (!f->init("0:/os/fonts/Roboto-Medium.ttf")) { montauk::mfree(f); f = nullptr; } } g_font = f; } diff --git a/programs/src/man/main.cpp b/programs/src/man/main.cpp index d29078f..7d9b303 100644 --- a/programs/src/man/main.cpp +++ b/programs/src/man/main.cpp @@ -146,7 +146,7 @@ extern "C" void _start() { char path[128]; if (section > 0) { - const char* prefix = "0:/man/"; + const char* prefix = "0:/os/man/"; int p = 0; while (prefix[p]) { path[p] = prefix[p]; p++; } int t = 0; @@ -159,7 +159,7 @@ extern "C" void _start() { if (handle >= 0) foundSection = section; } else { for (int s = 1; s <= 9; s++) { - const char* prefix = "0:/man/"; + const char* prefix = "0:/os/man/"; int p = 0; while (prefix[p]) { path[p] = prefix[p]; p++; } int t = 0; diff --git a/programs/src/mandelbrot/main.cpp b/programs/src/mandelbrot/main.cpp index 86982a0..199d518 100644 --- a/programs/src/mandelbrot/main.cpp +++ b/programs/src/mandelbrot/main.cpp @@ -286,7 +286,7 @@ extern "C" void _start() { g_font = (TrueTypeFont*)montauk::malloc(sizeof(TrueTypeFont)); if (g_font) { montauk::memset(g_font, 0, sizeof(TrueTypeFont)); - if (!g_font->init("0:/fonts/Roboto-Medium.ttf")) { + if (!g_font->init("0:/os/fonts/Roboto-Medium.ttf")) { montauk::mfree(g_font); g_font = nullptr; } diff --git a/programs/src/music/main.cpp b/programs/src/music/main.cpp index 8be3d8f..766ff11 100644 --- a/programs/src/music/main.cpp +++ b/programs/src/music/main.cpp @@ -1562,7 +1562,7 @@ extern "C" void _start() { TrueTypeFont* f = (TrueTypeFont*)montauk::malloc(sizeof(TrueTypeFont)); if (f) { montauk::memset(f, 0, sizeof(TrueTypeFont)); - if (!f->init("0:/fonts/Roboto-Medium.ttf")) { montauk::mfree(f); f = nullptr; } + if (!f->init("0:/os/fonts/Roboto-Medium.ttf")) { montauk::mfree(f); f = nullptr; } } g.font = f; } @@ -1570,22 +1570,22 @@ extern "C" void _start() { // Load transport icons (dark + white variants for colored backgrounds) { Color ic_color = TEXT_COLOR; - g.ico_rewind = svg_load("0:/icons/media-rewind.svg", 16, 16, ic_color); - g.ico_play = svg_load("0:/icons/media-play.svg", 16, 16, ic_color); - g.ico_pause = svg_load("0:/icons/media-pause.svg", 16, 16, ic_color); - g.ico_stop = svg_load("0:/icons/media-stop.svg", 16, 16, ic_color); - g.ico_forward = svg_load("0:/icons/media-forward.svg", 16, 16, ic_color); - g.ico_play_w = svg_load("0:/icons/media-play.svg", 16, 16, WHITE); - g.ico_pause_w = svg_load("0:/icons/media-pause.svg", 16, 16, WHITE); - g.ico_stop_w = svg_load("0:/icons/media-stop.svg", 16, 16, WHITE); - g.ico_visualizer = svg_load("0:/icons/view-media-equalizer.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, ic_color); - g.ico_visualizer_w = svg_load("0:/icons/view-media-equalizer.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, WHITE); - g.ico_shuffle = svg_load("0:/icons/media-playlist-shuffle.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, ic_color); - g.ico_shuffle_w = svg_load("0:/icons/media-playlist-shuffle.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, WHITE); - g.ico_repeat_all = svg_load("0:/icons/media-playlist-repeat.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, ic_color); - g.ico_repeat_all_w = svg_load("0:/icons/media-playlist-repeat.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, WHITE); - g.ico_repeat_one = svg_load("0:/icons/media-playlist-repeat-song.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, ic_color); - g.ico_repeat_one_w = svg_load("0:/icons/media-playlist-repeat-song.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, WHITE); + g.ico_rewind = svg_load("0:/os/icons/media-rewind.svg", 16, 16, ic_color); + g.ico_play = svg_load("0:/os/icons/media-play.svg", 16, 16, ic_color); + g.ico_pause = svg_load("0:/os/icons/media-pause.svg", 16, 16, ic_color); + g.ico_stop = svg_load("0:/os/icons/media-stop.svg", 16, 16, ic_color); + g.ico_forward = svg_load("0:/os/icons/media-forward.svg", 16, 16, ic_color); + g.ico_play_w = svg_load("0:/os/icons/media-play.svg", 16, 16, WHITE); + g.ico_pause_w = svg_load("0:/os/icons/media-pause.svg", 16, 16, WHITE); + g.ico_stop_w = svg_load("0:/os/icons/media-stop.svg", 16, 16, WHITE); + g.ico_visualizer = svg_load("0:/os/icons/view-media-equalizer.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, ic_color); + g.ico_visualizer_w = svg_load("0:/os/icons/view-media-equalizer.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, WHITE); + g.ico_shuffle = svg_load("0:/os/icons/media-playlist-shuffle.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, ic_color); + g.ico_shuffle_w = svg_load("0:/os/icons/media-playlist-shuffle.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, WHITE); + g.ico_repeat_all = svg_load("0:/os/icons/media-playlist-repeat.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, ic_color); + g.ico_repeat_all_w = svg_load("0:/os/icons/media-playlist-repeat.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, WHITE); + g.ico_repeat_one = svg_load("0:/os/icons/media-playlist-repeat-song.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, ic_color); + g.ico_repeat_one_w = svg_load("0:/os/icons/media-playlist-repeat-song.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, WHITE); } // Scan for audio files diff --git a/programs/src/paint/main.cpp b/programs/src/paint/main.cpp index 6f8037c..fc8636e 100644 --- a/programs/src/paint/main.cpp +++ b/programs/src/paint/main.cpp @@ -256,7 +256,7 @@ extern "C" void _start() { g_font = (TrueTypeFont*)montauk::malloc(sizeof(TrueTypeFont)); if (g_font) { montauk::memset(g_font, 0, sizeof(TrueTypeFont)); - if (!g_font->init("0:/fonts/Roboto-Medium.ttf")) { + if (!g_font->init("0:/os/fonts/Roboto-Medium.ttf")) { montauk::mfree(g_font); g_font = nullptr; } diff --git a/programs/src/pdfviewer/main.cpp b/programs/src/pdfviewer/main.cpp index cf16b51..ae0d425 100644 --- a/programs/src/pdfviewer/main.cpp +++ b/programs/src/pdfviewer/main.cpp @@ -162,14 +162,14 @@ extern "C" void _start() { if (!f->init(path)) { montauk::mfree(f); return nullptr; } return f; }; - g_font = load_font("0:/fonts/Roboto-Medium.ttf"); - g_font_bold = load_font("0:/fonts/Roboto-Bold.ttf"); - g_font_mono = load_font("0:/fonts/JetBrainsMono-Regular.ttf"); + g_font = load_font("0:/os/fonts/Roboto-Medium.ttf"); + g_font_bold = load_font("0:/os/fonts/Roboto-Bold.ttf"); + g_font_mono = load_font("0:/os/fonts/JetBrainsMono-Regular.ttf"); // Load toolbar icons Color icon_color = HEADER_TEXT; - g_icon_folder = svg_load("0:/icons/folder.svg", 16, 16, icon_color); - g_icon_print = svg_load("0:/icons/printer-symbolic.svg", 16, 16, icon_color); + g_icon_folder = svg_load("0:/os/icons/folder.svg", 16, 16, icon_color); + g_icon_print = svg_load("0:/os/icons/printer-symbolic.svg", 16, 16, icon_color); // Check for file argument char args[512] = {}; diff --git a/programs/src/printd/test_page_jpeg.cpp b/programs/src/printd/test_page_jpeg.cpp index d5b28d3..fee9800 100644 --- a/programs/src/printd/test_page_jpeg.cpp +++ b/programs/src/printd/test_page_jpeg.cpp @@ -26,8 +26,8 @@ namespace { static constexpr int PAGE_W = 1240; static constexpr int PAGE_H = 1754; -static constexpr const char* ROBOTO_MEDIUM_PATH = "0:/fonts/Roboto-Medium.ttf"; -static constexpr const char* ROBOTO_BOLD_PATH = "0:/fonts/Roboto-Bold.ttf"; +static constexpr const char* ROBOTO_MEDIUM_PATH = "0:/os/fonts/Roboto-Medium.ttf"; +static constexpr const char* ROBOTO_BOLD_PATH = "0:/os/fonts/Roboto-Bold.ttf"; struct JpegBuffer { uint8_t* data; diff --git a/programs/src/printers/main.cpp b/programs/src/printers/main.cpp index dd97ca6..de25350 100644 --- a/programs/src/printers/main.cpp +++ b/programs/src/printers/main.cpp @@ -173,7 +173,7 @@ static void load_accent() { static void load_icons() { if (g_printer_icon.pixels) svg_free(g_printer_icon); - g_printer_icon = svg_load("0:/icons/printer-symbolic.svg", + g_printer_icon = svg_load("0:/os/icons/printer-symbolic.svg", PRINTER_ICON_SIZE, PRINTER_ICON_SIZE, Color::from_rgb(0x6A, 0x72, 0x7D)); } diff --git a/programs/src/spreadsheet/main.cpp b/programs/src/spreadsheet/main.cpp index 0889fc1..301af2e 100644 --- a/programs/src/spreadsheet/main.cpp +++ b/programs/src/spreadsheet/main.cpp @@ -18,15 +18,15 @@ SvgIcon g_icon_paste = {}; void ss_load_icons() { Color def_color = HEADER_TEXT; if (!g_icon_folder.pixels) - g_icon_folder = svg_load("0:/icons/folder.svg", 16, 16, def_color); + g_icon_folder = svg_load("0:/os/icons/folder.svg", 16, 16, def_color); if (!g_icon_save.pixels) - g_icon_save = svg_load("0:/icons/document-save-symbolic.svg", 16, 16, def_color); + g_icon_save = svg_load("0:/os/icons/document-save-symbolic.svg", 16, 16, def_color); if (!g_icon_cut.pixels) - g_icon_cut = svg_load("0:/icons/edit-cut.svg", 16, 16, def_color); + g_icon_cut = svg_load("0:/os/icons/edit-cut.svg", 16, 16, def_color); if (!g_icon_copy.pixels) - g_icon_copy = svg_load("0:/icons/edit-copy.svg", 16, 16, def_color); + g_icon_copy = svg_load("0:/os/icons/edit-copy.svg", 16, 16, def_color); if (!g_icon_paste.pixels) - g_icon_paste = svg_load("0:/icons/edit-paste.svg", 16, 16, def_color); + g_icon_paste = svg_load("0:/os/icons/edit-paste.svg", 16, 16, def_color); } void ss_unload_icons() { @@ -339,8 +339,8 @@ extern "C" void _start() { if (!f->init(path)) { montauk::mfree(f); return nullptr; } return f; }; - g_font = load_font("0:/fonts/Roboto-Medium.ttf"); - g_font_bold = load_font("0:/fonts/Roboto-Bold.ttf"); + g_font = load_font("0:/os/fonts/Roboto-Medium.ttf"); + g_font_bold = load_font("0:/os/fonts/Roboto-Bold.ttf"); ss_load_icons(); diff --git a/programs/src/texteditor/main.cpp b/programs/src/texteditor/main.cpp index 9032f43..8ccaba0 100644 --- a/programs/src/texteditor/main.cpp +++ b/programs/src/texteditor/main.cpp @@ -1438,13 +1438,13 @@ extern "C" void _start() { if (!f->init(path)) { montauk::mfree(f); return nullptr; } return f; }; - g_font = load_font("0:/fonts/Roboto-Medium.ttf"); - g_font_mono = load_font("0:/fonts/JetBrainsMono-Regular.ttf"); + g_font = load_font("0:/os/fonts/Roboto-Medium.ttf"); + g_font_mono = load_font("0:/os/fonts/JetBrainsMono-Regular.ttf"); // Load toolbar icons Color icon_color = Color::from_rgb(0x44, 0x44, 0x44); - g_icon_folder = svg_load("0:/icons/folder.svg", 16, 16, icon_color); - g_icon_save = svg_load("0:/icons/document-save-symbolic.svg", 16, 16, icon_color); + g_icon_folder = svg_load("0:/os/icons/folder.svg", 16, 16, icon_color); + g_icon_save = svg_load("0:/os/icons/document-save-symbolic.svg", 16, 16, icon_color); // Check for file argument char args[512] = {}; diff --git a/programs/src/video/main.cpp b/programs/src/video/main.cpp index c28ad73..38f492e 100644 --- a/programs/src/video/main.cpp +++ b/programs/src/video/main.cpp @@ -1311,7 +1311,7 @@ extern "C" void _start() { TrueTypeFont* font = (TrueTypeFont*)montauk::malloc(sizeof(TrueTypeFont)); if (font) { montauk::memset(font, 0, sizeof(TrueTypeFont)); - if (!font->init("0:/fonts/Roboto-Medium.ttf")) { + if (!font->init("0:/os/fonts/Roboto-Medium.ttf")) { montauk::mfree(font); font = nullptr; } @@ -1319,16 +1319,16 @@ extern "C" void _start() { g.font = font; Color icon_fg = TEXT; - g.ico_rewind = svg_load("0:/icons/media-rewind.svg", 16, 16, icon_fg); - g.ico_play = svg_load("0:/icons/media-play.svg", 16, 16, icon_fg); - g.ico_pause = svg_load("0:/icons/media-pause.svg", 16, 16, icon_fg); - g.ico_stop = svg_load("0:/icons/media-stop.svg", 16, 16, icon_fg); - g.ico_forward = svg_load("0:/icons/media-forward.svg", 16, 16, icon_fg); - g.ico_play_w = svg_load("0:/icons/media-play.svg", 16, 16, WHITE); - g.ico_pause_w = svg_load("0:/icons/media-pause.svg", 16, 16, WHITE); - g.ico_stop_w = svg_load("0:/icons/media-stop.svg", 16, 16, WHITE); - g.ico_repeat = svg_load("0:/icons/media-playlist-repeat.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, icon_fg); - g.ico_repeat_w = svg_load("0:/icons/media-playlist-repeat.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, WHITE); + g.ico_rewind = svg_load("0:/os/icons/media-rewind.svg", 16, 16, icon_fg); + g.ico_play = svg_load("0:/os/icons/media-play.svg", 16, 16, icon_fg); + g.ico_pause = svg_load("0:/os/icons/media-pause.svg", 16, 16, icon_fg); + g.ico_stop = svg_load("0:/os/icons/media-stop.svg", 16, 16, icon_fg); + g.ico_forward = svg_load("0:/os/icons/media-forward.svg", 16, 16, icon_fg); + g.ico_play_w = svg_load("0:/os/icons/media-play.svg", 16, 16, WHITE); + g.ico_pause_w = svg_load("0:/os/icons/media-pause.svg", 16, 16, WHITE); + g.ico_stop_w = svg_load("0:/os/icons/media-stop.svg", 16, 16, WHITE); + g.ico_repeat = svg_load("0:/os/icons/media-playlist-repeat.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, icon_fg); + g.ico_repeat_w = svg_load("0:/os/icons/media-playlist-repeat.svg", TOOL_ICON_SIZE, TOOL_ICON_SIZE, WHITE); scan_directory(); diff --git a/programs/src/weather/main.cpp b/programs/src/weather/main.cpp index 7f71fe9..5cf1327 100644 --- a/programs/src/weather/main.cpp +++ b/programs/src/weather/main.cpp @@ -172,7 +172,7 @@ static void load_weather_icon(const char* icon_name) { if (g_icon.pixels) svg_free(g_icon); static char path[80]; - snprintf(path, sizeof(path), "0:/icons/%s", icon_name); + snprintf(path, sizeof(path), "0:/os/icons/%s", icon_name); // ColorScheme-Text paths (main shape) use this fill_color; accent classes // (ColorScheme-Highlight=blue, ColorScheme-NeutralText=yellow, etc.) use their // CSS-defined colors as parsed from the SVG's