# Writing GUI Applications for MontaukOS This guide covers how to build graphical applications for MontaukOS, from standalone Window Server clients to desktop-integrated apps. ## Table of Contents - [App Types](#app-types) - [Standalone Window Server Apps](#standalone-window-server-apps) - [Desktop-Integrated Apps](#desktop-integrated-apps) - [Drawing and Rendering](#drawing-and-rendering) - [Text and Fonts](#text-and-fonts) - [Input Handling](#input-handling) - [Widgets](#widgets) - [Colors and Theming](#colors-and-theming) - [Memory Management](#memory-management) - [Networking and HTTPS](#networking-and-https) - [App Manifests](#app-manifests) - [Build System](#build-system) --- ## App Types MontaukOS supports two kinds of GUI applications: | | Standalone Apps | Desktop Apps | |---|---|---| | **Location** | `programs/src//` | `programs/src/desktop/apps/` | | **Window** | Own process, shared-memory pixel buffer | Embedded in desktop compositor | | **Event loop** | `win_poll()` syscall | Callback-driven (`on_draw`, `on_mouse`, `on_key`) | | **Drawing** | Direct pixel buffer writes | `Canvas` abstraction | | **Examples** | Spreadsheet, Music, Wikipedia | File Manager, System Info, Settings | **Choose standalone** when you need a separate process (e.g., networking, heavy computation, isolation). **Choose desktop-integrated** for lightweight tools that benefit from tight compositor integration. --- ## Standalone Window Server Apps Standalone apps are separate ELF binaries that communicate with the Window Server through syscalls. They get a shared-memory pixel buffer and manage their own event loop. ### Minimal Example ```cpp #include #include #include #include #include static TrueTypeFont* g_font; static int g_win_w, g_win_h; static void render(uint32_t* pixels) { // Clear background for (int i = 0; i < g_win_w * g_win_h; i++) pixels[i] = Color::from_rgb(0xFF, 0xFF, 0xFF).to_pixel(); // Draw text if (g_font) g_font->draw_to_buffer(pixels, g_win_w, g_win_h, 20, 30, "Hello, MontaukOS!", Color::from_rgb(0x33, 0x33, 0x33), 18); } extern "C" void _start() { // Load font g_font = new TrueTypeFont(); g_font->init("0:/fonts/Roboto-Medium.ttf"); // Create window g_win_w = 400; g_win_h = 300; montauk::abi::WinCreateResult wres; montauk::win_create("My App", g_win_w, g_win_h, &wres); int win_id = wres.id; uint32_t* pixels = (uint32_t*)(uintptr_t)wres.pixelVa; // Initial render render(pixels); montauk::win_present(win_id); // Event loop while (true) { montauk::abi::WinEvent ev; int r = montauk::win_poll(win_id, &ev); if (r < 0) break; // Window destroyed externally if (r == 0) { montauk::sleep_ms(16); // ~60 FPS idle continue; } if (ev.type == 3) break; // Close event if (ev.type == 2) { // Resize g_win_w = ev.resize.w; g_win_h = ev.resize.h; pixels = (uint32_t*)(uintptr_t)montauk::win_resize(win_id, g_win_w, g_win_h); } if (ev.type == 0) { // Keyboard // ev.key.ascii, ev.key.scancode, ev.key.pressed } if (ev.type == 1) { // Mouse // ev.mouse.x, ev.mouse.y, ev.mouse.buttons } render(pixels); montauk::win_present(win_id); } montauk::win_destroy(win_id); montauk::exit(0); } ``` ### Window Lifecycle ``` win_create() Create window, get pixel buffer pointer | v win_present() Push current pixel buffer to screen | v win_poll() Receive events (returns 0 if none, <0 if closed) | v win_resize() Handle resize, get new pixel buffer pointer | v win_destroy() Clean up window ``` ### Event Types Events are delivered via `win_poll()` into a `WinEvent` struct: | `ev.type` | Event | Fields | |---|---|---| | 0 | Keyboard | `ev.key.scancode`, `ev.key.ascii`, `ev.key.pressed`, `ev.key.shift`, `ev.key.ctrl`, `ev.key.alt` | | 1 | Mouse | `ev.mouse.x`, `ev.mouse.y`, `ev.mouse.buttons`, `ev.mouse.prev_buttons`, `ev.mouse.scroll` | | 2 | Resize | `ev.resize.w`, `ev.resize.h` | | 3 | Close | (none) | ### Drawing Helpers For new standalone apps, prefer the shared helpers in `#include `. It provides: - `gui::WsWindow` for `win_create()` / `win_poll()` / `win_resize()` / `win_present()` - `gui::Canvas` for drawing into the window buffer - immediate-mode helpers like `draw_text()`, `draw_button()`, and `fill_circle()` Older apps in the tree still define local `px_*` helpers, but new code should not need to. ```cpp gui::WsWindow win; win.create("My App", 400, 300); gui::Canvas c = win.canvas(); c.fill(gui::colors::WHITE); draw_text(c, g_font, 20, 30, "Hello", gui::colors::TEXT_COLOR, 18); draw_button(c, g_font, 20, 60, 96, 28, "OK", gui::colors::ACCENT, gui::colors::WHITE, 6, 16); ``` ### Rounded Rectangles ```cpp static void px_fill_rounded(uint32_t* px, int bw, int bh, int x, int y, int w, int h, int r, uint32_t color) { for (int row = y; row < y + h && row < bh; row++) { for (int col = x; col < x + w && col < bw; col++) { int dx = 0, dy = 0; if (col < x + r && row < y + r) { dx = x + r - col; dy = y + r - row; } else if (col >= x+w-r && row < y + r) { dx = col - (x+w-r-1); dy = y + r - row; } else if (col < x + r && row >= y+h-r) { dx = x + r - col; dy = row - (y+h-r-1); } else if (col >= x+w-r && row >= y+h-r) { dx = col - (x+w-r-1); dy = row - (y+h-r-1); } if (dx * dx + dy * dy <= r * r) px[row * bw + col] = color; else if (dx == 0 && dy == 0) px[row * bw + col] = color; } } } ``` --- ## Desktop-Integrated Apps Desktop apps are compiled into the desktop binary itself. They register callback functions that the compositor calls during its event loop. ### Creating a Desktop App **Step 1: Define your app state** ```cpp // In apps/app_myapp.cpp struct MyAppState { int counter; char label[64]; }; ``` **Step 2: Implement callbacks** ```cpp static void myapp_on_draw(Window* win, Framebuffer& fb) { MyAppState* state = (MyAppState*)win->app_data; Canvas c(win); c.fill(colors::WINDOW_BG); // Draw toolbar c.fill_rect(0, 0, win->content_w, 36, Color::from_rgb(0xF5, 0xF5, 0xF5)); c.hline(0, 36, win->content_w, colors::BORDER); // Draw content c.text(20, 60, state->label, colors::TEXT_COLOR); } static void myapp_on_mouse(Window* win, MouseEvent& ev) { MyAppState* state = (MyAppState*)win->app_data; if (ev.left_pressed()) { state->counter++; win->dirty = true; // Request redraw } } static void myapp_on_key(Window* win, const montauk::abi::KeyEvent& key) { if (!key.pressed) return; MyAppState* state = (MyAppState*)win->app_data; // Handle keystrokes... win->dirty = true; } static void myapp_on_close(Window* win) { MyAppState* state = (MyAppState*)win->app_data; montauk::mfree(state); } ``` **Step 3: Write the open function** ```cpp void open_myapp(DesktopState* ds) { int idx = desktop_create_window(ds, "My App", 400, 300, 320, 400); if (idx < 0) return; Window* win = &ds->windows[idx]; MyAppState* state = (MyAppState*)montauk::malloc(sizeof(MyAppState)); montauk::memset(state, 0, sizeof(MyAppState)); win->app_data = state; win->on_draw = myapp_on_draw; win->on_mouse = myapp_on_mouse; win->on_key = myapp_on_key; win->on_close = myapp_on_close; win->dirty = true; } ``` **Step 4: Register in the app menu** Add an entry in `desktop_init()` (`main.cpp`) to the app menu so users can launch it. Include the `open_myapp` function in `apps_common.hpp` or similar. ### Callback Reference | Callback | Signature | When Called | |---|---|---| | `on_draw` | `void(Window*, Framebuffer&)` | Every frame when `win->dirty` is true | | `on_mouse` | `void(Window*, MouseEvent&)` | Mouse event within window content area | | `on_key` | `void(Window*, const KeyEvent&)` | Keyboard event while window is focused | | `on_close` | `void(Window*)` | Window close button clicked | | `on_poll` | `void(Window*)` | Every frame, for background processing | ### The `dirty` Flag Desktop apps use a `dirty` flag to control redraws. Set `win->dirty = true` after any state change that requires a visual update. The compositor skips `on_draw` for non-dirty windows. --- ## Drawing and Rendering ### Canvas API (Desktop Apps) The `Canvas` wraps a window's pixel buffer with drawing primitives: ```cpp Canvas c(win); // Construct from Window* // Fills c.fill(Color c); // Entire buffer c.fill_rect(int x, int y, int w, int h, Color c); // Rectangle c.fill_rounded_rect(int x, int y, int w, int h, int r, Color c); // Rounded rect // Lines c.hline(int x, int y, int len, Color c); // Horizontal c.vline(int x, int y, int len, Color c); // Vertical c.rect(int x, int y, int w, int h, Color c); // Outline // Text c.text(int x, int y, const char* str, Color c); // TrueType or bitmap c.text_2x(int x, int y, const char* str, Color c); // 2x scaled bitmap c.text_mono(int x, int y, const char* str, Color c); // Monospace // UI elements c.button(int x, int y, int w, int h, const char* label, Color bg, Color fg, int radius); // Styled button c.icon(int x, int y, const SvgIcon& ic); // SVG icon // Layout helpers c.kv_line(int x, int* y, const char* line, Color c, int line_h); // Key-value line c.separator(int x_start, int x_end, int* y, Color c, int spacing); // Horizontal separator ``` ### Framebuffer API (Low-Level) For direct framebuffer access (used by the compositor itself and fullscreen apps): ```cpp Framebuffer fb; fb.put_pixel(x, y, color); fb.put_pixel_alpha(x, y, color); // With alpha blending fb.fill_rect(x, y, w, h, color); fb.fill_rect_alpha(x, y, w, h, color); fb.blit(x, y, w, h, pixels); // Copy pixel region fb.blit_alpha(x, y, w, h, pixels); // With alpha blending fb.clear(color); fb.flip(); // Swap to hardware ``` ### Drawing Primitives From `gui/draw.hpp`, available for both Framebuffer-based rendering: ```cpp draw_hline(fb, x, y, w, color); draw_vline(fb, x, y, h, color); draw_rect(fb, x, y, w, h, color); fill_rounded_rect(fb, x, y, w, h, radius, color); fill_circle(fb, cx, cy, r, color); draw_circle(fb, cx, cy, r, color); draw_line(fb, x0, y0, x1, y1, color); // Bresenham's draw_shadow(fb, x, y, w, h, offset, color); ``` --- ## Text and Fonts ### TrueType Fonts (Preferred) MontaukOS uses `stb_truetype` for font rendering. Fonts are loaded from the VFS: ```cpp TrueTypeFont* font = new TrueTypeFont(); font->init("0:/fonts/Roboto-Medium.ttf"); // Render text to a pixel buffer font->draw_to_buffer(pixels, buf_w, buf_h, x, y, "Hello", color, 18); // Measure text width before drawing int width = font->measure_text("Hello", 18); // Get line height for layout int line_h = font->get_line_height(18); ``` ### System Fonts The desktop initializes a set of global fonts: ```cpp fonts::init(); // Call once at startup // Available fonts fonts::system_font // Roboto-Medium.ttf (UI text) fonts::system_bold // Roboto-Bold.ttf (headings) fonts::mono // JetBrainsMono-Regular.ttf (code/terminal) fonts::mono_bold // JetBrainsMono-Bold.ttf // Standard sizes fonts::UI_SIZE // 18 (body text) fonts::TITLE_SIZE // 18 (window titles) fonts::LARGE_SIZE // 28 (headings) fonts::TERM_SIZE // 18 (terminal) ``` ### Glyph Caching TrueType fonts cache rasterized glyphs per pixel size. Up to 4 size caches are maintained per font. Access the cache directly for advanced metrics: ```cpp GlyphCache* cache = font->get_cache(18); // cache->ascent, cache->descent — for line-height calculation ``` ### Bitmap Font (Fallback) An 8x8 bitmap font is always available for basic text rendering when TrueType is not loaded: ```cpp draw_char(fb, x, y, 'A', color); draw_text(fb, x, y, "Hello", color); int w = text_width("Hello"); ``` --- ## Input Handling ### Keyboard ```cpp // In standalone apps (via win_poll) if (ev.type == 0) { montauk::abi::KeyEvent& key = ev.key; if (!key.pressed) { /* key release */ } if (key.ascii >= 0x20 && key.ascii < 0x7F) { // Printable character } // Special keys by scancode switch (key.scancode) { case 0x01: /* Escape */ break; case 0x0E: /* Backspace */ break; case 0x1C: /* Enter */ break; case 0x0F: /* Tab */ break; case 0x53: /* Delete */ break; case 0x48: /* Up */ break; case 0x50: /* Down */ break; case 0x4B: /* Left */ break; case 0x4D: /* Right */ break; case 0x47: /* Home */ break; case 0x4F: /* End */ break; case 0x49: /* Page Up */ break; case 0x51: /* Page Down */ break; } // Modifiers if (key.ctrl) { /* Ctrl held */ } if (key.shift) { /* Shift held */ } if (key.alt) { /* Alt held */ } } ``` ### Mouse ```cpp // In standalone apps (via win_poll) if (ev.type == 1) { int mx = ev.mouse.x; int my = ev.mouse.y; // Button state bool left_down = ev.mouse.buttons & 0x01; bool right_down = ev.mouse.buttons & 0x02; // Detect clicks (press edge) bool left_pressed = (ev.mouse.buttons & 0x01) && !(ev.mouse.prev_buttons & 0x01); bool left_released = !(ev.mouse.buttons & 0x01) && (ev.mouse.prev_buttons & 0x01); // Scroll wheel int scroll = ev.mouse.scroll; // Positive = up, negative = down } ``` In desktop apps, the `MouseEvent` struct provides convenience methods: ```cpp void myapp_on_mouse(Window* win, MouseEvent& ev) { if (ev.left_pressed()) { /* click start */ } if (ev.left_released()) { /* click end */ } if (ev.left_held()) { /* dragging */ } if (ev.right_pressed()) { /* context menu */ } if (ev.scroll != 0) { /* scroll */ } } ``` ### Hit Testing A common pattern for clickable UI regions: ```cpp struct ButtonRect { int x, y, w, h; }; bool hit_test(ButtonRect& btn, int mx, int my) { return mx >= btn.x && mx < btn.x + btn.w && my >= btn.y && my < btn.y + btn.h; } ``` --- ## Widgets MontaukOS provides built-in widget types in `gui/widgets.hpp`: ### Button ```cpp Button btn; btn.init(x, y, width, height, "Click Me"); btn.bg = colors::ACCENT; btn.fg = colors::WHITE; btn.on_click = [](void* data) { /* handle click */ }; btn.userdata = my_state; // In draw callback btn.draw(fb); // In mouse callback btn.handle_mouse(ev); ``` ### TextBox ```cpp TextBox tb; tb.init(x, y, width, height); // In draw callback tb.draw(fb); // In mouse callback (sets focus) tb.handle_mouse(ev); // In key callback (text input) tb.handle_key(key); // Read value const char* value = tb.text; ``` ### Scrollbar ```cpp Scrollbar sb; sb.init(x, y, width, height); sb.content_height = 2000; // Total content height sb.view_height = 400; // Visible area height // In draw callback sb.draw(fb); // In mouse callback sb.handle_mouse(ev); // Use scroll_offset for content positioning int offset = sb.scroll_offset; ``` --- ## Colors and Theming ### Color Construction ```cpp Color c1 = Color::from_rgb(0xFF, 0x00, 0x00); // Red Color c2 = Color::from_rgba(0x00, 0x00, 0xFF, 0x80); // Semi-transparent blue Color c3 = Color::from_hex(0x367BF0); // From hex uint32_t pixel = c3.to_pixel(); // ARGB for pixel buffer ``` ### System Colors Defined in `gui/gui.hpp` under the `colors` namespace: | Constant | Hex | Usage | |---|---|---| | `WINDOW_BG` | `#FFFFFF` | Window content background | | `TEXT_COLOR` | `#333333` | Primary text | | `ACCENT` | `#367BF0` | Links, selections, active elements | | `BORDER` | `#D0D0D0` | Window/widget borders | | `PANEL_BG` | `#2B3E50` | Taskbar/panel background | | `PANEL_TEXT` | `#FFFFFF` | Panel text | | `TITLEBAR_BG` | `#F5F5F5` | Window titlebar | | `DESKTOP_BG` | `#E0E0E0` | Desktop background | | `CLOSE_BTN` | `#FF5F57` | Close button (red) | | `MAX_BTN` | `#28CA42` | Maximize button (green) | | `MIN_BTN` | `#FFBD2E` | Minimize button (yellow) | | `TERM_BG` | `#2D2D2D` | Terminal background | | `TERM_FG` | `#CCCCCC` | Terminal text | | `SCROLLBAR_BG` | | Scrollbar track | | `SCROLLBAR_FG` | | Scrollbar thumb | ### Toolbar Convention Standard toolbar pattern used across desktop apps: ```cpp // 36px tall, light gray background, thin bottom border c.fill_rect(0, 0, win->content_w, 36, Color::from_rgb(0xF5, 0xF5, 0xF5)); c.hline(0, 36, win->content_w, colors::BORDER); // 24x24 icon buttons centered at y=6 c.icon(8, 6, my_icon); // Content starts below toolbar int content_y = 37; ``` --- ## Memory Management ### Userspace Heap Use `montauk::malloc`, `montauk::mfree`, and `montauk::realloc` for dynamic allocation: ```cpp #include MyState* state = (MyState*)montauk::malloc(sizeof(MyState)); montauk::memset(state, 0, sizeof(MyState)); // ... use state ... montauk::mfree(state); // Resize char* buf = (char*)montauk::malloc(256); buf = (char*)montauk::realloc(buf, 512); ``` The allocator uses size-class buckets (32 to 4096 bytes) with an overflow list for larger allocations. ### Kernel Page Allocation `montauk::alloc` / `montauk::free` allocate kernel pages. Avoid for temporary buffers; use the heap instead. ### Important Notes - **User stack is 32 KiB** (8 pages). Deep call chains (e.g., TrueType rendering) can approach this limit. Avoid large stack allocations. - Use `inline` (not `static`) for shared globals in headers to avoid per-translation-unit copies and heap corruption. - The libc needs `-fno-tree-loop-distribute-patterns` in CFLAGS to prevent GCC from converting `memcpy`/`memset` into calls to themselves. --- ## Networking and HTTPS MontaukOS provides a shared TLS library (`tls/tls.hpp`) backed by BearSSL, and the MontaukAI dev environment adds a higher-level HTTP wrapper (`http/http.hpp`) on top. Build with `USE_TLS=1` to link TLS support. ### HTTP Wrapper (`http/http.hpp`) Header-only library that handles DNS resolution, request building, TLS, response parsing, and cleanup. All functions return an `http::Response` struct. #### Setup ```cpp #include // Load CA certificates once at startup (required for HTTPS) tls::TrustAnchors tas = tls::load_trust_anchors(); ``` #### GET ```cpp auto resp = http::get("api.example.com", "/v1/data", tas); if (resp.status == 200) { // resp.body is a pointer to the response body // resp.body_len is its length } http::free_response(&resp); ``` #### POST ```cpp const char* json = "{\"name\":\"MontaukOS\",\"version\":1}"; auto resp = http::post("api.example.com", "/v1/submit", "application/json", json, montauk::slen(json), tas); if (resp.status == 201) { // Created successfully } http::free_response(&resp); ``` #### Other Methods (PUT, PATCH, DELETE, ...) ```cpp auto resp = http::request("PUT", "api.example.com", "/v1/item/42", "application/json", body, bodyLen, tas); http::free_response(&resp); // DELETE with no body auto resp2 = http::request("DELETE", "api.example.com", "/v1/item/42", nullptr, nullptr, 0, tas); http::free_response(&resp2); ``` #### Plain HTTP (No TLS, Port 80) ```cpp auto resp = http::get_plain("example.com", "/"); if (resp.status == 200) { // resp.body ... } http::free_response(&resp); ``` #### Reading Response Headers ```cpp char content_type[128]; if (http::get_header(&resp, "Content-Type", content_type, sizeof(content_type))) { // content_type is e.g. "application/json; charset=utf-8" } ``` #### Custom Headers Pass extra headers as a string with `\r\n` terminators: ```cpp auto resp = http::get("api.example.com", "/v1/data", tas, 32768, // response buffer size "Authorization: Bearer tok_abc123\r\n" "Accept: application/json\r\n"); http::free_response(&resp); ``` #### Cancellable Requests For GUI apps that need to stay responsive during network I/O: ```cpp static bool g_quit = false; static bool check_abort() { return g_quit; } auto resp = http::get("api.example.com", "/v1/slow", tas, 32768, nullptr, check_abort); http::free_response(&resp); ``` Set `g_quit = true` from your keyboard handler (e.g., on Escape) to cancel mid-request. #### Response Struct Reference ```cpp struct http::Response { int status; // HTTP status code (200, 404, ...) or -1 on error const char* headers; // Pointer to header block (within raw buffer) int headers_len; const char* body; // Pointer to body (within raw buffer) int body_len; char* raw; // Owned buffer — freed by free_response() int raw_len; }; ``` #### Function Signatures ```cpp // HTTPS GET http::Response http::get(const char* host, const char* path, const tls::TrustAnchors& tas, int resp_buf_size = 32768, const char* extra_headers = nullptr, tls::AbortCheckFn abort_check = nullptr); // HTTPS POST http::Response http::post(const char* host, const char* path, const char* content_type, const char* body, int body_len, const tls::TrustAnchors& tas, int resp_buf_size = 32768, const char* extra_headers = nullptr, tls::AbortCheckFn abort_check = nullptr); // HTTPS with any method http::Response http::request(const char* method, const char* host, const char* path, const char* content_type, const char* body, int body_len, const tls::TrustAnchors& tas, int resp_buf_size = 32768, const char* extra_headers = nullptr, tls::AbortCheckFn abort_check = nullptr); // Plain HTTP GET (port 80, no TLS) http::Response http::get_plain(const char* host, const char* path, int resp_buf_size = 32768, const char* extra_headers = nullptr); // Parse raw HTTP response buffer (used internally, available if needed) int http::parse_response(char* buf, int len, http::Response* out); // Case-insensitive header lookup bool http::get_header(const http::Response* resp, const char* name, char* out_val, int max_len); // Free the response's raw buffer void http::free_response(http::Response* resp); ``` ### Low-Level TLS API (`tls/tls.hpp`) If you need more control than `http::` provides (e.g., streaming responses, custom BearSSL setup), use the TLS layer directly: ```cpp #include tls::TrustAnchors tas = tls::load_trust_anchors(); // Build raw HTTP request yourself char req[512]; // ... "GET /stream HTTP/1.1\r\nHost: ...\r\n\r\n" ... char buf[65536]; int n = tls::https_fetch("example.com", ip, 443, req, reqLen, tas, buf, sizeof(buf)); ``` See `syscalls.md` for the full `tls::` API reference. ### Plain TCP/UDP For non-TLS networking without the HTTP wrapper, use the raw socket syscalls directly (see `syscalls.md`): ```cpp int sock = montauk::socket(montauk::abi::SOCK_TCP); // or SOCK_UDP montauk::connect(sock, ip, port); montauk::send(sock, data, len); int n = montauk::recv(sock, buf, maxLen); montauk::closesocket(sock); ``` --- ## App Manifests External standalone apps can be discovered by the desktop through TOML manifest files placed in `0:/apps/`: ```toml [app] name = "My App" binary = "myapp" icon = "myapp_icon.svg" [menu] category = "Applications" visible = true ``` **Categories:** `Applications`, `Internet`, `System`, `Games` The desktop scans `0:/apps/` at startup and adds matching entries to the application menu. The `binary` field is the executable name (looked up in the system path). --- ## Build System ### Independent Development (MontaukAI) The `MontaukAI/` directory provides a self-contained build environment. Edit the top of `Makefile` to configure your app: ```makefile APP_NAME := myapp SRCS := src/main.cpp src/stb_truetype_impl.cpp src/cxxrt.cpp src/network.cpp ``` Build with optional feature flags: ```bash make # GUI-only app make USE_TLS=1 # With HTTPS/TLS (links libtls + libbearssl) make USE_JPEG=1 # With JPEG decoding (links libjpeg) make USE_TLS=1 USE_JPEG=1 # Both make install # Copy ELF to MontaukOS ramdisk ``` The sysroot contains all headers and pre-built libraries: ``` sysroot/ ├── include/ │ ├── montauk/ syscall.h, heap.h, string.h, config.h, toml.h, user.h │ ├── gui/ gui.hpp, canvas.hpp, truetype.hpp, widgets.hpp, svg.hpp, ... │ ├── tls/ tls.hpp (HTTPS/TLS) │ ├── Api/ Syscall.hpp (low-level syscall numbers) │ ├── libc/ stdio.h, stdlib.h, string.h, ... (freestanding libc) │ ├── bearssl*.h BearSSL headers (for USE_TLS=1) │ └── (freestanding C/C++ standard headers) └── lib/ ├── crt1.o Startup shim for main(argc, argv) ports ├── crti.o CRT init prologue placeholder ├── crtn.o CRT init epilogue placeholder ├── liblibc.a C library (always linked) ├── libtls.a TLS helper library ├── libbearssl.a BearSSL crypto └── libjpeg.a JPEG decoding (stb_image) ``` Key build details: - **Toolchain:** `x86_64-elf-g++` cross-compiler (falls back to system g++) - **Standard:** C++20 (`-std=gnu++20`), freestanding, no exceptions/RTTI - **SSE:** Enabled (`-msse -msse2`) for floating-point / TrueType rendering - **Entry point:** `extern "C" void _start()` by default, or `main(argc, argv)` with `USE_CRT=1` - **Load address:** `0x400000` (set in `link.ld`) - **Runtime support:** `src/cxxrt.cpp` provides `operator new/delete` via `montauk::malloc/mfree` - **TrueType support:** `src/stb_truetype_impl.cpp` provides the stb_truetype implementation `USE_CRT=1` is primarily for plain C ports and other code that already expects `main(argc, argv)`. The shared CRT does not run C++ global constructors or destructors yet, so the default template still uses `_start()`. ### In-Tree Development Standalone apps can also live in `MontaukOS/programs/src//` with their own `Makefile`. Each app's Makefile sets `SRCS`, `CXXFLAGS`, `LDFLAGS`, and links against libraries in `programs/lib/`. Desktop-integrated apps are compiled as part of the desktop binary — add your `.cpp` file to the desktop's source list in `programs/src/desktop/Makefile`.