- Home
- SDK
- Applications
- Memento Desktop
Memento (GUI)¶
Memento is the graphical desktop for r2, shipped as MEMENTO.ELF. It provides
login and session locking, a window manager, and a taskbar for switching between
applications. It is built with libc++r2 and the
Memento cross-platform UI toolkit, using a
backend written for this kernel.
Files, Tasks, the clock and network tools run within the desktop. Other windows host separate programs: the shell, web browser, Jug, media players, Telegram, Turbo C++ and DOS programs. Memento displays their output and forwards input, bringing the application suite together in one session.
- Source (
cpp/memento-hello) - Memento toolkit, with the
r2backend insrc/ui/platform/impl/r2

Fig. 1: The landing screen. Enter (or a click) opens Login; Esc restarts the machine and Shift+Esc powers it off. On a kernel without the power calls, Memento ends instead.
Running It¶
make build rebuilds Memento and stages it as iso/bin/memento.elf, available
in /mnt/tar/bin and, on CD boots, /mnt/iso/bin. Start it from the text kernel:
fg memento
The graphics kernel starts it automatically after INIT.RC; keep fg memento
out of that script on graphics boots. On the text kernel you can add it to
INIT.RC to start the desktop. See Graphics Session.
Some windows need things that live outside the program:
| Needs | For |
|---|---|
| A PS/2 mouse | Everything. The cursor is the main way around the desktop. |
ETH running (bg eth) |
Net, Chat, IRC and Web |
/mnt/tar/opt/memento/cacerts.bin |
HTTPS in the Web and Telegram windows. make build in the kernel tree copies it onto the ISO and into usb.tar. |
tcpp.elf in /mnt/tar/bin or /mnt/iso/bin |
The Editor |
them.elf in /mnt/tar/bin |
Running DOS programs from the file manager (the theM window) |
mpegplay.elf in /mnt/tar/bin, films in /mnt/tar/video |
Video |
r2web.elf in /mnt/tar/bin or /mnt/iso/bin |
Web |
spotify.elf in /mnt/tar/bin or /mnt/iso/bin, an HD Audio controller, and for streaming a Premium account in SPOTIFY.CFG |
Spotify |
telegram.elf in the boot medium's bin/, plus a bot token in /mnt/tar/opt/memento/telegram.txt (or typed in) |
Telegram |
c8.elf in the boot medium's bin/, ROMs under /mnt/tar/opt/c8 or /mnt/iso/opt/c8 |
CHIP-8 programs opened from Files |
/mnt/tmp (the RAM disk) or a writable floppy |
Saving screenshots |
sh.elf in /mnt/tar/bin or /mnt/iso/bin |
The Shell icon |
MIDI files in /mnt/fat/SOUND |
Music |
Esc on the desktop locks the session, and leaving the login dialog restarts
the machine (syscall 0x3e); see The Session. Hello offers restart
with Esc and power off with Shift+Esc. On older kernels without those power
calls, leaving Hello ends the program and returns to the text shell. The
graphics supervisor applies its normal reboot policy to an ordinary exit.
The Session¶
Session flow. Saved credentials select the Locked dialog; an active lock keeps the existing windows running underneath it. The diagram shows the normal path when allocation succeeds.
The program goes through three full-screen stages:
- Hello: the landing screen.
- Login: a username and password dialog drawn over the wallpaper. Esc, Cancel or its close box restarts the computer (the dialog says so under it); on a kernel without syscall
0x3ethe program ends instead. The first login since boot that gives credentials sets the session's: a salted SHA-256 hash of the pair goes to/mnt/tmp/SESSION.CFG(the RAM disk, so it lasts until the next restart), and every later login and unlock has to match it. Until then the system isrootwith no password: empty fields, orrootwith an empty password, log in as that and set nothing, so noSESSION.CFGis written,TNTlets a new connection in without asking, and the next login (the lock screen's included) can still give the session its credentials. An accepted login also becomes the system user (syscall0x01,0x03), sosysinfoand the shells' prompts show it; spaces in it become_, and an empty login isroot. - Desktop: the launcher. It stays at the bottom of the window stack until it is closed. Esc on it (when it has the keyboard: everything minimised, or after Alt+D) locks the session, as Alt+L does from any window. Only when there is no memory for the lock screen does Esc log out instead --- every window closes as its close box would close it, and the login dialog comes back.
The lock screen is the login dialog titled Locked, over the whole screen and the taskbar. Every key and click goes to it, the window manager's own keys included, while the windows under it keep running (downloads, chats, music). The session's login and password and Unlock give it back as it was; Esc only clears the fields, and Restart and Power off restart or switch off the computer, which ends the session.
After Jug updates Memento, its Y / N confirmation can relaunch
the desktop without rebooting. All windows close and their hosted processes
stop; save unsaved work first. The graphics kernel starts the downloaded
Memento with --relaunch, skipping Hello and opening Locked when saved
credentials exist, or Login otherwise. The existing
/mnt/tmp/SESSION.CFG stays on the RAM disk and supplies the credentials again.
A relaunch requested while the session is locked waits until it is unlocked.
The first deployment of this feature requires booting the updated image once.

