feat: multi-user system, bug fixes, security & performance fixes, and more

This commit is contained in:
2026-03-14 13:28:46 +01:00
parent 576ad34f95
commit 261b536041
389 changed files with 231853 additions and 591 deletions
+247 -11
View File
@@ -5,8 +5,133 @@
*/
#include "desktop_internal.hpp"
#include <montauk/user.h>
// ============================================================================
// Lock Screen Input
// ============================================================================
static void lock_screen(DesktopState* ds) {
ds->screen_locked = true;
ds->lock_password[0] = '\0';
ds->lock_password_len = 0;
ds->lock_error[0] = '\0';
ds->lock_show_error = false;
ds->app_menu_open = false;
ds->ctx_menu_open = false;
ds->net_popup_open = false;
ds->vol_popup_open = false;
// Cache display name for lock screen rendering
montauk::strncpy(ds->lock_display_name, ds->current_user, sizeof(ds->lock_display_name));
montauk::user::UserInfo users[16];
int count = montauk::user::load_users(users, 16);
for (int i = 0; i < count; i++) {
if (montauk::streq(users[i].username, ds->current_user)) {
if (users[i].display_name[0])
montauk::strncpy(ds->lock_display_name, users[i].display_name, sizeof(ds->lock_display_name));
break;
}
}
}
static bool try_unlock(DesktopState* ds) {
ds->lock_show_error = false;
if (montauk::user::authenticate(ds->current_user, ds->lock_password)) {
ds->screen_locked = false;
ds->lock_password[0] = '\0';
ds->lock_password_len = 0;
return true;
}
montauk::strcpy(ds->lock_error, "Incorrect password");
ds->lock_show_error = true;
ds->lock_password[0] = '\0';
ds->lock_password_len = 0;
return false;
}
static void handle_lock_mouse(DesktopState* ds) {
int mx = ds->mouse.x;
int my = ds->mouse.y;
uint8_t buttons = ds->mouse.buttons;
uint8_t prev = ds->prev_buttons;
bool left_pressed = (buttons & 0x01) && !(prev & 0x01);
if (!left_pressed) return;
int sfh = system_font_height();
int card_w = 360;
int content_w = card_w - 48;
int field_h = 36;
int btn_h = 40;
// Calculate card layout to find button position
int error_h = ds->lock_show_error ? sfh + 8 : 0;
int card_h = 20 + sfh + 16 + sfh + 12 + sfh + 4 + field_h + 16 + btn_h + error_h + 20;
int card_x = (ds->screen_w - card_w) / 2;
int card_y = (ds->screen_h - card_h) / 2;
int x = card_x + 24;
// Walk through the layout to find the Unlock button y position
int y = card_y + 20;
y += sfh + 16; // title
y += sfh + 12; // username
y += sfh + 4; // "Password" label
y += field_h + 16; // field + gap
// Check Unlock button
if (mx >= x && mx < x + content_w && my >= y && my < y + btn_h) {
try_unlock(ds);
return;
}
// Check password field click (just keep focus, nothing else to switch to)
int field_y = y - field_h - 16;
if (mx >= x && mx < x + content_w && my >= field_y && my < field_y + field_h) {
ds->lock_show_error = false;
}
}
static void handle_lock_keyboard(DesktopState* ds, const Montauk::KeyEvent& key) {
if (!key.pressed) return;
// Enter submits
if (key.ascii == '\n' || key.ascii == '\r') {
try_unlock(ds);
return;
}
// Backspace
if (key.ascii == '\b' || key.scancode == 0x0E) {
if (ds->lock_password_len > 0) {
ds->lock_password_len--;
ds->lock_password[ds->lock_password_len] = '\0';
}
return;
}
// Printable characters
if (key.ascii >= 0x20 && key.ascii < 0x7F) {
if (ds->lock_password_len < 63) {
ds->lock_password[ds->lock_password_len] = key.ascii;
ds->lock_password_len++;
ds->lock_password[ds->lock_password_len] = '\0';
}
}
}
// ============================================================================
// Desktop Mouse Handling
// ============================================================================
void gui::desktop_handle_mouse(DesktopState* ds) {
if (ds->screen_locked) {
handle_lock_mouse(ds);
return;
}
int mx = ds->mouse.x;
int my = ds->mouse.y;
uint8_t buttons = ds->mouse.buttons;
@@ -213,8 +338,8 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
menu_cat_expanded[cur_cat] = !menu_cat_expanded[cur_cat];
} else if (!row.is_category) {
if (row.external) {
// Launch external app from manifest
montauk::spawn(row.binary_path);
// Launch external app with user's home dir
montauk::spawn(row.binary_path, ds->home_dir);
} else {
// Dispatch embedded app
switch (row.app_id) {
@@ -230,6 +355,8 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
case 12: open_reboot_dialog(ds); break;
case 14: open_shutdown_dialog(ds); break;
case 15: open_wordprocessor(ds); break;
case 16: montauk::exit(0); break; // Log Out
case 17: lock_screen(ds); break; // Lock Screen
}
}
ds->app_menu_open = false;
@@ -244,10 +371,104 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
}
}
// Handle volume popup interaction
if (ds->vol_popup_open) {
int popup_x = ds->vol_icon_rect.x + ds->vol_icon_rect.w - 200;
int popup_y = PANEL_HEIGHT + 2;
if (popup_x < 4) popup_x = 4;
Rect vol_rect = {popup_x, popup_y, 200, 120};
// Handle drag continuity
if (ds->vol_dragging) {
if (left_held) {
int slider_abs_x = popup_x + 16;
int v = ((mx - slider_abs_x) * 100) / (200 - 32);
if (v < 0) v = 0;
if (v > 100) v = 100;
ds->vol_muted = false;
ds->vol_level = v;
montauk::audio_set_volume(0, v);
return;
}
if (left_released) {
ds->vol_dragging = false;
}
}
if (left_pressed) {
if (vol_rect.contains(mx, my)) {
// Slider area (y = popup_y + 56, height = 8, with generous hit zone)
int slider_abs_x = popup_x + 16;
int slider_abs_y = popup_y + 56;
int slider_w = 200 - 32;
if (my >= slider_abs_y - 10 && my <= slider_abs_y + 8 + 10 &&
mx >= slider_abs_x - 8 && mx <= slider_abs_x + slider_w + 8) {
int v = ((mx - slider_abs_x) * 100) / slider_w;
if (v < 0) v = 0;
if (v > 100) v = 100;
ds->vol_muted = false;
ds->vol_level = v;
montauk::audio_set_volume(0, v);
ds->vol_dragging = true;
return;
}
// Buttons (y = popup_y + 78, h = 24)
int btn_h = 24;
int btn_y = popup_y + 78;
int minus_w = 36, plus_w = 36, mute_w = 50, gap = 8;
int total_w = minus_w + plus_w + mute_w + gap * 2;
int bx = popup_x + (200 - total_w) / 2;
if (my >= btn_y && my < btn_y + btn_h) {
// [-]
if (mx >= bx && mx < bx + minus_w) {
ds->vol_muted = false;
int v = ds->vol_level - 5;
if (v < 0) v = 0;
ds->vol_level = v;
montauk::audio_set_volume(0, v);
return;
}
bx += minus_w + gap;
// [+]
if (mx >= bx && mx < bx + plus_w) {
ds->vol_muted = false;
int v = ds->vol_level + 5;
if (v > 100) v = 100;
ds->vol_level = v;
montauk::audio_set_volume(0, v);
return;
}
bx += plus_w + gap;
// [Mute]
if (mx >= bx && mx < bx + mute_w) {
if (ds->vol_muted) {
ds->vol_muted = false;
montauk::audio_set_volume(0, ds->vol_pre_mute);
ds->vol_level = ds->vol_pre_mute;
} else {
ds->vol_pre_mute = ds->vol_level;
ds->vol_muted = true;
montauk::audio_set_volume(0, 0);
}
return;
}
}
return; // click inside popup but not on any control
} else if (!ds->vol_icon_rect.contains(mx, my)) {
ds->vol_popup_open = false;
ds->vol_dragging = false;
}
}
}
// Handle net popup clicks
if (ds->net_popup_open && left_pressed) {
int popup_w = 220;
int popup_h = 130;
int fh_net = system_font_height();
int row_h_net = fh_net + 8;
int popup_h = (row_h_net + 8) + row_h_net * 5 + 12;
int popup_x = ds->net_icon_rect.x + ds->net_icon_rect.w - popup_w;
int popup_y = PANEL_HEIGHT + 2;
if (popup_x < 4) popup_x = 4;
@@ -266,6 +487,17 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
if (mx < 36) {
ds->app_menu_open = !ds->app_menu_open;
ds->net_popup_open = false;
ds->vol_popup_open = false;
ds->ctx_menu_open = false;
return;
}
// Volume icon
if (ds->vol_icon_rect.w > 0 && ds->vol_icon_rect.contains(mx, my)) {
ds->vol_popup_open = !ds->vol_popup_open;
ds->vol_dragging = false;
ds->app_menu_open = false;
ds->net_popup_open = false;
ds->ctx_menu_open = false;
return;
}
@@ -274,6 +506,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
if (ds->net_icon_rect.w > 0 && ds->net_icon_rect.contains(mx, my)) {
ds->net_popup_open = !ds->net_popup_open;
ds->app_menu_open = false;
ds->vol_popup_open = false;
ds->ctx_menu_open = false;
return;
}
@@ -369,11 +602,6 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
if (win->state != WIN_MAXIMIZED) {
ResizeEdge edge = hit_test_resize_edge(win->frame, mx, my);
if (edge != RESIZE_NONE) {
win->resizing = true;
win->resize_edge = edge;
win->resize_start_frame = win->frame;
win->resize_start_mx = mx;
win->resize_start_my = my;
desktop_raise_window(ds, i);
int new_idx = ds->window_count - 1;
ds->windows[new_idx].resizing = true;
@@ -388,9 +616,6 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
// Check titlebar (start drag)
Rect tb = win->titlebar_rect();
if (tb.contains(mx, my)) {
win->dragging = true;
win->drag_offset_x = mx - win->frame.x;
win->drag_offset_y = my - win->frame.y;
desktop_raise_window(ds, i);
int new_idx = ds->window_count - 1;
ds->windows[new_idx].dragging = true;
@@ -433,6 +658,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
ds->app_menu_open = false;
ds->ctx_menu_open = false;
ds->vol_popup_open = false;
}
// Forward continuous mouse events to focused window (hover, drag, release)
@@ -499,13 +725,23 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
ds->ctx_menu_y = my;
ds->app_menu_open = false;
ds->net_popup_open = false;
ds->vol_popup_open = false;
}
}
}
void gui::desktop_handle_keyboard(DesktopState* ds, const Montauk::KeyEvent& key) {
if (ds->screen_locked) {
handle_lock_keyboard(ds, key);
return;
}
// Global shortcuts (only on key press)
if (key.pressed && key.ctrl && key.alt) {
if (key.ascii == 'l' || key.ascii == 'L') {
lock_screen(ds);
return;
}
if (key.ascii == 't' || key.ascii == 'T') {
open_terminal(ds);
return;