Skip to content
Kavachकवच

Windows

● Intermediate4 minBefore this: CapabilitiesSpec 14.22

std.window opens windows on the screen and reads the keyboard and mouse input that comes to them: the start of games, tools, charts and user interfaces.

use std.window

fn main() ! WindowError uses Window, Input, Console {
    const win = try window.open("Swarm", 1280, 720)
    win.listen_input()
    let running = true
    while running {
        for e in win.events() {
            match e {
                Event.Closed => running = false,
                Event.Key(key, down) => if down and key == "Escape" { running = false },
                Event.Resized(w, h) => print("now {w} × {h}"),
                _ => {}
            }
        }
    }
}
main.kav, from spec 14.22: Kavach code
  • window.open shows a window of 1280 × 720 pixels at once.
  • events() waits for at least one event, then gives every event that came.
  • Closed means the person asked to close it. The window stays open until the program closes it or lets go of it, so it can ask "save first?".
  • On a machine that shows no windows, such as a server with no screen, open fails with WindowError.Unavailable(reason).

Two capabilities

Window opens windows, changes them and reads their window events. Input reads the keyboard, the mouse and typed text. So a function that only draws can't read what a person types:

use std.window

fn watch(win: AppWindow) uses Window {
    win.listen_input()
}

fn main() uses Window, Input {
    const win = window.open("Keys", 640, 480) catch _ => return
    watch(win)
}

The compiler refused the program:

kavach run input.kav

error: `watch` uses Input (through `listen_input`), but its `uses` clause doesn't list it: add `Input` to `uses` (spec 8.1)
input.kav: Kavach code, then what running it prints

Opening a window needs Window, like every way to the outside world:

use std.window

fn show() ! WindowError uses Console {
    const win = try window.open("Hello", 640, 480)
    win.set_title("Hello again")
}

fn main() uses Console {
    show() catch e => print("{e}")
}

The compiler refused the program:

kavach run window.kav

error: `show` uses Window (through `open`), but its `uses` clause doesn't list it: add `Window` to `uses` (spec 8.1)
window.kav: Kavach code, then what running it prints

Waiting, polling or answering

  • win.events() waits: for a tool that does nothing until a person acts.
  • win.poll() never waits, and is empty when nothing came: a game calls it once a frame.
  • win.run(f) calls f for each event until f gives false or the window closes:
win.run(e => match e {
    Event.Key(key, down) => not (down and key == "Escape"),   // false ends `run`
    _ => true,
})
from spec 14.22: Kavach code

The system's event loop runs on a thread of the runtime's own, so a slow frame never freezes the window.

Every function and method

Function or methodGives
window.open(title, width, height) -> AppWindow ! WindowErrorA new window of width × height pixels, shown at once
win.events() -> [Event]The events that came, waiting for at least one
win.poll() -> [Event]The events that came, without waiting; empty when none did
win.run(f)Calls f(event) for each event as it comes, until f gives false or the window closes
win.listen_input()From now on, keyboard, mouse and text events come too. Needs Input
win.size() -> (width: Int, height: Int)The inside of the window, in pixels
win.scale() -> FloatHow many pixels make one point on this screen: 2.0 on most high-DPI screens
win.set_title(title)Changes the title
win.set_fullscreen(on)Fills the screen the window is on, or leaves it
win.lock_cursor(on)Hides the mouse pointer and keeps it in the window, as a game's camera wants; Motion events still come. Needs Input
win.number() -> IntThe window's number, which std.gpu (14.24) draws into it by
win.close()Closes the window; a window is closed anyway when its last holder ends

Events

Event is a union. The last six variants come only after listen_input(), which needs Input:

EventWhen
ClosedThe person asked to close the window. It stays open until close() or its last holder ends, so a program can ask "save first?"
Resized(width: Int, height: Int)Its inside has this size now, in pixels
Scaled(factor: Float)It moved to a screen with another scale
Focused(on: Bool)It gained or lost the keyboard
Key(key: String, down: Bool)A key went down or up. key names the key's place, not its letter, as the W3C's KeyboardEvent.code does: KeyW is the same key on every keyboard layout, as a game wants. Keys held down don't repeat
Text(text: String)Text typed, after the keyboard layout and input methods (IME), as a text box wants; held keys repeat here
MouseMoved(x: Float, y: Float)The pointer is here, in pixels from the window's top left
MouseButton(button: Int, down: Bool)A button went down or up: 0 left, 1 right, 2 middle, 3 back, 4 forward
Wheel(x: Float, y: Float)The wheel turned, in lines; y above 0 is away from the person
Motion(x: Float, y: Float)The mouse moved this much, however the pointer moved or stopped: for a game's camera

Key names a key's place, not its letter: KeyW is the same key on every keyboard layout, as a game wants. For text a person types, read Text, which follows their layout.

Not yet

  • Drawing into a window comes with GPU rendering; gamepads and touch with a later std.input.
  • On macOS, window.open fails with Unavailable for now: macOS shows windows only from a program's first thread.
  • Generated tests skip functions that use Window or Input: there is no fake screen yet. See Testing.