Fig. 2: The login dialog over the wallpaper.
Everything opened from the desktop is a floating window over it, with a frame, a title bar and an entry on the taskbar along the bottom; the taskbar's right end has a clock (hh:mm:ss, from the RTC). A click on a taskbar entry brings its window to the front, restoring it if it was minimised. The window manager keeps a few keys for itself:
| Keys | What they do |
|---|---|
| Alt+Tab | Cycles through the open windows |
| Alt+D | Puts every window away to show the desktop; again brings them back |
| Alt+L | Locks the session (see above) |
| Alt+F | Makes the window in front as large as the screen allows, and back. A window that says it cannot be maximised keeps Alt+F (the Editor, whose Turbo C++ opens its File menu with it) |
| PrintScreen (or Alt+PrintScreen) | Copies the screen, without the pointer, to Memento's clipboard. The taskbar then asks whether to save it as a file too: Y saves it as SCRnnnnn.PNG in /mnt/tmp (or on the floppy when that will not take it), N or Esc does not |
The clipboard¶
One clipboard serves every window: a line of text, or the last screenshot, whichever was put there last. Ctrl+C and Ctrl+V copy and paste text in the Web window (addresses, the find box, form fields) and in Telegram. A screenshot pasted into Telegram is sent as a photo.

Fig. 3: The desktop launcher.
| Icon | Window | What it does | Kernel interface |
|---|---|---|---|
| Clock | Clock | Analog clock | RTC, 0x02 |
| Settings | Settings | Desktop preferences and UTC time synchronization through NTP | RTC 0x02, UDP binding 0x37 |
| Shell | Shell | The userland shell (sh.elf --host) as an 80x25 terminal with 200 lines of scrollback (PageUp/PageDown) |
spawn 0x2A, shared user-heap block |
| Net | Network | Stats, subnet scan, ping, traceroute and charts; physical NIC throughput and TCP ports with owner PIDs and names | 0x38, 0x45, 0x46 |
| Mount | Files | Two-pane file manager in the style of Norton Commander. Its top level is the mount list: each mount with its type and size, and on the info line the one under the bar in full (/mnt/tmp: memdisk, fat16, 126 MiB, 125 MiB free), read again after anything that changes a disk. F5 copy and F6 move to the other pane (F6 renames when both show one directory), F7 new folder, F8 delete (a folder only when empty), F3 view, F4 edit. Enter on an .EXE or .COM runs it in theM; Enter on a .CH8 ROM runs it in C8; Alt+Space, Shift+F10 or a right click opens a menu of the same for the entry under the bar. On a .PNG the menu has Set as wallpaper: the picture covers the whole screen behind every window (and the login dialog) until Memento ends; /mnt/tar/pics/warp.png is one made for it. Enter on / walks the tree from the root (mnt, then the mounts), so every file has its full path; the root, like the CD and the archive, is read-only. Copies go a chunk per idle turn with progress shown |
0x2C, 0x2D, 0x39, 0x3A, 0x22, 0x23, 0x27, 0x40 |
| Tasks | Tasks | Live task table: PID, mode, status, name, RIP; kill by row or typed PID. A Memory tab (Tab or M) shows the user heap, each program's frame and heap share, and Memento's own arena | 0x2F, 0x3B, 0x3C |
| Chat | Chat | Client for the CHAT server on TCP/9000 |
libcr2 TCP/IP |
| Calc | Calculator | Four-function calculator | none |
| IRC | IRC | IRC client | libcr2 TCP/IP |
| Music | Music | Plays .MID files from /mnt/fat/SOUND |
PIT and speaker ports, 0x30 |
| Web | Web | HTTP/1.1 and HTTPS (TLS 1.2) browser with pictures (PNG, JPEG, GIF, BMP) and a little JavaScript (ES5 through MuJS, a small DOM; :js off turns it off); also opens files from the disks (/mnt/... in the address bar). Runs as r2web.elf, a process of its own per window |
spawn 0x2A, shared user-heap block; in the child its own TCP/IP, BearSSL, stb_image |
| Jug | Jug | CDN program catalog with timestamp, size, SHA-256 and running PIDs; downloads verified ELF updates to /mnt/tmp/jug, restarts programs with saved arguments, and coordinates Memento's own relaunch |
hosted jug.elf, 0x2A, 0x2F, 0x3B, 0x41, 0x42 |
| Editor | Editor | Turbo C++ 23 (tcpp.elf) in a window |
spawn 0x2A, shared user-heap block |
| Snake | Snake | libc++r2's snake example in a window, sharing its rules (examples/snake/game.hpp) and its high score (/mnt/fat/SNAKE.HSC) |
PC speaker beeps, file 0x21 |
| Mines | Minesweeper | Beginner, intermediate and expert boards (1/2/3); a safe first click, flags on the right button or F, chording on open numbers, best times in /mnt/fat/MINES.HSC |
PC speaker beeps, file 0x21 |
| Telegram | Telegram | A Telegram bot of your own as a chat client: people who write to the bot are chats on the left, and you answer as the bot. Photos they send are shown; a pasted screenshot goes out as a photo | hosted telegram.elf (Go), shared user-heap block, r2net and r2tls; the Bot API over HTTPS |
| Video | Video | MPEG-1 films from /mnt/tar/video, with their MP2 sound through HD Audio, played by mpegplay.elf in a process of its own; and HLS streams (an .m3u8, a .url file, or an address typed with U) of MPEG-1 video and MP2 audio. Up/Down set the volume while one plays |
spawn 0x2A, shared user-heap block, 0x3f |
| Spotify | Spotify / Go | Spotify client in Go (spotify.elf, a process of its own): playlists from the Web API, and Premium tracks streamed, decrypted and decoded (Ogg Vorbis, through Tremor) to HD Audio inside r2. Without an account it offers two generated test tones |
spawn 0x2A, shared user-heap block; in the child r2net, r2tls (BearSSL), 0x3f |
The theM window has no icon: the file manager opens it, one per program run (see below).
The file manager opens a File viewer on the selected file (0x20).

