/* * main.cpp * MontaukOS Installer — entry point, event loop, state * Copyright (c) 2026 Daniel Hammer */ #include "installer.h" #include // ============================================================================ // Global state definitions // ============================================================================ int g_win_w = INIT_W; int g_win_h = INIT_H; int FONT_SIZE = 18; int FONT_SM = 14; InstallerState g_state; TrueTypeFont* g_font = nullptr; uint32_t* g_pixels = nullptr; uint32_t* g_backbuf = nullptr; int g_win_id = -1; static WsWindow g_window; void apply_scale(int scale) { switch (scale) { case 0: FONT_SIZE = 14; FONT_SM = 11; break; case 2: FONT_SIZE = 22; FONT_SM = 17; break; default: FONT_SIZE = 18; FONT_SM = 14; break; } } // ============================================================================ // Helpers // ============================================================================ void set_status(const char* msg) { int i = 0; for (; i < 79 && msg[i]; i++) g_state.status[i] = msg[i]; g_state.status[i] = '\0'; g_state.status_time = montauk::get_milliseconds(); } void add_log(const char* msg) { if (g_state.log_count >= LOG_LINES) { // Scroll: shift all lines up by one for (int j = 0; j < LOG_LINES - 1; j++) montauk::memcpy(g_state.log[j], g_state.log[j + 1], LOG_LINE_LEN); g_state.log_count = LOG_LINES - 1; } int i = 0; for (; i < LOG_LINE_LEN - 1 && msg[i]; i++) g_state.log[g_state.log_count][i] = msg[i]; g_state.log[g_state.log_count][i] = '\0'; g_state.log_count++; } void flush_ui() { if (g_pixels && g_backbuf && g_window.id >= 0) { render(g_backbuf); montauk::memcpy(g_pixels, g_backbuf, g_win_w * g_win_h * 4); g_window.present(); } } void format_disk_size(char* buf, int bufsize, uint64_t sectors, uint16_t sectorSize) { uint64_t bytes = sectors * sectorSize; uint64_t gb = bytes / (1024ULL * 1024 * 1024); if (gb >= 1024) { uint64_t tb = gb / 1024; uint64_t frac = ((gb % 1024) * 10) / 1024; snprintf(buf, bufsize, "%lu.%lu TB", (unsigned)tb, (unsigned)frac); } else if (gb > 0) { uint64_t frac = ((bytes % (1024ULL * 1024 * 1024)) * 10) / (1024ULL * 1024 * 1024); snprintf(buf, bufsize, "%lu.%lu GB", (unsigned)gb, (unsigned)frac); } else { uint64_t mb = bytes / (1024ULL * 1024); snprintf(buf, bufsize, "%lu MB", (unsigned)mb); } } // ============================================================================ // Mouse handling // ============================================================================ static bool handle_click(int mx, int my) { auto& st = g_state; int fh = g_font ? g_font->get_cache(FONT_SIZE)->ascent - g_font->get_cache(FONT_SIZE)->descent : 16; int fh_sm = g_font ? g_font->get_cache(FONT_SM)->ascent - g_font->get_cache(FONT_SM)->descent : 12; // Common bottom button area int btn_w = 120, btn_h = 34; int btn_y = g_win_h - STATUS_H - btn_h - 12; if (st.step == STEP_MODE_SELECT) { // Two mode cards int y = CONTENT_TOP + 16 + fh + 4 + fh_sm + 16; int card_h = 52, card_x = 16, card_w = g_win_w - 32; // Install card if (mx >= card_x && mx < card_x + card_w && my >= y && my < y + card_h) { st.mode = MODE_INSTALL; installer_refresh_disks(); st.step = STEP_SELECT_DISK; return true; } y += card_h + 8; // Update card if (mx >= card_x && mx < card_x + card_w && my >= y && my < y + card_h) { st.mode = MODE_UPDATE; installer_refresh_parts(); st.step = STEP_UPDATE_SELECT_PART; return true; } } else if (st.step == STEP_SELECT_DISK) { // Disk list items int y = CONTENT_TOP + 40 + fh + 12; for (int i = 0; i < st.disk_count; i++) { int item_h = 48; if (mx >= 16 && mx < g_win_w - 16 && my >= y && my < y + item_h) { st.selected_disk = i; return true; } y += item_h + 4; } // "Next" button int next_x = g_win_w - btn_w - 16; if (st.selected_disk >= 0 && mx >= next_x && mx < next_x + btn_w && my >= btn_y && my < btn_y + btn_h) { st.step = STEP_PARTITION_SCHEME; return true; } // "Refresh" button int ref_w = 80; int ref_x = next_x - ref_w - 8; if (mx >= ref_x && mx < ref_x + ref_w && my >= btn_y && my < btn_y + btn_h) { installer_refresh_disks(); return true; } } else if (st.step == STEP_PARTITION_SCHEME) { // Scheme radio buttons int y = CONTENT_TOP + 40 + fh + 12; for (int i = 0; i < SCHEME_COUNT; i++) { int item_h = 52; if (mx >= 16 && mx < g_win_w - 16 && my >= y && my < y + item_h) { st.partition_scheme = i; return true; } y += item_h + 4; } // "Next" button int next_x = g_win_w - btn_w - 16; if (mx >= next_x && mx < next_x + btn_w && my >= btn_y && my < btn_y + btn_h) { st.step = STEP_CONFIRM; return true; } // "Back" button int back_x = next_x - btn_w - 8; if (mx >= back_x && mx < back_x + btn_w && my >= btn_y && my < btn_y + btn_h) { st.step = STEP_SELECT_DISK; return true; } } else if (st.step == STEP_CONFIRM) { int center_x = g_win_w / 2; int gap = 16; // "Install" button int conf_x = center_x - btn_w - gap / 2; if (mx >= conf_x && mx < conf_x + btn_w && my >= btn_y && my < btn_y + btn_h) { st.step = STEP_INSTALLING; st.log_count = 0; return true; } // "Back" button int canc_x = center_x + gap / 2; if (mx >= canc_x && mx < canc_x + btn_w && my >= btn_y && my < btn_y + btn_h) { st.step = STEP_PARTITION_SCHEME; return true; } } else if (st.step == STEP_DONE || st.step == STEP_ERROR) { int close_x = (g_win_w - 100) / 2; if (mx >= close_x && mx < close_x + 100 && my >= btn_y && my < btn_y + btn_h) { return false; // signal quit } } else if (st.step == STEP_UPDATE_SELECT_PART) { // Partition list items int y = CONTENT_TOP + 16 + fh + 4 + fh_sm + 12; for (int i = 0; i < st.part_count; i++) { int item_h = 48; if (mx >= 16 && mx < g_win_w - 16 && my >= y && my < y + item_h) { st.selected_part = i; return true; } y += item_h + 4; } // "Next" button int next_x = g_win_w - btn_w - 16; if (st.selected_part >= 0 && mx >= next_x && mx < next_x + btn_w && my >= btn_y && my < btn_y + btn_h) { st.step = STEP_UPDATE_CONFIRM; return true; } // "Back" button int back_x = next_x - btn_w - 8; if (mx >= back_x && mx < back_x + btn_w && my >= btn_y && my < btn_y + btn_h) { st.step = STEP_MODE_SELECT; return true; } } else if (st.step == STEP_UPDATE_CONFIRM) { int center_x = g_win_w / 2; int gap = 16; // "Update" button int upd_x = center_x - btn_w - gap / 2; if (mx >= upd_x && mx < upd_x + btn_w && my >= btn_y && my < btn_y + btn_h) { st.step = STEP_UPDATING; st.log_count = 0; return true; } // "Back" button int back_x = center_x + gap / 2; if (mx >= back_x && mx < back_x + btn_w && my >= btn_y && my < btn_y + btn_h) { st.step = STEP_UPDATE_SELECT_PART; return true; } } return true; } // ============================================================================ // Entry point // ============================================================================ extern "C" void _start() { montauk::memset(&g_state, 0, sizeof(g_state)); g_state.selected_disk = -1; g_state.selected_part = -1; g_state.partition_scheme = SCHEME_EFI_EXT2; g_state.step = STEP_MODE_SELECT; // Load font { TrueTypeFont* f = (TrueTypeFont*)montauk::malloc(sizeof(TrueTypeFont)); if (f) { montauk::memset(f, 0, sizeof(TrueTypeFont)); if (!f->init("0:/fonts/Roboto-Medium.ttf")) { montauk::mfree(f); f = nullptr; } } g_font = f; } apply_scale(montauk::win_getscale()); installer_refresh_disks(); if (!g_window.create("Install MontaukOS", INIT_W, INIT_H)) montauk::exit(1); g_pixels = g_window.pixels; g_win_id = g_window.id; g_backbuf = (uint32_t*)montauk::malloc(g_win_w * g_win_h * 4); render(g_backbuf); montauk::memcpy(g_pixels, g_backbuf, g_win_w * g_win_h * 4); g_window.present(); bool install_triggered = false; while (true) { Montauk::WinEvent ev; bool redraw = false; int r = g_window.poll(&ev); if (r < 0) break; if (r == 0) { if (g_state.step == STEP_INSTALLING && !install_triggered) { install_triggered = true; flush_ui(); do_install(); flush_ui(); } if (g_state.step == STEP_UPDATING && !install_triggered) { install_triggered = true; flush_ui(); do_update(); flush_ui(); } montauk::sleep_ms(16); continue; } if (ev.type == 3) break; if (ev.type == 4) { apply_scale(g_window.scale_factor); redraw = true; } if (ev.type == 2) { g_win_w = g_window.width; g_win_h = g_window.height; g_pixels = g_window.pixels; montauk::mfree(g_backbuf); g_backbuf = (uint32_t*)montauk::malloc(g_win_w * g_win_h * 4); redraw = true; } if (ev.type == 0 && ev.key.pressed) { if (ev.key.scancode == 0x01) break; redraw = true; } if (ev.type == 1) { bool clicked = (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1); if (clicked) { if (!handle_click(ev.mouse.x, ev.mouse.y)) break; redraw = true; } } if (redraw) flush_ui(); } g_window.destroy(); montauk::exit(0); }