module x11

module lib/x11.mu

import "x11"

x11 speaks the X11 wire protocol directly: connect, authenticate, create windows, draw, and read events — over a unix socket, in pure µ. No Xlib, no FFI, no C. This is the platform layer beneath ui on Linux, the way objc is on macOS, and it is usable on its own for anything that wants a window an X server is offering.

Everything on the wire lives in µ buffers, never strings: the protocol is binary, and a buffer says exactly the bytes it means. We announce little-endian ('l') in the setup request, so every integer here is little-endian; the one exception is ~/.Xauthority, whose u16 fields are big-endian by its own convention.

One connection is a map handle. Requests write immediately; replies and events are read from an internal byte accumulator, and events that arrive while a reply is awaited queue up for the next wait_event(). Text drawing uses the core protocol's 8-bit path (ImageText8) with the "fixed" font: ASCII renders as itself, and µ's UTF-8 multibyte sequences will show as their latin-1 component glyphs — a core-fonts limitation, not a µ one.

Imports

Functions

close#

fn close(x)

close shuts the connection down.

Source lib/x11.mu:76
fn close(x) {
    return syscall("close", x["fd"])
}

connect#

fn connect(display...)

connect opens a connection to the X server named by the display string (":0" style; defaults to $DISPLAY), authenticates from ~/.Xauthority when the server asks for it, and returns a connection handle, or an error.

Source lib/x11.mu:28
fn connect(display...) {
    name := nil

    if len(display) > 0 {
        name = display[0]
    }

    if name == nil {
        name = env("DISPLAY")
    }

    if name == nil || name == "" {
        return error("x11.connect: no display — set DISPLAY or pass one")
    }

    parsed := _parse_display(name)

    if is_error(parsed) {
        return parsed
    }

    fd := _dial_unix(parsed["socket"])

    if is_error(fd) {
        return fd
    }

    x := {"fd": fd, "acc": buf(0), "off": 0, "seq": 0, "idnext": 0, "evq": [], "atoms": {}}
    auth := _read_xauthority(parsed["number"])
    ok := _handshake(x, auth)

    if is_error(ok) {
        syscall("close", fd)
        return ok
    }

    ok = _load_keymap(x)

    if is_error(ok) {
        syscall("close", fd)
        return ok
    }

    return x
}

copy_area#

fn copy_area(x, src, dst, gc, sx, sy, dx, dy, w, h)

copy_area blits a w×h region between same-depth drawables.

Source lib/x11.mu:1093
fn copy_area(x, src, dst, gc, sx, sy, dx, dy, w, h) {
    b := buf(0)
    // CopyArea
    _w8(b, 62)
    _w8(b, 0)
    _w16(b, 7)
    _w32(b, src)
    _w32(b, dst)
    _w32(b, gc)
    _w16(b, sx & 0xffff)
    _w16(b, sy & 0xffff)
    _w16(b, dx & 0xffff)
    _w16(b, dy & 0xffff)
    _w16(b, w)
    _w16(b, h)
    return _send(x, b)
}

create_gc#

fn create_gc(x, drawable, fg, bg)

create_gc makes a graphics context on the drawable with the given foreground and background pixels, using the core "fixed" font so the same gc draws rectangles and text. Returns the gc id.

Source lib/x11.mu:234
fn create_gc(x, drawable, fg, bg) {
    fid := _newid(x)
    fname := "fixed"
    b := buf(0)
    // OpenFont
    _w8(b, 45)
    _w8(b, 0)
    _w16(b, 3 + (len(fname) + _padlen(len(fname))) / 4)
    _w32(b, fid)
    _w16(b, len(fname))
    _w16(b, 0)
    _wstr(b, fname)
    _pad(b)
    err := _send(x, b)

    if is_error(err) {
        return err
    }

    gid := _newid(x)
    b = buf(0)
    // CreateGC
    _w8(b, 55)
    _w8(b, 0)
    // 4 fixed + 3 values
    _w16(b, 7)
    _w32(b, gid)
    _w32(b, drawable)
    // GCForeground | GCBackground | GCFont
    _w32(b, 4 + 8 + 16384)
    _w32(b, fg)
    _w32(b, bg)
    _w32(b, fid)
    err = _send(x, b)

    if is_error(err) {
        return err
    }

    return gid
}

