Standard library · Graphics and games

gui.window

Native windows that show a pixel buffer, with an event loop for pointer, keyboard, text input, timers and the clipboard.

import gui.window

gui.window opens real windows and shows pixels you draw yourself. It is the bottom layer of Salam's native user interface: the program renders a frame into memory (for example with gui.paint), and this package puts it on the screen and reports what the user does. It talks to the system directly: X11 on Linux, Win32 on Windows and Cocoa on macOS, with no GTK, no web view and no other library. A headless backend keeps windows in memory, so the same program can be tested on any machine.

A frame is a buffer of 32-bit pixels, premultiplied alpha, with the value 0xAARRGGBB (bytes B, G, R, A in memory), described by a pointer, a width, a height and a stride. Sizes and positions in the API are logical pixels; the buffer is in physical pixels, which is the logical size times ScaleFactor.

  • Events are pulled, not pushed: call Wait in a loop. This is what macOS needs, since its windows only work on the main thread.
  • Closing is a request. The close button sends CloseRequested, and the window stays until you call Close.
  • Redraw requests merge. Call RequestRedraw as often as you like; one RedrawRequested arrives.
  • Keys and text are separate. KeyDown names the key by its position, the same on every keyboard language; the characters come in TextInput and, from an input method, in ImePreedit and ImeCommit.

The text of an event belongs to the package and is freed at the next Wait or Poll. Clone it with str.Clone if you keep it.

The event loop

A window program opens a window, then waits for events until it closes. RedrawRequested asks for a frame: allocate a buffer of the physical size, fill it and give it to PresentAll. A repeating timer drives anything that changes over time. This example is headless and uses the test clock, so it runs anywhere and prints the same lines every time; drop headless and SetManualClock and the same loop drives a real window.

gui-window-guide-loop.salam
import gui.window
import mem

func paint(w: window.Window, frame: int):
    size := w.Size()
    width := size.physical_width
    height := size.physical_height
    pixels := mem.AllocateZeroed(((width * height) * 4) as u64) as u32*
    defer mem.Free(pixels as void*)
    shade := (frame * 40) as u32
    repeat width * height in i:
        pixels[i] = (0xFF000000 as u32) | (shade << 8)
    end
    w.PresentAll(pixels as void*, width, height, width * 4)
end

func main:
    window.SetManualClock(true)
    w := window.Open(window.Options { title = "Clock", width = 64.0, height = 48.0, headless = true })
    tick := window.SetTimer(500, true)
    mut frames := 0
    until w.IsOpen():
        e := window.Wait(-1)
        switch e.kind:
            window.EventKind.RedrawRequested:
                paint(w, frames)
                frames++
                println "frame", frames, "at", window.Clock(), "ms"
                break
            end
            window.EventKind.Timer:
                w.RequestRedraw()
                if frames == 3:
                    window.Inject(window.Event { kind = window.EventKind.CloseRequested, window = w.id })
                end
                break
            end
            window.EventKind.CloseRequested:
                println "closing"
                window.ClearTimer(tick)
                w.Close()
                break
            end
            else:
                break
            end
        end
    end
    println "presented", w.PresentCount(), "frames"
end
Outputframe 1 at 0 ms frame 2 at 500 ms frame 3 at 1000 ms closing presented 3 frames

Mouse, keys and text

Pointer events carry logical coordinates and the button. clicks counts a double or triple click: presses of the same button close together in time and place. A key event names the key with Key, by position, and the system's own key code in code. Text never comes from key events: insert the text of TextInput and ImeCommit, and draw ImePreedit as the composition underline. SetImeRect places the input method's candidate window at your caret.

gui-window-guide-input.salam
import gui.window

