Documentation
¶
Overview ¶
Package x11 is a from-scratch, pure-Go (CGO-free, no non-stdlib dependency) implementation of the pieces of the X Window System protocol, version 11.0, that every X client needs before it can say anything of its own: the wire encoder and decoder, the .Xauthority parser, the connection-setup exchange and its reply, the anonymous shared-memory segment MIT-SHM attaches, and the unix-domain transport that hands the server a descriptor over SCM_RIGHTS.
It deliberately stops there. It has no request table, no event loop and no opinion about what a client does with a connection: a screen capture and a window toolkit want very different request/reply machines on top of the same bytes, and this package is the bytes. A consumer builds its own connection type over Handshake's result.
Everything above the socket is transport-agnostic: Handshake takes any io.ReadWriteCloser, so the whole codec is exercisable in-process over a net.Pipe against a scripted fake server. That is what lets the wire format be tested to 100% on darwin and on windows, with no X server anywhere — a protocol bug is caught on every platform, not only on the one that can run an X server.
Index ¶
- Constants
- Variables
- func AuthFilePath() string
- func DialUnix(path string) (io.ReadWriteCloser, error)
- func EncodeAuthEntry(e AuthEntry) []byte
- func LoadAuthCookie(authFile, host, display string) (name string, data []byte, err error)
- func Pad4(n int) int
- func Padding(n int) int
- func ReadFull(r io.Reader, b []byte) error
- func TrimNul(b []byte) string
- func WrapUnix(c *net.UnixConn) io.ReadWriteCloser
- type AuthEntry
- type ByteOrder
- type Decoder
- func (d *Decoder) Get8() byte
- func (d *Decoder) Get16() uint16
- func (d *Decoder) Get16s() int16
- func (d *Decoder) Get32() uint32
- func (d *Decoder) GetBytes(n int) []byte
- func (d *Decoder) GetString(n int) string
- func (d *Decoder) OK() bool
- func (d *Decoder) Order() ByteOrder
- func (d *Decoder) Skip(n int)
- type Depth
- type Encoder
- func (e *Encoder) Bytes() []byte
- func (e *Encoder) Order() ByteOrder
- func (e *Encoder) Pad(n int)
- func (e *Encoder) Put8(v byte)
- func (e *Encoder) Put16(v uint16)
- func (e *Encoder) Put32(v uint32)
- func (e *Encoder) PutBytes(b []byte)
- func (e *Encoder) PutString(s string)
- func (e *Encoder) Skip(n int)
- type FDSender
- type Format
- type Screen
- type Segment
- type Setup
- type SetupError
- type VisualType
- type Waiter
Constants ¶
const ( VisualStaticGray = 0 VisualGrayScale = 1 VisualStaticColor = 2 VisualPseudoColor = 3 VisualTrueColor = 4 VisualDirectColor = 5 )
Visual classes. Only TrueColor and DirectColor decompose a pixel through the masks; the palette classes would need the colormap read back, which no display built this millennium presents.
const ( ImageOrderLSB = 0 ImageOrderMSB = 1 )
Image byte-order values reported by Setup.ImageByteOrder.
const ( OrderLSB = 'l' OrderMSB = 'B' )
The two byte-order sentinels sent as the first byte of the setup request: 'l' little-endian (LSB first), 'B' big-endian (MSB first).
const ( FamilyInternet = 0 FamilyLocal = 256 FamilyWild = 65535 FamilyInternet6 = 6 )
Xauthority address families (X11/Xauth.h). Lengths in the file are always big-endian, independent of the machine.
const AuthMITCookie = "MIT-MAGIC-COOKIE-1"
AuthMITCookie is the MIT-MAGIC-COOKIE-1 authorization protocol name sent in the setup request when a matching cookie is found in the authority file.
Variables ¶
ErrNoSharedMemory is reported off Linux, where no X server is dialed and so no shared segment is ever needed. Everything above it — the wire codec, the Xauthority parser, the setup exchange — is portable and is fully exercised here; only the shared memory and the socket are not.
var ErrNoTransport = errors.New("x11: dialing an X server over a unix socket is not implemented on this platform")
ErrNoTransport is reported where there is no unix-domain socket to dial — windows, js/wasm, plan9. The wire codec above this line is portable and is fully exercised on those platforms against an in-process scripted server; what is missing here is only the socket.
Functions ¶
func AuthFilePath ¶
func AuthFilePath() string
AuthFilePath returns the authority file to consult: $XAUTHORITY if set, otherwise $HOME/.Xauthority, otherwise "".
func DialUnix ¶
func DialUnix(path string) (io.ReadWriteCloser, error)
DialUnix reports ErrNoTransport.
func EncodeAuthEntry ¶
EncodeAuthEntry serializes an AuthEntry back to the Xauthority file format. It is the exact inverse of ParseXauthority, and is exported because the only honest way to test a client against a cookie is to write one: a test builds the fixture with this, and a round-trip through the parser proves the two agree.
func LoadAuthCookie ¶
LoadAuthCookie resolves the MIT-MAGIC-COOKIE-1 for (host, display) from the given authority file. A missing file, or no match, is not an error: it returns an empty name and data so the caller falls back to an unauthenticated setup, exactly as Xlib does. host defaults to the machine hostname when empty.
func Pad4 ¶
Pad4 returns n rounded up to the next multiple of four. X11 pads every variable-length field to a four-byte boundary.
func ReadFull ¶
ReadFull reads exactly len(b) bytes or returns the first error. It is kept here so the codec's callers have one spelling of "read a whole packet".
func TrimNul ¶
TrimNul returns b up to its first NUL, as a string. X11 zero-pads several text fields (a vendor string, a refusal reason, a format-8 property) and states their length separately or not at all.
func WrapUnix ¶
func WrapUnix(c *net.UnixConn) io.ReadWriteCloser
WrapUnix reports ErrNoTransport by returning nil: there is no SCM_RIGHTS on this platform, so there is nothing a wrapper could add to the connection. A caller passes its own io.ReadWriteCloser to Handshake instead.
Types ¶
type AuthEntry ¶
type AuthEntry struct {
Family uint16
Address []byte
Number string // display number as ASCII; "" is a wildcard
Name string // authorization protocol name
Data []byte // the cookie
}
AuthEntry is one record parsed from an Xauthority file.
type ByteOrder ¶
ByteOrder is the wire byte order negotiated at connection setup. X11 lets the client pick; the server then speaks the client's order for the session.
type Decoder ¶
type Decoder struct {
// contains filtered or unexported fields
}
Decoder reads a fixed-order byte slice. Every read is bounds-checked; once the Decoder is not OK it stays that way, so a truncated buffer degrades to a clean error at the call site rather than a panic.
func NewDecoder ¶
NewDecoder wraps b for reading in the given order.
func (*Decoder) OK ¶
OK reports whether every read so far stayed inside the buffer. A parser checks it once, at the end, rather than after every field.
type Depth ¶
type Depth struct {
Depth uint8
Visuals []VisualType
}
Depth groups the visuals available at a given colour depth.
type Encoder ¶
type Encoder struct {
// contains filtered or unexported fields
}
Encoder builds a request body in a chosen byte order. Every multi-byte integer goes through the negotiated ByteOrder, so the same code emits a correct little- or big-endian stream.
func NewEncoder ¶
NewEncoder starts an Encoder in the given order.
func (*Encoder) Bytes ¶
Bytes returns the bytes written so far. The slice aliases the Encoder's own buffer, so a caller that keeps it past the next write must copy it.
type FDSender ¶
type FDSender interface {
// SendFD writes one already-framed request with fd attached as a single
// SCM_RIGHTS control message.
SendFD(msg []byte, fd int) error
}
FDSender is implemented by a transport that can pass a file descriptor alongside a request over the same socket (a unix-domain stream, via SCM_RIGHTS). The transport WrapUnix returns implements it; an in-process net.Pipe used by a test does not, so a client's MIT-SHM fd-passing path degrades to the plain socket path when it is absent.
It is an interface rather than a concrete type because that is what keeps the connection above it transport-agnostic: a client type-asserts on this and never on a socket.
type Format ¶
Format is one entry of the server's pixmap-format list: for a given colour depth it fixes the bits-per-pixel and the scanline padding a ZPixmap image of that depth uses on the wire. It is what turns a width into a STRIDE.
type Screen ¶
type Screen struct {
Root uint32
DefaultColmap uint32
WhitePixel uint32
BlackPixel uint32
Width uint16
Height uint16
WidthMM uint16
HeightMM uint16
RootVisual uint32
RootDepth uint8
Depths []Depth
}
Screen is one root screen: its root window, size, root visual and the allowed depths (each carrying its visuals).
func (*Screen) DepthOfVisual ¶
DepthOfVisual returns the colour depth the given visual lives at, and whether it was found.
func (*Screen) FindVisual ¶
func (sc *Screen) FindVisual(id uint32) (VisualType, bool)
FindVisual returns the VisualType with the given id on screen sc, and whether it was found.
func (*Screen) RootVisualType ¶
func (sc *Screen) RootVisualType() VisualType
RootVisualType returns the screen's root visual descriptor, falling back to a synthesized 24-bit TrueColor BGRX visual if the root visual id is somehow absent from the depth list (defensive; real servers always list it).
type Segment ¶
Segment is a mapped anonymous shared-memory region backing a MIT-SHM attachment: Data is the pixel store both peers see, FD is the descriptor handed to the X server by the extension's AttachFd request, and Seg is the resource id the server knows it by.
It is the memory, not the protocol. Which AttachFd/PutImage/GetImage requests a client sends over it is the client's business — a capture asks the server to WRITE into the segment, a window writes into it and asks the server to read — and those requests live in the consumer, not here.
The lifecycle is portable; the shared-memory syscalls themselves sit behind createAnonFile/mmapRegion/munmapRegion/closeFD, which are provided per platform. Off Linux there is no X server to attach to, so createAnonFile reports ErrNoSharedMemory and no segment is ever created.
func NewSegment ¶
NewSegment allocates and maps a shared-memory segment of size bytes and assigns it the resource id seg. The caller registers it with the server via the MIT-SHM AttachFd request and frees it with Segment.Close.
type Setup ¶
type Setup struct {
ProtoMajor uint16
ProtoMinor uint16
Release uint32
ResourceIDBase uint32
ResourceIDMask uint32
Vendor string
MaxRequestLen uint16 // in 4-byte units
ImageByteOrder uint8 // 0 = LSBFirst, 1 = MSBFirst
BitmapBitOrder uint8
BitmapUnit uint8
BitmapPad uint8
MinKeycode uint8
MaxKeycode uint8
Formats []Format
Screens []Screen
}
Setup is the parsed server connection-setup reply: everything a client needs to allocate resource IDs, pick a visual, size images correctly and map keycodes.
func Handshake ¶
func Handshake(rw io.ReadWriteCloser, order ByteOrder, authName string, authData []byte) (*Setup, error)
Handshake runs the client connection setup over rw: it sends the byte-order sentinel, protocol 11.0 and the authorization name and data, then reads and parses the server's reply. order selects the wire byte order; both are valid and the server adopts the client's choice for the whole session.
It returns only the parsed Setup. Framing requests and demultiplexing replies, errors and events is the caller's business, and the two things a client does with a connection — pump events, or push frames — want different machines over the same socket. What is common is everything up to this point, which is what this function is.
On return, rw is positioned exactly at the first byte the server sends after the setup reply, so the caller can start reading packets immediately. On error rw is left as it is: the caller closes it.
func (*Setup) FormatFor ¶
FormatFor returns the pixmap Format matching depth, and whether one exists. It is what sizes each pixel and pads each scanline of an image at that depth.
type SetupError ¶
type SetupError struct {
Reason string
Authenticate bool // the server asked for further authentication
}
SetupError is the connection-setup refusal: the server would not talk to us at all. Reason is the server's own wording, which for a missing or wrong cookie is "No protocol specified" or "Authorization required".
type VisualType ¶
type VisualType struct {
ID uint32
Class uint8
BitsPerRGB uint8
ColormapEnt uint16
RedMask uint32
GreenMask uint32
BlueMask uint32
}
VisualType describes a visual: its class and the RGB channel masks a TrueColor or DirectColor visual packs a pixel with. The masks are what convert a pixel to or from any other layout.
func (VisualType) Direct ¶
func (v VisualType) Direct() bool
Direct reports whether the visual's pixels decompose through its masks.
type Waiter ¶
type Waiter interface {
// WaitReadable reports whether the server sent anything within d. An
// implementation must not consume a partial packet: see the note on the
// unix transport for why a read deadline is not a substitute.
WaitReadable(d time.Duration) bool
}
Waiter is implemented by a transport that can say whether the server sent anything, without reading a whole packet. The transport WrapUnix returns implements it.
It exists because parts of the X11 protocol have no timeout of their own — a selection paste asks whoever owns the clipboard and waits for an event that arrives only if that owner is alive and still answering. A client that cannot bound that wait freezes.