create_pixmap#

fn create_pixmap(x, drawable, w, h)

create_pixmap makes an offscreen drawable the depth of the screen — the back buffer a flicker-free redraw paints into.

Source lib/x11.mu:1059
fn create_pixmap(x, drawable, w, h) {
    pid := _newid(x)
    b := buf(0)
    // CreatePixmap
    _w8(b, 53)
    _w8(b, x["depth"])
    _w16(b, 4)
    _w32(b, pid)
    _w32(b, drawable)
    _w16(b, w)
    _w16(b, h)
    err := _send(x, b)

    if is_error(err) {
        return err
    }

    return pid
}

create_window#

fn create_window(x, w, h, title)

create_window makes a w×h top-level InputOutput window with a white background, subscribed to key, button, exposure and structure events, and wired for WM_DELETE_WINDOW so a window manager's close button reports as a "close" event instead of killing the connection. Returns the window id.

Source lib/x11.mu:85
fn create_window(x, w, h, title) {
    wid := _newid(x)
    b := buf(0)
    _w8(b, 1)
    // depth: CopyFromParent
    _w8(b, 0)
    // 8 fixed words + 2 values
    _w16(b, 10)
    _w32(b, wid)
    _w32(b, x["root"])
    // x, y — the WM decides anyway
    _w16(b, 0)
    _w16(b, 0)
    _w16(b, w)
    _w16(b, h)
    // border
    _w16(b, 0)
    // InputOutput
    _w16(b, 1)
    // CopyFromParent visual
    _w32(b, 0)
    // CWBackPixel | CWEventMask
    _w32(b, 2 + 2048)
    _w32(b, x["white"])
    // KeyPress | ButtonPress | ButtonRelease | Exposure | StructureNotify
    _w32(b, 1 + 4 + 8 + 32768 + 131072)
    err := _send(x, b)

    if is_error(err) {
        return err
    }

    err = set_title(x, wid, title)

    if is_error(err) {
        return err
    }

    err = _wire_close(x, wid)

    if is_error(err) {
        return err
    }

    return wid
}

destroy_window#

fn destroy_window(x, wid)

destroy_window tears a window down.

Source lib/x11.mu:170
fn destroy_window(x, wid) {
    b := buf(0)
    _w8(b, 4)
    _w8(b, 0)
    _w16(b, 2)
    _w32(b, wid)
    return _send(x, b)
}

draw_rect#

fn draw_rect(x, drawable, gc, rx, ry, rw, rh)

draw_rect outlines one rectangle on the drawable.

Source lib/x11.mu:310
fn draw_rect(x, drawable, gc, rx, ry, rw, rh) {
    b := buf(0)
    // PolyRectangle
    _w8(b, 67)
    _w8(b, 0)
    _w16(b, 5)
    _w32(b, drawable)
    _w32(b, gc)
    _w16(b, rx & 0xffff)
    _w16(b, ry & 0xffff)
    _w16(b, rw)
    _w16(b, rh)
    return _send(x, b)
}

draw_text#

fn draw_text(x, drawable, gc, tx, ty, s)

draw_text draws a string with its baseline at (tx, ty). 8-bit core text: ASCII/latin-1 only, at most 255 bytes.

Source lib/x11.mu:328
fn draw_text(x, drawable, gc, tx, ty, s) {
    n := len(s)

    if n > 255 {
        return error("x11.draw_text: string longer than 255 bytes")
    }

    b := buf(0)
    // ImageText8
    _w8(b, 76)
    _w8(b, n)
    _w16(b, 4 + (n + _padlen(n)) / 4)
    _w32(b, drawable)
    _w32(b, gc)
    _w16(b, tx & 0xffff)
    _w16(b, ty & 0xffff)
    _wstr(b, s)
    _pad(b)
    return _send(x, b)
}