func main:
    window.SetManualClock(true)
    w := window.Open(window.Options { width = 300.0, height = 200.0, headless = true, visible = false })
    window.Inject(window.Event { kind = window.EventKind.PointerDown, window = w.id, x = 40.0, y = 30.0, button = window.MouseButton.Left })
    window.Advance(120)
    window.Inject(window.Event { kind = window.EventKind.PointerDown, window = w.id, x = 41.0, y = 30.0, button = window.MouseButton.Left })
    window.Inject(window.Event { kind = window.EventKind.KeyDown, window = w.id, key = window.Key.A, code = 38 })
    window.Inject(window.Event { kind = window.EventKind.TextInput, window = w.id, text = "a" })
    window.Inject(window.Event { kind = window.EventKind.ImePreedit, window = w.id, text = "سل", cursor = 4 })
    window.Inject(window.Event { kind = window.EventKind.ImeCommit, window = w.id, text = "سلام" })
    mut e := window.Poll()
    until e.kind != window.EventKind.None:
        switch e.kind:
            window.EventKind.PointerDown:
                println "click", e.clicks, "at", e.x, e.y
                break
            end
            window.EventKind.KeyDown:
                println "key A:", e.key == window.Key.A
                break
            end
            window.EventKind.TextInput, window.EventKind.ImeCommit:
                println "insert", e.text
                break
            end
            window.EventKind.ImePreedit:
                println "composing", e.text, "caret at byte", e.cursor
                break
            end
            else:
                break
            end
        end
        e = window.Poll()
    end
    w.SetImeRect(40.0, 30.0, 2.0, 18.0)
    println "candidate window goes to", w.ImeRect()
end
Outputclick 1 at 40 30 click 2 at 41 30 key A: true insert a composing سل caret at byte 4 insert سلام candidate window goes to Rect {x = 40, y = 30, width = 2, height = 18}

Scale factor and partial updates

On a high density screen one logical pixel is several device pixels. Draw in physical pixels and use ScaleFactor to convert. Moving a window to another screen sends ScaleChanged and then Resized. When only part of the frame changed, pass the changed rectangles to Present; it copies those alone and clips them to the buffer.

gui-window-guide-hidpi.salam
import gui.window
import mem

func main:
    w := window.Open(window.Options { width = 100.0, height = 50.0, headless = true, scale = 1.5, visible = false })
    size := w.Size()
    println "logical", size.width, size.height, "physical", size.physical_width, size.physical_height
    window.Inject(window.Event { kind = window.EventKind.ScaleChanged, window = w.id, scale = 2.0 })
    e := window.Poll()
    println "new scale", e.scale, "logical", e.width, e.height, "physical", e.physical_width, e.physical_height
    window.Inject(window.Event { kind = window.EventKind.Resized, window = w.id, physical_width = 300, physical_height = 100 })
    r := window.Poll()
    println "resized to", r.width, r.height
    width := r.physical_width
    height := r.physical_height
    pixels := mem.AllocateZeroed(((width * height) * 4) as u64) as u32*
    defer mem.Free(pixels as void*)
    w.PresentAll(pixels as void*, width, height, width * 4)
    mut damage := Vector {} as Vector<window.Rect>
    defer damage.free()
    damage.push(window.Rect { x = 10, y = 10, width = 20, height = 8 })
    damage.push(window.Rect { x = 290, y = 90, width = 50, height = 50 })
    w.Present(pixels as void*, width, height, width * 4, damage)
    println "copied", w.LastDamageCount(), "rects inside", w.LastDamage()
end
Outputlogical 100 50 physical 150 75 new scale 2 logical 75 37.5 physical 150 75 resized to 150 50 copied 2 rects inside Rect {x = 10, y = 10, width = 290, height = 90}

Testing without a screen

A headless window behaves like a real one: it gets focus, redraw requests, resize events and timers, and keeps every presented frame. PixelAt reads the frame back, Inject plays any event, and SetManualClock makes time jump straight to the next timer, so a test of a one second animation takes no time. The environment variable SALAM_WINDOW_BACKEND=headless makes every window headless without changing the program.

gui-window-guide-testing.salam
import gui.window
import mem

