feat: allow applets to be shared modules
This commit is contained in:
+18
-4
@@ -78,12 +78,17 @@ WWWDST := $(patsubst $(WWWDIR)/%,$(BINDIR)/www/%,$(WWWSRC))
|
|||||||
# CA certificate bundle.
|
# CA certificate bundle.
|
||||||
CA_CERTS := $(BINDIR)/etc/ca-certificates.crt
|
CA_CERTS := $(BINDIR)/etc/ca-certificates.crt
|
||||||
|
|
||||||
|
# System config TOML files bundled into bin/config/.
|
||||||
|
CONFIGDIR := data/config
|
||||||
|
CONFIGSRC := $(wildcard $(CONFIGDIR)/*.toml)
|
||||||
|
CONFIGDST := $(patsubst $(CONFIGDIR)/%,$(BINDIR)/config/%,$(CONFIGSRC))
|
||||||
|
|
||||||
# Common shared assets (wallpapers, etc.)
|
# Common shared assets (wallpapers, etc.)
|
||||||
COMMONKEEP := $(BINDIR)/common/.keep
|
COMMONKEEP := $(BINDIR)/common/.keep
|
||||||
|
|
||||||
.PHONY: all clean doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator login desktop shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs icons fonts bearssl libc tls libjpeg libjpegwrite install-apps libloader libs libhello test_dialogs test_dl crashpad
|
.PHONY: all clean doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator login desktop shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs icons fonts configs bearssl libc tls libjpeg libjpegwrite install-apps libloader libs libhello test_dialogs test_dl crashpad
|
||||||
|
|
||||||
all: bearssl libc libjpeg libjpegwrite tls libloader libs libhello $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator doom rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs login desktop shell icons fonts install-apps test_dialogs test_dl crashpad $(MANDST) $(WWWDST) $(CA_CERTS) $(COMMONKEEP)
|
all: bearssl libc libjpeg libjpegwrite tls libloader libs libhello $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator doom rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs login desktop shell icons fonts install-apps test_dialogs test_dl crashpad $(MANDST) $(WWWDST) $(CA_CERTS) $(CONFIGDST) $(COMMONKEEP)
|
||||||
|
|
||||||
# Build BearSSL static library (cross-compiled for freestanding x86_64).
|
# 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)
|
BEARSSL_INCLUDES := -isystem $(shell cd .. && pwd)/kernel/freestnd-c-hdrs/x86_64/include -isystem $(abspath include/libc)
|
||||||
@@ -111,6 +116,7 @@ libloader: libc
|
|||||||
# Build shared libraries (libmath.lib etc).
|
# Build shared libraries (libmath.lib etc).
|
||||||
libs: libloader
|
libs: libloader
|
||||||
$(MAKE) -C libs/libmath
|
$(MAKE) -C libs/libmath
|
||||||
|
$(MAKE) -C libs/libprintersapplet
|
||||||
|
|
||||||
# Build libhello shared GUI library.
|
# Build libhello shared GUI library.
|
||||||
libhello: libloader
|
libhello: libloader
|
||||||
@@ -216,8 +222,8 @@ login: bearssl libc
|
|||||||
shell:
|
shell:
|
||||||
$(MAKE) -C src/shell
|
$(MAKE) -C src/shell
|
||||||
|
|
||||||
# Build desktop via its own Makefile (depends on libc, libjpeg, bearssl for user.h, and dialogs for duplicate-session warnings).
|
# Build desktop via its own Makefile (depends on libc, libjpeg, bearssl for user.h, dialogs, and registry config files).
|
||||||
desktop: libc libjpeg bearssl libloader dialogs
|
desktop: libc libjpeg bearssl libloader dialogs configs
|
||||||
$(MAKE) -C src/desktop
|
$(MAKE) -C src/desktop
|
||||||
|
|
||||||
# Copy SVG icons for the desktop into bin/icons/.
|
# Copy SVG icons for the desktop into bin/icons/.
|
||||||
@@ -228,6 +234,9 @@ icons:
|
|||||||
fonts:
|
fonts:
|
||||||
../scripts/copy_fonts.sh
|
../scripts/copy_fonts.sh
|
||||||
|
|
||||||
|
# Copy default system config files into bin/config/.
|
||||||
|
configs: $(CONFIGDST)
|
||||||
|
|
||||||
# Build paint standalone GUI tool (depends on libc).
|
# Build paint standalone GUI tool (depends on libc).
|
||||||
paint: libc
|
paint: libc
|
||||||
$(MAKE) -C src/paint
|
$(MAKE) -C src/paint
|
||||||
@@ -308,6 +317,11 @@ $(CA_CERTS): data/ca-certificates.crt
|
|||||||
mkdir -p $(BINDIR)/etc
|
mkdir -p $(BINDIR)/etc
|
||||||
cp $< $@
|
cp $< $@
|
||||||
|
|
||||||
|
# Copy system config files into bin/config/.
|
||||||
|
$(BINDIR)/config/%: $(CONFIGDIR)/%
|
||||||
|
mkdir -p $(BINDIR)/config
|
||||||
|
cp $< $@
|
||||||
|
|
||||||
# Ensure common assets directory exists.
|
# Ensure common assets directory exists.
|
||||||
$(COMMONKEEP):
|
$(COMMONKEEP):
|
||||||
mkdir -p $(BINDIR)/common
|
mkdir -p $(BINDIR)/common
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[applets.printers]
|
||||||
|
label = "Printers"
|
||||||
|
library = "0:/os/libprintersapplet.lib"
|
||||||
|
icon = "0:/icons/printer.svg"
|
||||||
|
enabled = true
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* desktop_applet.hpp
|
||||||
|
* Shared-library desktop applet ABI for MontaukOS
|
||||||
|
* Copyright (c) 2026 Daniel Hammer
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace gui::desktop_applet {
|
||||||
|
|
||||||
|
inline constexpr uint32_t ABI_VERSION = 1;
|
||||||
|
inline constexpr uint32_t CAP_SYSTEM_CONFIGURATION = 1u << 0;
|
||||||
|
|
||||||
|
struct Host {
|
||||||
|
char current_user[32];
|
||||||
|
char home_dir[128];
|
||||||
|
char user_config_dir[128];
|
||||||
|
bool is_admin;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Descriptor {
|
||||||
|
uint32_t abi_version;
|
||||||
|
uint32_t capabilities;
|
||||||
|
const char* applet_id;
|
||||||
|
const char* display_name;
|
||||||
|
const char* icon_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
using QueryFn = const Descriptor* (*)();
|
||||||
|
using OpenFn = bool (*)(const Host* host);
|
||||||
|
|
||||||
|
inline constexpr const char* QUERY_SYMBOL = "desktop_applet_query_v1";
|
||||||
|
inline constexpr const char* OPEN_SYMBOL = "desktop_applet_open_v1";
|
||||||
|
|
||||||
|
} // namespace gui::desktop_applet
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# Makefile for the Printers shared desktop applet
|
||||||
|
# Copyright (c) 2026 Daniel Hammer
|
||||||
|
|
||||||
|
MAKEFLAGS += -rR
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-elf-
|
||||||
|
ifneq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),)
|
||||||
|
CXX := $(TOOLCHAIN_PREFIX)g++
|
||||||
|
LD := $(TOOLCHAIN_PREFIX)ld
|
||||||
|
else
|
||||||
|
CXX := g++
|
||||||
|
LD := ld
|
||||||
|
endif
|
||||||
|
|
||||||
|
OUTDIR := ../../bin/os
|
||||||
|
OBJDIR := obj
|
||||||
|
TARGET := $(OUTDIR)/libprintersapplet.lib
|
||||||
|
|
||||||
|
CXXFLAGS := \
|
||||||
|
-std=gnu++20 \
|
||||||
|
-g -O2 -pipe \
|
||||||
|
-Wall \
|
||||||
|
-Wextra \
|
||||||
|
-nostdinc \
|
||||||
|
-ffreestanding \
|
||||||
|
-fno-stack-protector \
|
||||||
|
-fno-stack-check \
|
||||||
|
-fPIC \
|
||||||
|
-fno-rtti \
|
||||||
|
-fno-exceptions \
|
||||||
|
-ffunction-sections \
|
||||||
|
-fdata-sections \
|
||||||
|
-m64 \
|
||||||
|
-march=x86-64 \
|
||||||
|
-mno-red-zone \
|
||||||
|
-mcmodel=small \
|
||||||
|
-MMD -MP \
|
||||||
|
-I ../../include \
|
||||||
|
-isystem ../../include/libc \
|
||||||
|
-isystem ../../../kernel/freestnd-c-hdrs/x86_64/include \
|
||||||
|
-isystem ../../../kernel/freestnd-cxx-hdrs/x86_64/include
|
||||||
|
|
||||||
|
LDFLAGS := \
|
||||||
|
-shared \
|
||||||
|
--build-id=none \
|
||||||
|
--hash-style=sysv \
|
||||||
|
-m elf_x86_64 \
|
||||||
|
-z max-page-size=0x1000
|
||||||
|
|
||||||
|
SRCS := src/libprintersapplet.cpp
|
||||||
|
OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o))
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS) Makefile
|
||||||
|
mkdir -p $(OUTDIR)
|
||||||
|
$(LD) $(LDFLAGS) $(OBJS) -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o: %.cpp Makefile
|
||||||
|
mkdir -p $(dir $@)
|
||||||
|
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
-include $(OBJS:.o=.d)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(OBJDIR) $(TARGET)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
obj/src/libprintersapplet.o: src/libprintersapplet.cpp \
|
||||||
|
../../include/gui/desktop_applet.hpp ../../include/montauk/syscall.h \
|
||||||
|
../../include/Api/Syscall.hpp
|
||||||
|
../../include/gui/desktop_applet.hpp:
|
||||||
|
../../include/montauk/syscall.h:
|
||||||
|
../../include/Api/Syscall.hpp:
|
||||||
Binary file not shown.
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* libprintersapplet.cpp
|
||||||
|
* Shared desktop applet that launches the Printers configuration tool
|
||||||
|
* Copyright (c) 2026 Daniel Hammer
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gui/desktop_applet.hpp>
|
||||||
|
#include <montauk/syscall.h>
|
||||||
|
|
||||||
|
using gui::desktop_applet::Descriptor;
|
||||||
|
using gui::desktop_applet::Host;
|
||||||
|
|
||||||
|
static constexpr Descriptor kAppletDescriptor = {
|
||||||
|
gui::desktop_applet::ABI_VERSION,
|
||||||
|
gui::desktop_applet::CAP_SYSTEM_CONFIGURATION,
|
||||||
|
"printers",
|
||||||
|
"Printers",
|
||||||
|
"0:/icons/printer.svg",
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" const Descriptor* desktop_applet_query_v1() {
|
||||||
|
return &kAppletDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool desktop_applet_open_v1(const Host* host) {
|
||||||
|
(void)host;
|
||||||
|
return montauk::spawn("0:/apps/printers/printers.elf") >= 0;
|
||||||
|
}
|
||||||
@@ -68,7 +68,7 @@ LDFLAGS := \
|
|||||||
|
|
||||||
# ---- C++ source files ----
|
# ---- C++ source files ----
|
||||||
|
|
||||||
CORE_SRCS := main.cpp window.cpp panel.cpp compose.cpp input.cpp dialogs.cpp launcher.cpp desktop_builtin.cpp font_data.cpp stb_truetype_impl.cpp
|
CORE_SRCS := main.cpp window.cpp panel.cpp compose.cpp input.cpp dialogs.cpp launcher.cpp desktop_builtin.cpp shared_applets.cpp font_data.cpp stb_truetype_impl.cpp
|
||||||
APP_SRCS := $(sort $(shell find apps -name '*.cpp' -print))
|
APP_SRCS := $(sort $(shell find apps -name '*.cpp' -print))
|
||||||
SRCS := $(CORE_SRCS) $(APP_SRCS)
|
SRCS := $(CORE_SRCS) $(APP_SRCS)
|
||||||
OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o))
|
OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o))
|
||||||
|
|||||||
@@ -190,6 +190,18 @@ SvgIcon* desktop_builtin_menu_icon(DesktopState* ds, DesktopBuiltinId id);
|
|||||||
void desktop_launch_builtin(DesktopState* ds, DesktopBuiltinId id);
|
void desktop_launch_builtin(DesktopState* ds, DesktopBuiltinId id);
|
||||||
void desktop_lock_screen(DesktopState* ds);
|
void desktop_lock_screen(DesktopState* ds);
|
||||||
|
|
||||||
|
struct DesktopSharedAppletEntry {
|
||||||
|
char id[48];
|
||||||
|
char label[64];
|
||||||
|
char icon_path[128];
|
||||||
|
char library_path[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
int desktop_list_system_configuration_applets(DesktopState* ds,
|
||||||
|
DesktopSharedAppletEntry* out,
|
||||||
|
int max_entries);
|
||||||
|
bool desktop_launch_shared_applet(DesktopState* ds, const char* lib_path);
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Forward declarations for desktop launch entry points
|
// Forward declarations for desktop launch entry points
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@@ -30,14 +30,23 @@ enum FileManagerVirtualViewKind : uint8_t {
|
|||||||
FM_VIRTUAL_VIEW_SYSTEM_TOOLS,
|
FM_VIRTUAL_VIEW_SYSTEM_TOOLS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum FileManagerVirtualEntryKind : uint8_t {
|
||||||
|
FM_VIRTUAL_ENTRY_NONE = 0,
|
||||||
|
FM_VIRTUAL_ENTRY_EXTERNAL_APP,
|
||||||
|
FM_VIRTUAL_ENTRY_BUILTIN,
|
||||||
|
FM_VIRTUAL_ENTRY_SHARED_APPLET,
|
||||||
|
};
|
||||||
|
|
||||||
struct FileManagerLocation {
|
struct FileManagerLocation {
|
||||||
char path[256];
|
char path[256];
|
||||||
FileManagerVirtualViewKind virtual_view;
|
FileManagerVirtualViewKind virtual_view;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FileManagerVirtualEntry {
|
struct FileManagerVirtualEntry {
|
||||||
|
FileManagerVirtualEntryKind kind;
|
||||||
int external_app_index;
|
int external_app_index;
|
||||||
DesktopBuiltinId builtin_id;
|
DesktopBuiltinId builtin_id;
|
||||||
|
char shared_applet_path[128];
|
||||||
SvgIcon icon_lg;
|
SvgIcon icon_lg;
|
||||||
SvgIcon icon_sm;
|
SvgIcon icon_sm;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,8 +27,10 @@ static void filemanager_reset_list_state(FileManagerState* fm) {
|
|||||||
|
|
||||||
static void filemanager_reset_virtual_entry(FileManagerVirtualEntry* entry) {
|
static void filemanager_reset_virtual_entry(FileManagerVirtualEntry* entry) {
|
||||||
if (!entry) return;
|
if (!entry) return;
|
||||||
|
entry->kind = FM_VIRTUAL_ENTRY_NONE;
|
||||||
entry->external_app_index = -1;
|
entry->external_app_index = -1;
|
||||||
entry->builtin_id = DESKTOP_BUILTIN_NONE;
|
entry->builtin_id = DESKTOP_BUILTIN_NONE;
|
||||||
|
entry->shared_applet_path[0] = '\0';
|
||||||
entry->icon_lg = {};
|
entry->icon_lg = {};
|
||||||
entry->icon_sm = {};
|
entry->icon_sm = {};
|
||||||
}
|
}
|
||||||
@@ -50,8 +52,10 @@ static void filemanager_add_root_entry(FileManagerState* fm,
|
|||||||
static void filemanager_add_virtual_entry(FileManagerState* fm,
|
static void filemanager_add_virtual_entry(FileManagerState* fm,
|
||||||
const char* name,
|
const char* name,
|
||||||
const char* icon_path,
|
const char* icon_path,
|
||||||
|
FileManagerVirtualEntryKind kind,
|
||||||
int external_index,
|
int external_index,
|
||||||
DesktopBuiltinId builtin_id) {
|
DesktopBuiltinId builtin_id,
|
||||||
|
const char* shared_applet_path) {
|
||||||
if (!fm || fm->entry_count >= 64) return;
|
if (!fm || fm->entry_count >= 64) return;
|
||||||
|
|
||||||
int idx = fm->entry_count;
|
int idx = fm->entry_count;
|
||||||
@@ -61,8 +65,14 @@ static void filemanager_add_virtual_entry(FileManagerState* fm,
|
|||||||
fm->is_dir[idx] = false;
|
fm->is_dir[idx] = false;
|
||||||
fm->drive_indices[idx] = -1;
|
fm->drive_indices[idx] = -1;
|
||||||
filemanager_reset_virtual_entry(&fm->virtual_entries[idx]);
|
filemanager_reset_virtual_entry(&fm->virtual_entries[idx]);
|
||||||
|
fm->virtual_entries[idx].kind = kind;
|
||||||
fm->virtual_entries[idx].external_app_index = external_index;
|
fm->virtual_entries[idx].external_app_index = external_index;
|
||||||
fm->virtual_entries[idx].builtin_id = builtin_id;
|
fm->virtual_entries[idx].builtin_id = builtin_id;
|
||||||
|
if (shared_applet_path && shared_applet_path[0]) {
|
||||||
|
montauk::strncpy(fm->virtual_entries[idx].shared_applet_path,
|
||||||
|
shared_applet_path,
|
||||||
|
sizeof(fm->virtual_entries[idx].shared_applet_path));
|
||||||
|
}
|
||||||
|
|
||||||
if (icon_path && icon_path[0]) {
|
if (icon_path && icon_path[0]) {
|
||||||
Color defColor = colors::ICON_COLOR;
|
Color defColor = colors::ICON_COLOR;
|
||||||
@@ -344,8 +354,9 @@ void filemanager_read_apps(FileManagerState* fm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filemanager_add_virtual_entry(fm, name, icon_path,
|
filemanager_add_virtual_entry(fm, name, icon_path,
|
||||||
|
FM_VIRTUAL_ENTRY_EXTERNAL_APP,
|
||||||
filemanager_find_external_app(ds, bin_path),
|
filemanager_find_external_app(ds, bin_path),
|
||||||
DESKTOP_BUILTIN_NONE);
|
DESKTOP_BUILTIN_NONE, nullptr);
|
||||||
|
|
||||||
doc.destroy();
|
doc.destroy();
|
||||||
}
|
}
|
||||||
@@ -361,7 +372,17 @@ void filemanager_read_system_tools(FileManagerState* fm) {
|
|||||||
for (int i = 0; i < builtin_count; i++) {
|
for (int i = 0; i < builtin_count; i++) {
|
||||||
if (!builtins[i].system_tools_applet) continue;
|
if (!builtins[i].system_tools_applet) continue;
|
||||||
filemanager_add_virtual_entry(fm, builtins[i].label, builtins[i].icon_path,
|
filemanager_add_virtual_entry(fm, builtins[i].label, builtins[i].icon_path,
|
||||||
-1, builtins[i].id);
|
FM_VIRTUAL_ENTRY_BUILTIN,
|
||||||
|
-1, builtins[i].id, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
DesktopSharedAppletEntry applets[32];
|
||||||
|
int applet_count = desktop_list_system_configuration_applets(fm->desktop, applets, 32);
|
||||||
|
for (int i = 0; i < applet_count && fm->entry_count < 64; i++) {
|
||||||
|
filemanager_add_virtual_entry(fm, applets[i].label, applets[i].icon_path,
|
||||||
|
FM_VIRTUAL_ENTRY_SHARED_APPLET,
|
||||||
|
-1, DESKTOP_BUILTIN_NONE,
|
||||||
|
applets[i].library_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
filemanager_reset_list_state(fm);
|
filemanager_reset_list_state(fm);
|
||||||
|
|||||||
@@ -197,17 +197,23 @@ void filemanager_open_entry(FileManagerState* fm, int idx) {
|
|||||||
if (filemanager_is_virtual_view(fm) && fm->entry_types[idx] == FM_ENTRY_VIRTUAL_APP) {
|
if (filemanager_is_virtual_view(fm) && fm->entry_types[idx] == FM_ENTRY_VIRTUAL_APP) {
|
||||||
DesktopState* ds = fm->desktop;
|
DesktopState* ds = fm->desktop;
|
||||||
const FileManagerVirtualEntry& entry = fm->virtual_entries[idx];
|
const FileManagerVirtualEntry& entry = fm->virtual_entries[idx];
|
||||||
if (ds && entry.builtin_id != DESKTOP_BUILTIN_NONE) {
|
if (ds && entry.kind == FM_VIRTUAL_ENTRY_BUILTIN
|
||||||
|
&& entry.builtin_id != DESKTOP_BUILTIN_NONE) {
|
||||||
desktop_launch_builtin(ds, entry.builtin_id);
|
desktop_launch_builtin(ds, entry.builtin_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ds && entry.external_app_index >= 0 && entry.external_app_index < ds->external_app_count) {
|
if (ds && entry.kind == FM_VIRTUAL_ENTRY_EXTERNAL_APP
|
||||||
|
&& entry.external_app_index >= 0
|
||||||
|
&& entry.external_app_index < ds->external_app_count) {
|
||||||
const ExternalApp& app = ds->external_apps[entry.external_app_index];
|
const ExternalApp& app = ds->external_apps[entry.external_app_index];
|
||||||
if (app.launch_with_home) {
|
if (app.launch_with_home) {
|
||||||
montauk::spawn(app.binary_path, ds->home_dir);
|
montauk::spawn(app.binary_path, ds->home_dir);
|
||||||
} else {
|
} else {
|
||||||
montauk::spawn(app.binary_path);
|
montauk::spawn(app.binary_path);
|
||||||
}
|
}
|
||||||
|
} else if (ds && entry.kind == FM_VIRTUAL_ENTRY_SHARED_APPLET
|
||||||
|
&& entry.shared_applet_path[0] != '\0') {
|
||||||
|
desktop_launch_shared_applet(ds, entry.shared_applet_path);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* shared_applets.cpp
|
||||||
|
* Shared-library desktop applet discovery and launch helpers
|
||||||
|
* Copyright (c) 2026 Daniel Hammer
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "desktop_internal.hpp"
|
||||||
|
#include <gui/desktop_applet.hpp>
|
||||||
|
#include <libloader/libloader.h>
|
||||||
|
#include <montauk/config.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using gui::desktop_applet::Descriptor;
|
||||||
|
using gui::desktop_applet::OpenFn;
|
||||||
|
using gui::desktop_applet::QueryFn;
|
||||||
|
|
||||||
|
static constexpr const char* DEFAULT_APPLET_ICON = "0:/icons/preferences-system.svg";
|
||||||
|
static constexpr const char* APPLET_CONFIG_NAME = "desktop-applets";
|
||||||
|
static constexpr const char* APPLET_TABLE_PREFIX = "applets.";
|
||||||
|
|
||||||
|
static bool str_ends_with(const char* s, const char* suffix) {
|
||||||
|
if (!s || !suffix) return false;
|
||||||
|
int slen = montauk::slen(s);
|
||||||
|
int tlen = montauk::slen(suffix);
|
||||||
|
if (tlen > slen) return false;
|
||||||
|
for (int i = 0; i < tlen; i++) {
|
||||||
|
if (s[slen - tlen + i] != suffix[i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* applet_field_string(const montauk::toml::Doc& doc,
|
||||||
|
const char* applet_key,
|
||||||
|
const char* field,
|
||||||
|
const char* def = "") {
|
||||||
|
char key[256];
|
||||||
|
snprintf(key, sizeof(key), "%s.%s", applet_key, field);
|
||||||
|
return doc.get_string(key, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool applet_field_bool(const montauk::toml::Doc& doc,
|
||||||
|
const char* applet_key,
|
||||||
|
const char* field,
|
||||||
|
bool def = false) {
|
||||||
|
char key[256];
|
||||||
|
snprintf(key, sizeof(key), "%s.%s", applet_key, field);
|
||||||
|
return doc.get_bool(key, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* applet_id_from_table_key(const char* table_key) {
|
||||||
|
if (!table_key || !montauk::starts_with(table_key, APPLET_TABLE_PREFIX)) return nullptr;
|
||||||
|
const char* applet_id = table_key + montauk::slen(APPLET_TABLE_PREFIX);
|
||||||
|
return applet_id[0] ? applet_id : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool resolve_shared_applet(LibHandle* lib,
|
||||||
|
const Descriptor** out_desc,
|
||||||
|
OpenFn* out_open) {
|
||||||
|
if (out_desc) *out_desc = nullptr;
|
||||||
|
if (out_open) *out_open = nullptr;
|
||||||
|
if (!lib) return false;
|
||||||
|
|
||||||
|
QueryFn query = (QueryFn)libloader::dlsym(lib, gui::desktop_applet::QUERY_SYMBOL);
|
||||||
|
OpenFn open = (OpenFn)libloader::dlsym(lib, gui::desktop_applet::OPEN_SYMBOL);
|
||||||
|
if (!query || !open) return false;
|
||||||
|
|
||||||
|
const Descriptor* desc = query();
|
||||||
|
if (!desc || desc->abi_version != gui::desktop_applet::ABI_VERSION) return false;
|
||||||
|
if (!desc->applet_id || !desc->applet_id[0]) return false;
|
||||||
|
if (!desc->display_name || !desc->display_name[0]) return false;
|
||||||
|
|
||||||
|
if (out_desc) *out_desc = desc;
|
||||||
|
if (out_open) *out_open = open;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sort_shared_applets(DesktopSharedAppletEntry* entries, int count) {
|
||||||
|
if (!entries || count <= 1) return;
|
||||||
|
|
||||||
|
for (int i = 1; i < count; i++) {
|
||||||
|
DesktopSharedAppletEntry tmp = entries[i];
|
||||||
|
int j = i - 1;
|
||||||
|
while (j >= 0 && str_compare_ci(tmp.label, entries[j].label) < 0) {
|
||||||
|
entries[j + 1] = entries[j];
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
entries[j + 1] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int desktop_list_system_configuration_applets(DesktopState* ds,
|
||||||
|
DesktopSharedAppletEntry* out,
|
||||||
|
int max_entries) {
|
||||||
|
(void)ds;
|
||||||
|
if (!out || max_entries <= 0) return 0;
|
||||||
|
|
||||||
|
auto doc = montauk::config::load(APPLET_CONFIG_NAME);
|
||||||
|
int written = 0;
|
||||||
|
for (int i = 0; i < doc.entries.count && written < max_entries; i++) {
|
||||||
|
montauk::toml::Value* item = doc.entries.items[i];
|
||||||
|
if (!item || item->type != montauk::toml::Type::Table || !item->key) continue;
|
||||||
|
|
||||||
|
const char* applet_id = applet_id_from_table_key(item->key);
|
||||||
|
if (!applet_id) continue;
|
||||||
|
if (!applet_field_bool(doc, item->key, "enabled", true)) continue;
|
||||||
|
|
||||||
|
const char* library = applet_field_string(doc, item->key, "library");
|
||||||
|
if (!library[0] || !str_ends_with(library, ".lib")) continue;
|
||||||
|
|
||||||
|
const char* label = applet_field_string(doc, item->key, "label", applet_id);
|
||||||
|
const char* icon = applet_field_string(doc, item->key, "icon", DEFAULT_APPLET_ICON);
|
||||||
|
|
||||||
|
montauk::memset(&out[written], 0, sizeof(out[written]));
|
||||||
|
montauk::strncpy(out[written].id, applet_id, sizeof(out[written].id));
|
||||||
|
montauk::strncpy(out[written].label, label[0] ? label : library, sizeof(out[written].label));
|
||||||
|
montauk::strncpy(out[written].icon_path,
|
||||||
|
icon[0] ? icon : DEFAULT_APPLET_ICON,
|
||||||
|
sizeof(out[written].icon_path));
|
||||||
|
montauk::strncpy(out[written].library_path, library, sizeof(out[written].library_path));
|
||||||
|
written++;
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.destroy();
|
||||||
|
sort_shared_applets(out, written);
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool desktop_launch_shared_applet(DesktopState* ds, const char* lib_path) {
|
||||||
|
if (!ds || !lib_path || !lib_path[0]) return false;
|
||||||
|
|
||||||
|
LibHandle* lib = libloader::dlopen(lib_path);
|
||||||
|
if (!lib) return false;
|
||||||
|
|
||||||
|
const Descriptor* desc = nullptr;
|
||||||
|
OpenFn open = nullptr;
|
||||||
|
bool ok = resolve_shared_applet(lib, &desc, &open);
|
||||||
|
if (ok) {
|
||||||
|
gui::desktop_applet::Host host = {};
|
||||||
|
montauk::strncpy(host.current_user, ds->current_user, sizeof(host.current_user));
|
||||||
|
montauk::strncpy(host.home_dir, ds->home_dir, sizeof(host.home_dir));
|
||||||
|
montauk::strncpy(host.user_config_dir, ds->user_config_dir, sizeof(host.user_config_dir));
|
||||||
|
host.is_admin = ds->is_admin;
|
||||||
|
ok = open(&host);
|
||||||
|
}
|
||||||
|
|
||||||
|
libloader::dlclose(lib);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* desktop_applet.hpp
|
||||||
|
* Shared-library desktop applet ABI for MontaukOS
|
||||||
|
* Copyright (c) 2026 Daniel Hammer
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace gui::desktop_applet {
|
||||||
|
|
||||||
|
inline constexpr uint32_t ABI_VERSION = 1;
|
||||||
|
inline constexpr uint32_t CAP_SYSTEM_CONFIGURATION = 1u << 0;
|
||||||
|
|
||||||
|
struct Host {
|
||||||
|
char current_user[32];
|
||||||
|
char home_dir[128];
|
||||||
|
char user_config_dir[128];
|
||||||
|
bool is_admin;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Descriptor {
|
||||||
|
uint32_t abi_version;
|
||||||
|
uint32_t capabilities;
|
||||||
|
const char* applet_id;
|
||||||
|
const char* display_name;
|
||||||
|
const char* icon_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
using QueryFn = const Descriptor* (*)();
|
||||||
|
using OpenFn = bool (*)(const Host* host);
|
||||||
|
|
||||||
|
inline constexpr const char* QUERY_SYMBOL = "desktop_applet_query_v1";
|
||||||
|
inline constexpr const char* OPEN_SYMBOL = "desktop_applet_open_v1";
|
||||||
|
|
||||||
|
} // namespace gui::desktop_applet
|
||||||
Reference in New Issue
Block a user