271 lines
6.9 KiB
Go
271 lines
6.9 KiB
Go
|
package xprop
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
|
||
|
"github.com/jezek/xgb"
|
||
|
"github.com/jezek/xgb/xproto"
|
||
|
|
||
|
"github.com/jezek/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
|
||
|
}
|