Index: src/pkg/xgb/xgb.go |
=================================================================== |
deleted file mode 100644 |
--- a/src/pkg/xgb/xgb.go |
+++ /dev/null |
@@ -1,464 +0,0 @@ |
-// Copyright 2009 The Go Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-// The XGB package implements the X11 core protocol. |
-// It is based on XCB: http://xcb.freedesktop.org/ |
-package xgb |
- |
-import ( |
- "fmt" |
- "io" |
- "net" |
- "os" |
- "strconv" |
- "strings" |
-) |
- |
-// A Conn represents a connection to an X server. |
-// Only one goroutine should use a Conn's methods at a time. |
-type Conn struct { |
- host string |
- conn net.Conn |
- nextId Id |
- nextCookie Cookie |
- replies map[Cookie][]byte |
- events queue |
- err os.Error |
- display string |
- defaultScreen int |
- scratch [32]byte |
- Setup SetupInfo |
-} |
- |
-// Id is used for all X identifiers, such as windows, pixmaps, and GCs. |
-type Id uint32 |
- |
-// Cookies are the sequence numbers used to pair replies up with their requests |
-type Cookie uint16 |
- |
-type Keysym uint32 |
-type Timestamp uint32 |
- |
-// 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{} |
- |
-// Error contains protocol errors returned to us by the X server. |
-type Error struct { |
- Detail uint8 |
- Major uint8 |
- Minor uint16 |
- Cookie Cookie |
- Id Id |
-} |
- |
-func (e *Error) String() string { |
- return fmt.Sprintf("Bad%s (major=%d minor=%d cookie=%d id=0x%x)", |
- errorNames[e.Detail], e.Major, e.Minor, e.Cookie, e.Id) |
-} |
- |
-// NewID generates a new unused ID for use with requests like CreateWindow. |
-func (c *Conn) NewId() Id { |
- id := c.nextId |
- // TODO: handle ID overflow |
- c.nextId++ |
- return id |
-} |
- |
-// Pad a length to align on 4 bytes. |
-func pad(n int) int { return (n + 3) & ^3 } |
- |
-func put16(buf []byte, v uint16) { |
- buf[0] = byte(v) |
- buf[1] = byte(v >> 8) |
-} |
- |
-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) |
-} |
- |
-func get16(buf []byte) uint16 { |
- v := uint16(buf[0]) |
- v |= uint16(buf[1]) << 8 |
- return v |
-} |
- |
-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 |
-} |
- |
-// Voodoo to count 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 |
-} |
- |
-// A simple queue used to stow away events. |
-type queue struct { |
- data [][]byte |
- a, b int |
-} |
- |
-func (q *queue) queue(item []byte) { |
- if q.b == len(q.data) { |
- if q.a > 0 { |
- copy(q.data, q.data[q.a:q.b]) |
- q.a, q.b = 0, q.b-q.a |
- } else { |
- newData := make([][]byte, (len(q.data)*3)/2) |
- copy(newData, q.data) |
- q.data = newData |
- } |
- } |
- q.data[q.b] = item |
- q.b++ |
-} |
- |
-func (q *queue) dequeue() []byte { |
- if q.a < q.b { |
- item := q.data[q.a] |
- q.a++ |
- return item |
- } |
- return nil |
-} |
- |
-// sendRequest sends a request to the server and return its associated sequence number, or cookie. |
-// It is only used to send the fixed length portion of the request, sendBytes and friends are used |
-// to send any additional variable length data. |
-func (c *Conn) sendRequest(buf []byte) Cookie { |
- if _, err := c.conn.Write(buf); err != nil { |
- fmt.Fprintf(os.Stderr, "x protocol write error: %s\n", err) |
- c.err = err |
- } |
- cookie := c.nextCookie |
- c.nextCookie++ |
- return cookie |
-} |
- |
-// sendPadding sends enough bytes to align to a 4-byte border. |
-// It is used to pad the variable length data that is used with some requests. |
-func (c *Conn) sendPadding(n int) { |
- x := pad(n) - n |
- if x > 0 { |
- _, err := c.conn.Write(c.scratch[0:x]) |
- if err != nil { |
- fmt.Fprintf(os.Stderr, "x protocol write error: %s\n", err) |
- c.err = err |
- } |
- } |
-} |
- |
-// sendBytes sends a byte slice as variable length data after the fixed portion of a request, |
-// along with any necessary padding. |
-func (c *Conn) sendBytes(buf []byte) { |
- if _, err := c.conn.Write(buf); err != nil { |
- fmt.Fprintf(os.Stderr, "x protocol write error: %s\n", err) |
- c.err = err |
- } |
- c.sendPadding(len(buf)) |
-} |
- |
-func (c *Conn) sendString(str string) { c.sendBytes([]byte(str)) } |
- |
-// sendUInt32s sends a list of 32-bit integers as variable length data. |
-func (c *Conn) sendUInt32List(list []uint32) { |
- buf := make([]byte, len(list)*4) |
- for i := 0; i < len(list); i++ { |
- put32(buf[i*4:], list[i]) |
- } |
- c.sendBytes(buf) |
-} |
- |
-func (c *Conn) sendIdList(list []Id, length int) { |
- buf := make([]byte, length*4) |
- for i := 0; i < length; i++ { |
- put32(buf[i*4:], uint32(list[i])) |
- } |
- c.sendBytes(buf) |
-} |
- |
-func (c *Conn) sendKeysymList(list []Keysym, length int) { |
- buf := make([]byte, length*4) |
- for i := 0; i < length; i++ { |
- put32(buf[i*4:], uint32(list[i])) |
- } |
- c.sendBytes(buf) |
-} |
- |
-// readNextReply reads and processes the next server reply. |
-// If it is a protocol error then it is returned as an Error. |
-// Events are pushed onto the event queue and replies to requests |
-// are stashed away in a map indexed by the sequence number. |
-func (c *Conn) readNextReply() os.Error { |
- buf := make([]byte, 32) |
- if _, err := io.ReadFull(c.conn, buf); err != nil { |
- fmt.Fprintf(os.Stderr, "x protocol read error: %s\n", err) |
- return err |
- } |
- |
- switch buf[0] { |
- case 0: |
- err := &Error{ |
- Detail: buf[1], |
- Cookie: Cookie(get16(buf[2:])), |
- Id: Id(get32(buf[4:])), |
- Minor: get16(buf[8:]), |
- Major: buf[10], |
- } |
- fmt.Fprintf(os.Stderr, "x protocol error: %s\n", err) |
- return err |
- |
- case 1: |
- seq := Cookie(get16(buf[2:])) |
- size := get32(buf[4:]) |
- if size > 0 { |
- bigbuf := make([]byte, 32+size*4, 32+size*4) |
- copy(bigbuf[0:32], buf) |
- if _, err := io.ReadFull(c.conn, bigbuf[32:]); err != nil { |
- fmt.Fprintf(os.Stderr, "x protocol read error: %s\n", err) |
- return err |
- } |
- c.replies[seq] = bigbuf |
- } else { |
- c.replies[seq] = buf |
- } |
- |
- default: |
- c.events.queue(buf) |
- } |
- |
- return nil |
-} |
- |
-// waitForReply looks for a reply in the map indexed by sequence number. |
-// If the reply is not in the map it will block while reading replies from the server |
-// until the reply is found or an error occurs. |
-func (c *Conn) waitForReply(cookie Cookie) ([]byte, os.Error) { |
- for { |
- if reply, ok := c.replies[cookie]; ok { |
- c.replies[cookie] = reply, false |
- return reply, nil |
- } |
- if err := c.readNextReply(); err != nil { |
- return nil, err |
- } |
- } |
- panic("unreachable") |
-} |
- |
-// WaitForEvent returns the next event from the server. |
-// It will block until an event is available. |
-func (c *Conn) WaitForEvent() (Event, os.Error) { |
- for { |
- if reply := c.events.dequeue(); reply != nil { |
- return parseEvent(reply) |
- } |
- if err := c.readNextReply(); err != nil { |
- return nil, err |
- } |
- } |
- panic("unreachable") |
-} |
- |
-// PollForEvent returns the next event from the server if one is available in the internal queue. |
-// It will not read from the connection, so you must call WaitForEvent to receive new events. |
-// Only use this function to empty the queue without blocking. |
-func (c *Conn) PollForEvent() (Event, os.Error) { |
- if reply := c.events.dequeue(); reply != nil { |
- return parseEvent(reply) |
- } |
- 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, os.Error) { |
- c, err := connect(display) |
- if err != nil { |
- return nil, err |
- } |
- |
- // Get authentication data |
- authName, authData, err := readAuthority(c.host, c.display) |
- if err != nil { |
- return nil, err |
- } |
- |
- // Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1". |
- if authName != "MIT-MAGIC-COOKIE-1" || len(authData) != 16 { |
- return nil, os.NewError("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, os.NewError(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, os.NewError(fmt.Sprintf("x protocol authentication refused: %s", string(reason))) |
- } |
- |
- getSetupInfo(buf, &c.Setup) |
- |
- if c.defaultScreen >= len(c.Setup.Roots) { |
- c.defaultScreen = 0 |
- } |
- |
- c.nextId = Id(c.Setup.ResourceIdBase) |
- c.nextCookie = 1 |
- c.replies = make(map[Cookie][]byte) |
- c.events = queue{make([][]byte, 100), 0, 0} |
- return c, nil |
-} |
- |
-// Close closes the connection to the X server. |
-func (c *Conn) Close() { c.conn.Close() } |
- |
-// DefaultScreen returns the Screen info for the default screen, which is |
-// 0 or the one given in the display argument to Dial. |
-func (c *Conn) DefaultScreen() *ScreenInfo { return &c.Setup.Roots[c.defaultScreen] } |
- |
- |
-// ClientMessageData holds the data from a client message, |
-// duplicated in three forms because Go doesn't have unions. |
-type ClientMessageData struct { |
- Data8 [20]byte |
- Data16 [10]uint16 |
- Data32 [5]uint32 |
-} |
- |
-func getClientMessageData(b []byte, v *ClientMessageData) int { |
- copy(&v.Data8, b) |
- for i := 0; i < 10; i++ { |
- v.Data16[i] = get16(b[i*2:]) |
- } |
- for i := 0; i < 5; i++ { |
- v.Data32[i] = get32(b[i*4:]) |
- } |
- return 20 |
-} |
- |
-func connect(display string) (*Conn, os.Error) { |
- if len(display) == 0 { |
- display = os.Getenv("DISPLAY") |
- } |
- |
- display0 := display |
- if len(display) == 0 { |
- return nil, os.NewError("empty display string") |
- } |
- |
- colonIdx := strings.LastIndex(display, ":") |
- if colonIdx < 0 { |
- return nil, os.NewError("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, os.NewError("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.Atoui(c.display) |
- if err != nil { |
- return nil, os.NewError("bad display string: " + display0) |
- } |
- |
- if len(scr) != 0 { |
- c.defaultScreen, err = strconv.Atoi(scr) |
- if err != nil { |
- return nil, os.NewError("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.Uitoa(6000+dispnum)) |
- } else { |
- c.conn, err = net.Dial("unix", "", "/tmp/.X11-unix/X"+c.display) |
- } |
- |
- if err != nil { |
- return nil, os.NewError("cannot connect to " + display0 + ": " + err.String()) |
- } |
- return c, nil |
-} |