feat: add SYS_FUTEX_WAIT and SYS_FUTEX_WAKE syscalls; revamp desktop application categories
This commit is contained in:
1 parent
60ca9c78c7
commit
abfd9de8f6
35 files changed
+545
-70
No files matched your search
@@ -48,6 +48,7 @@ static constexpr int MENU_DIV_H = 10;
|
||||
|
||||
struct MenuRow {
|
||||
bool is_category;
|
||||
bool expanded; // category rows only: children shown (dividers always true)
|
||||
char label[48];
|
||||
DesktopBuiltinId app_id; // desktop builtin ID, or DESKTOP_BUILTIN_NONE for categories/dividers
|
||||
bool external; // true = spawn binary_path
|
||||
@@ -74,23 +75,15 @@ inline MenuRow* menu_alloc_row() {
|
||||
return &menu_rows[menu_row_count++];
|
||||
}
|
||||
|
||||
// Collapsible category state (categories 0-3 are toggleable; divider category always expanded)
|
||||
static constexpr int MENU_NUM_CATS = 5;
|
||||
inline bool menu_cat_expanded[MENU_NUM_CATS] = { false, false, false, false, true };
|
||||
|
||||
inline int menu_get_cat(int row_idx) {
|
||||
int cat = -1;
|
||||
for (int i = 0; i <= row_idx; i++)
|
||||
if (menu_rows[i].is_category) cat++;
|
||||
return cat;
|
||||
}
|
||||
|
||||
// Collapsible categories: each category row carries its own expanded flag,
|
||||
// so the menu can hold any number of manifest-defined categories. Dividers
|
||||
// (empty label) are always expanded.
|
||||
inline bool menu_row_visible(int row_idx) {
|
||||
const MenuRow& row = menu_rows[row_idx];
|
||||
if (row.is_category) return true;
|
||||
int cat = menu_get_cat(row_idx);
|
||||
if (cat < 0 || cat >= MENU_NUM_CATS) return true;
|
||||
return menu_cat_expanded[cat];
|
||||
for (int i = row_idx - 1; i >= 0; i--)
|
||||
if (menu_rows[i].is_category) return menu_rows[i].expanded;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline int menu_row_height(const MenuRow& row) {
|
||||
@@ -102,17 +95,11 @@ inline int menu_total_height() {
|
||||
// Single-pass walk to avoid O(N^2) from menu_row_visible repeatedly
|
||||
// counting categories from the start.
|
||||
int h = 10; // top + bottom padding
|
||||
int cur_cat = -1;
|
||||
bool cat_expanded = true;
|
||||
for (int i = 0; i < menu_row_count; i++) {
|
||||
const MenuRow& row = menu_rows[i];
|
||||
if (row.is_category) cur_cat++;
|
||||
bool visible = true;
|
||||
if (!row.is_category) {
|
||||
if (cur_cat >= 0 && cur_cat < MENU_NUM_CATS) {
|
||||
visible = menu_cat_expanded[cur_cat];
|
||||
}
|
||||
}
|
||||
if (visible) h += menu_row_height(row);
|
||||
if (row.is_category) cat_expanded = row.expanded;
|
||||
if (row.is_category || cat_expanded) h += menu_row_height(row);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
@@ -126,6 +113,7 @@ inline int menu_add_category(const char* label) {
|
||||
if (!rp) return -1;
|
||||
MenuRow& r = *rp;
|
||||
r.is_category = true;
|
||||
r.expanded = !label[0]; // named categories start collapsed; dividers stay open
|
||||
montauk::strncpy(r.label, label, sizeof(r.label));
|
||||
r.app_id = DESKTOP_BUILTIN_NONE;
|
||||
r.external = false;
|
||||
@@ -140,6 +128,7 @@ inline int menu_add_embedded(const char* label, DesktopBuiltinId app_id, SvgIcon
|
||||
if (!rp) return -1;
|
||||
MenuRow& r = *rp;
|
||||
r.is_category = false;
|
||||
r.expanded = false;
|
||||
montauk::strncpy(r.label, label, sizeof(r.label));
|
||||
r.app_id = app_id;
|
||||
r.external = false;
|
||||
@@ -154,6 +143,7 @@ inline int menu_add_external(const char* label, const char* binary, SvgIcon* ico
|
||||
if (!rp) return -1;
|
||||
MenuRow& r = *rp;
|
||||
r.is_category = false;
|
||||
r.expanded = false;
|
||||
montauk::strncpy(r.label, label, sizeof(r.label));
|
||||
r.app_id = DESKTOP_BUILTIN_NONE;
|
||||
r.external = true;
|
||||
|
||||
@@ -360,16 +360,16 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
if (menu_rect.contains(mx, my)) {
|
||||
// Walk visible rows to find which one was clicked
|
||||
int iy = menu_y + 5;
|
||||
int cur_cat = -1;
|
||||
bool cat_expanded = true;
|
||||
for (int i = 0; i < menu_row_count; i++) {
|
||||
const MenuRow& row = menu_rows[i];
|
||||
if (row.is_category) cur_cat++;
|
||||
if (!menu_row_visible(i)) continue;
|
||||
MenuRow& row = menu_rows[i];
|
||||
if (row.is_category) cat_expanded = row.expanded;
|
||||
else if (!cat_expanded) continue;
|
||||
int row_h = menu_row_height(row);
|
||||
if (my >= iy && my < iy + row_h) {
|
||||
if (row.is_category && row.label[0] && cur_cat >= 0 && cur_cat < MENU_NUM_CATS - 1) {
|
||||
if (row.is_category && row.label[0]) {
|
||||
// Toggle category expand/collapse
|
||||
menu_cat_expanded[cur_cat] = !menu_cat_expanded[cur_cat];
|
||||
row.expanded = !row.expanded;
|
||||
} else if (!row.is_category) {
|
||||
if (row.external) {
|
||||
if (row.launch_with_home) {
|
||||
|
||||
@@ -121,7 +121,11 @@ void desktop_scan_apps(DesktopState* ds) {
|
||||
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");
|
||||
const char* category = doc.get_string("menu.category", "Productivity");
|
||||
// "Applications" was the old catch-all; keep older manifests out of
|
||||
// a stray custom category.
|
||||
if (!category[0] || montauk::streq(category, "Applications"))
|
||||
category = "Productivity";
|
||||
bool visible = doc.get_bool("menu.visible", true);
|
||||
bool launch_with_home = doc.get_bool("launch.pass_home_dir", true);
|
||||
const char* section_name = doc.get_string("desktop.section", "apps");
|
||||
@@ -197,18 +201,55 @@ void desktop_scan_apps(DesktopState* ds) {
|
||||
// Menu Builder
|
||||
// ============================================================================
|
||||
|
||||
// Category definitions and their ordering
|
||||
static const char* CATEGORY_NAMES[] = { "Applications", "Internet", "System", "Games" };
|
||||
static constexpr int NUM_CATEGORIES = 4;
|
||||
// Predefined categories and their ordering. Manifests may name any other
|
||||
// category; those are appended after these, sorted by name.
|
||||
// Builtins reference these by index (DesktopBuiltinEntry::launcher_category).
|
||||
static const char* CATEGORY_NAMES[] = {
|
||||
"Productivity", "Media", "Internet",
|
||||
"Utilities", "Games", "Hardware", "System",
|
||||
};
|
||||
static constexpr int NUM_CATEGORIES = sizeof(CATEGORY_NAMES) / sizeof(CATEGORY_NAMES[0]);
|
||||
|
||||
static bool category_eq(const char* a, const char* b) {
|
||||
for (;; a++, b++) {
|
||||
char ca = (*a >= 'A' && *a <= 'Z') ? *a + 32 : *a;
|
||||
char cb = (*b >= 'A' && *b <= 'Z') ? *b + 32 : *b;
|
||||
if (ca != cb) return false;
|
||||
if (!ca) return true;
|
||||
}
|
||||
}
|
||||
|
||||
static int category_cmp(const char* a, const char* b) {
|
||||
for (;; a++, b++) {
|
||||
char ca = (*a >= 'A' && *a <= 'Z') ? *a + 32 : *a;
|
||||
char cb = (*b >= 'A' && *b <= 'Z') ? *b + 32 : *b;
|
||||
if (ca != cb || !ca) return (int)(unsigned char)ca - (int)(unsigned char)cb;
|
||||
}
|
||||
}
|
||||
|
||||
static bool menu_item_shown(DesktopState* ds, const DesktopItem* item) {
|
||||
return item->menu_visible && !(item->admin_only && !ds->is_admin);
|
||||
}
|
||||
|
||||
static void menu_add_manifest_items(DesktopState* ds, const char* category) {
|
||||
for (int x = 0; x < ds->desktop_item_count; x++) {
|
||||
DesktopItem* item = &ds->desktop_items[x];
|
||||
if (!menu_item_shown(ds, item)) continue;
|
||||
if (category_eq(item->category, category)) {
|
||||
menu_add_external(item->name, item->binary_path,
|
||||
&item->icon, item->launch_with_home);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void desktop_build_menu(DesktopState* ds) {
|
||||
menu_row_count = 0;
|
||||
int builtin_count = 0;
|
||||
const DesktopBuiltinEntry* builtins = desktop_builtin_registry(&builtin_count);
|
||||
|
||||
// Build each category
|
||||
// Build each predefined category
|
||||
for (int cat = 0; cat < NUM_CATEGORIES; cat++) {
|
||||
menu_add_category(CATEGORY_NAMES[cat]);
|
||||
int header = menu_add_category(CATEGORY_NAMES[cat]);
|
||||
|
||||
// Add desktop builtins in this category
|
||||
for (int b = 0; b < builtin_count; b++) {
|
||||
@@ -218,19 +259,48 @@ void desktop_build_menu(DesktopState* ds) {
|
||||
}
|
||||
}
|
||||
|
||||
// Add manifest-backed items in this category.
|
||||
menu_add_manifest_items(ds, CATEGORY_NAMES[cat]);
|
||||
|
||||
// Drop the header again if nothing landed under it.
|
||||
if (header >= 0 && menu_row_count == header + 1) menu_row_count = header;
|
||||
}
|
||||
|
||||
// Custom categories: the first item of each distinct, non-predefined
|
||||
// category (case-insensitive) represents it; emit them in name order.
|
||||
const DesktopItem** custom = ds->desktop_item_count > 0
|
||||
? (const DesktopItem**)montauk::malloc(
|
||||
(uint64_t)ds->desktop_item_count * sizeof(DesktopItem*))
|
||||
: nullptr;
|
||||
int custom_count = 0;
|
||||
if (custom) {
|
||||
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);
|
||||
const DesktopItem* item = &ds->desktop_items[x];
|
||||
if (!menu_item_shown(ds, item)) continue;
|
||||
|
||||
bool known = false;
|
||||
for (int c = 0; c < NUM_CATEGORIES && !known; c++)
|
||||
known = category_eq(item->category, CATEGORY_NAMES[c]);
|
||||
for (int c = 0; c < custom_count && !known; c++)
|
||||
known = category_eq(item->category, custom[c]->category);
|
||||
if (known) continue;
|
||||
|
||||
int pos = custom_count;
|
||||
while (pos > 0 && category_cmp(custom[pos - 1]->category, item->category) > 0) {
|
||||
custom[pos] = custom[pos - 1];
|
||||
pos--;
|
||||
}
|
||||
custom[pos] = item;
|
||||
custom_count++;
|
||||
}
|
||||
for (int c = 0; c < custom_count; c++) {
|
||||
menu_add_category(custom[c]->category);
|
||||
menu_add_manifest_items(ds, custom[c]->category);
|
||||
}
|
||||
montauk::mfree(custom);
|
||||
}
|
||||
|
||||
// Divider + always-visible entries
|
||||
menu_add_category(""); // divider (cat 4, always expanded)
|
||||
menu_add_category(""); // divider (always expanded)
|
||||
for (int b = 0; b < builtin_count; b++) {
|
||||
if (builtins[b].launcher_footer) {
|
||||
menu_add_embedded(builtins[b].label, builtins[b].id,
|
||||
|
||||
@@ -271,13 +271,13 @@ void desktop_draw_app_menu(DesktopState* ds) {
|
||||
int mx = ds->mouse.x;
|
||||
int my = ds->mouse.y;
|
||||
int iy = menu_y + 5;
|
||||
int cur_cat = -1;
|
||||
bool cat_expanded = true;
|
||||
|
||||
for (int i = 0; i < menu_row_count; i++) {
|
||||
const MenuRow& row = menu_rows[i];
|
||||
|
||||
if (row.is_category) cur_cat++;
|
||||
if (!menu_row_visible(i)) continue;
|
||||
if (row.is_category) cat_expanded = row.expanded;
|
||||
else if (!cat_expanded) continue;
|
||||
|
||||
int row_h = menu_row_height(row);
|
||||
|
||||
@@ -297,7 +297,7 @@ void desktop_draw_app_menu(DesktopState* ds) {
|
||||
Color::from_rgb(0xE8, 0xE8, 0xE8));
|
||||
|
||||
// Arrow indicator: > for collapsed, v for expanded
|
||||
bool expanded = (cur_cat >= 0 && cur_cat < MENU_NUM_CATS) && menu_cat_expanded[cur_cat];
|
||||
bool expanded = row.expanded;
|
||||
int ax = menu_x + 10;
|
||||
int ay = iy + row_h / 2;
|
||||
Color arrow_color = Color::from_rgb(0x88, 0x88, 0x88);
|
||||
|
||||
Reference in new issue
Block a user