xgb

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 5, 2022 License: BSD-3-Clause, GooglePatentClause Imports: 15 Imported by: 109

README

XGB is the X Go Binding, which is a low-level API to communicate with the
core X protocol and many of the X extensions. It is closely modeled after
XCB and xpyb.

It is thread safe and gets immediate improvement from parallelism when
GOMAXPROCS > 1. (See the benchmarks in xproto/xproto_test.go for evidence.)

Please see doc.go for more info.

Note that unless you know you need XGB, you can probably make your life
easier by using a slightly higher level library: xgbutil.

This is a fork of github.com/BurntSushi/xgb

Quick Usage
===========
go get github.com/jezek/xgb
go run go/path/src/github.com/jezek/xgb/examples/create-window/main.go

jezek's Fork
============
I've forked the XGB repository from BurntSushi's github to apply some
patches which caused panics and memory leaks upon close and tests were added,
to test multiple server close scenarios.

BurntSushi's Fork
=================
I've forked the XGB repository from Google Code due to inactivty upstream.

Godoc documentation can be found here:
https://godoc.org/github.com/BurntSushi/xgb

Much of the code has been rewritten in an effort to support thread safety
and multiple extensions. Namely, go_client.py has been thrown away in favor
of an xgbgen package.

The biggest parts that *haven't* been rewritten by me are the connection and
authentication handshakes. They're inherently messy, and there's really no
reason to re-work them. The rest of XGB has been completely rewritten.

I like to release my code under the WTFPL, but since I'm starting with someone
else's work, I'm leaving the original license/contributor/author information
in tact.

I suppose I can legitimately release xgbgen under the WTFPL. To be fair, it is
at least as complex as XGB itself. *sigh*

What follows is the original README:

XGB README
==========
XGB is the X protocol Go language Binding.

