xgbutil

package module
v0.0.0-...-e2e9464 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2024 License: BSD-3-Clause Imports: 6 Imported by: 52

README

xgbutil is a utility library designed to work with the X Go Binding. This
project's main goal is to make various X related tasks easier. For example,
binding keys, using the EWMH or ICCCM specs with the window manager,
moving/resizing windows, assigning function callbacks to particular events,
drawing images to a window, etc.

xgbutil attempts to be thread safe, but it has not been completely tested in
this regard. In general, the X event loop implemented in the xevent package is
sequential. The idea is to be sequential by default, and let the user spawn
concurrent code at their discretion. (i.e., the complexity of making the main
event loop generally concurrent is vast.)

You may sleep safely at night by assuming that XGB is thread safe, though.

To start using xgbutil, you should have at least a passing familiarity with X.
Your first stop should be the examples directory.

Installation
============
go get github.com/jezek/xgbutil

Dependencies
============
XGB is the main dependency. Use of the xgraphics packages requires graphics-go
and freetype-go.

XGB project URL: https://github.com/jezek/xgb
graphics-go project URL: https://github.com/BurntSushi/graphics-go
freetype-go project URL: https://github.com/BurntSushi/freetype-go

Quick Example
=============
go get github.com/jezek/xgbutil/_examples/window-name-sizes
"$GOPATH"/bin/window-name-sizes

The output will be a list of names of all top-level windows and their geometry
including window manager decorations. (Assuming your window manager supports
some basic EWMH properties.)

Documentation
=============
https://godoc.org/github.com/jezek/xgbutil

Examples
========
There are several examples in the examples directory covering common use cases.
They are heavily documented and should run out of the box.

Python
======
An older project of mine (BurntSushi), xpybutil, served as inspiration for xgbutil. If you
want to use Python, xpybutil should help quite a bit. Please note though, that
at this point, xgbutil provides a lot more functionality and is much better
documented.

xpybutil project URL: https://github.com/BurntSushi/xpybutil

