129 lines
4.6 KiB
C++
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);
|
|
}
|
|
}
|