reworking xgb. cleaned up connection stuff a little. making new xid generation cleaner and use goroutines for it.
This commit is contained in:
parent
5cdae5950c
commit
a5d4ad6c9d
|
@ -44,8 +44,10 @@ func getString(r io.Reader, b []byte) (string, error) {
|
||||||
|
|
||||||
// readAuthority reads the X authority file for the DISPLAY.
|
// readAuthority reads the X authority file for the DISPLAY.
|
||||||
// If hostname == "" or hostname == "localhost",
|
// If hostname == "" or hostname == "localhost",
|
||||||
// readAuthority uses the system's hostname (as returned by os.Hostname) instead.
|
// then use the system's hostname (as returned by os.Hostname) instead.
|
||||||
func readAuthority(hostname, display string) (name string, data []byte, err error) {
|
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
|
// 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).
|
// (i.e. it should be able to hold a hostname).
|
||||||
var b [256]byte
|
var b [256]byte
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
package xgb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// connect connects to the X server given in the 'display' string.
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get authentication data
|
||||||
|
authName, authData, err := readAuthority(c.host, c.display)
|
||||||
|
noauth := false
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Could not get authority info: %v\n", err)
|
||||||
|
fmt.Fprintf(os.Stderr, "Trying connection without authority info...\n")
|
||||||
|
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 errors.New(fmt.Sprintf("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 errors.New(fmt.Sprintf("x protocol authentication refused: %s",
|
||||||
|
string(reason)))
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadSetupInfo(buf, &c.Setup)
|
||||||
|
|
||||||
|
if c.defaultScreen >= len(c.Setup.Roots) {
|
||||||
|
c.defaultScreen = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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:]
|
||||||
|
}
|
||||||
|
|
||||||
|
dispnum, err := strconv.Atoi(c.display)
|
||||||
|
if err != nil || dispnum < 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 {
|
||||||
|
if protocol == "" {
|
||||||
|
protocol = "tcp"
|
||||||
|
}
|
||||||
|
c.conn, err = net.Dial(protocol, c.host+":"+strconv.Itoa(6000+dispnum))
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/xgb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.SetFlags(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
X, err := xgb.NewConn()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
aname := "_NET_ACTIVE_WINDOW"
|
||||||
|
atom, err := X.InternAtom(true, uint16(len(aname)), aname)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Printf("%d", atom.Atom)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/xgb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.SetFlags(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
X, err := xgb.NewConn()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
root := X.DefaultScreen().Root
|
||||||
|
|
||||||
|
aname := "_NET_ACTIVE_WINDOW"
|
||||||
|
atom, err := X.InternAtom(true, uint16(len(aname)), aname)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := X.GetProperty(false, root, atom.Atom, xgb.GetPropertyTypeAny,
|
||||||
|
0, (1<<32)-1)
|
||||||
|
log.Printf("%X", get32(reply.Value))
|
||||||
|
}
|
||||||
|
|
257
nexgb/xgb.go
257
nexgb/xgb.go
|
@ -12,7 +12,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
@ -23,11 +22,9 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Conn represents a connection to an X server.
|
// A Conn represents a connection to an X server.
|
||||||
// Only one goroutine should use a Conn's methods at a time.
|
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
host string
|
host string
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
nextId Id
|
|
||||||
nextCookie uint16
|
nextCookie uint16
|
||||||
cookies map[uint16]*Cookie
|
cookies map[uint16]*Cookie
|
||||||
events queue
|
events queue
|
||||||
|
@ -44,6 +41,7 @@ type Conn struct {
|
||||||
eventChan chan bool
|
eventChan chan bool
|
||||||
errorChan chan bool
|
errorChan chan bool
|
||||||
|
|
||||||
|
xidChan chan xid
|
||||||
newIdLock sync.Mutex
|
newIdLock sync.Mutex
|
||||||
writeLock sync.Mutex
|
writeLock sync.Mutex
|
||||||
dequeueLock sync.Mutex
|
dequeueLock sync.Mutex
|
||||||
|
@ -51,6 +49,51 @@ type Conn struct {
|
||||||
extLock sync.Mutex
|
extLock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.)
|
||||||
|
func NewConn() (*Conn, error) {
|
||||||
|
return NewConnDisplay("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConnDisplay is just like NewConn, 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-123/:0") -> net.Dial("unix", "", "/tmp/launch-123/: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) {
|
||||||
|
conn := &Conn{}
|
||||||
|
|
||||||
|
// First connect. This reads authority, checks DISPLAY environment
|
||||||
|
// variable, and loads the initial Setup info.
|
||||||
|
err := conn.connect(display)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.xidChan = make(chan xid, 5)
|
||||||
|
go conn.generateXids()
|
||||||
|
|
||||||
|
conn.nextCookie = 1
|
||||||
|
conn.cookies = make(map[uint16]*Cookie)
|
||||||
|
conn.events = queue{make([][]byte, 100), 0, 0}
|
||||||
|
conn.extensions = make(map[string]byte)
|
||||||
|
|
||||||
|
conn.newReadChannels()
|
||||||
|
conn.newRequestChannels()
|
||||||
|
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the connection to the X server.
|
||||||
|
func (c *Conn) Close() {
|
||||||
|
c.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// Id is used for all X identifiers, such as windows, pixmaps, and GCs.
|
// Id is used for all X identifiers, such as windows, pixmaps, and GCs.
|
||||||
type Id uint32
|
type Id uint32
|
||||||
|
|
||||||
|
@ -111,14 +154,46 @@ type Error interface {
|
||||||
var newErrorFuncs = map[int]func(buf []byte) Error{}
|
var newErrorFuncs = map[int]func(buf []byte) Error{}
|
||||||
|
|
||||||
// NewID generates a new unused ID for use with requests like CreateWindow.
|
// NewID generates a new unused ID for use with requests like CreateWindow.
|
||||||
func (c *Conn) NewId() Id {
|
// If no new ids can be generated, the id returned is 0 and error is non-nil.
|
||||||
c.newIdLock.Lock()
|
func (c *Conn) NewId() (Id, error) {
|
||||||
defer c.newIdLock.Unlock()
|
xid := <-c.xidChan
|
||||||
|
if xid.err != nil {
|
||||||
|
return 0, xid.err
|
||||||
|
}
|
||||||
|
return xid.id, nil
|
||||||
|
}
|
||||||
|
|
||||||
id := c.nextId
|
// xid encapsulates a resource identifier being sent over the Conn.xidChan
|
||||||
// TODO: handle ID overflow
|
// channel. If no new resource id can be generated, id is set to -1 and a
|
||||||
c.nextId++
|
// non-nil error is set in xid.err.
|
||||||
return id
|
type xid struct {
|
||||||
|
id Id
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateXids sends new Ids down the channel for NewId to use.
|
||||||
|
// This needs to be updated to use the XC Misc extension once we run out of
|
||||||
|
// new ids.
|
||||||
|
func (conn *Conn) generateXids() {
|
||||||
|
inc := conn.Setup.ResourceIdMask & -conn.Setup.ResourceIdMask
|
||||||
|
max := conn.Setup.ResourceIdMask
|
||||||
|
last := uint32(0)
|
||||||
|
for {
|
||||||
|
// TODO: Use the XC Misc extension to look for released ids.
|
||||||
|
if last > 0 && last >= max - inc + 1 {
|
||||||
|
conn.xidChan <- xid{
|
||||||
|
id: Id(0),
|
||||||
|
err: errors.New("There are no more available resource" +
|
||||||
|
"identifiers."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last += inc
|
||||||
|
conn.xidChan <- xid{
|
||||||
|
id: Id(last | conn.Setup.ResourceIdBase),
|
||||||
|
err: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterExtension adds the respective extension's major op code to
|
// RegisterExtension adds the respective extension's major op code to
|
||||||
|
@ -328,165 +403,3 @@ func (c *Conn) PollForEvent() (Event, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dial connects to the X server given in the 'display' string.
|
|
||||||
// If 'display' is empty it will be taken from os.Getenv("DISPLAY").
|
|
||||||
//
|
|
||||||
// Examples:
|
|
||||||
// Dial(":1") // connect to net.Dial("unix", "", "/tmp/.X11-unix/X1")
|
|
||||||
// Dial("/tmp/launch-123/:0") // connect to net.Dial("unix", "", "/tmp/launch-123/:0")
|
|
||||||
// Dial("hostname:2.1") // connect to net.Dial("tcp", "", "hostname:6002")
|
|
||||||
// Dial("tcp/hostname:1.0") // connect to net.Dial("tcp", "", "hostname:6001")
|
|
||||||
func Dial(display string) (*Conn, error) {
|
|
||||||
c, err := connect(display)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get authentication data
|
|
||||||
authName, authData, err := readAuthority(c.host, c.display)
|
|
||||||
noauth := false
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Could not get authority info: %v\n", err)
|
|
||||||
fmt.Fprintf(os.Stderr, "Trying connection without authority info...\n")
|
|
||||||
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 nil, 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 nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
head := make([]byte, 8)
|
|
||||||
if _, err = io.ReadFull(c.conn, head[0:8]); err != nil {
|
|
||||||
return nil, 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 nil, errors.New(fmt.Sprintf("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 nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if code == 0 {
|
|
||||||
reason := buf[8 : 8+reasonLen]
|
|
||||||
return nil, errors.New(fmt.Sprintf("x protocol authentication refused: %s", string(reason)))
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadSetupInfo(buf, &c.Setup)
|
|
||||||
|
|
||||||
if c.defaultScreen >= len(c.Setup.Roots) {
|
|
||||||
c.defaultScreen = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
c.nextId = Id(c.Setup.ResourceIdBase)
|
|
||||||
c.nextCookie = 1
|
|
||||||
c.cookies = make(map[uint16]*Cookie)
|
|
||||||
c.events = queue{make([][]byte, 100), 0, 0}
|
|
||||||
c.extensions = make(map[string]byte)
|
|
||||||
|
|
||||||
c.newReadChannels()
|
|
||||||
c.newRequestChannels()
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close closes the connection to the X server.
|
|
||||||
func (c *Conn) Close() { c.conn.Close() }
|
|
||||||
|
|
||||||
func connect(display string) (*Conn, error) {
|
|
||||||
if len(display) == 0 {
|
|
||||||
display = os.Getenv("DISPLAY")
|
|
||||||
}
|
|
||||||
|
|
||||||
display0 := display
|
|
||||||
if len(display) == 0 {
|
|
||||||
return nil, errors.New("empty display string")
|
|
||||||
}
|
|
||||||
|
|
||||||
colonIdx := strings.LastIndex(display, ":")
|
|
||||||
if colonIdx < 0 {
|
|
||||||
return nil, errors.New("bad display string: " + display0)
|
|
||||||
}
|
|
||||||
|
|
||||||
var protocol, socket string
|
|
||||||
c := new(Conn)
|
|
||||||
|
|
||||||
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 nil, 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:]
|
|
||||||
}
|
|
||||||
|
|
||||||
dispnum, err := strconv.Atoi(c.display)
|
|
||||||
if err != nil || dispnum < 0 {
|
|
||||||
return nil, errors.New("bad display string: " + display0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(scr) != 0 {
|
|
||||||
c.defaultScreen, err = strconv.Atoi(scr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 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 {
|
|
||||||
if protocol == "" {
|
|
||||||
protocol = "tcp"
|
|
||||||
}
|
|
||||||
c.conn, err = net.Dial(protocol, c.host+":"+strconv.Itoa(6000+dispnum))
|
|
||||||
} else {
|
|
||||||
c.conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+c.display)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("cannot connect to " + display0 + ": " + err.Error())
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue