refactor: unify desktop apps and Settings under item catalog
This commit is contained in:
@@ -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/<dir>/<binary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user