From 75ae7ede5618bbb8cec050a95e420e00993cbf1b Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Wed, 29 Jul 2026 13:59:46 +0100 Subject: [PATCH] refactor: unify desktop apps and Settings under item catalog --- kernel/src/Api/BuildNo.hpp | 2 +- programs/GNUmakefile | 15 +- programs/data/config/config-applets.toml | 17 -- programs/include/gui/desktop.hpp | 29 ++- programs/include/gui/desktop_applet.hpp | 37 --- programs/libs/libnetworkapplet/Makefile | 69 ------ .../libnetworkapplet/src/libnetworkapplet.cpp | 28 --- programs/libs/libprintersapplet/Makefile | 69 ------ .../obj/src/libprintersapplet.d | 6 - .../obj/src/libprintersapplet.o | Bin 19896 -> 0 bytes .../src/libprintersapplet.cpp | 28 --- programs/libs/libtimezonesapplet/Makefile | 69 ------ .../obj/src/libtimezonesapplet.d | 6 - .../obj/src/libtimezonesapplet.o | Bin 20040 -> 0 bytes .../src/libtimezonesapplet.cpp | 28 --- programs/src/desktop/Makefile | 2 +- programs/src/desktop/apps/apps_common.hpp | 25 +- .../src/desktop/apps/filemanager/actions.cpp | 2 +- programs/src/desktop/apps/filemanager/app.cpp | 14 +- .../apps/filemanager/filemanager_internal.hpp | 12 +- .../desktop/apps/filemanager/filesystem.cpp | 61 ++--- .../desktop/apps/filemanager/navigation.cpp | 16 +- .../desktop/apps/filemanager/properties.cpp | 36 +-- .../src/desktop/apps/filemanager/render.cpp | 8 +- programs/src/desktop/desktop_applets.cpp | 222 ------------------ programs/src/desktop/desktop_builtin.cpp | 2 +- programs/src/desktop/desktop_catalog.cpp | 63 +++++ programs/src/desktop/launcher.cpp | 26 +- programs/src/desktop/main.cpp | 117 ++++++--- programs/src/installer/components.cpp | 3 +- programs/src/network/main.cpp | 2 +- programs/src/network/manifest.toml | 5 + programs/src/printers/manifest.toml | 5 + programs/src/timezone/main.cpp | 2 +- programs/src/timezone/manifest.toml | 5 + template/docs/gui-apps.md | 22 +- template/sysroot/include/gui/desktop.hpp | 29 ++- .../sysroot/include/gui/desktop_applet.hpp | 37 --- 38 files changed, 322 insertions(+), 797 deletions(-) delete mode 100644 programs/data/config/config-applets.toml delete mode 100644 programs/include/gui/desktop_applet.hpp delete mode 100644 programs/libs/libnetworkapplet/Makefile delete mode 100644 programs/libs/libnetworkapplet/src/libnetworkapplet.cpp delete mode 100644 programs/libs/libprintersapplet/Makefile delete mode 100644 programs/libs/libprintersapplet/obj/src/libprintersapplet.d delete mode 100644 programs/libs/libprintersapplet/obj/src/libprintersapplet.o delete mode 100644 programs/libs/libprintersapplet/src/libprintersapplet.cpp delete mode 100644 programs/libs/libtimezonesapplet/Makefile delete mode 100644 programs/libs/libtimezonesapplet/obj/src/libtimezonesapplet.d delete mode 100644 programs/libs/libtimezonesapplet/obj/src/libtimezonesapplet.o delete mode 100644 programs/libs/libtimezonesapplet/src/libtimezonesapplet.cpp delete mode 100644 programs/src/desktop/desktop_applets.cpp create mode 100644 programs/src/desktop/desktop_catalog.cpp delete mode 100644 template/sysroot/include/gui/desktop_applet.hpp diff --git a/kernel/src/Api/BuildNo.hpp b/kernel/src/Api/BuildNo.hpp index 43b7931..4adff58 100644 --- a/kernel/src/Api/BuildNo.hpp +++ b/kernel/src/Api/BuildNo.hpp @@ -12,4 +12,4 @@ #pragma once -#define MONTAUK_BUILD_NUMBER 6 +#define MONTAUK_BUILD_NUMBER 7 diff --git a/programs/GNUmakefile b/programs/GNUmakefile index 2f9994d..85215d6 100644 --- a/programs/GNUmakefile +++ b/programs/GNUmakefile @@ -89,9 +89,9 @@ WPDIR := data/wallpapers WPSRC := $(wildcard $(WPDIR)/*.jpg) WPDST := $(patsubst $(WPDIR)/%,$(BINDIR)/os/wallpapers/%,$(WPSRC)) -.PHONY: all clean 2048 doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network terminal klog procmgr powermgr calculator charmap login desktop shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs icons fonts configs bearssl libc tls libjpeg libjpegwrite install-apps libloader libs crashpad check-syscalls gen-syscalls +.PHONY: all clean 2048 doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network terminal klog procmgr powermgr calculator charmap login desktop shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs icons fonts configs bearssl libc tls libjpeg libjpegwrite install-apps libloader crashpad check-syscalls gen-syscalls -all: bearssl libc libjpeg libjpegwrite tls libloader libs devkit $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network terminal klog procmgr powermgr calculator charmap 2048 doom rpgdemo paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs login desktop shell icons fonts install-apps crashpad $(MANDST) $(WWWDST) $(CA_CERTS) $(CONFIGDST) $(FWDST) $(LICDST) $(WPDST) +all: bearssl libc libjpeg libjpegwrite tls libloader devkit $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network terminal klog procmgr powermgr calculator charmap 2048 doom rpgdemo paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs login desktop shell icons fonts install-apps crashpad $(MANDST) $(WWWDST) $(CA_CERTS) $(CONFIGDST) $(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) @@ -112,16 +112,10 @@ libc: tls: bearssl libc $(MAKE) -C lib/tls -# Build libloader static library (used by the applet shared libs). +# Build the shared-library loader used by runtime GUI components. libloader: libc $(MAKE) -C src/libloader -# Build shared libraries (applet .lib files). -libs: libloader - $(MAKE) -C libs/libnetworkapplet - $(MAKE) -C libs/libprintersapplet - $(MAKE) -C libs/libtimezonesapplet - # Build fetch via its own Makefile (depends on bearssl, libc, and tls). fetch: bearssl libc tls $(MAKE) -C src/fetch @@ -487,6 +481,3 @@ clean: $(MAKE) -C src/dialogs clean $(MAKE) -C src/crashpad clean $(MAKE) -C src/libloader clean - $(MAKE) -C libs/libnetworkapplet clean - $(MAKE) -C libs/libprintersapplet clean - $(MAKE) -C libs/libtimezonesapplet clean diff --git a/programs/data/config/config-applets.toml b/programs/data/config/config-applets.toml deleted file mode 100644 index 4829531..0000000 --- a/programs/data/config/config-applets.toml +++ /dev/null @@ -1,17 +0,0 @@ -[applets.printers] -label = "Printers" -library = "0:/os/printersapplet.lib" -icon = "0:/icons/printer.svg" -enabled = true - -[applets.network] -label = "Network" -library = "0:/os/networkapplet.lib" -icon = "0:/icons/network-wired.svg" -enabled = true - -[applets.timezone] -label = "Time Zone" -library = "0:/os/timezonesapplet.lib" -icon = "0:/icons/preferences-system-time.svg" -enabled = true diff --git a/programs/include/gui/desktop.hpp b/programs/include/gui/desktop.hpp index a473983..abc3534 100644 --- a/programs/include/gui/desktop.hpp +++ b/programs/include/gui/desktop.hpp @@ -18,15 +18,32 @@ namespace gui { static constexpr int MAX_WINDOWS = 32; static constexpr int PANEL_HEIGHT = 32; -// External app discovered from 0:/apps/ manifest -struct ExternalApp { +enum DesktopItemSection : uint8_t { + DESKTOP_ITEM_SECTION_HIDDEN = 0, + DESKTOP_ITEM_SECTION_APPS, + DESKTOP_ITEM_SECTION_SETTINGS, +}; + +enum DesktopItemLaunchKind : uint8_t { + DESKTOP_ITEM_LAUNCH_EXECUTABLE = 0, + DESKTOP_ITEM_LAUNCH_BUILTIN, +}; + +// Launchable desktop item discovered from an app manifest or supplied by the +// desktop's built-in registry. +struct DesktopItem { + char id[48]; char name[48]; char binary_path[128]; char icon_path[128]; char category[24]; SvgIcon icon; + DesktopItemSection section; + DesktopItemLaunchKind launch_kind; + int builtin_id; bool menu_visible; bool launch_with_home; + bool admin_only; }; enum LauncherItemKind : uint8_t { @@ -150,10 +167,10 @@ struct DesktopState { SvgIcon icon_volume; - // External apps discovered from 0:/apps/ manifests (dynamically grown) - ExternalApp* external_apps; - int external_app_count; - int external_app_capacity; + // Desktop items discovered from 0:/apps/ manifests (dynamically grown). + DesktopItem* desktop_items; + int desktop_item_count; + int desktop_item_capacity; bool ctx_menu_open; int ctx_menu_x, ctx_menu_y; diff --git a/programs/include/gui/desktop_applet.hpp b/programs/include/gui/desktop_applet.hpp deleted file mode 100644 index a82b549..0000000 --- a/programs/include/gui/desktop_applet.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * desktop_applet.hpp - * Shared-library desktop applet ABI for MontaukOS - * Copyright (c) 2026 Daniel Hammer -*/ - -#pragma once - -#include - -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 diff --git a/programs/libs/libnetworkapplet/Makefile b/programs/libs/libnetworkapplet/Makefile deleted file mode 100644 index 890670c..0000000 --- a/programs/libs/libnetworkapplet/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -# Makefile for the Network shared desktop applet -# Copyright (c) 2026 Daniel Hammer - -MAKEFLAGS += -rR -.SUFFIXES: - -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- -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)/networkapplet.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/libnetworkapplet.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) diff --git a/programs/libs/libnetworkapplet/src/libnetworkapplet.cpp b/programs/libs/libnetworkapplet/src/libnetworkapplet.cpp deleted file mode 100644 index e0ff8de..0000000 --- a/programs/libs/libnetworkapplet/src/libnetworkapplet.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * libnetworkapplet.cpp - * Shared desktop applet that launches the Network configuration tool - * Copyright (c) 2026 Daniel Hammer -*/ - -#include -#include - -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, - "network", - "Network", - "0:/icons/network-wired.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/network/network.elf") >= 0; -} diff --git a/programs/libs/libprintersapplet/Makefile b/programs/libs/libprintersapplet/Makefile deleted file mode 100644 index 1bdf255..0000000 --- a/programs/libs/libprintersapplet/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -# 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-montauk- -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)/printersapplet.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) diff --git a/programs/libs/libprintersapplet/obj/src/libprintersapplet.d b/programs/libs/libprintersapplet/obj/src/libprintersapplet.d deleted file mode 100644 index 78abc7d..0000000 --- a/programs/libs/libprintersapplet/obj/src/libprintersapplet.d +++ /dev/null @@ -1,6 +0,0 @@ -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: diff --git a/programs/libs/libprintersapplet/obj/src/libprintersapplet.o b/programs/libs/libprintersapplet/obj/src/libprintersapplet.o deleted file mode 100644 index 467993623e5a1420684ab303112007c9adfe9a8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19896 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 u&;N5OF8qI&;w7ou^J9$OyNEIu%f{Em6<=}Vb` -#include - -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; -} diff --git a/programs/libs/libtimezonesapplet/Makefile b/programs/libs/libtimezonesapplet/Makefile deleted file mode 100644 index 975e003..0000000 --- a/programs/libs/libtimezonesapplet/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -# Makefile for the Time Zone shared desktop applet -# Copyright (c) 2026 Daniel Hammer - -MAKEFLAGS += -rR -.SUFFIXES: - -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- -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)/timezonesapplet.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/libtimezonesapplet.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) diff --git a/programs/libs/libtimezonesapplet/obj/src/libtimezonesapplet.d b/programs/libs/libtimezonesapplet/obj/src/libtimezonesapplet.d deleted file mode 100644 index 779da65..0000000 --- a/programs/libs/libtimezonesapplet/obj/src/libtimezonesapplet.d +++ /dev/null @@ -1,6 +0,0 @@ -obj/src/libtimezonesapplet.o: src/libtimezonesapplet.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: diff --git a/programs/libs/libtimezonesapplet/obj/src/libtimezonesapplet.o b/programs/libs/libtimezonesapplet/obj/src/libtimezonesapplet.o deleted file mode 100644 index 26a0e26bafac196315286b38041188024b51cf09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20040 zcmb_k33wdEmG0I^vh2aKZ26K;$zWqlBw5B7AJ}*_GqMJcG{YRW32Z_ZzJ+iF_PxJe&9t7S&0hVX z*MI%}>eZ`Pud1ti+8hi=TS{Elv4`tya*8F(I!H01hvpl?L_YcmP79(pm53OD^O*?P@F=35W_GJ5ExX=Q);!G{B9 zKKh5nXFX=^I4Lq%yOS)M`qWNu*Wkc#<4``=lgsA@x^lzy!~2Iva{cvOr(t;SE~9BA z_hr2PSe;o_j#K8i6^3@T(T3Vz}sreMsS20}ydg`vxUZ>O_rC!V?mSEK!KG(UW zRTXa%K#S9-u!6xertBtM3%(loj=5Z;bmo+Oe8F|f@26r7bG4;&D#AoUd2S`UV{i>{ zDfoHQ50Z-M+I-+D@C$(FI_2+jHK+1S(&E2q+=s=~YecM^DO}^$aqS>oE8!|rx`>)r zTUGXXmj=RdzDPxYyWOdbD@^GgciLC^N|g<;ud0;Q=d&pLitD?SuPzuK>2}IjyZ+x$ z$zQS2{|KEOB-kXs|39WU&eUvYuQO@pR|ul{%EgD-0`N3o<5m@L3Ha&2KHwR^rNGs| zWxz9m%YkPBPXe9|Tmd`>crx%@;3>d0z<%I)z{dd32c8PN0Jsu(A@DTdMZi_Si-D&D z*8&t4ZyX)jlgxlD}k2)Hvu0DybAa@;FExt0QPEslaCdZw5{P2Y{2n z&A=((5O5m!0^l9M8-Y83Hv#ViJ`MQ8z+vFCfrG$V;1=Lc;4Q#iz^%aDz!Bga@ae!k zz*~WL0Y`z)0geOj0X_q`4>$qb51a%Z0!{&+3!Dbd18)N!2Hp-l0=xtGJm3!C1He0h zKLY$=;0u7y1U?9S7Vw3@X9HgZoB_TV`0s!(0qz986u1lcGT?6D%Yk#iR{-|_e-wBZ z@FC#cz*hqI0$&Au4)E2$dw{P2?gPFSxF7gB-~r(4fd_$a03HIq5%^r-n}GAchk=KI zZw4L#{sizS@TY+H0)HC#Jm6b__W|DqydU^>-~+&S0DlDdPT;=>J_39`@MnMz0^bFE zA@Dx{Uj%#)@WsGi0KNqHUf@fC?*qOJ_)EZ-1Ahhh3gE8-e-!v3;6uO<178XJ2=Gq0|(PL806fTofjmLJ0~Ny6A_w@-460 z_Q{VV}hN&mYouW)knvAe>rUJ|4T-5aCI@nJfz055G;iF89!#&VujJF5ehk zzSFn?7JNT+c~Nt7EO;urJbzqHV3)JTy_3bgEFNU>IE!akJkR1~7H_a{eI%x`s9~{` zMH7pSEFvt@EV3;6S?p(V8H*cO+{)tfEbeFVD2wm2_!)~AS-i&LuPk^N+*vH@Sk$vv z$0E$)3>Igx=w&g=;vyE;u=pg4&$9Rui-%b}#p1^-e$C=fEZ$~OMq6NaI*WxYPGE5| zivWu@79A{dEY4+dK8r&vZenpKi+fo-$l`Gp&#-u&#mg+-V8Od+cPfh-7E4()vDnBW z!XnKg%c7sfeioOpxPis3EI!ZTeio0i_&$rDv3QZiYb^fCVlq8+xU*Q)v8ZRUjzyTo z87$6X(aU0##YHTxVev^8pJnkS77w#{ip7sv{F=p|SiH@mjGnpN=`0qqIDy54MGcFkESgwsVzHIQ4i-5U zc@_s*T+QN>Ebb!Vcc(1i$0@(-U%*dkb@WG87xF{eWJ+*zEa8(|Go7EP?6F*c`{{vc zj&m%R+?v&l?J@nZrvO{-{CO3(d&r8rJ%#BHcnXw>wCL<#Sn&-HS@EQ|@QkN$9IG#V z&ciS+@uy1{di#tDb}=_%aN8T^FCtyeRGb(1#u*ZCvWr`9a+_tA5+?>NWr-{kjI(%s4`lzA1(rlMM@skYWnkMzr& z2-%xdh7&zYH&vI+`D!yg%1@pRU7yjVAWd`pbrr1auW;7;nVw69W6J2^cYR&ShPvaq zC3=`$=Mv%HP)74K(~kjd|6s-%p+qLrxAX$s8J)x}|5*5DK!C|aPzq}F)ckWrLrH_~4jz3H$At-|Igbr!kl(nZTl zKjWrvr#B`Al|@qu3&B{vWaaHnnMbcAG`8%mH%5=@$xARa?Z%x`3DDh}jzY8JlpJR{ z*rP>;DBCN{JyxOnW~p0V>aQ%Fw#d9@`fsvkPLi^jt6XcjGntkGZlae;uIs*AIh9Ym zKF}Y5#bZ6^O6n+a7ne+DYPf8@S7k1%RF{^NRr#K$yWZsLvYEd74l<}NCDn4@kV_XQ`>JZW=o{K$N;^#H zRJm6EZ{;pAr*TWZJ=9dA!5hlljkKS2-DF2Hvpv!tOoZvps>7vVYbcU%x^`#tC#}ki z2o;HjBC*W&L`0Ofgj1=VxE4s$m0&cMG_{*k$#5zV3MFuHYc#e6Aem0I1cKp=v@<#| z+`DTa*ImmmL%Gowj|1dRJP}TY+f$}$G#rj++LF$e_H=FV#1mJotZiD|u&QBYZGHd1 zV0}KG=tF}J2s&gv{^wKM5D))>IbTO_UCKJMSXGgMyGCCTHB)1kLY$Mhdh&$);XwX<7)|p@` znxXh-+5*W`IFV^f+ks02lC7CUI37!w$Tg>evG(?GFy*Nj52R_Nx^u&OMh1s6^zOYc zH+1ms+wg)1qcqHT`Ly1g0kO;J8C?Cj3CK+gpLxUO*?+6FufmAEXaI5Hf zFdB(B#{!8^hEgFzs^0dQiltNWbjpdugPCMxOM4(nP6t9Au*I!L+FN2Mv;`v3=GYFp z9NgygXZK~YeUvs7i0xh$3Hs6&fgVgi6h+mRN$qXzZjYDs7&{ zhjNH|V_J{J!|l+bMI)Wc@L-}Ck8P*EQBTs;ZHGp0&1$=t71k=wHPr7K&C^dpBbm|R zTpqQl=>%m&tj#z;dK5dERc66UMLm;>)a`8C7K^6aOk&Xr7D|~!ZfS0zN#PViLluJC zLlocsT&BC%w27hT&eO%MVKW;DrXscE{X zG+`$eyNE8fBs0m5_8>6Nn1W`~1mCkf)0)$U++$xU+o`c&I+2W-dq&e54l}hy1K1Ww zWrFFom^^DG`pI;XM$9xyl|wW-iJ0kZJVEyno>hASSe8P$;jVn|5Usg(Oi~dEZHrlL ziWAD-N4CWI<^%nXNH}T`N84tdao9{x?f`d`CP^lca_C2%%-&pnm=HX~_6iFnbvx27nctkE0kjK0+iB)m<>>^+uCV%H_Om+BVERwk1u1Ihmd9r^pg@^6*ghyn%3hYge)<Br%-4NhnM+Gi@=A$2uVEg2xYXIFQ(4!fM+mS253bV)7Q& zP9CdZEKO-CJBQwG6Bb^DXfE;X#xo#m?bHbO_xIb7(M_y5z`I4VW%d`G8@L)u$L)=n z!b`(qrvh&W&AM)JotMI6HiyXznn}o9dnZQuy@;;%N%uwR8zo=KZ$MSO5lAyby zT`OpBXO;>YNR!Q6sU;MS(iRa0+QMz@f=pVPgbv?iGqh3Y>D^Vh_i-*HQ?W7oE?#RL zc}zeb%`_|Y+fEq@BaI8sbkhiI+4Y3o;r31csFmWA3guKR$|+PBX5QdN!JTCJ#Gd&j>6pJsVzGbbc8i1^qw1dD4OgrgO482t#F%tD_Vso`*so=V&1`mt^Id#R(G6WgL(cz?b*G`Bk^bu)=;|Bo&NbStrC~|#$>j%f zeU0WJY@oZotA2NPez=hy=Q3+n+iJ=Pf9Eo>fqnbNGtt=DJ2I^71cv_ScAN>KH32Ql zVZ&~R9y%$1>vwf^QDN-USi^1#H(l?}_0YAh6HhdAg>cerG@#IBG#qD3Fu1;UIXxSn zAdkiT;=z2AL}&Lv!g2Rix$}>iRB=7M-rzTv3s`{;`8E>EOH%sMJGqC1$6c~g;!Y~mifZ# z9L3{R%ovUfK8N1+j&t}t?Rqc!oT=Vo0s9=!8|MPc_VFIr!x-o*M1SlhpZO4LEJ-Dw zgU_tS;qj@}7`_puqvNxh_!*u!+rf&0FUF0>8pi|~n%Nm`I_2p7cSAI|Ql)9}rNP+r zE!;`bjD6wAufEu)_dYPk3|uv@3OS0Fw|;Xzd3$LiZFxK5Hge1tds)nF&H!%~*b!!q z-oiWg&>tVxALet)(;*XaByh8DNrF^yG>$oFy+-6P% z|68Qp`xO7Qyc2yu@jasdEyeS%r+oatoC@~&H&Q-+VNL};Fa7$1;{PIv_MYOaq+NbT z%!eHpza-Zz#or;w-s}%on8Ly8k{w(2- zD1MXh|D^bbC4U}Ld|u-A4aMIr{rauqmq@?fQG7-whxtaL80VizyEDX|jlaz&^DSUe ze~tLFLh0Wu@mZtzbHtx!#eZG+cEw*V@i*UQ72ADY#OB@Eye`WL^D<;?I*j{Egyo7JuyeXX9Z0(SqZ= zqx3J7@hX>bu=-z;_}KBW{2#^tMM}R-^j9c;gXphO{39}6&5FN5^xGAGtN6K7@plQ| zqj>&?jgP$I&y;pAP<&AMD-}OY{5h=nE95?UMDgF0`F@|`zbkegQvA1N9PR$X#`!BU z?$0Xy`Qqmbir;9u>%5})%@T(<72hD`67kEn`0SD*lU--vf%DBYqxG{0)*nmn+`p&5erZX9hlQQ~V+6 z*WHSLU*h?I;ulEyn~MLT#O-Ot-!A=nPVtvWd|p!g>oUHtEB=$>&-;r1j`%-C;$-vT zd@0XX{1-%jiQ;b;e;O1|UlQT4_epEN%g|1X(!WXaEur}B5{I)D|FGCUNAX8wUD~Vo zy`q1y;`d0uu2uZE#h+UgZ~lFWLozeVv=g#Vo4*GT@~ulSdx{B^}YDt3OP_@Ly&&lR7L@)6m1aFOB1 zC2#*xc<#QKCgeC@Q~Ga>k@cf&TdLEB<&xJ2Mp@5Pq)WPZPdQc#e;^zbicY?8_3-U*qA~pEHDCulSho zLB(f<-=cW_oR*Kc;`bZcNh$t3;X6D$`?*&5P7lw19umGs@mB~x;^BEH-sFJLaZq?J z$`T3w4yE5O!MjKCZIX1aDE_lz|24&bSJsEO6d#p*{y_2ecZG6EJe&W0vOZ5${1-VG zbj(!zGP&_Q;#lkOd+W%uG&|fzJAM^0uyz21q-hM3+p2wF{;A|-`Q~aG$ zUZMEUO1VMt|19NIiho7QYZPyPhgh%pRU8mHHklLR%zlQ1Z&m!L@NJ5}T6mi$w!fbd z-uwFz+qd_%GnF0tdq7t4-xoVQivNl5dlb+As|7xW%&E|?SB3ZHp?4f_6@6Coj$^Ix ztn1aczppXp)pr_(_xF!vJLx=}RIKZ)?v$>y^IyXdPkFP9(Kb+lq%Fa2*;#5lQXA=4R@ zy9ViN6#CNNSjz3r^w4K0IT^D5(~1929-Iqy9kRwYTcFO8UIn&}5OcDu7x>KuG#2Rk zyg%Su(f_u76V+v#6Z!AmTaj8}AHrdn{jWO7=d+|2GrXv-T{{>m|2u z*C~QHTIFolc_~7dv5f=I)A9Vb^IF`n)sOO@e{UYo|IOq0&s$aP|IO0A_Wu*oBK^~? zF^Bcrp6{ZojCK7lO0A`1Y8TtL^&gV@di;MS^=jp8PrA(iRCB!k?~wktN<|(&-eTzf zzf7Fye_h(2sv1;9Con<# zPfGhwN(GMp>~Y#p&~;W>Nq^qssadA<9oawIYhtc2W@k-M|6|9R8uoc(qWb+4)ITH> z|8K1y{9Ok7q|)5EL+bCa4a?ca-_m=j@_6}keaL9oxN!XVUT5pev>dl>uKAX -#include - -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, - "timezone", - "Time Zone", - "0:/icons/preferences-system-time.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/timezone/timezone.elf") >= 0; -} diff --git a/programs/src/desktop/Makefile b/programs/src/desktop/Makefile index 191b298..3973388 100644 --- a/programs/src/desktop/Makefile +++ b/programs/src/desktop/Makefile @@ -56,7 +56,7 @@ LDFLAGS := \ # ---- C++ source files ---- -CORE_SRCS := main.cpp window.cpp panel.cpp compose.cpp input.cpp dialogs.cpp launcher.cpp desktop_builtin.cpp desktop_applets.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 desktop_catalog.cpp font_data.cpp stb_truetype_impl.cpp APP_SRCS := $(sort $(shell find apps -name '*.cpp' -print)) SRCS := $(CORE_SRCS) $(APP_SRCS) OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) diff --git a/programs/src/desktop/apps/apps_common.hpp b/programs/src/desktop/apps/apps_common.hpp index be0ba18..e96c82e 100644 --- a/programs/src/desktop/apps/apps_common.hpp +++ b/programs/src/desktop/apps/apps_common.hpp @@ -232,26 +232,11 @@ SvgIcon* desktop_builtin_menu_icon(DesktopState* ds, DesktopBuiltinId id); void desktop_launch_builtin(DesktopState* ds, DesktopBuiltinId id); void desktop_lock_screen(DesktopState* ds); -enum DesktopAppletKind : int { - DESKTOP_APPLET_NONE = 0, - DESKTOP_APPLET_BUILTIN, - DESKTOP_APPLET_SHARED_LIBRARY, -}; - -struct DesktopAppletEntry { - DesktopAppletKind kind; - char id[48]; - char label[64]; - char icon_path[128]; - DesktopBuiltinId builtin_id; - char library_path[128]; -}; - -int desktop_list_system_configuration_applets(DesktopState* ds, - DesktopAppletEntry* out, - int max_entries); -bool desktop_launch_system_configuration_applet(DesktopState* ds, - const DesktopAppletEntry* applet); +int desktop_list_item_indices(DesktopState* ds, + DesktopItemSection section, + int* out, + int max_entries); +bool desktop_launch_item(DesktopState* ds, const DesktopItem* item); // ============================================================================ // Forward declarations for desktop launch entry points diff --git a/programs/src/desktop/apps/filemanager/actions.cpp b/programs/src/desktop/apps/filemanager/actions.cpp index e82a55b..0f8fad9 100644 --- a/programs/src/desktop/apps/filemanager/actions.cpp +++ b/programs/src/desktop/apps/filemanager/actions.cpp @@ -200,7 +200,7 @@ void filemanager_open_ctx_menu(FileManagerState* fm, int local_x, int local_y, i if ((filemanager_is_computer_view(fm) && (tt == FM_ENTRY_DRIVE || tt == FM_ENTRY_HOME || tt == FM_ENTRY_APPS_ROOT || tt == FM_ENTRY_SPECIAL_DIR || tt == FM_ENTRY_SYSTEM_CONFIGURATION_ROOT)) - || (filemanager_is_virtual_view(fm) && tt == FM_ENTRY_VIRTUAL_APP)) { + || (filemanager_is_virtual_view(fm) && tt == FM_ENTRY_VIRTUAL_ITEM)) { // Drive, Home, Apps shortcut, or app entry: only Open fm->ctx_items[fm->ctx_item_count++] = CTX_OPEN; fm->ctx_items[fm->ctx_item_count++] = CTX_PROPERTIES; diff --git a/programs/src/desktop/apps/filemanager/app.cpp b/programs/src/desktop/apps/filemanager/app.cpp index 284b428..e046328 100644 --- a/programs/src/desktop/apps/filemanager/app.cpp +++ b/programs/src/desktop/apps/filemanager/app.cpp @@ -8,12 +8,20 @@ namespace filemanager { -static constexpr const char* FM_PATH_SYSTEM_CONFIGURATION = "virtual://system-configuration"; +static constexpr const char* FM_PATH_APPS = "virtual://apps"; +static constexpr const char* FM_PATH_SETTINGS = "virtual://settings"; +static constexpr const char* FM_PATH_LEGACY_SYSTEM_CONFIGURATION = + "virtual://system-configuration"; static bool filemanager_open_virtual_path(FileManagerState* fm, const char* path) { if (!fm || !path) return false; - if (montauk::streq(path, FM_PATH_SYSTEM_CONFIGURATION)) { + if (montauk::streq(path, FM_PATH_APPS)) { + filemanager_read_virtual_view(fm, FM_VIRTUAL_VIEW_APPS); + return true; + } + if (montauk::streq(path, FM_PATH_SETTINGS) + || montauk::streq(path, FM_PATH_LEGACY_SYSTEM_CONFIGURATION)) { filemanager_read_virtual_view(fm, FM_VIRTUAL_VIEW_SYSTEM_CONFIGURATION); return true; } @@ -108,5 +116,5 @@ void open_filemanager_path(DesktopState* ds, const char* path) { } void open_system_configuration(DesktopState* ds) { - filemanager::open_filemanager_internal(ds, filemanager::FM_PATH_SYSTEM_CONFIGURATION); + filemanager::open_filemanager_internal(ds, filemanager::FM_PATH_SETTINGS); } diff --git a/programs/src/desktop/apps/filemanager/filemanager_internal.hpp b/programs/src/desktop/apps/filemanager/filemanager_internal.hpp index b74fb4a..06fe7bc 100644 --- a/programs/src/desktop/apps/filemanager/filemanager_internal.hpp +++ b/programs/src/desktop/apps/filemanager/filemanager_internal.hpp @@ -20,7 +20,7 @@ enum FileManagerEntryType : int { FM_ENTRY_DRIVE = 3, FM_ENTRY_HOME = 4, FM_ENTRY_APPS_ROOT = 5, - FM_ENTRY_VIRTUAL_APP = 6, + FM_ENTRY_VIRTUAL_ITEM = 6, FM_ENTRY_SPECIAL_DIR = 7, FM_ENTRY_SYSTEM_CONFIGURATION_ROOT = 8, }; @@ -31,21 +31,13 @@ enum FileManagerVirtualViewKind : uint8_t { FM_VIRTUAL_VIEW_SYSTEM_CONFIGURATION, }; -enum FileManagerVirtualEntryKind : uint8_t { - FM_VIRTUAL_ENTRY_NONE = 0, - FM_VIRTUAL_ENTRY_EXTERNAL_APP, - FM_VIRTUAL_ENTRY_SYSTEM_CONFIGURATION_APPLET, -}; - struct FileManagerLocation { char path[256]; FileManagerVirtualViewKind virtual_view; }; struct FileManagerVirtualEntry { - FileManagerVirtualEntryKind kind; - int external_app_index; - DesktopAppletEntry applet; + int desktop_item_index; SvgIcon icon_lg; SvgIcon icon_sm; }; diff --git a/programs/src/desktop/apps/filemanager/filesystem.cpp b/programs/src/desktop/apps/filemanager/filesystem.cpp index 2ef23c0..f41fc0f 100644 --- a/programs/src/desktop/apps/filemanager/filesystem.cpp +++ b/programs/src/desktop/apps/filemanager/filesystem.cpp @@ -110,11 +110,7 @@ static void filemanager_reset_list_state(FileManagerState* fm) { static void filemanager_reset_virtual_entry(FileManagerVirtualEntry* entry) { if (!entry) return; - entry->kind = FM_VIRTUAL_ENTRY_NONE; - entry->external_app_index = -1; - montauk::memset(&entry->applet, 0, sizeof(entry->applet)); - entry->applet.kind = DESKTOP_APPLET_NONE; - entry->applet.builtin_id = DESKTOP_BUILTIN_NONE; + entry->desktop_item_index = -1; entry->icon_lg = {}; entry->icon_sm = {}; } @@ -140,19 +136,17 @@ static void filemanager_add_root_entry(FileManagerState* fm, static int filemanager_add_virtual_entry(FileManagerState* fm, const char* name, - const char* icon_path, - FileManagerVirtualEntryKind kind) { + const char* icon_path) { if (!fm || !filemanager_ensure_entry_capacity(fm, fm->entry_count + 1)) return -1; int idx = fm->entry_count; montauk::strncpy(fm->entry_names[idx], name, 63); - fm->entry_types[idx] = FM_ENTRY_VIRTUAL_APP; + fm->entry_types[idx] = FM_ENTRY_VIRTUAL_ITEM; fm->entry_sizes[idx] = 0; fm->entry_mtimes[idx] = 0; fm->is_dir[idx] = false; fm->drive_indices[idx] = -1; filemanager_reset_virtual_entry(&fm->virtual_entries[idx]); - fm->virtual_entries[idx].kind = kind; if (icon_path && icon_path[0]) { Color defColor = colors::ICON_COLOR; @@ -165,24 +159,32 @@ static int filemanager_add_virtual_entry(FileManagerState* fm, return idx; } -static void filemanager_add_external_app_entry(FileManagerState* fm, - const ExternalApp& app, - int external_index) { - int idx = filemanager_add_virtual_entry(fm, app.name, app.icon_path, - FM_VIRTUAL_ENTRY_EXTERNAL_APP); +static void filemanager_add_desktop_item_entry(FileManagerState* fm, + const DesktopItem& item, + int desktop_item_index) { + int idx = filemanager_add_virtual_entry(fm, item.name, item.icon_path); if (idx >= 0) { - fm->virtual_entries[idx].external_app_index = external_index; + fm->virtual_entries[idx].desktop_item_index = desktop_item_index; } } -static void filemanager_add_system_configuration_applet_entry( - FileManagerState* fm, - const DesktopAppletEntry& applet) { - int idx = filemanager_add_virtual_entry(fm, applet.label, applet.icon_path, - FM_VIRTUAL_ENTRY_SYSTEM_CONFIGURATION_APPLET); - if (idx >= 0) { - fm->virtual_entries[idx].applet = applet; +static void filemanager_add_catalog_section(FileManagerState* fm, + DesktopItemSection section) { + if (!fm || !fm->desktop || fm->desktop->desktop_item_count <= 0) return; + + int capacity = fm->desktop->desktop_item_count; + int* item_indices = (int*)montauk::malloc((uint64_t)capacity * sizeof(int)); + if (!item_indices) return; + + int item_count = desktop_list_item_indices( + fm->desktop, section, item_indices, capacity); + for (int i = 0; i < item_count; i++) { + int item_index = item_indices[i]; + filemanager_add_desktop_item_entry( + fm, fm->desktop->desktop_items[item_index], item_index); } + + montauk::mfree(item_indices); } static void filemanager_begin_virtual_view(FileManagerState* fm, FileManagerVirtualViewKind view) { @@ -418,25 +420,14 @@ void filemanager_read_virtual_view(FileManagerState* fm, FileManagerVirtualViewK void filemanager_read_apps(FileManagerState* fm) { filemanager_begin_virtual_view(fm, FM_VIRTUAL_VIEW_APPS); - - DesktopState* ds = fm->desktop; - if (!ds) return; - - for (int i = 0; i < ds->external_app_count; i++) { - filemanager_add_external_app_entry(fm, ds->external_apps[i], i); - } + filemanager_add_catalog_section(fm, DESKTOP_ITEM_SECTION_APPS); filemanager_reset_list_state(fm); } void filemanager_read_system_configuration(FileManagerState* fm) { filemanager_begin_virtual_view(fm, FM_VIRTUAL_VIEW_SYSTEM_CONFIGURATION); - - DesktopAppletEntry applets[32]; - int applet_count = desktop_list_system_configuration_applets(fm->desktop, applets, 32); - for (int i = 0; i < applet_count; i++) { - filemanager_add_system_configuration_applet_entry(fm, applets[i]); - } + filemanager_add_catalog_section(fm, DESKTOP_ITEM_SECTION_SETTINGS); filemanager_reset_list_state(fm); } diff --git a/programs/src/desktop/apps/filemanager/navigation.cpp b/programs/src/desktop/apps/filemanager/navigation.cpp index 91dbb01..05b5ac3 100644 --- a/programs/src/desktop/apps/filemanager/navigation.cpp +++ b/programs/src/desktop/apps/filemanager/navigation.cpp @@ -242,20 +242,12 @@ void filemanager_open_entry(FileManagerState* fm, int idx) { return; } - 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_ITEM) { DesktopState* ds = fm->desktop; const FileManagerVirtualEntry& entry = fm->virtual_entries[idx]; - 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]; - if (app.launch_with_home) { - montauk::spawn(app.binary_path, ds->home_dir); - } else { - montauk::spawn(app.binary_path); - } - } else if (ds && entry.kind == FM_VIRTUAL_ENTRY_SYSTEM_CONFIGURATION_APPLET) { - desktop_launch_system_configuration_applet(ds, &entry.applet); + if (ds && entry.desktop_item_index >= 0 + && entry.desktop_item_index < ds->desktop_item_count) { + desktop_launch_item(ds, &ds->desktop_items[entry.desktop_item_index]); } return; } diff --git a/programs/src/desktop/apps/filemanager/properties.cpp b/programs/src/desktop/apps/filemanager/properties.cpp index 3bdda21..3bc5cc7 100644 --- a/programs/src/desktop/apps/filemanager/properties.cpp +++ b/programs/src/desktop/apps/filemanager/properties.cpp @@ -145,9 +145,9 @@ static const char* props_type_label(const FileManagerState* fm, int idx) { case FM_ENTRY_APPS_ROOT: return "Apps Folder"; case FM_ENTRY_SPECIAL_DIR: return "Folder"; case FM_ENTRY_SYSTEM_CONFIGURATION_ROOT: return "Settings"; - case FM_ENTRY_VIRTUAL_APP: + case FM_ENTRY_VIRTUAL_ITEM: if (fm->virtual_view == FM_VIRTUAL_VIEW_SYSTEM_CONFIGURATION) - return "Settings Applet"; + return "Setting"; return "Application"; case FM_ENTRY_FILE: default: @@ -192,21 +192,23 @@ static void props_build_path(const FileManagerState* fm, int idx, char* out, int } else if (type == FM_ENTRY_DRIVE) { props_drive_path(fm->drive_indices[idx], out, out_len); } else if (type == FM_ENTRY_APPS_ROOT) { - props_copy(out, out_len, "Apps"); + props_copy(out, out_len, "virtual://apps"); } else if (type == FM_ENTRY_SYSTEM_CONFIGURATION_ROOT) { - props_copy(out, out_len, "virtual://system-configuration"); + props_copy(out, out_len, "virtual://settings"); } return; } - if (type == FM_ENTRY_VIRTUAL_APP && idx < fm->virtual_entry_count) { + if (type == FM_ENTRY_VIRTUAL_ITEM && idx < fm->virtual_entry_count) { const FileManagerVirtualEntry& entry = fm->virtual_entries[idx]; - if (entry.kind == FM_VIRTUAL_ENTRY_EXTERNAL_APP && ds && - entry.external_app_index >= 0 && - entry.external_app_index < ds->external_app_count) { - props_copy(out, out_len, ds->external_apps[entry.external_app_index].binary_path); - } else if (entry.kind == FM_VIRTUAL_ENTRY_SYSTEM_CONFIGURATION_APPLET) { - props_copy(out, out_len, "Settings applet"); + if (ds && entry.desktop_item_index >= 0 + && entry.desktop_item_index < ds->desktop_item_count) { + const DesktopItem& item = ds->desktop_items[entry.desktop_item_index]; + if (item.launch_kind == DESKTOP_ITEM_LAUNCH_EXECUTABLE) { + props_copy(out, out_len, item.binary_path); + } else { + props_copy(out, out_len, item.id); + } } } } @@ -243,14 +245,12 @@ static void props_choose_icon(FilePropertiesDialogState* st, if (sfi >= 0 && ds && ds->icon_special_folder_lg[sfi].pixels) { props_set_shared_icon(st, &ds->icon_special_folder_lg[sfi]); - } else if (type == FM_ENTRY_VIRTUAL_APP && idx < fm->virtual_entry_count) { + } else if (type == FM_ENTRY_VIRTUAL_ITEM && idx < fm->virtual_entry_count) { const FileManagerVirtualEntry& entry = fm->virtual_entries[idx]; - if (entry.kind == FM_VIRTUAL_ENTRY_EXTERNAL_APP && ds && - entry.external_app_index >= 0 && - entry.external_app_index < ds->external_app_count) { - props_load_owned_icon(st, ds->external_apps[entry.external_app_index].icon_path); - } else if (entry.kind == FM_VIRTUAL_ENTRY_SYSTEM_CONFIGURATION_APPLET) { - props_load_owned_icon(st, entry.applet.icon_path); + if (ds && entry.desktop_item_index >= 0 + && entry.desktop_item_index < ds->desktop_item_count) { + props_load_owned_icon( + st, ds->desktop_items[entry.desktop_item_index].icon_path); } } else if (ds && type == FM_ENTRY_SYSTEM_CONFIGURATION_ROOT && ds->icon_system_configuration_lg.pixels) { diff --git a/programs/src/desktop/apps/filemanager/render.cpp b/programs/src/desktop/apps/filemanager/render.cpp index 9e1b383..402e46b 100644 --- a/programs/src/desktop/apps/filemanager/render.cpp +++ b/programs/src/desktop/apps/filemanager/render.cpp @@ -360,7 +360,7 @@ void filemanager_on_draw(Window* win, Framebuffer& fb) { if (sfi >= 0 && ds && ds->icon_special_folder_lg[sfi].pixels) { c.icon(icon_x, icon_y, ds->icon_special_folder_lg[sfi]); - } else if (fm->entry_types[i] == FM_ENTRY_VIRTUAL_APP + } else if (fm->entry_types[i] == FM_ENTRY_VIRTUAL_ITEM && i < fm->virtual_entry_count && fm->virtual_entries[i].icon_lg.pixels) { c.icon(icon_x, icon_y, fm->virtual_entries[i].icon_lg); @@ -500,7 +500,7 @@ void filemanager_on_draw(Window* win, Framebuffer& fb) { if (ico_y < list_y) { /* clipped by header repaint */ } else if (sfi_sm >= 0 && ds && ds->icon_special_folder[sfi_sm].pixels) { c.icon(ico_x, ico_y, ds->icon_special_folder[sfi_sm]); - } else if (fm->entry_types[i] == FM_ENTRY_VIRTUAL_APP + } else if (fm->entry_types[i] == FM_ENTRY_VIRTUAL_ITEM && i < fm->virtual_entry_count && fm->virtual_entries[i].icon_sm.pixels) { c.icon(ico_x, ico_y, fm->virtual_entries[i].icon_sm); @@ -588,9 +588,9 @@ void filemanager_on_draw(Window* win, Framebuffer& fb) { // Type if (type_col_x > 160 && ty >= list_y && ty + fm_sfh <= c.h) { const char* type_str = "File"; - if (fm->entry_types[i] == FM_ENTRY_VIRTUAL_APP) { + if (fm->entry_types[i] == FM_ENTRY_VIRTUAL_ITEM) { type_str = fm->virtual_view == FM_VIRTUAL_VIEW_SYSTEM_CONFIGURATION - ? "Applet" + ? "Setting" : "App"; } else if (fm->entry_types[i] == FM_ENTRY_APPS_ROOT) type_str = "Apps"; diff --git a/programs/src/desktop/desktop_applets.cpp b/programs/src/desktop/desktop_applets.cpp deleted file mode 100644 index ee4a724..0000000 --- a/programs/src/desktop/desktop_applets.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* - * desktop_applets.cpp - * Desktop applet registry and launch helpers - * Copyright (c) 2026 Daniel Hammer -*/ - -#include "desktop_internal.hpp" -#include -#include -#include - -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 = "config-applets"; -static constexpr const char* APPLET_TABLE_PREFIX = "applets."; -static constexpr uint32_t SYSTEM_CONFIGURATION_CAP = - gui::desktop_applet::CAP_SYSTEM_CONFIGURATION; - -static void clear_applet_entry(DesktopAppletEntry* entry) { - if (!entry) return; - montauk::memset(entry, 0, sizeof(*entry)); - entry->kind = DESKTOP_APPLET_NONE; - entry->builtin_id = DESKTOP_BUILTIN_NONE; -} - -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, - uint32_t required_capability, - 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->capabilities & required_capability) == 0) 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 bool load_shared_applet_metadata(const montauk::toml::Doc& doc, - const char* table_key, - const char* library, - DesktopAppletEntry* out) { - if (!out || !library || !library[0]) return false; - - LibHandle* lib = libloader::dlopen(library); - if (!lib) return false; - - const Descriptor* desc = nullptr; - bool ok = resolve_shared_applet(lib, SYSTEM_CONFIGURATION_CAP, &desc, nullptr); - if (ok) { - clear_applet_entry(out); - out->kind = DESKTOP_APPLET_SHARED_LIBRARY; - montauk::strncpy(out->id, desc->applet_id, sizeof(out->id)); - montauk::strncpy(out->library_path, library, sizeof(out->library_path)); - - const char* label_override = applet_field_string(doc, table_key, "label", ""); - const char* icon_override = applet_field_string(doc, table_key, "icon", ""); - const char* icon = icon_override[0] - ? icon_override - : (desc->icon_path && desc->icon_path[0] ? desc->icon_path : DEFAULT_APPLET_ICON); - - montauk::strncpy(out->label, - label_override[0] ? label_override : desc->display_name, - sizeof(out->label)); - montauk::strncpy(out->icon_path, icon, sizeof(out->icon_path)); - } - - libloader::dlclose(lib); - return ok; -} - -static void sort_applets(DesktopAppletEntry* entries, int count) { - if (!entries || count <= 1) return; - - for (int i = 1; i < count; i++) { - DesktopAppletEntry 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; - } -} - -static bool launch_shared_applet(DesktopState* ds, - const char* lib_path, - uint32_t required_capability) { - if (!ds || !lib_path || !lib_path[0]) return false; - - LibHandle* lib = libloader::dlopen(lib_path); - if (!lib) return false; - - OpenFn open = nullptr; - bool ok = resolve_shared_applet(lib, required_capability, nullptr, &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; -} - -} // namespace - -int desktop_list_system_configuration_applets(DesktopState* ds, - DesktopAppletEntry* out, - int max_entries) { - (void)ds; - if (!out || max_entries <= 0) return 0; - - int written = 0; - int builtin_count = 0; - const DesktopBuiltinEntry* builtins = desktop_builtin_registry(&builtin_count); - for (int i = 0; i < builtin_count && written < max_entries; i++) { - if (!builtins[i].system_configuration_id) continue; - - clear_applet_entry(&out[written]); - out[written].kind = DESKTOP_APPLET_BUILTIN; - out[written].builtin_id = builtins[i].id; - montauk::strncpy(out[written].id, - builtins[i].system_configuration_id, - sizeof(out[written].id)); - montauk::strncpy(out[written].label, builtins[i].label, sizeof(out[written].label)); - if (builtins[i].icon_path) { - montauk::strncpy(out[written].icon_path, - builtins[i].icon_path, - sizeof(out[written].icon_path)); - } - written++; - } - - auto doc = montauk::config::load(APPLET_CONFIG_NAME); - 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; - if (!applet_id_from_table_key(item->key)) 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; - - if (load_shared_applet_metadata(doc, item->key, library, &out[written])) { - written++; - } - } - doc.destroy(); - - sort_applets(out, written); - return written; -} - -bool desktop_launch_system_configuration_applet(DesktopState* ds, - const DesktopAppletEntry* applet) { - if (!ds || !applet) return false; - - switch (applet->kind) { - case DESKTOP_APPLET_BUILTIN: - if (applet->builtin_id == DESKTOP_BUILTIN_NONE) return false; - desktop_launch_builtin(ds, applet->builtin_id); - return true; - case DESKTOP_APPLET_SHARED_LIBRARY: - return launch_shared_applet(ds, applet->library_path, SYSTEM_CONFIGURATION_CAP); - default: - return false; - } -} diff --git a/programs/src/desktop/desktop_builtin.cpp b/programs/src/desktop/desktop_builtin.cpp index 8aa21b6..8e1547d 100644 --- a/programs/src/desktop/desktop_builtin.cpp +++ b/programs/src/desktop/desktop_builtin.cpp @@ -1,6 +1,6 @@ /* * desktop_builtin.cpp - * Shared builtin applet metadata and dispatch helpers + * Shared built-in desktop item metadata and dispatch helpers * Copyright (c) 2026 Daniel Hammer */ diff --git a/programs/src/desktop/desktop_catalog.cpp b/programs/src/desktop/desktop_catalog.cpp new file mode 100644 index 0000000..855f366 --- /dev/null +++ b/programs/src/desktop/desktop_catalog.cpp @@ -0,0 +1,63 @@ +/* + * desktop_catalog.cpp + * Unified catalog and launch helpers for desktop items + * Copyright (c) 2026 Daniel Hammer +*/ + +#include "desktop_internal.hpp" + +namespace { + +static void sort_item_indices(DesktopState* ds, int* indices, int count) { + for (int i = 1; i < count; i++) { + int tmp = indices[i]; + int j = i - 1; + while (j >= 0 + && str_compare_ci(ds->desktop_items[tmp].name, + ds->desktop_items[indices[j]].name) < 0) { + indices[j + 1] = indices[j]; + j--; + } + indices[j + 1] = tmp; + } +} + +} // namespace + +int desktop_list_item_indices(DesktopState* ds, + DesktopItemSection section, + int* out, + int max_entries) { + if (!ds || !out || max_entries <= 0) return 0; + + int written = 0; + for (int i = 0; i < ds->desktop_item_count && written < max_entries; i++) { + const DesktopItem& item = ds->desktop_items[i]; + if (item.section != section) continue; + if (item.admin_only && !ds->is_admin) continue; + out[written++] = i; + } + + sort_item_indices(ds, out, written); + return written; +} + +bool desktop_launch_item(DesktopState* ds, const DesktopItem* item) { + if (!ds || !item) return false; + if (item->admin_only && !ds->is_admin) return false; + + switch (item->launch_kind) { + case DESKTOP_ITEM_LAUNCH_BUILTIN: + if (item->builtin_id < 0) return false; + desktop_launch_builtin(ds, (DesktopBuiltinId)item->builtin_id); + return true; + case DESKTOP_ITEM_LAUNCH_EXECUTABLE: + if (!item->binary_path[0]) return false; + if (item->launch_with_home) { + return montauk::spawn(item->binary_path, ds->home_dir) >= 0; + } + return montauk::spawn(item->binary_path) >= 0; + default: + return false; + } +} diff --git a/programs/src/desktop/launcher.cpp b/programs/src/desktop/launcher.cpp index 1822e74..81580a8 100644 --- a/programs/src/desktop/launcher.cpp +++ b/programs/src/desktop/launcher.cpp @@ -199,16 +199,6 @@ static void launcher_add_item(DesktopState* ds, LauncherItemKind kind, item->ref_index = ref_index; } -static void desktop_launch_external_app(DesktopState* ds, const ExternalApp* app) { - if (!app) return; - - if (app->launch_with_home) { - montauk::spawn(app->binary_path, ds->home_dir); - } else { - montauk::spawn(app->binary_path); - } -} - static void desktop_build_launcher_items(DesktopState* ds) { ds->launcher_item_count = 0; @@ -219,11 +209,15 @@ static void desktop_build_launcher_items(DesktopState* ds) { &ds->icon_filemanager, -1, nullptr, "file manager browser"); - for (int i = 0; i < ds->external_app_count; i++) { - ExternalApp* app = &ds->external_apps[i]; - SvgIcon* icon = app->icon.pixels ? &app->icon : &ds->icon_exec; + for (int i = 0; i < ds->desktop_item_count; i++) { + DesktopItem* item = &ds->desktop_items[i]; + if (item->admin_only && !ds->is_admin) continue; + SvgIcon* icon = item->icon.pixels ? &item->icon : &ds->icon_exec; + const char* category = item->section == DESKTOP_ITEM_SECTION_SETTINGS + ? "Settings" + : item->category; launcher_add_item(ds, LAUNCHER_ITEM_EXTERNAL_APP, - app->name, app->category, + item->name, category, icon, i, nullptr, nullptr); } @@ -341,8 +335,8 @@ static void launcher_activate_selected(DesktopState* ds) { LauncherItem* item = &ds->launcher_items[item_idx]; switch (item->kind) { case LAUNCHER_ITEM_EXTERNAL_APP: - if (item->ref_index >= 0 && item->ref_index < ds->external_app_count) { - desktop_launch_external_app(ds, &ds->external_apps[item->ref_index]); + if (item->ref_index >= 0 && item->ref_index < ds->desktop_item_count) { + desktop_launch_item(ds, &ds->desktop_items[item->ref_index]); } break; case LAUNCHER_ITEM_BUILTIN_FILES: diff --git a/programs/src/desktop/main.cpp b/programs/src/desktop/main.cpp index 29f14ad..a59bff3 100644 --- a/programs/src/desktop/main.cpp +++ b/programs/src/desktop/main.cpp @@ -35,22 +35,46 @@ static void extract_basename(char* out, int outSz, const char* entry) { out[base_len] = '\0'; } -// Return a slot for the next external app, doubling the array as needed. +// Return a slot for the next desktop item, doubling the array as needed. // Returns nullptr if allocation failed. -static ExternalApp* next_external_app_slot(DesktopState* ds) { - if (ds->external_app_count >= ds->external_app_capacity) { - int new_cap = ds->external_app_capacity ? ds->external_app_capacity * 2 : 32; - auto* grown = (ExternalApp*)montauk::realloc( - ds->external_apps, (uint64_t)new_cap * sizeof(ExternalApp)); +static DesktopItem* next_desktop_item_slot(DesktopState* ds) { + if (ds->desktop_item_count >= ds->desktop_item_capacity) { + int new_cap = ds->desktop_item_capacity ? ds->desktop_item_capacity * 2 : 32; + auto* grown = (DesktopItem*)montauk::realloc( + ds->desktop_items, (uint64_t)new_cap * sizeof(DesktopItem)); if (!grown) return nullptr; - ds->external_apps = grown; - ds->external_app_capacity = new_cap; + ds->desktop_items = grown; + ds->desktop_item_capacity = new_cap; + } + return &ds->desktop_items[ds->desktop_item_count]; +} + +static void desktop_add_builtin_catalog_items(DesktopState* ds) { + int builtin_count = 0; + const DesktopBuiltinEntry* builtins = desktop_builtin_registry(&builtin_count); + for (int i = 0; i < builtin_count; i++) { + if (!builtins[i].system_configuration_id) continue; + + DesktopItem* item = next_desktop_item_slot(ds); + if (!item) return; + montauk::memset(item, 0, sizeof(*item)); + montauk::strncpy(item->id, builtins[i].system_configuration_id, sizeof(item->id)); + montauk::strncpy(item->name, builtins[i].label, sizeof(item->name)); + if (builtins[i].icon_path) { + montauk::strncpy(item->icon_path, builtins[i].icon_path, sizeof(item->icon_path)); + } + SvgIcon* icon = desktop_builtin_menu_icon(ds, builtins[i].id); + if (icon) item->icon = *icon; + item->section = DESKTOP_ITEM_SECTION_SETTINGS; + item->launch_kind = DESKTOP_ITEM_LAUNCH_BUILTIN; + item->builtin_id = (int)builtins[i].id; + ds->desktop_item_count++; } - return &ds->external_apps[ds->external_app_count]; } void desktop_scan_apps(DesktopState* ds) { - ds->external_app_count = 0; + ds->desktop_item_count = 0; + desktop_add_builtin_catalog_items(ds); // Ensure the apps directory exists montauk::fmkdir("0:/apps"); @@ -94,44 +118,78 @@ void desktop_scan_apps(DesktopState* ds) { montauk::mfree(text); // Read manifest fields + const char* id = doc.get_string("app.id", dirname); const char* name = doc.get_string("app.name", "Unknown"); const char* binary = doc.get_string("app.binary", ""); const char* icon_file = doc.get_string("app.icon", ""); const char* category = doc.get_string("menu.category", "Applications"); bool visible = doc.get_bool("menu.visible", true); bool launch_with_home = doc.get_bool("launch.pass_home_dir", true); - if (binary[0] == '\0') { + const char* section_name = doc.get_string("desktop.section", "apps"); + bool admin_only = doc.get_bool("desktop.admin_only", false); + if (id[0] == '\0' || binary[0] == '\0') { + montauk::print("desktop: skipping app manifest with missing id or binary\n"); doc.destroy(); continue; } - ExternalApp* app = next_external_app_slot(ds); - if (!app) { + bool duplicate = false; + for (int existing = 0; existing < ds->desktop_item_count; existing++) { + if (montauk::streq(ds->desktop_items[existing].id, id)) { + duplicate = true; + break; + } + } + if (duplicate) { + montauk::print("desktop: skipping app manifest with duplicate id\n"); + doc.destroy(); + continue; + } + + DesktopItemSection section = DESKTOP_ITEM_SECTION_APPS; + if (montauk::streq(section_name, "settings")) { + section = DESKTOP_ITEM_SECTION_SETTINGS; + } else if (montauk::streq(section_name, "hidden")) { + section = DESKTOP_ITEM_SECTION_HIDDEN; + } else if (!montauk::streq(section_name, "apps")) { + montauk::print("desktop: skipping app manifest with invalid desktop.section\n"); + doc.destroy(); + continue; + } + + DesktopItem* item = next_desktop_item_slot(ds); + if (!item) { doc.destroy(); return; } + montauk::memset(item, 0, sizeof(*item)); - montauk::strncpy(app->name, name, sizeof(app->name)); - montauk::strncpy(app->category, category, sizeof(app->category)); - app->menu_visible = visible; - app->launch_with_home = launch_with_home; + montauk::strncpy(item->id, id, sizeof(item->id)); + montauk::strncpy(item->name, name, sizeof(item->name)); + montauk::strncpy(item->category, category, sizeof(item->category)); + item->menu_visible = visible; + item->launch_with_home = launch_with_home; + item->admin_only = admin_only; + item->launch_kind = DESKTOP_ITEM_LAUNCH_EXECUTABLE; + item->builtin_id = -1; + item->section = section; // Build full binary path: 0:/apps// - snprintf(app->binary_path, sizeof(app->binary_path), + snprintf(item->binary_path, sizeof(item->binary_path), "0:/apps/%s/%s", dirname, binary); // Load icon from app directory - app->icon = {}; - app->icon_path[0] = '\0'; + item->icon = {}; + item->icon_path[0] = '\0'; if (icon_file[0]) { - snprintf(app->icon_path, sizeof(app->icon_path), + snprintf(item->icon_path, sizeof(item->icon_path), "0:/apps/%s/%s", dirname, icon_file); Color defColor = colors::ICON_COLOR; - app->icon = svg_load(app->icon_path, 20, 20, defColor); + item->icon = svg_load(item->icon_path, 20, 20, defColor); } doc.destroy(); - ds->external_app_count++; + ds->desktop_item_count++; } } } @@ -161,12 +219,13 @@ void desktop_build_menu(DesktopState* ds) { } } - // Add external apps in this category - for (int x = 0; x < ds->external_app_count; x++) { - ExternalApp* app = &ds->external_apps[x]; - if (!app->menu_visible) continue; - if (montauk::streq(app->category, CATEGORY_NAMES[cat])) { - menu_add_external(app->name, app->binary_path, &app->icon, app->launch_with_home); + // Add manifest-backed items in this category. + for (int x = 0; x < ds->desktop_item_count; x++) { + DesktopItem* item = &ds->desktop_items[x]; + if (!item->menu_visible || (item->admin_only && !ds->is_admin)) continue; + if (montauk::streq(item->category, CATEGORY_NAMES[cat])) { + menu_add_external(item->name, item->binary_path, + &item->icon, item->launch_with_home); } } } diff --git a/programs/src/installer/components.cpp b/programs/src/installer/components.cpp index 7e47395..8fc9651 100644 --- a/programs/src/installer/components.cpp +++ b/programs/src/installer/components.cpp @@ -138,8 +138,7 @@ Component g_components[] = { { "printing", "Printing support", "Print spooler daemon (printd), printer setup app and print tools", -1, "os/printd.elf", - {"os/printd.elf", "os/printctl.elf", "os/printersapplet.lib", - "apps/printers", nullptr}, + {"os/printd.elf", "os/printctl.elf", "apps/printers", nullptr}, false, -1, false, false, false, false, 0, 0 }, diff --git a/programs/src/network/main.cpp b/programs/src/network/main.cpp index 05ab419..591b9d7 100644 --- a/programs/src/network/main.cpp +++ b/programs/src/network/main.cpp @@ -1,6 +1,6 @@ /* * main.cpp - * MontaukOS Network configuration applet + * MontaukOS Network configuration app * Copyright (c) 2026 Daniel Hammer */ diff --git a/programs/src/network/manifest.toml b/programs/src/network/manifest.toml index 2b8747b..23bb568 100644 --- a/programs/src/network/manifest.toml +++ b/programs/src/network/manifest.toml @@ -1,4 +1,5 @@ [app] +id = "network" name = "Network" binary = "network.elf" icon = "network-wired.svg" @@ -6,3 +7,7 @@ icon = "network-wired.svg" [menu] category = "System" visible = false + +[desktop] +section = "settings" +admin_only = false diff --git a/programs/src/printers/manifest.toml b/programs/src/printers/manifest.toml index f5e54c7..ec325be 100644 --- a/programs/src/printers/manifest.toml +++ b/programs/src/printers/manifest.toml @@ -1,4 +1,5 @@ [app] +id = "printers" name = "Printers" binary = "printers.elf" icon = "preferences-devices-printer.svg" @@ -6,3 +7,7 @@ icon = "preferences-devices-printer.svg" [menu] category = "System" visible = true + +[desktop] +section = "settings" +admin_only = false diff --git a/programs/src/timezone/main.cpp b/programs/src/timezone/main.cpp index 135b370..1f2015a 100644 --- a/programs/src/timezone/main.cpp +++ b/programs/src/timezone/main.cpp @@ -1,6 +1,6 @@ /* * main.cpp - * MontaukOS Time Zone configuration applet + * MontaukOS Time Zone configuration app * Copyright (c) 2026 Daniel Hammer */ diff --git a/programs/src/timezone/manifest.toml b/programs/src/timezone/manifest.toml index c78420a..a0f63d0 100644 --- a/programs/src/timezone/manifest.toml +++ b/programs/src/timezone/manifest.toml @@ -1,4 +1,5 @@ [app] +id = "timezone" name = "Time Zone" binary = "timezone.elf" icon = "preferences-system-time.svg" @@ -6,3 +7,7 @@ icon = "preferences-system-time.svg" [menu] category = "System" visible = false + +[desktop] +section = "settings" +admin_only = false diff --git a/template/docs/gui-apps.md b/template/docs/gui-apps.md index 0947d16..e388366 100644 --- a/template/docs/gui-apps.md +++ b/template/docs/gui-apps.md @@ -841,18 +841,36 @@ External standalone apps can be discovered by the desktop through TOML manifest ```toml [app] +id = "my-app" name = "My App" -binary = "myapp" +binary = "myapp.elf" icon = "myapp_icon.svg" [menu] category = "Applications" visible = true + +[desktop] +section = "apps" +admin_only = false + +[launch] +pass_home_dir = true ``` **Categories:** `Applications`, `Internet`, `System`, `Games` -The desktop scans `0:/apps/` at startup and adds matching entries to the application menu. The `binary` field is the executable name (looked up in the system path). +The desktop scans `0:/apps/` at startup and builds one catalog used by the +application menu, launcher search, and the Apps and Settings virtual folders. +`app.id` must be unique; when omitted, the containing directory name is used. +The `binary` field names an executable in that app's bundle. + +`desktop.section` accepts `apps` (the default), `settings`, or `hidden`. +Section placement is independent of `menu.visible`: a Settings item can be +hidden from the application menu while remaining directly searchable in the +launcher. Set `desktop.admin_only` to hide the item from non-administrator +users. `launch.pass_home_dir` controls whether the current user's home path is +passed as the executable's first argument. --- diff --git a/template/sysroot/include/gui/desktop.hpp b/template/sysroot/include/gui/desktop.hpp index 05dbe41..5e659d1 100644 --- a/template/sysroot/include/gui/desktop.hpp +++ b/template/sysroot/include/gui/desktop.hpp @@ -17,18 +17,34 @@ namespace gui { static constexpr int MAX_WINDOWS = 8; static constexpr int PANEL_HEIGHT = 32; -static constexpr int MAX_EXTERNAL_APPS = 32; static constexpr int MAX_LAUNCHER_ITEMS = 64; -// External app discovered from 0:/apps/ manifest -struct ExternalApp { +enum DesktopItemSection : uint8_t { + DESKTOP_ITEM_SECTION_HIDDEN = 0, + DESKTOP_ITEM_SECTION_APPS, + DESKTOP_ITEM_SECTION_SETTINGS, +}; + +enum DesktopItemLaunchKind : uint8_t { + DESKTOP_ITEM_LAUNCH_EXECUTABLE = 0, + DESKTOP_ITEM_LAUNCH_BUILTIN, +}; + +// Launchable desktop item discovered from an app manifest or supplied by the +// desktop's built-in registry. +struct DesktopItem { + char id[48]; char name[48]; char binary_path[128]; char icon_path[128]; char category[24]; SvgIcon icon; + DesktopItemSection section; + DesktopItemLaunchKind launch_kind; + int builtin_id; bool menu_visible; bool launch_with_home; + bool admin_only; }; enum LauncherItemKind : uint8_t { @@ -152,9 +168,10 @@ struct DesktopState { SvgIcon icon_volume; - // External apps discovered from 0:/apps/ manifests - ExternalApp external_apps[MAX_EXTERNAL_APPS]; - int external_app_count; + // Desktop items discovered from 0:/apps/ manifests (dynamically grown). + DesktopItem* desktop_items; + int desktop_item_count; + int desktop_item_capacity; bool ctx_menu_open; int ctx_menu_x, ctx_menu_y; diff --git a/template/sysroot/include/gui/desktop_applet.hpp b/template/sysroot/include/gui/desktop_applet.hpp deleted file mode 100644 index a82b549..0000000 --- a/template/sysroot/include/gui/desktop_applet.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * desktop_applet.hpp - * Shared-library desktop applet ABI for MontaukOS - * Copyright (c) 2026 Daniel Hammer -*/ - -#pragma once - -#include - -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