feat: screenshot app improvement, WIndow Server supports full-screen overlay, Disks app UI improvements

This commit is contained in:
2026-05-10 10:45:05 +02:00
parent 69fc184a4e
commit 72e4fa080a
29 changed files with 1483 additions and 395 deletions
+3 -1
View File
@@ -30,7 +30,7 @@
#include "Device.hpp" // SYS_DEVLIST, SYS_DISKINFO #include "Device.hpp" // SYS_DEVLIST, SYS_DISKINFO
#include "Input.hpp" // SYS_INPUT_WAIT #include "Input.hpp" // SYS_INPUT_WAIT
#include "Storage.hpp" // SYS_PARTLIST, SYS_DISKREAD, SYS_DISKWRITE #include "Storage.hpp" // SYS_PARTLIST, SYS_DISKREAD, SYS_DISKWRITE
#include "Window.hpp" // SYS_WINCREATE, SYS_WINDESTROY, SYS_WINPRESENT, SYS_WINPOLL, SYS_WINENUM, SYS_WINMAP, SYS_WINSENDEVENT, SYS_WINRESIZE, SYS_WINSETSCALE, SYS_WINGETSCALE #include "Window.hpp" // SYS_WINCREATE, SYS_WINDESTROY, SYS_WINPRESENT, SYS_WINPOLL, SYS_WINENUM, SYS_WINMAP, SYS_WINSENDEVENT, SYS_WINRESIZE, SYS_WINSETCURSOR, SYS_WINSETFLAGS, SYS_WINSETSCALE, SYS_WINGETSCALE
#include "Audio.hpp" // SYS_AUDIOOPEN, SYS_AUDIOCLOSE, SYS_AUDIOWRITE, SYS_AUDIOCTL #include "Audio.hpp" // SYS_AUDIOOPEN, SYS_AUDIOCLOSE, SYS_AUDIOWRITE, SYS_AUDIOCTL
#include "BluetoothSyscall.hpp" // SYS_BTSCAN, SYS_BTCONNECT, SYS_BTDISCONNECT, SYS_BTLIST, SYS_BTINFO #include "BluetoothSyscall.hpp" // SYS_BTSCAN, SYS_BTCONNECT, SYS_BTDISCONNECT, SYS_BTLIST, SYS_BTINFO
#include "IpcSyscall.hpp" // SYS_DUPHANDLE, SYS_WAIT_HANDLE, SYS_STREAM_CREATE, SYS_STREAM_READ, SYS_STREAM_WRITE, SYS_MAILBOX_CREATE, SYS_MAILBOX_SEND, SYS_MAILBOX_RECV, SYS_WAITSET_CREATE, SYS_WAITSET_ADD, SYS_WAITSET_REMOVE, SYS_WAITSET_WAIT, SYS_PROC_OPEN, SYS_SURFACE_CREATE, SYS_SURFACE_MAP, SYS_SURFACE_RESIZE #include "IpcSyscall.hpp" // SYS_DUPHANDLE, SYS_WAIT_HANDLE, SYS_STREAM_CREATE, SYS_STREAM_READ, SYS_STREAM_WRITE, SYS_MAILBOX_CREATE, SYS_MAILBOX_SEND, SYS_MAILBOX_RECV, SYS_WAITSET_CREATE, SYS_WAITSET_ADD, SYS_WAITSET_REMOVE, SYS_WAITSET_WAIT, SYS_PROC_OPEN, SYS_SURFACE_CREATE, SYS_SURFACE_MAP, SYS_SURFACE_RESIZE
@@ -297,6 +297,8 @@ namespace Montauk {
return (int64_t)Sys_WinGetScale(); return (int64_t)Sys_WinGetScale();
case SYS_WINSETCURSOR: case SYS_WINSETCURSOR:
return (int64_t)Sys_WinSetCursor((int)frame->arg1, (int)frame->arg2); return (int64_t)Sys_WinSetCursor((int)frame->arg1, (int)frame->arg2);
case SYS_WINSETFLAGS:
return (int64_t)Sys_WinSetFlags((int)frame->arg1, (uint32_t)frame->arg2);
case SYS_MEMSTATS: case SYS_MEMSTATS:
if (!UserMemory::Writable<MemStats>(frame->arg1)) return -1; if (!UserMemory::Writable<MemStats>(frame->arg1)) return -1;
Sys_MemStats((MemStats*)frame->arg1); Sys_MemStats((MemStats*)frame->arg1);
+4
View File
@@ -129,6 +129,7 @@ namespace Montauk {
static constexpr uint64_t SYS_WINSETSCALE = 65; static constexpr uint64_t SYS_WINSETSCALE = 65;
static constexpr uint64_t SYS_WINGETSCALE = 66; static constexpr uint64_t SYS_WINGETSCALE = 66;
static constexpr uint64_t SYS_WINSETCURSOR = 68; static constexpr uint64_t SYS_WINSETCURSOR = 68;
static constexpr uint64_t SYS_WINSETFLAGS = 126;
/* Process.hpp */ /* Process.hpp */
static constexpr uint64_t SYS_PROCLIST = 61; static constexpr uint64_t SYS_PROCLIST = 61;
@@ -329,8 +330,11 @@ namespace Montauk {
uint8_t dirty; uint8_t dirty;
uint8_t cursor; // 0=arrow, 1=resize_h, 2=resize_v uint8_t cursor; // 0=arrow, 1=resize_h, 2=resize_v
uint8_t _pad[2]; uint8_t _pad[2];
uint32_t flags;
}; };
static constexpr uint32_t WIN_FLAG_FULLSCREEN = 1u << 0;
struct WinCreateResult { struct WinCreateResult {
int32_t id; // -1 on failure int32_t id; // -1 on failure
uint32_t _pad; uint32_t _pad;
+12
View File
@@ -159,6 +159,7 @@ namespace WinServer {
slot.ownerVa = userVa; slot.ownerVa = userVa;
slot.dirty = false; slot.dirty = false;
slot.cursor = 0; slot.cursor = 0;
slot.flags = 0;
int tlen = 0; int tlen = 0;
while (title[tlen] && tlen < 63) { while (title[tlen] && tlen < 63) {
@@ -224,6 +225,7 @@ namespace WinServer {
info.height = g_slots[i].height; info.height = g_slots[i].height;
info.dirty = g_slots[i].dirty ? 1 : 0; info.dirty = g_slots[i].dirty ? 1 : 0;
info.cursor = g_slots[i].cursor; info.cursor = g_slots[i].cursor;
info.flags = g_slots[i].flags;
g_slots[i].dirty = false; g_slots[i].dirty = false;
count++; count++;
} }
@@ -336,6 +338,16 @@ namespace WinServer {
return 0; return 0;
} }
int SetFlags(int windowId, int callerPid, uint32_t flags) {
WsGuard guard;
if (windowId < 0 || windowId >= MaxWindows) return -1;
WindowSlot& slot = g_slots[windowId];
if (!slot.used || slot.ownerPid != callerPid) return -1;
slot.flags = flags & Montauk::WIN_FLAG_FULLSCREEN;
return 0;
}
int SetScale(int scale) { int SetScale(int scale) {
WsGuard guard; WsGuard guard;
if (scale < 0) scale = 0; if (scale < 0) scale = 0;
+2
View File
@@ -24,6 +24,7 @@ namespace WinServer {
uint64_t ownerVa; // mapped VA of liveSurface in owner uint64_t ownerVa; // mapped VA of liveSurface in owner
bool dirty; bool dirty;
uint8_t cursor; // 0=arrow, 1=resize_h, 2=resize_v uint8_t cursor; // 0=arrow, 1=resize_h, 2=resize_v
uint32_t flags;
}; };
int Create(int ownerPid, uint64_t ownerPml4, const char* title, int w, int h, int Create(int ownerPid, uint64_t ownerPml4, const char* title, int w, int h,
@@ -39,6 +40,7 @@ namespace WinServer {
uint64_t& heapNext, uint64_t& outVa); uint64_t& heapNext, uint64_t& outVa);
void CleanupProcess(int pid); void CleanupProcess(int pid);
int SetCursor(int windowId, int callerPid, int cursor); int SetCursor(int windowId, int callerPid, int cursor);
int SetFlags(int windowId, int callerPid, uint32_t flags);
int SetScale(int scale); int SetScale(int scale);
int GetScale(); int GetScale();
+5 -1
View File
@@ -2,7 +2,7 @@
* Window.hpp * Window.hpp
* SYS_WINCREATE, SYS_WINDESTROY, SYS_WINPRESENT, SYS_WINPOLL, * SYS_WINCREATE, SYS_WINDESTROY, SYS_WINPRESENT, SYS_WINPOLL,
* SYS_WINENUM, SYS_WINMAP, SYS_WINSENDEVENT, SYS_WINRESIZE, * SYS_WINENUM, SYS_WINMAP, SYS_WINSENDEVENT, SYS_WINRESIZE,
* SYS_WINSETSCALE, SYS_WINGETSCALE syscalls * SYS_WINSETCURSOR, SYS_WINSETFLAGS, SYS_WINSETSCALE, SYS_WINGETSCALE syscalls
* Copyright (c) 2026 Daniel Hammer * Copyright (c) 2026 Daniel Hammer
*/ */
@@ -75,6 +75,10 @@ namespace Montauk {
return WinServer::SetCursor(windowId, Sched::GetCurrentPid(), cursor); return WinServer::SetCursor(windowId, Sched::GetCurrentPid(), cursor);
} }
static int Sys_WinSetFlags(int windowId, uint32_t flags) {
return WinServer::SetFlags(windowId, Sched::GetCurrentPid(), flags);
}
static int Sys_WinSetScale(int scale) { static int Sys_WinSetScale(int scale) {
return WinServer::SetScale(scale); return WinServer::SetScale(scale);
} }
+2 -2
View File
@@ -267,8 +267,8 @@ rpgdemo: libc
doom: libc doom: libc
$(MAKE) -C src/doom $(MAKE) -C src/doom
# Build screenshot tool (depends on libc and libjpegwrite). # Build screenshot tool (depends on libc, libjpegwrite, libloader, and libdialogs).
screenshot: libc libjpegwrite screenshot: libc libjpegwrite libloader dialogs
$(MAKE) -C src/screenshot $(MAKE) -C src/screenshot
# Build TCC (Tiny C Compiler) via its own Makefile (depends on libc). # Build TCC (Tiny C Compiler) via its own Makefile (depends on libc).
+4
View File
@@ -82,6 +82,7 @@ namespace Montauk {
static constexpr uint64_t SYS_WINSETSCALE = 65; static constexpr uint64_t SYS_WINSETSCALE = 65;
static constexpr uint64_t SYS_WINGETSCALE = 66; static constexpr uint64_t SYS_WINGETSCALE = 66;
static constexpr uint64_t SYS_WINSETCURSOR = 68; static constexpr uint64_t SYS_WINSETCURSOR = 68;
static constexpr uint64_t SYS_WINSETFLAGS = 126;
// Process management syscalls // Process management syscalls
static constexpr uint64_t SYS_PROCLIST = 61; static constexpr uint64_t SYS_PROCLIST = 61;
@@ -270,8 +271,11 @@ namespace Montauk {
uint8_t dirty; uint8_t dirty;
uint8_t cursor; // 0=arrow, 1=resize_h, 2=resize_v uint8_t cursor; // 0=arrow, 1=resize_h, 2=resize_v
uint8_t _pad2[2]; uint8_t _pad2[2];
uint32_t flags;
}; };
static constexpr uint32_t WIN_FLAG_FULLSCREEN = 1u << 0;
struct WinCreateResult { struct WinCreateResult {
int32_t id; // -1 on failure int32_t id; // -1 on failure
uint32_t _pad; uint32_t _pad;
+5
View File
@@ -70,6 +70,11 @@ struct WsWindow {
montauk::win_setcursor(id, cursor); montauk::win_setcursor(id, cursor);
} }
void set_flags(uint32_t flags) const {
if (id >= 0)
montauk::win_setflags(id, flags);
}
void destroy() { void destroy() {
if (id >= 0) if (id >= 0)
montauk::win_destroy(id); montauk::win_destroy(id);
+1
View File
@@ -67,6 +67,7 @@ struct Window {
bool external; // true = shared-memory window from external process bool external; // true = shared-memory window from external process
int ext_win_id; // window server ID (valid when external == true) int ext_win_id; // window server ID (valid when external == true)
uint8_t ext_cursor; // cursor style requested by external app (0=arrow, 1=resize_h, 2=resize_v) uint8_t ext_cursor; // cursor style requested by external app (0=arrow, 1=resize_h, 2=resize_v)
uint32_t ext_flags;
Rect titlebar_rect() const { Rect titlebar_rect() const {
return {frame.x, frame.y, frame.w, TITLEBAR_HEIGHT}; return {frame.x, frame.y, frame.w, TITLEBAR_HEIGHT};
+8
View File
@@ -88,6 +88,7 @@ extern "C" {
#define MTK_SYS_WINGETSCALE 66 #define MTK_SYS_WINGETSCALE 66
#define MTK_SYS_MEMSTATS 67 #define MTK_SYS_MEMSTATS 67
#define MTK_SYS_WINSETCURSOR 68 #define MTK_SYS_WINSETCURSOR 68
#define MTK_SYS_WINSETFLAGS 126
#define MTK_SYS_FDELETE 77 #define MTK_SYS_FDELETE 77
#define MTK_SYS_FMKDIR 78 #define MTK_SYS_FMKDIR 78
#define MTK_SYS_FRENAME 94 #define MTK_SYS_FRENAME 94
@@ -133,6 +134,8 @@ extern "C" {
#define MTK_EVENT_CLOSE 3 #define MTK_EVENT_CLOSE 3
#define MTK_EVENT_SCALE 4 #define MTK_EVENT_SCALE 4
#define MTK_WIN_FLAG_FULLSCREEN (1u << 0)
/* Audio control commands */ /* Audio control commands */
#define MTK_AUDIO_SET_VOLUME 0 #define MTK_AUDIO_SET_VOLUME 0
#define MTK_AUDIO_GET_VOLUME 1 #define MTK_AUDIO_GET_VOLUME 1
@@ -189,6 +192,7 @@ typedef struct {
uint8_t dirty; uint8_t dirty;
uint8_t cursor; uint8_t cursor;
uint8_t _pad2[2]; uint8_t _pad2[2];
uint32_t flags;
} mtk_win_info; } mtk_win_info;
typedef struct { typedef struct {
@@ -599,6 +603,10 @@ static inline int mtk_win_setcursor(int id, int cursor) {
return (int)_mtk_syscall2(MTK_SYS_WINSETCURSOR, (long)id, (long)cursor); return (int)_mtk_syscall2(MTK_SYS_WINSETCURSOR, (long)id, (long)cursor);
} }
static inline int mtk_win_setflags(int id, uint32_t flags) {
return (int)_mtk_syscall2(MTK_SYS_WINSETFLAGS, (long)id, (long)flags);
}
static inline int mtk_win_setscale(int scale) { static inline int mtk_win_setscale(int scale) {
return (int)_mtk_syscall1(MTK_SYS_WINSETSCALE, (long)scale); return (int)_mtk_syscall1(MTK_SYS_WINSETSCALE, (long)scale);
} }
+3
View File
@@ -554,5 +554,8 @@ namespace montauk {
inline int win_setcursor(int id, int cursor) { inline int win_setcursor(int id, int cursor) {
return (int)syscall2(Montauk::SYS_WINSETCURSOR, (uint64_t)id, (uint64_t)cursor); return (int)syscall2(Montauk::SYS_WINSETCURSOR, (uint64_t)id, (uint64_t)cursor);
} }
inline int win_setflags(int id, uint32_t flags) {
return (int)syscall2(Montauk::SYS_WINSETFLAGS, (uint64_t)id, (uint64_t)flags);
}
} }
+13 -2
View File
@@ -240,6 +240,15 @@ void gui::desktop_compose(DesktopState* ds) {
} }
} }
bool topFullscreen = false;
for (int i = ds->window_count - 1; i >= 0; i--) {
if (ds->windows[i].state == WIN_MINIMIZED || ds->windows[i].state == WIN_CLOSED)
continue;
topFullscreen = desktop_window_fullscreen(&ds->windows[i]);
break;
}
if (!topFullscreen) {
// Draw panel on top // Draw panel on top
desktop_draw_panel(ds); desktop_draw_panel(ds);
@@ -329,6 +338,7 @@ void gui::desktop_compose(DesktopState* ds) {
break; break;
} }
} }
}
// Determine cursor style based on resize hover or active resize // Determine cursor style based on resize hover or active resize
CursorStyle cur_style = CURSOR_ARROW; CursorStyle cur_style = CURSOR_ARROW;
@@ -339,7 +349,8 @@ void gui::desktop_compose(DesktopState* ds) {
cur_style = cursor_for_edge(win->resize_edge); cur_style = cursor_for_edge(win->resize_edge);
break; break;
} }
if (win->state == WIN_MINIMIZED || win->state == WIN_CLOSED || win->state == WIN_MAXIMIZED) if (win->state == WIN_MINIMIZED || win->state == WIN_CLOSED ||
win->state == WIN_MAXIMIZED || desktop_window_fullscreen(win))
continue; continue;
if (win->frame.contains(ds->mouse.x, ds->mouse.y)) { if (win->frame.contains(ds->mouse.x, ds->mouse.y)) {
ResizeEdge edge = hit_test_resize_edge(win->frame, ds->mouse.x, ds->mouse.y); ResizeEdge edge = hit_test_resize_edge(win->frame, ds->mouse.x, ds->mouse.y);
@@ -354,7 +365,7 @@ void gui::desktop_compose(DesktopState* ds) {
if (cur_style == CURSOR_ARROW && ds->focused_window >= 0) { if (cur_style == CURSOR_ARROW && ds->focused_window >= 0) {
Window* fwin = &ds->windows[ds->focused_window]; Window* fwin = &ds->windows[ds->focused_window];
if (fwin->external && fwin->ext_cursor > 0) { if (fwin->external && fwin->ext_cursor > 0) {
Rect cr = fwin->content_rect(); Rect cr = desktop_content_rect(fwin);
if (cr.contains(ds->mouse.x, ds->mouse.y)) { if (cr.contains(ds->mouse.x, ds->mouse.y)) {
if (fwin->ext_cursor == 1) cur_style = CURSOR_RESIZE_H; if (fwin->ext_cursor == 1) cur_style = CURSOR_RESIZE_H;
else if (fwin->ext_cursor == 2) cur_style = CURSOR_RESIZE_V; else if (fwin->ext_cursor == 2) cur_style = CURSOR_RESIZE_V;
+10
View File
@@ -112,6 +112,16 @@ inline int menu_add_external(const char* label, const char* binary, SvgIcon* ico
// Forward Declarations (internal functions) // Forward Declarations (internal functions)
// ============================================================================ // ============================================================================
inline bool desktop_window_fullscreen(const gui::Window* win) {
return win && win->external && (win->ext_flags & Montauk::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 // window.cpp
gui::ResizeEdge hit_test_resize_edge(const gui::Rect& f, int mx, int my); gui::ResizeEdge hit_test_resize_edge(const gui::Rect& f, int mx, int my);
gui::CursorStyle cursor_for_edge(gui::ResizeEdge edge); gui::CursorStyle cursor_for_edge(gui::ResizeEdge edge);
+88 -19
View File
@@ -94,6 +94,47 @@ static void handle_lock_keyboard(DesktopState* ds, const Montauk::KeyEvent& key)
} }
} }
static void forward_external_mouse(gui::Window* win,
const gui::MouseEvent& ev,
int mx,
int my,
uint8_t buttons,
uint8_t prev) {
gui::Rect cr = desktop_content_rect(win);
Montauk::WinEvent wev;
montauk::memset(&wev, 0, sizeof(wev));
wev.type = 1; // mouse
wev.mouse.x = mx - cr.x;
wev.mouse.y = my - cr.y;
wev.mouse.scroll = ev.scroll;
wev.mouse.buttons = buttons;
wev.mouse.prev_buttons = prev;
montauk::win_sendevent(win->ext_win_id, &wev);
}
static bool route_fullscreen_external_mouse(gui::DesktopState* ds,
const gui::MouseEvent& ev,
int mx,
int my,
uint8_t buttons,
uint8_t prev) {
for (int i = ds->window_count - 1; i >= 0; i--) {
gui::Window* win = &ds->windows[i];
if (win->state == gui::WIN_MINIMIZED || win->state == gui::WIN_CLOSED)
continue;
if (!desktop_window_fullscreen(win))
return false;
if (i != ds->window_count - 1) {
gui::desktop_raise_window(ds, i);
win = &ds->windows[ds->window_count - 1];
}
forward_external_mouse(win, ev, mx, my, buttons, prev);
return true;
}
return false;
}
// ============================================================================ // ============================================================================
// Desktop Mouse Handling // Desktop Mouse Handling
// ============================================================================ // ============================================================================
@@ -104,11 +145,6 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
return; return;
} }
if (ds->launcher_open) {
desktop_handle_launcher_mouse(ds);
return;
}
int mx = ds->mouse.x; int mx = ds->mouse.x;
int my = ds->mouse.y; int my = ds->mouse.y;
uint8_t buttons = ds->mouse.buttons; uint8_t buttons = ds->mouse.buttons;
@@ -125,6 +161,19 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
ev.prev_buttons = prev; ev.prev_buttons = prev;
ev.scroll = ds->mouse.scrollDelta; ev.scroll = ds->mouse.scrollDelta;
if (route_fullscreen_external_mouse(ds, ev, mx, my, buttons, prev)) {
ds->app_menu_open = false;
ds->ctx_menu_open = false;
ds->vol_popup_open = false;
ds->net_popup_open = false;
return;
}
if (ds->launcher_open) {
desktop_handle_launcher_mouse(ds);
return;
}
// Handle context menu clicks // Handle context menu clicks
if (ds->ctx_menu_open) { if (ds->ctx_menu_open) {
if (left_pressed) { if (left_pressed) {
@@ -183,7 +232,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
win->frame = {0, PANEL_HEIGHT, ds->screen_w / 2, ds->screen_h - PANEL_HEIGHT}; win->frame = {0, PANEL_HEIGHT, ds->screen_w / 2, ds->screen_h - PANEL_HEIGHT};
win->state = WIN_MAXIMIZED; win->state = WIN_MAXIMIZED;
if (!win->external) { if (!win->external) {
Rect cr = win->content_rect(); Rect cr = desktop_content_rect(win);
if (cr.w != win->content_w || cr.h != win->content_h) { if (cr.w != win->content_w || cr.h != win->content_h) {
if (win->content) montauk::free(win->content); if (win->content) montauk::free(win->content);
win->content_w = cr.w; win->content_w = cr.w;
@@ -192,7 +241,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
montauk::memset(win->content, 0xFF, cr.w * cr.h * 4); montauk::memset(win->content, 0xFF, cr.w * cr.h * 4);
} }
} else { } else {
Rect cr = win->content_rect(); Rect cr = desktop_content_rect(win);
Montauk::WinEvent rev; Montauk::WinEvent rev;
montauk::memset(&rev, 0, sizeof(rev)); montauk::memset(&rev, 0, sizeof(rev));
rev.type = 2; rev.type = 2;
@@ -205,7 +254,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
win->frame = {ds->screen_w / 2, PANEL_HEIGHT, ds->screen_w / 2, ds->screen_h - PANEL_HEIGHT}; win->frame = {ds->screen_w / 2, PANEL_HEIGHT, ds->screen_w / 2, ds->screen_h - PANEL_HEIGHT};
win->state = WIN_MAXIMIZED; win->state = WIN_MAXIMIZED;
if (!win->external) { if (!win->external) {
Rect cr = win->content_rect(); Rect cr = desktop_content_rect(win);
if (cr.w != win->content_w || cr.h != win->content_h) { if (cr.w != win->content_w || cr.h != win->content_h) {
if (win->content) montauk::free(win->content); if (win->content) montauk::free(win->content);
win->content_w = cr.w; win->content_w = cr.w;
@@ -214,7 +263,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
montauk::memset(win->content, 0xFF, cr.w * cr.h * 4); montauk::memset(win->content, 0xFF, cr.w * cr.h * 4);
} }
} else { } else {
Rect cr = win->content_rect(); Rect cr = desktop_content_rect(win);
Montauk::WinEvent rev; Montauk::WinEvent rev;
montauk::memset(&rev, 0, sizeof(rev)); montauk::memset(&rev, 0, sizeof(rev));
rev.type = 2; rev.type = 2;
@@ -271,7 +320,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
win->resizing = false; win->resizing = false;
// Reallocate content buffer if dimensions changed (skip for external) // Reallocate content buffer if dimensions changed (skip for external)
if (!win->external) { if (!win->external) {
Rect cr = win->content_rect(); Rect cr = desktop_content_rect(win);
if (cr.w != win->content_w || cr.h != win->content_h) { if (cr.w != win->content_w || cr.h != win->content_h) {
if (win->content) montauk::free(win->content); if (win->content) montauk::free(win->content);
win->content_w = cr.w; win->content_w = cr.w;
@@ -281,7 +330,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
} }
win->dirty = true; win->dirty = true;
} else { } else {
Rect cr = win->content_rect(); Rect cr = desktop_content_rect(win);
Montauk::WinEvent rev; Montauk::WinEvent rev;
montauk::memset(&rev, 0, sizeof(rev)); montauk::memset(&rev, 0, sizeof(rev));
rev.type = 2; rev.type = 2;
@@ -505,6 +554,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
Window* win = &ds->windows[i]; Window* win = &ds->windows[i];
if (win->state == WIN_MINIMIZED || win->state == WIN_CLOSED) continue; if (win->state == WIN_MINIMIZED || win->state == WIN_CLOSED) continue;
if (!desktop_window_fullscreen(win)) {
// Check close button // Check close button
Rect close_r = win->close_btn_rect(); Rect close_r = win->close_btn_rect();
if (close_r.contains(mx, my)) { if (close_r.contains(mx, my)) {
@@ -542,7 +592,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
} }
// Reallocate content buffer for local windows only // Reallocate content buffer for local windows only
if (!win->external) { if (!win->external) {
Rect cr = win->content_rect(); Rect cr = desktop_content_rect(win);
if (cr.w != win->content_w || cr.h != win->content_h) { if (cr.w != win->content_w || cr.h != win->content_h) {
if (win->content) montauk::free(win->content); if (win->content) montauk::free(win->content);
win->content_w = cr.w; win->content_w = cr.w;
@@ -551,7 +601,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
montauk::memset(win->content, 0xFF, cr.w * cr.h * 4); montauk::memset(win->content, 0xFF, cr.w * cr.h * 4);
} }
} else { } else {
Rect cr = win->content_rect(); Rect cr = desktop_content_rect(win);
Montauk::WinEvent rev; Montauk::WinEvent rev;
montauk::memset(&rev, 0, sizeof(rev)); montauk::memset(&rev, 0, sizeof(rev));
rev.type = 2; rev.type = 2;
@@ -588,9 +638,10 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
ds->windows[new_idx].drag_offset_y = my - ds->windows[new_idx].frame.y; ds->windows[new_idx].drag_offset_y = my - ds->windows[new_idx].frame.y;
return; return;
} }
}
// Check content area // Check content area
Rect cr = win->content_rect(); Rect cr = desktop_content_rect(win);
if (cr.contains(mx, my)) { if (cr.contains(mx, my)) {
desktop_raise_window(ds, i); desktop_raise_window(ds, i);
int new_idx = ds->window_count - 1; int new_idx = ds->window_count - 1;
@@ -630,7 +681,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
if (!left_pressed && ds->focused_window >= 0) { if (!left_pressed && ds->focused_window >= 0) {
Window* win = &ds->windows[ds->focused_window]; Window* win = &ds->windows[ds->focused_window];
if (win->state != WIN_MINIMIZED && win->state != WIN_CLOSED) { if (win->state != WIN_MINIMIZED && win->state != WIN_CLOSED) {
Rect cr = win->content_rect(); Rect cr = desktop_content_rect(win);
// Forward if mouse is over content (hover/move) or button is held/released (drag continuity) // Forward if mouse is over content (hover/move) or button is held/released (drag continuity)
if (cr.contains(mx, my) || left_held || left_released) { if (cr.contains(mx, my) || left_held || left_released) {
if (win->external) { if (win->external) {
@@ -655,7 +706,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
// Handle scroll events on focused window // Handle scroll events on focused window
if (ev.scroll != 0 && ds->focused_window >= 0) { if (ev.scroll != 0 && ds->focused_window >= 0) {
Window* win = &ds->windows[ds->focused_window]; Window* win = &ds->windows[ds->focused_window];
Rect cr = win->content_rect(); Rect cr = desktop_content_rect(win);
if (cr.contains(mx, my)) { if (cr.contains(mx, my)) {
if (win->external) { if (win->external) {
Montauk::WinEvent wev; Montauk::WinEvent wev;
@@ -696,12 +747,30 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
} }
void gui::desktop_handle_keyboard(DesktopState* ds, const Montauk::KeyEvent& key) { void gui::desktop_handle_keyboard(DesktopState* ds, const Montauk::KeyEvent& key) {
if (desktop_handle_launcher_keyboard(ds, key)) { if (ds->screen_locked) {
handle_lock_keyboard(ds, key);
return; return;
} }
if (ds->screen_locked) { for (int i = ds->window_count - 1; i >= 0; i--) {
handle_lock_keyboard(ds, key); Window* win = &ds->windows[i];
if (win->state == WIN_MINIMIZED || win->state == WIN_CLOSED)
continue;
if (!desktop_window_fullscreen(win))
break;
Montauk::WinEvent ev;
montauk::memset(&ev, 0, sizeof(ev));
ev.type = 0; // key
ev.key = key;
montauk::win_sendevent(win->ext_win_id, &ev);
ds->launcher_open = false;
ds->app_menu_open = false;
ds->ctx_menu_open = false;
return;
}
if (desktop_handle_launcher_keyboard(ds, key)) {
return; return;
} }
+27
View File
@@ -419,6 +419,7 @@ bool desktop_poll_external_windows(DesktopState* ds) {
if (ds->windows[i].external && ds->windows[i].ext_win_id == extId) { if (ds->windows[i].external && ds->windows[i].ext_win_id == extId) {
found = true; found = true;
bool remapRequested = false; bool remapRequested = false;
bool wasFullscreen = desktop_window_fullscreen(&ds->windows[i]);
uint64_t currentVa = (uint64_t)(uintptr_t)ds->windows[i].content; uint64_t currentVa = (uint64_t)(uintptr_t)ds->windows[i].content;
if (ds->windows[i].content_w != extWins[e].width || if (ds->windows[i].content_w != extWins[e].width ||
ds->windows[i].content_h != extWins[e].height) { ds->windows[i].content_h != extWins[e].height) {
@@ -436,6 +437,26 @@ bool desktop_poll_external_windows(DesktopState* ds) {
changed = true; changed = true;
} }
} }
if (ds->windows[i].ext_flags != extWins[e].flags) {
ds->windows[i].ext_flags = extWins[e].flags;
bool isFullscreen = desktop_window_fullscreen(&ds->windows[i]);
if (isFullscreen) {
if (!wasFullscreen) ds->windows[i].saved_frame = ds->windows[i].frame;
ds->windows[i].frame = {0, 0, ds->screen_w, ds->screen_h};
ds->windows[i].state = WIN_NORMAL;
} else if (wasFullscreen) {
ds->windows[i].frame = ds->windows[i].saved_frame;
ds->windows[i].state = WIN_NORMAL;
}
changed = true;
}
if (desktop_window_fullscreen(&ds->windows[i]) &&
(ds->windows[i].frame.x != 0 || ds->windows[i].frame.y != 0 ||
ds->windows[i].frame.w != ds->screen_w || ds->windows[i].frame.h != ds->screen_h)) {
ds->windows[i].frame = {0, 0, ds->screen_w, ds->screen_h};
ds->windows[i].state = WIN_NORMAL;
changed = true;
}
// Update dirty flag and cursor // Update dirty flag and cursor
if (extWins[e].dirty) { if (extWins[e].dirty) {
ds->windows[i].dirty = true; ds->windows[i].dirty = true;
@@ -524,6 +545,12 @@ bool desktop_poll_external_windows(DesktopState* ds) {
win->app_data = nullptr; win->app_data = nullptr;
win->external = true; win->external = true;
win->ext_win_id = extId; win->ext_win_id = extId;
win->ext_cursor = extWins[e].cursor;
win->ext_flags = extWins[e].flags;
if (desktop_window_fullscreen(win)) {
win->frame = {0, 0, ds->screen_w, ds->screen_h};
win->state = WIN_NORMAL;
}
// Unfocus previous window // Unfocus previous window
if (ds->focused_window >= 0 && ds->focused_window < ds->window_count) { if (ds->focused_window >= 0 && ds->focused_window < ds->window_count) {
+6 -1
View File
@@ -39,6 +39,8 @@ int gui::desktop_create_window(DesktopState* ds, const char* title, int x, int y
win->app_data = nullptr; win->app_data = nullptr;
win->external = false; win->external = false;
win->ext_win_id = -1; win->ext_win_id = -1;
win->ext_cursor = 0;
win->ext_flags = 0;
// Unfocus previous window // Unfocus previous window
if (ds->focused_window >= 0 && ds->focused_window < ds->window_count) { if (ds->focused_window >= 0 && ds->focused_window < ds->window_count) {
@@ -131,7 +133,9 @@ void gui::desktop_draw_window(DesktopState* ds, int idx) {
int y = win->frame.y; int y = win->frame.y;
int w = win->frame.w; int w = win->frame.w;
int h = win->frame.h; int h = win->frame.h;
bool fullscreen = desktop_window_fullscreen(win);
if (!fullscreen) {
// Draw shadow // Draw shadow
if (ds->settings.show_shadows) if (ds->settings.show_shadows)
draw_shadow(fb, x, y, w, h, SHADOW_SIZE, colors::SHADOW); draw_shadow(fb, x, y, w, h, SHADOW_SIZE, colors::SHADOW);
@@ -172,9 +176,10 @@ void gui::desktop_draw_window(DesktopState* ds, int idx) {
if (win->on_draw && !win->resizing) { if (win->on_draw && !win->resizing) {
win->on_draw(win, fb); win->on_draw(win, fb);
} }
}
// Blit content buffer to framebuffer (clip to actual buffer size during resize) // Blit content buffer to framebuffer (clip to actual buffer size during resize)
Rect cr = win->content_rect(); Rect cr = desktop_content_rect(win);
if (win->content) { if (win->content) {
if (win->external && (cr.w != win->content_w || cr.h != win->content_h)) { if (win->external && (cr.w != win->content_w || cr.h != win->content_h)) {
// Nearest-neighbor scale for external windows (fixed-size shared buffer) // Nearest-neighbor scale for external windows (fixed-size shared buffer)
+15 -27
View File
@@ -25,29 +25,17 @@ using namespace gui;
static constexpr int INIT_W = 640; static constexpr int INIT_W = 640;
static constexpr int INIT_H = 460; static constexpr int INIT_H = 460;
static constexpr int TOOLBAR_H = 40; static constexpr int TOOLBAR_H = 44;
static constexpr int HEADER_H = 26; static constexpr int HEADER_H = 28;
static constexpr int ITEM_H = 32; static constexpr int ITEM_H = 32;
static constexpr int MAP_H = 48; static constexpr int MAP_H = 48;
static constexpr int MAP_PAD = 16; static constexpr int MAP_PAD = 16;
static constexpr int MAX_PARTS = 32; static constexpr int MAX_PARTS = 32;
static constexpr int MAX_DISKS = 8; static constexpr int MAX_DISKS = 8;
static constexpr int STATUS_H = 26; static constexpr int STATUS_H = 44;
static constexpr int TB_BTN_Y = 7; static constexpr int TB_BTN_Y = 7;
static constexpr int TB_BTN_H = 26; static constexpr int TB_BTN_H = 30;
static constexpr int TB_BTN_RAD = 6;
static constexpr Color BG_COLOR = Color::from_rgb(0xFF, 0xFF, 0xFF);
static constexpr Color TOOLBAR_BG = Color::from_rgb(0xF5, 0xF5, 0xF5);
static constexpr Color HEADER_BG = Color::from_rgb(0xF0, 0xF0, 0xF0);
static constexpr Color BORDER_COLOR = Color::from_rgb(0xCC, 0xCC, 0xCC);
static constexpr Color TEXT_COLOR = Color::from_rgb(0x22, 0x22, 0x22);
static constexpr Color DIM_TEXT = Color::from_rgb(0x66, 0x66, 0x66);
static constexpr Color FAINT_TEXT = Color::from_rgb(0x88, 0x88, 0x88);
static constexpr Color HOVER_BG = Color::from_rgb(0xE8, 0xF0, 0xF8);
static constexpr Color STATUS_BG_COL = Color::from_rgb(0xF0, 0xF0, 0xF0);
static constexpr Color WHITE = Color::from_rgb(0xFF, 0xFF, 0xFF);
static constexpr int NUM_PART_COLORS = 8; static constexpr int NUM_PART_COLORS = 8;
@@ -119,6 +107,7 @@ struct DiskToolState {
extern int g_win_w, g_win_h; extern int g_win_w, g_win_h;
extern DiskToolState g_state; extern DiskToolState g_state;
extern Color g_accent;
// ============================================================================ // ============================================================================
// Partition colors // Partition colors
@@ -133,33 +122,34 @@ extern const Color part_colors[NUM_PART_COLORS];
inline int disk_button_width(int idx) { inline int disk_button_width(int idx) {
char label[8]; char label[8];
snprintf(label, sizeof(label), "Disk %d", idx); snprintf(label, sizeof(label), "Disk %d", idx);
return text_width(label) + 16; return text_width(label) + 20;
} }
inline Rect toolbar_disk_button_rect(int idx) { inline Rect toolbar_disk_button_rect(int idx) {
int bx = 8; int bx = 8;
for (int i = 0; i < idx; i++) for (int i = 0; i < idx; i++)
bx += disk_button_width(i) + 6; bx += disk_button_width(i) + 8;
return {bx, TB_BTN_Y, disk_button_width(idx), TB_BTN_H}; return {bx, TB_BTN_Y, disk_button_width(idx), TB_BTN_H};
} }
inline Rect toolbar_refresh_button_rect() { inline Rect toolbar_refresh_button_rect() {
return {g_win_w - 8 - 64, TB_BTN_Y, 64, TB_BTN_H}; int y = g_win_h - STATUS_H + (STATUS_H - TB_BTN_H) / 2;
return {g_win_w - 12 - 84, y, 84, TB_BTN_H};
} }
inline Rect toolbar_mount_button_rect() { inline Rect toolbar_mount_button_rect() {
Rect refresh = toolbar_refresh_button_rect(); Rect refresh = toolbar_refresh_button_rect();
return {refresh.x - 6 - 60, TB_BTN_Y, 60, TB_BTN_H}; return {refresh.x - 8 - 72, refresh.y, 72, TB_BTN_H};
} }
inline Rect toolbar_format_button_rect() { inline Rect toolbar_format_button_rect() {
Rect mount = toolbar_mount_button_rect(); Rect mount = toolbar_mount_button_rect();
return {mount.x - 6 - 64, TB_BTN_Y, 64, TB_BTN_H}; return {mount.x - 8 - 72, mount.y, 72, TB_BTN_H};
} }
inline Rect toolbar_newpart_button_rect() { inline Rect toolbar_newpart_button_rect() {
Rect format = toolbar_format_button_rect(); Rect format = toolbar_format_button_rect();
return {format.x - 6 - 74, TB_BTN_Y, 74, TB_BTN_H}; return {format.x - 8 - 96, format.y, 96, TB_BTN_H};
} }
inline int content_title_y() { inline int content_title_y() {
@@ -188,15 +178,13 @@ inline Rect format_option_rect(int dialog_w, int index) {
inline Rect dialog_primary_button_rect(int dialog_w, int dialog_h) { inline Rect dialog_primary_button_rect(int dialog_w, int dialog_h) {
int btn_w = 90; int btn_w = 90;
int btn_h = 30; int btn_h = 30;
int gap = 16; int bx = dialog_w - btn_w - 16;
int total_w = btn_w * 2 + gap; return {bx, dialog_h - btn_h - 12, btn_w, btn_h};
int bx = (dialog_w - total_w) / 2;
return {bx, dialog_h - btn_h - 16, btn_w, btn_h};
} }
inline Rect dialog_secondary_button_rect(int dialog_w, int dialog_h) { inline Rect dialog_secondary_button_rect(int dialog_w, int dialog_h) {
Rect primary = dialog_primary_button_rect(dialog_w, dialog_h); Rect primary = dialog_primary_button_rect(dialog_w, dialog_h);
return {primary.x + primary.w + 16, primary.y, primary.w, primary.h}; return {primary.x - 8 - primary.w, primary.y, primary.w, primary.h};
} }
// ============================================================================ // ============================================================================
+17 -3
View File
@@ -5,6 +5,7 @@
*/ */
#include "disks.h" #include "disks.h"
#include <gui/mtk/settings.hpp>
#include <gui/standalone.hpp> #include <gui/standalone.hpp>
// ============================================================================ // ============================================================================
@@ -15,6 +16,7 @@ int g_win_w = INIT_W;
int g_win_h = INIT_H; int g_win_h = INIT_H;
DiskToolState g_state; DiskToolState g_state;
Color g_accent = colors::ACCENT;
const Color part_colors[NUM_PART_COLORS] = { const Color part_colors[NUM_PART_COLORS] = {
Color::from_rgb(0x42, 0x7A, 0xB5), Color::from_rgb(0x42, 0x7A, 0xB5),
@@ -73,7 +75,6 @@ static bool handle_toolbar_click(int mx, int my) {
auto& dt = g_state; auto& dt = g_state;
if (dt.disk_count == 0) return false; if (dt.disk_count == 0) return false;
bool has_sel = dt.selected_part >= 0;
// Disk selector buttons // Disk selector buttons
for (int i = 0; i < dt.disk_count; i++) { for (int i = 0; i < dt.disk_count; i++) {
@@ -85,7 +86,16 @@ static bool handle_toolbar_click(int mx, int my) {
} }
} }
// Right-side buttons (must match render layout) return false;
}
static bool handle_action_click(int mx, int my) {
if (my < g_win_h - STATUS_H) return false;
auto& dt = g_state;
if (dt.disk_count == 0) return false;
bool has_sel = dt.selected_part >= 0;
if (toolbar_refresh_button_rect().contains(mx, my)) { if (toolbar_refresh_button_rect().contains(mx, my)) {
disktool_refresh(); disktool_refresh();
set_status("Refreshed"); set_status("Refreshed");
@@ -285,7 +295,9 @@ static bool handle_mouse(const Montauk::WinEvent& ev) {
bool clicked = (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1); bool clicked = (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1);
if (clicked) { if (clicked) {
if (handle_toolbar_click(ev.mouse.x, ev.mouse.y) || handle_content_click(ev.mouse.x, ev.mouse.y)) if (handle_toolbar_click(ev.mouse.x, ev.mouse.y) ||
handle_action_click(ev.mouse.x, ev.mouse.y) ||
handle_content_click(ev.mouse.x, ev.mouse.y))
return true; return true;
} }
@@ -365,6 +377,8 @@ extern "C" void _start() {
if (!fonts::init()) if (!fonts::init())
montauk::exit(1); montauk::exit(1);
g_accent = mtk::load_system_accent();
disktool_refresh(); disktool_refresh();
WsWindow win; WsWindow win;
+91 -58
View File
@@ -9,22 +9,20 @@
#include <gui/mtk.hpp> #include <gui/mtk.hpp>
static mtk::Theme disks_theme() { static mtk::Theme disks_theme() {
mtk::Theme theme = mtk::make_theme(); mtk::Theme theme = mtk::make_theme(g_accent);
theme.window_bg = BG_COLOR; theme.selection = theme.accent_soft;
theme.surface = TOOLBAR_BG; theme.disabled_bg = Color::from_rgb(0xE4, 0xE4, 0xE4);
theme.surface_alt = HEADER_BG;
theme.surface_hover = HOVER_BG;
theme.border = BORDER_COLOR;
theme.text = TEXT_COLOR;
theme.text_muted = FAINT_TEXT;
theme.text_subtle = DIM_TEXT;
theme.selection = HOVER_BG;
theme.accent_soft = HOVER_BG;
theme.disabled_bg = Color::from_rgb(0xF0, 0xF0, 0xF0);
theme.disabled_fg = Color::from_rgb(0x9A, 0x9A, 0x9A); theme.disabled_fg = Color::from_rgb(0x9A, 0x9A, 0x9A);
return theme; return theme;
} }
static mtk::TableStyle partition_table_style(const mtk::Theme& theme) {
mtk::TableStyle style = mtk::make_table_style(theme);
style.row_selected_bg = theme.accent_soft;
style.row_hover_bg = mtk::mix(theme.window_bg, theme.accent, 12);
return style;
}
static bool mouse_in_rect(const Rect& rect) { static bool mouse_in_rect(const Rect& rect) {
return rect.contains(g_state.mouse_x, g_state.mouse_y); return rect.contains(g_state.mouse_x, g_state.mouse_y);
} }
@@ -79,6 +77,13 @@ static void draw_centered_text(Canvas& c, int width, int y, const char* text, Co
c.text((width - tw) / 2, y, text, color); c.text((width - tw) / 2, y, text, color);
} }
static void draw_dialog_footer(Canvas& c, int dialog_w, int dialog_h, const mtk::Theme& theme) {
constexpr int FOOTER_H = 54;
int y = dialog_h - FOOTER_H;
c.fill_rect(0, y, dialog_w, FOOTER_H, theme.surface);
mtk::draw_separator(c, 0, y, dialog_w, theme);
}
static void render_toolbar(Canvas& c, const mtk::Theme& theme) { static void render_toolbar(Canvas& c, const mtk::Theme& theme) {
auto& dt = g_state; auto& dt = g_state;
int fh = system_font_height(); int fh = system_font_height();
@@ -98,21 +103,6 @@ static void render_toolbar(Canvas& c, const mtk::Theme& theme) {
c.text(8, (TOOLBAR_H - fh) / 2, "No disks detected", theme.text); c.text(8, (TOOLBAR_H - fh) / 2, "No disks detected", theme.text);
return; return;
} }
bool has_sel = dt.selected_part >= 0;
Rect newpart = toolbar_newpart_button_rect();
Rect format = toolbar_format_button_rect();
Rect mount = toolbar_mount_button_rect();
Rect refresh = toolbar_refresh_button_rect();
mtk::draw_button(c, newpart, "New Part", mtk::BUTTON_PRIMARY,
toolbar_button_state(newpart, true), theme);
mtk::draw_button(c, format, "Format", mtk::BUTTON_TONAL,
toolbar_button_state(format, has_sel), theme);
mtk::draw_button(c, mount, "Mount", mtk::BUTTON_TONAL,
toolbar_button_state(mount, has_sel), theme);
mtk::draw_button(c, refresh, "Refresh", mtk::BUTTON_SECONDARY,
toolbar_button_state(refresh, true), theme);
} }
static void render_content(Canvas& c, const mtk::Theme& theme) { static void render_content(Canvas& c, const mtk::Theme& theme) {
@@ -140,7 +130,7 @@ static void render_content(Canvas& c, const mtk::Theme& theme) {
y = partition_map_y(); y = partition_map_y();
Rect map_rect = {MAP_PAD, y, g_win_w - MAP_PAD * 2, MAP_H}; Rect map_rect = {MAP_PAD, y, g_win_w - MAP_PAD * 2, MAP_H};
c.fill_rounded_rect(map_rect.x, map_rect.y, map_rect.w, map_rect.h, theme.radius_md, theme.surface_alt); mtk::draw_rounded_frame(c, map_rect, theme.radius_md, theme.surface_alt, theme.border);
int part_indices[MAX_PARTS]; int part_indices[MAX_PARTS];
int nparts = get_disk_parts(part_indices, MAX_PARTS); int nparts = get_disk_parts(part_indices, MAX_PARTS);
@@ -155,45 +145,60 @@ static void render_content(Canvas& c, const mtk::Theme& theme) {
if (part_x + part_w > map_rect.x + map_rect.w) if (part_x + part_w > map_rect.x + map_rect.w)
part_w = map_rect.x + map_rect.w - part_x; part_w = map_rect.x + map_rect.w - part_x;
Color col = part_colors[pi % NUM_PART_COLORS]; Rect segment = {part_x, map_rect.y + 3, part_w, MAP_H - 6};
if (pi == dt.selected_part) { if (pi == dt.selected_part) {
col = Color::from_rgb((col.r + 255) / 2, c.fill_rounded_rect(segment.x - 1, segment.y - 1,
(col.g + 255) / 2, segment.w + 2, segment.h + 2,
(col.b + 255) / 2); theme.radius_sm, theme.accent);
} }
c.fill_rounded_rect(part_x, map_rect.y + 2, part_w, MAP_H - 4, theme.radius_sm, col);
Color col = part_colors[pi % NUM_PART_COLORS];
c.fill_rounded_rect(segment.x, segment.y, segment.w, segment.h,
theme.radius_sm, col);
char label[8]; char label[8];
snprintf(label, sizeof(label), "%d", pi); snprintf(label, sizeof(label), "%d", pi);
int label_w = text_width(label); int label_w = text_width(label);
if (part_w > label_w + 4) { if (part_w > label_w + 4) {
c.text(part_x + (part_w - label_w) / 2, c.text(segment.x + (segment.w - label_w) / 2,
map_rect.y + (MAP_H - fh) / 2, map_rect.y + (MAP_H - fh) / 2,
label, WHITE); label, theme.text_inverse);
} }
} }
} }
y = partition_header_y(); y = partition_header_y();
c.fill_rect(0, y, g_win_w, HEADER_H, theme.surface_alt); int list_y = partition_list_y();
mtk::draw_separator(c, 0, y + HEADER_H - 1, g_win_w, theme); int list_bottom = g_win_h - STATUS_H;
int hovered_row = hovered_partition_row();
mtk::TableStyle table_style = partition_table_style(theme);
mtk::TableLayout table = {
{0, y, g_win_w, HEADER_H},
{0, list_y, g_win_w, list_bottom - list_y},
ITEM_H
};
int ty = y + (HEADER_H - fh) / 2;
int col_idx = 12; int col_idx = 12;
int col_name = 40; int col_name = 40;
int col_type = g_win_w / 2 - 20; int col_type = g_win_w / 2 - 20;
int col_size = g_win_w - 160; int col_size = g_win_w - 160;
int col_lba = g_win_w - 80; int col_lba = g_win_w - 80;
mtk::TableColumn cols[5] = {
{"#", col_idx, col_name - col_idx - 8},
{"Name", col_name, col_type - col_name - 10},
{"Type", col_type, col_size - col_type - 10},
{"Size", col_size, col_lba - col_size - 10},
{"LBA", col_lba, g_win_w - col_lba - 12},
};
c.text(col_idx, ty, "#", theme.text_subtle); c.fill_rect(table.header.x, table.header.y, table.header.w, table.header.h,
c.text(col_name, ty, "Name", theme.text_subtle); table_style.header_bg);
c.text(col_type, ty, "Type", theme.text_subtle); c.hline(table.header.x, table.header.y + table.header.h - 1,
c.text(col_size, ty, "Size", theme.text_subtle); table.header.w, table_style.header_border);
c.text(col_lba, ty, "LBA", theme.text_subtle);
int list_y = partition_list_y(); int ty = table.header.y + (table.header.h - fh) / 2;
int list_bottom = g_win_h - STATUS_H; for (int i = 0; i < 5; i++)
int hovered_row = hovered_partition_row(); c.text(table.header.x + cols[i].x, ty, cols[i].label, table_style.header_text);
for (int pi = 0; pi < nparts; pi++) { for (int pi = 0; pi < nparts; pi++) {
int row_y = list_y + pi * ITEM_H - dt.scroll_y; int row_y = list_y + pi * ITEM_H - dt.scroll_y;
@@ -202,11 +207,11 @@ static void render_content(Canvas& c, const mtk::Theme& theme) {
Rect row_rect = {0, row_y, g_win_w, ITEM_H}; Rect row_rect = {0, row_y, g_win_w, ITEM_H};
if (pi == dt.selected_part) { if (pi == dt.selected_part) {
mtk::draw_list_row(c, row_rect, true, false, theme); c.fill_rect(row_rect.x, row_rect.y, row_rect.w, row_rect.h,
table_style.row_selected_bg);
} else if (pi == hovered_row) { } else if (pi == hovered_row) {
c.fill_rect(row_rect.x, row_rect.y, row_rect.w, row_rect.h, theme.surface_hover); c.fill_rect(row_rect.x, row_rect.y, row_rect.w, row_rect.h,
} else { table_style.row_hover_bg);
mtk::draw_list_row(c, row_rect, false, (pi & 1) != 0, theme);
} }
Montauk::PartInfo& p = dt.parts[part_indices[pi]]; Montauk::PartInfo& p = dt.parts[part_indices[pi]];
@@ -216,17 +221,17 @@ static void render_content(Canvas& c, const mtk::Theme& theme) {
int ry = row_y + (ITEM_H - fh) / 2; int ry = row_y + (ITEM_H - fh) / 2;
draw_text_fit(c, col_name, ry, p.name[0] ? p.name : "(unnamed)", draw_text_fit(c, col_name, ry, p.name[0] ? p.name : "(unnamed)",
col_type - col_name - 10, theme.text); cols[1].w, theme.text);
draw_text_fit(c, col_type, ry, p.typeName, draw_text_fit(c, col_type, ry, p.typeName,
col_size - col_type - 10, theme.text_subtle); cols[2].w, theme.text_subtle);
char sz[24]; char sz[24];
format_disk_size(sz, sizeof(sz), p.sectorCount, disk.sectorSizeLog); format_disk_size(sz, sizeof(sz), p.sectorCount, disk.sectorSizeLog);
c.text(col_size, ry, sz, theme.text); draw_text_fit(c, col_size, ry, sz, cols[3].w, theme.text);
char lba_str[24]; char lba_str[24];
snprintf(lba_str, sizeof(lba_str), "%lu", (unsigned)p.startLba); snprintf(lba_str, sizeof(lba_str), "%lu", (unsigned)p.startLba);
c.text(col_lba, ry, lba_str, theme.text_muted); draw_text_fit(c, col_lba, ry, lba_str, cols[4].w, theme.text_muted);
} }
if (nparts == 0) if (nparts == 0)
@@ -238,13 +243,34 @@ static void render_status(Canvas& c, const mtk::Theme& theme) {
int fh = system_font_height(); int fh = system_font_height();
int sy = g_win_h - STATUS_H; int sy = g_win_h - STATUS_H;
c.fill_rect(0, sy, g_win_w, STATUS_H, theme.surface_alt); c.fill_rect(0, sy, g_win_w, STATUS_H, theme.surface);
mtk::draw_separator(c, 0, sy, g_win_w, theme); mtk::draw_separator(c, 0, sy, g_win_w, theme);
bool has_disks = dt.disk_count > 0;
bool has_sel = dt.selected_part >= 0;
int text_right = g_win_w - 16;
if (has_disks) {
Rect newpart = toolbar_newpart_button_rect();
Rect format = toolbar_format_button_rect();
Rect mount = toolbar_mount_button_rect();
Rect refresh = toolbar_refresh_button_rect();
text_right = newpart.x - 12;
mtk::draw_button(c, newpart, "New Part", mtk::BUTTON_PRIMARY,
toolbar_button_state(newpart, true), theme);
mtk::draw_button(c, format, "Format", mtk::BUTTON_TONAL,
toolbar_button_state(format, has_sel), theme);
mtk::draw_button(c, mount, "Mount", mtk::BUTTON_TONAL,
toolbar_button_state(mount, has_sel), theme);
mtk::draw_button(c, refresh, "Refresh", mtk::BUTTON_SECONDARY,
toolbar_button_state(refresh, true), theme);
}
if (dt.status[0]) { if (dt.status[0]) {
uint64_t age = montauk::get_milliseconds() - dt.status_time; uint64_t age = montauk::get_milliseconds() - dt.status_time;
Color color = age < 5000 ? theme.text : theme.text_muted; Color color = age < 5000 ? theme.text : theme.text_muted;
c.text(8, sy + (STATUS_H - fh) / 2, dt.status, color); draw_text_fit(c, 16, sy + (STATUS_H - fh) / 2, dt.status,
text_right - 16, color);
} }
} }
@@ -265,11 +291,14 @@ void render_format_window() {
for (int i = 0; i < NUM_FS_TYPES; i++) { for (int i = 0; i < NUM_FS_TYPES; i++) {
Rect option = format_option_rect(FMT_DLG_W, i); Rect option = format_option_rect(FMT_DLG_W, i);
if (i == dlg.selected_fs) if (i == dlg.selected_fs) {
c.fill_rounded_rect(option.x, option.y, option.w, option.h, theme.radius_md, theme.accent_soft); mtk::draw_rounded_frame(c, option, theme.radius_md,
theme.accent_soft, theme.accent_soft);
}
mtk::draw_radio(c, option, g_fsTypes[i].name, i == dlg.selected_fs, theme); mtk::draw_radio(c, option, g_fsTypes[i].name, i == dlg.selected_fs, theme);
} }
draw_dialog_footer(c, FMT_DLG_W, FMT_DLG_H, theme);
mtk::draw_modal_actions(c, mtk::draw_modal_actions(c,
dialog_primary_button_rect(FMT_DLG_W, FMT_DLG_H), "Format", dialog_primary_button_rect(FMT_DLG_W, FMT_DLG_H), "Format",
mtk::BUTTON_DANGER, mtk::BUTTON_DANGER,
@@ -294,11 +323,15 @@ void render_newpart_window() {
Color warn_color = dlg.will_init_gpt ? theme.danger : theme.text; Color warn_color = dlg.will_init_gpt ? theme.danger : theme.text;
int warn_y = 12 + fh * 2 + 20; int warn_y = 12 + fh * 2 + 20;
Rect warn_panel = {16, warn_y - 8, NP_DLG_W - 32, fh * 2 + 20};
Color warn_bg = dlg.will_init_gpt ? theme.danger_soft : theme.surface_alt;
mtk::draw_rounded_frame(c, warn_panel, theme.radius_md, warn_bg, warn_bg);
draw_centered_text(c, NP_DLG_W, warn_y, dlg.warn_line1, warn_color); draw_centered_text(c, NP_DLG_W, warn_y, dlg.warn_line1, warn_color);
draw_centered_text(c, NP_DLG_W, warn_y + fh + 4, dlg.warn_line2, warn_color); draw_centered_text(c, NP_DLG_W, warn_y + fh + 4, dlg.warn_line2, warn_color);
const char* confirm_label = dlg.will_init_gpt ? "Initialize" : "Create"; const char* confirm_label = dlg.will_init_gpt ? "Initialize" : "Create";
mtk::ButtonVariant confirm_variant = dlg.will_init_gpt ? mtk::BUTTON_DANGER : mtk::BUTTON_PRIMARY; mtk::ButtonVariant confirm_variant = dlg.will_init_gpt ? mtk::BUTTON_DANGER : mtk::BUTTON_PRIMARY;
draw_dialog_footer(c, NP_DLG_W, NP_DLG_H, theme);
mtk::draw_modal_actions(c, mtk::draw_modal_actions(c,
dialog_primary_button_rect(NP_DLG_W, NP_DLG_H), confirm_label, dialog_primary_button_rect(NP_DLG_W, NP_DLG_H), confirm_label,
confirm_variant, confirm_variant,
+3 -2
View File
@@ -18,6 +18,7 @@ endif
PROJECT_ROOT := $(shell cd ../../.. && pwd) PROJECT_ROOT := $(shell cd ../../.. && pwd)
PROGRAMS := $(PROJECT_ROOT)/programs PROGRAMS := $(PROJECT_ROOT)/programs
JPEGWRITE_LIB := $(PROGRAMS)/lib/libjpegwrite JPEGWRITE_LIB := $(PROGRAMS)/lib/libjpegwrite
LOADER_LIB := $(PROGRAMS)/lib/libloader
LIBC_LIB := $(PROGRAMS)/lib/libc LIBC_LIB := $(PROGRAMS)/lib/libc
PROG_INC := $(PROGRAMS)/include PROG_INC := $(PROGRAMS)/include
LINK_LD := $(PROGRAMS)/link.ld LINK_LD := $(PROGRAMS)/link.ld
@@ -66,11 +67,11 @@ LDFLAGS := \
# ---- Libraries ---- # ---- Libraries ----
LIBS := $(JPEGWRITE_LIB)/libjpegwrite.a $(LIBC_LIB)/liblibc.a LIBS := $(JPEGWRITE_LIB)/libjpegwrite.a $(LOADER_LIB)/liblibloader.a $(LIBC_LIB)/liblibc.a
# ---- Source files ---- # ---- Source files ----
SRCS := main.cpp SRCS := main.cpp stb_truetype_impl.cpp
OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o))
# ---- Target ---- # ---- Target ----
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,33 @@
/*
* stb_truetype_impl.cpp
* Single compilation unit for stb_truetype in MontaukOS freestanding environment
* Copyright (c) 2026 Daniel Hammer
*/
#include <cstdint>
#include <cstddef>
#include <montauk/heap.h>
#include <montauk/string.h>
#include <gui/stb_math.h>
#define STBTT_ifloor(x) ((int) stb_floor(x))
#define STBTT_iceil(x) ((int) stb_ceil(x))
#define STBTT_sqrt(x) stb_sqrt(x)
#define STBTT_pow(x,y) stb_pow(x,y)
#define STBTT_fmod(x,y) stb_fmod(x,y)
#define STBTT_cos(x) stb_cos(x)
#define STBTT_acos(x) stb_acos(x)
#define STBTT_fabs(x) stb_fabs(x)
#define STBTT_malloc(x,u) ((void)(u), montauk::malloc(x))
#define STBTT_free(x,u) ((void)(u), montauk::mfree(x))
#define STBTT_memcpy(d,s,n) montauk::memcpy(d,s,n)
#define STBTT_memset(d,v,n) montauk::memset(d,v,n)
#define STBTT_strlen(x) montauk::slen(x)
#define STBTT_assert(x) ((void)(x))
#define STB_TRUETYPE_IMPLEMENTATION
#include <gui/stb_truetype.h>
+4
View File
@@ -83,6 +83,7 @@ namespace Montauk {
static constexpr uint64_t SYS_WINSETSCALE = 65; static constexpr uint64_t SYS_WINSETSCALE = 65;
static constexpr uint64_t SYS_WINGETSCALE = 66; static constexpr uint64_t SYS_WINGETSCALE = 66;
static constexpr uint64_t SYS_WINSETCURSOR = 68; static constexpr uint64_t SYS_WINSETCURSOR = 68;
static constexpr uint64_t SYS_WINSETFLAGS = 126;
// Process management syscalls // Process management syscalls
static constexpr uint64_t SYS_PROCLIST = 61; static constexpr uint64_t SYS_PROCLIST = 61;
@@ -213,8 +214,11 @@ namespace Montauk {
uint8_t dirty; uint8_t dirty;
uint8_t cursor; // 0=arrow, 1=resize_h, 2=resize_v uint8_t cursor; // 0=arrow, 1=resize_h, 2=resize_v
uint8_t _pad2[2]; uint8_t _pad2[2];
uint32_t flags;
}; };
static constexpr uint32_t WIN_FLAG_FULLSCREEN = 1u << 0;
struct WinCreateResult { struct WinCreateResult {
int32_t id; // -1 on failure int32_t id; // -1 on failure
uint32_t _pad; uint32_t _pad;
@@ -70,6 +70,11 @@ struct WsWindow {
montauk::win_setcursor(id, cursor); montauk::win_setcursor(id, cursor);
} }
void set_flags(uint32_t flags) const {
if (id >= 0)
montauk::win_setflags(id, flags);
}
void destroy() { void destroy() {
if (id >= 0) if (id >= 0)
montauk::win_destroy(id); montauk::win_destroy(id);
+1
View File
@@ -67,6 +67,7 @@ struct Window {
bool external; // true = shared-memory window from external process bool external; // true = shared-memory window from external process
int ext_win_id; // window server ID (valid when external == true) int ext_win_id; // window server ID (valid when external == true)
uint8_t ext_cursor; // cursor style requested by external app (0=arrow, 1=resize_h, 2=resize_v) uint8_t ext_cursor; // cursor style requested by external app (0=arrow, 1=resize_h, 2=resize_v)
uint32_t ext_flags;
Rect titlebar_rect() const { Rect titlebar_rect() const {
return {frame.x, frame.y, frame.w, TITLEBAR_HEIGHT}; return {frame.x, frame.y, frame.w, TITLEBAR_HEIGHT};
+8
View File
@@ -87,6 +87,7 @@ extern "C" {
#define MTK_SYS_WINGETSCALE 66 #define MTK_SYS_WINGETSCALE 66
#define MTK_SYS_MEMSTATS 67 #define MTK_SYS_MEMSTATS 67
#define MTK_SYS_WINSETCURSOR 68 #define MTK_SYS_WINSETCURSOR 68
#define MTK_SYS_WINSETFLAGS 126
#define MTK_SYS_FDELETE 77 #define MTK_SYS_FDELETE 77
#define MTK_SYS_FMKDIR 78 #define MTK_SYS_FMKDIR 78
#define MTK_SYS_FRENAME 94 #define MTK_SYS_FRENAME 94
@@ -111,6 +112,8 @@ extern "C" {
#define MTK_EVENT_CLOSE 3 #define MTK_EVENT_CLOSE 3
#define MTK_EVENT_SCALE 4 #define MTK_EVENT_SCALE 4
#define MTK_WIN_FLAG_FULLSCREEN (1u << 0)
/* Audio control commands */ /* Audio control commands */
#define MTK_AUDIO_SET_VOLUME 0 #define MTK_AUDIO_SET_VOLUME 0
#define MTK_AUDIO_GET_VOLUME 1 #define MTK_AUDIO_GET_VOLUME 1
@@ -162,6 +165,7 @@ typedef struct {
uint8_t dirty; uint8_t dirty;
uint8_t cursor; uint8_t cursor;
uint8_t _pad2[2]; uint8_t _pad2[2];
uint32_t flags;
} mtk_win_info; } mtk_win_info;
typedef struct { typedef struct {
@@ -492,6 +496,10 @@ static inline int mtk_win_setcursor(int id, int cursor) {
return (int)_mtk_syscall2(MTK_SYS_WINSETCURSOR, (long)id, (long)cursor); return (int)_mtk_syscall2(MTK_SYS_WINSETCURSOR, (long)id, (long)cursor);
} }
static inline int mtk_win_setflags(int id, uint32_t flags) {
return (int)_mtk_syscall2(MTK_SYS_WINSETFLAGS, (long)id, (long)flags);
}
static inline int mtk_win_setscale(int scale) { static inline int mtk_win_setscale(int scale) {
return (int)_mtk_syscall1(MTK_SYS_WINSETSCALE, (long)scale); return (int)_mtk_syscall1(MTK_SYS_WINSETSCALE, (long)scale);
} }
@@ -436,5 +436,8 @@ namespace montauk {
inline int win_setcursor(int id, int cursor) { inline int win_setcursor(int id, int cursor) {
return (int)syscall2(Montauk::SYS_WINSETCURSOR, (uint64_t)id, (uint64_t)cursor); return (int)syscall2(Montauk::SYS_WINSETCURSOR, (uint64_t)id, (uint64_t)cursor);
} }
inline int win_setflags(int id, uint32_t flags) {
return (int)syscall2(Montauk::SYS_WINSETFLAGS, (uint64_t)id, (uint64_t)flags);
}
} }