func main:
    window.SetManualClock(true)
    w := window.Open(window.Options { width = 2.0, height = 2.0, headless = true, visible = false })
    pixels := mem.AllocateZeroed(16 as u64) as u32*
    defer mem.Free(pixels as void*)
    pixels[0] = 0xFFFF0000 as u32
    pixels[3] = 0x80000080 as u32
    w.PresentAll(pixels as void*, 2, 2, 8)
    println "top left red:", w.PixelAt(0, 0) == (0xFFFF0000 as u32)
    println "bottom right half blue:", w.PixelAt(1, 1) == (0x80000080 as u32)
    timer := window.SetTimer(1000, false)
    mut e := window.Wait(-1)
    until e.kind != window.EventKind.Timer:
        println "skipped event", e.kind as int
        e = window.Wait(-1)
    end
    println "timer", e.timer == timer, "after", window.Clock(), "ms of test time"
    w.Close()
end
Outputtop left red: true bottom right half blue: true skipped event 4 timer true after 1000 ms of test time
SystemBackendNotes
LinuxX11 through libX11XPutImage per damaged rectangle, Xft.dpi for the scale, XIM for input methods, CLIPBOARD selection. Wayland sessions use XWayland.
WindowsWin32A DIB section and BitBlt, per-monitor DPI, IME composition, the Unicode clipboard and dark mode from the registry.
macOSCocoaA layer-backed view, NSTextInputClient for input methods, NSPasteboard and the system appearance.
AnyHeadlessIn memory, for tests and rendering to files.

Types

Rect

struct Rect
A rectangle in physical pixels: the damage areas of Present and the IME area.
NameTypeDescription
xint = 0Left edge in pixels.
yint = 0Top edge in pixels.
widthint = 0Width in pixels.
heightint = 0Height in pixels.
gui-window-Present.salam
import gui.window
import mem

func main:
    w := window.Open(window.Options { width = 4.0, height = 3.0, headless = true })
    pixels := mem.AllocateZeroed((4 * 3 * 4) as u64) as u32*
    defer mem.Free(pixels as void*)
    repeat 12 in i:
        pixels[i] = 0xFF336699 as u32
    end
    println w.PresentAll(pixels as void*, 4, 3, 16), w.PresentCount(), w.LastDamage()
    pixels[5] = 0xFFFF0000 as u32
    mut damage := Vector {} as Vector<window.Rect>
    defer damage.free()
    damage.push(window.Rect { x = 1, y = 1, width = 1, height = 1 })
    println w.Present(pixels as void*, 4, 3, 16, damage), w.LastDamage(), w.LastDamageCount()
    println w.PixelAt(1, 1) == (0xFFFF0000 as u32), w.ShownPixel(0, 0) == (0xFF336699 as u32)
    println w.SetIcon(pixels as void*, 2, 2, 16)
    w.Close()
end
Outputtrue 1 Rect {x = 0, y = 0, width = 4, height = 3} true Rect {x = 1, y = 1, width = 1, height = 1} 1 true true true

WindowSize

struct WindowSize
The size of a window's drawing area in logical and physical pixels, as Size returns it.
NameTypeDescription
widthf64 = 0Width in logical pixels.
heightf64 = 0Height in logical pixels.
physical_widthint = 0Width in device pixels: the width of the buffer to draw.
physical_heightint = 0Height in device pixels.
gui-window-Open.salam
import gui.window

func main:
    options := window.Options {
        title = "Notes", width = 400.0, height = 300.0, min_width = 200.0, min_height = 150.0,
        max_width = 800.0, max_height = 600.0, resizable = true, decorated = true, centered = true,
        x = 0.0, y = 0.0, background = 0xF5F5F5FF as u32, visible = true, headless = true, scale = 2.0
    }
    w := window.Open(options)
    println w.id, w.IsOpen(), w.IsHeadless(), w.IsFocused(), w.Title()
    size := w.Size()
    println size.width, size.height, size.physical_width, size.physical_height, w.ScaleFactor()
    w.SetTitle("Notes (2)")
    w.SetSize(1000.0, 100.0)
    println w.Title(), w.Size()
    w.SetMinSize(100.0, 100.0)
    w.SetMaxSize(0.0, 0.0)
    w.SetSize(1000.0, 100.0)
    println w.Size()
    w.SetCursor(window.Cursor.Pointer)
    w.SetImeRect(20.0, 40.0, 2.0, 16.0)
    println w.CurrentCursor() == window.Cursor.Pointer, w.ImeRect()
    w.SetFullscreen(true)
    println w.IsFullscreen()
    w.SetFullscreen(false)
    w.Minimize()
    w.Maximize()
    w.Restore()
    w.Focus()
    w.RequestRedraw()
    println w.Handle() == null
    w.Close()
    println w.IsOpen()
