summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Harris <git@peter.is-a-geek.org>2011-01-02 15:12:04 -0500
committerPeter Harris <git@peter.is-a-geek.org>2011-01-02 15:12:04 -0500
commit7144e5d343e4d0756aff4d6b03709bef0dfc7614 (patch)
tree1475ecc44c816c6581c82f904f54e2e193605eb6
parent60c503d7058fcc644db838ae0ffbefcf87409ed3 (diff)
Thinking out-loud about what xproto might look like
-rw-r--r--.gitignore1
-rw-r--r--Makefile4
-rw-r--r--xgob/util/atom.go105
-rw-r--r--xgob/xproto.go181
-rw-r--r--xlsclients.go9
5 files changed, 299 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index ab0e108..5da7293 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
test
noop
+xlsclients
build
*.6
*.xcodeproj
diff --git a/Makefile b/Makefile
index d730151..f84e177 100644
--- a/Makefile
+++ b/Makefile
@@ -10,8 +10,10 @@
6l -L. -o $@ $<
# Compile our simple test apps
-all: test noop
+all: test noop xlsclients
# Dependencies
+xgob/util/atom.6: xgob/xproto.6
test.6: xgob.6
+xlsclients.6: xgob.6 xgob/xproto.6 xgob/util/atom.6
noop.6: xgob.6
diff --git a/xgob/util/atom.go b/xgob/util/atom.go
new file mode 100644
index 0000000..f79e20a
--- /dev/null
+++ b/xgob/util/atom.go
@@ -0,0 +1,105 @@
+package atom
+
+import (
+ "sync"
+ "xgob"
+ "xproto"
+)
+
+type state struct {
+ c *xgob.Connection
+
+ name map[xproto.Atom]string
+ atom map[string]xproto.Atom
+
+ pendingAtom map[string]chan xproto.InternAtomReply
+}
+
+var lock sync.RWMutex
+var db = make(map[*xgob.Connection]state)
+
+func newState (c *xgob.Connection) state {
+ var rv state
+ rv.c = c
+ rv.name = make(map[xproto.Atom]string)
+ rv.atom = make(map[string]xproto.Atom)
+
+ rv.pendingAtom = make(map[string]chan xproto.InternAtomReply)
+ return rv
+}
+
+/* internAtom must be called under a write lock */
+func (s *state) internAtom (name string) xproto.Atom {
+ c, ok := s.pendingAtom[name]
+ if ok {
+ s.pendingAtom[name] = nil, false
+ } else {
+ c = xproto.InternAtom(s.c, false, name)
+ }
+ reply := <- c
+ if reply.Error == nil {
+ s.name[reply.Atom] = name
+ s.atom[name] = reply.Atom
+ }
+ return reply.Atom
+}
+
+func getState(c *xgob.Connection, writelocked bool) *state {
+ s, ok := db[c]
+ if !ok {
+ // Grab write lock, recheck, create state, downgrade to read lock
+ if !writelocked {
+ lock.RUnlock()
+ lock.Lock()
+ s, ok = db[c]
+ }
+ if !ok {
+ db[c] = newState(c)
+ s, ok = db[c]
+ }
+ if !writelocked {
+ lock.Unlock()
+ lock.RLock()
+ }
+ }
+ return &s
+}
+
+func PreloadAtom(c *xgob.Connection, name string) {
+ lock.Lock()
+
+ s := getState(c, true)
+ _, ok := s.atom[name]
+
+ if !ok {
+ _, ok := s.pendingAtom[name]
+ if !ok {
+ s.pendingAtom[name] = xproto.InternAtom(c, false, name)
+ }
+ }
+ lock.Unlock()
+}
+
+func Atom (c *xgob.Connection, name string) xproto.Atom {
+ lock.RLock()
+
+ s := getState(c, false)
+ atom, ok := s.atom[name]
+
+ lock.RUnlock()
+
+ if !ok {
+ // Grab write lock, recheck, InternAtom
+ lock.Lock()
+ atom, ok = s.atom[name]
+ if !ok {
+ atom = s.internAtom(name)
+ }
+ lock.Unlock()
+ }
+ return atom
+}
+
+func AtomName (c *xgob.Connection, atom uint32) string {
+ return ""
+}
diff --git a/xgob/xproto.go b/xgob/xproto.go
new file mode 100644
index 0000000..31fa0aa
--- /dev/null
+++ b/xgob/xproto.go
@@ -0,0 +1,181 @@
+package xproto
+
+import (
+ "xgob"
+)
+
+type Atom uint32
+type Window uint32
+
+type QueryTreeReply struct {
+ Error *xgob.Error
+ Root, Parent Window
+ Children []Window
+}
+
+type InternAtomReply struct {
+ Error *xgob.Error
+ Atom Atom
+}
+
+type GetPropertyReply struct {
+ Error *xgob.Error
+ Format uint8
+ Type Atom
+ BytesAfter uint32
+ Value []byte
+}
+
+func appendUint16(buf []byte, val uint16) []byte {
+ buf = append(buf, uint8(val >> 8))
+ buf = append(buf, uint8(val & 0xFF))
+ return buf
+}
+
+func appendUint32(buf []byte, val uint32) []byte {
+ buf = append(buf, uint8(val >> 24))
+ buf = append(buf, uint8(val >> 16))
+ buf = append(buf, uint8(val >> 8))
+ buf = append(buf, uint8(val & 0xFF))
+ return buf
+}
+
+func getUint16(buf []byte) uint16 {
+ var rv uint16
+ rv = uint16(buf[2]) << 8
+ rv |= uint16(buf[3])
+ return rv
+}
+
+func getUint32(buf []byte) uint32 {
+ var rv uint32
+ rv = uint32(buf[0]) << 24
+ rv |= uint32(buf[1]) << 16
+ rv |= uint32(buf[2]) << 8
+ rv |= uint32(buf[3])
+ return rv
+}
+
+func queryTreeReply(in chan interface{}, out chan QueryTreeReply) {
+ var rv QueryTreeReply
+ data := <-in
+
+ switch d := data.(type) {
+ case xgob.Error:
+ rv.Error = &d
+ case xgob.Reply:
+ rep := d.Remainder
+ rv.Root = Window(getUint32(rep))
+ rep = rep[4:]
+ rv.Parent = Window(getUint32(rep))
+ rep = rep[4:]
+ children_len := getUint16(rep)
+ rep = rep[2:]
+ rv.Children = make([]Window, 0, children_len)
+ rep = rep[14:] // Pad
+
+ for i := uint16(0); i < children_len; i++ {
+ rv.Children = append(rv.Children, Window(getUint32(rep)))
+ rep = rep[4:]
+ }
+ }
+ out <- rv
+}
+
+func QueryTree(c *xgob.Connection, window Window) chan QueryTreeReply {
+ req := make([]byte, 0, 8)
+
+ req = append(req, 15) // Opcode
+ req = append(req, 0) // Pad
+ req = appendUint16(req, 2) // Length
+ req = appendUint32(req, uint32(window))
+
+ rv := make(chan QueryTreeReply, 1)
+ reply := c.WriteReplyRequest(req)
+
+ go queryTreeReply(reply, rv)
+ return rv
+}
+
+func internAtomReply(in chan interface{}, out chan InternAtomReply) {
+ var rv InternAtomReply
+ data := <-in
+
+ switch d := data.(type) {
+ case xgob.Error:
+ rv.Error = &d
+ case xgob.Reply:
+ rv.Atom = Atom(getUint32(d.Remainder))
+ }
+ out <- rv
+}
+
+func InternAtom(c *xgob.Connection, only_if_exists bool, name string) chan InternAtomReply {
+ length := len(name) + 8
+ length += -length & 3
+
+ req := make([]byte, 0, length)
+
+ req = append(req, 16) // Opcode
+ if only_if_exists {
+ req = append(req, 1)
+ } else {
+ req = append(req, 0)
+ }
+ req = appendUint16(req, uint16(length/4))
+ req = appendUint16(req, uint16(len(name)))
+ req = appendUint16(req, 0) // Pad
+ copy(req[8:], name)
+
+ rv := make(chan InternAtomReply, 1)
+ reply := c.WriteReplyRequest(req)
+
+ go internAtomReply(reply, rv)
+ return rv
+}
+
+func getPropertyReply(in chan interface{}, out chan GetPropertyReply) {
+ var rv GetPropertyReply
+ data := <-in
+
+ switch d := data.(type) {
+ case xgob.Error:
+ rv.Error = &d
+ case xgob.Reply:
+ rv.Format = d.Aux
+ rep := d.Remainder
+ rv.Type = Atom(getUint32(rep))
+ rep = rep[4:]
+ rv.BytesAfter = getUint32(rep)
+ rep = rep[4:]
+ value_len := getUint32(rep)
+ rep = rep[4:]
+ rep = rep[12:] // Pad
+ rv.Value = rep[:value_len]
+ rep = rep[value_len:]
+ }
+ out <- rv
+}
+
+func GetProperty(c *xgob.Connection, delete bool, window Window, property Atom, _type Atom, long_offset uint32, long_length uint32) chan GetPropertyReply {
+ req := make([]byte, 0, 6 * 4)
+
+ req = append(req, 20) // Opcode
+ if delete {
+ req = append(req, 1)
+ } else {
+ req = append(req, 0)
+ }
+ req = appendUint16(req, 6)
+ req = appendUint32(req, uint32(window))
+ req = appendUint32(req, uint32(property))
+ req = appendUint32(req, uint32(_type))
+ req = appendUint32(req, long_offset)
+ req = appendUint32(req, long_length)
+
+ rv := make(chan GetPropertyReply, 1)
+ reply := c.WriteReplyRequest(req)
+
+ go getPropertyReply(reply, rv)
+ return rv
+}
diff --git a/xlsclients.go b/xlsclients.go
new file mode 100644
index 0000000..a0dec36
--- /dev/null
+++ b/xlsclients.go
@@ -0,0 +1,9 @@
+package main
+
+import (
+ "flag"
+)
+
+func main () {
+ flag.Parse()
+}