jezek's Fork
============
Why I've forked the xgbutil repository from BurntSushi's github is discussed in [issue #2](https://github.com/jezek/xgb/issues/2).
I've also changed the LICENSE to GNU GPL v3 to meet the requirements for pkg.go.dev

Documentation

Overview

Package xgbutil is a utility library designed to make common tasks with the X server easier. The central design choice that has driven development is to hide the complexity of X wherever possible but expose it when necessary.

For example, the xevent package provides an implementation of an X event loop that acts as a dispatcher to event handlers set up with the xevent, keybind and mousebind packages. At the same time, the event queue is exposed and can be modified using xevent.Peek and xevent.DequeueAt.

Sub-packages

The xgbutil package is considerably small, and only contains some type definitions and the initial setup for an X connection. Much of the functionality of xgbutil comes from its sub-packages. Each sub-package is appropriately documented.

Installation

xgbutil is go-gettable:

go get github.com/jezek/xgbutil

Dependencies

XGB is the main dependency, and is required for all packages inside xgbutil.

graphics-go and freetype-go are also required if using the xgraphics package.

Quick Example

A quick example to demonstrate that xgbutil is working correctly:

go get github.com/jezek/xgbutil/examples/window-name-sizes
GO/PATH/bin/window-name-sizes

The output will be a list of names of all top-level windows and their geometry including window manager decorations. (Assuming your window manager supports some basic EWMH properties.)

Examples

The examples directory contains a sizable number of examples demonstrating common tasks with X. They are intended to demonstrate a single thing each, although a few that require setup are necessarily long. Each example is heavily documented.

The examples directory should be your first stop when learning how to use xgbutil.

xgbutil is also used heavily throughout my (BurntSushi) window manager, Wingo. It may be useful reference material.

Wingo project page: https://github.com/BurntSushi/wingo

Thread Safety

While I am (BurntSushi) fairly confident that XGB is thread safe, I am only somewhat confident that xgbutil is thread safe. It simply has not been tested enough for my confidence to be higher.

Note that the xevent package's X event loop is not concurrent. Namely, designing a generally concurrent X event loop is extremely complex. Instead, the onus is on you, the user, to design concurrent callback functions if concurrency is desired.

Index

Constants

View Source
const MaxReqSize = (1 << 16) * 4

The current maximum request size. I think we can expand this with BigReq, but it probably isn't worth it at the moment.

Variables

View Source
var Logger = log.New(os.Stderr, "[xgbutil] ", log.Lshortfile)

Logger is used through xgbutil when messages need to be emitted to stderr.

Functions

This section is empty.

Types

type Callback

type Callback interface {
	// Connect modifies XUtil's state to attach an event handler to a
	// particular event.
	Connect(xu *XUtil, win xproto.Window)

	// Run is exported for use in the xevent package but should not be
	// used by the user. (It is used to run the callback function in the
	// main event loop.)
	Run(xu *XUtil, ev interface{})
}

Callback is an interface that should be implemented by event callback functions. Namely, to assign a function to a particular event/window combination, simply define a function with type 'SomeEventFun' (pre-defined in xevent/callback.go), and call the 'Connect' method. The 'Run' method is used inside the Main event loop, and shouldn't be used by the user. Also, it is perfectly legitimate to connect to events that don't specify a window (like MappingNotify and KeymapNotify). In this case, simply use 'xgbutil.NoWindow' as the window id.

Example to respond to ConfigureNotify events on window 0x1

xevent.ConfigureNotifyFun(
	func(X *xgbutil.XUtil, e xevent.ConfigureNotifyEvent) {
		fmt.Printf("(%d, %d) %dx%d\n", e.X, e.Y, e.Width, e.Height)
	}).Connect(X, 0x1)

type CallbackHook

type CallbackHook interface {
	// Connect connects this hook to the main loop of the passed XUtil
	// instance.
	Connect(xu *XUtil)

	// Run is exported for use in the xevent package, but should not be
	// used by the user.  It should return true if it's ok to process
	// the event as usual, or false if it should be suppressed.
	Run(xu *XUtil, ev interface{}) bool
}

CallbackHook works similarly to the more general Callback, but it is for hooks into the main xevent loop. As such it does not get attached to a window.

type CallbackKey

type CallbackKey interface {
	// Connect modifies XUtil's state to attach an event handler to a
	// particular key press. If grab is true, connect will request a passive
	// grab.
	Connect(xu *XUtil, win xproto.Window, keyStr string, grab bool) error

	// Run is exported for use in the keybind package but should not be
	// used by the user. (It is used to run the callback function in the
	// main event loop.
	Run(xu *XUtil, ev interface{})
}

CallbackKey works similarly to the more general Callback, but it adds parameters specific to key bindings.

type CallbackMouse

type CallbackMouse interface {
	// Connect modifies XUtil's state to attach an event handler to a
	// particular button press.
	// If sync is true, the grab will be synchronous. (This will require a
	// call to xproto.AllowEvents in response, otherwise no further events
	// will be processed and your program will lock.)
	// If grab is true, connect will request a passive grab.
	Connect(xu *XUtil, win xproto.Window, buttonStr string,
		sync bool, grab bool) error

	// Run is exported for use in the mousebind package but should not be
	// used by the user. (It is used to run the callback function in the
	// main event loop.)
	Run(xu *XUtil, ev interface{})
}

CallbackMouse works similarly to the more general Callback, but it adds parameters specific to mouse bindings.

type ErrorHandlerFun

type ErrorHandlerFun func(err xgb.Error)

ErrorHandlerFun is the type of function required to handle errors that come in through the main event loop. For example, to set a new error handler, use:

xevent.ErrorHandlerSet(xgbutil.ErrorHandlerFun(
	func(err xgb.Error) {
		// do something with err
	}))

type EventOrError

type EventOrError struct {
	Event xgb.Event
	Err   xgb.Error
}

EventOrError is a struct that contains either an event value or an error value. It is an error to contain both. Containing neither indicates an error too. This is exported for use in the xevent package. You shouldn't have any direct contact with values of this type, unless you need to inspect the queue directly with xevent.Peek.

type KeyKey

type KeyKey struct {
	Evtype int
	Win    xproto.Window
	Mod    uint16
	Code   xproto.Keycode
}

KeyKey is the type of the key in the map of keybindings. It essentially represents the tuple (event type, window id, modifier, keycode). It is exported for use in the keybind package. It should not be used.

type KeyString

type KeyString struct {
	Str      string
	Callback CallbackKey
	Evtype   int
	Win      xproto.Window
	Grab     bool
}

KeyString is the type of a key binding string used to connect to particular key combinations. A list of all such key strings is maintained in order to rebind keys when the keyboard mapping has been changed.

type KeyboardMapping

type KeyboardMapping struct {
	*xproto.GetKeyboardMappingReply
}

KeyboardMapping embeds a keyboard mapping reply from XGB. It should be retrieved using keybind.KeyMapGet, if necessary. xgbutil tries quite hard to absolve you from ever having to use this. A keyboard mapping is a table that maps keycodes to one or more keysyms.

type ModifierMapping

type ModifierMapping struct {
	*xproto.GetModifierMappingReply
}

ModifierMapping embeds a modifier mapping reply from XGB. It should be retrieved using keybind.ModMapGet, if necessary. xgbutil tries quite hard to absolve you from ever having to use this. A modifier mapping is a table that maps modifiers to one or more keycodes.

type MouseDragBeginFun

type MouseDragBeginFun func(xu *XUtil, rootX, rootY,
	eventX, eventY int) (bool, xproto.Cursor)

MouseDragBeginFun is the kind of function used to initialize a drag. The difference between this and MouseDragFun is that the begin function returns a bool (of whether or not to cancel the drag) and an X resource identifier corresponding to a cursor.

type MouseDragFun

type MouseDragFun func(xu *XUtil, rootX, rootY, eventX, eventY int)

MouseDragFun is the kind of function used on each dragging step and at the end of a drag.

type MouseKey

type MouseKey struct {
	Evtype int
	Win    xproto.Window
	Mod    uint16
	Button xproto.Button
}

MouseKey is the type of the key in the map of mouse bindings. It essentially represents the tuple (event type, window id, modifier, button). It is exported for use in the mousebind package. It should not be used.

type XUtil

type XUtil struct {

	// Quit can be set to true, and the main event loop will finish processing
	// the current event, and gracefully quit afterwards.
	// This is exported for use in the xevent package. Please us xevent.Quit
	// to set this value.
	Quit bool // when true, the main event loop will stop gracefully

	// Atoms is a cache of atom names to resource identifiers. This minimizes
	// round trips to the X server, since atom identifiers never change.
	// It is exported for use in the xprop package. It should not be used.
	Atoms    map[string]xproto.Atom
	AtomsLck *sync.RWMutex

	// AtomNames is a cache just like 'atoms', but in the reverse direction.
	// It is exported for use in the xprop package. It should not be used.
	AtomNames    map[xproto.Atom]string
	AtomNamesLck *sync.RWMutex

	// Evqueue is the queue that stores the results of xgb.WaitForEvent.
	// Namely, each value is either an Event *or* an Error.
	// It is exported for use in the xevent package. Do not use it.
	// If you need to interact with the event queue, please use the functions
	// available in the xevent package: Dequeue, DequeueAt, QueueEmpty
	// and QueuePeek.
	Evqueue    []EventOrError
	EvqueueLck *sync.RWMutex

	// Callbacks is a map of event numbers to a map of window identifiers
	// to callback functions.
	// This is the data structure that stores all callback functions, where
	// a callback function is always attached to a (event, window) tuple.
	// It is exported for use in the xevent package. Do not use it.
	Callbacks    map[int]map[xproto.Window][]Callback
	CallbacksLck *sync.RWMutex

	// Hooks are called by the XEvent main loop before processing the event
	// itself. These are meant for instances when it's not possible / easy
	// to use the normal Hook system. You should not modify this yourself.
	Hooks    []CallbackHook
	HooksLck *sync.RWMutex

	// Keymap corresponds to xgbutil's current conception of the keyboard
	// mapping. It is automatically kept up-to-date if xgbutil's event loop
	// is used.
	// It is exported for use in the keybind package. It should not be
	// accessed directly. Instead, use keybind.KeyMapGet.
	Keymap *KeyboardMapping

	// Modmap corresponds to xgbutil's current conception of the modifier key
	// mapping. It is automatically kept up-to-date if xgbutil's event loop
	// is used.
	// It is exported for use in the keybind package. It should not be
	// accessed directly. Instead, use keybind.ModMapGet.
	Modmap *ModifierMapping

	// KeyRedirect corresponds to a window identifier that, when set,
	// automatically receives *all* keyboard events. This is a sort-of
	// synthetic grab and is helpful in avoiding race conditions.
	// It is exported for use in the xevent and keybind packages. Do not use
	// it directly. To redirect key events, please use xevent.RedirectKeyEvents.
	KeyRedirect xproto.Window

	// Keybinds is the data structure storing all callbacks for key bindings.
	// This is extremely similar to the general notion of event callbacks,
	// but adds extra support to make handling key bindings easier. (Like
	// specifying human readable key sequences to bind to.)
	// KeyBindKey is a struct representing the 4-tuple
	// (event-type, window-id, modifiers, keycode).
	// It is exported for use in the keybind package. Do not access it directly.
	Keybinds    map[KeyKey][]CallbackKey
	KeybindsLck *sync.RWMutex

	// Keygrabs is a frequency count of the number of callbacks associated
	// with a particular KeyBindKey. This is necessary because we can only
	// grab a particular key *once*, but we may want to attach several callbacks
	// to a single keypress.
	// It is exported for use in the keybind package. Do not access it directly.
	Keygrabs map[KeyKey]int

	// Keystrings is a list of all key strings used to connect keybindings.
	// They are used to rebuild key grabs when the keyboard mapping is updated.
	// It is exported for use in the keybind package. Do not access it directly.
	Keystrings []KeyString

	// Mousebinds is the data structure storing all callbacks for mouse
	// bindings.This is extremely similar to the general notion of event
	// callbacks,but adds extra support to make handling mouse bindings easier.
	// (Like specifying human readable mouse sequences to bind to.)
	// MouseBindKey is a struct representing the 4-tuple
	// (event-type, window-id, modifiers, button).
	// It is exported for use in the mousebind package. Do not use it.
	Mousebinds    map[MouseKey][]CallbackMouse
	MousebindsLck *sync.RWMutex

	// Mousegrabs is a frequency count of the number of callbacks associated
	// with a particular MouseBindKey. This is necessary because we can only
	// grab a particular mouse button *once*, but we may want to attach
	// several callbacks to a single button press.
	// It is exported for use in the mousebind package. Do not use it.
	Mousegrabs map[MouseKey]int

	// InMouseDrag is true if a drag is currently in progress.
	// It is exported for use in the mousebind package. Do not use it.
	InMouseDrag bool

	// MouseDragStep is the function executed for each step (i.e., pointer
	// movement) in the current mouse drag. Note that this is nil when a drag
	// is not in progress.
	// It is exported for use in the mousebind package. Do not use it.
	MouseDragStepFun MouseDragFun

	// MouseDragEnd is the function executed at the end of the current
	// mouse drag. This is nil when a drag is not in progress.
	// It is exported for use in the mousebind package. Do not use it.
	MouseDragEndFun MouseDragFun

	// ErrorHandler is the function that handles errors *in the event loop*.
	// By default, it simply emits them to stderr.
	// It is exported for use in the xevent package. To set the default error
	// handler, please use xevent.ErrorHandlerSet.
	ErrorHandler ErrorHandlerFun
	// contains filtered or unexported fields
}

An XUtil represents the state of xgbutil. It keeps track of the current X connection, the root window, event callbacks, key/mouse bindings, etc. Regrettably, many of the members are exported, even though they should not be used directly by the user. They are exported for use in sub-packages. (Namely, xevent, keybind and mousebind.) In fact, there should *never* be a reason to access any members of an XUtil value directly. Any interaction with an XUtil value should be through its methods.

func NewConn

func NewConn() (*XUtil, error)

NewConn connects to the X server using the DISPLAY environment variable and creates a new XUtil. Most environments have the DISPLAY environment variable set, so this is probably what you want to use to connect to X.

func NewConnDisplay

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

NewConnDisplay connects to the X server and creates a new XUtil. If 'display' is empty, the DISPLAY environment variable is used. Otherwise there are several different display formats supported:

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 NewConnXgb

func NewConnXgb(c *xgb.Conn) (*XUtil, error)

NewConnXgb use the specific xgb.Conn to create a new XUtil.

NewConn, NewConnDisplay are wrapper of this function.

func (*XUtil) Conn

func (xu *XUtil) Conn() *xgb.Conn

Conn returns the xgb connection object.

func (*XUtil) Dummy

func (xu *XUtil) Dummy() xproto.Window

Dummy gets the id of the dummy window.

func (*XUtil) ExtInitialized

func (xu *XUtil) ExtInitialized(extName string) bool

ExtInitialized returns true if an extension has been initialized. This is useful for determining whether an extension is available or not.

func (*XUtil) GC

func (xu *XUtil) GC() xproto.Gcontext

GC gets a general purpose graphics context that is typically used to simply paint images.

func (*XUtil) Grab

func (xu *XUtil) Grab()

Grabs the server. Everything becomes synchronous.

func (*XUtil) RootWin

func (xu *XUtil) RootWin() xproto.Window

RootWin returns the current root window.

func (*XUtil) RootWinSet

func (xu *XUtil) RootWinSet(root xproto.Window)

RootWinSet will change the current root window to the one provided. N.B. This probably shouldn't be used unless you're desperately trying to support multiple X screens. (This is *not* the same as Xinerama/RandR or TwinView. All of those have a single root window.)

func (*XUtil) Screen

func (xu *XUtil) Screen() *xproto.ScreenInfo

Screen returns the default screen

func (*XUtil) Setup

func (xu *XUtil) Setup() *xproto.SetupInfo

Setup returns the setup information retrieved during connection time.

func (*XUtil) Sync

func (xu *XUtil) Sync()

Sync forces XGB to catch up with all events/requests and synchronize. This is done by issuing a benign round trip request to X.

func (*XUtil) TimeGet

func (xu *XUtil) TimeGet() xproto.Timestamp

TimeGet gets the most recent time seen by an event.

func (*XUtil) TimeSet

func (xu *XUtil) TimeSet(t xproto.Timestamp)

TimeSet sets the most recent time seen by an event.

func (*XUtil) Ungrab

func (xu *XUtil) Ungrab()

Ungrabs the server.

Directories

Path Synopsis
Package examples contains several complete examples depicting some common use cases of xgbutil.
Package examples contains several complete examples depicting some common use cases of xgbutil.
change-cursor
Example change-cursor shows how to use the cursor package to change the X cursor in a particular window.
Example change-cursor shows how to use the cursor package to change the X cursor in a particular window.
compress-events
Example compress-events shows how to manipulate the xevent package's event queue to compress events that arrive more often than you'd like to process them.
Example compress-events shows how to manipulate the xevent package's event queue to compress events that arrive more often than you'd like to process them.
draw-text
Example draw-text shows how to draw text to an xgraphics.Image type.
Example draw-text shows how to draw text to an xgraphics.Image type.
fullscreen
Example fullscreen shows how to make a window showing the Go Gopher go fullscreen and back using keybindings and EWMH.
Example fullscreen shows how to make a window showing the Go Gopher go fullscreen and back using keybindings and EWMH.
graceful-window-close
Example graceful-window-close shows how to create windows that can be closed without killing your X connection (and thereby destroying any other windows you may have open).
Example graceful-window-close shows how to create windows that can be closed without killing your X connection (and thereby destroying any other windows you may have open).
image-speed
This demonstration shows drawing entire generated images to an x window and calculating the speed of the generation and the drawing operations It should be noted that redrawing the entire image is inefficient, this demo was made to show me how fast I could draw to the windows with this method.
This demonstration shows drawing entire generated images to an x window and calculating the speed of the generation and the drawing operations It should be noted that redrawing the entire image is inefficient, this demo was made to show me how fast I could draw to the windows with this method.
keypress-english
Example keypress-english shows how to convert the State (modifiers) and Detail (keycode) members of Key{Press,Release} events to an english string representation.
Example keypress-english shows how to convert the State (modifiers) and Detail (keycode) members of Key{Press,Release} events to an english string representation.
multiple-source-event-loop
Example multiple-source-event-loop shows how to use the xevent package to combine multiple sources in your main event loop.
Example multiple-source-event-loop shows how to use the xevent package to combine multiple sources in your main event loop.
pointer-painting
Example pointer-painting shows how to draw on a window, MS Paint style.
Example pointer-painting shows how to draw on a window, MS Paint style.
screenshot
Example screenshot shows how to take a screenshot of the current desktop and show it in a window.
Example screenshot shows how to take a screenshot of the current desktop and show it in a window.
show-image
Example show-image is a very simple example to show how to use the xgraphics package to show an image in a window.
Example show-image is a very simple example to show how to use the xgraphics package to show an image in a window.
show-window-icons
Example show-window-icons shows how to get a list of all top-level client windows managed by the currently running window manager, and show the icon for each window.
Example show-window-icons shows how to get a list of all top-level client windows managed by the currently running window manager, and show the icon for each window.
simple-keybinding
Example simple-keybinding shows how to grab keys on the root window and respond to them via callback functions.
Example simple-keybinding shows how to grab keys on the root window and respond to them via callback functions.
simple-mousebinding
Example simple-mousebinding shows how to grab buttons on the root window and respond to them via callback functions.
Example simple-mousebinding shows how to grab buttons on the root window and respond to them via callback functions.
window-gradient
Example window-gradient demonstrates how to create several windows and draw gradients as their background.
Example window-gradient demonstrates how to create several windows and draw gradients as their background.
window-name-sizes
Example window-names fetches a list of all top-level client windows managed by the currently running window manager, and prints the name and size of each window.
Example window-names fetches a list of all top-level client windows managed by the currently running window manager, and prints the name and size of each window.
workarea-struts
Example workarea-struts shows how to find the all of the struts set by top-level clients and apply them to each active monitor to get the true workarea for each monitor.
Example workarea-struts shows how to find the all of the struts set by top-level clients and apply them to each active monitor to get the true workarea for each monitor.
xmodmap
Example xmodmap shows how one might implement a rudimentary version of xmodmap's modifier listing.
Example xmodmap shows how one might implement a rudimentary version of xmodmap's modifier listing.
Package ewmh provides a comprehensive API to get and set properties specified by the EWMH spec, as well as perform actions specified by the EWMH spec.
Package ewmh provides a comprehensive API to get and set properties specified by the EWMH spec, as well as perform actions specified by the EWMH spec.
Package gopher contains a single image of the Go gopher.
Package gopher contains a single image of the Go gopher.
Package icccm provides an API for a portion of the ICCCM, namely, getters and setters for many of the properties specified in the ICCCM.
Package icccm provides an API for a portion of the ICCCM, namely, getters and setters for many of the properties specified in the ICCCM.
Package keybind provides an easy to use interface to assign callback functions to human readable key sequences.
Package keybind provides an easy to use interface to assign callback functions to human readable key sequences.
Package motif has a few functions to allow easy access to Motif related properties.
Package motif has a few functions to allow easy access to Motif related properties.
Package mousebind provides an easy to use interface to assign callback functions to human readable button sequences.
Package mousebind provides an easy to use interface to assign callback functions to human readable button sequences.
Package xcursor provides a small interface for using cursors that are predefined in the X 'cursor' font.
Package xcursor provides a small interface for using cursors that are predefined in the X 'cursor' font.
Package xevent provides an event handler interface for attaching callback functions to X events, and an implementation of an X event loop.
Package xevent provides an event handler interface for attaching callback functions to X events, and an implementation of an X event loop.
Package xgraphics defines an X image type and provides convenience functions for reading and writing X pixmaps and bitmaps.
Package xgraphics defines an X image type and provides convenience functions for reading and writing X pixmaps and bitmaps.
Package xinerama provides a convenience function to retrieve the geometry of all active heads sorted in order from left to right and then top to bottom.
Package xinerama provides a convenience function to retrieve the geometry of all active heads sorted in order from left to right and then top to bottom.
Package xprop provides a cache for interning atoms and helper functions for dealing with GetProperty and ChangeProperty X requests.
Package xprop provides a cache for interning atoms and helper functions for dealing with GetProperty and ChangeProperty X requests.
Package xrect defines a Rect interface and an XRect type implementing the Rect interface for working with X rectangles.
Package xrect defines a Rect interface and an XRect type implementing the Rect interface for working with X rectangles.
Package xwindow defines a window type that provides easy access to common window operations while hiding many of the more obscure X parameters.
Package xwindow defines a window type that provides easy access to common window operations while hiding many of the more obscure X parameters.

Jump to

Keyboard shortcuts

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