The F8 menu is redrawn in the Niveus language: a window with three lights, bevelled keys with a lit edge, wells for panels, anti-aliased corners and a soft shadow, set in Instrument Sans rasterised into include/gfx/nvfont.h (tools/python/mknvfont.py, make nvfont). Scale doubles on screens 1400 px tall or more. Lists taller than the screen scroll. The keyboard still drives everything, and a mouse, touchpad or tablet does too: both UEFI pointer protocols are polled, hover moves the highlight, a click activates. The cursor stays hidden until the pointer has really done something, since the firmware installs a pointer protocol with or without a mouse. The 'keep this resolution?' countdown is one ten-second budget however many times the pointer moves. Loaders found at well-known paths on any volume (Windows, Ubuntu, Debian, Fedora, Arch, openSUSE, systemd-boot, rEFInd, other BOOTX64.EFI) are listed and chain-loaded with LoadImage/StartImage. 'Reboot to firmware' used to halt; it now sets OsIndications and restarts, and Restart and Shut Down call ResetSystem. Checked under QEMU+OVMF: menu, resolution list (incl. 2560x1600 at double scale), system information, shut down, firmware setup, chain-loading a copy of the loader from a second disk, and a full boot of the ISO to the login prompt. Pointer hover and click were checked only with synthetic events: in this setup a USB mouse or tablet delivered no event to the loader (one USB I/O handle appeared but no pointer protocol came from it), and why was not established. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVRhxi9zpdW2uDUN4FVcao
106 lines
4.3 KiB
C
106 lines
4.3 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* The loader's user interface, shared by both firmwares.
|
|
*
|
|
* This is the first piece of the two loaders that is genuinely common code
|
|
* rather than a contract they both honour. It can be, because the difference
|
|
* between BIOS and UEFI is entirely in how you *obtain* a framebuffer -- VBE in
|
|
* real mode, or GOP -- and not in what you do with one afterwards. By the time
|
|
* there is a base address, a size and a stride, there is nothing firmware-
|
|
* specific left to say.
|
|
*
|
|
* Everything here draws and nothing here decides. No disk, no memory map, no
|
|
* mode setting: a caller hands over a framebuffer and asks for pixels. That is
|
|
* what makes it compilable into a 16/32/64-bit BIOS loader and into a PE/COFF
|
|
* UEFI application without either of them leaking into it.
|
|
*
|
|
* Types are spelled out rather than taken from a header, because the two
|
|
* callers do not agree on one: the BIOS side has uchar/uint32 from the kernel
|
|
* tree, the UEFI side has UINT8/UINT32 from the EFI headers, and this file has
|
|
* to compile inside both.
|
|
*/
|
|
#ifndef SCHOS_BOOT_UI_H
|
|
#define SCHOS_BOOT_UI_H
|
|
|
|
typedef unsigned char ui_u8;
|
|
typedef unsigned short ui_u16;
|
|
typedef unsigned int ui_u32;
|
|
typedef unsigned long long ui_u64;
|
|
|
|
/* A linear framebuffer, 32 bits per pixel. Both firmwares can produce one and
|
|
* neither can produce anything this code could use if they could not. */
|
|
struct ui_fb {
|
|
ui_u8 *base;
|
|
ui_u32 width;
|
|
ui_u32 height;
|
|
ui_u32 stride; /* bytes per row, from the driver -- never width*4 */
|
|
};
|
|
|
|
/* Hand over the framebuffer. Passing a null base, or a zero size, leaves the
|
|
* UI inert: every call below then does nothing, so a caller with no display
|
|
* does not need to guard each one. */
|
|
void ui_init(const struct ui_fb *fb);
|
|
int ui_active(void);
|
|
|
|
ui_u32 ui_width(void);
|
|
ui_u32 ui_height(void);
|
|
|
|
void ui_clear(void);
|
|
void ui_fill_rect(int x, int y, int w, int h, ui_u32 colour);
|
|
void ui_text(int x, int y, const char *s, ui_u32 colour, ui_u32 bg);
|
|
void ui_text_centered(int y, const char *s, ui_u32 colour);
|
|
|
|
/* The logo, centred horizontally, top-left at the given y, scaled to `w`
|
|
* pixels wide. Downscaled from the source mask -- never up, which would only
|
|
* make it soft. */
|
|
void ui_logo(int y, int w);
|
|
|
|
/* The mark's width, which is also the progress bar's. One number, because the
|
|
* two being the same width is the whole arrangement. */
|
|
int ui_mark_width(void);
|
|
|
|
/* The splash: the mark, and the bar beneath it.
|
|
*
|
|
* No product name: the name is *in* the mark, and setting it again underneath
|
|
* is the kind of thing that reads as a placeholder nobody removed.
|
|
*
|
|
* Laid out from the centre outwards rather than from the top down, so it looks
|
|
* the same at 800x600 and at 1600x1200 instead of drifting up the screen as the
|
|
* mode grows.
|
|
*/
|
|
void ui_splash(const char *subtitle);
|
|
|
|
/* A menu, drawn as a panel. The caller owns the keyboard: this draws a state
|
|
* and returns, so the same function serves a firmware with INT 16h and one with
|
|
* a UEFI text-input protocol without either appearing in here.
|
|
*/
|
|
void ui_menu(const char *title, const char *const *items, int n, int selected,
|
|
const char *hint);
|
|
|
|
/* Repaint only the keys that changed when the highlight moves (a full paint
|
|
* redraws the screen). Returns without effect on a panel. */
|
|
void ui_menu_select(int selected);
|
|
|
|
/* Which key is under a point, or -1. A panel has one key, index 0. */
|
|
int ui_menu_hit(int x, int y);
|
|
|
|
/* The pointer: drawn on top of everything, with what is under it saved and put
|
|
* back. Menus hide it while they repaint and show it again afterwards. */
|
|
void ui_cursor(int x, int y, int show);
|
|
|
|
/* A message in the same window as the panels, with one button. */
|
|
void ui_notice(const char *title, const char *const *lines, int n,
|
|
const char *button, const char *hint);
|
|
|
|
/* A panel of label/value rows -- the system information screen. */
|
|
void ui_panel(const char *title, const char *const *labels,
|
|
const char *const *values, int n, const char *hint);
|
|
|
|
/* The progress bar. `total` is whatever unit the caller counts in; ticks are
|
|
* cumulative, and the bar only ever moves forward. */
|
|
void ui_progress_begin(const char *label, ui_u32 total);
|
|
void ui_progress_label(const char *label);
|
|
void ui_progress_tick(ui_u32 done);
|
|
void ui_progress_end(void);
|
|
|
|
#endif /* SCHOS_BOOT_UI_H */
|