module ui_x11
module lib/ui_x11.mu
import "ui_x11"
ui_x11 is the Linux backend behind ui: widgets drawn by µ itself with the X11 core protocol — rectangles and server-side "fixed"-font text — and an event loop over x11.wait_event. Programs import ui, never this module. It runs on X.org sessions and, through Xwayland, on every Wayland desktop.
Where Cocoa hands out real controls, here a widget is only state: its frame, its text, its handler. Every expose repaints the window from that state, a button press hit-tests against it, and key presses edit whichever input holds focus. The "fixed" font is 6×13, which is where the metric constants below come from.
Imports
Functions
backend#
backend answers the function table ui dispatches through.
Source lib/ui_x11.mu:30
fn backend() {
return {"init": init, "window": window, "label": label, "button": button, "input": input, "checkbox": checkbox, "textarea": textarea, "set_text": set_text, "get_text": get_text, "get_checked": get_checked, "set_checked": set_checked, "place": place, "remove": remove, "run": run}
}button#
Undocumented.
Source lib/ui_x11.mu:74
fn button(_, win, title, x, y, w, h, onclick) {
return _add(win, {"kind": "button", "text": title, "x": x, "y": y, "w": w, "h": h, "win": win, "onclick": onclick})
}checkbox#
Undocumented.
Source lib/ui_x11.mu:82
fn checkbox(_, win, title, x, y, w, h, onchange) {
return _add(win, {"kind": "checkbox", "text": title, "checked": false, "x": x, "y": y, "w": w, "h": h, "win": win, "onchange": onchange})
}get_checked#
Undocumented.
Source lib/ui_x11.mu:90
fn get_checked(_, widget) {
return widget["checked"]
}get_text#
Undocumented.
Source lib/ui_x11.mu:134
fn get_text(_, widget) {
if widget["kind"] == "window" {
return widget["title"]
}
return widget["text"]
}init#
init defers connecting: the display is only touched when the first window is created, so importing ui stays harmless without one.
Source lib/ui_x11.mu:37
fn init(_) {
return true
}input#
Undocumented.
Source lib/ui_x11.mu:78
fn input(_, win, text, x, y, w, h, onsubmit) {
return _add(win, {"kind": "input", "text": text, "x": x, "y": y, "w": w, "h": h, "win": win, "onsubmit": onsubmit})
}label#
Undocumented.
Source lib/ui_x11.mu:70
fn label(_, win, text, x, y, w, h) {
return _add(win, {"kind": "label", "text": text, "x": x, "y": y, "w": w, "h": h, "win": win})
}place#
Undocumented.
Source lib/ui_x11.mu:142
fn place(u, widget, x, y, w, h) {
widget["x"] = x
widget["y"] = y
widget["w"] = w
widget["h"] = h
return _redraw(u, widget["win"])
}remove#
remove drops a view from its window for good.
Source lib/ui_x11.mu:101
fn remove(u, widget) {
win := widget["win"]
kept := []
views := win["views"]
i := 0
while i < len(views) {
if !_same(views[i], widget) {
kept = append(kept, views[i])
}
i = i + 1
}
win["views"] = kept
if _same(win["focus"], widget) {
win["focus"] = nil
}
return _redraw(u, win)
}run#
run multiplexes with the language's own tools: a reader task blocks in wait_event and feeds a channel, and this loop receives from it — with poll(ch, timeout_ms) bounding the wait when a timer is pending. poll(2) stays out of the µ syscall surface, as decided; the scheduler's timed receive is what µ has instead.
Source lib/ui_x11.mu:159
fn run(u) {
x := u["x"]
if x == nil {
return error("ui: no window was created before run()")
}
events := chan(64)
u["_x_stop"] = false
task(fn() {
while !u["_x_stop"] {
ev := x11.wait_event(u["x"])
// Bounded retry-push: the reader must never be stranded in a
// blocking send after the loop has gone away.
delivered := false
while !delivered && !u["_x_stop"] {
delivered = push(events, ev)
if !delivered {
time.sleep(0.01)
}
}
if is_error(ev) {
return nil
}
}
return nil
})
result := nil
while u["running"] {
_show_new_windows(u)
// Fire due timers; the budget until the next one bounds the wait —
// poll(ch, ms) is the scheduler's own timed receive, so a timer
// deadline costs no waker tasks and wakes exactly on time.
tick := u["tick"]
budget := tick()
ev := nil
if budget == nil {
ev = recv(events)
} else {
if budget < 1 {
budget = 1
}
got := poll(events, budget)
if !got[0] {
// The budget elapsed: timers are due again.
continue
}
ev = got[1]
}
if is_error(ev) {
result = ev
u["running"] = false
} else {
_handle(u, ev)
}
if !_any_window_open(u) {
u["running"] = false
}
}
// Tear down: closing the connection unblocks the reader, which sees the
// dead socket and exits — nothing is left to keep the process alive.
// The windows die with the connection, which real programs never see:
// run() is their last act.
u["_x_stop"] = true
x11.close(u["x"])
u["x"] = nil
wins := u["windows"]
i := 0
while i < len(wins) {
wins[i]["_closed"] = true
i = i + 1
}
return result
}set_checked#
Undocumented.
Source lib/ui_x11.mu:94
fn set_checked(u, widget, v) {
widget["checked"] = v == true
return _redraw(u, widget["win"])
}set_text#
Undocumented.
Source lib/ui_x11.mu:124
fn set_text(u, widget, text) {
if widget["kind"] == "window" {
widget["title"] = text
return x11.set_title(u["x"], widget["wid"], text)
}
widget["text"] = text
return _redraw(u, widget["win"])
}textarea#
Undocumented.
Source lib/ui_x11.mu:86
fn textarea(_, win, content, x, y, w, h) {
return _add(win, {"kind": "textarea", "text": content, "x": x, "y": y, "w": w, "h": h, "win": win})
}window#
window creates (and lazily connects to) an X11 top-level window.
Source lib/ui_x11.mu:43
fn window(u, title, w, h) {
if u["x"] == nil {
x := x11.connect()
if is_error(x) {
return x
}
u["x"] = x
}
x := u["x"]
wid := x11.create_window(x, w, h, title)
if is_error(wid) {
return wid
}
gc := x11.create_gc(x, wid, _BLACK, _WHITE)
if is_error(gc) {
return gc
}
return {"kind": "window", "wid": wid, "gc": gc, "title": title, "w": w, "h": h, "views": [], "focus": nil, "_shown": false, "_closed": false, "onclose": nil}
}Internal helpers
Underscore-prefixed names are implementation detail. They are listed so the module's source reads without surprises, not as API — they may change at any time.
| _ACCENT | 0x3580c4: focus ring |
| _ASCENT | — |
| _BLACK | — |
| _CHARW | — |
| _FACE | 0xe9e9e9: button face |
| _WHITE | — |
| _add(win, widget) | — |
| _any_window_open(u) | — |
| _draw_view(x, wid, gc, v, focus) | — |
| _find_window(u, wid) | — |
| _handle(u, ev) | — |
| _hit(win, px, py) | — |
| _ids | — |
| _redraw(u, win) | — |
| _same(a, b) | — |
| _show_new_windows(u) | — |
| _type_key(u, win, key) | — |