update deps

This commit is contained in:
a 2023-06-11 09:21:08 -05:00
parent 9d961ec0ba
commit ba042cc537
159 changed files with 89054 additions and 6 deletions

7
go.mod
View File

@ -2,13 +2,12 @@ module tuxpa.in/t/wm
go 1.19
replace github.com/jezek/xgb v1.1.0 => ./xgb
replace github.com/jezek/xgb v1.1.0 => ./vend/xgb
replace github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0 => ./xgbutil
require github.com/jezek/xgb v1.1.0
replace github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0 => ./vend/xgbutil
require (
github.com/jezek/xgb v1.1.0
github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0
github.com/stretchr/testify v1.8.4
)

2
vend/xgb/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
xgbgen/xgbgen
.*.swp

18
vend/xgb/AUTHORS Normal file
View File

@ -0,0 +1,18 @@
Andrew Gallant is the maintainer of this fork. What follows is the original
list of authors for the x-go-binding.
# This is the official list of XGB authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS files.
# See the latter for an explanation.
# Names should be added to this file as
# Name or Organization <email address>
# The email address is not required for organizations.
# Please keep the list sorted.
Anthony Martin <ality@pbrane.org>
Firmansyah Adiputra <frm.adiputra@gmail.com>
Google Inc.
Scott Lawrence <bytbox@gmail.com>
Tor Andersson <tor.andersson@gmail.com>

39
vend/xgb/CONTRIBUTORS Normal file
View File

@ -0,0 +1,39 @@
Andrew Gallant is the maintainer of this fork. What follows is the original
list of contributors for the x-go-binding.
# This is the official list of people who can contribute
# (and typically have contributed) code to the XGB repository.
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees are listed here
# but not in AUTHORS, because Google holds the copyright.
#
# The submission process automatically checks to make sure
# that people submitting code are listed in this file (by email address).
#
# Names should be added to this file only after verifying that
# the individual or the individual's organization has agreed to
# the appropriate Contributor License Agreement, found here:
#
# http://code.google.com/legal/individual-cla-v1.0.html
# http://code.google.com/legal/corporate-cla-v1.0.html
#
# The agreement for individuals can be filled out on the web.
#
# When adding J Random Contributor's name to this file,
# either J's name or J's organization's name should be
# added to the AUTHORS file, depending on whether the
# individual or corporate CLA was used.
# Names should be added to this file like so:
# Name <email address>
# Please keep the list sorted.
Anthony Martin <ality@pbrane.org>
Firmansyah Adiputra <frm.adiputra@gmail.com>
Ian Lance Taylor <iant@golang.org>
Nigel Tao <nigeltao@golang.org>
Robert Griesemer <gri@golang.org>
Russ Cox <rsc@golang.org>
Scott Lawrence <bytbox@gmail.com>
Tor Andersson <tor.andersson@gmail.com>

42
vend/xgb/LICENSE Normal file
View File

@ -0,0 +1,42 @@
// Copyright (c) 2009 The XGB Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Subject to the terms and conditions of this License, Google hereby
// grants to You a perpetual, worldwide, non-exclusive, no-charge,
// royalty-free, irrevocable (except as stated in this section) patent
// license to make, have made, use, offer to sell, sell, import, and
// otherwise transfer this implementation of XGB, where such license
// applies only to those patent claims licensable by Google that are
// necessarily infringed by use of this implementation of XGB. If You
// institute patent litigation against any entity (including a
// cross-claim or counterclaim in a lawsuit) alleging that this
// implementation of XGB or a Contribution incorporated within this
// implementation of XGB constitutes direct or contributory patent
// infringement, then any patent licenses granted to You under this
// License for this implementation of XGB shall terminate as of the date
// such litigation is filed.

80
vend/xgb/Makefile Normal file
View File

@ -0,0 +1,80 @@
# This Makefile is used by the developer. It is not needed in any way to build
# a checkout of the XGB repository.
# It will be useful, however, if you are hacking at the code generator.
# i.e., after making a change to the code generator, run 'make' in the
# xgb directory. This will build xgbgen and regenerate each sub-package.
# 'make test' will then run any appropriate tests (just tests xproto right now).
# 'make bench' will test a couple of benchmarks.
# 'make build-all' will then try to build each extension. This isn't strictly
# necessary, but it's a good idea to make sure each sub-package is a valid
# Go package.
# My path to the X protocol XML descriptions.
ifndef XPROTO
XPROTO=/usr/share/xcb
endif
# All of the XML files in my /usr/share/xcb directory EXCEPT XKB. -_-
# This is intended to build xgbgen and generate Go code for each supported
# extension.
all: build-xgbgen \
bigreq.xml composite.xml damage.xml dpms.xml dri2.xml \
ge.xml glx.xml randr.xml record.xml render.xml res.xml \
screensaver.xml shape.xml shm.xml xc_misc.xml \
xevie.xml xf86dri.xml xf86vidmode.xml xfixes.xml xinerama.xml \
xprint.xml xproto.xml xselinux.xml xtest.xml \
xvmc.xml xv.xml
build-xgbgen:
(cd xgbgen && go build)
# Builds each individual sub-package to make sure its valid Go code.
build-all: bigreq.b composite.b damage.b dpms.b dri2.b ge.b glx.b randr.b \
record.b render.b res.b screensaver.b shape.b shm.b xcmisc.b \
xevie.b xf86dri.b xf86vidmode.b xfixes.b xinerama.b \
xprint.b xproto.b xselinux.b xtest.b xv.b xvmc.b
%.b:
(cd $* ; go build)
# Installs each individual sub-package.
install: bigreq.i composite.i damage.i dpms.i dri2.i ge.i glx.i randr.i \
record.i render.i res.i screensaver.i shape.i shm.i xcmisc.i \
xevie.i xf86dri.i xf86vidmode.i xfixes.i xinerama.i \
xprint.i xproto.i xselinux.i xtest.i xv.i xvmc.i
go install
%.i:
(cd $* ; go install)
# xc_misc is special because it has an underscore.
# There's probably a way to do this better, but Makefiles aren't my strong suit.
xc_misc.xml: build-xgbgen
mkdir -p xcmisc
xgbgen/xgbgen --proto-path $(XPROTO) $(XPROTO)/xc_misc.xml > xcmisc/xcmisc.go
%.xml: build-xgbgen
mkdir -p $*
xgbgen/xgbgen --proto-path $(XPROTO) $(XPROTO)/$*.xml > $*/$*.go
# Just test the xproto core protocol for now.
test:
(cd xproto ; go test)
# Force all xproto benchmarks to run and no tests.
bench:
(cd xproto ; go test -run 'nomatch' -bench '.*' -cpu 1,2,3,6)
# gofmt all non-auto-generated code.
# (auto-generated code is already gofmt'd.)
# Also do a column check (80 cols) after a gofmt.
# But don't check columns on auto-generated code, since I don't care if they
# break 80 cols.
gofmt:
gofmt -w *.go xgbgen/*.go examples/*.go examples/*/*.go xproto/xproto_test.go
colcheck *.go xgbgen/*.go examples/*.go examples/*/*.go xproto/xproto_test.go
push:
git push origin master
git push github master

62
vend/xgb/README Normal file
View File

@ -0,0 +1,62 @@
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

29
vend/xgb/STYLE Normal file
View 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.

110
vend/xgb/auth.go Normal file
View File

@ -0,0 +1,110 @@
package xgb
/*
auth.go contains functions to facilitate the parsing of .Xauthority files.
It is largely unmodified from the original XGB package that I forked.
*/
import (
"encoding/binary"
"errors"
"io"
"os"
)
// readAuthority reads the X authority file for the DISPLAY.
// If hostname == "" or hostname == "localhost",
// then use the system's hostname (as returned by os.Hostname) instead.
func readAuthority(hostname, display string) (
name string, data []byte, err error) {
// b is a scratch buffer to use and should be at least 256 bytes long
// (i.e. it should be able to hold a hostname).
b := make([]byte, 256)
// As per /usr/include/X11/Xauth.h.
const familyLocal = 256
const familyWild = 65535
if len(hostname) == 0 || hostname == "localhost" {
hostname, err = os.Hostname()
if err != nil {
return "", nil, err
}
}
fname := os.Getenv("XAUTHORITY")
if len(fname) == 0 {
home := os.Getenv("HOME")
if len(home) == 0 {
err = errors.New("Xauthority not found: $XAUTHORITY, $HOME not set")
return "", nil, err
}
fname = home + "/.Xauthority"
}
r, err := os.Open(fname)
if err != nil {
return "", nil, err
}
defer r.Close()
for {
var family uint16
if err := binary.Read(r, binary.BigEndian, &family); err != nil {
return "", nil, err
}
addr, err := getString(r, b)
if err != nil {
return "", nil, err
}
disp, err := getString(r, b)
if err != nil {
return "", nil, err
}
name0, err := getString(r, b)
if err != nil {
return "", nil, err
}
data0, err := getBytes(r, b)
if err != nil {
return "", nil, err
}
addrmatch := (family == familyWild) ||
(family == familyLocal && addr == hostname)
dispmatch := (disp == "") || (disp == display)
if addrmatch && dispmatch {
return name0, data0, nil
}
}
panic("unreachable")
}
func getBytes(r io.Reader, b []byte) ([]byte, error) {
var n uint16
if err := binary.Read(r, binary.BigEndian, &n); err != nil {
return nil, err
} else if n > uint16(len(b)) {
return nil, errors.New("bytes too long for buffer")
}
if _, err := io.ReadFull(r, b[0:n]); err != nil {
return nil, err
}
return b[0:n], nil
}
func getString(r io.Reader, b []byte) (string, error) {
b, err := getBytes(r, b)
if err != nil {
return "", err
}
return string(b), nil
}

152
vend/xgb/bigreq/bigreq.go Normal file
View File

@ -0,0 +1,152 @@
// Package bigreq is the X client API for the BIG-REQUESTS extension.
package bigreq
// This file is automatically generated from bigreq.xml. Edit at your peril!
import (
"github.com/jezek/xgb"
"github.com/jezek/xgb/xproto"
)
// Init must be called before using the BIG-REQUESTS extension.
func Init(c *xgb.Conn) error {
reply, err := xproto.QueryExtension(c, 12, "BIG-REQUESTS").Reply()
switch {
case err != nil:
return err
case !reply.Present:
return xgb.Errorf("No extension named BIG-REQUESTS could be found on on the server.")
}
c.ExtLock.Lock()
c.Extensions["BIG-REQUESTS"] = reply.MajorOpcode
c.ExtLock.Unlock()
for evNum, fun := range xgb.NewExtEventFuncs["BIG-REQUESTS"] {
xgb.NewEventFuncs[int(reply.FirstEvent)+evNum] = fun
}
for errNum, fun := range xgb.NewExtErrorFuncs["BIG-REQUESTS"] {
xgb.NewErrorFuncs[int(reply.FirstError)+errNum] = fun
}
return nil
}
func init() {
xgb.NewExtEventFuncs["BIG-REQUESTS"] = make(map[int]xgb.NewEventFun)
xgb.NewExtErrorFuncs["BIG-REQUESTS"] = make(map[int]xgb.NewErrorFun)
}
// Skipping definition for base type 'Bool'
// Skipping definition for base type 'Byte'
// Skipping definition for base type 'Card8'
// Skipping definition for base type 'Char'
// Skipping definition for base type 'Void'
// Skipping definition for base type 'Double'
// Skipping definition for base type 'Float'
// Skipping definition for base type 'Int16'
// Skipping definition for base type 'Int32'
// Skipping definition for base type 'Int8'
// Skipping definition for base type 'Card16'
// Skipping definition for base type 'Card32'
// EnableCookie is a cookie used only for Enable requests.
type EnableCookie struct {
*xgb.Cookie
}
// Enable sends a checked request.
// If an error occurs, it will be returned with the reply by calling EnableCookie.Reply()
func Enable(c *xgb.Conn) EnableCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["BIG-REQUESTS"]; !ok {
panic("Cannot issue request 'Enable' using the uninitialized extension 'BIG-REQUESTS'. bigreq.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(enableRequest(c), cookie)
return EnableCookie{cookie}
}
// EnableUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func EnableUnchecked(c *xgb.Conn) EnableCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["BIG-REQUESTS"]; !ok {
panic("Cannot issue request 'Enable' using the uninitialized extension 'BIG-REQUESTS'. bigreq.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(enableRequest(c), cookie)
return EnableCookie{cookie}
}
// EnableReply represents the data returned from a Enable request.
type EnableReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
MaximumRequestLength uint32
}
// Reply blocks and returns the reply data for a Enable request.
func (cook EnableCookie) Reply() (*EnableReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return enableReply(buf), nil
}
// enableReply reads a byte slice into a EnableReply value.
func enableReply(buf []byte) *EnableReply {
v := new(EnableReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.MaximumRequestLength = xgb.Get32(buf[b:])
b += 4
return v
}
// Write request to wire for Enable
// enableRequest writes a Enable request to a byte slice.
func enableRequest(c *xgb.Conn) []byte {
size := 4
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["BIG-REQUESTS"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 0 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
return buf
}

View File

@ -0,0 +1,721 @@
// Package composite is the X client API for the Composite extension.
package composite
// This file is automatically generated from composite.xml. Edit at your peril!
import (
"github.com/jezek/xgb"
"github.com/jezek/xgb/xfixes"
"github.com/jezek/xgb/xproto"
)
// Init must be called before using the Composite extension.
func Init(c *xgb.Conn) error {
reply, err := xproto.QueryExtension(c, 9, "Composite").Reply()
switch {
case err != nil:
return err
case !reply.Present:
return xgb.Errorf("No extension named Composite could be found on on the server.")
}
c.ExtLock.Lock()
c.Extensions["Composite"] = reply.MajorOpcode
c.ExtLock.Unlock()
for evNum, fun := range xgb.NewExtEventFuncs["Composite"] {
xgb.NewEventFuncs[int(reply.FirstEvent)+evNum] = fun
}
for errNum, fun := range xgb.NewExtErrorFuncs["Composite"] {
xgb.NewErrorFuncs[int(reply.FirstError)+errNum] = fun
}
return nil
}
func init() {
xgb.NewExtEventFuncs["Composite"] = make(map[int]xgb.NewEventFun)
xgb.NewExtErrorFuncs["Composite"] = make(map[int]xgb.NewErrorFun)
}
const (
RedirectAutomatic = 0
RedirectManual = 1
)
// Skipping definition for base type 'Bool'
// Skipping definition for base type 'Byte'
// Skipping definition for base type 'Card8'
// Skipping definition for base type 'Char'
// Skipping definition for base type 'Void'
// Skipping definition for base type 'Double'
// Skipping definition for base type 'Float'
// Skipping definition for base type 'Int16'
// Skipping definition for base type 'Int32'
// Skipping definition for base type 'Int8'
// Skipping definition for base type 'Card16'
// Skipping definition for base type 'Card32'
// CreateRegionFromBorderClipCookie is a cookie used only for CreateRegionFromBorderClip requests.
type CreateRegionFromBorderClipCookie struct {
*xgb.Cookie
}
// CreateRegionFromBorderClip sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func CreateRegionFromBorderClip(c *xgb.Conn, Region xfixes.Region, Window xproto.Window) CreateRegionFromBorderClipCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'CreateRegionFromBorderClip' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(createRegionFromBorderClipRequest(c, Region, Window), cookie)
return CreateRegionFromBorderClipCookie{cookie}
}
// CreateRegionFromBorderClipChecked sends a checked request.
// If an error occurs, it can be retrieved using CreateRegionFromBorderClipCookie.Check()
func CreateRegionFromBorderClipChecked(c *xgb.Conn, Region xfixes.Region, Window xproto.Window) CreateRegionFromBorderClipCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'CreateRegionFromBorderClip' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(createRegionFromBorderClipRequest(c, Region, Window), cookie)
return CreateRegionFromBorderClipCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook CreateRegionFromBorderClipCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for CreateRegionFromBorderClip
// createRegionFromBorderClipRequest writes a CreateRegionFromBorderClip request to a byte slice.
func createRegionFromBorderClipRequest(c *xgb.Conn, Region xfixes.Region, Window xproto.Window) []byte {
size := 12
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["Composite"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 5 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Region))
b += 4
xgb.Put32(buf[b:], uint32(Window))
b += 4
return buf
}
// GetOverlayWindowCookie is a cookie used only for GetOverlayWindow requests.
type GetOverlayWindowCookie struct {
*xgb.Cookie
}
// GetOverlayWindow sends a checked request.
// If an error occurs, it will be returned with the reply by calling GetOverlayWindowCookie.Reply()
func GetOverlayWindow(c *xgb.Conn, Window xproto.Window) GetOverlayWindowCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'GetOverlayWindow' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(getOverlayWindowRequest(c, Window), cookie)
return GetOverlayWindowCookie{cookie}
}
// GetOverlayWindowUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func GetOverlayWindowUnchecked(c *xgb.Conn, Window xproto.Window) GetOverlayWindowCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'GetOverlayWindow' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(getOverlayWindowRequest(c, Window), cookie)
return GetOverlayWindowCookie{cookie}
}
// GetOverlayWindowReply represents the data returned from a GetOverlayWindow request.
type GetOverlayWindowReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
OverlayWin xproto.Window
// padding: 20 bytes
}
// Reply blocks and returns the reply data for a GetOverlayWindow request.
func (cook GetOverlayWindowCookie) Reply() (*GetOverlayWindowReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return getOverlayWindowReply(buf), nil
}
// getOverlayWindowReply reads a byte slice into a GetOverlayWindowReply value.
func getOverlayWindowReply(buf []byte) *GetOverlayWindowReply {
v := new(GetOverlayWindowReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.OverlayWin = xproto.Window(xgb.Get32(buf[b:]))
b += 4
b += 20 // padding
return v
}
// Write request to wire for GetOverlayWindow
// getOverlayWindowRequest writes a GetOverlayWindow request to a byte slice.
func getOverlayWindowRequest(c *xgb.Conn, Window xproto.Window) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["Composite"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 7 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Window))
b += 4
return buf
}
// NameWindowPixmapCookie is a cookie used only for NameWindowPixmap requests.
type NameWindowPixmapCookie struct {
*xgb.Cookie
}
// NameWindowPixmap sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func NameWindowPixmap(c *xgb.Conn, Window xproto.Window, Pixmap xproto.Pixmap) NameWindowPixmapCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'NameWindowPixmap' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(nameWindowPixmapRequest(c, Window, Pixmap), cookie)
return NameWindowPixmapCookie{cookie}
}
// NameWindowPixmapChecked sends a checked request.
// If an error occurs, it can be retrieved using NameWindowPixmapCookie.Check()
func NameWindowPixmapChecked(c *xgb.Conn, Window xproto.Window, Pixmap xproto.Pixmap) NameWindowPixmapCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'NameWindowPixmap' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(nameWindowPixmapRequest(c, Window, Pixmap), cookie)
return NameWindowPixmapCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook NameWindowPixmapCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for NameWindowPixmap
// nameWindowPixmapRequest writes a NameWindowPixmap request to a byte slice.
func nameWindowPixmapRequest(c *xgb.Conn, Window xproto.Window, Pixmap xproto.Pixmap) []byte {
size := 12
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["Composite"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 6 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Window))
b += 4
xgb.Put32(buf[b:], uint32(Pixmap))
b += 4
return buf
}
// QueryVersionCookie is a cookie used only for QueryVersion requests.
type QueryVersionCookie struct {
*xgb.Cookie
}
// QueryVersion sends a checked request.
// If an error occurs, it will be returned with the reply by calling QueryVersionCookie.Reply()
func QueryVersion(c *xgb.Conn, ClientMajorVersion uint32, ClientMinorVersion uint32) QueryVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(queryVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return QueryVersionCookie{cookie}
}
// QueryVersionUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func QueryVersionUnchecked(c *xgb.Conn, ClientMajorVersion uint32, ClientMinorVersion uint32) QueryVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(queryVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return QueryVersionCookie{cookie}
}
// QueryVersionReply represents the data returned from a QueryVersion request.
type QueryVersionReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
MajorVersion uint32
MinorVersion uint32
// padding: 16 bytes
}
// Reply blocks and returns the reply data for a QueryVersion request.
func (cook QueryVersionCookie) Reply() (*QueryVersionReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return queryVersionReply(buf), nil
}
// queryVersionReply reads a byte slice into a QueryVersionReply value.
func queryVersionReply(buf []byte) *QueryVersionReply {
v := new(QueryVersionReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.MajorVersion = xgb.Get32(buf[b:])
b += 4
v.MinorVersion = xgb.Get32(buf[b:])
b += 4
b += 16 // padding
return v
}
// Write request to wire for QueryVersion
// queryVersionRequest writes a QueryVersion request to a byte slice.
func queryVersionRequest(c *xgb.Conn, ClientMajorVersion uint32, ClientMinorVersion uint32) []byte {
size := 12
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["Composite"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 0 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], ClientMajorVersion)
b += 4
xgb.Put32(buf[b:], ClientMinorVersion)
b += 4
return buf
}
// RedirectSubwindowsCookie is a cookie used only for RedirectSubwindows requests.
type RedirectSubwindowsCookie struct {
*xgb.Cookie
}
// RedirectSubwindows sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func RedirectSubwindows(c *xgb.Conn, Window xproto.Window, Update byte) RedirectSubwindowsCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'RedirectSubwindows' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(redirectSubwindowsRequest(c, Window, Update), cookie)
return RedirectSubwindowsCookie{cookie}
}
// RedirectSubwindowsChecked sends a checked request.
// If an error occurs, it can be retrieved using RedirectSubwindowsCookie.Check()
func RedirectSubwindowsChecked(c *xgb.Conn, Window xproto.Window, Update byte) RedirectSubwindowsCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'RedirectSubwindows' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(redirectSubwindowsRequest(c, Window, Update), cookie)
return RedirectSubwindowsCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook RedirectSubwindowsCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for RedirectSubwindows
// redirectSubwindowsRequest writes a RedirectSubwindows request to a byte slice.
func redirectSubwindowsRequest(c *xgb.Conn, Window xproto.Window, Update byte) []byte {
size := 12
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["Composite"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 2 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Window))
b += 4
buf[b] = Update
b += 1
b += 3 // padding
return buf
}
// RedirectWindowCookie is a cookie used only for RedirectWindow requests.
type RedirectWindowCookie struct {
*xgb.Cookie
}
// RedirectWindow sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func RedirectWindow(c *xgb.Conn, Window xproto.Window, Update byte) RedirectWindowCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'RedirectWindow' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(redirectWindowRequest(c, Window, Update), cookie)
return RedirectWindowCookie{cookie}
}
// RedirectWindowChecked sends a checked request.
// If an error occurs, it can be retrieved using RedirectWindowCookie.Check()
func RedirectWindowChecked(c *xgb.Conn, Window xproto.Window, Update byte) RedirectWindowCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'RedirectWindow' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(redirectWindowRequest(c, Window, Update), cookie)
return RedirectWindowCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook RedirectWindowCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for RedirectWindow
// redirectWindowRequest writes a RedirectWindow request to a byte slice.
func redirectWindowRequest(c *xgb.Conn, Window xproto.Window, Update byte) []byte {
size := 12
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["Composite"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 1 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Window))
b += 4
buf[b] = Update
b += 1
b += 3 // padding
return buf
}
// ReleaseOverlayWindowCookie is a cookie used only for ReleaseOverlayWindow requests.
type ReleaseOverlayWindowCookie struct {
*xgb.Cookie
}
// ReleaseOverlayWindow sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func ReleaseOverlayWindow(c *xgb.Conn, Window xproto.Window) ReleaseOverlayWindowCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'ReleaseOverlayWindow' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(releaseOverlayWindowRequest(c, Window), cookie)
return ReleaseOverlayWindowCookie{cookie}
}
// ReleaseOverlayWindowChecked sends a checked request.
// If an error occurs, it can be retrieved using ReleaseOverlayWindowCookie.Check()
func ReleaseOverlayWindowChecked(c *xgb.Conn, Window xproto.Window) ReleaseOverlayWindowCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'ReleaseOverlayWindow' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(releaseOverlayWindowRequest(c, Window), cookie)
return ReleaseOverlayWindowCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook ReleaseOverlayWindowCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for ReleaseOverlayWindow
// releaseOverlayWindowRequest writes a ReleaseOverlayWindow request to a byte slice.
func releaseOverlayWindowRequest(c *xgb.Conn, Window xproto.Window) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["Composite"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 8 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Window))
b += 4
return buf
}
// UnredirectSubwindowsCookie is a cookie used only for UnredirectSubwindows requests.
type UnredirectSubwindowsCookie struct {
*xgb.Cookie
}
// UnredirectSubwindows sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func UnredirectSubwindows(c *xgb.Conn, Window xproto.Window, Update byte) UnredirectSubwindowsCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'UnredirectSubwindows' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(unredirectSubwindowsRequest(c, Window, Update), cookie)
return UnredirectSubwindowsCookie{cookie}
}
// UnredirectSubwindowsChecked sends a checked request.
// If an error occurs, it can be retrieved using UnredirectSubwindowsCookie.Check()
func UnredirectSubwindowsChecked(c *xgb.Conn, Window xproto.Window, Update byte) UnredirectSubwindowsCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'UnredirectSubwindows' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(unredirectSubwindowsRequest(c, Window, Update), cookie)
return UnredirectSubwindowsCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook UnredirectSubwindowsCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for UnredirectSubwindows
// unredirectSubwindowsRequest writes a UnredirectSubwindows request to a byte slice.
func unredirectSubwindowsRequest(c *xgb.Conn, Window xproto.Window, Update byte) []byte {
size := 12
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["Composite"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 4 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Window))
b += 4
buf[b] = Update
b += 1
b += 3 // padding
return buf
}
// UnredirectWindowCookie is a cookie used only for UnredirectWindow requests.
type UnredirectWindowCookie struct {
*xgb.Cookie
}
// UnredirectWindow sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func UnredirectWindow(c *xgb.Conn, Window xproto.Window, Update byte) UnredirectWindowCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'UnredirectWindow' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(unredirectWindowRequest(c, Window, Update), cookie)
return UnredirectWindowCookie{cookie}
}
// UnredirectWindowChecked sends a checked request.
// If an error occurs, it can be retrieved using UnredirectWindowCookie.Check()
func UnredirectWindowChecked(c *xgb.Conn, Window xproto.Window, Update byte) UnredirectWindowCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Composite"]; !ok {
panic("Cannot issue request 'UnredirectWindow' using the uninitialized extension 'Composite'. composite.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(unredirectWindowRequest(c, Window, Update), cookie)
return UnredirectWindowCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook UnredirectWindowCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for UnredirectWindow
// unredirectWindowRequest writes a UnredirectWindow request to a byte slice.
func unredirectWindowRequest(c *xgb.Conn, Window xproto.Window, Update byte) []byte {
size := 12
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["Composite"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 3 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Window))
b += 4
buf[b] = Update
b += 1
b += 3 // padding
return buf
}

