From 0e1601be74068e7efb3fda165c3632a4aaaab032 Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Fri, 7 Aug 2026 10:55:38 +0200 Subject: [PATCH] feat: desktop - use MTK menu for desktop right-click menu --- kernel/src/Api/BuildNo.hpp | 2 +- programs/include/gui/desktop.hpp | 5 +- programs/include/gui/mtk/widgets.hpp | 4 +- programs/src/desktop/compose.cpp | 57 +++------------- programs/src/desktop/desktop_builtin.cpp | 2 +- programs/src/desktop/desktop_internal.hpp | 27 ++++++++ programs/src/desktop/input.cpp | 79 +++++++++++------------ programs/src/desktop/launcher.cpp | 2 +- programs/src/desktop/main.cpp | 4 +- 9 files changed, 83 insertions(+), 99 deletions(-) diff --git a/kernel/src/Api/BuildNo.hpp b/kernel/src/Api/BuildNo.hpp index 99f8f8a..5edc9c2 100644 --- a/kernel/src/Api/BuildNo.hpp +++ b/kernel/src/Api/BuildNo.hpp @@ -12,4 +12,4 @@ #pragma once -#define MONTAUK_BUILD_NUMBER 84 +#define MONTAUK_BUILD_NUMBER 87 diff --git a/programs/include/gui/desktop.hpp b/programs/include/gui/desktop.hpp index f530362..dac778a 100644 --- a/programs/include/gui/desktop.hpp +++ b/programs/include/gui/desktop.hpp @@ -10,6 +10,7 @@ #include "gui/svg.hpp" #include "gui/window.hpp" #include "gui/widgets.hpp" +#include "gui/mtk/widgets.hpp" #include "gui/terminal.hpp" #include @@ -172,8 +173,8 @@ struct DesktopState { int desktop_item_count; int desktop_item_capacity; - bool ctx_menu_open; - int ctx_menu_x, ctx_menu_y; + // Right-click menu on the desktop background (MTK context menu). + mtk::ContextMenuState ctx_menu; bool net_popup_open; montauk::abi::NetCfg cached_net_cfg; diff --git a/programs/include/gui/mtk/widgets.hpp b/programs/include/gui/mtk/widgets.hpp index b3effcc..1b71e4c 100644 --- a/programs/include/gui/mtk/widgets.hpp +++ b/programs/include/gui/mtk/widgets.hpp @@ -210,8 +210,8 @@ inline void draw_context_menu(Canvas& c, Rect menu = context_menu_rect(state, item_count, c.w, c.h, menu_w, item_h); - c.fill_rect(menu.x + 2, menu.y + 2, menu.w, menu.h, - Color::from_rgb(0x80, 0x80, 0x80)); + c.fill_rounded_rect(menu.x + 2, menu.y + 2, menu.w, menu.h, 4, + Color::from_rgb(0x80, 0x80, 0x80)); c.fill_rounded_rect(menu.x, menu.y, menu.w, menu.h, 4, colors::MENU_BG); c.rect(menu.x, menu.y, menu.w, menu.h, theme.border); diff --git a/programs/src/desktop/compose.cpp b/programs/src/desktop/compose.cpp index 1af49be..6962e06 100644 --- a/programs/src/desktop/compose.cpp +++ b/programs/src/desktop/compose.cpp @@ -274,55 +274,16 @@ void gui::desktop_compose(DesktopState* ds) { } // Draw right-click context menu if open - if (ds->ctx_menu_open) { - static constexpr int CTX_MENU_W = 180; - static constexpr int CTX_ITEM_H = 36; - static constexpr int CTX_ITEM_COUNT = 6; - int cmx = ds->ctx_menu_x; - int cmy = ds->ctx_menu_y; - int cmh = CTX_ITEM_H * CTX_ITEM_COUNT + 8; + if (ds->ctx_menu.open) { + gui::mtk::ContextMenuItem ctx_items[DESKTOP_CTX_COUNT]; + desktop_ctx_menu_items(ctx_items); - // Clamp to screen - if (cmx + CTX_MENU_W > sw) cmx = sw - CTX_MENU_W; - if (cmy + cmh > sh) cmy = sh - cmh; - - ensure_filemanager_icons_loaded(ds); - - draw_shadow(fb, cmx, cmy, CTX_MENU_W, cmh, 4, colors::SHADOW); - fill_rounded_rect(fb, cmx, cmy, CTX_MENU_W, cmh, 8, colors::MENU_BG); - draw_rect(fb, cmx, cmy, CTX_MENU_W, cmh, colors::BORDER); - - struct CtxItem { const char* label; SvgIcon* icon; }; - CtxItem ctx_items[CTX_ITEM_COUNT] = { - { "Terminal", &ds->icon_terminal }, - { "Files", &ds->icon_filemanager }, - { "Settings", &ds->icon_system_configuration_menu }, - { "Sleep", &ds->icon_sleep }, - { "Reboot", &ds->icon_reboot }, - { "Shutdown", &ds->icon_shutdown }, - }; - - int mmx = ds->mouse.x; - int mmy = ds->mouse.y; - - for (int i = 0; i < CTX_ITEM_COUNT; i++) { - int iy = cmy + 4 + i * CTX_ITEM_H; - Rect item_r = {cmx + 4, iy, CTX_MENU_W - 8, CTX_ITEM_H}; - - if (item_r.contains(mmx, mmy)) { - fill_rounded_rect(fb, item_r.x, item_r.y, item_r.w, item_r.h, 4, gui::mtk::accent_hover_tint(ds->settings.accent_color)); - } - - int icon_x = item_r.x + 8; - int icon_y = item_r.y + (CTX_ITEM_H - 20) / 2; - if (ctx_items[i].icon && ctx_items[i].icon->pixels) { - fb.blit_alpha(icon_x, icon_y, ctx_items[i].icon->width, ctx_items[i].icon->height, ctx_items[i].icon->pixels); - } - - int tx = icon_x + 28; - int ty = item_r.y + (CTX_ITEM_H - system_font_height()) / 2; - draw_text(fb, tx, ty, ctx_items[i].label, colors::TEXT_COLOR); - } + // The compositor draws straight into the back buffer; wrap it in a + // Canvas so the shared MTK widget can render it. + Canvas c(fb.buffer(), fb.pitch() / 4, sh); + gui::mtk::Theme theme = gui::mtk::make_theme(ds->settings.accent_color); + gui::mtk::draw_context_menu(c, ds->ctx_menu, ctx_items, DESKTOP_CTX_COUNT, + theme, DESKTOP_CTX_MENU_W, DESKTOP_CTX_ITEM_H); } if (ds->launcher_open) { diff --git a/programs/src/desktop/desktop_builtin.cpp b/programs/src/desktop/desktop_builtin.cpp index e34ec60..03f90e8 100644 --- a/programs/src/desktop/desktop_builtin.cpp +++ b/programs/src/desktop/desktop_builtin.cpp @@ -64,7 +64,7 @@ void desktop_lock_screen(DesktopState* ds) { ds->lock_show_error = false; ds->app_menu_open = false; desktop_close_launcher(ds); - ds->ctx_menu_open = false; + gui::mtk::context_menu_close(ds->ctx_menu); ds->net_popup_open = false; ds->wifi_popup_open = false; ds->vol_popup_open = false; diff --git a/programs/src/desktop/desktop_internal.hpp b/programs/src/desktop/desktop_internal.hpp index c65c2cd..a7dd5ce 100644 --- a/programs/src/desktop/desktop_internal.hpp +++ b/programs/src/desktop/desktop_internal.hpp @@ -8,8 +8,35 @@ #include "apps/apps_common.hpp" #include "wallpaper.hpp" +#include #include +// ============================================================================ +// 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) // ============================================================================ diff --git a/programs/src/desktop/input.cpp b/programs/src/desktop/input.cpp index 1dbb6b0..655ef05 100644 --- a/programs/src/desktop/input.cpp +++ b/programs/src/desktop/input.cpp @@ -163,7 +163,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) { if (route_fullscreen_external_mouse(ds, ev, mx, my, buttons, prev)) { ds->app_menu_open = false; - ds->ctx_menu_open = false; + gui::mtk::context_menu_close(ds->ctx_menu); ds->vol_popup_open = false; ds->net_popup_open = false; ds->wifi_popup_open = false; @@ -176,41 +176,33 @@ void gui::desktop_handle_mouse(DesktopState* ds) { } // Handle context menu clicks - if (ds->ctx_menu_open) { - if (left_pressed) { - static constexpr int CTX_MENU_W = 180; - static constexpr int CTX_ITEM_H = 36; - static constexpr int CTX_ITEM_COUNT = 6; - int cmx = ds->ctx_menu_x; - int cmy = ds->ctx_menu_y; - int cmh = CTX_ITEM_H * CTX_ITEM_COUNT + 8; - if (cmx + CTX_MENU_W > ds->screen_w) cmx = ds->screen_w - CTX_MENU_W; - if (cmy + cmh > ds->screen_h) cmy = ds->screen_h - cmh; + if (ds->ctx_menu.open) { + gui::mtk::ContextMenuItem ctx_items[DESKTOP_CTX_COUNT]; + desktop_ctx_menu_items(ctx_items); + int action = gui::mtk::context_menu_handle_mouse( + ds->ctx_menu, ctx_items, DESKTOP_CTX_COUNT, mx, my, buttons, prev, + ds->screen_w, ds->screen_h, DESKTOP_CTX_MENU_W, DESKTOP_CTX_ITEM_H); - Rect ctx_rect = {cmx, cmy, CTX_MENU_W, cmh}; - if (ctx_rect.contains(mx, my)) { - int rel_y = my - cmy - 4; - int item_idx = rel_y / CTX_ITEM_H; - if (item_idx >= 0 && item_idx < CTX_ITEM_COUNT) { - ds->ctx_menu_open = false; - switch (item_idx) { - case 0: open_terminal(ds); break; - case 1: open_filemanager(ds); break; - case 2: desktop_launch_builtin(ds, DESKTOP_BUILTIN_SYSTEM_CONFIGURATION); break; - case 3: desktop_launch_builtin(ds, DESKTOP_BUILTIN_SLEEP); break; - case 4: desktop_launch_builtin(ds, DESKTOP_BUILTIN_REBOOT); break; - case 5: desktop_launch_builtin(ds, DESKTOP_BUILTIN_SHUTDOWN); break; - } - return; - } - } - ds->ctx_menu_open = false; + switch (action) { + case DESKTOP_CTX_TERMINAL: open_terminal(ds); return; + case DESKTOP_CTX_FILES: open_filemanager(ds); return; + case DESKTOP_CTX_SETTINGS: + desktop_launch_builtin(ds, DESKTOP_BUILTIN_SYSTEM_CONFIGURATION); return; - } - if (right_pressed) { - ds->ctx_menu_open = false; + case DESKTOP_CTX_SLEEP: + desktop_launch_builtin(ds, DESKTOP_BUILTIN_SLEEP); return; + case DESKTOP_CTX_REBOOT: + desktop_launch_builtin(ds, DESKTOP_BUILTIN_REBOOT); + return; + case DESKTOP_CTX_SHUTDOWN: + desktop_launch_builtin(ds, DESKTOP_BUILTIN_SHUTDOWN); + return; + default: break; } + // A click outside the menu just dismisses it; plain motion (CONSUMED) + // falls through so window hover and drags keep working. + if (action == gui::mtk::CONTEXT_MENU_DISMISSED) return; } // Check for ongoing window drags first @@ -542,7 +534,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) { ds->net_popup_open = false; ds->wifi_popup_open = false; ds->vol_popup_open = false; - ds->ctx_menu_open = false; + gui::mtk::context_menu_close(ds->ctx_menu); return; } @@ -553,7 +545,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) { ds->app_menu_open = false; ds->net_popup_open = false; ds->wifi_popup_open = false; - ds->ctx_menu_open = false; + gui::mtk::context_menu_close(ds->ctx_menu); return; } @@ -563,7 +555,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) { ds->app_menu_open = false; ds->vol_popup_open = false; ds->wifi_popup_open = false; - ds->ctx_menu_open = false; + gui::mtk::context_menu_close(ds->ctx_menu); return; } @@ -573,7 +565,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) { ds->app_menu_open = false; ds->vol_popup_open = false; ds->net_popup_open = false; - ds->ctx_menu_open = false; + gui::mtk::context_menu_close(ds->ctx_menu); return; } // Window indicator buttons @@ -725,7 +717,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) { } ds->app_menu_open = false; - ds->ctx_menu_open = false; + gui::mtk::context_menu_close(ds->ctx_menu); ds->vol_popup_open = false; } @@ -792,9 +784,14 @@ void gui::desktop_handle_mouse(DesktopState* ds) { } } if (!on_window) { - ds->ctx_menu_open = true; - ds->ctx_menu_x = mx; - ds->ctx_menu_y = my; + gui::mtk::context_menu_open(ds->ctx_menu, mx, my); + // Pin the menu inside the screen up front so hit-testing and + // drawing agree on where it landed. + Rect r = gui::mtk::context_menu_rect(ds->ctx_menu, DESKTOP_CTX_COUNT, + ds->screen_w, ds->screen_h, + DESKTOP_CTX_MENU_W, DESKTOP_CTX_ITEM_H); + ds->ctx_menu.x = r.x; + ds->ctx_menu.y = r.y; ds->app_menu_open = false; ds->net_popup_open = false; ds->wifi_popup_open = false; @@ -823,7 +820,7 @@ void gui::desktop_handle_keyboard(DesktopState* ds, const montauk::abi::KeyEvent montauk::win_sendevent(win->ext_win_id, &ev); ds->launcher_open = false; ds->app_menu_open = false; - ds->ctx_menu_open = false; + gui::mtk::context_menu_close(ds->ctx_menu); return; } diff --git a/programs/src/desktop/launcher.cpp b/programs/src/desktop/launcher.cpp index b59a4c9..c425b5c 100644 --- a/programs/src/desktop/launcher.cpp +++ b/programs/src/desktop/launcher.cpp @@ -404,7 +404,7 @@ void desktop_open_launcher(DesktopState* ds) { ds->launcher_selected = -1; ds->launcher_scroll = 0; ds->app_menu_open = false; - ds->ctx_menu_open = false; + gui::mtk::context_menu_close(ds->ctx_menu); ds->net_popup_open = false; ds->wifi_popup_open = false; ds->vol_popup_open = false; diff --git a/programs/src/desktop/main.cpp b/programs/src/desktop/main.cpp index 1653aaf..98fb6c5 100644 --- a/programs/src/desktop/main.cpp +++ b/programs/src/desktop/main.cpp @@ -384,9 +384,7 @@ void gui::desktop_init(DesktopState* ds) { montauk::win_setscale(ds->settings.ui_scale); - ds->ctx_menu_open = false; - ds->ctx_menu_x = 0; - ds->ctx_menu_y = 0; + gui::mtk::context_menu_reset(ds->ctx_menu); ds->net_popup_open = false; montauk::get_netcfg(&ds->cached_net_cfg);