Files
MontaukOS/programs/src/desktop/desktop_internal.hpp
T

221 lines
7.6 KiB
C++

/*
* desktop_internal.hpp
* Shared declarations for desktop source files
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include "apps/apps_common.hpp"
#include "wallpaper.hpp"
#include <gui/mtk.hpp>
#include <montauk/toml.h>
// ============================================================================
// Desktop Background Context Menu
// ============================================================================
enum DesktopCtxItem : int {
DESKTOP_CTX_TERMINAL = 0,
DESKTOP_CTX_FILES,
DESKTOP_CTX_SETTINGS,
DESKTOP_CTX_SLEEP,
DESKTOP_CTX_REBOOT,
DESKTOP_CTX_SHUTDOWN,
DESKTOP_CTX_COUNT,
};
static constexpr int DESKTOP_CTX_MENU_W = 160;
static constexpr int DESKTOP_CTX_ITEM_H = 28;
inline void desktop_ctx_menu_items(gui::mtk::ContextMenuItem items[DESKTOP_CTX_COUNT]) {
items[DESKTOP_CTX_TERMINAL] = {"Terminal", DESKTOP_CTX_TERMINAL, true};
items[DESKTOP_CTX_FILES] = {"Files", DESKTOP_CTX_FILES, true};
items[DESKTOP_CTX_SETTINGS] = {"Settings", DESKTOP_CTX_SETTINGS, true};
items[DESKTOP_CTX_SLEEP] = {"Sleep", DESKTOP_CTX_SLEEP, true};
items[DESKTOP_CTX_REBOOT] = {"Reboot", DESKTOP_CTX_REBOOT, true};
items[DESKTOP_CTX_SHUTDOWN] = {"Shutdown", DESKTOP_CTX_SHUTDOWN, true};
}
// ============================================================================
// App Menu Data (dynamic — built at startup from embedded + external apps)
// ============================================================================
static constexpr int MENU_W = 220;
static constexpr int MENU_ITEM_H = 36;
static constexpr int MENU_CAT_H = 32;
static constexpr int MENU_DIV_H = 10;
struct MenuRow {
bool is_category;
char label[48];
DesktopBuiltinId app_id; // desktop builtin ID, or DESKTOP_BUILTIN_NONE for categories/dividers
bool external; // true = spawn binary_path
char binary_path[128]; // full VFS path for external apps
bool launch_with_home; // true = pass home_dir as first argument
SvgIcon* icon; // loaded menu icon (null for categories/dividers)
};
inline MenuRow* menu_rows = nullptr;
inline int menu_row_count = 0;
inline int menu_row_capacity = 0;
// Return the next menu row, doubling the array as needed.
// Returns nullptr if allocation failed.
inline MenuRow* menu_alloc_row() {
if (menu_row_count >= menu_row_capacity) {
int new_cap = menu_row_capacity ? menu_row_capacity * 2 : 64;
auto* grown = (MenuRow*)montauk::realloc(
menu_rows, (uint64_t)new_cap * sizeof(MenuRow));
if (!grown) return nullptr;
menu_rows = grown;
menu_row_capacity = new_cap;
}
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;
}
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];
}
inline int menu_row_height(const MenuRow& row) {
if (!row.is_category) return MENU_ITEM_H;
return row.label[0] ? MENU_CAT_H : MENU_DIV_H;
}
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;
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);
}
return h;
}
// ============================================================================
// Menu Builder Helpers
// ============================================================================
inline int menu_add_category(const char* label) {
MenuRow* rp = menu_alloc_row();
if (!rp) return -1;
MenuRow& r = *rp;
r.is_category = true;
montauk::strncpy(r.label, label, sizeof(r.label));
r.app_id = DESKTOP_BUILTIN_NONE;
r.external = false;
r.binary_path[0] = '\0';
r.launch_with_home = false;
r.icon = nullptr;
return menu_row_count - 1;
}
inline int menu_add_embedded(const char* label, DesktopBuiltinId app_id, SvgIcon* icon) {
MenuRow* rp = menu_alloc_row();
if (!rp) return -1;
MenuRow& r = *rp;
r.is_category = false;
montauk::strncpy(r.label, label, sizeof(r.label));
r.app_id = app_id;
r.external = false;
r.binary_path[0] = '\0';
r.launch_with_home = false;
r.icon = icon;
return menu_row_count - 1;
}
inline int menu_add_external(const char* label, const char* binary, SvgIcon* icon, bool launch_with_home) {
MenuRow* rp = menu_alloc_row();
if (!rp) return -1;
MenuRow& r = *rp;
r.is_category = false;
montauk::strncpy(r.label, label, sizeof(r.label));
r.app_id = DESKTOP_BUILTIN_NONE;
r.external = true;
montauk::strncpy(r.binary_path, binary, sizeof(r.binary_path));
r.launch_with_home = launch_with_home;
r.icon = icon;
return menu_row_count - 1;
}
// ============================================================================
// Forward Declarations (internal functions)
// ============================================================================
inline bool desktop_window_fullscreen(const gui::Window* win) {
return win && win->external && (win->ext_flags & montauk::abi::WIN_FLAG_FULLSCREEN);
}
inline gui::Rect desktop_content_rect(const gui::Window* win) {
return desktop_window_fullscreen(win)
? win->frame
: win->content_rect();
}
// window.cpp
gui::ResizeEdge hit_test_resize_edge(const gui::Rect& f, int mx, int my);
gui::CursorStyle cursor_for_edge(gui::ResizeEdge edge);
// panel.cpp
void desktop_draw_app_menu(gui::DesktopState* ds);
void desktop_draw_net_popup(gui::DesktopState* ds);
void desktop_draw_vol_popup(gui::DesktopState* ds);
const montauk::abi::NetIfInfo* desktop_eth_iface(const gui::DesktopState* ds);
bool desktop_eth_online(const gui::DesktopState* ds);
// wifi.cpp
void desktop_wifi_init(gui::DesktopState* ds);
bool desktop_wifi_poll(gui::DesktopState* ds, uint64_t now);
void desktop_draw_wifi_popup(gui::DesktopState* ds);
bool desktop_wifi_handle_mouse(gui::DesktopState* ds, int mx, int my,
bool left_pressed, int scroll);
// compose.cpp
void desktop_draw_lock_screen(gui::DesktopState* ds);
void desktop_mark_background_dirty(gui::DesktopState* ds);
// main.cpp
void desktop_refresh_netifs(gui::DesktopState* ds);
void desktop_scan_apps(gui::DesktopState* ds);
void desktop_build_menu(gui::DesktopState* ds);
void desktop_open_launcher(gui::DesktopState* ds);
void desktop_close_launcher(gui::DesktopState* ds);
// Month names (shared by panel clock)
inline const char* month_names[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
// launcher.cpp
void desktop_init_launcher(gui::DesktopState* ds);
bool desktop_handle_launcher_keyboard(gui::DesktopState* ds, const montauk::abi::KeyEvent& key);
void desktop_handle_launcher_mouse(gui::DesktopState* ds);
void desktop_draw_launcher(gui::DesktopState* ds);
uint64_t desktop_launcher_blink_token(const gui::DesktopState* ds, uint64_t now);