end
Output0 true true true Notes 400 300 800 600 2 Notes (2) WindowSize {width = 800, height = 150, physical_width = 1600, physical_height = 300} WindowSize {width = 1000, height = 100, physical_width = 2000, physical_height = 200} true Rect {x = 20, y = 40, width = 2, height = 16} true true false

EventKind

enum EventKind
What an Event reports.
NameTypeDescription
NoneNothing happened before the timeout.
CloseRequestedThe user asked to close the window. Nothing closes until you call Close.
ResizedThe drawing area changed size; width, height and the physical fields hold the new size.
ScaleChangedThe window moved to a screen with another scale factor; scale holds it.
RedrawRequestedDraw a frame now and present it. Several requests in one turn arrive as one.
FocusInThe window received keyboard focus.
FocusOutThe window lost keyboard focus.
PointerMoveThe pointer moved; x and y are in logical pixels.
PointerEnterThe pointer entered the window.
PointerLeaveThe pointer left the window.
PointerDownA mouse button was pressed; see button and clicks.
PointerUpA mouse button was released.
WheelThe wheel or touchpad scrolled; see delta_x, delta_y and delta_mode.
KeyDownA key was pressed or repeats; see key, code and repeated.
KeyUpA key was released.
TextInputTyped text, separate from the key events, in text.
ImePreeditThe input method's composition text changed; empty text means it ended.
ImeCommitThe input method committed text.
ColorSchemeChangedThe system switched between light and dark; see scheme.
TimerA timer from SetTimer fired; timer is its number.
WakeAnother thread called Wake.
gui-window-Event.salam
import gui.window

func main:
    window.SetManualClock(true)
    w := window.Open(window.Options { width = 300.0, height = 200.0, headless = true })
    window.Inject(window.Event { kind = window.EventKind.PointerDown, window = w.id, x = 10.0, y = 20.0, button = window.MouseButton.Left })
    window.Inject(window.Event { kind = window.EventKind.PointerDown, window = w.id, x = 10.0, y = 20.0, button = window.MouseButton.Left })
    window.Inject(window.Event { kind = window.EventKind.KeyDown, window = w.id, key = window.Key.Enter, code = 36, modifiers = window.mod_control })
    window.Inject(window.Event { kind = window.EventKind.TextInput, window = w.id, text = "سلام" })
    window.Inject(window.Event { kind = window.EventKind.Wheel, window = w.id, delta_y = 1.0, delta_mode = window.WheelMode.Line })
    mut e := window.Poll()
    until e.kind != window.EventKind.None:
        switch e.kind:
            window.EventKind.PointerDown:
                println "down", e.x, e.y, e.button == window.MouseButton.Left, "clicks", e.clicks
                break
            end
            window.EventKind.KeyDown:
                println "key", e.key == window.Key.Enter, e.code, (e.modifiers & window.mod_control) != 0, e.repeated
                break
            end
            window.EventKind.TextInput:
                println "text", e.text
                break
            end
            window.EventKind.Wheel:
                println "wheel", e.delta_x, e.delta_y, e.delta_mode == window.WheelMode.Line
                break
            end
            else:
                println "other", e.kind as int, e.window
                break
            end
        end
        e = window.Wait(0)
    end
    w.Close()
end
Outputother 5 0 down 10 20 true clicks 1 down 10 20 true clicks 2 key true 36 true false text سلام wheel 0 1 true other 4 0

MouseButton

enum MouseButton
A mouse button.
NameTypeDescription
NoneNo button, as in a move event.
LeftThe primary button.
RightThe secondary button.
MiddleThe wheel button.
BackThe back side button.
ForwardThe forward side button.

The example for this item is shown with the ones above: gui-window-Event.salam

WheelMode

enum WheelMode
The unit of a wheel event's deltas.
NameTypeDescription
PixelLogical pixels, from a touchpad or a precise wheel.
LineLines, from a notched mouse wheel.