fill_rect#

fn fill_rect(x, drawable, gc, rx, ry, rw, rh)

fill_rect fills one rectangle on the drawable.

Source lib/x11.mu:293
fn fill_rect(x, drawable, gc, rx, ry, rw, rh) {
    b := buf(0)
    // PolyFillRectangle
    _w8(b, 70)
    _w8(b, 0)
    _w16(b, 5)
    _w32(b, drawable)
    _w32(b, gc)
    _w16(b, rx & 0xffff)
    _w16(b, ry & 0xffff)
    _w16(b, rw)
    _w16(b, rh)
    return _send(x, b)
}

free_pixmap#

fn free_pixmap(x, pid)

free_pixmap releases an offscreen drawable.

Source lib/x11.mu:1081
fn free_pixmap(x, pid) {
    b := buf(0)
    // FreePixmap
    _w8(b, 54)
    _w8(b, 0)
    _w16(b, 2)
    _w32(b, pid)
    return _send(x, b)
}

get_image#

fn get_image(x, drawable, ix, iy, iw, ih)

get_image reads back a w×h region of the drawable as ZPixmap bytes. Returns {"depth", "data"}; at the usual 24-bit depth each pixel is 4 little-endian bytes, blue first.

Source lib/x11.mu:382
fn get_image(x, drawable, ix, iy, iw, ih) {
    b := buf(0)
    // GetImage
    _w8(b, 73)
    // ZPixmap
    _w8(b, 2)
    _w16(b, 5)
    _w32(b, drawable)
    _w16(b, ix & 0xffff)
    _w16(b, iy & 0xffff)
    _w16(b, iw)
    _w16(b, ih)
    // plane mask
    _w32(b, 0xffffffff)
    reply := _roundtrip(x, b)

    if is_error(reply) {
        return reply
    }

    depth := reply[1]
    data := buf(len(reply) - 32)
    i := 32

    while i < len(reply) {
        data[i - 32] = reply[i]
        i = i + 1
    }

    return {"depth": depth, "data": data}
}

intern_atom#

fn intern_atom(x, name)

intern_atom resolves an atom name to its id (cached per connection).

Source lib/x11.mu:351
fn intern_atom(x, name) {
    got := x["atoms"][name]

    if got != nil {
        return got
    }

    b := buf(0)
    // InternAtom
    _w8(b, 16)
    _w8(b, 0)
    _w16(b, 2 + (len(name) + _padlen(len(name))) / 4)
    _w16(b, len(name))
    _w16(b, 0)
    _wstr(b, name)
    _pad(b)
    reply := _roundtrip(x, b)

    if is_error(reply) {
        return reply
    }

    atom := _b32(reply, 8)
    x["atoms"][name] = atom
    return atom
}

map_window#

fn map_window(x, wid)

map_window puts a window on screen.

Source lib/x11.mu:159
fn map_window(x, wid) {
    b := buf(0)
    _w8(b, 8)
    _w8(b, 0)
    _w16(b, 2)
    _w32(b, wid)
    return _send(x, b)
}

pixel_at#

fn pixel_at(img, iw, px, py)

pixel_at reads one pixel from a get_image result as 0xRRGGBB.

Source lib/x11.mu:416
fn pixel_at(img, iw, px, py) {
    data := img["data"]
    off := (py * iw + px) * 4
    return data[off + 2] * 65536 + data[off + 1] * 256 + data[off]
}

send_event#

fn send_event(x, wid, event_mask, event32)

send_event delivers a raw 32-byte event to whoever selected event_mask on the destination window — the protocol's own way to synthesize input, which is what makes a headless UI test honest: the event arrives through the server like any other.

