Files
MontaukOS/programs/src/login/main.cpp
T

129 lines
4.6 KiB
C++

/*
* main.cpp
* MontaukOS graphical login screen
* Copyright (c) 2026 Daniel Hammer
*/
#include "login.hpp"
inline void* operator new(unsigned long, void* p) { return p; }
static void maybe_run_setup_session() {
auto doc = montauk::config::load("setup");
const char* mode = doc.get_string("environment.mode", "");
if (!montauk::streq(mode, "setup")) {
doc.destroy();
return;
}
const char* user = doc.get_string("session.username", "liveuser");
const char* display = doc.get_string("session.display_name", "Live User");
const char* role = doc.get_string("session.role", "admin");
montauk::fmkdir("0:/users");
montauk::user::create_user(user, display, "", role);
montauk::user::set_session(user);
doc.destroy();
int pid = montauk::spawn("0:/os/desktop.elf", user);
if (pid >= 0) {
montauk::setuser(pid, user);
montauk::waitpid(pid);
}
montauk::user::clear_session();
}
static void initialize_login_mode(LoginState* ls) {
int fh = montauk::open("0:/config/users.toml");
if (fh < 0) {
ls->mode = MODE_FIRST_BOOT;
ls->active_field = 0;
montauk::strcpy(ls->username, "admin");
ls->username_len = 5;
gui::mtk::text_input_set_cursor(ls->username_input, ls->username_len,
ls->username_len, false);
return;
}
montauk::close(fh);
ls->mode = MODE_LOGIN;
ls->active_field = 0;
}
extern "C" void _start() {
LoginState* ls = (LoginState*)montauk::malloc(sizeof(LoginState));
montauk::memset(ls, 0, sizeof(LoginState));
new (&ls->fb) gui::Framebuffer();
ls->screen_w = ls->fb.width();
ls->screen_h = ls->fb.height();
gui::fonts::init();
montauk::set_mouse_bounds(ls->screen_w - 1, ls->screen_h - 1);
load_login_wallpaper(ls);
// MTK theme (picks up the system accent). The compose buffer is only
// needed when the framebuffer pitch is not tightly packed; otherwise the
// renderer draws straight into the framebuffer back buffer.
ls->theme = gui::mtk::make_theme();
if (ls->fb.pitch() != ls->screen_w * (int)sizeof(uint32_t)) {
ls->compose = (uint32_t*)montauk::alloc(
(uint64_t)ls->screen_w * ls->screen_h * sizeof(uint32_t));
}
maybe_run_setup_session();
initialize_login_mode(ls);
bool first_frame = true;
uint64_t input_serial = montauk::input_wait(0, 0);
for (;;) {
bool mouse_changed = false;
bool key_changed = false;
bool fast_mouse_path = false;
int prev_mouse_x = ls->mouse.x;
int prev_mouse_y = ls->mouse.y;
uint8_t prev_mouse_buttons = ls->mouse.buttons;
ls->prev_buttons = ls->mouse.buttons;
montauk::mouse_state(&ls->mouse);
mouse_changed = ls->mouse.x != prev_mouse_x
|| ls->mouse.y != prev_mouse_y
|| ls->mouse.buttons != prev_mouse_buttons
|| ls->mouse.scrollDelta != 0;
fast_mouse_path = mouse_changed || ls->mouse.buttons != 0;
while (montauk::is_key_available()) {
montauk::abi::KeyEvent key;
montauk::getkey(&key);
// Deliberately untranslated: the login screen is US-English only
// until it grows its own layout switcher. There is no user yet, so
// there is no per-user layout to apply, and silently picking one
// would leave no way to type a password in a different layout.
handle_key(ls, key);
key_changed = true;
}
if (mouse_changed) handle_mouse(ls);
if (first_frame || mouse_changed || key_changed) {
draw_login_screen(ls);
first_frame = false;
}
// Event-driven wait: input_wait returns the instant the mouse or
// keyboard ISR reports activity, so the cursor tracks the device with
// no fixed-timer latency. timeoutMs is only an upper bound. Matches
// the desktop's run loop; a plain sleep_ms() here cannot wake early
// and makes every gesture start ~16 ms late.
//
// The login screen has no periodic UI (no clock, no caret blink, no
// animation), so when idle it never needs to wake without input: pass
// UINT64_MAX to block indefinitely and consume 0% CPU until the next
// mouse/keyboard event, instead of waking ~62x/sec for nothing.
uint64_t wait_ms = fast_mouse_path ? 1
: ((mouse_changed || key_changed) ? 4 : UINT64_MAX);
input_serial = montauk::input_wait(input_serial, wait_ms);
}
}