The example for this item is shown with the ones above: gui-window-Event.salam

ColorScheme

enum ColorScheme
The light or dark appearance of the system.
NameTypeDescription
LightLight appearance.
DarkDark appearance.
gui-window-App.salam
import gui.window
import mem

func main:
    first := window.Open(window.Options { headless = true, visible = false })
    second := window.Open(window.Options { headless = true, visible = false })
    println window.OpenWindows(), first.id, second.id
    println window.SetClipboardText("hello")
    text := window.ClipboardText()
    println text
    mem.Free(text as void*)
    println window.CurrentColorScheme() == window.ColorScheme.Light
    window.Inject(window.Event { kind = window.EventKind.ColorSchemeChanged, scheme = window.ColorScheme.Dark })
    e := window.Poll()
    println e.scheme == window.ColorScheme.Dark, window.CurrentColorScheme() == window.ColorScheme.Dark
    println window.LastError() == ""
    second.Close()
    println window.OpenWindows()
end
Output2 0 1 true hello true true true true 1

Cursor

enum Cursor
The shape of the mouse pointer over a window.
NameTypeDescription
DefaultThe arrow.
PointerA hand, for links and buttons.
TextThe text beam.
WaitBusy. macOS has no public busy cursor and shows the arrow.
CrosshairA crosshair.
MoveMove in any direction.
ResizeHorizontalResize left and right.
ResizeVerticalResize up and down.
ResizeDiagonalUpResize along the diagonal from bottom left to top right.
ResizeDiagonalDownResize along the diagonal from top left to bottom right.
NotAllowedNot allowed.
HiddenNo pointer at all.

The example for this item is shown with the ones above: gui-window-Event.salam

Key

enum Key
A key by its position on the keyboard, named after a US layout, so it does not change with the keyboard language. Use TextInput events for the characters typed.
NameTypeDescription
UnknownThe Unknown key.
AThe A key.
BThe B key.
CThe C key.
DThe D key.
EThe E key.
FThe F key.
GThe G key.
HThe H key.
IThe I key.
JThe J key.
KThe K key.
LThe L key.
MThe M key.
NThe N key.
OThe O key.
PThe P key.
QThe Q key.
RThe R key.
SThe S key.
TThe T key.
UThe U key.
VThe V key.
WThe W key.
XThe X key.
YThe Y key.
ZThe Z key.
Digit0The Digit0 key.
Digit1The Digit1 key.
Digit2The Digit2 key.
Digit3The Digit3 key.
Digit4The Digit4 key.
Digit5The Digit5 key.
Digit6The Digit6 key.
Digit7The Digit7 key.
Digit8The Digit8 key.
Digit9The Digit9 key.
F1The F1 key.
F2The F2 key.
F3The F3 key.
F4The F4 key.
F5The F5 key.
F6The F6 key.
F7The F7 key.
F8The F8 key.
F9The F9 key.
F10The F10 key.
F11The F11 key.
F12The F12 key.
EscapeThe Escape key.
EnterThe Enter key.
TabThe Tab key.
BackspaceThe Backspace key.
SpaceThe Space key.
InsertThe Insert key.
DeleteThe Delete key.
HomeThe Home key.
EndThe End key.
PageUpThe Page Up key.
PageDownThe Page Down key.
LeftThe Left key.
RightThe Right key.
UpThe Up key.
DownThe Down key.
ShiftLeftThe Shift Left key.
ShiftRightThe Shift Right key.
ControlLeftThe Control Left key.
ControlRightThe Control Right key.
AltLeftThe Alt Left key.
AltRightThe Alt Right key.
SuperLeftThe Super Left key.
SuperRightThe Super Right key.
CapsLockThe Caps Lock key.
MinusThe Minus key.
EqualThe Equal key.
BracketLeftThe Bracket Left key.
BracketRightThe Bracket Right key.
BackslashThe Backslash key.
SemicolonThe Semicolon key.
QuoteThe Quote key.
BackquoteThe Backquote key.
CommaThe Comma key.
PeriodThe Period key.
SlashThe Slash key.
IntlBackslashThe Intl Backslash key.
Numpad0The Numpad0 key.
Numpad1The Numpad1 key.
Numpad2The Numpad2 key.
Numpad3The Numpad3 key.
Numpad4The Numpad4 key.
Numpad5The Numpad5 key.
Numpad6The Numpad6 key.
Numpad7The Numpad7 key.
Numpad8The Numpad8 key.
Numpad9The Numpad9 key.
NumpadAddThe Numpad Add key.
NumpadSubtractThe Numpad Subtract key.
NumpadMultiplyThe Numpad Multiply key.
NumpadDivideThe Numpad Divide key.
NumpadDecimalThe Numpad Decimal key.
NumpadEnterThe Numpad Enter key.
NumLockThe Num Lock key.
ScrollLockThe Scroll Lock key.
PrintScreenThe Print Screen key.
PauseThe Pause key.
ContextMenuThe Context Menu key.

The example for this item is shown with the ones above: gui-window-Event.salam

Options

struct Options
How to open a window. Sizes are in logical pixels.
NameTypeDescription
titlestr = "Salam"The title bar text.
widthf64 = 800Width of the drawing area.
heightf64 = 600Height of the drawing area.
min_widthf64 = 0Smallest width the user can drag to; 0 for no limit.
min_heightf64 = 0Smallest height; 0 for no limit.
max_widthf64 = 0Largest width; 0 for no limit.
max_heightf64 = 0Largest height; 0 for no limit.
resizablebool = trueWhether the user can resize the window.
decoratedbool = trueWhether the window has a title bar and border.
centeredbool = trueCenter on the screen instead of using x and y.
xf64 = 0Left edge on the screen when not centered.
yf64 = 0Top edge on the screen when not centered.
backgroundu32 = 4294967295Colour shown before the first frame, as 0xRRGGBBAA.
visiblebool = trueShow the window as soon as it opens.
headlessbool = falseKeep the window in memory only, for tests and rendering without a screen.
scalef64 = 0Force a scale factor; 0 asks the system (or SALAM_SCALE_FACTOR).

The example for this item is shown with the ones above: gui-window-Open.salam

Event

struct Event
One event from Wait or Poll. Only the fields that belong to its kind are set.
NameTypeDescription
kindEventKindWhat happened.
windowint = -1The id of the window it belongs to, or -1 for app events.
xf64 = 0Pointer position from the left, logical pixels.
yf64 = 0Pointer position from the top, logical pixels.
widthf64 = 0New logical width (resize, scale and redraw events).
heightf64 = 0New logical height.
physical_widthint = 0New width in device pixels.
physical_heightint = 0New height in device pixels.
scalef64 = 0The scale factor (scale, resize and redraw events).
buttonMouseButtonThe mouse button.
clicksint = 01 for a single click, 2 for a double click and so on.
modifiersint = 0The Mod bits held during the event.
delta_xf64 = 0Horizontal scroll; positive scrolls right.
delta_yf64 = 0Vertical scroll; positive scrolls down, like the web wheel event.
delta_modeWheelModeWhether the deltas are pixels or lines.
keyKeyThe key by position.
codeint = 0The raw key code of the system (X11 keycode, Windows scan code, macOS key code).
repeatedbool = falseTrue when the key repeats because it is held.
textstr = ""Typed or composed text in UTF-8. It is valid until the next Wait or Poll; clone it to keep it.
cursorint = 0Caret position inside the composition text, in bytes.
schemeColorSchemeThe new colour scheme.
timerint = 0The number of the timer that fired.

The example for this item is shown with the ones above: gui-window-Event.salam

Window

struct Window
A handle to an open window. Copies refer to the same window.
NameTypeDescription
idint = -1The window's number; events carry it in window.

The example for this item is shown with the ones above: gui-window-Open.salam

IsOpen

func IsOpen(): bool
Whether the window is open. False when opening failed; see LastError.

The example for this item is shown with the ones above: gui-window-Open.salam

IsHeadless

func IsHeadless(): bool
Whether it is an in-memory window.

The example for this item is shown with the ones above: gui-window-Open.salam

IsFocused

func IsFocused(): bool
Whether it has keyboard focus.

The example for this item is shown with the ones above: gui-window-Open.salam

