/* * apps_common.hpp * Shared inline utilities and forward declarations for desktop apps * Copyright (c) 2026 Daniel Hammer */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include // Placement new for freestanding environment inline void* operator new(unsigned long, void* p) { return p; } using namespace gui; // ============================================================================ // Minimal snprintf // ============================================================================ using va_list = __builtin_va_list; #define va_start __builtin_va_start #define va_end __builtin_va_end #define va_arg __builtin_va_arg struct PfState { char* buf; int pos; int max; }; inline void pf_putc(PfState* st, char c) { if (st->pos < st->max) st->buf[st->pos] = c; st->pos++; } inline void pf_putnum(PfState* st, unsigned long val, int base, int width, char pad, int neg) { char tmp[24]; int i = 0; const char* digits = "0123456789abcdef"; if (val == 0) { tmp[i++] = '0'; } else { while (val > 0) { tmp[i++] = digits[val % base]; val /= base; } } int total = (neg ? 1 : 0) + i; if (neg && pad == '0') pf_putc(st, '-'); for (int w = total; w < width; w++) pf_putc(st, pad); if (neg && pad != '0') pf_putc(st, '-'); while (i > 0) pf_putc(st, tmp[--i]); } inline int snprintf(char* buf, int size, const char* fmt, ...) { va_list ap; va_start(ap, fmt); PfState st; st.buf = buf; st.pos = 0; st.max = size > 0 ? size - 1 : 0; while (*fmt) { if (*fmt != '%') { pf_putc(&st, *fmt++); continue; } fmt++; char pad = ' '; if (*fmt == '0') { pad = '0'; fmt++; } int width = 0; while (*fmt >= '0' && *fmt <= '9') { width = width * 10 + (*fmt - '0'); fmt++; } if (*fmt == 'l') fmt++; switch (*fmt) { case 'd': case 'i': { long val = va_arg(ap, int); int neg = 0; unsigned long uval; if (val < 0) { neg = 1; uval = (unsigned long)(-val); } else uval = (unsigned long)val; pf_putnum(&st, uval, 10, width, pad, neg); break; } case 'u': { unsigned val = va_arg(ap, unsigned); pf_putnum(&st, val, 10, width, pad, 0); break; } case 'x': { unsigned val = va_arg(ap, unsigned); pf_putnum(&st, val, 16, width, pad, 0); break; } case 's': { const char* s = va_arg(ap, const char*); if (!s) s = "(null)"; int slen = 0; while (s[slen]) slen++; for (int w = slen; w < width; w++) pf_putc(&st, ' '); for (int j = 0; j < slen; j++) pf_putc(&st, s[j]); break; } case 'c': { char c = (char)va_arg(ap, int); pf_putc(&st, c); break; } case '%': pf_putc(&st, '%'); break; default: pf_putc(&st, '%'); pf_putc(&st, *fmt); break; } if (*fmt) fmt++; } if (size > 0) { if (st.pos < size) st.buf[st.pos] = '\0'; else st.buf[size - 1] = '\0'; } va_end(ap); return st.pos; } // ============================================================================ // String helpers // ============================================================================ inline void str_append(char* dst, const char* src, int max) { int len = montauk::slen(dst); int i = 0; while (src[i] && len < max - 1) { dst[len++] = src[i++]; } dst[len] = '\0'; } inline int str_compare_ci(const char* a, const char* b) { while (*a && *b) { char ca = (*a >= 'A' && *a <= 'Z') ? (*a + 32) : *a; char cb = (*b >= 'A' && *b <= 'Z') ? (*b + 32) : *b; if (ca != cb) return ca - cb; a++; b++; } return (unsigned char)*a - (unsigned char)*b; } // ============================================================================ // Network formatting helpers // ============================================================================ inline void format_ip(char* buf, uint32_t ip) { snprintf(buf, 20, "%d.%d.%d.%d", (int)(ip & 0xFF), (int)((ip >> 8) & 0xFF), (int)((ip >> 16) & 0xFF), (int)((ip >> 24) & 0xFF)); } inline void format_mac(char* buf, const uint8_t* mac) { snprintf(buf, 20, "%02x:%02x:%02x:%02x:%02x:%02x", (unsigned)mac[0], (unsigned)mac[1], (unsigned)mac[2], (unsigned)mac[3], (unsigned)mac[4], (unsigned)mac[5]); } // ============================================================================ // File size formatting // ============================================================================ inline void format_size(char* buf, uint64_t size) { // Pick the largest unit that keeps the integer part below 1024, then show // one decimal place for small values. 64-bit throughout: no 2 GiB overflow. static const char* const units[] = { "B", "KB", "MB", "GB", "TB", "PB" }; if (size < 1024) { snprintf(buf, 16, "%d B", (int)size); return; } int unit = 0; uint64_t scaled = size; uint64_t rem = 0; while (scaled >= 1024 && unit < 5) { rem = scaled % 1024; scaled /= 1024; unit++; } int whole = (int)scaled; int frac = (int)((rem * 10) / 1024); if (whole < 10) { snprintf(buf, 16, "%d.%d %s", whole, frac, units[unit]); } else { snprintf(buf, 16, "%d %s", whole, units[unit]); } } // ============================================================================ // Desktop builtins // ============================================================================ enum DesktopBuiltinId : int { DESKTOP_BUILTIN_NONE = -1, DESKTOP_BUILTIN_FILES = 1, DESKTOP_BUILTIN_DESKTOP_SETTINGS = 11, DESKTOP_BUILTIN_REBOOT = 12, DESKTOP_BUILTIN_SHUTDOWN = 14, DESKTOP_BUILTIN_LOG_OUT = 16, DESKTOP_BUILTIN_LOCK_SCREEN = 17, DESKTOP_BUILTIN_SLEEP = 18, DESKTOP_BUILTIN_USER_MANAGEMENT = 19, DESKTOP_BUILTIN_SYSTEM_CONFIGURATION = 20, }; struct DesktopBuiltinEntry { DesktopBuiltinId id; const char* label; int launcher_category; bool launcher_footer; const char* system_configuration_id; const char* icon_path; }; const DesktopBuiltinEntry* desktop_builtin_registry(int* count); const DesktopBuiltinEntry* desktop_builtin_entry(DesktopBuiltinId id); 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); // ============================================================================ // Forward declarations for desktop launch entry points // ============================================================================ void open_terminal(DesktopState* ds); void open_filemanager(DesktopState* ds); void open_filemanager_path(DesktopState* ds, const char* path); void open_system_configuration(DesktopState* ds); void ensure_filemanager_icons_loaded(DesktopState* ds); void open_calculator(DesktopState* ds); void open_texteditor(DesktopState* ds); void open_klog(DesktopState* ds); void open_settings(DesktopState* ds); void open_user_manager(DesktopState* ds); void open_reboot_dialog(DesktopState* ds); void open_wordprocessor(DesktopState* ds); void open_shutdown_dialog(DesktopState* ds); void open_sleep_dialog(DesktopState* ds); // Hand a graceful power-off request to login.elf and exit the desktop so the // user returns to the login screen, where the shutdown stages run (Bluetooth // teardown, filesystem flush) before the final ACPI power-off / reset. Pass // montauk::abi::POWER_REQ_SHUTDOWN or montauk::abi::POWER_REQ_REBOOT. [[noreturn]] inline void desktop_request_power(int action) { montauk::power_request(action); montauk::exit(0); } bool desktop_poll_external_windows(DesktopState* ds);