186
vend/xgb/conn.go Normal file
View File

@ -0,0 +1,186 @@
package xgb
/*
conn.go contains a couple of functions that do some real dirty work related
to the initial connection handshake with X.
This code is largely unmodified from the original XGB package that I forked.
*/
import (
"errors"
"fmt"
"io"
"net"
"os"
"strconv"
"strings"
)
// connect connects to the X server given in the 'display' string,
// and does all the necessary setup handshaking.
// If 'display' is empty it will be taken from os.Getenv("DISPLAY").
// Note that you should read and understand the "Connection Setup" of the
// X Protocol Reference Manual before changing this function:
// http://goo.gl/4zGQg
func (c *Conn) connect(display string) error {
err := c.dial(display)
if err != nil {
return err
}
return c.postConnect()
}
// connect init from to the net.Conn,
func (c *Conn) connectNet(netConn net.Conn) error {
c.conn = netConn
return c.postConnect()
}
// do the postConnect action after Conn get it's underly net.Conn
func (c *Conn) postConnect() error {
// Get authentication data
authName, authData, err := readAuthority(c.host, c.display)
noauth := false
if err != nil {
Logger.Printf("Could not get authority info: %v", err)
Logger.Println("Trying connection without authority info...")
authName = ""
authData = []byte{}
noauth = true
}
// Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1".
if !noauth && (authName != "MIT-MAGIC-COOKIE-1" || len(authData) != 16) {
return errors.New("unsupported auth protocol " + authName)
}
buf := make([]byte, 12+Pad(len(authName))+Pad(len(authData)))
buf[0] = 0x6c
buf[1] = 0
Put16(buf[2:], 11)
Put16(buf[4:], 0)
Put16(buf[6:], uint16(len(authName)))
Put16(buf[8:], uint16(len(authData)))
Put16(buf[10:], 0)
copy(buf[12:], []byte(authName))
copy(buf[12+Pad(len(authName)):], authData)
if _, err = c.conn.Write(buf); err != nil {
return err
}
head := make([]byte, 8)
if _, err = io.ReadFull(c.conn, head[0:8]); err != nil {
return err
}
code := head[0]
reasonLen := head[1]
major := Get16(head[2:])
minor := Get16(head[4:])
dataLen := Get16(head[6:])
if major != 11 || minor != 0 {
return fmt.Errorf("x protocol version mismatch: %d.%d", major, minor)
}
buf = make([]byte, int(dataLen)*4+8, int(dataLen)*4+8)
copy(buf, head)
if _, err = io.ReadFull(c.conn, buf[8:]); err != nil {
return err
}
if code == 0 {
reason := buf[8 : 8+reasonLen]
return fmt.Errorf("x protocol authentication refused: %s",
string(reason))
}
// Unfortunately, it isn't really feasible to read the setup bytes here,
// since the code to do so is in a different package.
// Users must call 'xproto.Setup(X)' to get the setup info.
c.SetupBytes = buf
// But also read stuff that we *need* to get started.
c.setupResourceIdBase = Get32(buf[12:])
c.setupResourceIdMask = Get32(buf[16:])
return nil
}
// dial initializes the actual net connection with X.
func (c *Conn) dial(display string) error {
if len(display) == 0 {
display = os.Getenv("DISPLAY")
}
display0 := display
if len(display) == 0 {
return errors.New("empty display string")
}
colonIdx := strings.LastIndex(display, ":")
if colonIdx < 0 {
return errors.New("bad display string: " + display0)
}
var protocol, socket string
if display[0] == '/' {
socket = display[0:colonIdx]
} else {
slashIdx := strings.LastIndex(display, "/")
if slashIdx >= 0 {
protocol = display[0:slashIdx]
c.host = display[slashIdx+1 : colonIdx]
} else {
c.host = display[0:colonIdx]
}
}
display = display[colonIdx+1 : len(display)]
if len(display) == 0 {
return errors.New("bad display string: " + display0)
}
var scr string
dotIdx := strings.LastIndex(display, ".")
if dotIdx < 0 {
c.display = display[0:]
} else {
c.display = display[0:dotIdx]
scr = display[dotIdx+1:]
}
var err error
c.DisplayNumber, err = strconv.Atoi(c.display)
if err != nil || c.DisplayNumber < 0 {
return errors.New("bad display string: " + display0)
}
if len(scr) != 0 {
c.DefaultScreen, err = strconv.Atoi(scr)
if err != nil {
return errors.New("bad display string: " + display0)
}
}
// Connect to server
if len(socket) != 0 {
c.conn, err = net.Dial("unix", socket+":"+c.display)
} else if len(c.host) != 0 && c.host != "unix" {
if protocol == "" {
protocol = "tcp"
}
c.conn, err = net.Dial(protocol,
c.host+":"+strconv.Itoa(6000+c.DisplayNumber))
} else {
c.host = ""
c.conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+c.display)
}
if err != nil {
return errors.New("cannot connect to " + display0 + ": " + err.Error())
}
return nil
}

178
vend/xgb/cookie.go Normal file
View File

@ -0,0 +1,178 @@
package xgb
import (
"errors"
"io"
)
// 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'.
type Cookie struct {
conn *Conn
Sequence uint16
replyChan chan []byte
errorChan chan error
pingChan chan bool
}
// 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 (c *Conn) NewCookie(checked, reply bool) *Cookie {
cookie := &Cookie{
conn: c,
Sequence: 0, // we add the sequence id just before sending a request
replyChan: nil,
errorChan: nil,
pingChan: nil,
}
// There are four different kinds of cookies:
// Checked requests with replies get a reply channel and an error channel.
// Unchecked requests with replies get a reply channel and a ping channel.
// Checked requests w/o replies get a ping channel and an error channel.
// Unchecked requests w/o replies get no channels.
// The reply channel is used to send reply data.
// The error channel is used to send error data.
// The ping channel is used when one of the 'reply' or 'error' channels
// is missing but the other is present. The ping channel is way to force
// the blocking to stop and basically say "the error has been received
// in the main event loop" (when the ping channel is coupled with a reply
// channel) or "the request you made that has no reply was successful"
// (when the ping channel is coupled with an error channel).
if checked {
cookie.errorChan = make(chan error, 1)
if !reply {
cookie.pingChan = make(chan bool, 1)
}
}
if reply {
cookie.replyChan = make(chan []byte, 1)
if !checked {
cookie.pingChan = make(chan bool, 1)
}
}
return cookie
}
// 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.
func (c Cookie) Reply() ([]byte, error) {
// checked
if c.errorChan != nil {
return c.replyChecked()
}
return c.replyUnchecked()
}
// replyChecked waits for a response on either the replyChan or errorChan
// channels. If the former arrives, the bytes are returned with a nil error.
// If the latter arrives, no bytes are returned (nil) and the error received
// is returned.
// Returns (nil, io.EOF) when the connection is closed.
//
// Unless you're building requests from bytes by hand, this method should
// not be used.
func (c Cookie) replyChecked() ([]byte, error) {
if c.replyChan == nil {
return nil, errors.New("Cannot call 'replyChecked' on a cookie that " +
"is not expecting a *reply* or an error.")
}
if c.errorChan == nil {
return nil, errors.New("Cannot call 'replyChecked' on a cookie that " +
"is not expecting a reply or an *error*.")
}
select {
case reply := <-c.replyChan:
return reply, nil
case err := <-c.errorChan:
return nil, err
case <-c.conn.doneRead:
// c.conn.readResponses is no more, there will be no replys or errors
return nil, io.EOF
}
}
// replyUnchecked waits for a response on either the replyChan or pingChan
// channels. If the former arrives, the bytes are returned with a nil error.
// If the latter arrives, no bytes are returned (nil) and a nil error
// is returned. (In the latter case, the corresponding error can be retrieved
// from (Wait|Poll)ForEvent asynchronously.)
// Returns (nil, io.EOF) when the connection is closed.
// In all honesty, you *probably* don't want to use this method.
//
// Unless you're building requests from bytes by hand, this method should
// not be used.
func (c Cookie) replyUnchecked() ([]byte, error) {
if c.replyChan == nil {
return nil, errors.New("Cannot call 'replyUnchecked' on a cookie " +
"that is not expecting a *reply*.")
}
select {
case reply := <-c.replyChan:
return reply, nil
case <-c.pingChan:
return nil, nil
case <-c.conn.doneRead:
// c.conn.readResponses is no more, there will be no replys or pings
return nil, io.EOF
}
}
// 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 (c Cookie) Check() error {
if c.replyChan != nil {
return errors.New("Cannot call 'Check' on a cookie that is " +
"expecting a *reply*. Use 'Reply' instead.")
}
if c.errorChan == nil {
return errors.New("Cannot call 'Check' on a cookie that is " +
"not expecting a possible *error*.")
}
// First do a quick non-blocking check to see if we've been pinged.
select {
case err := <-c.errorChan:
return err
case <-c.pingChan:
return nil
default:
}
// Now force a round trip and try again, but block this time.
c.conn.Sync()
select {
case err := <-c.errorChan:
return err
case <-c.pingChan:
return nil
case <-c.conn.doneRead:
// c.conn.readResponses is no more, there will be no errors or pings
return io.EOF
}
}

592
vend/xgb/damage/damage.go Normal file
View File

@ -0,0 +1,592 @@
// Package damage is the X client API for the DAMAGE extension.
package damage
// This file is automatically generated from damage.xml. Edit at your peril!
import (
"github.com/jezek/xgb"
"github.com/jezek/xgb/xfixes"
"github.com/jezek/xgb/xproto"
)
// Init must be called before using the DAMAGE extension.
func Init(c *xgb.Conn) error {
reply, err := xproto.QueryExtension(c, 6, "DAMAGE").Reply()
switch {
case err != nil:
return err
case !reply.Present:
return xgb.Errorf("No extension named DAMAGE could be found on on the server.")
}
c.ExtLock.Lock()
c.Extensions["DAMAGE"] = reply.MajorOpcode
c.ExtLock.Unlock()
for evNum, fun := range xgb.NewExtEventFuncs["DAMAGE"] {
xgb.NewEventFuncs[int(reply.FirstEvent)+evNum] = fun
}
for errNum, fun := range xgb.NewExtErrorFuncs["DAMAGE"] {
xgb.NewErrorFuncs[int(reply.FirstError)+errNum] = fun
}
return nil
}
func init() {
xgb.NewExtEventFuncs["DAMAGE"] = make(map[int]xgb.NewEventFun)
xgb.NewExtErrorFuncs["DAMAGE"] = make(map[int]xgb.NewErrorFun)
}
// BadBadDamage is the error number for a BadBadDamage.
const BadBadDamage = 0
type BadDamageError struct {
Sequence uint16
NiceName string
}
// BadDamageErrorNew constructs a BadDamageError value that implements xgb.Error from a byte slice.
func BadDamageErrorNew(buf []byte) xgb.Error {
v := BadDamageError{}
v.NiceName = "BadDamage"
b := 1 // skip error determinant
b += 1 // don't read error number
v.Sequence = xgb.Get16(buf[b:])
b += 2
return v
}
// SequenceId returns the sequence id attached to the BadBadDamage error.
// This is mostly used internally.
func (err BadDamageError) SequenceId() uint16 {
return err.Sequence
}
// BadId returns the 'BadValue' number if one exists for the BadBadDamage error. If no bad value exists, 0 is returned.
func (err BadDamageError) BadId() uint32 {
return 0
}
// Error returns a rudimentary string representation of the BadBadDamage error.
func (err BadDamageError) Error() string {
fieldVals := make([]string, 0, 0)
fieldVals = append(fieldVals, "NiceName: "+err.NiceName)
fieldVals = append(fieldVals, xgb.Sprintf("Sequence: %d", err.Sequence))
return "BadBadDamage {" + xgb.StringsJoin(fieldVals, ", ") + "}"
}
func init() {
xgb.NewExtErrorFuncs["DAMAGE"][0] = BadDamageErrorNew
}
type Damage uint32
func NewDamageId(c *xgb.Conn) (Damage, error) {
id, err := c.NewId()
if err != nil {
return 0, err
}
return Damage(id), nil
}
// Notify is the event number for a NotifyEvent.
const Notify = 0
type NotifyEvent struct {
Sequence uint16
Level byte
Drawable xproto.Drawable
Damage Damage
Timestamp xproto.Timestamp
Area xproto.Rectangle
Geometry xproto.Rectangle
}
// NotifyEventNew constructs a NotifyEvent value that implements xgb.Event from a byte slice.
func NotifyEventNew(buf []byte) xgb.Event {
v := NotifyEvent{}
b := 1 // don't read event number
v.Level = buf[b]
b += 1
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Drawable = xproto.Drawable(xgb.Get32(buf[b:]))
b += 4
v.Damage = Damage(xgb.Get32(buf[b:]))
b += 4
v.Timestamp = xproto.Timestamp(xgb.Get32(buf[b:]))
b += 4
v.Area = xproto.Rectangle{}
b += xproto.RectangleRead(buf[b:], &v.Area)
v.Geometry = xproto.Rectangle{}
b += xproto.RectangleRead(buf[b:], &v.Geometry)
return v
}
// Bytes writes a NotifyEvent value to a byte slice.
func (v NotifyEvent) Bytes() []byte {
buf := make([]byte, 32)
b := 0
// write event number
buf[b] = 0
b += 1
buf[b] = v.Level
b += 1
b += 2 // skip sequence number
xgb.Put32(buf[b:], uint32(v.Drawable))
b += 4
xgb.Put32(buf[b:], uint32(v.Damage))
b += 4
xgb.Put32(buf[b:], uint32(v.Timestamp))
b += 4
{
structBytes := v.Area.Bytes()
copy(buf[b:], structBytes)
b += len(structBytes)
}
{
structBytes := v.Geometry.Bytes()
copy(buf[b:], structBytes)
b += len(structBytes)
}
return buf
}
// SequenceId returns the sequence id attached to the Notify event.
// Events without a sequence number (KeymapNotify) return 0.
// This is mostly used internally.
func (v NotifyEvent) SequenceId() uint16 {
return v.Sequence
}
// String is a rudimentary string representation of NotifyEvent.
func (v NotifyEvent) String() string {
fieldVals := make([]string, 0, 6)
fieldVals = append(fieldVals, xgb.Sprintf("Sequence: %d", v.Sequence))
fieldVals = append(fieldVals, xgb.Sprintf("Level: %d", v.Level))
fieldVals = append(fieldVals, xgb.Sprintf("Drawable: %d", v.Drawable))
fieldVals = append(fieldVals, xgb.Sprintf("Damage: %d", v.Damage))
fieldVals = append(fieldVals, xgb.Sprintf("Timestamp: %d", v.Timestamp))
return "Notify {" + xgb.StringsJoin(fieldVals, ", ") + "}"
}
func init() {
xgb.NewExtEventFuncs["DAMAGE"][0] = NotifyEventNew
}
const (
ReportLevelRawRectangles = 0
ReportLevelDeltaRectangles = 1
ReportLevelBoundingBox = 2
ReportLevelNonEmpty = 3
)
// Skipping definition for base type 'Bool'
// Skipping definition for base type 'Byte'
// Skipping definition for base type 'Card8'
// Skipping definition for base type 'Char'
// Skipping definition for base type 'Void'
// Skipping definition for base type 'Double'
// Skipping definition for base type 'Float'
// Skipping definition for base type 'Int16'
// Skipping definition for base type 'Int32'
// Skipping definition for base type 'Int8'
// Skipping definition for base type 'Card16'
// Skipping definition for base type 'Card32'
// AddCookie is a cookie used only for Add requests.
type AddCookie struct {
*xgb.Cookie
}
// Add sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func Add(c *xgb.Conn, Drawable xproto.Drawable, Region xfixes.Region) AddCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DAMAGE"]; !ok {
panic("Cannot issue request 'Add' using the uninitialized extension 'DAMAGE'. damage.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(addRequest(c, Drawable, Region), cookie)
return AddCookie{cookie}
}
// AddChecked sends a checked request.
// If an error occurs, it can be retrieved using AddCookie.Check()
func AddChecked(c *xgb.Conn, Drawable xproto.Drawable, Region xfixes.Region) AddCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DAMAGE"]; !ok {
panic("Cannot issue request 'Add' using the uninitialized extension 'DAMAGE'. damage.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(addRequest(c, Drawable, Region), cookie)
return AddCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook AddCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for Add
// addRequest writes a Add request to a byte slice.
func addRequest(c *xgb.Conn, Drawable xproto.Drawable, Region xfixes.Region) []byte {
size := 12
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["DAMAGE"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 4 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Drawable))
b += 4
xgb.Put32(buf[b:], uint32(Region))
b += 4
return buf
}
// CreateCookie is a cookie used only for Create requests.
type CreateCookie struct {
*xgb.Cookie
}
// Create sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func Create(c *xgb.Conn, Damage Damage, Drawable xproto.Drawable, Level byte) CreateCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DAMAGE"]; !ok {
panic("Cannot issue request 'Create' using the uninitialized extension 'DAMAGE'. damage.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(createRequest(c, Damage, Drawable, Level), cookie)
return CreateCookie{cookie}
}
// CreateChecked sends a checked request.
// If an error occurs, it can be retrieved using CreateCookie.Check()
func CreateChecked(c *xgb.Conn, Damage Damage, Drawable xproto.Drawable, Level byte) CreateCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DAMAGE"]; !ok {
panic("Cannot issue request 'Create' using the uninitialized extension 'DAMAGE'. damage.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(createRequest(c, Damage, Drawable, Level), cookie)
return CreateCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook CreateCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for Create
// createRequest writes a Create request to a byte slice.
func createRequest(c *xgb.Conn, Damage Damage, Drawable xproto.Drawable, Level byte) []byte {
size := 16
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["DAMAGE"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 1 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Damage))
b += 4
xgb.Put32(buf[b:], uint32(Drawable))
b += 4
buf[b] = Level
b += 1
b += 3 // padding
return buf
}
// DestroyCookie is a cookie used only for Destroy requests.
type DestroyCookie struct {
*xgb.Cookie
}
// Destroy sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func Destroy(c *xgb.Conn, Damage Damage) DestroyCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DAMAGE"]; !ok {
panic("Cannot issue request 'Destroy' using the uninitialized extension 'DAMAGE'. damage.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(destroyRequest(c, Damage), cookie)
return DestroyCookie{cookie}
}
// DestroyChecked sends a checked request.
// If an error occurs, it can be retrieved using DestroyCookie.Check()
func DestroyChecked(c *xgb.Conn, Damage Damage) DestroyCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DAMAGE"]; !ok {
panic("Cannot issue request 'Destroy' using the uninitialized extension 'DAMAGE'. damage.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(destroyRequest(c, Damage), cookie)
return DestroyCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook DestroyCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for Destroy
// destroyRequest writes a Destroy request to a byte slice.
func destroyRequest(c *xgb.Conn, Damage Damage) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["DAMAGE"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 2 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Damage))
b += 4
return buf
}
// QueryVersionCookie is a cookie used only for QueryVersion requests.
type QueryVersionCookie struct {
*xgb.Cookie
}
// QueryVersion sends a checked request.
// If an error occurs, it will be returned with the reply by calling QueryVersionCookie.Reply()
func QueryVersion(c *xgb.Conn, ClientMajorVersion uint32, ClientMinorVersion uint32) QueryVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DAMAGE"]; !ok {
panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'DAMAGE'. damage.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(queryVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return QueryVersionCookie{cookie}
}
// QueryVersionUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func QueryVersionUnchecked(c *xgb.Conn, ClientMajorVersion uint32, ClientMinorVersion uint32) QueryVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DAMAGE"]; !ok {
panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'DAMAGE'. damage.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(queryVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return QueryVersionCookie{cookie}
}
// QueryVersionReply represents the data returned from a QueryVersion request.
type QueryVersionReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
MajorVersion uint32
MinorVersion uint32
// padding: 16 bytes
}
// Reply blocks and returns the reply data for a QueryVersion request.
func (cook QueryVersionCookie) Reply() (*QueryVersionReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return queryVersionReply(buf), nil
}
// queryVersionReply reads a byte slice into a QueryVersionReply value.
func queryVersionReply(buf []byte) *QueryVersionReply {
v := new(QueryVersionReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.MajorVersion = xgb.Get32(buf[b:])
b += 4
v.MinorVersion = xgb.Get32(buf[b:])
b += 4
b += 16 // padding
return v
}
// Write request to wire for QueryVersion
// queryVersionRequest writes a QueryVersion request to a byte slice.
func queryVersionRequest(c *xgb.Conn, ClientMajorVersion uint32, ClientMinorVersion uint32) []byte {
size := 12
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["DAMAGE"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 0 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], ClientMajorVersion)
b += 4
xgb.Put32(buf[b:], ClientMinorVersion)
b += 4
return buf
}
// SubtractCookie is a cookie used only for Subtract requests.
type SubtractCookie struct {
*xgb.Cookie
}
// Subtract sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func Subtract(c *xgb.Conn, Damage Damage, Repair xfixes.Region, Parts xfixes.Region) SubtractCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DAMAGE"]; !ok {
panic("Cannot issue request 'Subtract' using the uninitialized extension 'DAMAGE'. damage.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(subtractRequest(c, Damage, Repair, Parts), cookie)
return SubtractCookie{cookie}
}
// SubtractChecked sends a checked request.
// If an error occurs, it can be retrieved using SubtractCookie.Check()
func SubtractChecked(c *xgb.Conn, Damage Damage, Repair xfixes.Region, Parts xfixes.Region) SubtractCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DAMAGE"]; !ok {
panic("Cannot issue request 'Subtract' using the uninitialized extension 'DAMAGE'. damage.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(subtractRequest(c, Damage, Repair, Parts), cookie)
return SubtractCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook SubtractCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for Subtract
// subtractRequest writes a Subtract request to a byte slice.
func subtractRequest(c *xgb.Conn, Damage Damage, Repair xfixes.Region, Parts xfixes.Region) []byte {
size := 16
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["DAMAGE"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 3 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Damage))
b += 4
xgb.Put32(buf[b:], uint32(Repair))
b += 4
xgb.Put32(buf[b:], uint32(Parts))
b += 4
return buf
}

146
vend/xgb/doc.go Normal file
View File

@ -0,0 +1,146 @@
/*
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.
*/
package xgb

715
vend/xgb/dpms/dpms.go Normal file
View File

@ -0,0 +1,715 @@
// Package dpms is the X client API for the DPMS extension.
package dpms
// This file is automatically generated from dpms.xml. Edit at your peril!
import (
"github.com/jezek/xgb"
"github.com/jezek/xgb/xproto"
)
// Init must be called before using the DPMS extension.
func Init(c *xgb.Conn) error {
reply, err := xproto.QueryExtension(c, 4, "DPMS").Reply()
switch {
case err != nil:
return err
case !reply.Present:
return xgb.Errorf("No extension named DPMS could be found on on the server.")
}
c.ExtLock.Lock()
c.Extensions["DPMS"] = reply.MajorOpcode
c.ExtLock.Unlock()
for evNum, fun := range xgb.NewExtEventFuncs["DPMS"] {
xgb.NewEventFuncs[int(reply.FirstEvent)+evNum] = fun
}
for errNum, fun := range xgb.NewExtErrorFuncs["DPMS"] {
xgb.NewErrorFuncs[int(reply.FirstError)+errNum] = fun
}
return nil
}
func init() {
xgb.NewExtEventFuncs["DPMS"] = make(map[int]xgb.NewEventFun)
xgb.NewExtErrorFuncs["DPMS"] = make(map[int]xgb.NewErrorFun)
}
const (
DPMSModeOn = 0
DPMSModeStandby = 1
DPMSModeSuspend = 2
DPMSModeOff = 3
)
// Skipping definition for base type 'Bool'
// Skipping definition for base type 'Byte'
// Skipping definition for base type 'Card8'
// Skipping definition for base type 'Char'
// Skipping definition for base type 'Void'
// Skipping definition for base type 'Double'
// Skipping definition for base type 'Float'
// Skipping definition for base type 'Int16'
// Skipping definition for base type 'Int32'
// Skipping definition for base type 'Int8'
// Skipping definition for base type 'Card16'
// Skipping definition for base type 'Card32'
// CapableCookie is a cookie used only for Capable requests.
type CapableCookie struct {
*xgb.Cookie
}
// Capable sends a checked request.
// If an error occurs, it will be returned with the reply by calling CapableCookie.Reply()
func Capable(c *xgb.Conn) CapableCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'Capable' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(capableRequest(c), cookie)
return CapableCookie{cookie}
}
// CapableUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func CapableUnchecked(c *xgb.Conn) CapableCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'Capable' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(capableRequest(c), cookie)
return CapableCookie{cookie}
}
// CapableReply represents the data returned from a Capable request.
type CapableReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
Capable bool
// padding: 23 bytes
}
// Reply blocks and returns the reply data for a Capable request.
func (cook CapableCookie) Reply() (*CapableReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return capableReply(buf), nil
}
// capableReply reads a byte slice into a CapableReply value.
func capableReply(buf []byte) *CapableReply {
v := new(CapableReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
if buf[b] == 1 {
v.Capable = true
} else {
v.Capable = false
}
b += 1
b += 23 // padding
return v
}
// Write request to wire for Capable
// capableRequest writes a Capable request to a byte slice.
func capableRequest(c *xgb.Conn) []byte {
size := 4
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["DPMS"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 1 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
return buf
}
// DisableCookie is a cookie used only for Disable requests.
type DisableCookie struct {
*xgb.Cookie
}
// Disable sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func Disable(c *xgb.Conn) DisableCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'Disable' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(disableRequest(c), cookie)
return DisableCookie{cookie}
}
// DisableChecked sends a checked request.
// If an error occurs, it can be retrieved using DisableCookie.Check()
func DisableChecked(c *xgb.Conn) DisableCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'Disable' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(disableRequest(c), cookie)
return DisableCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook DisableCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for Disable
// disableRequest writes a Disable request to a byte slice.
func disableRequest(c *xgb.Conn) []byte {
size := 4
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["DPMS"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 5 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
return buf
}
// EnableCookie is a cookie used only for Enable requests.
type EnableCookie struct {
*xgb.Cookie
}
// Enable sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func Enable(c *xgb.Conn) EnableCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'Enable' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(enableRequest(c), cookie)
return EnableCookie{cookie}
}
// EnableChecked sends a checked request.
// If an error occurs, it can be retrieved using EnableCookie.Check()
func EnableChecked(c *xgb.Conn) EnableCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'Enable' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(enableRequest(c), cookie)
return EnableCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook EnableCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for Enable
// enableRequest writes a Enable request to a byte slice.
func enableRequest(c *xgb.Conn) []byte {
size := 4
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["DPMS"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 4 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
return buf
}
// ForceLevelCookie is a cookie used only for ForceLevel requests.
type ForceLevelCookie struct {
*xgb.Cookie
}
// ForceLevel sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func ForceLevel(c *xgb.Conn, PowerLevel uint16) ForceLevelCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'ForceLevel' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(forceLevelRequest(c, PowerLevel), cookie)
return ForceLevelCookie{cookie}
}
// ForceLevelChecked sends a checked request.
// If an error occurs, it can be retrieved using ForceLevelCookie.Check()
func ForceLevelChecked(c *xgb.Conn, PowerLevel uint16) ForceLevelCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'ForceLevel' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(forceLevelRequest(c, PowerLevel), cookie)
return ForceLevelCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook ForceLevelCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for ForceLevel
// forceLevelRequest writes a ForceLevel request to a byte slice.
func forceLevelRequest(c *xgb.Conn, PowerLevel uint16) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["DPMS"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 6 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put16(buf[b:], PowerLevel)
b += 2
return buf
}
// GetTimeoutsCookie is a cookie used only for GetTimeouts requests.
type GetTimeoutsCookie struct {
*xgb.Cookie
}
// GetTimeouts sends a checked request.
// If an error occurs, it will be returned with the reply by calling GetTimeoutsCookie.Reply()
func GetTimeouts(c *xgb.Conn) GetTimeoutsCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'GetTimeouts' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(getTimeoutsRequest(c), cookie)
return GetTimeoutsCookie{cookie}
}
// GetTimeoutsUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func GetTimeoutsUnchecked(c *xgb.Conn) GetTimeoutsCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'GetTimeouts' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(getTimeoutsRequest(c), cookie)
return GetTimeoutsCookie{cookie}
}
// GetTimeoutsReply represents the data returned from a GetTimeouts request.
type GetTimeoutsReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
StandbyTimeout uint16
SuspendTimeout uint16
OffTimeout uint16
// padding: 18 bytes
}
// Reply blocks and returns the reply data for a GetTimeouts request.
func (cook GetTimeoutsCookie) Reply() (*GetTimeoutsReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return getTimeoutsReply(buf), nil
}
// getTimeoutsReply reads a byte slice into a GetTimeoutsReply value.
func getTimeoutsReply(buf []byte) *GetTimeoutsReply {
v := new(GetTimeoutsReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.StandbyTimeout = xgb.Get16(buf[b:])
b += 2
v.SuspendTimeout = xgb.Get16(buf[b:])
b += 2
v.OffTimeout = xgb.Get16(buf[b:])
b += 2
b += 18 // padding
return v
}
// Write request to wire for GetTimeouts
// getTimeoutsRequest writes a GetTimeouts request to a byte slice.
func getTimeoutsRequest(c *xgb.Conn) []byte {
size := 4
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["DPMS"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 2 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
return buf
}
// GetVersionCookie is a cookie used only for GetVersion requests.
type GetVersionCookie struct {
*xgb.Cookie
}
// GetVersion sends a checked request.
// If an error occurs, it will be returned with the reply by calling GetVersionCookie.Reply()
func GetVersion(c *xgb.Conn, ClientMajorVersion uint16, ClientMinorVersion uint16) GetVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'GetVersion' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(getVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return GetVersionCookie{cookie}
}
// GetVersionUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func GetVersionUnchecked(c *xgb.Conn, ClientMajorVersion uint16, ClientMinorVersion uint16) GetVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'GetVersion' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(getVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return GetVersionCookie{cookie}
}
// GetVersionReply represents the data returned from a GetVersion request.
type GetVersionReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
ServerMajorVersion uint16
ServerMinorVersion uint16
}
// Reply blocks and returns the reply data for a GetVersion request.
func (cook GetVersionCookie) Reply() (*GetVersionReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return getVersionReply(buf), nil
}
// getVersionReply reads a byte slice into a GetVersionReply value.
func getVersionReply(buf []byte) *GetVersionReply {
v := new(GetVersionReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.ServerMajorVersion = xgb.Get16(buf[b:])
b += 2
v.ServerMinorVersion = xgb.Get16(buf[b:])
b += 2
return v
}
// Write request to wire for GetVersion
// getVersionRequest writes a GetVersion request to a byte slice.
func getVersionRequest(c *xgb.Conn, ClientMajorVersion uint16, ClientMinorVersion uint16) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["DPMS"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 0 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put16(buf[b:], ClientMajorVersion)
b += 2
xgb.Put16(buf[b:], ClientMinorVersion)
b += 2
return buf
}
// InfoCookie is a cookie used only for Info requests.
type InfoCookie struct {
*xgb.Cookie
}
// Info sends a checked request.
// If an error occurs, it will be returned with the reply by calling InfoCookie.Reply()
func Info(c *xgb.Conn) InfoCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'Info' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(infoRequest(c), cookie)
return InfoCookie{cookie}
}
// InfoUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func InfoUnchecked(c *xgb.Conn) InfoCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'Info' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(infoRequest(c), cookie)
return InfoCookie{cookie}
}
// InfoReply represents the data returned from a Info request.
type InfoReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
PowerLevel uint16
State bool
// padding: 21 bytes
}
// Reply blocks and returns the reply data for a Info request.
func (cook InfoCookie) Reply() (*InfoReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return infoReply(buf), nil
}
// infoReply reads a byte slice into a InfoReply value.
func infoReply(buf []byte) *InfoReply {
v := new(InfoReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.PowerLevel = xgb.Get16(buf[b:])
b += 2
if buf[b] == 1 {
v.State = true
} else {
v.State = false
}
b += 1
b += 21 // padding
return v
}
// Write request to wire for Info
// infoRequest writes a Info request to a byte slice.
func infoRequest(c *xgb.Conn) []byte {
size := 4
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["DPMS"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 7 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
return buf
}
// SetTimeoutsCookie is a cookie used only for SetTimeouts requests.
type SetTimeoutsCookie struct {
*xgb.Cookie
}
// SetTimeouts sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func SetTimeouts(c *xgb.Conn, StandbyTimeout uint16, SuspendTimeout uint16, OffTimeout uint16) SetTimeoutsCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'SetTimeouts' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(setTimeoutsRequest(c, StandbyTimeout, SuspendTimeout, OffTimeout), cookie)
return SetTimeoutsCookie{cookie}
}
// SetTimeoutsChecked sends a checked request.
// If an error occurs, it can be retrieved using SetTimeoutsCookie.Check()
func SetTimeoutsChecked(c *xgb.Conn, StandbyTimeout uint16, SuspendTimeout uint16, OffTimeout uint16) SetTimeoutsCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["DPMS"]; !ok {
panic("Cannot issue request 'SetTimeouts' using the uninitialized extension 'DPMS'. dpms.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(setTimeoutsRequest(c, StandbyTimeout, SuspendTimeout, OffTimeout), cookie)
return SetTimeoutsCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook SetTimeoutsCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for SetTimeouts
// setTimeoutsRequest writes a SetTimeouts request to a byte slice.
func setTimeoutsRequest(c *xgb.Conn, StandbyTimeout uint16, SuspendTimeout uint16, OffTimeout uint16) []byte {
size := 12
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["DPMS"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 3 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put16(buf[b:], StandbyTimeout)
b += 2
xgb.Put16(buf[b:], SuspendTimeout)
b += 2
xgb.Put16(buf[b:], OffTimeout)
b += 2
return buf
}

1821
vend/xgb/dri2/dri2.go Normal file

File diff suppressed because it is too large Load Diff

3
vend/xgb/examples/atoms/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
atoms
*.info
*.prof

View File

@ -0,0 +1,12 @@
atoms:
go build
test: atoms
./atoms --requests 500000 --cpu 1 \
--cpuprof cpu1.prof --memprof mem1.prof > atoms1.info 2>&1
./atoms --requests 500000 --cpu 2 \
--cpuprof cpu2.prof --memprof mem2.prof > atoms2.info 2>&1
./atoms --requests 500000 --cpu 3 \
--cpuprof cpu3.prof --memprof mem3.prof > atoms3.info 2>&1
./atoms --requests 500000 --cpu 6 \
--cpuprof cpu6.prof --memprof mem6.prof > atoms6.info 2>&1

View File

@ -0,0 +1,91 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"runtime"
"runtime/pprof"
"time"
"github.com/jezek/xgb"
"github.com/jezek/xgb/xproto"
)
var (
flagRequests int
flagGOMAXPROCS int
flagCpuProfName string
flagMemProfName string
)
func init() {
flag.IntVar(&flagRequests, "requests", 100000, "Number of atoms to intern.")
flag.IntVar(&flagGOMAXPROCS, "cpu", 1, "Value of GOMAXPROCS.")
flag.StringVar(&flagCpuProfName, "cpuprof", "cpu.prof",
"Name of CPU profile file.")
flag.StringVar(&flagMemProfName, "memprof", "mem.prof",
"Name of memory profile file.")
flag.Parse()
runtime.GOMAXPROCS(flagGOMAXPROCS)
}
func seqNames(n int) []string {
names := make([]string, n)
for i := range names {
names[i] = fmt.Sprintf("NAME%d", i)
}
return names
}
func main() {
X, err := xgb.NewConn()
if err != nil {
log.Fatal(err)
}
names := seqNames(flagRequests)
fcpu, err := os.Create(flagCpuProfName)
if err != nil {
log.Fatal(err)
}
defer fcpu.Close()
pprof.StartCPUProfile(fcpu)
defer pprof.StopCPUProfile()
start := time.Now()
cookies := make([]xproto.InternAtomCookie, flagRequests)
for i := 0; i < flagRequests; i++ {
cookies[i] = xproto.InternAtom(X,
false, uint16(len(names[i])), names[i])
}
for _, cookie := range cookies {
cookie.Reply()
}
fmt.Printf("Exec time: %s\n\n", time.Since(start))
fmem, err := os.Create(flagMemProfName)
if err != nil {
log.Fatal(err)
}
defer fmem.Close()
pprof.WriteHeapProfile(fmem)
memStats := &runtime.MemStats{}
runtime.ReadMemStats(memStats)
// This isn't right. I'm not sure what's wrong.
lastGcTime := time.Unix(int64(memStats.LastGC/1000000000),
int64(memStats.LastGC-memStats.LastGC/1000000000))
fmt.Printf("Alloc: %d\n", memStats.Alloc)
fmt.Printf("TotalAlloc: %d\n", memStats.TotalAlloc)
fmt.Printf("LastGC: %s\n", lastGcTime)
fmt.Printf("PauseTotalNs: %d\n", memStats.PauseTotalNs)
fmt.Printf("PauseNs: %d\n", memStats.PauseNs)
fmt.Printf("NumGC: %d\n", memStats.NumGC)
}

View File

@ -0,0 +1,148 @@
// 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). The events are printed to stdout.
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
}
defer X.Close()
// xproto.Setup retrieves the Setup information from the setup bytes
// gathered during connection.
setup := xproto.Setup(X)
// This is the default screen with all its associated info.
screen := setup.DefaultScreen(X)
// Any time a new resource (i.e., a window, pixmap, graphics context, etc.)
// is created, we need to generate a resource identifier.
// If the resource is a window, then use xproto.NewWindowId. If it's for
// a pixmap, then use xproto.NewPixmapId. And so on...
wid, _ := xproto.NewWindowId(X)
// CreateWindow takes a boatload of parameters.
xproto.CreateWindow(X, screen.RootDepth, wid, screen.Root,
0, 0, 500, 500, 0,
xproto.WindowClassInputOutput, screen.RootVisual, 0, []uint32{})
// This call to ChangeWindowAttributes could be factored out and
// included with the above CreateWindow call, but it is left here for
// instructive purposes. It tells X to send us events when the 'structure'
// of the window is changed (i.e., when it is resized, mapped, unmapped,
// etc.) and when a key press or a key release has been made when the
// window has focus.
// We also set the 'BackPixel' to white so that the window isn't butt ugly.
xproto.ChangeWindowAttributes(X, wid,
xproto.CwBackPixel|xproto.CwEventMask,
[]uint32{ // values must be in the order defined by the protocol
0xffffffff,
xproto.EventMaskStructureNotify |
xproto.EventMaskKeyPress |
xproto.EventMaskKeyRelease,
})
// MapWindow makes the window we've created appear on the screen.
// We demonstrated the use of a 'checked' request here.
// A checked request is a fancy way of saying, "do error handling
// synchronously." Namely, if there is a problem with the MapWindow request,
// we'll get the error *here*. If we were to do a normal unchecked
// request (like the above CreateWindow and ChangeWindowAttributes
// requests), then we would only see the error arrive in the main event
// loop.
//
// Typically, checked requests are useful when you need to make sure they
// succeed. Since they are synchronous, they incur a round trip cost before
// the program can continue, but this is only going to be noticeable if
// you're issuing tons of requests in succession.
//
// Note that requests without replies are by default unchecked while
// requests *with* replies are checked by default.
err = xproto.MapWindowChecked(X, wid).Check()
if err != nil {
fmt.Printf("Checked Error for mapping window %d: %s\n", wid, err)
} else {
fmt.Printf("Map window %d successful!\n", wid)
}
// This is an example of an invalid MapWindow request and what an error
// looks like.
err = xproto.MapWindowChecked(X, 0).Check()
if err != nil {
fmt.Printf("Checked Error for mapping window 0x1: %s\n", err)
} else { // neva
fmt.Printf("Map window 0x1 successful!\n")
}
// Start the main event loop.
for {
// WaitForEvent either returns an event or an error and never both.
// If both are nil, then something went wrong and the loop should be
// halted.
//
// An error can only be seen here as a response to an unchecked
// request.
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)
}
// This is how accepting events work:
// The application checks what event we got and reacts to it
// accordingly. All events are defined in the xproto subpackage.
// To receive events, we have to first register it using
// either xproto.CreateWindow or xproto.ChangeWindowAttributes.
switch ev.(type) {
case xproto.KeyPressEvent:
// See https://pkg.go.dev/github.com/jezek/xgb/xproto#KeyPressEvent
// for documentation about a key press event.
kpe := ev.(xproto.KeyPressEvent)
fmt.Printf("Key pressed: %d\n", kpe.Detail)
// The Detail value depends on the keyboard layout,
// for QWERTY, q is #24.
if kpe.Detail == 24 {
return // exit on q
}
case xproto.DestroyNotifyEvent:
// Depending on the user's desktop environment (especially
// window manager), killing a window might close the
// client's X connection (e. g. the default Ubuntu
// desktop environment).
//
// If that's the case for your environment, closing this example's window
// will also close the underlying Go program (because closing the X
// connection gives a nil event and EOF error).
//
// Consider how a single application might have multiple windows
// (e.g. an open popup or dialog, ...)
//
// With other DEs, the X connection will still stay open even after the
// X window is closed. For these DEs (e.g. i3) we have to check whether
// the WM sent us a DestroyNotifyEvent and close our program.
//
// For more information about closing windows while maintaining
// the X connection see
// https://github.com/jezek/xgbutil/blob/master/_examples/graceful-window-close/main.go
return
}
}
}

21
vend/xgb/examples/doc.go Normal file
View File

@ -0,0 +1,21 @@
/*
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.
If you're looking to get started quickly, I recommend checking out the
create-window example first. It is the most documented and probably covers
some of the more common bare bones cases of creating windows and responding
to events.
If you're looking to query information about your window manager,
get-active-window is a start. However, to do anything extensive requires
a lot of boiler plate. To that end, I'd recommend use of a higher level
library (eg. xgbutil: https://github.com/jezek/xgbutil).
There are also examples of using the Xinerama and RandR extensions, if you're
interested in querying information about your active heads. In RandR's case,
you can also reconfigure your heads, but the example doesn't cover that.
*/
package documentation

View File

@ -0,0 +1,61 @@
// 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.
package main
import (
"fmt"
"log"
"github.com/jezek/xgb"
"github.com/jezek/xgb/xproto"
)
func main() {
X, err := xgb.NewConn()
if err != nil {
log.Fatal(err)
}
// Get the window id of the root window.
setup := xproto.Setup(X)
root := setup.DefaultScreen(X).Root
// Get the atom id (i.e., intern an atom) of "_NET_ACTIVE_WINDOW".
aname := "_NET_ACTIVE_WINDOW"
activeAtom, err := xproto.InternAtom(X, true, uint16(len(aname)),
aname).Reply()
if err != nil {
log.Fatal(err)
}
// Get the atom id (i.e., intern an atom) of "_NET_WM_NAME".
aname = "_NET_WM_NAME"
nameAtom, err := xproto.InternAtom(X, true, uint16(len(aname)),
aname).Reply()
if err != nil {
log.Fatal(err)
}
// Get the actual value of _NET_ACTIVE_WINDOW.
// Note that 'reply.Value' is just a slice of bytes, so we use an
// XGB helper function, 'Get32', to pull an unsigned 32-bit integer out
// of the byte slice. We then convert it to an X resource id so it can
// be used to get the name of the window in the next GetProperty request.
reply, err := xproto.GetProperty(X, false, root, activeAtom.Atom,
xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply()
if err != nil {
log.Fatal(err)
}
windowId := xproto.Window(xgb.Get32(reply.Value))
fmt.Printf("Active window id: %X\n", windowId)
// Now get the value of _NET_WM_NAME for the active window.
// Note that this time, we simply convert the resulting byte slice,
// reply.Value, to a string.
reply, err = xproto.GetProperty(X, false, windowId, nameAtom.Atom,
xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Active window name: %s\n", string(reply.Value))
}

View File

@ -0,0 +1,92 @@
// Example randr uses the randr protocol to get information about the active
// heads. It also listens for events that are sent when the head configuration
// changes. Since it listens to events, you'll have to manually kill this
// process when you're done (i.e., ctrl+c.)
//
// While this program is running, if you use 'xrandr' to reconfigure your
// heads, you should see event information dumped to standard out.
//
// For more information, please see the RandR protocol spec:
// http://www.x.org/releases/X11R7.6/doc/randrproto/randrproto.txt
package main
import (
"fmt"
"log"
"github.com/jezek/xgb"
"github.com/jezek/xgb/randr"
"github.com/jezek/xgb/xproto"
)
func main() {
X, _ := xgb.NewConn()
// Every extension must be initialized before it can be used.
err := randr.Init(X)
if err != nil {
log.Fatal(err)
}
// Get the root window on the default screen.
root := xproto.Setup(X).DefaultScreen(X).Root
// Gets the current screen resources. Screen resources contains a list
// of names, crtcs, outputs and modes, among other things.
resources, err := randr.GetScreenResources(X, root).Reply()
if err != nil {
log.Fatal(err)
}
// Iterate through all of the outputs and show some of their info.
for _, output := range resources.Outputs {
info, err := randr.GetOutputInfo(X, output, 0).Reply()
if err != nil {
log.Fatal(err)
}
if info.Connection == randr.ConnectionConnected {
bestMode := info.Modes[0]
for _, mode := range resources.Modes {
if mode.Id == uint32(bestMode) {
fmt.Printf("Width: %d, Height: %d\n",
mode.Width, mode.Height)
}
}
}
}
fmt.Println("")
// Iterate through all of the crtcs and show some of their info.
for _, crtc := range resources.Crtcs {
info, err := randr.GetCrtcInfo(X, crtc, 0).Reply()
if err != nil {
log.Fatal(err)
}
fmt.Printf("X: %d, Y: %d, Width: %d, Height: %d\n",
info.X, info.Y, info.Width, info.Height)
}
// Tell RandR to send us events. (I think these are all of them, as of 1.3.)
err = randr.SelectInputChecked(X, root,
randr.NotifyMaskScreenChange|
randr.NotifyMaskCrtcChange|
randr.NotifyMaskOutputChange|
randr.NotifyMaskOutputProperty).Check()
if err != nil {
log.Fatal(err)
}
// Listen to events and just dump them to standard out.
// A more involved approach will have to read the 'U' field of
// RandrNotifyEvent, which is a union (really a struct) of type
// RanrNotifyDataUnion.
for {
ev, err := X.WaitForEvent()
if err != nil {
log.Fatal(err)
}
fmt.Println(ev)
}
}

View File

@ -0,0 +1,306 @@
// The shapes example shows how to draw basic shapes into a window.
// It can be considered the Go equivalent of
// https://x.org/releases/X11R7.5/doc/libxcb/tutorial/#drawingprim
// Four points, a single polyline, two line segments,
// two rectangles and two arcs are drawn.
// In addition to this, we will also write some text
// and fill a rectangle.
package main
import (
"fmt"
"unicode/utf16"
"github.com/jezek/xgb"
"github.com/jezek/xgb/xproto"
)
func main() {
X, err := xgb.NewConn()
if err != nil {
fmt.Println("error connecting to X:", err)
return
}
defer X.Close()
setup := xproto.Setup(X)
screen := setup.DefaultScreen(X)
wid, err := xproto.NewWindowId(X)
if err != nil {
fmt.Println("error creating window id:", err)
return
}
draw := xproto.Drawable(wid) // for now, we simply draw into the window
// Create the window
xproto.CreateWindow(X, screen.RootDepth, wid, screen.Root,
0, 0, 180, 200, 8, // X, Y, width, height, *border width*
xproto.WindowClassInputOutput, screen.RootVisual,
xproto.CwBackPixel|xproto.CwEventMask,
[]uint32{screen.WhitePixel, xproto.EventMaskStructureNotify | xproto.EventMaskExposure})
// Map the window on the screen
xproto.MapWindow(X, wid)
// Up to here everything is the same as in the `create-window` example.
// We opened a connection, created and mapped the window.
// But this time we'll be drawing some basic shapes.
// Note how this time the border width is set to 8 instead of 0.
//
// First of all we need to create a context to draw with.
// The graphics context combines all properties (e.g. color, line width, font, fill style, ...)
// that should be used to draw something. All available properties
//
// These properties can be set by or'ing their keys (xproto.Gc*)
// and adding the value to the end of the values array.
// The order in which the values have to be given corresponds to the order that they defined
// mentioned in `xproto`.
//
// Here we create a new graphics context
// which only has the foreground (color) value set to black:
foreground, err := xproto.NewGcontextId(X)
if err != nil {
fmt.Println("error creating foreground context:", err)
return
}
mask := uint32(xproto.GcForeground)
values := []uint32{screen.BlackPixel}
xproto.CreateGC(X, foreground, draw, mask, values)
// It is possible to set the foreground value to something different.
// In production, this should use xorg color maps instead for compatibility
// but for demonstration setting the color directly also works.
// For more information on color maps, see the xcb documentation:
// https://x.org/releases/X11R7.5/doc/libxcb/tutorial/#usecolor
red, err := xproto.NewGcontextId(X)
if err != nil {
fmt.Println("error creating red context:", err)
return
}
mask = uint32(xproto.GcForeground)
values = []uint32{0xff0000}
xproto.CreateGC(X, red, draw, mask, values)
// We'll create another graphics context that draws thick lines:
thick, err := xproto.NewGcontextId(X)
if err != nil {
fmt.Println("error creating thick context:", err)
return
}
mask = uint32(xproto.GcLineWidth)
values = []uint32{10}
xproto.CreateGC(X, thick, draw, mask, values)
// It is even possible to set multiple properties at once.
// Only remember to put the values in the same order as they're
// defined in `xproto`:
// Foreground is defined first, so we also set it's value first.
// LineWidth comes second.
blue, err := xproto.NewGcontextId(X)
if err != nil {
fmt.Println("error creating blue context:", err)
return
}
mask = uint32(xproto.GcForeground | xproto.GcLineWidth)
values = []uint32{0x0000ff, 4}
xproto.CreateGC(X, blue, draw, mask, values)
// Properties of an already created gc can also be changed
// if the original values aren't needed anymore.
// In this case, we will change the line width
// and cap (line corner) style of our foreground context,
// to smooth out the polyline:
mask = uint32(xproto.GcLineWidth | xproto.GcCapStyle)
values = []uint32{3, xproto.CapStyleRound}
xproto.ChangeGC(X, foreground, mask, values)
// Writing text needs a bit more setup -- we first have
// to open the required font.
font, err := xproto.NewFontId(X)
if err != nil {
fmt.Println("error creating font id:", err)
return
}
// The font identifier that has to be passed to X for opening the font
// sets all font properties:
// publisher-family-weight-slant-width-adstyl-pxlsz-ptSz-resx-resy-spc-avgWidth-registry-encoding
// For all available fonts, install and run xfontsel.
//
// To load any available font, set all fields to an asterisk.
// To specify a font, set one or multiple fields.
// This can also be seen in xfontsel -- initially every field is set to *,
// however, the more fields are set, the fewer fonts match.
//
// Using a specific font (e.g. Gnu Unifont) can be as easy as
// "-gnu-unifont-*-*-*-*-16-*-*-*-*-*-*-*"
//
// To load any font that is encoded for usage
// with Unicode characters, one would use
// fontname := "-*-*-*-*-*-*-14-*-*-*-*-*-iso10646-1"
//
// For now, we'll simply stick with the fixed font which is available
// to every X session:
fontname := "-*-fixed-*-*-*-*-14-*-*-*-*-*-*-*"
err = xproto.OpenFontChecked(X, font, uint16(len(fontname)), fontname).Check()
if err != nil {
fmt.Println("failed opening the font:", err)
return
}
// And create a context from it. We simply pass the font's ID to the GcFont property.
textCtx, err := xproto.NewGcontextId(X)
if err != nil {
fmt.Println("error creating text context:", err)
return
}
mask = uint32(xproto.GcForeground | xproto.GcBackground | xproto.GcFont)
values = []uint32{screen.BlackPixel, screen.WhitePixel, uint32(font)}
xproto.CreateGC(X, textCtx, draw, mask, values)
text := convertStringToChar2b("Hellö World!") // Unicode capable!
// Close the font handle:
xproto.CloseFont(X, font)
// After all, writing text is way more comfortable using Xft - it supports TrueType,
// and overall better configuration.
points := []xproto.Point{
{X: 10, Y: 10},
{X: 20, Y: 10},
{X: 30, Y: 10},
{X: 40, Y: 10},
}
// A polyline is essentially a line with multiple points.
// The first point is placed absolutely inside the window,
// while every other point is placed relative to the one before it.
polyline := []xproto.Point{
{X: 50, Y: 10},
{X: 5, Y: 20}, // move 5 to the right, 20 down
{X: 25, Y: -20}, // move 25 to the right, 20 up - notice how this point is level again with the first point
{X: 10, Y: 10}, // move 10 to the right, 10 down
}
segments := []xproto.Segment{
{X1: 100, Y1: 10, X2: 140, Y2: 30},
{X1: 110, Y1: 25, X2: 130, Y2: 60},
{X1: 0, Y1: 160, X2: 90, Y2: 100},
}
// Rectangles have a start coordinate (upper left) and width and height.
rectangles := []xproto.Rectangle{
{X: 10, Y: 50, Width: 40, Height: 20},
{X: 80, Y: 50, Width: 10, Height: 40},
}
// This rectangle we will use to demonstrate filling a shape.
rectangles2 := []xproto.Rectangle{
{X: 150, Y: 50, Width: 20, Height: 60},
}
// Arcs are defined by a top left position (notice where the third line goes to)
// their width and height, a starting and end angle.
// Angles are defined in units of 1/64 of a single degree,
// so we have to multiply the degrees by 64 (or left shift them by 6).
arcs := []xproto.Arc{
{X: 10, Y: 100, Width: 60, Height: 40, Angle1: 0 << 6, Angle2: 90 << 6},
{X: 90, Y: 100, Width: 55, Height: 40, Angle1: 20 << 6, Angle2: 270 << 6},
}
for {
evt, err := X.WaitForEvent()
if err != nil {
fmt.Println("error reading event:", err)
return
} else if evt == nil {
return
}
switch evt.(type) {
case xproto.ExposeEvent:
// Draw the four points we specified earlier.
// Notice how we use the `foreground` context to draw them in black.
// Also notice how even though we changed the line width to 3,
// these still only appear as a single pixel.
// To draw points that are bigger than a single pixel,
// one has to either fill rectangles, circles or polygons.
xproto.PolyPoint(X, xproto.CoordModeOrigin, draw, foreground, points)
// Draw the polyline. This time we specified `xproto.CoordModePrevious`,
// which means that every point is placed relatively to the previous.
// If we were to use `xproto.CoordModeOrigin` instead,
// we could specify each point absolutely on the screen.
// It is also possible to use `xproto.CoordModePrevious` for drawing *points*
// which means that each point would be specified relative to the previous one,
// just as we did with the polyline.
xproto.PolyLine(X, xproto.CoordModePrevious, draw, foreground, polyline)
// Draw two lines in red.
xproto.PolySegment(X, draw, red, segments)
// Draw two thick rectangles.
// The line width only specifies the width of the outline.
// Notice how the second rectangle gets completely filled
// due to the line width.
xproto.PolyRectangle(X, draw, thick, rectangles)
// Draw the circular arcs in blue.
xproto.PolyArc(X, draw, blue, arcs)
// There's also a fill variant for all drawing commands:
xproto.PolyFillRectangle(X, draw, red, rectangles2)
// Draw the text. Xorg currently knows two ways of specifying text:
// a) the (extended) ASCII encoding using ImageText8(..., []byte)
// b) UTF16 encoding using ImageText16(..., []Char2b) -- Char2b is
// a structure consisting of two bytes.
// At the bottom of this example, there are two utility functions that help
// convert a go string into an array of Char2b's.
xproto.ImageText16(X, byte(len(text)), draw, textCtx, 10, 160, text)
case xproto.DestroyNotifyEvent:
return
}
}
}
// Char2b is defined as
// Byte1 byte
// Byte2 byte
// and is used as a utf16 character.
// This function takes a string and converts each rune into a char2b.
func convertStringToChar2b(s string) []xproto.Char2b {
var chars []xproto.Char2b
var p []uint16
for _, r := range []rune(s) {
p = utf16.Encode([]rune{r})
if len(p) == 1 {
chars = append(chars, convertUint16ToChar2b(p[0]))
} else {
// If the utf16 representation is larger than 2 bytes
// we can not use it and insert a blank instead:
chars = append(chars, xproto.Char2b{Byte1: 0, Byte2: 32})
}
}
return chars
}
// convertUint16ToChar2b converts a uint16 (which is basically two bytes)
// into a Char2b by using the higher 8 bits of u as Byte1
// and the lower 8 bits of u as Byte2.
func convertUint16ToChar2b(u uint16) xproto.Char2b {
return xproto.Char2b{
Byte1: byte((u & 0xff00) >> 8),
Byte2: byte((u & 0x00ff)),
}
}

View File

@ -0,0 +1,40 @@
// Example xinerama shows how to query the geometry of all active heads.
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)
}
// Issue a request to get the screen information.
reply, err := xinerama.QueryScreens(X).Reply()
if err != nil {
log.Fatal(err)
}
// reply.Number is the number of active heads, while reply.ScreenInfo
// is a slice of XineramaScreenInfo containing the rectangle geometry
// of each head.
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)
}
}

165
vend/xgb/ge/ge.go Normal file
View File

@ -0,0 +1,165 @@
// Package ge is the X client API for the Generic Event Extension extension.
package ge
// This file is automatically generated from ge.xml. Edit at your peril!
import (
"github.com/jezek/xgb"
"github.com/jezek/xgb/xproto"
)
// Init must be called before using the Generic Event Extension extension.
func Init(c *xgb.Conn) error {
reply, err := xproto.QueryExtension(c, 23, "Generic Event Extension").Reply()
switch {
case err != nil:
return err
case !reply.Present:
return xgb.Errorf("No extension named Generic Event Extension could be found on on the server.")
}
c.ExtLock.Lock()
c.Extensions["Generic Event Extension"] = reply.MajorOpcode
c.ExtLock.Unlock()
for evNum, fun := range xgb.NewExtEventFuncs["Generic Event Extension"] {
xgb.NewEventFuncs[int(reply.FirstEvent)+evNum] = fun
}
for errNum, fun := range xgb.NewExtErrorFuncs["Generic Event Extension"] {
xgb.NewErrorFuncs[int(reply.FirstError)+errNum] = fun
}
return nil
}
func init() {
xgb.NewExtEventFuncs["Generic Event Extension"] = make(map[int]xgb.NewEventFun)
xgb.NewExtErrorFuncs["Generic Event Extension"] = make(map[int]xgb.NewErrorFun)
}
// Skipping definition for base type 'Bool'
// Skipping definition for base type 'Byte'
// Skipping definition for base type 'Card8'
// Skipping definition for base type 'Char'
// Skipping definition for base type 'Void'
// Skipping definition for base type 'Double'
// Skipping definition for base type 'Float'
// Skipping definition for base type 'Int16'
// Skipping definition for base type 'Int32'
// Skipping definition for base type 'Int8'
// Skipping definition for base type 'Card16'
// Skipping definition for base type 'Card32'
// QueryVersionCookie is a cookie used only for QueryVersion requests.
type QueryVersionCookie struct {
*xgb.Cookie
}
// QueryVersion sends a checked request.
// If an error occurs, it will be returned with the reply by calling QueryVersionCookie.Reply()
func QueryVersion(c *xgb.Conn, ClientMajorVersion uint16, ClientMinorVersion uint16) QueryVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Generic Event Extension"]; !ok {
panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'Generic Event Extension'. ge.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(queryVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return QueryVersionCookie{cookie}
}
// QueryVersionUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func QueryVersionUnchecked(c *xgb.Conn, ClientMajorVersion uint16, ClientMinorVersion uint16) QueryVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["Generic Event Extension"]; !ok {
panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'Generic Event Extension'. ge.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(queryVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return QueryVersionCookie{cookie}
}
// QueryVersionReply represents the data returned from a QueryVersion request.
type QueryVersionReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
MajorVersion uint16
MinorVersion uint16
// padding: 20 bytes
}
// Reply blocks and returns the reply data for a QueryVersion request.
func (cook QueryVersionCookie) Reply() (*QueryVersionReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return queryVersionReply(buf), nil
}
// queryVersionReply reads a byte slice into a QueryVersionReply value.
func queryVersionReply(buf []byte) *QueryVersionReply {
v := new(QueryVersionReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.MajorVersion = xgb.Get16(buf[b:])
b += 2
v.MinorVersion = xgb.Get16(buf[b:])
b += 2
b += 20 // padding
return v
}
// Write request to wire for QueryVersion
// queryVersionRequest writes a QueryVersion request to a byte slice.
func queryVersionRequest(c *xgb.Conn, ClientMajorVersion uint16, ClientMinorVersion uint16) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["Generic Event Extension"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 0 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put16(buf[b:], ClientMajorVersion)
b += 2
xgb.Put16(buf[b:], ClientMinorVersion)
b += 2
return buf
}

10930
vend/xgb/glx/glx.go Normal file

File diff suppressed because it is too large Load Diff

3
vend/xgb/go.mod Normal file
View File

@ -0,0 +1,3 @@
module github.com/jezek/xgb
go 1.11

105
vend/xgb/help.go Normal file
View File

@ -0,0 +1,105 @@
package xgb
/*
help.go is meant to contain a rough hodge podge of functions that are mainly
used in the auto generated code. Indeed, several functions here are simple
wrappers so that the sub-packages don't need to be smart about which stdlib
packages to import.
Also, the 'Get..' and 'Put..' functions are used through the core xgb package
too. (xgbutil uses them too.)
*/
import (
"fmt"
"strings"
)
// StringsJoin is an alias to strings.Join. It allows us to avoid having to
// import 'strings' in each of the generated Go files.
func StringsJoin(ss []string, sep string) string {
return strings.Join(ss, sep)
}
// Sprintf is so we don't need to import 'fmt' in the generated Go files.
func Sprintf(format string, v ...interface{}) string {
return fmt.Sprintf(format, v...)
}
// Errorf is just a wrapper for fmt.Errorf. Exists for the same reason
// that 'stringsJoin' and 'sprintf' exists.
func Errorf(format string, v ...interface{}) error {
return fmt.Errorf(format, v...)
}
// Pad a length to align on 4 bytes.
func Pad(n int) int {
return (n + 3) & ^3
}
// PopCount counts the number of bits set in a value list mask.
func PopCount(mask0 int) int {
mask := uint32(mask0)
n := 0
for i := uint32(0); i < 32; i++ {
if mask&(1<<i) != 0 {
n++
}
}
return n
}
// Put16 takes a 16 bit integer and copies it into a byte slice.
func Put16(buf []byte, v uint16) {
buf[0] = byte(v)
buf[1] = byte(v >> 8)
}
// Put32 takes a 32 bit integer and copies it into a byte slice.
func Put32(buf []byte, v uint32) {
buf[0] = byte(v)
buf[1] = byte(v >> 8)
buf[2] = byte(v >> 16)
buf[3] = byte(v >> 24)
}
// Put64 takes a 64 bit integer and copies it into a byte slice.
func Put64(buf []byte, v uint64) {
buf[0] = byte(v)
buf[1] = byte(v >> 8)
buf[2] = byte(v >> 16)
buf[3] = byte(v >> 24)
buf[4] = byte(v >> 32)
buf[5] = byte(v >> 40)
buf[6] = byte(v >> 48)
buf[7] = byte(v >> 56)
}
// Get16 constructs a 16 bit integer from the beginning of a byte slice.
func Get16(buf []byte) uint16 {
v := uint16(buf[0])
v |= uint16(buf[1]) << 8
return v
}
// Get32 constructs a 32 bit integer from the beginning of a byte slice.
func Get32(buf []byte) uint32 {
v := uint32(buf[0])
v |= uint32(buf[1]) << 8
v |= uint32(buf[2]) << 16
v |= uint32(buf[3]) << 24
return v
}
// Get64 constructs a 64 bit integer from the beginning of a byte slice.
func Get64(buf []byte) uint64 {
v := uint64(buf[0])
v |= uint64(buf[1]) << 8
v |= uint64(buf[2]) << 16
v |= uint64(buf[3]) << 24
v |= uint64(buf[4]) << 32
v |= uint64(buf[5]) << 40
v |= uint64(buf[6]) << 48
v |= uint64(buf[7]) << 56
return v
}

6607
vend/xgb/randr/randr.go Normal file

File diff suppressed because it is too large Load Diff

1204
vend/xgb/record/record.go Normal file

File diff suppressed because it is too large Load Diff

4029
vend/xgb/render/render.go Normal file

File diff suppressed because it is too large Load Diff

1110
vend/xgb/res/res.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,690 @@
// Package screensaver is the X client API for the MIT-SCREEN-SAVER extension.
package screensaver
// This file is automatically generated from screensaver.xml. Edit at your peril!
import (
"github.com/jezek/xgb"
"github.com/jezek/xgb/xproto"
)
// Init must be called before using the MIT-SCREEN-SAVER extension.
func Init(c *xgb.Conn) error {
reply, err := xproto.QueryExtension(c, 16, "MIT-SCREEN-SAVER").Reply()
switch {
case err != nil:
return err
case !reply.Present:
return xgb.Errorf("No extension named MIT-SCREEN-SAVER could be found on on the server.")
}
c.ExtLock.Lock()
c.Extensions["MIT-SCREEN-SAVER"] = reply.MajorOpcode
c.ExtLock.Unlock()
for evNum, fun := range xgb.NewExtEventFuncs["MIT-SCREEN-SAVER"] {
xgb.NewEventFuncs[int(reply.FirstEvent)+evNum] = fun
}
for errNum, fun := range xgb.NewExtErrorFuncs["MIT-SCREEN-SAVER"] {
xgb.NewErrorFuncs[int(reply.FirstError)+errNum] = fun
}
return nil
}
func init() {
xgb.NewExtEventFuncs["MIT-SCREEN-SAVER"] = make(map[int]xgb.NewEventFun)
xgb.NewExtErrorFuncs["MIT-SCREEN-SAVER"] = make(map[int]xgb.NewErrorFun)
}
const (
EventNotifyMask = 1
EventCycleMask = 2
)
const (
KindBlanked = 0
KindInternal = 1
KindExternal = 2
)
// Notify is the event number for a NotifyEvent.
const Notify = 0
type NotifyEvent struct {
Sequence uint16
State byte
Time xproto.Timestamp
Root xproto.Window
Window xproto.Window
Kind byte
Forced bool
// padding: 14 bytes
}
// NotifyEventNew constructs a NotifyEvent value that implements xgb.Event from a byte slice.
func NotifyEventNew(buf []byte) xgb.Event {
v := NotifyEvent{}
b := 1 // don't read event number
v.State = buf[b]
b += 1
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Time = xproto.Timestamp(xgb.Get32(buf[b:]))
b += 4
v.Root = xproto.Window(xgb.Get32(buf[b:]))
b += 4
v.Window = xproto.Window(xgb.Get32(buf[b:]))
b += 4
v.Kind = buf[b]
b += 1
if buf[b] == 1 {
v.Forced = true
} else {
v.Forced = false
}
b += 1
b += 14 // padding
return v
}
// Bytes writes a NotifyEvent value to a byte slice.
func (v NotifyEvent) Bytes() []byte {
buf := make([]byte, 32)
b := 0
// write event number
buf[b] = 0
b += 1
buf[b] = v.State
b += 1
b += 2 // skip sequence number
xgb.Put32(buf[b:], uint32(v.Time))
b += 4
xgb.Put32(buf[b:], uint32(v.Root))
b += 4
xgb.Put32(buf[b:], uint32(v.Window))
b += 4
buf[b] = v.Kind
b += 1
if v.Forced {
buf[b] = 1
} else {
buf[b] = 0
}
b += 1
b += 14 // padding
return buf
}
// SequenceId returns the sequence id attached to the Notify event.
// Events without a sequence number (KeymapNotify) return 0.
// This is mostly used internally.
func (v NotifyEvent) SequenceId() uint16 {
return v.Sequence
}
// String is a rudimentary string representation of NotifyEvent.
func (v NotifyEvent) String() string {
fieldVals := make([]string, 0, 7)
fieldVals = append(fieldVals, xgb.Sprintf("Sequence: %d", v.Sequence))
fieldVals = append(fieldVals, xgb.Sprintf("State: %d", v.State))
fieldVals = append(fieldVals, xgb.Sprintf("Time: %d", v.Time))
fieldVals = append(fieldVals, xgb.Sprintf("Root: %d", v.Root))
fieldVals = append(fieldVals, xgb.Sprintf("Window: %d", v.Window))
fieldVals = append(fieldVals, xgb.Sprintf("Kind: %d", v.Kind))
fieldVals = append(fieldVals, xgb.Sprintf("Forced: %t", v.Forced))
return "Notify {" + xgb.StringsJoin(fieldVals, ", ") + "}"
}
func init() {
xgb.NewExtEventFuncs["MIT-SCREEN-SAVER"][0] = NotifyEventNew
}
const (
StateOff = 0
StateOn = 1
StateCycle = 2
StateDisabled = 3
)
// Skipping definition for base type 'Bool'
// Skipping definition for base type 'Byte'
// Skipping definition for base type 'Card8'
// Skipping definition for base type 'Char'
// Skipping definition for base type 'Void'
// Skipping definition for base type 'Double'
// Skipping definition for base type 'Float'
// Skipping definition for base type 'Int16'
// Skipping definition for base type 'Int32'
// Skipping definition for base type 'Int8'
// Skipping definition for base type 'Card16'
// Skipping definition for base type 'Card32'
// QueryInfoCookie is a cookie used only for QueryInfo requests.
type QueryInfoCookie struct {
*xgb.Cookie
}
// QueryInfo sends a checked request.
// If an error occurs, it will be returned with the reply by calling QueryInfoCookie.Reply()
func QueryInfo(c *xgb.Conn, Drawable xproto.Drawable) QueryInfoCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
panic("Cannot issue request 'QueryInfo' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(queryInfoRequest(c, Drawable), cookie)
return QueryInfoCookie{cookie}
}
// QueryInfoUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func QueryInfoUnchecked(c *xgb.Conn, Drawable xproto.Drawable) QueryInfoCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
panic("Cannot issue request 'QueryInfo' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(queryInfoRequest(c, Drawable), cookie)
return QueryInfoCookie{cookie}
}
// QueryInfoReply represents the data returned from a QueryInfo request.
type QueryInfoReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
State byte
SaverWindow xproto.Window
MsUntilServer uint32
MsSinceUserInput uint32
EventMask uint32
Kind byte
// padding: 7 bytes
}
// Reply blocks and returns the reply data for a QueryInfo request.
func (cook QueryInfoCookie) Reply() (*QueryInfoReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return queryInfoReply(buf), nil
}
// queryInfoReply reads a byte slice into a QueryInfoReply value.
func queryInfoReply(buf []byte) *QueryInfoReply {
v := new(QueryInfoReply)
b := 1 // skip reply determinant
v.State = buf[b]
b += 1
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.SaverWindow = xproto.Window(xgb.Get32(buf[b:]))
b += 4
v.MsUntilServer = xgb.Get32(buf[b:])
b += 4
v.MsSinceUserInput = xgb.Get32(buf[b:])
b += 4
v.EventMask = xgb.Get32(buf[b:])
b += 4
v.Kind = buf[b]
b += 1
b += 7 // padding
return v
}
// Write request to wire for QueryInfo
// queryInfoRequest writes a QueryInfo request to a byte slice.
func queryInfoRequest(c *xgb.Conn, Drawable xproto.Drawable) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SCREEN-SAVER"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 1 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Drawable))
b += 4
return buf
}
// QueryVersionCookie is a cookie used only for QueryVersion requests.
type QueryVersionCookie struct {
*xgb.Cookie
}
// QueryVersion sends a checked request.
// If an error occurs, it will be returned with the reply by calling QueryVersionCookie.Reply()
func QueryVersion(c *xgb.Conn, ClientMajorVersion byte, ClientMinorVersion byte) QueryVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(queryVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return QueryVersionCookie{cookie}
}
// QueryVersionUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func QueryVersionUnchecked(c *xgb.Conn, ClientMajorVersion byte, ClientMinorVersion byte) QueryVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(queryVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return QueryVersionCookie{cookie}
}
// QueryVersionReply represents the data returned from a QueryVersion request.
type QueryVersionReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
ServerMajorVersion uint16
ServerMinorVersion uint16
// padding: 20 bytes
}
// Reply blocks and returns the reply data for a QueryVersion request.
func (cook QueryVersionCookie) Reply() (*QueryVersionReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return queryVersionReply(buf), nil
}
// queryVersionReply reads a byte slice into a QueryVersionReply value.
func queryVersionReply(buf []byte) *QueryVersionReply {
v := new(QueryVersionReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.ServerMajorVersion = xgb.Get16(buf[b:])
b += 2
v.ServerMinorVersion = xgb.Get16(buf[b:])
b += 2
b += 20 // padding
return v
}
// Write request to wire for QueryVersion
// queryVersionRequest writes a QueryVersion request to a byte slice.
func queryVersionRequest(c *xgb.Conn, ClientMajorVersion byte, ClientMinorVersion byte) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SCREEN-SAVER"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 0 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
buf[b] = ClientMajorVersion
b += 1
buf[b] = ClientMinorVersion
b += 1
b += 2 // padding
return buf
}
// SelectInputCookie is a cookie used only for SelectInput requests.
type SelectInputCookie struct {
*xgb.Cookie
}
// SelectInput sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func SelectInput(c *xgb.Conn, Drawable xproto.Drawable, EventMask uint32) SelectInputCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
panic("Cannot issue request 'SelectInput' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(selectInputRequest(c, Drawable, EventMask), cookie)
return SelectInputCookie{cookie}
}
// SelectInputChecked sends a checked request.
// If an error occurs, it can be retrieved using SelectInputCookie.Check()
func SelectInputChecked(c *xgb.Conn, Drawable xproto.Drawable, EventMask uint32) SelectInputCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
panic("Cannot issue request 'SelectInput' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(selectInputRequest(c, Drawable, EventMask), cookie)
return SelectInputCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook SelectInputCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for SelectInput
// selectInputRequest writes a SelectInput request to a byte slice.
func selectInputRequest(c *xgb.Conn, Drawable xproto.Drawable, EventMask uint32) []byte {
size := 12
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SCREEN-SAVER"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 2 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Drawable))
b += 4
xgb.Put32(buf[b:], EventMask)
b += 4
return buf
}
// SetAttributesCookie is a cookie used only for SetAttributes requests.
type SetAttributesCookie struct {
*xgb.Cookie
}
// SetAttributes sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func SetAttributes(c *xgb.Conn, Drawable xproto.Drawable, X int16, Y int16, Width uint16, Height uint16, BorderWidth uint16, Class byte, Depth byte, Visual xproto.Visualid, ValueMask uint32, ValueList []uint32) SetAttributesCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
panic("Cannot issue request 'SetAttributes' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(setAttributesRequest(c, Drawable, X, Y, Width, Height, BorderWidth, Class, Depth, Visual, ValueMask, ValueList), cookie)
return SetAttributesCookie{cookie}
}
// SetAttributesChecked sends a checked request.
// If an error occurs, it can be retrieved using SetAttributesCookie.Check()
func SetAttributesChecked(c *xgb.Conn, Drawable xproto.Drawable, X int16, Y int16, Width uint16, Height uint16, BorderWidth uint16, Class byte, Depth byte, Visual xproto.Visualid, ValueMask uint32, ValueList []uint32) SetAttributesCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
panic("Cannot issue request 'SetAttributes' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(setAttributesRequest(c, Drawable, X, Y, Width, Height, BorderWidth, Class, Depth, Visual, ValueMask, ValueList), cookie)
return SetAttributesCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook SetAttributesCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for SetAttributes
// setAttributesRequest writes a SetAttributes request to a byte slice.
func setAttributesRequest(c *xgb.Conn, Drawable xproto.Drawable, X int16, Y int16, Width uint16, Height uint16, BorderWidth uint16, Class byte, Depth byte, Visual xproto.Visualid, ValueMask uint32, ValueList []uint32) []byte {
size := xgb.Pad((28 + xgb.Pad((4 * xgb.PopCount(int(ValueMask))))))
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SCREEN-SAVER"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 3 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Drawable))
b += 4
xgb.Put16(buf[b:], uint16(X))
b += 2
xgb.Put16(buf[b:], uint16(Y))
b += 2
xgb.Put16(buf[b:], Width)
b += 2
xgb.Put16(buf[b:], Height)
b += 2
xgb.Put16(buf[b:], BorderWidth)
b += 2
buf[b] = Class
b += 1
buf[b] = Depth
b += 1
xgb.Put32(buf[b:], uint32(Visual))
b += 4
xgb.Put32(buf[b:], ValueMask)
b += 4
for i := 0; i < xgb.PopCount(int(ValueMask)); i++ {
xgb.Put32(buf[b:], ValueList[i])
b += 4
}
b = xgb.Pad(b)
return buf
}
// SuspendCookie is a cookie used only for Suspend requests.
type SuspendCookie struct {
*xgb.Cookie
}
// Suspend sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func Suspend(c *xgb.Conn, Suspend uint32) SuspendCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
panic("Cannot issue request 'Suspend' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(suspendRequest(c, Suspend), cookie)
return SuspendCookie{cookie}
}
// SuspendChecked sends a checked request.
// If an error occurs, it can be retrieved using SuspendCookie.Check()
func SuspendChecked(c *xgb.Conn, Suspend uint32) SuspendCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
panic("Cannot issue request 'Suspend' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(suspendRequest(c, Suspend), cookie)
return SuspendCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook SuspendCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for Suspend
// suspendRequest writes a Suspend request to a byte slice.
func suspendRequest(c *xgb.Conn, Suspend uint32) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SCREEN-SAVER"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 5 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], Suspend)
b += 4
return buf
}
// UnsetAttributesCookie is a cookie used only for UnsetAttributes requests.
type UnsetAttributesCookie struct {
*xgb.Cookie
}
// UnsetAttributes sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func UnsetAttributes(c *xgb.Conn, Drawable xproto.Drawable) UnsetAttributesCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
panic("Cannot issue request 'UnsetAttributes' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(unsetAttributesRequest(c, Drawable), cookie)
return UnsetAttributesCookie{cookie}
}
// UnsetAttributesChecked sends a checked request.
// If an error occurs, it can be retrieved using UnsetAttributesCookie.Check()
func UnsetAttributesChecked(c *xgb.Conn, Drawable xproto.Drawable) UnsetAttributesCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
panic("Cannot issue request 'UnsetAttributes' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(unsetAttributesRequest(c, Drawable), cookie)
return UnsetAttributesCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook UnsetAttributesCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for UnsetAttributes
// unsetAttributesRequest writes a UnsetAttributes request to a byte slice.
func unsetAttributesRequest(c *xgb.Conn, Drawable xproto.Drawable) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SCREEN-SAVER"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 4 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Drawable))
b += 4
return buf
}

1025
vend/xgb/shape/shape.go Normal file

File diff suppressed because it is too large Load Diff

945
vend/xgb/shm/shm.go Normal file
View File

@ -0,0 +1,945 @@
// Package shm is the X client API for the MIT-SHM extension.
package shm
// This file is automatically generated from shm.xml. Edit at your peril!
import (
"github.com/jezek/xgb"
"github.com/jezek/xgb/xproto"
)
// Init must be called before using the MIT-SHM extension.
func Init(c *xgb.Conn) error {
reply, err := xproto.QueryExtension(c, 7, "MIT-SHM").Reply()
switch {
case err != nil:
return err
case !reply.Present:
return xgb.Errorf("No extension named MIT-SHM could be found on on the server.")
}
c.ExtLock.Lock()
c.Extensions["MIT-SHM"] = reply.MajorOpcode
c.ExtLock.Unlock()
for evNum, fun := range xgb.NewExtEventFuncs["MIT-SHM"] {
xgb.NewEventFuncs[int(reply.FirstEvent)+evNum] = fun
}
for errNum, fun := range xgb.NewExtErrorFuncs["MIT-SHM"] {
xgb.NewErrorFuncs[int(reply.FirstError)+errNum] = fun
}
return nil
}
func init() {
xgb.NewExtEventFuncs["MIT-SHM"] = make(map[int]xgb.NewEventFun)
xgb.NewExtErrorFuncs["MIT-SHM"] = make(map[int]xgb.NewErrorFun)
}
// BadBadSeg is the error number for a BadBadSeg.
const BadBadSeg = 0
type BadSegError xproto.ValueError
// BadSegErrorNew constructs a BadSegError value that implements xgb.Error from a byte slice.
func BadSegErrorNew(buf []byte) xgb.Error {
v := BadSegError(xproto.ValueErrorNew(buf).(xproto.ValueError))
v.NiceName = "BadSeg"
return v
}
// SequenceId returns the sequence id attached to the BadBadSeg error.
// This is mostly used internally.
func (err BadSegError) SequenceId() uint16 {
return err.Sequence
}
// BadId returns the 'BadValue' number if one exists for the BadBadSeg error. If no bad value exists, 0 is returned.
func (err BadSegError) BadId() uint32 {
return 0
}
// Error returns a rudimentary string representation of the BadBadSeg error.
func (err BadSegError) Error() string {
fieldVals := make([]string, 0, 4)
fieldVals = append(fieldVals, "NiceName: "+err.NiceName)
fieldVals = append(fieldVals, xgb.Sprintf("Sequence: %d", err.Sequence))
fieldVals = append(fieldVals, xgb.Sprintf("BadValue: %d", err.BadValue))
fieldVals = append(fieldVals, xgb.Sprintf("MinorOpcode: %d", err.MinorOpcode))
fieldVals = append(fieldVals, xgb.Sprintf("MajorOpcode: %d", err.MajorOpcode))
return "BadBadSeg {" + xgb.StringsJoin(fieldVals, ", ") + "}"
}
func init() {
xgb.NewExtErrorFuncs["MIT-SHM"][0] = BadSegErrorNew
}
// Completion is the event number for a CompletionEvent.
const Completion = 0
type CompletionEvent struct {
Sequence uint16
// padding: 1 bytes
Drawable xproto.Drawable
MinorEvent uint16
MajorEvent byte
// padding: 1 bytes
Shmseg Seg
Offset uint32
}
// CompletionEventNew constructs a CompletionEvent value that implements xgb.Event from a byte slice.
func CompletionEventNew(buf []byte) xgb.Event {
v := CompletionEvent{}
b := 1 // don't read event number
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Drawable = xproto.Drawable(xgb.Get32(buf[b:]))
b += 4
v.MinorEvent = xgb.Get16(buf[b:])
b += 2
v.MajorEvent = buf[b]
b += 1
b += 1 // padding
v.Shmseg = Seg(xgb.Get32(buf[b:]))
b += 4
v.Offset = xgb.Get32(buf[b:])
b += 4
return v
}
// Bytes writes a CompletionEvent value to a byte slice.
func (v CompletionEvent) Bytes() []byte {
buf := make([]byte, 32)
b := 0
// write event number
buf[b] = 0
b += 1
b += 1 // padding
b += 2 // skip sequence number
xgb.Put32(buf[b:], uint32(v.Drawable))
b += 4
xgb.Put16(buf[b:], v.MinorEvent)
b += 2
buf[b] = v.MajorEvent
b += 1
b += 1 // padding
xgb.Put32(buf[b:], uint32(v.Shmseg))
b += 4
xgb.Put32(buf[b:], v.Offset)
b += 4
return buf
}
// SequenceId returns the sequence id attached to the Completion event.
// Events without a sequence number (KeymapNotify) return 0.
// This is mostly used internally.
func (v CompletionEvent) SequenceId() uint16 {
return v.Sequence
}
// String is a rudimentary string representation of CompletionEvent.
func (v CompletionEvent) String() string {
fieldVals := make([]string, 0, 7)
fieldVals = append(fieldVals, xgb.Sprintf("Sequence: %d", v.Sequence))
fieldVals = append(fieldVals, xgb.Sprintf("Drawable: %d", v.Drawable))
fieldVals = append(fieldVals, xgb.Sprintf("MinorEvent: %d", v.MinorEvent))
fieldVals = append(fieldVals, xgb.Sprintf("MajorEvent: %d", v.MajorEvent))
fieldVals = append(fieldVals, xgb.Sprintf("Shmseg: %d", v.Shmseg))
fieldVals = append(fieldVals, xgb.Sprintf("Offset: %d", v.Offset))
return "Completion {" + xgb.StringsJoin(fieldVals, ", ") + "}"
}
func init() {
xgb.NewExtEventFuncs["MIT-SHM"][0] = CompletionEventNew
}
type Seg uint32
func NewSegId(c *xgb.Conn) (Seg, error) {
id, err := c.NewId()
if err != nil {
return 0, err
}
return Seg(id), nil
}
// Skipping definition for base type 'Bool'
// Skipping definition for base type 'Byte'
// Skipping definition for base type 'Card8'
// Skipping definition for base type 'Char'
// Skipping definition for base type 'Void'
// Skipping definition for base type 'Double'
// Skipping definition for base type 'Float'
// Skipping definition for base type 'Int16'
// Skipping definition for base type 'Int32'
// Skipping definition for base type 'Int8'
// Skipping definition for base type 'Card16'
// Skipping definition for base type 'Card32'
// AttachCookie is a cookie used only for Attach requests.
type AttachCookie struct {
*xgb.Cookie
}
// Attach sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func Attach(c *xgb.Conn, Shmseg Seg, Shmid uint32, ReadOnly bool) AttachCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'Attach' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(attachRequest(c, Shmseg, Shmid, ReadOnly), cookie)
return AttachCookie{cookie}
}
// AttachChecked sends a checked request.
// If an error occurs, it can be retrieved using AttachCookie.Check()
func AttachChecked(c *xgb.Conn, Shmseg Seg, Shmid uint32, ReadOnly bool) AttachCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'Attach' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(attachRequest(c, Shmseg, Shmid, ReadOnly), cookie)
return AttachCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook AttachCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for Attach
// attachRequest writes a Attach request to a byte slice.
func attachRequest(c *xgb.Conn, Shmseg Seg, Shmid uint32, ReadOnly bool) []byte {
size := 16
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SHM"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 1 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Shmseg))
b += 4
xgb.Put32(buf[b:], Shmid)
b += 4
if ReadOnly {
buf[b] = 1
} else {
buf[b] = 0
}
b += 1
b += 3 // padding
return buf
}
// AttachFdCookie is a cookie used only for AttachFd requests.
type AttachFdCookie struct {
*xgb.Cookie
}
// AttachFd sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func AttachFd(c *xgb.Conn, Shmseg Seg, ReadOnly bool) AttachFdCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'AttachFd' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(attachFdRequest(c, Shmseg, ReadOnly), cookie)
return AttachFdCookie{cookie}
}
// AttachFdChecked sends a checked request.
// If an error occurs, it can be retrieved using AttachFdCookie.Check()
func AttachFdChecked(c *xgb.Conn, Shmseg Seg, ReadOnly bool) AttachFdCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'AttachFd' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(attachFdRequest(c, Shmseg, ReadOnly), cookie)
return AttachFdCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook AttachFdCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for AttachFd
// attachFdRequest writes a AttachFd request to a byte slice.
func attachFdRequest(c *xgb.Conn, Shmseg Seg, ReadOnly bool) []byte {
size := 12
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SHM"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 6 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Shmseg))
b += 4
if ReadOnly {
buf[b] = 1
} else {
buf[b] = 0
}
b += 1
b += 3 // padding
return buf
}
// CreatePixmapCookie is a cookie used only for CreatePixmap requests.
type CreatePixmapCookie struct {
*xgb.Cookie
}
// CreatePixmap sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func CreatePixmap(c *xgb.Conn, Pid xproto.Pixmap, Drawable xproto.Drawable, Width uint16, Height uint16, Depth byte, Shmseg Seg, Offset uint32) CreatePixmapCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'CreatePixmap' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(createPixmapRequest(c, Pid, Drawable, Width, Height, Depth, Shmseg, Offset), cookie)
return CreatePixmapCookie{cookie}
}
// CreatePixmapChecked sends a checked request.
// If an error occurs, it can be retrieved using CreatePixmapCookie.Check()
func CreatePixmapChecked(c *xgb.Conn, Pid xproto.Pixmap, Drawable xproto.Drawable, Width uint16, Height uint16, Depth byte, Shmseg Seg, Offset uint32) CreatePixmapCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'CreatePixmap' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(createPixmapRequest(c, Pid, Drawable, Width, Height, Depth, Shmseg, Offset), cookie)
return CreatePixmapCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook CreatePixmapCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for CreatePixmap
// createPixmapRequest writes a CreatePixmap request to a byte slice.
func createPixmapRequest(c *xgb.Conn, Pid xproto.Pixmap, Drawable xproto.Drawable, Width uint16, Height uint16, Depth byte, Shmseg Seg, Offset uint32) []byte {
size := 28
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SHM"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 5 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Pid))
b += 4
xgb.Put32(buf[b:], uint32(Drawable))
b += 4
xgb.Put16(buf[b:], Width)
b += 2
xgb.Put16(buf[b:], Height)
b += 2
buf[b] = Depth
b += 1
b += 3 // padding
xgb.Put32(buf[b:], uint32(Shmseg))
b += 4
xgb.Put32(buf[b:], Offset)
b += 4
return buf
}
// CreateSegmentCookie is a cookie used only for CreateSegment requests.
type CreateSegmentCookie struct {
*xgb.Cookie
}
// CreateSegment sends a checked request.
// If an error occurs, it will be returned with the reply by calling CreateSegmentCookie.Reply()
func CreateSegment(c *xgb.Conn, Shmseg Seg, Size uint32, ReadOnly bool) CreateSegmentCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'CreateSegment' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(createSegmentRequest(c, Shmseg, Size, ReadOnly), cookie)
return CreateSegmentCookie{cookie}
}
// CreateSegmentUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func CreateSegmentUnchecked(c *xgb.Conn, Shmseg Seg, Size uint32, ReadOnly bool) CreateSegmentCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'CreateSegment' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(createSegmentRequest(c, Shmseg, Size, ReadOnly), cookie)
return CreateSegmentCookie{cookie}
}
// CreateSegmentReply represents the data returned from a CreateSegment request.
type CreateSegmentReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
Nfd byte
// padding: 24 bytes
}
// Reply blocks and returns the reply data for a CreateSegment request.
func (cook CreateSegmentCookie) Reply() (*CreateSegmentReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return createSegmentReply(buf), nil
}
// createSegmentReply reads a byte slice into a CreateSegmentReply value.
func createSegmentReply(buf []byte) *CreateSegmentReply {
v := new(CreateSegmentReply)
b := 1 // skip reply determinant
v.Nfd = buf[b]
b += 1
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
b += 24 // padding
return v
}
// Write request to wire for CreateSegment
// createSegmentRequest writes a CreateSegment request to a byte slice.
func createSegmentRequest(c *xgb.Conn, Shmseg Seg, Size uint32, ReadOnly bool) []byte {
size := 16
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SHM"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 7 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Shmseg))
b += 4
xgb.Put32(buf[b:], Size)
b += 4
if ReadOnly {
buf[b] = 1
} else {
buf[b] = 0
}
b += 1
b += 3 // padding
return buf
}
// DetachCookie is a cookie used only for Detach requests.
type DetachCookie struct {
*xgb.Cookie
}
// Detach sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func Detach(c *xgb.Conn, Shmseg Seg) DetachCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'Detach' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(detachRequest(c, Shmseg), cookie)
return DetachCookie{cookie}
}
// DetachChecked sends a checked request.
// If an error occurs, it can be retrieved using DetachCookie.Check()
func DetachChecked(c *xgb.Conn, Shmseg Seg) DetachCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'Detach' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(detachRequest(c, Shmseg), cookie)
return DetachCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook DetachCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for Detach
// detachRequest writes a Detach request to a byte slice.
func detachRequest(c *xgb.Conn, Shmseg Seg) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SHM"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 2 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Shmseg))
b += 4
return buf
}
// GetImageCookie is a cookie used only for GetImage requests.
type GetImageCookie struct {
*xgb.Cookie
}
// GetImage sends a checked request.
// If an error occurs, it will be returned with the reply by calling GetImageCookie.Reply()
func GetImage(c *xgb.Conn, Drawable xproto.Drawable, X int16, Y int16, Width uint16, Height uint16, PlaneMask uint32, Format byte, Shmseg Seg, Offset uint32) GetImageCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'GetImage' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(getImageRequest(c, Drawable, X, Y, Width, Height, PlaneMask, Format, Shmseg, Offset), cookie)
return GetImageCookie{cookie}
}
// GetImageUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func GetImageUnchecked(c *xgb.Conn, Drawable xproto.Drawable, X int16, Y int16, Width uint16, Height uint16, PlaneMask uint32, Format byte, Shmseg Seg, Offset uint32) GetImageCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'GetImage' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(getImageRequest(c, Drawable, X, Y, Width, Height, PlaneMask, Format, Shmseg, Offset), cookie)
return GetImageCookie{cookie}
}
// GetImageReply represents the data returned from a GetImage request.
type GetImageReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
Depth byte
Visual xproto.Visualid
Size uint32
}
// Reply blocks and returns the reply data for a GetImage request.
func (cook GetImageCookie) Reply() (*GetImageReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return getImageReply(buf), nil
}
// getImageReply reads a byte slice into a GetImageReply value.
func getImageReply(buf []byte) *GetImageReply {
v := new(GetImageReply)
b := 1 // skip reply determinant
v.Depth = buf[b]
b += 1
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.Visual = xproto.Visualid(xgb.Get32(buf[b:]))
b += 4
v.Size = xgb.Get32(buf[b:])
b += 4
return v
}
// Write request to wire for GetImage
// getImageRequest writes a GetImage request to a byte slice.
func getImageRequest(c *xgb.Conn, Drawable xproto.Drawable, X int16, Y int16, Width uint16, Height uint16, PlaneMask uint32, Format byte, Shmseg Seg, Offset uint32) []byte {
size := 32
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SHM"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 4 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Drawable))
b += 4
xgb.Put16(buf[b:], uint16(X))
b += 2
xgb.Put16(buf[b:], uint16(Y))
b += 2
xgb.Put16(buf[b:], Width)
b += 2
xgb.Put16(buf[b:], Height)
b += 2
xgb.Put32(buf[b:], PlaneMask)
b += 4
buf[b] = Format
b += 1
b += 3 // padding
xgb.Put32(buf[b:], uint32(Shmseg))
b += 4
xgb.Put32(buf[b:], Offset)
b += 4
return buf
}
// PutImageCookie is a cookie used only for PutImage requests.
type PutImageCookie struct {
*xgb.Cookie
}
// PutImage sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func PutImage(c *xgb.Conn, Drawable xproto.Drawable, Gc xproto.Gcontext, TotalWidth uint16, TotalHeight uint16, SrcX uint16, SrcY uint16, SrcWidth uint16, SrcHeight uint16, DstX int16, DstY int16, Depth byte, Format byte, SendEvent byte, Shmseg Seg, Offset uint32) PutImageCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'PutImage' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, false)
c.NewRequest(putImageRequest(c, Drawable, Gc, TotalWidth, TotalHeight, SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY, Depth, Format, SendEvent, Shmseg, Offset), cookie)
return PutImageCookie{cookie}
}
// PutImageChecked sends a checked request.
// If an error occurs, it can be retrieved using PutImageCookie.Check()
func PutImageChecked(c *xgb.Conn, Drawable xproto.Drawable, Gc xproto.Gcontext, TotalWidth uint16, TotalHeight uint16, SrcX uint16, SrcY uint16, SrcWidth uint16, SrcHeight uint16, DstX int16, DstY int16, Depth byte, Format byte, SendEvent byte, Shmseg Seg, Offset uint32) PutImageCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'PutImage' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, false)
c.NewRequest(putImageRequest(c, Drawable, Gc, TotalWidth, TotalHeight, SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY, Depth, Format, SendEvent, Shmseg, Offset), cookie)
return PutImageCookie{cookie}
}
// Check returns an error if one occurred for checked requests that are not expecting a reply.
// This cannot be called for requests expecting a reply, nor for unchecked requests.
func (cook PutImageCookie) Check() error {
return cook.Cookie.Check()
}
// Write request to wire for PutImage
// putImageRequest writes a PutImage request to a byte slice.
func putImageRequest(c *xgb.Conn, Drawable xproto.Drawable, Gc xproto.Gcontext, TotalWidth uint16, TotalHeight uint16, SrcX uint16, SrcY uint16, SrcWidth uint16, SrcHeight uint16, DstX int16, DstY int16, Depth byte, Format byte, SendEvent byte, Shmseg Seg, Offset uint32) []byte {
size := 40
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SHM"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 3 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], uint32(Drawable))
b += 4
xgb.Put32(buf[b:], uint32(Gc))
b += 4
xgb.Put16(buf[b:], TotalWidth)
b += 2
xgb.Put16(buf[b:], TotalHeight)
b += 2
xgb.Put16(buf[b:], SrcX)
b += 2
xgb.Put16(buf[b:], SrcY)
b += 2
xgb.Put16(buf[b:], SrcWidth)
b += 2
xgb.Put16(buf[b:], SrcHeight)
b += 2
xgb.Put16(buf[b:], uint16(DstX))
b += 2
xgb.Put16(buf[b:], uint16(DstY))
b += 2
buf[b] = Depth
b += 1
buf[b] = Format
b += 1
buf[b] = SendEvent
b += 1
b += 1 // padding
xgb.Put32(buf[b:], uint32(Shmseg))
b += 4
xgb.Put32(buf[b:], Offset)
b += 4
return buf
}
// QueryVersionCookie is a cookie used only for QueryVersion requests.
type QueryVersionCookie struct {
*xgb.Cookie
}
// QueryVersion sends a checked request.
// If an error occurs, it will be returned with the reply by calling QueryVersionCookie.Reply()
func QueryVersion(c *xgb.Conn) QueryVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(queryVersionRequest(c), cookie)
return QueryVersionCookie{cookie}
}
// QueryVersionUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func QueryVersionUnchecked(c *xgb.Conn) QueryVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["MIT-SHM"]; !ok {
panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'MIT-SHM'. shm.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(queryVersionRequest(c), cookie)
return QueryVersionCookie{cookie}
}
// QueryVersionReply represents the data returned from a QueryVersion request.
type QueryVersionReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
SharedPixmaps bool
MajorVersion uint16
MinorVersion uint16
Uid uint16
Gid uint16
PixmapFormat byte
// padding: 15 bytes
}
// Reply blocks and returns the reply data for a QueryVersion request.
func (cook QueryVersionCookie) Reply() (*QueryVersionReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return queryVersionReply(buf), nil
}
// queryVersionReply reads a byte slice into a QueryVersionReply value.
func queryVersionReply(buf []byte) *QueryVersionReply {
v := new(QueryVersionReply)
b := 1 // skip reply determinant
if buf[b] == 1 {
v.SharedPixmaps = true
} else {
v.SharedPixmaps = false
}
b += 1
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.MajorVersion = xgb.Get16(buf[b:])
b += 2
v.MinorVersion = xgb.Get16(buf[b:])
b += 2
v.Uid = xgb.Get16(buf[b:])
b += 2
v.Gid = xgb.Get16(buf[b:])
b += 2
v.PixmapFormat = buf[b]
b += 1
b += 15 // padding
return v
}
// Write request to wire for QueryVersion
// queryVersionRequest writes a QueryVersion request to a byte slice.
func queryVersionRequest(c *xgb.Conn) []byte {
size := 4
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["MIT-SHM"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 0 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
return buf
}

29
vend/xgb/sync.go Normal file
View File

@ -0,0 +1,29 @@
package xgb
// 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 (c *Conn) Sync() {
cookie := c.NewCookie(true, true)
c.NewRequest(c.getInputFocusRequest(), cookie)
cookie.Reply() // wait for the buffer to clear
}
// getInputFocusRequest writes the raw bytes to a buffer.
// It is duplicated from xproto/xproto.go.
func (c *Conn) getInputFocusRequest() []byte {
size := 4
b := 0
buf := make([]byte, size)
buf[b] = 43 // request opcode
b += 1
b += 1 // padding
Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
return buf
}

426
vend/xgb/testingTools.go Normal file
View File

@ -0,0 +1,426 @@
package xgb
import (
"bytes"
"errors"
"io"
"net"
"regexp"
"runtime"
"strconv"
"strings"
"testing"
"time"
)
// Leaks monitor
type goroutine struct {
id int
name string
stack []byte
}
type leaks struct {
name string
goroutines map[int]goroutine
report []*leaks
}
func leaksMonitor(name string, monitors ...*leaks) *leaks {
return &leaks{
name,
leaks{}.collectGoroutines(),
monitors,
}
}
// ispired by https://golang.org/src/runtime/debug/stack.go?s=587:606#L21
// stack returns a formatted stack trace of all goroutines.
// It calls runtime.Stack with a large enough buffer to capture the entire trace.
func (_ leaks) stack() []byte {
buf := make([]byte, 1024)
for {
n := runtime.Stack(buf, true)
if n < len(buf) {
return buf[:n]
}
buf = make([]byte, 2*len(buf))
}
}
func (l leaks) collectGoroutines() map[int]goroutine {
res := make(map[int]goroutine)
stacks := bytes.Split(l.stack(), []byte{'\n', '\n'})
regexpId := regexp.MustCompile(`^\s*goroutine\s*(\d+)`)
for _, st := range stacks {
lines := bytes.Split(st, []byte{'\n'})
if len(lines) < 2 {
panic("routine stach has less tnan two lines: " + string(st))
}
idMatches := regexpId.FindSubmatch(lines[0])
if len(idMatches) < 2 {
panic("no id found in goroutine stack's first line: " + string(lines[0]))
}
id, err := strconv.Atoi(string(idMatches[1]))
if err != nil {
panic("converting goroutine id to number error: " + err.Error())
}
if _, ok := res[id]; ok {
panic("2 goroutines with same id: " + strconv.Itoa(id))
}
name := strings.TrimSpace(string(lines[1]))
//filter out our stack routine
if strings.Contains(name, "xgb.leaks.stack") {
continue
}
res[id] = goroutine{id, name, st}
}
return res
}
func (l leaks) leakingGoroutines() []goroutine {
goroutines := l.collectGoroutines()
res := []goroutine{}
for id, gr := range goroutines {
if _, ok := l.goroutines[id]; ok {
continue
}
res = append(res, gr)
}
return res
}
func (l leaks) checkTesting(t *testing.T) {
if len(l.leakingGoroutines()) == 0 {
return
}
leakTimeout := 10 * time.Millisecond
time.Sleep(leakTimeout)
//t.Logf("possible goroutine leakage, waiting %v", leakTimeout)
grs := l.leakingGoroutines()
for _, gr := range grs {
t.Errorf("%s: %s is leaking", l.name, gr.name)
//t.Errorf("%s: %s is leaking\n%v", l.name, gr.name, string(gr.stack))
}
for _, rl := range l.report {
rl.ignoreLeak(grs...)
}
}
func (l *leaks) ignoreLeak(grs ...goroutine) {
for _, gr := range grs {
l.goroutines[gr.id] = gr
}
}
// dummy net.Conn
type dAddr struct {
s string
}
func (_ dAddr) Network() string { return "dummy" }
func (a dAddr) String() string { return a.s }
var (
dNCErrNotImplemented = errors.New("command not implemented")
dNCErrClosed = errors.New("server closed")
dNCErrWrite = errors.New("server write failed")
dNCErrRead = errors.New("server read failed")
dNCErrResponse = errors.New("server response error")
)
type dNCIoResult struct {
n int
err error
}
type dNCIo struct {
b []byte
result chan dNCIoResult
}
type dNCCWriteLock struct{}
type dNCCWriteUnlock struct{}
type dNCCWriteError struct{}
type dNCCWriteSuccess struct{}
type dNCCReadLock struct{}
type dNCCReadUnlock struct{}
type dNCCReadError struct{}
type dNCCReadSuccess struct{}
// dummy net.Conn interface. Needs to be constructed via newDummyNetConn([...]) function.
type dNC struct {
reply func([]byte) []byte
addr dAddr
in, out chan dNCIo
control chan interface{}
done chan struct{}
}
// Results running dummy server, satisfying net.Conn interface for test purposes.
// 'name' parameter will be returned via (*dNC).Local/RemoteAddr().String()
// 'reply' parameter function will be runned only on successful (*dNC).Write(b) with 'b' as parameter to 'reply'. The result will be stored in internal buffer and can be retrieved later via (*dNC).Read([...]) method.
// It is users responsibility to stop and clean up resources with (*dNC).Close, if not needed anymore.
// By default, the (*dNC).Write([...]) and (*dNC).Read([...]) methods are unlocked and will not result in error.
//TODO make (*dNC).SetDeadline, (*dNC).SetReadDeadline, (*dNC).SetWriteDeadline work proprely.
func newDummyNetConn(name string, reply func([]byte) []byte) *dNC {
s := &dNC{
reply,
dAddr{name},
make(chan dNCIo), make(chan dNCIo),
make(chan interface{}),
make(chan struct{}),
}
in, out := s.in, chan dNCIo(nil)
buf := &bytes.Buffer{}
errorRead, errorWrite := false, false
lockRead := false
go func() {
defer close(s.done)
for {
select {
case dxsio := <-in:
if errorWrite {
dxsio.result <- dNCIoResult{0, dNCErrWrite}
break
}
response := s.reply(dxsio.b)
buf.Write(response)
dxsio.result <- dNCIoResult{len(dxsio.b), nil}
if !lockRead && buf.Len() > 0 && out == nil {
out = s.out
}
case dxsio := <-out:
if errorRead {
dxsio.result <- dNCIoResult{0, dNCErrRead}
break
}
n, err := buf.Read(dxsio.b)
dxsio.result <- dNCIoResult{n, err}
if buf.Len() == 0 {
out = nil
}
case ci := <-s.control:
if ci == nil {
return
}
switch ci.(type) {
case dNCCWriteLock:
in = nil
case dNCCWriteUnlock:
in = s.in
case dNCCWriteError:
errorWrite = true
case dNCCWriteSuccess:
errorWrite = false
case dNCCReadLock:
out = nil
lockRead = true
case dNCCReadUnlock:
lockRead = false
if buf.Len() > 0 && out == nil {
out = s.out
}
case dNCCReadError:
errorRead = true
case dNCCReadSuccess:
errorRead = false
default:
}
}
}
}()
return s
}
// Shuts down dummy net.Conn server. Every blocking or future method calls will do nothing and result in error.
// Result will be dNCErrClosed if server was allready closed.
// Server can not be unclosed.
func (s *dNC) Close() error {
select {
case s.control <- nil:
<-s.done
return nil
case <-s.done:
}
return dNCErrClosed
}
// Performs a write action to server.
// If not locked by (*dNC).WriteLock, it results in error or success. If locked, this method will block until unlocked, or closed.
//
// This method can be set to result in error or success, via (*dNC).WriteError() or (*dNC).WriteSuccess() methods.
//
// If setted to result in error, the 'reply' function will NOT be called and internal buffer will NOT increasethe.
// Result will be (0, dNCErrWrite).
//
// If setted to result in success, the 'reply' function will be called and its result will be writen to internal buffer.
// If there is something in the internal buffer, the (*dNC).Read([...]) will be unblocked (if not previously locked with (*dNC).ReadLock).
// Result will be (len(b), nil)
//
// If server was closed previously, result will be (0, dNCErrClosed).
func (s *dNC) Write(b []byte) (int, error) {
resChan := make(chan dNCIoResult)
select {
case s.in <- dNCIo{b, resChan}:
res := <-resChan
return res.n, res.err
case <-s.done:
}
return 0, dNCErrClosed
}
// Performs a read action from server.
// If locked by (*dNC).ReadLock(), this method will block until unlocked with (*dNC).ReadUnlock(), or server closes.
//
// If not locked, this method can be setted to result imidiatly in error, will block if internal buffer is empty or will perform an read operation from internal buffer.
//
// If setted to result in error via (*dNC).ReadError(), the result will be (0, dNCErrWrite).
//
// If not locked and not setted to result in error via (*dNC).ReadSuccess(), this method will block until internall buffer is not empty, than it returns the result of the buffer read operation via (*bytes.Buffer).Read([...]).
// If the internal buffer is empty after this method, all follwing (*dNC).Read([...]), requests will block until internall buffer is filled after successful write requests.
//
// If server was closed previously, result will be (0, io.EOF).
func (s *dNC) Read(b []byte) (int, error) {
resChan := make(chan dNCIoResult)
select {
case s.out <- dNCIo{b, resChan}:
res := <-resChan
return res.n, res.err
case <-s.done:
}
return 0, io.EOF
}
func (s *dNC) LocalAddr() net.Addr { return s.addr }
func (s *dNC) RemoteAddr() net.Addr { return s.addr }
func (s *dNC) SetDeadline(t time.Time) error { return dNCErrNotImplemented }
func (s *dNC) SetReadDeadline(t time.Time) error { return dNCErrNotImplemented }
func (s *dNC) SetWriteDeadline(t time.Time) error { return dNCErrNotImplemented }
func (s *dNC) Control(i interface{}) error {
select {
case s.control <- i:
return nil
case <-s.done:
}
return dNCErrClosed
}
// Locks writing. All write requests will be blocked until write is unlocked with (*dNC).WriteUnlock, or server closes.
func (s *dNC) WriteLock() error {
return s.Control(dNCCWriteLock{})
}
// Unlocks writing. All blocked write requests until now will be accepted.
func (s *dNC) WriteUnlock() error {
return s.Control(dNCCWriteUnlock{})
}
// Unlocks writing and makes (*dNC).Write to result (0, dNCErrWrite).
func (s *dNC) WriteError() error {
if err := s.WriteUnlock(); err != nil {
return err
}
return s.Control(dNCCWriteError{})
}
// Unlocks writing and makes (*dNC).Write([...]) not result in error. See (*dNC).Write for details.
func (s *dNC) WriteSuccess() error {
if err := s.WriteUnlock(); err != nil {
return err
}
return s.Control(dNCCWriteSuccess{})
}
// Locks reading. All read requests will be blocked until read is unlocked with (*dNC).ReadUnlock, or server closes.
// (*dNC).Read([...]) wil block even after successful write.
func (s *dNC) ReadLock() error {
return s.Control(dNCCReadLock{})
}
// Unlocks reading. If the internall buffer is not empty, next read will not block.
func (s *dNC) ReadUnlock() error {
return s.Control(dNCCReadUnlock{})
}
// Unlocks read and makes every blocked and following (*dNC).Read([...]) imidiatly result in error. See (*dNC).Read for details.
func (s *dNC) ReadError() error {
if err := s.ReadUnlock(); err != nil {
return err
}
return s.Control(dNCCReadError{})
}
// Unlocks read and makes every blocked and following (*dNC).Read([...]) requests be handled, if according to internal buffer. See (*dNC).Read for details.
func (s *dNC) ReadSuccess() error {
if err := s.ReadUnlock(); err != nil {
return err
}
return s.Control(dNCCReadSuccess{})
}
// dummy X server replier for dummy net.Conn
type dXSEvent struct{}
func (_ dXSEvent) Bytes() []byte { return nil }
func (_ dXSEvent) String() string { return "dummy X server event" }
type dXSError struct {
seqId uint16
}
func (e dXSError) SequenceId() uint16 { return e.seqId }
func (_ dXSError) BadId() uint32 { return 0 }
func (_ dXSError) Error() string { return "dummy X server error reply" }
func newDummyXServerReplier() func([]byte) []byte {
// register xgb error & event replies
NewErrorFuncs[255] = func(buf []byte) Error {
return dXSError{Get16(buf[2:])}
}
NewEventFuncs[128&127] = func(buf []byte) Event {
return dXSEvent{}
}
// sequence number generator
seqId := uint16(1)
incrementSequenceId := func() {
// this has to be the same algorithm as in (*Conn).generateSeqIds
if seqId == uint16((1<<16)-1) {
seqId = 0
} else {
seqId++
}
}
return func(request []byte) []byte {
res := make([]byte, 32)
switch string(request) {
case "event":
res[0] = 128
return res
case "error":
res[0] = 0 // error
res[1] = 255 // error function
default:
res[0] = 1 // reply
}
Put16(res[2:], seqId) // sequence number
incrementSequenceId()
if string(request) == "noreply" {
return nil
}
return res
}
}