Fig. 4: The Clock window.
Time settings¶
Open Settings → Time to choose an NTP server hostname or IPv4 address,
turn automatic synchronization on or off, and set the poll interval in
seconds (64–86400). The defaults are pool.ntp.org, automatic synchronization
on, and 3600 seconds. Save activates the settings; Sync now applies
them and requests synchronization even when automatic polling is off.
The tab displays the current UTC date/time and the request status. The taskbar
and Clock window refresh after a successful correction.
Memento waits for the network configuration published by eth, resolves
the server, and sends SNTPv4 requests to UDP port 123 from port 47012. Work
runs in the desktop idle loop, so network waits do not block the UI. Replies
must come from the selected address and port and echo the current request's
timestamp. Malformed, stale or unsynchronized replies leave the clock alone.
Requests are at least 64 seconds apart; failures back off, RATE replies
wait at least an hour, and a server denial requires choosing another server.
A valid reply sets whole-second UTC through
RTC syscall 0x02, operation 2.
The change lasts for this boot and is visible to other applications. It
does not write the hardware CMOS clock or change uptime and sleep deadlines.
The client handles NTP's 2036 rollover using a bootstrap date range of
2000–2136. This is a single-server SNTP client using the wire format in
RFC 4330 and
RFC 5905; it does not authenticate
servers with NTS or continuously discipline oscillator frequency.
Save stores session preferences in /mnt/tmp/MEMENTO.CFG, which survives
a desktop relaunch but is lost on reboot. To set boot defaults in the image,
edit iso/opt/memento/defaults.cfg before rebuilding:
ntp_server=pool.ntp.org
ntp_enabled=on
ntp_interval=3600
Memento reads /mnt/tar/opt/memento/defaults.cfg before applying saved session
overrides. A working Ethernet connection and UDP/123 access to the server
are required.
Network tools¶
In-process network clients share one frame reader. Hosted applications such as
r2web.elf are separate processes with their own kernel frame queues.
The Net window has Stats, Scan, Ping, Trace and Charts tabs. Stats reads physical NIC counters and the TCP owner table: both services and client reply ports are listed with their full PIDs and bounded process names. RX/TX rates use successive timestamped samples. Charts keeps a history of the rates. On older kernels, traffic figures cover Memento's own frame mux and the port list shows numbers without owners.
Scan accepts a subnet in CIDR form; Ping and Trace take numeric IPv4 addresses. They share Memento's frame mux with its other stacks. Closing the window stops its tools and releases their port. For encrypted subnet probes from Shell or TNT, see the separate WireGuard commands.
Notes on individual windows¶
Shell runs sh.elf as a process of its own, started with --host and the address of a block on the user heap: the shell writes its output into a ring in the block and reads typed characters from another, and the window is the terminal between them (c/r2sh/host.h has the layout). Programs the shell starts with run print to the console, not the window. exit, or the close box, ends the shell; if Memento stops beating, the shell leaves on its own after ten seconds. For WireGuard, bg wgd <config> displays a startup log snapshot and the path /mnt/tmp/WGD.LOG, so daemon failures remain readable in the window. The shell's ping <IPv4> and traceroute <IPv4> builtins write their tunnel-probe results directly into the window.
Music does not use syscall 0x1b. That call plays a whole song inside the kernel and blocks the caller until it ends, which would freeze the desktop. Instead the window parses the file itself, drives the PIT and speaker ports directly, and plays one step at a time from the idle loop, so the other windows keep running and a song can be stopped.
Editor runs as a separate process. tcpp.elf is started with --host and the address of a block on the user heap. The editor draws its 80×25 screen into that block and reads its keys from it, and the window copies both ways. The editor keeps its own 2 MiB and its own dialog loops, and Memento keeps running beside it. If no window can be created, the editor takes the whole screen instead. With TCC in the boot image, F9 saves and compiles the current .C file to an .ELF beside it and Ctrl+F9 compiles and runs it; the compiler runs as a task of its own (tcc.elf --ide), and its diagnostics go to the Build panel.
Web is described in its engine's README. In short: the browser never blocks, pages are cut at 768 KiB, CSS is limited to what a grid of 16-colour character cells can show, and text is mapped to CP437. Pictures are fetched after the page and its style sheets, the first 16 of a page, and each takes a line of its own in the screen's colours. Ctrl+Space, Shift+F10 or a right click opens a menu (open, open in a new window, copy a link or its text, paste and go, back, reload, find, dark mode); :img off turns pictures off. An address answering with a picture shows the picture, and a path (/mnt/tmp/SCR00001.PNG) opens a file from a disk.
The Web window is a host for r2web.elf, a separate process started with --host and a block on the user heap, the way the Editor and the Shell are. The browser, with its navigation, layout, forms, pictures, TLS and networking, runs in the child. Memento owns the outer window, passes it keys, mouse and clipboard text, and composites the frames it draws. Each browser window is a process of its own with its own page and script state, on eight TCP ports from 48000 + slot × 32 (and a DNS port at base + 10). The engine in web/ also supplies Memento's own image loading and the Video
window's HLS loader; the Telegram client now runs in a separate Go process.
JavaScript is MuJS (ES5): the first 16 classic <script> elements run in document order, before the page's style sheets and pictures load, with document.write, getElementById, element innerHTML/textContent/value, inline onclick, location and console.log/alert (to the status line). There are no timers, event listeners, fetch, storage or modules. Each script gets at most a 2 MiB heap and one million steps or 250 ms. :js off and :js on turn scripts off and on. See r2web's README.
Telegram runs as telegram.elf (go/telegram) in its own process. Memento
forwards input and clipboard content, displays its frames, and presents its
notification bubbles. The child uses r2net and r2tls for the bot's side of the
Bot API: getUpdates as a long poll, sendMessage for what you type, getFile and a download for each photo someone sends (the size nearest 320 pixels wide, the last eight kept), and sendPhoto for a pasted screenshot, with what is typed as its caption. The token comes from /mnt/tar/opt/memento/telegram.txt, then
/mnt/fat/TELEGRAM.CFG, or is typed in and saved there. Ctrl+T changes it.
See the Telegram source guide
for keys, media support and notification settings.
C8 opens a .CH8 ROM from Files with Enter or Run in C8, one hosted
c8.elf process per window. The ISO build installs twelve ROMs under /opt/c8
on both tar and ISO. Space pauses/resumes, F5 resets, and Esc closes. The PC
keys 1234, QWER, ASDF, ZXCV map to the CHIP-8 keypad. Rendering keeps
the 64×32 aspect ratio; only original CHIP-8 is supported. See the
C8 source guide.
Video decodes the film's MP2 audio in the player (in integers: it was written before the kernel saved SSE state across task switches, and is still built with -mgeneral-regs-only) and plays it through the HD Audio driver; the sound is then the clock the pictures keep to. For a stream, the window fetches the HLS playlist and its MPEG-TS segments with the browser's loader and hands the bytes to the player through a 1 MiB ring on the user heap; only MPEG-1 video with MP2 audio plays, which is what ffmpeg -c:v mpeg1video -c:a mp2 -f hls makes. See the player's README.
theM runs a DOS program in them.elf, the emulator, as a process of its own, started with --host and a block on the user heap (c/them/winhost.h). The emulator then leaves the screen and the keyboard alone: it puts each picture in the block in the screen's colours, text mode included, and takes its keys from the block as the scancodes the keyboard sent. DOS console output goes into the guest's own text screen. The window scales the picture to 4:3 and hands every key on; F12 ends the program, and Enter runs it again once it has ended. The program starts in its own directory, as on DOS.
How It Is Put Together¶
UI composition and hosted processes. The backend owns the visible desktop;
each hosted program owns its runtime. libc++r2compat supplies toolkit support,
and in-process network clients use libcr2, web/ and BearSSL through the mux.
- Display. On the text kernel the backend asks the kernel for mode
0x12(syscall0x15), then reprograms the CRTC to a 640×400 planar mode with the EGA 16-colour palette. Frames are composed in memory and written to the four planes through the VGA window mapped by syscall0x14. On the graphics kernel's framebuffer the screen is as large as the framebuffer and has 256 colours: the same 16, a 6×6×6 cube and 24 greys. Either way a bitmap is one palette index a pixel, which is what the Web, Telegram, Video and theM windows write their pictures into directly. - Coordinates. Windows are written in 320×200 units. They are created at 192 DPI, so the backend draws them at twice that resolution, text included.
- Networking. The process has two TCP/IP stacks: libcr2's, for Chat and IRC, and the browser's own. The kernel gives a process a single frame queue (syscall
0x35), sonetmux.cppis the only code that reads it. It sends each frame to the stack that owns the destination port (the browser claims its ports), and holds frames for the other stack until that stack asks for them. ARP goes to both stacks and ping replies go to one. libcr2 receives its frames throughnet_set_frame_source(). - Build flags. Everything is built freestanding against libc++r2 in C++17, since Memento is a C++17 codebase.
libcr2.ais linked last and only for its TCP/IP stack; every symbol both libraries define comes from libc++r2. - Windows. The window sources are
#included intomain.cpprather than compiled separately. The Makefile rebuildsmain.owhen any of them changes.
Memory¶
The process's private 2 MiB frame at 0x600_000 holds code, static data, the
window manager's buffers and its runtime stack. The heap arena starts in .bss
and grows onto the kernel's shared user heap:
R2_HEAP_ARENA_GROWING(640 * 1024) // r2_stubs.cpp
The arena starts at 640 KiB in the image. When it is full, it takes further 256 KiB regions from the user heap (syscall 0x0a). The desktop bitmap alone is 244 KiB and every window has a bitmap of its own, so opening more windows grows the arena instead of failing. The arena does not start on the user heap because the browser keeps page bodies and layout there, about four times the page's size. The user heap is 4 MiB for all processes together until it is full; then the kernel grows it once by an eighth of the RAM (see 0x0a), which is where decoded pictures, the theM window's 600 KiB block and screenshots find their room.
Image usage depends on the build and the windows linked into it. Large buffers
belong on the heap so the code, data and .bss stay within the 2 MiB frame.
This only works because the kernel accepts user-heap pointers in syscalls: every pointer argument may lie wholly inside the program image or wholly inside the user heap (see the specification). On older kernels, which accepted pointers only into the image, the program cannot run.
Building¶
The Makefile expects a checkout of Memento beside the two repositories, at ../../../Memento from cpp/memento-hello.
cd cpp/memento-hello
make build # memento-hello.elf and memento-hello.bin
make install # copies it onto fat.img as MEMENTO.ELF
make check # compile-only syntax check of every source
make webtest # host-side tests of the browser engine
| Variable | Default | Meaning |
|---|---|---|
MEMENTO |
../../../Memento |
Memento source tree |
LIBCXXR2 |
../libc++r2 |
libc++r2, built on demand |
LIBCR2 |
../../c/libcr2.a |
libcr2, used for its TCP/IP stack |
FLOPPY |
../../fat.img |
Image for make install |
STACK_BYTES |
262144 |
Stack size given to _crt0.asm |
EXTRA |
(empty) | Extra compiler flags, e.g. EXTRA=-DMEMENTO_R2_SERIAL_DEBUG for backend traces on serial |
The build writes header dependencies (-MMD -MP), and they are required. Every new of a platform object compiles in that object's size. If a header gains a member and a caller is not rebuilt, the allocation comes out too small and silently corrupts the heap. After changing a header outside this tree, run make clean.
Adding a Window¶
A window is a class with a static event entry point. For example, trimmed from windows/hello_window.cpp:
class MyWindow
{
public:
static void onEvent(void *instance, struct PlatformWindowInterfaceInputEvent *data)
{
reinterpret_cast<MyWindow *>(instance)->onEvent_(data);
}
void SetWindow(PlatformWindow *w) { wnd = w; }
private:
PlatformWindow *wnd = nullptr;
void onEvent_(struct PlatformWindowInterfaceInputEvent *data)
{
switch (data->type)
{
case PlatformWindowInputEventType::OnPaint:
// data->Data.OnPaint.ctx creates colours and fonts,
// data->Data.OnPaint.target is the bitmap to draw on
break;
case PlatformWindowInputEventType::OnKeyEvent:
if (data->Data.OnKeyEvent.key->isEscape)
wnd->Close();
break;
default:
break;
}
}
};
To add a window to the desktop:
- Put the class in
windows/and#includeit inmain.cpp, beforedesktop_window.cpp. - Add an
AppKindvalue and acaseinopenApp(). The case creates the window withg_root->CreateWindow(title, w, h, MyWindow::onEvent, obj, &g_appOpts, deleteMy, obj), wherewandhare in 320×200 units. The delete callback frees the object when its window closes. - Give the window an icon and a hit-test area in
desktop_window.cpp.
Every allocation can fail, since there are no exceptions. Check each new and each Create* call for nullptr, as the existing windows do.
A window that writes pixels straight into its bitmap (R2_BitmapImpl::GetPixels(), one palette index a pixel, rows GetRealWidth() apart), as the picture windows do, takes the pixels a unit from the DPI: wnd->GetEffectiveDPI() / 96.0. Not from the bitmap's width over the window's: Memento allocates bitmaps in steps of 150 pixels, so a bitmap is often wider than its window, and a scale worked out that way puts everything too far right and down.
Related documentation: SDK Overview, Application Suite, Jug, Video Overview.