SetTitle

func SetTitle(title: str)
Changes the title.

The example for this item is shown with the ones above: gui-window-Open.salam

Title

func Title(): str
The current title. Valid until the next SetTitle.

The example for this item is shown with the ones above: gui-window-Open.salam

SetSize

func SetSize(width: f64, height: f64)
Asks for a new size in logical pixels, clamped to the limits; a Resized event follows.

The example for this item is shown with the ones above: gui-window-Open.salam

Size

func Size(): WindowSize
The current size in logical and physical pixels.

The example for this item is shown with the ones above: gui-window-Open.salam

ScaleFactor

func ScaleFactor(): f64
Device pixels per logical pixel.

The example for this item is shown with the ones above: gui-window-Open.salam

Present

func Present(pixels: void*, width: int, height: int, stride: int, damage: Vector<Rect>): bool
Shows a premultiplied BGRA buffer and copies only the damaged rectangles; an empty vector means the whole buffer. Returns false for a bad buffer.

The example for this item is shown with the ones above: gui-window-Present.salam

PresentAll

func PresentAll(pixels: void*, width: int, height: int, stride: int): bool
Shows the whole buffer.

The example for this item is shown with the ones above: gui-window-Present.salam

RequestRedraw

func RequestRedraw()
Asks for a RedrawRequested event; repeated requests merge into one.

The example for this item is shown with the ones above: gui-window-Open.salam

SetCursor

func SetCursor(cursor: Cursor)
Sets the pointer shape over the window.

The example for this item is shown with the ones above: gui-window-Open.salam

SetImeRect

func SetImeRect(x: f64, y: f64, width: f64, height: f64)
Tells the input method where the caret is, in logical pixels, so its window follows the text.

The example for this item is shown with the ones above: gui-window-Open.salam

SetMinSize

func SetMinSize(width: f64, height: f64)
Sets the smallest size; 0 removes the limit.

The example for this item is shown with the ones above: gui-window-Open.salam

SetMaxSize

func SetMaxSize(width: f64, height: f64)
Sets the largest size; 0 removes the limit.

The example for this item is shown with the ones above: gui-window-Open.salam

Minimize

func Minimize()
Minimizes the window.

The example for this item is shown with the ones above: gui-window-Open.salam

Maximize

func Maximize()
Maximizes the window.

The example for this item is shown with the ones above: gui-window-Open.salam

Restore

func Restore()
Restores it from minimized or maximized.

The example for this item is shown with the ones above: gui-window-Open.salam

SetFullscreen

func SetFullscreen(enabled: bool)
Enters or leaves full screen.

The example for this item is shown with the ones above: gui-window-Open.salam

IsFullscreen

func IsFullscreen(): bool
Whether full screen was requested.

The example for this item is shown with the ones above: gui-window-Open.salam

Focus

func Focus()
Brings the window to the front with keyboard focus.

The example for this item is shown with the ones above: gui-window-Open.salam

Close

func Close()
Closes the window and frees its buffer.

The example for this item is shown with the ones above: gui-window-Open.salam

SetIcon

func SetIcon(pixels: void*, width: int, height: int, stride: int): bool
Sets the window icon (the application icon on macOS) from a pixel buffer.

The example for this item is shown with the ones above: gui-window-Present.salam

PixelAt

func PixelAt(x: int, y: int): u32
Reads a pixel of the last presented frame as 0xAARRGGBB, or 0 outside it.

The example for this item is shown with the ones above: gui-window-Present.salam

ShownPixel

func ShownPixel(x: int, y: int): u32
Reads a pixel back from the system, where it can: X11 and Windows read the screen, macOS and headless windows the frame. Alpha is always FF.

The example for this item is shown with the ones above: gui-window-Present.salam

PresentCount

func PresentCount(): int
How many frames were presented.

The example for this item is shown with the ones above: gui-window-Present.salam

LastDamage

func LastDamage(): Rect
The bounding box of the rectangles the last present copied.

The example for this item is shown with the ones above: gui-window-Present.salam

LastDamageCount

func LastDamageCount(): int
How many rectangles the last present copied.

The example for this item is shown with the ones above: gui-window-Present.salam