View File

@ -0,0 +1,350 @@
package xgb
import (
"bytes"
"errors"
"fmt"
"io"
"reflect"
"sync"
"testing"
"time"
)
func TestLeaks(t *testing.T) {
lm := leaksMonitor("lm")
if lgrs := lm.leakingGoroutines(); len(lgrs) != 0 {
t.Errorf("leakingGoroutines returned %d leaking goroutines, want 0", len(lgrs))
}
done := make(chan struct{})
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
<-done
wg.Done()
}()
if lgrs := lm.leakingGoroutines(); len(lgrs) != 1 {
t.Errorf("leakingGoroutines returned %d leaking goroutines, want 1", len(lgrs))
}
wg.Add(1)
go func() {
<-done
wg.Done()
}()
if lgrs := lm.leakingGoroutines(); len(lgrs) != 2 {
t.Errorf("leakingGoroutines returned %d leaking goroutines, want 2", len(lgrs))
}
close(done)
wg.Wait()
if lgrs := lm.leakingGoroutines(); len(lgrs) != 0 {
t.Errorf("leakingGoroutines returned %d leaking goroutines, want 0", len(lgrs))
}
lm.checkTesting(t)
//TODO multiple leak monitors with report ignore tests
}
func TestDummyNetConn(t *testing.T) {
ioStatesPairGenerator := func(writeStates, readStates []string) []func() (*dNC, error) {
writeSetters := map[string]func(*dNC) error{
"lock": (*dNC).WriteLock,
"error": (*dNC).WriteError,
"success": (*dNC).WriteSuccess,
}
readSetters := map[string]func(*dNC) error{
"lock": (*dNC).ReadLock,
"error": (*dNC).ReadError,
"success": (*dNC).ReadSuccess,
}
res := []func() (*dNC, error){}
for _, writeState := range writeStates {
writeState, writeSetter := writeState, writeSetters[writeState]
if writeSetter == nil {
panic("unknown write state: " + writeState)
continue
}
for _, readState := range readStates {
readState, readSetter := readState, readSetters[readState]
if readSetter == nil {
panic("unknown read state: " + readState)
continue
}
res = append(res, func() (*dNC, error) {
// loopback server
s := newDummyNetConn("w:"+writeState+";r:"+readState, func(b []byte) []byte { return b })
if err := readSetter(s); err != nil {
s.Close()
return nil, errors.New("set read " + readState + " error: " + err.Error())
}
if err := writeSetter(s); err != nil {
s.Close()
return nil, errors.New("set write " + writeState + " error: " + err.Error())
}
return s, nil
})
}
}
return res
}
timeout := 10 * time.Millisecond
wantResponse := func(action func(*dNC) error, want, block error) func(*dNC) error {
return func(s *dNC) error {
actionResult := make(chan error)
timedOut := make(chan struct{})
go func() {
err := action(s)
select {
case <-timedOut:
if err != block {
t.Errorf("after unblocking, action result=%v, want %v", err, block)
}
case actionResult <- err:
}
}()
select {
case err := <-actionResult:
if err != want {
return errors.New(fmt.Sprintf("action result=%v, want %v", err, want))
}
case <-time.After(timeout):
close(timedOut)
return errors.New(fmt.Sprintf("action did not respond for %v, result want %v", timeout, want))
}
return nil
}
}
wantBlock := func(action func(*dNC) error, unblock error) func(*dNC) error {
return func(s *dNC) error {
actionResult := make(chan error)
timedOut := make(chan struct{})
go func() {
err := action(s)
select {
case <-timedOut:
if err != unblock {
t.Errorf("after unblocking, action result=%v, want %v", err, unblock)
}
case actionResult <- err:
}
}()
select {
case err := <-actionResult:
return errors.New(fmt.Sprintf("action result=%v, want to be blocked", err))
case <-time.After(timeout):
close(timedOut)
}
return nil
}
}
write := func(b string) func(*dNC) error {
return func(s *dNC) error {
n, err := s.Write([]byte(b))
if err == nil && n != len(b) {
return errors.New("Write returned nil error, but not everything was written")
}
return err
}
}
read := func(b string) func(*dNC) error {
return func(s *dNC) error {
r := make([]byte, len(b))
n, err := s.Read(r)
if err == nil {
if n != len(b) {
return errors.New("Read returned nil error, but not everything was read")
}
if !reflect.DeepEqual(r, []byte(b)) {
return errors.New("Read=\"" + string(r) + "\", want \"" + string(b) + "\"")
}
}
return err
}
}
testCases := []struct {
description string
servers []func() (*dNC, error)
actions []func(*dNC) error // actions per server
}{
{"close,close",
ioStatesPairGenerator(
[]string{"lock", "error", "success"},
[]string{"lock", "error", "success"},
),
[]func(*dNC) error{
wantResponse((*dNC).Close, nil, dNCErrClosed),
wantResponse((*dNC).Close, dNCErrClosed, dNCErrClosed),
},
},
{"write,close,write",
ioStatesPairGenerator(
[]string{"lock"},
[]string{"lock", "error", "success"},
),
[]func(*dNC) error{
wantBlock(write(""), dNCErrClosed),
wantResponse((*dNC).Close, nil, dNCErrClosed),
wantResponse(write(""), dNCErrClosed, dNCErrClosed),
},
},
{"write,close,write",
ioStatesPairGenerator(
[]string{"error"},
[]string{"lock", "error", "success"},
),
[]func(*dNC) error{
wantResponse(write(""), dNCErrWrite, dNCErrClosed),
wantResponse((*dNC).Close, nil, dNCErrClosed),
wantResponse(write(""), dNCErrClosed, dNCErrClosed),
},
},
{"write,close,write",
ioStatesPairGenerator(
[]string{"success"},
[]string{"lock", "error", "success"},
),
[]func(*dNC) error{
wantResponse(write(""), nil, dNCErrClosed),
wantResponse((*dNC).Close, nil, dNCErrClosed),
wantResponse(write(""), dNCErrClosed, dNCErrClosed),
},
},
{"read,close,read",
ioStatesPairGenerator(
[]string{"lock", "error", "success"},
[]string{"lock", "error", "success"},
),
[]func(*dNC) error{
wantBlock(read(""), io.EOF),
wantResponse((*dNC).Close, nil, dNCErrClosed),
wantResponse(read(""), io.EOF, io.EOF),
},
},
{"write,read",
ioStatesPairGenerator(
[]string{"lock"},
[]string{"lock", "error", "success"},
),
[]func(*dNC) error{
wantBlock(write("1"), dNCErrClosed),
wantBlock(read("1"), io.EOF),
},
},
{"write,read",
ioStatesPairGenerator(
[]string{"error"},
[]string{"lock", "error", "success"},
),
[]func(*dNC) error{
wantResponse(write("1"), dNCErrWrite, dNCErrClosed),
wantBlock(read("1"), io.EOF),
},
},
{"write,read",
ioStatesPairGenerator(
[]string{"success"},
[]string{"lock"},
),
[]func(*dNC) error{
wantResponse(write("1"), nil, dNCErrClosed),
wantBlock(read("1"), io.EOF),
},
},
{"write,read",
ioStatesPairGenerator(
[]string{"success"},
[]string{"error"},
),
[]func(*dNC) error{
wantResponse(write("1"), nil, dNCErrClosed),
wantResponse(read("1"), dNCErrRead, io.EOF),
},
},
{"write,read",
ioStatesPairGenerator(
[]string{"success"},
[]string{"success"},
),
[]func(*dNC) error{
wantResponse(write("1"), nil, dNCErrClosed),
wantResponse(read("1"), nil, io.EOF),
},
},
}
for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {
defer leaksMonitor(tc.description).checkTesting(t)
for _, server := range tc.servers {
s, err := server()
if err != nil {
t.Error(err)
continue
}
if s == nil {
t.Error("nil server in testcase")
continue
}
t.Run(s.LocalAddr().String(), func(t *testing.T) {
defer leaksMonitor(s.LocalAddr().String()).checkTesting(t)
for _, action := range tc.actions {
if err := action(s); err != nil {
t.Error(err)
break
}
}
s.Close()
})
}
})
}
}
func TestDummyXServerReplier(t *testing.T) {
testCases := [][][2][]byte{
{
[2][]byte{[]byte("reply"), []byte{1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte("eply"), []byte{1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte("ply"), []byte{1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte("event"), []byte{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte("ly"), []byte{1, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte("y"), []byte{1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte(""), []byte{1, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte("event"), []byte{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte("reply"), []byte{1, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte("error"), []byte{0, 255, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte("ply"), []byte{1, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte("event"), []byte{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte("ly"), []byte{1, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte("noreply"), nil},
[2][]byte{[]byte("error"), []byte{0, 255, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
[2][]byte{[]byte("noreply"), nil},
[2][]byte{[]byte(""), []byte{1, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
},
}
for tci, tc := range testCases {
replier := newDummyXServerReplier()
for ai, ioPair := range tc {
in, want := ioPair[0], ioPair[1]
if out := replier(in); !bytes.Equal(out, want) {
t.Errorf("testCase %d, action %d, replier(%s) = %v, want %v", tci, ai, string(in), out, want)
break
}
}
}
}

361
vend/xgb/xcmisc/xcmisc.go Normal file
View File

@ -0,0 +1,361 @@
// Package xcmisc is the X client API for the XC-MISC extension.
package xcmisc
// This file is automatically generated from xc_misc.xml. Edit at your peril!
import (
"github.com/jezek/xgb"
"github.com/jezek/xgb/xproto"
)
// Init must be called before using the XC-MISC extension.
func Init(c *xgb.Conn) error {
reply, err := xproto.QueryExtension(c, 7, "XC-MISC").Reply()
switch {
case err != nil:
return err
case !reply.Present:
return xgb.Errorf("No extension named XC-MISC could be found on on the server.")
}
c.ExtLock.Lock()
c.Extensions["XC-MISC"] = reply.MajorOpcode
c.ExtLock.Unlock()
for evNum, fun := range xgb.NewExtEventFuncs["XC-MISC"] {
xgb.NewEventFuncs[int(reply.FirstEvent)+evNum] = fun
}
for errNum, fun := range xgb.NewExtErrorFuncs["XC-MISC"] {
xgb.NewErrorFuncs[int(reply.FirstError)+errNum] = fun
}
return nil
}
func init() {
xgb.NewExtEventFuncs["XC-MISC"] = make(map[int]xgb.NewEventFun)
xgb.NewExtErrorFuncs["XC-MISC"] = make(map[int]xgb.NewErrorFun)
}
// Skipping definition for base type 'Bool'
// Skipping definition for base type 'Byte'
// Skipping definition for base type 'Card8'
// Skipping definition for base type 'Char'
// Skipping definition for base type 'Void'
// Skipping definition for base type 'Double'
// Skipping definition for base type 'Float'
// Skipping definition for base type 'Int16'
// Skipping definition for base type 'Int32'
// Skipping definition for base type 'Int8'
// Skipping definition for base type 'Card16'
// Skipping definition for base type 'Card32'
// GetVersionCookie is a cookie used only for GetVersion requests.
type GetVersionCookie struct {
*xgb.Cookie
}
// GetVersion sends a checked request.
// If an error occurs, it will be returned with the reply by calling GetVersionCookie.Reply()
func GetVersion(c *xgb.Conn, ClientMajorVersion uint16, ClientMinorVersion uint16) GetVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XC-MISC"]; !ok {
panic("Cannot issue request 'GetVersion' using the uninitialized extension 'XC-MISC'. xcmisc.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(getVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return GetVersionCookie{cookie}
}
// GetVersionUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func GetVersionUnchecked(c *xgb.Conn, ClientMajorVersion uint16, ClientMinorVersion uint16) GetVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XC-MISC"]; !ok {
panic("Cannot issue request 'GetVersion' using the uninitialized extension 'XC-MISC'. xcmisc.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(getVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return GetVersionCookie{cookie}
}
// GetVersionReply represents the data returned from a GetVersion request.
type GetVersionReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
ServerMajorVersion uint16
ServerMinorVersion uint16
}
// Reply blocks and returns the reply data for a GetVersion request.
func (cook GetVersionCookie) Reply() (*GetVersionReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return getVersionReply(buf), nil
}
// getVersionReply reads a byte slice into a GetVersionReply value.
func getVersionReply(buf []byte) *GetVersionReply {
v := new(GetVersionReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.ServerMajorVersion = xgb.Get16(buf[b:])
b += 2
v.ServerMinorVersion = xgb.Get16(buf[b:])
b += 2
return v
}
// Write request to wire for GetVersion
// getVersionRequest writes a GetVersion request to a byte slice.
func getVersionRequest(c *xgb.Conn, ClientMajorVersion uint16, ClientMinorVersion uint16) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["XC-MISC"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 0 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put16(buf[b:], ClientMajorVersion)
b += 2
xgb.Put16(buf[b:], ClientMinorVersion)
b += 2
return buf
}
// GetXIDListCookie is a cookie used only for GetXIDList requests.
type GetXIDListCookie struct {
*xgb.Cookie
}
// GetXIDList sends a checked request.
// If an error occurs, it will be returned with the reply by calling GetXIDListCookie.Reply()
func GetXIDList(c *xgb.Conn, Count uint32) GetXIDListCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XC-MISC"]; !ok {
panic("Cannot issue request 'GetXIDList' using the uninitialized extension 'XC-MISC'. xcmisc.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(getXIDListRequest(c, Count), cookie)
return GetXIDListCookie{cookie}
}
// GetXIDListUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func GetXIDListUnchecked(c *xgb.Conn, Count uint32) GetXIDListCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XC-MISC"]; !ok {
panic("Cannot issue request 'GetXIDList' using the uninitialized extension 'XC-MISC'. xcmisc.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(getXIDListRequest(c, Count), cookie)
return GetXIDListCookie{cookie}
}
// GetXIDListReply represents the data returned from a GetXIDList request.
type GetXIDListReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
IdsLen uint32
// padding: 20 bytes
Ids []uint32 // size: xgb.Pad((int(IdsLen) * 4))
}
// Reply blocks and returns the reply data for a GetXIDList request.
func (cook GetXIDListCookie) Reply() (*GetXIDListReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return getXIDListReply(buf), nil
}
// getXIDListReply reads a byte slice into a GetXIDListReply value.
func getXIDListReply(buf []byte) *GetXIDListReply {
v := new(GetXIDListReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.IdsLen = xgb.Get32(buf[b:])
b += 4
b += 20 // padding
v.Ids = make([]uint32, v.IdsLen)
for i := 0; i < int(v.IdsLen); i++ {
v.Ids[i] = xgb.Get32(buf[b:])
b += 4
}
return v
}
// Write request to wire for GetXIDList
// getXIDListRequest writes a GetXIDList request to a byte slice.
func getXIDListRequest(c *xgb.Conn, Count uint32) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["XC-MISC"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 2 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], Count)
b += 4
return buf
}
// GetXIDRangeCookie is a cookie used only for GetXIDRange requests.
type GetXIDRangeCookie struct {
*xgb.Cookie
}
// GetXIDRange sends a checked request.
// If an error occurs, it will be returned with the reply by calling GetXIDRangeCookie.Reply()
func GetXIDRange(c *xgb.Conn) GetXIDRangeCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XC-MISC"]; !ok {
panic("Cannot issue request 'GetXIDRange' using the uninitialized extension 'XC-MISC'. xcmisc.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(getXIDRangeRequest(c), cookie)
return GetXIDRangeCookie{cookie}
}
// GetXIDRangeUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func GetXIDRangeUnchecked(c *xgb.Conn) GetXIDRangeCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XC-MISC"]; !ok {
panic("Cannot issue request 'GetXIDRange' using the uninitialized extension 'XC-MISC'. xcmisc.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(getXIDRangeRequest(c), cookie)
return GetXIDRangeCookie{cookie}
}
// GetXIDRangeReply represents the data returned from a GetXIDRange request.
type GetXIDRangeReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
StartId uint32
Count uint32
}
// Reply blocks and returns the reply data for a GetXIDRange request.
func (cook GetXIDRangeCookie) Reply() (*GetXIDRangeReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return getXIDRangeReply(buf), nil
}
// getXIDRangeReply reads a byte slice into a GetXIDRangeReply value.
func getXIDRangeReply(buf []byte) *GetXIDRangeReply {
v := new(GetXIDRangeReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.StartId = xgb.Get32(buf[b:])
b += 4
v.Count = xgb.Get32(buf[b:])
b += 4
return v
}
// Write request to wire for GetXIDRange
// getXIDRangeRequest writes a GetXIDRange request to a byte slice.
func getXIDRangeRequest(c *xgb.Conn) []byte {
size := 4
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["XC-MISC"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 1 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
return buf
}

595
vend/xgb/xevie/xevie.go Normal file
View File

@ -0,0 +1,595 @@
// Package xevie is the X client API for the XEVIE extension.
package xevie
// This file is automatically generated from xevie.xml. Edit at your peril!
import (
"github.com/jezek/xgb"
"github.com/jezek/xgb/xproto"
)
// Init must be called before using the XEVIE extension.
func Init(c *xgb.Conn) error {
reply, err := xproto.QueryExtension(c, 5, "XEVIE").Reply()
switch {
case err != nil:
return err
case !reply.Present:
return xgb.Errorf("No extension named XEVIE could be found on on the server.")
}
c.ExtLock.Lock()
c.Extensions["XEVIE"] = reply.MajorOpcode
c.ExtLock.Unlock()
for evNum, fun := range xgb.NewExtEventFuncs["XEVIE"] {
xgb.NewEventFuncs[int(reply.FirstEvent)+evNum] = fun
}
for errNum, fun := range xgb.NewExtErrorFuncs["XEVIE"] {
xgb.NewErrorFuncs[int(reply.FirstError)+errNum] = fun
}
return nil
}
func init() {
xgb.NewExtEventFuncs["XEVIE"] = make(map[int]xgb.NewEventFun)
xgb.NewExtErrorFuncs["XEVIE"] = make(map[int]xgb.NewErrorFun)
}
const (
DatatypeUnmodified = 0
DatatypeModified = 1
)
type Event struct {
// padding: 32 bytes
}
// EventRead reads a byte slice into a Event value.
func EventRead(buf []byte, v *Event) int {
b := 0
b += 32 // padding
return b
}
// EventReadList reads a byte slice into a list of Event values.
func EventReadList(buf []byte, dest []Event) int {
b := 0
for i := 0; i < len(dest); i++ {
dest[i] = Event{}
b += EventRead(buf[b:], &dest[i])
}
return xgb.Pad(b)
}
// Bytes writes a Event value to a byte slice.
func (v Event) Bytes() []byte {
buf := make([]byte, 32)
b := 0
b += 32 // padding
return buf[:b]
}
// EventListBytes writes a list of Event values to a byte slice.
func EventListBytes(buf []byte, list []Event) int {
b := 0
var structBytes []byte
for _, item := range list {
structBytes = item.Bytes()
copy(buf[b:], structBytes)
b += len(structBytes)
}
return xgb.Pad(b)
}
// Skipping definition for base type 'Bool'
// Skipping definition for base type 'Byte'
// Skipping definition for base type 'Card8'
// Skipping definition for base type 'Char'
// Skipping definition for base type 'Void'
// Skipping definition for base type 'Double'
// Skipping definition for base type 'Float'
// Skipping definition for base type 'Int16'
// Skipping definition for base type 'Int32'
// Skipping definition for base type 'Int8'
// Skipping definition for base type 'Card16'
// Skipping definition for base type 'Card32'
// EndCookie is a cookie used only for End requests.
type EndCookie struct {
*xgb.Cookie
}
// End sends a checked request.
// If an error occurs, it will be returned with the reply by calling EndCookie.Reply()
func End(c *xgb.Conn, Cmap uint32) EndCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XEVIE"]; !ok {
panic("Cannot issue request 'End' using the uninitialized extension 'XEVIE'. xevie.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(endRequest(c, Cmap), cookie)
return EndCookie{cookie}
}
// EndUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func EndUnchecked(c *xgb.Conn, Cmap uint32) EndCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XEVIE"]; !ok {
panic("Cannot issue request 'End' using the uninitialized extension 'XEVIE'. xevie.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(endRequest(c, Cmap), cookie)
return EndCookie{cookie}
}
// EndReply represents the data returned from a End request.
type EndReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
// padding: 24 bytes
}
// Reply blocks and returns the reply data for a End request.
func (cook EndCookie) Reply() (*EndReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return endReply(buf), nil
}
// endReply reads a byte slice into a EndReply value.
func endReply(buf []byte) *EndReply {
v := new(EndReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
b += 24 // padding
return v
}
// Write request to wire for End
// endRequest writes a End request to a byte slice.
func endRequest(c *xgb.Conn, Cmap uint32) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["XEVIE"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 2 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], Cmap)
b += 4
return buf
}
// QueryVersionCookie is a cookie used only for QueryVersion requests.
type QueryVersionCookie struct {
*xgb.Cookie
}
// QueryVersion sends a checked request.
// If an error occurs, it will be returned with the reply by calling QueryVersionCookie.Reply()
func QueryVersion(c *xgb.Conn, ClientMajorVersion uint16, ClientMinorVersion uint16) QueryVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XEVIE"]; !ok {
panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'XEVIE'. xevie.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(queryVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return QueryVersionCookie{cookie}
}
// QueryVersionUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func QueryVersionUnchecked(c *xgb.Conn, ClientMajorVersion uint16, ClientMinorVersion uint16) QueryVersionCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XEVIE"]; !ok {
panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'XEVIE'. xevie.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(queryVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
return QueryVersionCookie{cookie}
}
// QueryVersionReply represents the data returned from a QueryVersion request.
type QueryVersionReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
ServerMajorVersion uint16
ServerMinorVersion uint16
// padding: 20 bytes
}
// Reply blocks and returns the reply data for a QueryVersion request.
func (cook QueryVersionCookie) Reply() (*QueryVersionReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return queryVersionReply(buf), nil
}
// queryVersionReply reads a byte slice into a QueryVersionReply value.
func queryVersionReply(buf []byte) *QueryVersionReply {
v := new(QueryVersionReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
v.ServerMajorVersion = xgb.Get16(buf[b:])
b += 2
v.ServerMinorVersion = xgb.Get16(buf[b:])
b += 2
b += 20 // padding
return v
}
// Write request to wire for QueryVersion
// queryVersionRequest writes a QueryVersion request to a byte slice.
func queryVersionRequest(c *xgb.Conn, ClientMajorVersion uint16, ClientMinorVersion uint16) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["XEVIE"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 0 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put16(buf[b:], ClientMajorVersion)
b += 2
xgb.Put16(buf[b:], ClientMinorVersion)
b += 2
return buf
}
// SelectInputCookie is a cookie used only for SelectInput requests.
type SelectInputCookie struct {
*xgb.Cookie
}
// SelectInput sends a checked request.
// If an error occurs, it will be returned with the reply by calling SelectInputCookie.Reply()
func SelectInput(c *xgb.Conn, EventMask uint32) SelectInputCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XEVIE"]; !ok {
panic("Cannot issue request 'SelectInput' using the uninitialized extension 'XEVIE'. xevie.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(selectInputRequest(c, EventMask), cookie)
return SelectInputCookie{cookie}
}
// SelectInputUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func SelectInputUnchecked(c *xgb.Conn, EventMask uint32) SelectInputCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XEVIE"]; !ok {
panic("Cannot issue request 'SelectInput' using the uninitialized extension 'XEVIE'. xevie.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(selectInputRequest(c, EventMask), cookie)
return SelectInputCookie{cookie}
}
// SelectInputReply represents the data returned from a SelectInput request.
type SelectInputReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
// padding: 24 bytes
}
// Reply blocks and returns the reply data for a SelectInput request.
func (cook SelectInputCookie) Reply() (*SelectInputReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return selectInputReply(buf), nil
}
// selectInputReply reads a byte slice into a SelectInputReply value.
func selectInputReply(buf []byte) *SelectInputReply {
v := new(SelectInputReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
b += 24 // padding
return v
}
// Write request to wire for SelectInput
// selectInputRequest writes a SelectInput request to a byte slice.
func selectInputRequest(c *xgb.Conn, EventMask uint32) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["XEVIE"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 4 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], EventMask)
b += 4
return buf
}
// SendCookie is a cookie used only for Send requests.
type SendCookie struct {
*xgb.Cookie
}
// Send sends a checked request.
// If an error occurs, it will be returned with the reply by calling SendCookie.Reply()
func Send(c *xgb.Conn, Event Event, DataType uint32) SendCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XEVIE"]; !ok {
panic("Cannot issue request 'Send' using the uninitialized extension 'XEVIE'. xevie.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(sendRequest(c, Event, DataType), cookie)
return SendCookie{cookie}
}
// SendUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func SendUnchecked(c *xgb.Conn, Event Event, DataType uint32) SendCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XEVIE"]; !ok {
panic("Cannot issue request 'Send' using the uninitialized extension 'XEVIE'. xevie.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(sendRequest(c, Event, DataType), cookie)
return SendCookie{cookie}
}
// SendReply represents the data returned from a Send request.
type SendReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
// padding: 24 bytes
}
// Reply blocks and returns the reply data for a Send request.
func (cook SendCookie) Reply() (*SendReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return sendReply(buf), nil
}
// sendReply reads a byte slice into a SendReply value.
func sendReply(buf []byte) *SendReply {
v := new(SendReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
b += 24 // padding
return v
}
// Write request to wire for Send
// sendRequest writes a Send request to a byte slice.
func sendRequest(c *xgb.Conn, Event Event, DataType uint32) []byte {
size := 104
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["XEVIE"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 3 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
{
structBytes := Event.Bytes()
copy(buf[b:], structBytes)
b += len(structBytes)
}
xgb.Put32(buf[b:], DataType)
b += 4
b += 64 // padding
return buf
}
// StartCookie is a cookie used only for Start requests.
type StartCookie struct {
*xgb.Cookie
}
// Start sends a checked request.
// If an error occurs, it will be returned with the reply by calling StartCookie.Reply()
func Start(c *xgb.Conn, Screen uint32) StartCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XEVIE"]; !ok {
panic("Cannot issue request 'Start' using the uninitialized extension 'XEVIE'. xevie.Init(connObj) must be called first.")
}
cookie := c.NewCookie(true, true)
c.NewRequest(startRequest(c, Screen), cookie)
return StartCookie{cookie}
}
// StartUnchecked sends an unchecked request.
// If an error occurs, it can only be retrieved using xgb.WaitForEvent or xgb.PollForEvent.
func StartUnchecked(c *xgb.Conn, Screen uint32) StartCookie {
c.ExtLock.RLock()
defer c.ExtLock.RUnlock()
if _, ok := c.Extensions["XEVIE"]; !ok {
panic("Cannot issue request 'Start' using the uninitialized extension 'XEVIE'. xevie.Init(connObj) must be called first.")
}
cookie := c.NewCookie(false, true)
c.NewRequest(startRequest(c, Screen), cookie)
return StartCookie{cookie}
}
// StartReply represents the data returned from a Start request.
type StartReply struct {
Sequence uint16 // sequence number of the request for this reply
Length uint32 // number of bytes in this reply
// padding: 1 bytes
// padding: 24 bytes
}
// Reply blocks and returns the reply data for a Start request.
func (cook StartCookie) Reply() (*StartReply, error) {
buf, err := cook.Cookie.Reply()
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return startReply(buf), nil
}
// startReply reads a byte slice into a StartReply value.
func startReply(buf []byte) *StartReply {
v := new(StartReply)
b := 1 // skip reply determinant
b += 1 // padding
v.Sequence = xgb.Get16(buf[b:])
b += 2
v.Length = xgb.Get32(buf[b:]) // 4-byte units
b += 4
b += 24 // padding
return v
}
// Write request to wire for Start
// startRequest writes a Start request to a byte slice.
func startRequest(c *xgb.Conn, Screen uint32) []byte {
size := 8
b := 0
buf := make([]byte, size)
c.ExtLock.RLock()
buf[b] = c.Extensions["XEVIE"]
c.ExtLock.RUnlock()
b += 1
buf[b] = 1 // request opcode
b += 1
xgb.Put16(buf[b:], uint16(size/4)) // write request size in 4-byte units
b += 2
xgb.Put32(buf[b:], Screen)
b += 4
return buf
}

1301
vend/xgb/xf86dri/xf86dri.go Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2995
vend/xgb/xfixes/xfixes.go Normal file

File diff suppressed because it is too large Load Diff

608
vend/xgb/xgb.go Normal file
View File

@ -0,0 +1,608 @@
package xgb
import (
"errors"
"io"
"log"
"net"
"os"
"sync"
)
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)
)
const (
// cookieBuffer represents the queue size of cookies existing at any
// point in time. The size of the buffer is really only important when
// there are many requests without replies made in sequence. Once the
// buffer fills, a round trip request is made to clear the buffer.
cookieBuffer = 1000
// xidBuffer represents the queue size of the xid channel.
// I don't think this value matters much, since xid generation is not
// that expensive.
xidBuffer = 5
// seqBuffer represents the queue size of the sequence number channel.
// I don't think this value matters much, since sequence number generation
// is not that expensive.
seqBuffer = 5
// reqBuffer represents the queue size of the number of requests that
// can be made until new ones block. This value seems OK.
reqBuffer = 100
// eventBuffer represents the queue size of the number of events or errors
// that can be loaded off the wire and not grabbed with WaitForEvent
// until reading an event blocks. This value should be big enough to handle
// bursts of events.
eventBuffer = 5000
)
// A Conn represents a connection to an X server.
type Conn struct {
host string
conn net.Conn
display string
DisplayNumber int
DefaultScreen int
SetupBytes []byte
setupResourceIdBase uint32
setupResourceIdMask uint32
eventChan chan eventOrError
cookieChan chan *Cookie
xidChan chan xid
seqChan chan uint16
reqChan chan *request
doneSend chan struct{}
doneRead chan struct{}
// 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
}
// 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 NewConn() (*Conn, error) {
return NewConnDisplay("")
}
// 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 NewConnDisplay(display string) (*Conn, error) {
c := &Conn{}
// First connect. This reads authority, checks DISPLAY environment
// variable, and loads the initial Setup info.
err := c.connect(display)
if err != nil {
return nil, err
}
return postNewConn(c)
}
// NewConnNet is just like NewConn (see closing instructions), but allows a specific net.Conn
// to be used.
func NewConnNet(netConn net.Conn) (*Conn, error) {
c := &Conn{}
// First connect. This reads authority, checks DISPLAY environment
// variable, and loads the initial Setup info.
err := c.connectNet(netConn)
if err != nil {
return nil, err
}
return postNewConn(c)
}
func postNewConn(c *Conn) (*Conn, error) {
c.Extensions = make(map[string]byte)
c.cookieChan = make(chan *Cookie, cookieBuffer)
c.xidChan = make(chan xid, xidBuffer)
c.seqChan = make(chan uint16, seqBuffer)
c.reqChan = make(chan *request, reqBuffer)
c.eventChan = make(chan eventOrError, eventBuffer)
c.doneSend = make(chan struct{})
c.doneRead = make(chan struct{})
go c.generateXIds()
go c.generateSeqIds()
go c.sendRequests()
go c.readResponses()
return c, nil
}
// Close gracefully closes the connection to the X server.
// When everything is cleaned up, the WaitForEvent method will return (nil, nil)
func (c *Conn) Close() {
select {
case c.reqChan <- nil:
case <-c.doneSend:
}
}
// 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 Event interface {
Bytes() []byte
String() string
}
// 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.
type NewEventFun func(buf []byte) Event
// 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.
var NewEventFuncs = make(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.
var NewExtEventFuncs = make(map[string]map[int]NewEventFun)
// 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 Error interface {
SequenceId() uint16
BadId() uint32
Error() string
}
// 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 NewErrorFun func(buf []byte) Error
// 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.
var NewErrorFuncs = make(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.
var NewExtErrorFuncs = make(map[string]map[int]NewErrorFun)
// eventOrError corresponds to values that can be either an event or an
// error.
type eventOrError interface{}
// 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 (c *Conn) NewId() (uint32, error) {
xid, ok := <-c.xidChan
if !ok {
return 0, io.EOF
}
if xid.err != nil {
return 0, xid.err
}
return xid.id, nil
}
// xid encapsulates a resource identifier being sent over the Conn.xidChan
// channel. If no new resource id can be generated, id is set to 0 and a
// non-nil error is set in xid.err.
type xid struct {
id uint32
err error
}