Source lib/x11.mu:184
fn send_event(x, wid, event_mask, event32) {
    b := buf(0)
    // SendEvent
    _w8(b, 25)
    // propagate: false
    _w8(b, 0)
    _w16(b, 11)
    _w32(b, wid)
    _w32(b, event_mask)
    _wbuf(b, event32)

    while len(b) < 44 {
        append(b, 0)
    }

    err := _send(x, b)

    if is_error(err) {
        return err
    }

    // The server only flushes another client's event buffer when its
    // dispatch loop comes around; a roundtrip makes it come around — the
    // same reason Xlib has XSync — and surfaces any error this request drew.
    return sync(x)
}

set_foreground#

fn set_foreground(x, gc, pixel)

set_foreground changes a gc's foreground pixel.

Source lib/x11.mu:278
fn set_foreground(x, gc, pixel) {
    b := buf(0)
    // ChangeGC
    _w8(b, 56)
    _w8(b, 0)
    _w16(b, 4)
    _w32(b, gc)
    // GCForeground
    _w32(b, 4)
    _w32(b, pixel)
    return _send(x, b)
}

set_title#

fn set_title(x, wid, title)

set_title names a window (WM_NAME, latin-1/ASCII).

Source lib/x11.mu:134
fn set_title(x, wid, title) {
    b := buf(0)
    n := len(title)
    // ChangeProperty
    _w8(b, 18)
    // Replace
    _w8(b, 0)
    _w16(b, 6 + (n + _padlen(n)) / 4)
    _w32(b, wid)
    // WM_NAME
    _w32(b, 39)
    // STRING
    _w32(b, 31)
    // format
    _w8(b, 8)
    _w8(b, 0)
    _w16(b, 0)
    _w32(b, n)
    _wstr(b, title)
    _pad(b)
    return _send(x, b)
}

sync#

fn sync(x)

sync completes a roundtrip: once it returns, the server has processed every request sent before it, and their events have been flushed to the clients they were for.

Source lib/x11.mu:215
fn sync(x) {
    b := buf(0)
    // GetInputFocus: the no-op with a reply
    _w8(b, 43)
    _w8(b, 0)
    _w16(b, 1)
    reply := _roundtrip(x, b)

    if is_error(reply) {
        return reply
    }

    return nil
}

wait_event#

fn wait_event(x)

wait_event blocks until the server sends an event and returns it decoded: {"type": "expose" | "button_press" | "button_release" | "key_press" | "close" | "configure" | "error" | "other", ...}. Key presses carry the keycode, the modifier state, and "key" — the translated text ("a", "A") or a name ("return", "backspace", "tab", "escape", "") for the rest. An asynchronous server error arrives as {"type": "error", "code", "seq"}; only a dead connection is a µ error value.

Source lib/x11.mu:430
fn wait_event(x) {
    while true {
        if len(x["evq"]) > 0 {
            q := x["evq"]
            ev := q[0]
            rest := []
            i := 1

            while i < len(q) {
                rest = append(rest, q[i])
                i = i + 1
            }

            x["evq"] = rest
            return ev
        }

        unit := _read_unit(x)

        if is_error(unit) {
            return unit
        }

        code := unit[0] & 0x7f

        if code == 0 {
            return error("x11: server error code " + str(unit[1]) + " for request " + str(_b16(unit, 2)))
        }

        if code == 1 {
        } else {
            // A reply nothing is waiting for; drop it.
            ev := _decode_event(x, unit)

            if ev != nil {
                return ev
            }
        }
    }
}

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.

_auth_field(data, i)
_b16(b, off)
_b16s(b, off)
_b32(b, off)
_decode_event(x, unit)
_dial_unix(path)
_handshake(x, auth)
_load_keymap(x)
_newid(x)
_pad(b)
_padlen(n)
_parse_display(name)
_read_unit(x)
_read_xauthority(number)
_read_xauthority_at(path, number)
_roundtrip(x, b)
_send(x, b)
_send_raw(x, b)
_take(x, n)
_translate_key(x, keycode, state)
_w16(b, v)
_w32(b, v)
_w8(b, v)
_wbuf(b, src)
_wire_close(x, wid)
_wstr(b, s)