summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--README12
-rw-r--r--bigreq/bigreq.go4
-rw-r--r--composite/composite.go6
-rw-r--r--cookie.go13
-rw-r--r--damage/damage.go6
-rw-r--r--doc.go10
-rw-r--r--dpms/dpms.go4
-rw-r--r--dri2/dri2.go4
-rw-r--r--examples/atoms/main.go4
-rw-r--r--examples/create-window/main.go4
-rw-r--r--examples/doc.go2
-rw-r--r--examples/get-active-window/main.go4
-rw-r--r--examples/randr/main.go6
-rw-r--r--examples/xinerama/main.go4
-rw-r--r--ge/ge.go4
-rw-r--r--glx/glx.go4
-rw-r--r--randr/randr.go6
-rw-r--r--record/record.go4
-rw-r--r--render/render.go4
-rw-r--r--res/res.go4
-rw-r--r--screensaver/screensaver.go4
-rw-r--r--shape/shape.go4
-rw-r--r--shm/shm.go4
-rw-r--r--xcmisc/xcmisc.go4
-rw-r--r--xevie/xevie.go4
-rw-r--r--xf86dri/xf86dri.go4
-rw-r--r--xf86vidmode/xf86vidmode.go4
-rw-r--r--xfixes/xfixes.go8
-rw-r--r--xgb.go206
-rw-r--r--xgbgen/context.go6
-rw-r--r--xinerama/xinerama.go4
-rw-r--r--xprint/xprint.go4
-rw-r--r--xproto/xproto.go2
-rw-r--r--xproto/xproto_test.go2
-rw-r--r--xselinux/xselinux.go4
-rw-r--r--xtest/xtest.go4
-rw-r--r--xv/xv.go6
-rw-r--r--xvmc/xvmc.go6
39 files changed, 234 insertions, 157 deletions
diff --git a/Makefile b/Makefile
index 7a3dae2..c0ee531 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,9 @@
# 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
diff --git a/README b/README
index c96a5fb..ffd4092 100644
--- a/README
+++ b/README
@@ -10,10 +10,18 @@ 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/BurntSushi/xgb
-go run go/path/src/github.com/BurntSushi/xgb/examples/create-window/main.go
+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 be used in other project.
+
+Will make some changes to tailor it for my needs.
BurntSushi's Fork
=================
diff --git a/bigreq/bigreq.go b/bigreq/bigreq.go
index 6590376..d8a5859 100644
--- a/bigreq/bigreq.go
+++ b/bigreq/bigreq.go
@@ -4,9 +4,9 @@ package bigreq
// This file is automatically generated from bigreq.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the BIG-REQUESTS extension.
diff --git a/composite/composite.go b/composite/composite.go
index 1373f8b..4622cee 100644
--- a/composite/composite.go
+++ b/composite/composite.go
@@ -4,10 +4,10 @@ package composite
// This file is automatically generated from composite.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xfixes"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xfixes"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the Composite extension.
diff --git a/cookie.go b/cookie.go
index d5cdb29..c012cfd 100644
--- a/cookie.go
+++ b/cookie.go
@@ -2,6 +2,7 @@ package xgb
import (
"errors"
+ "io"
)
// Cookie is the internal representation of a cookie, where one is generated
@@ -80,6 +81,7 @@ func (c Cookie) Reply() ([]byte, error) {
// 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.
@@ -98,6 +100,9 @@ func (c Cookie) replyChecked() ([]byte, error) {
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
}
}
@@ -106,6 +111,7 @@ func (c Cookie) replyChecked() ([]byte, 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
@@ -121,6 +127,9 @@ func (c Cookie) replyUnchecked() ([]byte, error) {
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
}
}
@@ -132,6 +141,7 @@ func (c Cookie) replyUnchecked() ([]byte, error) {
// 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.
@@ -161,5 +171,8 @@ func (c Cookie) Check() error {
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
}
}
diff --git a/damage/damage.go b/damage/damage.go
index 26eca04..53326d9 100644
--- a/damage/damage.go
+++ b/damage/damage.go
@@ -4,10 +4,10 @@ package damage
// This file is automatically generated from damage.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xfixes"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xfixes"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the DAMAGE extension.
diff --git a/doc.go b/doc.go
index 64540e9..3a28558 100644
--- a/doc.go
+++ b/doc.go
@@ -10,7 +10,7 @@ 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/BurntSushi/xgbutil
+https://github.com/jezek/xgbutil
Example
@@ -23,8 +23,8 @@ accompanying documentation can be found in examples/create-window.
import (
"fmt"
- "github.com/BurntSushi/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb"
+ "github.com/jezek/xgb/xproto"
)
func main() {
@@ -74,8 +74,8 @@ can be found in examples/xinerama.
import (
"fmt"
"log"
- "github.com/BurntSushi/xgb"
- "github.com/BurntSushi/xgb/xinerama"
+ "github.com/jezek/xgb"
+ "github.com/jezek/xgb/xinerama"
)
func main() {
diff --git a/dpms/dpms.go b/dpms/dpms.go
index 4bf5883..da28f1e 100644
--- a/dpms/dpms.go
+++ b/dpms/dpms.go
@@ -4,9 +4,9 @@ package dpms
// This file is automatically generated from dpms.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the DPMS extension.
diff --git a/dri2/dri2.go b/dri2/dri2.go
index 820cf2b..1cc1d0a 100644
--- a/dri2/dri2.go
+++ b/dri2/dri2.go
@@ -4,9 +4,9 @@ package dri2
// This file is automatically generated from dri2.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the DRI2 extension.
diff --git a/examples/atoms/main.go b/examples/atoms/main.go
index 8985768..b94a772 100644
--- a/examples/atoms/main.go
+++ b/examples/atoms/main.go
@@ -9,8 +9,8 @@ import (
"runtime/pprof"
"time"
- "github.com/BurntSushi/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb"
+ "github.com/jezek/xgb/xproto"
)
var (
diff --git a/examples/create-window/main.go b/examples/create-window/main.go
index 73a0099..50a9bff 100644
--- a/examples/create-window/main.go
+++ b/examples/create-window/main.go
@@ -7,8 +7,8 @@ package main
import (
"fmt"
- "github.com/BurntSushi/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb"
+ "github.com/jezek/xgb/xproto"
)
func main() {
diff --git a/examples/doc.go b/examples/doc.go
index 80ea5b7..20fed98 100644
--- a/examples/doc.go
+++ b/examples/doc.go
@@ -11,7 +11,7 @@ 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 my higher level
-library, xgbutil: https://github.com/BurntSushi/xgbutil
+library, 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,
diff --git a/examples/get-active-window/main.go b/examples/get-active-window/main.go
index 48e020c..37f374c 100644
--- a/examples/get-active-window/main.go
+++ b/examples/get-active-window/main.go
@@ -6,8 +6,8 @@ import (
"fmt"
"log"
- "github.com/BurntSushi/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb"
+ "github.com/jezek/xgb/xproto"
)
func main() {
diff --git a/examples/randr/main.go b/examples/randr/main.go
index e349144..13b934a 100644
--- a/examples/randr/main.go
+++ b/examples/randr/main.go
@@ -14,9 +14,9 @@ import (
"fmt"
"log"
- "github.com/BurntSushi/xgb"
- "github.com/BurntSushi/xgb/randr"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb"
+ "github.com/jezek/xgb/randr"
+ "github.com/jezek/xgb/xproto"
)
func main() {
diff --git a/examples/xinerama/main.go b/examples/xinerama/main.go
index 896bb63..a7e1531 100644
--- a/examples/xinerama/main.go
+++ b/examples/xinerama/main.go
@@ -5,8 +5,8 @@ import (
"fmt"
"log"
- "github.com/BurntSushi/xgb"
- "github.com/BurntSushi/xgb/xinerama"
+ "github.com/jezek/xgb"
+ "github.com/jezek/xgb/xinerama"
)
func main() {
diff --git a/ge/ge.go b/ge/ge.go
index f7e1ce4..1466744 100644
--- a/ge/ge.go
+++ b/ge/ge.go
@@ -4,9 +4,9 @@ package ge
// This file is automatically generated from ge.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the Generic Event Extension extension.
diff --git a/glx/glx.go b/glx/glx.go
index cf72d9a..3b87616 100644
--- a/glx/glx.go
+++ b/glx/glx.go
@@ -4,9 +4,9 @@ package glx
// This file is automatically generated from glx.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the GLX extension.
diff --git a/randr/randr.go b/randr/randr.go
index 021c011..bc62d73 100644
--- a/randr/randr.go
+++ b/randr/randr.go
@@ -4,10 +4,10 @@ package randr
// This file is automatically generated from randr.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/render"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/render"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the RANDR extension.
diff --git a/record/record.go b/record/record.go
index 5469170..419587f 100644
--- a/record/record.go
+++ b/record/record.go
@@ -4,9 +4,9 @@ package record
// This file is automatically generated from record.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the RECORD extension.
diff --git a/render/render.go b/render/render.go
index e15bd67..223162a 100644
--- a/render/render.go
+++ b/render/render.go
@@ -4,9 +4,9 @@ package render
// This file is automatically generated from render.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the RENDER extension.
diff --git a/res/res.go b/res/res.go
index 0ad0389..18cbb68 100644
--- a/res/res.go
+++ b/res/res.go
@@ -4,9 +4,9 @@ package res
// This file is automatically generated from res.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the X-Resource extension.
diff --git a/screensaver/screensaver.go b/screensaver/screensaver.go
index 418576c..6854505 100644
--- a/screensaver/screensaver.go
+++ b/screensaver/screensaver.go
@@ -4,9 +4,9 @@ package screensaver
// This file is automatically generated from screensaver.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the MIT-SCREEN-SAVER extension.
diff --git a/shape/shape.go b/shape/shape.go
index 7069f7e..42b3f9f 100644
--- a/shape/shape.go
+++ b/shape/shape.go
@@ -4,9 +4,9 @@ package shape
// This file is automatically generated from shape.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the SHAPE extension.
diff --git a/shm/shm.go b/shm/shm.go
index b310c34..732eb68 100644
--- a/shm/shm.go
+++ b/shm/shm.go
@@ -4,9 +4,9 @@ package shm
// This file is automatically generated from shm.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the MIT-SHM extension.
diff --git a/xcmisc/xcmisc.go b/xcmisc/xcmisc.go
index 1778057..93dd20f 100644
--- a/xcmisc/xcmisc.go
+++ b/xcmisc/xcmisc.go
@@ -4,9 +4,9 @@ package xcmisc
// This file is automatically generated from xc_misc.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the XC-MISC extension.
diff --git a/xevie/xevie.go b/xevie/xevie.go
index 180312b..f0ddd31 100644
--- a/xevie/xevie.go
+++ b/xevie/xevie.go
@@ -4,9 +4,9 @@ package xevie
// This file is automatically generated from xevie.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the XEVIE extension.
diff --git a/xf86dri/xf86dri.go b/xf86dri/xf86dri.go
index 51c9322..bc67e9b 100644
--- a/xf86dri/xf86dri.go
+++ b/xf86dri/xf86dri.go
@@ -4,9 +4,9 @@ package xf86dri
// This file is automatically generated from xf86dri.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the XFree86-DRI extension.
diff --git a/xf86vidmode/xf86vidmode.go b/xf86vidmode/xf86vidmode.go
index 2829fd6..6bd3232 100644
--- a/xf86vidmode/xf86vidmode.go
+++ b/xf86vidmode/xf86vidmode.go
@@ -4,9 +4,9 @@ package xf86vidmode
// This file is automatically generated from xf86vidmode.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the XFree86-VidModeExtension extension.
diff --git a/xfixes/xfixes.go b/xfixes/xfixes.go
index 0f9e4b0..5751527 100644
--- a/xfixes/xfixes.go
+++ b/xfixes/xfixes.go
@@ -4,11 +4,11 @@ package xfixes
// This file is automatically generated from xfixes.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/render"
- "github.com/BurntSushi/xgb/shape"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/render"
+ "github.com/jezek/xgb/shape"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the XFIXES extension.
diff --git a/xgb.go b/xgb.go
index 3d2c61f..d605da6 100644
--- a/xgb.go
+++ b/xgb.go
@@ -60,7 +60,8 @@ type Conn struct {
xidChan chan xid
seqChan chan uint16
reqChan chan *request
- closing chan chan struct{}
+ 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
@@ -75,11 +76,13 @@ type Conn struct {
// 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, but allows a specific DISPLAY
+// 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").
//
@@ -89,55 +92,60 @@ func NewConn() (*Conn, error) {
// 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) {
- conn := &Conn{}
+ c := &Conn{}
// First connect. This reads authority, checks DISPLAY environment
// variable, and loads the initial Setup info.
- err := conn.connect(display)
+ err := c.connect(display)
if err != nil {
return nil, err
}
- return postNewConn(conn)
+ return postNewConn(c)
}
-// NewConnDisplay is just like NewConn, but allows a specific net.Conn
+// NewConnNet is just like NewConn (see closing instructions), but allows a specific net.Conn
// to be used.
func NewConnNet(netConn net.Conn) (*Conn, error) {
- conn := &Conn{}
+ c := &Conn{}
// First connect. This reads authority, checks DISPLAY environment
// variable, and loads the initial Setup info.
- err := conn.connectNet(netConn)
+ err := c.connectNet(netConn)
if err != nil {
return nil, err
}
- return postNewConn(conn)
+ return postNewConn(c)
}
-func postNewConn(conn *Conn) (*Conn, error) {
- conn.Extensions = make(map[string]byte)
+func postNewConn(c *Conn) (*Conn, error) {
+ c.Extensions = make(map[string]byte)
- conn.cookieChan = make(chan *Cookie, cookieBuffer)
- conn.xidChan = make(chan xid, xidBuffer)
- conn.seqChan = make(chan uint16, seqBuffer)
- conn.reqChan = make(chan *request, reqBuffer)
- conn.eventChan = make(chan eventOrError, eventBuffer)
- conn.closing = make(chan chan struct{}, 1)
+ 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 conn.generateXIds()
- go conn.generateSeqIds()
- go conn.sendRequests()
- go conn.readResponses()
+ go c.generateXIds()
+ go c.generateSeqIds()
+ go c.sendRequests()
+ go c.readResponses()
- return conn, nil
+ 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() {
- close(c.reqChan)
+ select {
+ case c.reqChan <- nil:
+ case <-c.doneSend:
+ }
}
// Event is an interface that can contain any of the events returned by the
@@ -196,8 +204,12 @@ type eventOrError interface{}
// 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 := <-c.xidChan
+ xid, ok := <-c.xidChan
+ if !ok {
+ return 0, io.EOF
+ }
if xid.err != nil {
return 0, xid.err
}
@@ -217,8 +229,8 @@ type xid struct {
// This needs to be updated to use the XC Misc extension once we run out of
// new ids.
// Thanks to libxcb/src/xcb_xid.c. This code is greatly inspired by it.
-func (conn *Conn) generateXIds() {
- defer close(conn.xidChan)
+func (c *Conn) generateXIds() {
+ defer close(c.xidChan)
// This requires some explanation. From the horse's mouth:
// "The resource-id-mask contains a single contiguous set of bits (at least
@@ -236,23 +248,30 @@ func (conn *Conn) generateXIds() {
// 00111000 & 11001000 = 00001000.
// And we use that value to increment the last resource id to get a new one.
// (And then, of course, we OR it with resource-id-base.)
- inc := conn.setupResourceIdMask & -conn.setupResourceIdMask
- max := conn.setupResourceIdMask
+ inc := c.setupResourceIdMask & -c.setupResourceIdMask
+ max := c.setupResourceIdMask
last := uint32(0)
for {
- // TODO: Use the XC Misc extension to look for released ids.
+ id := xid{}
if last > 0 && last >= max-inc+1 {
- conn.xidChan <- xid{
- id: 0,
- err: errors.New("There are no more available resource" +
- "identifiers."),
+ // TODO: Use the XC Misc extension to look for released ids.
+ id = xid{
+ id: 0,
+ err: errors.New("There are no more available resource identifiers."),
+ }
+ } else {
+ last += inc
+ id = xid{
+ id: last | c.setupResourceIdBase,
+ err: nil,
}
}
- last += inc
- conn.xidChan <- xid{
- id: last | conn.setupResourceIdBase,
- err: nil,
+ select {
+ case c.xidChan <- id:
+ case <-c.doneSend:
+ // c.sendRequests is down and since this id is used by requests, we don't need this goroutine running anymore.
+ return
}
}
}
@@ -275,11 +294,16 @@ func (c *Conn) generateSeqIds() {
seqid := uint16(1)
for {
- c.seqChan <- seqid
- if seqid == uint16((1<<16)-1) {
- seqid = 0
- } else {
- seqid++
+ select {
+ case c.seqChan <- seqid:
+ if seqid == uint16((1<<16)-1) {
+ seqid = 0
+ } else {
+ seqid++
+ }
+ case <-c.doneSend:
+ // c.sendRequests is down and since only that function uses sequence ids (via newSequenceId method), we don't need this goroutine running anymore.
+ return
}
}
}
@@ -315,8 +339,19 @@ type request struct {
// edits the generated code for the request you want to issue.
func (c *Conn) NewRequest(buf []byte, cookie *Cookie) {
seq := make(chan struct{})
- c.reqChan <- &request{buf: buf, cookie: cookie, seq: seq}
- <-seq
+ select {
+ case c.reqChan <- &request{buf: buf, cookie: cookie, seq: seq}:
+ // request is in buffer
+ // wait until request is processed or connection is closed
+ select {
+ case <-seq:
+ // request was successfully sent to X server
+ case <-c.doneSend:
+ // c.sendRequests is down, your request was not handled
+ }
+ case <-c.doneSend:
+ // c.sendRequests is down, nobody is listening to your requests
+ }
}
// sendRequests is run as a single goroutine that takes requests and writes
@@ -324,28 +359,45 @@ func (c *Conn) NewRequest(buf []byte, cookie *Cookie) {
// It is meant to be run as its own goroutine.
func (c *Conn) sendRequests() {
defer close(c.cookieChan)
+ defer c.conn.Close()
+ defer close(c.doneSend)
- for req := range c.reqChan {
- // ho there! if the cookie channel is nearly full, force a round
- // trip to clear out the cookie buffer.
- // Note that we circumvent the request channel, because we're *in*
- // the request channel.
- if len(c.cookieChan) == cookieBuffer-1 {
- if err := c.noop(); err != nil {
- // Shut everything down.
- break
+ for {
+ select {
+ case req := <-c.reqChan:
+ if req == nil {
+ // a request by c.Close() to gracefully exit
+ // Flush the response reading goroutine.
+ if err := c.noop(); err != nil {
+ c.conn.Close()
+ <-c.doneRead
+ }
+ return
+ }
+ // ho there! if the cookie channel is nearly full, force a round
+ // trip to clear out the cookie buffer.
+ // Note that we circumvent the request channel, because we're *in*
+ // the request channel.
+ if len(c.cookieChan) == cookieBuffer-1 {
+ if err := c.noop(); err != nil {
+ // Shut everything down.
+ c.conn.Close()
+ <-c.doneRead
+ return
+ }
+ }
+ req.cookie.Sequence = c.newSequenceId()
+ c.cookieChan <- req.cookie
+ if err := c.writeBuffer(req.buf); err != nil {
+ c.conn.Close()
+ <-c.doneRead
+ return
}
+ close(req.seq)
+ case <-c.doneRead:
+ return
}
- req.cookie.Sequence = c.newSequenceId()
- c.cookieChan <- req.cookie
- c.writeBuffer(req.buf)
- close(req.seq)
}
- response := make(chan struct{})
- c.closing <- response
- c.noop() // Flush the response reading goroutine, ignore error.
- <-response
- c.conn.Close()
}
// noop circumvents the usual request sending goroutines and forces a round
@@ -366,9 +418,8 @@ func (c *Conn) writeBuffer(buf []byte) error {
if _, err := c.conn.Write(buf); err != nil {
Logger.Printf("A write error is unrecoverable: %s", err)
return err
- } else {
- return nil
}
+ return nil
}
// readResponses is a goroutine that reads events, errors and
@@ -382,6 +433,8 @@ func (c *Conn) writeBuffer(buf []byte) error {
// Finally, cookies that came "before" this reply are always cleaned up.
func (c *Conn) readResponses() {
defer close(c.eventChan)
+ defer c.conn.Close()
+ defer close(c.doneRead)
var (
err Error
@@ -390,20 +443,18 @@ func (c *Conn) readResponses() {
)
for {
- select {
- case respond := <-c.closing:
- respond <- struct{}{}
- return
- default:
- }
-
buf := make([]byte, 32)
err, seq = nil, 0
if _, err := io.ReadFull(c.conn, buf); err != nil {
+ select {
+ case <-c.doneSend:
+ // gracefully closing
+ return
+ default:
+ }
Logger.Printf("A read error is unrecoverable: %s", err)
c.eventChan <- err
- c.Close()
- continue
+ return
}
switch buf[0] {
case 0: // This is an error
@@ -432,8 +483,7 @@ func (c *Conn) readResponses() {
if _, err := io.ReadFull(c.conn, biggerBuf[32:]); err != nil {
Logger.Printf("A read error is unrecoverable: %s", err)
c.eventChan <- err
- c.Close()
- continue
+ return
}
replyBytes = biggerBuf
} else {
@@ -522,10 +572,14 @@ func processEventOrError(everr eventOrError) (Event, Error) {
return ee, nil
case Error:
return nil, ee
+ case error:
+ // c.conn read error
+ case nil:
+ // c.eventChan is closed
default:
Logger.Printf("Invalid event/error type: %T", everr)
- return nil, nil
}
+ return nil, nil
}
// WaitForEvent returns the next event from the server.
diff --git a/xgbgen/context.go b/xgbgen/context.go
index f18fd67..755cf6e 100644
--- a/xgbgen/context.go
+++ b/xgbgen/context.go
@@ -64,10 +64,10 @@ func (c *Context) Morph(xmlBytes []byte) {
// Write imports. We always need to import at least xgb.
// We also need to import xproto if it's an extension.
c.Putln("import (")
- c.Putln("\"github.com/BurntSushi/xgb\"")
+ c.Putln("\"github.com/jezek/xgb\"")
c.Putln("")
if c.protocol.isExt() {
- c.Putln("\"github.com/BurntSushi/xgb/xproto\"")
+ c.Putln("\"github.com/jezek/xgb/xproto\"")
}
sort.Sort(Protocols(c.protocol.Imports))
@@ -76,7 +76,7 @@ func (c *Context) Morph(xmlBytes []byte) {
if imp.Name == "xproto" {
continue
}
- c.Putln("\"github.com/BurntSushi/xgb/%s\"", imp.Name)
+ c.Putln("\"github.com/jezek/xgb/%s\"", imp.Name)
}
c.Putln(")")
c.Putln("")
diff --git a/xinerama/xinerama.go b/xinerama/xinerama.go
index ec97406..580387c 100644
--- a/xinerama/xinerama.go
+++ b/xinerama/xinerama.go
@@ -4,9 +4,9 @@ package xinerama
// This file is automatically generated from xinerama.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the XINERAMA extension.
diff --git a/xprint/xprint.go b/xprint/xprint.go
index d692aed..97e06e1 100644
--- a/xprint/xprint.go
+++ b/xprint/xprint.go
@@ -4,9 +4,9 @@ package xprint
// This file is automatically generated from xprint.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the XpExtension extension.
diff --git a/xproto/xproto.go b/xproto/xproto.go
index 716c49b..8d7e51b 100644
--- a/xproto/xproto.go
+++ b/xproto/xproto.go
@@ -4,7 +4,7 @@ package xproto
// This file is automatically generated from xproto.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
)
// Setup parses the setup bytes retrieved when
diff --git a/xproto/xproto_test.go b/xproto/xproto_test.go
index a5bec71..f8080bf 100644
--- a/xproto/xproto_test.go
+++ b/xproto/xproto_test.go
@@ -26,7 +26,7 @@ import (
"testing"
"time"
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
)
// The X connection used throughout testing.
diff --git a/xselinux/xselinux.go b/xselinux/xselinux.go
index 1afcc10..68d55ea 100644
--- a/xselinux/xselinux.go
+++ b/xselinux/xselinux.go
@@ -4,9 +4,9 @@ package xselinux
// This file is automatically generated from xselinux.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the SELinux extension.
diff --git a/xtest/xtest.go b/xtest/xtest.go
index 182760e..c11cfc6 100644
--- a/xtest/xtest.go
+++ b/xtest/xtest.go
@@ -4,9 +4,9 @@ package xtest
// This file is automatically generated from xtest.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the XTEST extension.
diff --git a/xv/xv.go b/xv/xv.go
index f0d3f3a..e4e36e9 100644
--- a/xv/xv.go
+++ b/xv/xv.go
@@ -4,10 +4,10 @@ package xv
// This file is automatically generated from xv.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/shm"
- "github.com/BurntSushi/xgb/xproto"
+ "github.com/jezek/xgb/shm"
+ "github.com/jezek/xgb/xproto"
)
// Init must be called before using the XVideo extension.
diff --git a/xvmc/xvmc.go b/xvmc/xvmc.go
index b943fa0..3f61416 100644
--- a/xvmc/xvmc.go
+++ b/xvmc/xvmc.go
@@ -4,10 +4,10 @@ package xvmc
// This file is automatically generated from xvmc.xml. Edit at your peril!
import (
- "github.com/BurntSushi/xgb"
+ "github.com/jezek/xgb"
- "github.com/BurntSushi/xgb/xproto"
- "github.com/BurntSushi/xgb/xv"
+ "github.com/jezek/xgb/xproto"
+ "github.com/jezek/xgb/xv"
)
// Init must be called before using the XVideo-MotionCompensation extension.