std1.0.0-beta-7 SafeC docs

Module gui::gui_web

#include <std/gui/gui_web.h> source

GUI: the WebAssembly <canvas> backend.

On a wasm32/wasm64 target std/gui's platform backend is the browser: every GuiWindow is a <canvas> element of the page (or an OffscreenCanvas where there is no document), and everything else in std/gui — the canvas, text, widgets, GuiApp with its timers and animation frames — works unchanged on top of it. The host side is std/gui/gui_web.js, an ES module shipped next to this header (see its header comment):

import { loadSafeCGui } from "./gui_web.js";
const app = await loadSafeCGui(fetch("app.wasm"), { entry: "start" });

A browser must not block, so a program doesn't call GuiApp::run(): its entry point (an export_name function the glue calls once) opens the windows, then hands the app to gui_web_run(), which returns at once; the glue then calls GuiApp::pump(0) once per requestAnimationFrame until it returns 0 (the last window closed or quit()):

static struct GuiApp gApp;                 // must outlive start()
__attribute__((export_name("start")))
int start() {
    gApp = GuiApp::new();
    ?&GuiWindow w = gApp.open_window("Hello", 480, 320);
    ...
    gui_web_run(&gApp);
    return 0;
}

What maps to what:

windows     windows: "canvas" (default) — each window a <canvas>: the
            glue's 'canvas' option picks it (an element, a selector, or
            a function (index, title) => canvas), else the next unused
            canvas[data-safec-gui] of the page, else a new <canvas>
            appended to <body>. Its CSS size is the window's logical
            size and its backing store that times devicePixelRatio
            (hiDpi), so drawing is sharp; with the 'fit' option (or a
            data-safec-fit attribute) the canvas keeps the size the
            page's CSS gives it and follows it (ResizeObserver) —
            GUI_EVENT_RESIZE, as a window would. windows: "frames" —
            each window a positioned <div class="safec-gui-window"> in
            a container, with a title bar (drag it: GUI_EVENT_MOVE,
            set_position()/pos_x() work; its × : GUI_EVENT_CLOSE), a
            resize grip honoring the size limits, raised on a click.
presenting  putImageData of the damaged rectangle, straight from the
            module's memory (premultiplied pixels converted to
            ImageData's straight alpha on the way) — or, with the
            page's present: "webgl" option or GUI_PRESENT_GPU, WebGL2
            (else WebGL1): the damaged rectangle uploaded into a
            texture and drawn as one quad (gui_gpu_web_wasm.sc), back
            to putImageData if there is no WebGL or the context is lost.
input       pointer events (with pointer capture while a button is
            down), wheel (pixel/line/page deltas to lines); keyboard
            focus is real DOM focus on a hidden <textarea> per window
            (a click on the canvas focuses it): KeyboardEvent.code/key
            to GUI_KEY_* and the typed character, and text that comes
            without a key — IME composition, virtual keyboards,
            context-menu pastes — as GUI_EVENT_CHAR.
HiDPI       devicePixelRatio, followed when it changes (zoom, another
            display): GUI_EVENT_SCALE.
clipboard   gui_clipboard_set_text() writes navigator.clipboard (and the
            copy event a Ctrl/Cmd+C shortcut fires); gui_clipboard_get_text()
            returns the text of the last paste event or of the last
            copy — the glue holds a Ctrl/Cmd+V keydown back until its
            paste event arrived, so a paste shortcut sees the pasted
            text. Reading the system clipboard any other way needs a
            permission browsers don't grant silently.
cursors     CSS cursor on the canvas.
a11y        canvases are role="img" labelled with the window title, the
            hidden input carries it too, and gui_web_announce() speaks
            through an aria-live region.
DOM         gui_web_window_element()/gui_web_mount() trade elements with
            std/wasm/dom.h, so a page mixes DOM and std/gui windows.
clock       performance.now(); timers fire from the frame loop.

Files: fopen()/fread() read the glue's 'files' option (fetchFiles()), e.g. fonts at the paths std/gui looks in; the TrueType stack's embedded fallback face is there without any. 'safeguard bundle --target wasm32' writes build/<name>.web/: the module, this glue and a page.

Functions

gui_web_runLets the JS glue drive 'app' from requestAnimationFrame: one app.pump(0) per frame until it returns 0. Returns at once. 'app' must stay alive (a static or heap object) after the caller returns.
gui_web_announceScreen readers: says 'text' through the page's aria-live region (e.g. a status change your UI only draws).
gui_web_window_elementstd/wasm/dom.h interop (the page loaded the module through safec_dom.js's loadSafeC, or passed its glue as the domGlue option): the window's element — its frame in "frames" mode, else its <canvas> — as a dom.h handle (-1 without the DOM glue), to style it or put DOM elements next to it; and moving the window's element into DOM element 'parent' (1 = done).
gui_web_mount