CurrentCursor

func CurrentCursor(): Cursor
The pointer shape set last.

The example for this item is shown with the ones above: gui-window-Open.salam

ImeRect

func ImeRect(): Rect
The IME area set last.

The example for this item is shown with the ones above: gui-window-Open.salam

Handle

func Handle(): void*
The native handle: an X11 window id, an HWND or an NSWindow; null for headless windows.

The example for this item is shown with the ones above: gui-window-Open.salam

Constants and variables

mod_shift

const mod_shift: i32 = 1
Bit set in modifiers while Shift is held.

The example for this item is shown with the ones above: gui-window-Event.salam

mod_control

const mod_control: i32 = 2
Bit set in modifiers while Control is held.

The example for this item is shown with the ones above: gui-window-Event.salam

mod_alt

const mod_alt: i32 = 4
Bit set in modifiers while Alt (Option on macOS) is held.

The example for this item is shown with the ones above: gui-window-Event.salam

mod_super

const mod_super: i32 = 8
Bit set in modifiers while the Windows key or Command is held.

The example for this item is shown with the ones above: gui-window-Event.salam

Functions

Open

func Open(options: Options): Window
Opens a window. Check IsOpen: without a window system it returns a closed window and LastError says why.

The example for this item is shown with the ones above: gui-window-Open.salam

LastError

func LastError(): str
Why the last native call failed, or empty.

The example for this item is shown with the ones above: gui-window-App.salam

Wait

func Wait(timeout_ms: int): Event
Waits up to timeout_ms (-1 for no limit) for the next event, firing due timers. Returns a None event on timeout.

The example for this item is shown with the ones above: gui-window-Event.salam

Poll

func Poll(): Event
Returns the next event without waiting.

The example for this item is shown with the ones above: gui-window-Event.salam

Inject

func Inject(event: Event)
Adds an event to the queue as if the system had sent it, and applies it (size, focus, scheme). For tests.

The example for this item is shown with the ones above: gui-window-Event.salam

SetTimer

func SetTimer(ms: int, repeating: bool): int
Starts a timer that fires every ms milliseconds, or once; returns its number.
gui-window-Timer.salam
import gui.window

func main:
    window.SetManualClock(true)
    tick := window.SetTimer(100, true)
    once := window.SetTimer(250, false)
    repeat 4:
        e := window.Wait(-1)
        println e.kind == window.EventKind.Timer, e.timer == tick ? "tick" : "once", window.Clock()
    end
    window.ClearTimer(tick)
    window.Advance(1000)
    println window.Clock(), window.Wait(10).kind == window.EventKind.None
    window.Wake()
    println window.Wait(-1).kind == window.EventKind.Wake, once > tick
end
Outputtrue tick 100 true tick 200 true once 250 true tick 300 1300 true true true

ClearTimer

func ClearTimer(id: int)
Stops a timer.

The example for this item is shown with the ones above: gui-window-Timer.salam

Wake

func Wake()
Interrupts Wait from any thread with a Wake event.

The example for this item is shown with the ones above: gui-window-Timer.salam

SetManualClock

func SetManualClock(enabled: bool)
Switches to a test clock that starts at 0 and only moves when Wait jumps to the next timer or Advance is called.

The example for this item is shown with the ones above: gui-window-Timer.salam

Clock

func Clock(): i64
The event clock in milliseconds.

The example for this item is shown with the ones above: gui-window-Timer.salam

Advance

func Advance(ms: int)
Moves the test clock forward.

The example for this item is shown with the ones above: gui-window-Timer.salam

ClipboardText

func ClipboardText(): str
The clipboard text. The caller frees it.

The example for this item is shown with the ones above: gui-window-App.salam

SetClipboardText

func SetClipboardText(text: str): bool
Puts text on the clipboard.

The example for this item is shown with the ones above: gui-window-App.salam

CurrentColorScheme

func CurrentColorScheme(): ColorScheme
Whether the system is in light or dark mode.

The example for this item is shown with the ones above: gui-window-App.salam

OpenWindows

func OpenWindows(): int
How many windows are open.

The example for this item is shown with the ones above: gui-window-App.salam