feat: move fonts/icons/man to 0:/os, add capabilities GUI app
This commit is contained in:
1 parent
80b5beb17d
commit
75e85f24ef
35 files changed
+1035
-177
No files matched your search
@@ -12,4 +12,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MONTAUK_BUILD_NUMBER 223
|
||||
#define MONTAUK_BUILD_NUMBER 236
|
||||
+14
-11
@@ -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/<name>/.
|
||||
@@ -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/<name>/.
|
||||
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."
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -0,0 +1,744 @@
|
||||
/*
|
||||
* main.cpp
|
||||
* MontaukOS capability grant viewer
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include <montauk/syscall.h>
|
||||
#include <montauk/string.h>
|
||||
#include <montauk/config.h>
|
||||
#include <montauk/capabilities.h>
|
||||
#include <gui/mtk.hpp>
|
||||
#include <gui/mtk/settings.hpp>
|
||||
#include <gui/standalone.hpp>
|
||||
|
||||
extern "C" {
|
||||
#include <stdio.h>
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* stb_truetype_impl.cpp
|
||||
* Single compilation unit for stb_truetype in MontaukOS freestanding environment
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <montauk/heap.h>
|
||||
#include <montauk/string.h>
|
||||
#include <gui/stb_math.h>
|
||||
|
||||
#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 <gui/stb_truetype.h>
|
||||
@@ -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) {
|
||||
|
||||
@@ -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" : "");
|
||||
}
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
#include <montauk/user.h>
|
||||
|
||||
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 },
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+17
-17
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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] = {};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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] = {};
|
||||
|
||||
+11
-11
@@ -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();
|
||||
|
||||
|
||||
@@ -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 <style> block by svg_load.
|
||||
@@ -379,8 +379,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");
|
||||
if (!g_font) montauk::exit(1);
|
||||
|
||||
apply_scale(montauk::win_getscale());
|
||||
|
||||
@@ -20,16 +20,16 @@ static bool init_buffers_and_fonts() {
|
||||
g_extract_buf = (char*)malloc(RESP_MAX + 1);
|
||||
if (!g_lines || !g_resp_buf || !g_extract_buf) return false;
|
||||
|
||||
g_body_fonts[(int)ReaderFontFace::SANS] = load_font("0:/fonts/Roboto-Regular.ttf");
|
||||
g_body_fonts[(int)ReaderFontFace::SANS] = load_font("0:/os/fonts/Roboto-Regular.ttf");
|
||||
if (!g_body_fonts[(int)ReaderFontFace::SANS])
|
||||
g_body_fonts[(int)ReaderFontFace::SANS] = load_font("0:/fonts/Roboto-Medium.ttf");
|
||||
g_heading_fonts[(int)ReaderFontFace::SANS] = load_font("0:/fonts/Roboto-Bold.ttf");
|
||||
g_body_fonts[(int)ReaderFontFace::SANS] = load_font("0:/os/fonts/Roboto-Medium.ttf");
|
||||
g_heading_fonts[(int)ReaderFontFace::SANS] = load_font("0:/os/fonts/Roboto-Bold.ttf");
|
||||
|
||||
g_body_fonts[(int)ReaderFontFace::SERIF] = load_font("0:/fonts/NotoSerif-Regular.ttf");
|
||||
g_heading_fonts[(int)ReaderFontFace::SERIF] = load_font("0:/fonts/NotoSerif-SemiBold.ttf");
|
||||
g_body_fonts[(int)ReaderFontFace::SERIF] = load_font("0:/os/fonts/NotoSerif-Regular.ttf");
|
||||
g_heading_fonts[(int)ReaderFontFace::SERIF] = load_font("0:/os/fonts/NotoSerif-SemiBold.ttf");
|
||||
|
||||
g_body_fonts[(int)ReaderFontFace::BOOK] = load_font("0:/fonts/C059-Roman.ttf");
|
||||
g_heading_fonts[(int)ReaderFontFace::BOOK] = load_font("0:/fonts/C059-Bold.ttf");
|
||||
g_body_fonts[(int)ReaderFontFace::BOOK] = load_font("0:/os/fonts/C059-Roman.ttf");
|
||||
g_heading_fonts[(int)ReaderFontFace::BOOK] = load_font("0:/os/fonts/C059-Bold.ttf");
|
||||
|
||||
if (!g_body_fonts[(int)ReaderFontFace::SANS]) return false;
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ static constexpr int RESP_MAX = 131072;
|
||||
static constexpr int MAX_LINES = 2000;
|
||||
|
||||
inline const char WIKI_HOST[] = "en.wikipedia.org";
|
||||
inline const char DISPLAY_ICON_PATH[] = "0:/icons/cog.svg";
|
||||
inline const char DISPLAY_ICON_PATH[] = "0:/os/icons/cog.svg";
|
||||
|
||||
// ============================================================================
|
||||
// Types
|
||||
|
||||
@@ -446,7 +446,7 @@ static int wp_split_at(WordProcessorState* wp, int abs_pos) {
|
||||
// ============================================================================
|
||||
// Font discovery
|
||||
//
|
||||
// Fonts live in 0:/fonts as "<Family>-<Style>.ttf" (e.g. Roboto-BoldItalic.ttf).
|
||||
// Fonts live in 0:/os/fonts as "<Family>-<Style>.ttf" (e.g. Roboto-BoldItalic.ttf).
|
||||
// We scan that directory at startup, group files by family, and slot each file
|
||||
// into one of four style variants. Families are sorted deterministically so a
|
||||
// given set of installed fonts yields stable font ids across runs. Documents
|
||||
@@ -560,7 +560,7 @@ static void wp_register_font_file(const char* filename) {
|
||||
WpFontFamily* fam = &g_wp_fonts.families[fi];
|
||||
if (fam->paths[variant][0]) return; // first file wins for this slot
|
||||
|
||||
montauk::strncpy(fam->paths[variant], "0:/fonts/", WP_FONT_PATH_MAX);
|
||||
montauk::strncpy(fam->paths[variant], "0:/os/fonts/", WP_FONT_PATH_MAX);
|
||||
int plen = montauk::slen(fam->paths[variant]);
|
||||
montauk::strncpy(fam->paths[variant] + plen, filename, WP_FONT_PATH_MAX - plen);
|
||||
montauk::strncpy(fam->basenames[variant], stem, WP_FONT_BASENAME_MAX);
|
||||
@@ -601,7 +601,7 @@ void wp_load_fonts() {
|
||||
g_wp_fonts.count = 0;
|
||||
|
||||
const char* names[256];
|
||||
int count = montauk::readdir("0:/fonts", names, 256);
|
||||
int count = montauk::readdir("0:/os/fonts", names, 256);
|
||||
|
||||
// Sort entries so per-slot conflicts resolve deterministically. With
|
||||
// first-wins below, "Roboto-Medium" sorts before "Roboto-Regular" and
|
||||
@@ -653,7 +653,7 @@ void wp_load_fonts() {
|
||||
}
|
||||
}
|
||||
|
||||
// Defensive fallback: if 0:/fonts yielded nothing usable, expose the
|
||||
// Defensive fallback: if 0:/os/fonts yielded nothing usable, expose the
|
||||
// shared system font so the editor still renders.
|
||||
if (g_wp_fonts.count == 0 && fonts::system_font) {
|
||||
WpFontFamily* fam = &g_wp_fonts.families[0];
|
||||
|
||||
@@ -31,36 +31,36 @@ TrueTypeFont* g_ui_bold = nullptr;
|
||||
void wp_load_icons() {
|
||||
Color def_color = colors::ICON_COLOR;
|
||||
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_print.pixels)
|
||||
g_icon_print = svg_load("0:/icons/printer-symbolic.svg", 16, 16, def_color);
|
||||
g_icon_print = svg_load("0:/os/icons/printer-symbolic.svg", 16, 16, def_color);
|
||||
if (!g_icon_export_pdf.pixels) {
|
||||
g_icon_export_pdf = svg_load("0:/icons/document-export-symbolic.svg", 16, 16, def_color);
|
||||
g_icon_export_pdf = svg_load("0:/os/icons/document-export-symbolic.svg", 16, 16, def_color);
|
||||
if (!g_icon_export_pdf.pixels)
|
||||
g_icon_export_pdf = svg_load("0:/icons/text-x-generic-symbolic.svg", 16, 16, def_color);
|
||||
g_icon_export_pdf = svg_load("0:/os/icons/text-x-generic-symbolic.svg", 16, 16, def_color);
|
||||
}
|
||||
if (!g_icon_undo.pixels)
|
||||
g_icon_undo = svg_load("0:/icons/edit-undo-symbolic.svg", 16, 16, def_color);
|
||||
g_icon_undo = svg_load("0:/os/icons/edit-undo-symbolic.svg", 16, 16, def_color);
|
||||
if (!g_icon_redo.pixels)
|
||||
g_icon_redo = svg_load("0:/icons/edit-redo-symbolic.svg", 16, 16, def_color);
|
||||
g_icon_redo = svg_load("0:/os/icons/edit-redo-symbolic.svg", 16, 16, def_color);
|
||||
if (!g_icon_align_left.pixels)
|
||||
g_icon_align_left = svg_load("0:/icons/format-justify-left-symbolic.svg", 16, 16, def_color);
|
||||
g_icon_align_left = svg_load("0:/os/icons/format-justify-left-symbolic.svg", 16, 16, def_color);
|
||||
if (!g_icon_align_center.pixels)
|
||||
g_icon_align_center = svg_load("0:/icons/format-justify-center-symbolic.svg", 16, 16, def_color);
|
||||
g_icon_align_center = svg_load("0:/os/icons/format-justify-center-symbolic.svg", 16, 16, def_color);
|
||||
if (!g_icon_align_right.pixels)
|
||||
g_icon_align_right = svg_load("0:/icons/format-justify-right-symbolic.svg", 16, 16, def_color);
|
||||
g_icon_align_right = svg_load("0:/os/icons/format-justify-right-symbolic.svg", 16, 16, def_color);
|
||||
if (!g_icon_list_bullet.pixels)
|
||||
g_icon_list_bullet = svg_load("0:/icons/view-list-bullet-symbolic.svg", 16, 16, def_color);
|
||||
g_icon_list_bullet = svg_load("0:/os/icons/view-list-bullet-symbolic.svg", 16, 16, def_color);
|
||||
if (!g_icon_list_number.pixels)
|
||||
g_icon_list_number = svg_load("0:/icons/view-list-ordered-symbolic.svg", 16, 16, def_color);
|
||||
g_icon_list_number = svg_load("0:/os/icons/view-list-ordered-symbolic.svg", 16, 16, def_color);
|
||||
if (!g_icon_indent_less.pixels)
|
||||
g_icon_indent_less = svg_load("0:/icons/format-indent-less-symbolic.svg", 16, 16, def_color);
|
||||
g_icon_indent_less = svg_load("0:/os/icons/format-indent-less-symbolic.svg", 16, 16, def_color);
|
||||
if (!g_icon_indent_more.pixels)
|
||||
g_icon_indent_more = svg_load("0:/icons/format-indent-more-symbolic.svg", 16, 16, def_color);
|
||||
g_icon_indent_more = svg_load("0:/os/icons/format-indent-more-symbolic.svg", 16, 16, def_color);
|
||||
if (!g_icon_page_view.pixels)
|
||||
g_icon_page_view = svg_load("0:/icons/view-paged-symbolic.svg", 16, 16, def_color);
|
||||
g_icon_page_view = svg_load("0:/os/icons/view-paged-symbolic.svg", 16, 16, def_color);
|
||||
}
|
||||
|
||||
void wp_cleanup_state() {
|
||||
|
||||
@@ -82,12 +82,12 @@ static constexpr int WP_DIVIDER_FLYOUT_W = 216;
|
||||
static constexpr int WP_SPECIAL_CHAR_ROW_H = 24;
|
||||
static constexpr int WP_SPECIAL_CHAR_FLYOUT_W = 144;
|
||||
|
||||
// Fonts are discovered at runtime by scanning 0:/fonts (see wp_load_fonts).
|
||||
// Fonts are discovered at runtime by scanning 0:/os/fonts (see wp_load_fonts).
|
||||
// A font id is an index into the discovered family table (g_wp_fonts). The
|
||||
// table is bounded by WP_MAX_FONTS; ids beyond the table fall back to default.
|
||||
static constexpr int WP_MAX_FONTS = 24; // max discovered families
|
||||
static constexpr int WP_FONT_NAME_MAX = 32; // family/display name
|
||||
static constexpr int WP_FONT_PATH_MAX = 96; // "0:/fonts/<file>.ttf"
|
||||
static constexpr int WP_FONT_PATH_MAX = 96; // "0:/os/fonts/<file>.ttf"
|
||||
static constexpr int WP_FONT_BASENAME_MAX = 48; // filename stem (PDF base font)
|
||||
|
||||
static constexpr uint8_t STYLE_BOLD = 0x01;
|
||||
|
||||
@@ -8,7 +8,7 @@ set -e
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
FONT_DST="$PROJECT_ROOT/programs/bin/fonts"
|
||||
FONT_DST="$PROJECT_ROOT/programs/bin/os/fonts"
|
||||
|
||||
mkdir -p "$FONT_DST"
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
ICON_SRC="$PROJECT_ROOT/programs/gui/icons/Flat-Remix-Blue-Light-darkPanel"
|
||||
ICON_DST="$PROJECT_ROOT/programs/bin/icons"
|
||||
ICON_DST="$PROJECT_ROOT/programs/bin/os/icons"
|
||||
|
||||
mkdir -p "$ICON_DST"
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ APPS=(
|
||||
"bluetooth|apps/scalable/bluetooth.svg"
|
||||
"network|devices/scalable/network-wired.svg"
|
||||
"display|apps/scalable/preferences-desktop-display.svg"
|
||||
"capabilities|apps/scalable/stock_lock.svg"
|
||||
"keyboard|categories/scalable/preferences-keyboard.svg"
|
||||
"sshserver|apps/scalable/utilities-terminal.svg"
|
||||
"terminal|apps/scalable/utilities-terminal.svg"
|
||||
|
||||
Reference in new issue
Block a user