It is the Go equivalent of XCB, the X protocol C-language Binding
(http://xcb.freedesktop.org/).

Unless otherwise noted, the XGB source files are distributed
under the BSD-style license found in the LICENSE file.

Contributions should follow the same procedure as for the Go project:
http://golang.org/doc/contribute.html

Documentation

Overview

Package XGB provides the X Go Binding, which is a low-level API to communicate with the core X protocol and many of the X extensions.

It is *very* closely modeled on XCB, so that experience with XCB (or xpyb) is easily translatable to XGB. That is, it uses the same cookie/reply model and is thread safe. There are otherwise no major differences (in the API).

Most uses of XGB typically fall under the realm of window manager and GUI kit development, but other applications (like pagers, panels, tilers, etc.) may also require XGB. Moreover, it is a near certainty that if you need to work with X, xgbutil will be of great use to you as well: https://github.com/jezek/xgbutil

Example

This is an extremely terse example that demonstrates how to connect to X, create a window, listen to StructureNotify events and Key{Press,Release} events, map the window, and print out all events received. An example with accompanying documentation can be found in examples/create-window.

package main

import (
	"fmt"
	"github.com/jezek/xgb"
	"github.com/jezek/xgb/xproto"
)

func main() {
	X, err := xgb.NewConn()
	if err != nil {
		fmt.Println(err)
		return
	}

	wid, _ := xproto.NewWindowId(X)
	screen := xproto.Setup(X).DefaultScreen(X)
	xproto.CreateWindow(X, screen.RootDepth, wid, screen.Root,
		0, 0, 500, 500, 0,
		xproto.WindowClassInputOutput, screen.RootVisual,
		xproto.CwBackPixel | xproto.CwEventMask,
		[]uint32{ // values must be in the order defined by the protocol
			0xffffffff,
			xproto.EventMaskStructureNotify |
			xproto.EventMaskKeyPress |
			xproto.EventMaskKeyRelease})

	xproto.MapWindow(X, wid)
	for {
		ev, xerr := X.WaitForEvent()
		if ev == nil && xerr == nil {
			fmt.Println("Both event and error are nil. Exiting...")
			return
		}

		if ev != nil {
			fmt.Printf("Event: %s\n", ev)
		}
		if xerr != nil {
			fmt.Printf("Error: %s\n", xerr)
		}
	}
}

Xinerama Example

This is another small example that shows how to query Xinerama for geometry information of each active head. Accompanying documentation for this example can be found in examples/xinerama.

package main

import (
	"fmt"
	"log"
	"github.com/jezek/xgb"
	"github.com/jezek/xgb/xinerama"
)

func main() {
	X, err := xgb.NewConn()
	if err != nil {
		log.Fatal(err)
	}

	// Initialize the Xinerama extension.
	// The appropriate 'Init' function must be run for *every*
	// extension before any of its requests can be used.
	err = xinerama.Init(X)
	if err != nil {
		log.Fatal(err)
	}

	reply, err := xinerama.QueryScreens(X).Reply()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Number of heads: %d\n", reply.Number)
	for i, screen := range reply.ScreenInfo {
		fmt.Printf("%d :: X: %d, Y: %d, Width: %d, Height: %d\n",
			i, screen.XOrg, screen.YOrg, screen.Width, screen.Height)
	}
}

Parallelism

XGB can benefit greatly from parallelism due to its concurrent design. For evidence of this claim, please see the benchmarks in xproto/xproto_test.go.

Tests

xproto/xproto_test.go contains a number of contrived tests that stress particular corners of XGB that I presume could be problem areas. Namely: requests with no replies, requests with replies, checked errors, unchecked errors, sequence number wrapping, cookie buffer flushing (i.e., forcing a round trip every N requests made that don't have a reply), getting/setting properties and creating a window and listening to StructureNotify events.

Code Generator

Both XCB and xpyb use the same Python module (xcbgen) for a code generator. XGB (before this fork) used the same code generator as well, but in my attempt to add support for more extensions, I found the code generator extremely difficult to work with. Therefore, I re-wrote the code generator in Go. It can be found in its own sub-package, xgbgen, of xgb. My design of xgbgen includes a rough consideration that it could be used for other languages.

What works

I am reasonably confident that the core X protocol is in full working form. I've also tested the Xinerama and RandR extensions sparingly. Many of the other existing extensions have Go source generated (and are compilable) and are included in this package, but I am currently unsure of their status. They *should* work.

What does not work

XKB is the only extension that intentionally does not work, although I suspect that GLX also does not work (however, there is Go source code for GLX that compiles, unlike XKB). I don't currently have any intention of getting XKB working, due to its complexity and my current mental incapacity to test it.

Index

Constants

This section is empty.

Variables

View Source
var (
	// Where to log error-messages. Defaults to stderr.
	// To disable logging, just set this to log.New(ioutil.Discard, "", 0)
	Logger = log.New(os.Stderr, "XGB: ", log.Lshortfile)
)
View Source
var NewErrorFuncs = make(map[int]NewErrorFun)

NewErrorFuncs is a map from error numbers to functions that create the corresponding error. It should not be used. It is exported for use in the extension sub-packages.

View Source
var NewEventFuncs = make(map[int]NewEventFun)

NewEventFuncs is a map from event numbers to functions that create the corresponding event. It should not be used. It is exported for use in the extension sub-packages.

View Source
var NewExtErrorFuncs = make(map[string]map[int]NewErrorFun)

NewExtErrorFuncs is a temporary map that stores error constructor functions for each extension. When an extension is initialized, each error for that extension is added to the 'NewErrorFuncs' map. It should not be used. It is exported for use in the extension sub-packages.

View Source
var NewExtEventFuncs = make(map[string]map[int]NewEventFun)

NewExtEventFuncs is a temporary map that stores event constructor functions for each extension. When an extension is initialized, each event for that extension is added to the 'NewEventFuncs' map. It should not be used. It is exported for use in the extension sub-packages.

Functions

func Errorf

func Errorf(format string, v ...interface{}) error

Errorf is just a wrapper for fmt.Errorf. Exists for the same reason that 'stringsJoin' and 'sprintf' exists.

func Get16

func Get16(buf []byte) uint16

Get16 constructs a 16 bit integer from the beginning of a byte slice.

func Get32

func Get32(buf []byte) uint32

Get32 constructs a 32 bit integer from the beginning of a byte slice.

func Get64

func Get64(buf []byte) uint64

Get64 constructs a 64 bit integer from the beginning of a byte slice.

func Pad

func Pad(n int) int

Pad a length to align on 4 bytes.

func PopCount

func PopCount(mask0 int) int

PopCount counts the number of bits set in a value list mask.

func Put16

func Put16(buf []byte, v uint16)

Put16 takes a 16 bit integer and copies it into a byte slice.

func Put32

func Put32(buf []byte, v uint32)

Put32 takes a 32 bit integer and copies it into a byte slice.

func Put64

func Put64(buf []byte, v uint64)

Put64 takes a 64 bit integer and copies it into a byte slice.

func Sprintf

func Sprintf(format string, v ...interface{}) string

Sprintf is so we don't need to import 'fmt' in the generated Go files.

func StringsJoin

func StringsJoin(ss []string, sep string) string

StringsJoin is an alias to strings.Join. It allows us to avoid having to import 'strings' in each of the generated Go files.

Types

type Conn

type Conn struct {
	DisplayNumber int
	DefaultScreen int
	SetupBytes    []byte

	// ExtLock is a lock used whenever new extensions are initialized.
	// It should not be used. It is exported for use in the extension
	// sub-packages.
	ExtLock sync.RWMutex

	// Extensions is a map from extension name to major opcode. It should
	// not be used. It is exported for use in the extension sub-packages.
	Extensions map[string]byte
	// contains filtered or unexported fields
}

A Conn represents a connection to an X server.

func NewConn

func NewConn() (*Conn, error)

NewConn creates a new connection instance. It initializes locks, data structures, and performs the initial handshake. (The code for the handshake has been relegated to conn.go.) It is up to user to close connection with Close() method to finish all unfinished requests and clean up spawned goroutines. If the connection unexpectedly closes itself and WaitForEvent() returns "nil, nil", everything is cleaned by that moment, but nothing bad happens if you call Close() after.

func NewConnDisplay

func NewConnDisplay(display string) (*Conn, error)

NewConnDisplay is just like NewConn (see closing instructions), but allows a specific DISPLAY string to be used. If 'display' is empty it will be taken from os.Getenv("DISPLAY").

Examples:

NewConn(":1") -> net.Dial("unix", "", "/tmp/.X11-unix/X1")
NewConn("/tmp/launch-12/:0") -> net.Dial("unix", "", "/tmp/launch-12/:0")
NewConn("hostname:2.1") -> net.Dial("tcp", "", "hostname:6002")
NewConn("tcp/hostname:1.0") -> net.Dial("tcp", "", "hostname:6001")

func NewConnNet

func NewConnNet(netConn net.Conn) (*Conn, error)

NewConnNet is just like NewConn (see closing instructions), but allows a specific net.Conn to be used.

func (*Conn) Close

func (c *Conn) Close()

Close gracefully closes the connection to the X server. When everything is cleaned up, the WaitForEvent method will return (nil, nil)

func (*Conn) NewCookie

func (c *Conn) NewCookie(checked, reply bool) *Cookie

NewCookie creates a new cookie with the correct channels initialized depending upon the values of 'checked' and 'reply'. Together, there are four different kinds of cookies. (See more detailed comments in the function for more info on those.) Note that a sequence number is not set until just before the request corresponding to this cookie is sent over the wire.

Unless you're building requests from bytes by hand, this method should not be used.

func (*Conn) NewId

func (c *Conn) NewId() (uint32, error)

NewId generates a new unused ID for use with requests like CreateWindow. If no new ids can be generated, the id returned is 0 and error is non-nil. This shouldn't be used directly, and is exported for use in the extension sub-packages. If you need identifiers, use the appropriate constructor. e.g., For a window id, use xproto.NewWindowId. For a new pixmap id, use xproto.NewPixmapId. And so on. Returns (0, io.EOF) when the connection is closed.

func (*Conn) NewRequest

func (c *Conn) NewRequest(buf []byte, cookie *Cookie)

NewRequest takes the bytes and a cookie of a particular request, constructs a request type, and sends it over the Conn.reqChan channel. Note that the sequence number is added to the cookie after it is sent over the request channel, but before it is sent to X.

Note that you may safely use NewRequest to send arbitrary byte requests to X. The resulting cookie can be used just like any normal cookie and abides by the same rules, except that for replies, you'll get back the raw byte data. This may be useful for performance critical sections where every allocation counts, since all X requests in XGB allocate a new byte slice. In contrast, NewRequest allocates one small request struct and nothing else. (Except when the cookie buffer is full and has to be flushed.)

If you're using NewRequest manually, you'll need to use NewCookie to create a new cookie.

In all likelihood, you should be able to copy and paste with some minor edits the generated code for the request you want to issue.

func (*Conn) PollForEvent

func (c *Conn) PollForEvent() (Event, Error)

PollForEvent returns the next event from the server if one is available in the internal queue without blocking. Note that unlike WaitForEvent, both Event and Error could be nil. Indeed, they are both nil when the event queue is empty.

func (*Conn) Sync

func (c *Conn) Sync()

Sync sends a round trip request and waits for the response. This forces all pending cookies to be dealt with. You actually shouldn't need to use this like you might with Xlib. Namely, buffers are automatically flushed using Go's channels and round trip requests are forced where appropriate automatically.

func (*Conn) WaitForEvent

func (c *Conn) WaitForEvent() (Event, Error)

WaitForEvent returns the next event from the server. It will block until an event is available. WaitForEvent returns either an Event or an Error. (Returning both is a bug.) Note than an Error here is an X error and not an XGB error. That is, X errors are sometimes completely expected (and you may want to ignore them in some cases).

If both the event and error are nil, then the connection has been closed.

type Cookie struct {
	Sequence uint16
	// contains filtered or unexported fields
}

Cookie is the internal representation of a cookie, where one is generated for *every* request sent by XGB. 'cookie' is most frequently used by embedding it into a more specific kind of cookie, i.e., 'GetInputFocusCookie'.

func (Cookie) Check

func (c Cookie) Check() error

Check is used for checked requests that have no replies. It is a mechanism by which to report "success" or "error" in a synchronous fashion. (Therefore, unchecked requests without replies cannot use this method.) If the request causes an error, it is sent to this cookie's errorChan. If the request was successful, there is no response from the server. Thus, pingChan is sent a value when the *next* reply is read. If no more replies are being processed, we force a round trip request with GetInputFocus. Returns io.EOF error when the connection is closed.

Unless you're building requests from bytes by hand, this method should not be used.

func (Cookie) Reply

func (c Cookie) Reply() ([]byte, error)

Reply detects whether this is a checked or unchecked cookie, and calls 'replyChecked' or 'replyUnchecked' appropriately.

Unless you're building requests from bytes by hand, this method should not be used.

type Error

type Error interface {
	SequenceId() uint16
	BadId() uint32
	Error() string
}

Error is an interface that can contain any of the errors returned by the server. Use a type assertion switch to extract the Error structs.

type Event

type Event interface {
	Bytes() []byte
	String() string
}

Event is an interface that can contain any of the events returned by the server. Use a type assertion switch to extract the Event structs.

type NewErrorFun

type NewErrorFun func(buf []byte) Error

NewErrorFun is the type of function use to construct errors from raw bytes. It should not be used. It is exported for use in the extension sub-packages.

type NewEventFun

type NewEventFun func(buf []byte) Event

NewEventFun is the type of function use to construct events from raw bytes. It should not be used. It is exported for use in the extension sub-packages.

Directories

Path Synopsis
Package bigreq is the X client API for the BIG-REQUESTS extension.
Package bigreq is the X client API for the BIG-REQUESTS extension.
Package composite is the X client API for the Composite extension.
Package composite is the X client API for the Composite extension.
Package damage is the X client API for the DAMAGE extension.
Package damage is the X client API for the DAMAGE extension.
Package dpms is the X client API for the DPMS extension.
Package dpms is the X client API for the DPMS extension.
Package dri2 is the X client API for the DRI2 extension.
Package dri2 is the X client API for the DRI2 extension.
Package examples contains a few different use cases of XGB, like creating a window, reading properties, and querying for information about multiple heads using the Xinerama or RandR extensions.
Package examples contains a few different use cases of XGB, like creating a window, reading properties, and querying for information about multiple heads using the Xinerama or RandR extensions.
create-window
Example create-window shows how to create a window, map it, resize it, and listen to structure and key events (i.e., when the window is resized by the window manager, or when key presses/releases are made when the window has focus).
Example create-window shows how to create a window, map it, resize it, and listen to structure and key events (i.e., when the window is resized by the window manager, or when key presses/releases are made when the window has focus).
get-active-window
Example get-active-window reads the _NET_ACTIVE_WINDOW property of the root window and uses the result (a window id) to get the name of the window.
Example get-active-window reads the _NET_ACTIVE_WINDOW property of the root window and uses the result (a window id) to get the name of the window.
randr
Example randr uses the randr protocol to get information about the active heads.
Example randr uses the randr protocol to get information about the active heads.
shapes
The shapes example shows how to draw basic shapes into a window.
The shapes example shows how to draw basic shapes into a window.
xinerama
Example xinerama shows how to query the geometry of all active heads.
Example xinerama shows how to query the geometry of all active heads.
Package ge is the X client API for the Generic Event Extension extension.
Package ge is the X client API for the Generic Event Extension extension.
Package glx is the X client API for the GLX extension.
Package glx is the X client API for the GLX extension.
Package randr is the X client API for the RANDR extension.
Package randr is the X client API for the RANDR extension.
Package record is the X client API for the RECORD extension.
Package record is the X client API for the RECORD extension.
Package render is the X client API for the RENDER extension.
Package render is the X client API for the RENDER extension.
Package res is the X client API for the X-Resource extension.
Package res is the X client API for the X-Resource extension.
Package screensaver is the X client API for the MIT-SCREEN-SAVER extension.
Package screensaver is the X client API for the MIT-SCREEN-SAVER extension.
Package shape is the X client API for the SHAPE extension.
Package shape is the X client API for the SHAPE extension.
Package shm is the X client API for the MIT-SHM extension.
Package shm is the X client API for the MIT-SHM extension.
Package xcmisc is the X client API for the XC-MISC extension.
Package xcmisc is the X client API for the XC-MISC extension.
Package xevie is the X client API for the XEVIE extension.
Package xevie is the X client API for the XEVIE extension.
Package xf86dri is the X client API for the XFree86-DRI extension.
Package xf86dri is the X client API for the XFree86-DRI extension.
Package xf86vidmode is the X client API for the XFree86-VidModeExtension extension.
Package xf86vidmode is the X client API for the XFree86-VidModeExtension extension.
Package xfixes is the X client API for the XFIXES extension.
Package xfixes is the X client API for the XFIXES extension.
Package xinerama is the X client API for the XINERAMA extension.
Package xinerama is the X client API for the XINERAMA extension.
Package xprint is the X client API for the XpExtension extension.
Package xprint is the X client API for the XpExtension extension.
Package xproto is the X client API for the extension.
Package xproto is the X client API for the extension.
Package xselinux is the X client API for the SELinux extension.
Package xselinux is the X client API for the SELinux extension.
Package xtest is the X client API for the XTEST extension.
Package xtest is the X client API for the XTEST extension.
Package xv is the X client API for the XVideo extension.
Package xv is the X client API for the XVideo extension.
Package xvmc is the X client API for the XVideo-MotionCompensation extension.
Package xvmc is the X client API for the XVideo-MotionCompensation extension.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL