Initial commit
This commit is contained in:
6
vendor/github.com/BurntSushi/xgbutil/.gitignore
generated
vendored
Normal file
6
vendor/github.com/BurntSushi/xgbutil/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
*.swp
|
||||
*.png
|
||||
tst_first
|
||||
tst_graphics
|
||||
TAGS
|
||||
|
||||
13
vendor/github.com/BurntSushi/xgbutil/COPYING
generated
vendored
Normal file
13
vendor/github.com/BurntSushi/xgbutil/COPYING
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
36
vendor/github.com/BurntSushi/xgbutil/Makefile
generated
vendored
Normal file
36
vendor/github.com/BurntSushi/xgbutil/Makefile
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
all: callback.go types_auto.go gofmt
|
||||
|
||||
install:
|
||||
go install -p 6 . ./ewmh ./gopher ./icccm ./keybind ./motif ./mousebind \
|
||||
./xcursor ./xevent ./xgraphics ./xinerama ./xprop ./xrect ./xwindow
|
||||
|
||||
push:
|
||||
git push origin master
|
||||
git push github master
|
||||
|
||||
build-ex:
|
||||
find ./_examples/ -type d -wholename './_examples/[a-z]*' -print0 \
|
||||
| xargs -0 go build -p 6
|
||||
|
||||
gofmt:
|
||||
gofmt -w *.go */*.go _examples/*/*.go
|
||||
colcheck *.go */*.go _examples/*/*.go
|
||||
|
||||
callback.go:
|
||||
scripts/write-events callbacks > xevent/callback.go
|
||||
|
||||
types_auto.go:
|
||||
scripts/write-events evtypes > xevent/types_auto.go
|
||||
|
||||
tags:
|
||||
find ./ \( -name '*.go' -and -not -wholename './tests/*' -and -not -wholename './_examples/*' \) -print0 | xargs -0 gotags > TAGS
|
||||
|
||||
loc:
|
||||
find ./ -name '*.go' -and -not -wholename './tests*' -and -not -name '*keysymdef.go' -and -not -name '*gopher.go' -print | sort | xargs wc -l
|
||||
|
||||
ex-%:
|
||||
go run _examples/$*/main.go
|
||||
|
||||
gopherimg:
|
||||
go-bindata -f GopherPng -p gopher -i gopher/gophercolor-small.png -o gopher/gopher.go
|
||||
|
||||
55
vendor/github.com/BurntSushi/xgbutil/README
generated
vendored
Normal file
55
vendor/github.com/BurntSushi/xgbutil/README
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
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/BurntSushi/xgbutil
|
||||
|
||||
Dependencies
|
||||
============
|
||||
XGB is the main dependency. Use of the xgraphics packages requires graphics-go
|
||||
and freetype-go.
|
||||
|
||||
XGB project URL: https://github.com/BurntSushi/xgb
|
||||
|
||||
Quick Example
|
||||
=============
|
||||
go get github.com/BurntSushi/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/BurntSushi/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, 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
|
||||
|
||||
29
vendor/github.com/BurntSushi/xgbutil/STYLE
generated
vendored
Normal file
29
vendor/github.com/BurntSushi/xgbutil/STYLE
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
I like to keep all my code to 80 columns or less. I have plenty of screen real
|
||||
estate, but enjoy 80 columns so that I can have multiple code windows open side
|
||||
to side and not be plagued by the ugly auto-wrapping of a text editor.
|
||||
|
||||
If you don't oblige me, I will fix any patch you submit to abide 80 columns.
|
||||
|
||||
Note that this style restriction does not preclude gofmt, but introduces a few
|
||||
peculiarities. The first is that gofmt will occasionally add spacing (typically
|
||||
to comments) that ends up going over 80 columns. Either shorten the comment or
|
||||
put it on its own line.
|
||||
|
||||
The second and more common hiccup is when a function definition extends beyond
|
||||
80 columns. If one adds line breaks to keep it below 80 columns, gofmt will
|
||||
indent all subsequent lines in a function definition to the same indentation
|
||||
level of the function body. This results in a less-than-ideal separation
|
||||
between function definition and function body. To remedy this, simply add a
|
||||
line break like so:
|
||||
|
||||
func RestackWindowExtra(xu *xgbutil.XUtil, win xproto.Window, stackMode int,
|
||||
sibling xproto.Window, source int) error {
|
||||
|
||||
return ClientEvent(xu, win, "_NET_RESTACK_WINDOW", source, int(sibling),
|
||||
stackMode)
|
||||
}
|
||||
|
||||
Something similar should also be applied to long 'if' or 'for' conditionals,
|
||||
although it would probably be preferrable to break up the conditional to
|
||||
smaller chunks with a few helper variables.
|
||||
|
||||
67
vendor/github.com/BurntSushi/xgbutil/doc.go
generated
vendored
Normal file
67
vendor/github.com/BurntSushi/xgbutil/doc.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
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/BurntSushi/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/BurntSushi/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 window manager, Wingo. It may be
|
||||
useful reference material.
|
||||
|
||||
Wingo project page: https://github.com/BurntSushi/wingo
|
||||
|
||||
Thread Safety
|
||||
|
||||
While I am 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.
|
||||
*/
|
||||
package xgbutil
|
||||
1
vendor/github.com/BurntSushi/xgbutil/session.vim
generated
vendored
Normal file
1
vendor/github.com/BurntSushi/xgbutil/session.vim
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
au BufWritePost *.go silent!make tags > /dev/null 2>&1
|
||||
167
vendor/github.com/BurntSushi/xgbutil/types.go
generated
vendored
Normal file
167
vendor/github.com/BurntSushi/xgbutil/types.go
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
package xgbutil
|
||||
|
||||
/*
|
||||
types.go contains several types used in the XUtil structure. In an ideal world,
|
||||
they would be defined in their appropriate packages, but must be defined here
|
||||
(and exported) for use in some sub-packages. (Namely, xevent, keybind and
|
||||
mousebind.)
|
||||
*/
|
||||
|
||||
import (
|
||||
"github.com/BurntSushi/xgb"
|
||||
"github.com/BurntSushi/xgb/xproto"
|
||||
)
|
||||
|
||||
// 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 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{})
|
||||
}
|
||||
|
||||
// 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 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
|
||||
}
|
||||
|
||||
// CallbackKey works similarly to the more general Callback, but it adds
|
||||
// parameters specific to key bindings.
|
||||
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{})
|
||||
}
|
||||
|
||||
// CallbackMouse works similarly to the more general Callback, but it adds
|
||||
// parameters specific to mouse bindings.
|
||||
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{})
|
||||
}
|
||||
|
||||
// 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 KeyKey struct {
|
||||
Evtype int
|
||||
Win xproto.Window
|
||||
Mod uint16
|
||||
Code xproto.Keycode
|
||||
}
|
||||
|
||||
// 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 KeyString struct {
|
||||
Str string
|
||||
Callback CallbackKey
|
||||
Evtype int
|
||||
Win xproto.Window
|
||||
Grab bool
|
||||
}
|
||||
|
||||
// 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 MouseKey struct {
|
||||
Evtype int
|
||||
Win xproto.Window
|
||||
Mod uint16
|
||||
Button xproto.Button
|
||||
}
|
||||
|
||||
// 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 KeyboardMapping struct {
|
||||
*xproto.GetKeyboardMappingReply
|
||||
}
|
||||
|
||||
// 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 ModifierMapping struct {
|
||||
*xproto.GetModifierMappingReply
|
||||
}
|
||||
|
||||
// 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 ErrorHandlerFun func(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 EventOrError struct {
|
||||
Event xgb.Event
|
||||
Err xgb.Error
|
||||
}
|
||||
|
||||
// MouseDragFun is the kind of function used on each dragging step
|
||||
// and at the end of a drag.
|
||||
type MouseDragFun func(xu *XUtil, rootX, rootY, eventX, eventY int)
|
||||
|
||||
// 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 MouseDragBeginFun func(xu *XUtil, rootX, rootY,
|
||||
eventX, eventY int) (bool, xproto.Cursor)
|
||||
348
vendor/github.com/BurntSushi/xgbutil/xgbutil.go
generated
vendored
Normal file
348
vendor/github.com/BurntSushi/xgbutil/xgbutil.go
generated
vendored
Normal file
@@ -0,0 +1,348 @@
|
||||
package xgbutil
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/BurntSushi/xgb"
|
||||
"github.com/BurntSushi/xgb/xinerama"
|
||||
"github.com/BurntSushi/xgb/xproto"
|
||||
)
|
||||
|
||||
// Logger is used through xgbutil when messages need to be emitted to stderr.
|
||||
var Logger = log.New(os.Stderr, "[xgbutil] ", log.Lshortfile)
|
||||
|
||||
// The current maximum request size. I think we can expand this with
|
||||
// BigReq, but it probably isn't worth it at the moment.
|
||||
const MaxReqSize = (1 << 16) * 4
|
||||
|
||||
// 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.
|
||||
type XUtil struct {
|
||||
// conn is the XGB connection object used to issue protocol requests.
|
||||
conn *xgb.Conn
|
||||
|
||||
// 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
|
||||
|
||||
// setup contains all the setup information retrieved at connection time.
|
||||
setup *xproto.SetupInfo
|
||||
|
||||
// screen is a simple alias to the default screen info.
|
||||
screen *xproto.ScreenInfo
|
||||
|
||||
// root is an alias to the default root window.
|
||||
root xproto.Window
|
||||
|
||||
// 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
|
||||
|
||||
// eventTime is the last time recorded by an event. It is automatically
|
||||
// updated if xgbutil's main event loop is used.
|
||||
eventTime xproto.Timestamp
|
||||
|
||||
// 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
|
||||
|
||||
// gc is a general purpose graphics context; used to paint images.
|
||||
// Since we don't do any real X drawing, we don't really care about the
|
||||
// particulars of our graphics context.
|
||||
gc xproto.Gcontext
|
||||
|
||||
// dummy is a dummy window used for mouse/key GRABs.
|
||||
// Basically, whenever a grab is instituted, mouse and key events are
|
||||
// redirected to the dummy the window.
|
||||
dummy xproto.Window
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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 NewConn() (*XUtil, error) {
|
||||
return NewConnDisplay("")
|
||||
}
|
||||
|
||||
// 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 NewConnDisplay(display string) (*XUtil, error) {
|
||||
c, err := xgb.NewConnDisplay(display)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewConnXgb(c)
|
||||
|
||||
}
|
||||
|
||||
// NewConnXgb use the specific xgb.Conn to create a new XUtil.
|
||||
//
|
||||
// NewConn, NewConnDisplay are wrapper of this function.
|
||||
func NewConnXgb(c *xgb.Conn) (*XUtil, error) {
|
||||
setup := xproto.Setup(c)
|
||||
screen := setup.DefaultScreen(c)
|
||||
|
||||
// Initialize our central struct that stores everything.
|
||||
xu := &XUtil{
|
||||
conn: c,
|
||||
Quit: false,
|
||||
Evqueue: make([]EventOrError, 0, 1000),
|
||||
EvqueueLck: &sync.RWMutex{},
|
||||
setup: setup,
|
||||
screen: screen,
|
||||
root: screen.Root,
|
||||
eventTime: xproto.Timestamp(0), // last event time
|
||||
Atoms: make(map[string]xproto.Atom, 50),
|
||||
AtomsLck: &sync.RWMutex{},
|
||||
AtomNames: make(map[xproto.Atom]string, 50),
|
||||
AtomNamesLck: &sync.RWMutex{},
|
||||
Callbacks: make(map[int]map[xproto.Window][]Callback, 33),
|
||||
CallbacksLck: &sync.RWMutex{},
|
||||
Hooks: make([]CallbackHook, 0),
|
||||
HooksLck: &sync.RWMutex{},
|
||||
Keymap: nil, // we don't have anything yet
|
||||
Modmap: nil,
|
||||
KeyRedirect: 0,
|
||||
Keybinds: make(map[KeyKey][]CallbackKey, 10),
|
||||
KeybindsLck: &sync.RWMutex{},
|
||||
Keygrabs: make(map[KeyKey]int, 10),
|
||||
Keystrings: make([]KeyString, 0, 10),
|
||||
Mousebinds: make(map[MouseKey][]CallbackMouse, 10),
|
||||
MousebindsLck: &sync.RWMutex{},
|
||||
Mousegrabs: make(map[MouseKey]int, 10),
|
||||
InMouseDrag: false,
|
||||
MouseDragStepFun: nil,
|
||||
MouseDragEndFun: nil,
|
||||
ErrorHandler: func(err xgb.Error) { Logger.Println(err) },
|
||||
}
|
||||
|
||||
var err error = nil
|
||||
// Create a general purpose graphics context
|
||||
xu.gc, err = xproto.NewGcontextId(xu.conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
xproto.CreateGC(xu.conn, xu.gc, xproto.Drawable(xu.root),
|
||||
xproto.GcForeground, []uint32{xu.screen.WhitePixel})
|
||||
|
||||
// Create a dummy window
|
||||
xu.dummy, err = xproto.NewWindowId(xu.conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
xproto.CreateWindow(xu.conn, xu.Screen().RootDepth, xu.dummy, xu.RootWin(),
|
||||
-1000, -1000, 1, 1, 0,
|
||||
xproto.WindowClassInputOutput, xu.Screen().RootVisual,
|
||||
xproto.CwEventMask|xproto.CwOverrideRedirect,
|
||||
[]uint32{1, xproto.EventMaskPropertyChange})
|
||||
xproto.MapWindow(xu.conn, xu.dummy)
|
||||
|
||||
// Register the Xinerama extension... because it doesn't cost much.
|
||||
err = xinerama.Init(xu.conn)
|
||||
|
||||
// If we can't register Xinerama, that's okay. Output something
|
||||
// and move on.
|
||||
if err != nil {
|
||||
Logger.Printf("WARNING: %s\n", err)
|
||||
Logger.Printf("MESSAGE: The 'xinerama' package cannot be used " +
|
||||
"because the XINERAMA extension could not be loaded.")
|
||||
}
|
||||
|
||||
return xu, nil
|
||||
}
|
||||
|
||||
// Conn returns the xgb connection object.
|
||||
func (xu *XUtil) Conn() *xgb.Conn {
|
||||
return xu.conn
|
||||
}
|
||||
|
||||
// ExtInitialized returns true if an extension has been initialized.
|
||||
// This is useful for determining whether an extension is available or not.
|
||||
func (xu *XUtil) ExtInitialized(extName string) bool {
|
||||
_, ok := xu.Conn().Extensions[extName]
|
||||
return ok
|
||||
}
|
||||
|
||||
// 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 (xu *XUtil) Sync() {
|
||||
xproto.GetInputFocus(xu.Conn()).Reply()
|
||||
}
|
||||
|
||||
// Setup returns the setup information retrieved during connection time.
|
||||
func (xu *XUtil) Setup() *xproto.SetupInfo {
|
||||
return xu.setup
|
||||
}
|
||||
|
||||
// Screen returns the default screen
|
||||
func (xu *XUtil) Screen() *xproto.ScreenInfo {
|
||||
return xu.screen
|
||||
}
|
||||
|
||||
// RootWin returns the current root window.
|
||||
func (xu *XUtil) RootWin() xproto.Window {
|
||||
return xu.root
|
||||
}
|
||||
|
||||
// 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 (xu *XUtil) RootWinSet(root xproto.Window) {
|
||||
xu.root = root
|
||||
}
|
||||
|
||||
// TimeGet gets the most recent time seen by an event.
|
||||
func (xu *XUtil) TimeGet() xproto.Timestamp {
|
||||
return xu.eventTime
|
||||
}
|
||||
|
||||
// TimeSet sets the most recent time seen by an event.
|
||||
func (xu *XUtil) TimeSet(t xproto.Timestamp) {
|
||||
xu.eventTime = t
|
||||
}
|
||||
|
||||
// GC gets a general purpose graphics context that is typically used to simply
|
||||
// paint images.
|
||||
func (xu *XUtil) GC() xproto.Gcontext {
|
||||
return xu.gc
|
||||
}
|
||||
|
||||
// Dummy gets the id of the dummy window.
|
||||
func (xu *XUtil) Dummy() xproto.Window {
|
||||
return xu.dummy
|
||||
}
|
||||
|
||||
// Grabs the server. Everything becomes synchronous.
|
||||
func (xu *XUtil) Grab() {
|
||||
xproto.GrabServer(xu.Conn())
|
||||
}
|
||||
|
||||
// Ungrabs the server.
|
||||
func (xu *XUtil) Ungrab() {
|
||||
xproto.UngrabServer(xu.Conn())
|
||||
}
|
||||
103
vendor/github.com/BurntSushi/xgbutil/xprop/atom.go
generated
vendored
Normal file
103
vendor/github.com/BurntSushi/xgbutil/xprop/atom.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
package xprop
|
||||
|
||||
/*
|
||||
xprop/atom.go contains functions related to interning atoms and retrieving
|
||||
atom names from an atom identifier.
|
||||
|
||||
It also manages an atom cache so that once an atom is interned from the X
|
||||
server, all future atom interns use that value. (So that one and only one
|
||||
request is sent for interning each atom.)
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/BurntSushi/xgb/xproto"
|
||||
|
||||
"github.com/BurntSushi/xgbutil"
|
||||
)
|
||||
|
||||
// Atm is a short alias for Atom in the common case of interning an atom.
|
||||
// Namely, interning the atom always succeeds. (If the atom does not already
|
||||
// exist, a new one is created.)
|
||||
func Atm(xu *xgbutil.XUtil, name string) (xproto.Atom, error) {
|
||||
aid, err := Atom(xu, name, false)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if aid == 0 {
|
||||
return 0, fmt.Errorf("Atm: '%s' returned an identifier of 0.", name)
|
||||
}
|
||||
|
||||
return aid, err
|
||||
}
|
||||
|
||||
// Atom interns an atom and panics if there is any error.
|
||||
func Atom(xu *xgbutil.XUtil, name string,
|
||||
onlyIfExists bool) (xproto.Atom, error) {
|
||||
|
||||
// Check the cache first
|
||||
if aid, ok := atomGet(xu, name); ok {
|
||||
return aid, nil
|
||||
}
|
||||
|
||||
reply, err := xproto.InternAtom(xu.Conn(), onlyIfExists,
|
||||
uint16(len(name)), name).Reply()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("Atom: Error interning atom '%s': %s", name, err)
|
||||
}
|
||||
|
||||
// If we're here, it means we didn't have this atom cached. So cache it!
|
||||
cacheAtom(xu, name, reply.Atom)
|
||||
|
||||
return reply.Atom, nil
|
||||
}
|
||||
|
||||
// AtomName fetches a string representation of an ATOM given its integer id.
|
||||
func AtomName(xu *xgbutil.XUtil, aid xproto.Atom) (string, error) {
|
||||
// Check the cache first
|
||||
if atomName, ok := atomNameGet(xu, aid); ok {
|
||||
return string(atomName), nil
|
||||
}
|
||||
|
||||
reply, err := xproto.GetAtomName(xu.Conn(), aid).Reply()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("AtomName: Error fetching name for ATOM "+
|
||||
"id '%d': %s", aid, err)
|
||||
}
|
||||
|
||||
// If we're here, it means we didn't have ths ATOM id cached. So cache it.
|
||||
atomName := string(reply.Name)
|
||||
cacheAtom(xu, atomName, aid)
|
||||
|
||||
return atomName, nil
|
||||
}
|
||||
|
||||
// atomGet retrieves an atom identifier from a cache if it exists.
|
||||
func atomGet(xu *xgbutil.XUtil, name string) (xproto.Atom, bool) {
|
||||
xu.AtomsLck.RLock()
|
||||
defer xu.AtomsLck.RUnlock()
|
||||
|
||||
aid, ok := xu.Atoms[name]
|
||||
return aid, ok
|
||||
}
|
||||
|
||||
// atomNameGet retrieves an atom name from a cache if it exists.
|
||||
func atomNameGet(xu *xgbutil.XUtil, aid xproto.Atom) (string, bool) {
|
||||
xu.AtomNamesLck.RLock()
|
||||
defer xu.AtomNamesLck.RUnlock()
|
||||
|
||||
name, ok := xu.AtomNames[aid]
|
||||
return name, ok
|
||||
}
|
||||
|
||||
// cacheAtom puts an atom into the cache.
|
||||
func cacheAtom(xu *xgbutil.XUtil, name string, aid xproto.Atom) {
|
||||
xu.AtomsLck.Lock()
|
||||
xu.AtomNamesLck.Lock()
|
||||
defer xu.AtomsLck.Unlock()
|
||||
defer xu.AtomNamesLck.Unlock()
|
||||
|
||||
xu.Atoms[name] = aid
|
||||
xu.AtomNames[aid] = name
|
||||
}
|
||||
40
vendor/github.com/BurntSushi/xgbutil/xprop/doc.go
generated
vendored
Normal file
40
vendor/github.com/BurntSushi/xgbutil/xprop/doc.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Package xprop provides a cache for interning atoms and helper functions for
|
||||
dealing with GetProperty and ChangeProperty X requests.
|
||||
|
||||
Atoms
|
||||
|
||||
Atoms in X are interned, meaning that strings are assigned unique integer
|
||||
identifiers. This minimizes the amount of data transmitted over an X connection.
|
||||
|
||||
Once atoms have been interned, they are never changed while the X server is
|
||||
running. xgbutil takes advantage of this invariant and will only issue an
|
||||
intern atom request once and cache the result.
|
||||
|
||||
To use the xprop package to intern an atom, use Atom:
|
||||
|
||||
atom, err := xprop.Atom(XUtilValue, "THE_ATOM_NAME", false)
|
||||
if err == nil {
|
||||
println("The atom number: ", atom.Atom)
|
||||
}
|
||||
|
||||
The 'false' parameter corresponds to the 'only_if_exists' parameter of the
|
||||
X InternAtom request. When it's false, the atom being interned always returns
|
||||
a non-zero atom number---even if the string being interned hasn't been interned
|
||||
before. If 'only_if_exists' is true, the atom being interned will return a 0
|
||||
atom number if it hasn't already been interned.
|
||||
|
||||
The typical case is to set 'only_if_exists' to false. To this end, xprop.Atm is
|
||||
an alias that always sets this value to false.
|
||||
|
||||
The reverse can also be done: getting an atom string if you have an atom
|
||||
number. This can be done with the xprop.AtomName function.
|
||||
|
||||
Properties
|
||||
|
||||
The other facility of xprop is to help with the use of GetProperty and
|
||||
ChangeProperty. Please see the source code of the ewmh package for plenty of
|
||||
examples.
|
||||
|
||||
*/
|
||||
package xprop
|
||||
270
vendor/github.com/BurntSushi/xgbutil/xprop/xprop.go
generated
vendored
Normal file
270
vendor/github.com/BurntSushi/xgbutil/xprop/xprop.go
generated
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
package xprop
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/BurntSushi/xgb"
|
||||
"github.com/BurntSushi/xgb/xproto"
|
||||
|
||||
"github.com/BurntSushi/xgbutil"
|
||||
)
|
||||
|
||||
// GetProperty abstracts the messiness of calling xgb.GetProperty.
|
||||
func GetProperty(xu *xgbutil.XUtil, win xproto.Window, atom string) (
|
||||
*xproto.GetPropertyReply, error) {
|
||||
|
||||
atomId, err := Atm(xu, atom)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reply, err := xproto.GetProperty(xu.Conn(), false, win, atomId,
|
||||
xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetProperty: Error retrieving property '%s' "+
|
||||
"on window %x: %s", atom, win, err)
|
||||
}
|
||||
|
||||
if reply.Format == 0 {
|
||||
return nil, fmt.Errorf("GetProperty: No such property '%s' on "+
|
||||
"window %x.", atom, win)
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
|
||||
// ChangeProperty abstracts the semi-nastiness of xgb.ChangeProperty.
|
||||
func ChangeProp(xu *xgbutil.XUtil, win xproto.Window, format byte, prop string,
|
||||
typ string, data []byte) error {
|
||||
|
||||
propAtom, err := Atm(xu, prop)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
typAtom, err := Atm(xu, typ)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return xproto.ChangePropertyChecked(xu.Conn(), xproto.PropModeReplace, win,
|
||||
propAtom, typAtom, format,
|
||||
uint32(len(data)/(int(format)/8)), data).Check()
|
||||
}
|
||||
|
||||
// ChangeProperty32 makes changing 32 bit formatted properties easier
|
||||
// by constructing the raw X data for you.
|
||||
func ChangeProp32(xu *xgbutil.XUtil, win xproto.Window, prop string, typ string,
|
||||
data ...uint) error {
|
||||
|
||||
buf := make([]byte, len(data)*4)
|
||||
for i, datum := range data {
|
||||
xgb.Put32(buf[(i*4):], uint32(datum))
|
||||
}
|
||||
|
||||
return ChangeProp(xu, win, 32, prop, typ, buf)
|
||||
}
|
||||
|
||||
// WindowToUint is a covenience function for converting []xproto.Window
|
||||
// to []uint.
|
||||
func WindowToInt(ids []xproto.Window) []uint {
|
||||
ids32 := make([]uint, len(ids))
|
||||
for i, v := range ids {
|
||||
ids32[i] = uint(v)
|
||||
}
|
||||
return ids32
|
||||
}
|
||||
|
||||
// AtomToInt is a covenience function for converting []xproto.Atom
|
||||
// to []uint.
|
||||
func AtomToUint(ids []xproto.Atom) []uint {
|
||||
ids32 := make([]uint, len(ids))
|
||||
for i, v := range ids {
|
||||
ids32[i] = uint(v)
|
||||
}
|
||||
return ids32
|
||||
}
|
||||
|
||||
// StrToAtoms is a convenience function for converting
|
||||
// []string to []uint32 atoms.
|
||||
// NOTE: If an atom name in the list doesn't exist, it will be created.
|
||||
func StrToAtoms(xu *xgbutil.XUtil, atomNames []string) ([]uint, error) {
|
||||
var err error
|
||||
atoms := make([]uint, len(atomNames))
|
||||
for i, atomName := range atomNames {
|
||||
a, err := Atom(xu, atomName, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
atoms[i] = uint(a)
|
||||
}
|
||||
return atoms, err
|
||||
}
|
||||
|
||||
// PropValAtom transforms a GetPropertyReply struct into an ATOM name.
|
||||
// The property reply must be in 32 bit format.
|
||||
func PropValAtom(xu *xgbutil.XUtil, reply *xproto.GetPropertyReply,
|
||||
err error) (string, error) {
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if reply.Format != 32 {
|
||||
return "", fmt.Errorf("PropValAtom: Expected format 32 but got %d",
|
||||
reply.Format)
|
||||
}
|
||||
|
||||
return AtomName(xu, xproto.Atom(xgb.Get32(reply.Value)))
|
||||
}
|
||||
|
||||
// PropValAtoms is the same as PropValAtom, except that it returns a slice
|
||||
// of atom names. Also must be 32 bit format.
|
||||
// This is a method of an XUtil struct, unlike the other 'PropVal...' functions.
|
||||
func PropValAtoms(xu *xgbutil.XUtil, reply *xproto.GetPropertyReply,
|
||||
err error) ([]string, error) {
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if reply.Format != 32 {
|
||||
return nil, fmt.Errorf("PropValAtoms: Expected format 32 but got %d",
|
||||
reply.Format)
|
||||
}
|
||||
|
||||
ids := make([]string, reply.ValueLen)
|
||||
vals := reply.Value
|
||||
for i := 0; len(vals) >= 4; i++ {
|
||||
ids[i], err = AtomName(xu, xproto.Atom(xgb.Get32(vals)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vals = vals[4:]
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// PropValWindow transforms a GetPropertyReply struct into an X resource
|
||||
// window identifier.
|
||||
// The property reply must be in 32 bit format.
|
||||
func PropValWindow(reply *xproto.GetPropertyReply,
|
||||
err error) (xproto.Window, error) {
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if reply.Format != 32 {
|
||||
return 0, fmt.Errorf("PropValId: Expected format 32 but got %d",
|
||||
reply.Format)
|
||||
}
|
||||
return xproto.Window(xgb.Get32(reply.Value)), nil
|
||||
}
|
||||
|
||||
// PropValWindows is the same as PropValWindow, except that it returns a slice
|
||||
// of identifiers. Also must be 32 bit format.
|
||||
func PropValWindows(reply *xproto.GetPropertyReply,
|
||||
err error) ([]xproto.Window, error) {
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if reply.Format != 32 {
|
||||
return nil, fmt.Errorf("PropValIds: Expected format 32 but got %d",
|
||||
reply.Format)
|
||||
}
|
||||
|
||||
ids := make([]xproto.Window, reply.ValueLen)
|
||||
vals := reply.Value
|
||||
for i := 0; len(vals) >= 4; i++ {
|
||||
ids[i] = xproto.Window(xgb.Get32(vals))
|
||||
vals = vals[4:]
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// PropValNum transforms a GetPropertyReply struct into an unsigned
|
||||
// integer. Useful when the property value is a single integer.
|
||||
func PropValNum(reply *xproto.GetPropertyReply, err error) (uint, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if reply.Format != 32 {
|
||||
return 0, fmt.Errorf("PropValNum: Expected format 32 but got %d",
|
||||
reply.Format)
|
||||
}
|
||||
return uint(xgb.Get32(reply.Value)), nil
|
||||
}
|
||||
|
||||
// PropValNums is the same as PropValNum, except that it returns a slice
|
||||
// of integers. Also must be 32 bit format.
|
||||
func PropValNums(reply *xproto.GetPropertyReply, err error) ([]uint, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if reply.Format != 32 {
|
||||
return nil, fmt.Errorf("PropValIds: Expected format 32 but got %d",
|
||||
reply.Format)
|
||||
}
|
||||
|
||||
nums := make([]uint, reply.ValueLen)
|
||||
vals := reply.Value
|
||||
for i := 0; len(vals) >= 4; i++ {
|
||||
nums[i] = uint(xgb.Get32(vals))
|
||||
vals = vals[4:]
|
||||
}
|
||||
return nums, nil
|
||||
}
|
||||
|
||||
// PropValNum64 transforms a GetPropertyReply struct into a 64 bit
|
||||
// integer. Useful when the property value is a single integer.
|
||||
func PropValNum64(reply *xproto.GetPropertyReply, err error) (int64, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if reply.Format != 32 {
|
||||
return 0, fmt.Errorf("PropValNum: Expected format 32 but got %d",
|
||||
reply.Format)
|
||||
}
|
||||
return int64(xgb.Get32(reply.Value)), nil
|
||||
}
|
||||
|
||||
// PropValStr transforms a GetPropertyReply struct into a string.
|
||||
// Useful when the property value is a null terminated string represented
|
||||
// by integers. Also must be 8 bit format.
|
||||
func PropValStr(reply *xproto.GetPropertyReply, err error) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if reply.Format != 8 {
|
||||
return "", fmt.Errorf("PropValStr: Expected format 8 but got %d",
|
||||
reply.Format)
|
||||
}
|
||||
return string(reply.Value), nil
|
||||
}
|
||||
|
||||
// PropValStrs is the same as PropValStr, except that it returns a slice
|
||||
// of strings. The raw byte string is a sequence of null terminated strings,
|
||||
// which is translated into a slice of strings.
|
||||
func PropValStrs(reply *xproto.GetPropertyReply, err error) ([]string, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if reply.Format != 8 {
|
||||
return nil, fmt.Errorf("PropValStrs: Expected format 8 but got %d",
|
||||
reply.Format)
|
||||
}
|
||||
|
||||
var strs []string
|
||||
sstart := 0
|
||||
for i, c := range reply.Value {
|
||||
if c == 0 {
|
||||
strs = append(strs, string(reply.Value[sstart:i]))
|
||||
sstart = i + 1
|
||||
}
|
||||
}
|
||||
if sstart < int(reply.ValueLen) {
|
||||
strs = append(strs, string(reply.Value[sstart:]))
|
||||
}
|
||||
return strs, nil
|
||||
}
|
||||
Reference in New Issue
Block a user