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}"),
_ => {}
}
}
}
}window.openshows a window of 1280 × 720 pixels at once.events()waits for at least one event, then gives every event that came.Closedmeans 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,
openfails withWindowError.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)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)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)callsffor each event untilfgivesfalseor the window closes:
win.run(e => match e {
Event.Key(key, down) => not (down and key == "Escape"), // false ends `run`
_ => true,
})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 method | Gives |
|---|---|
window.open(title, width, height) -> AppWindow ! WindowError | A 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() -> Float | How 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() -> Int | The 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:
Event | When |
|---|---|
Closed | The 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.openfails withUnavailablefor now: macOS shows windows only from a program's first thread. - Generated tests skip functions that use
WindoworInput: there is no fake screen yet. See Testing.