diff options
author | Peter Harris <git@peter.is-a-geek.org> | 2011-01-02 15:12:04 -0500 |
---|---|---|
committer | Peter Harris <git@peter.is-a-geek.org> | 2011-01-02 15:12:04 -0500 |
commit | 7144e5d343e4d0756aff4d6b03709bef0dfc7614 (patch) | |
tree | 1475ecc44c816c6581c82f904f54e2e193605eb6 | |
parent | 60c503d7058fcc644db838ae0ffbefcf87409ed3 (diff) |
Thinking out-loud about what xproto might look like
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | xgob/util/atom.go | 105 | ||||
-rw-r--r-- | xgob/xproto.go | 181 | ||||
-rw-r--r-- | xlsclients.go | 9 |
5 files changed, 299 insertions, 1 deletions
@@ -1,5 +1,6 @@ test noop +xlsclients build *.6 *.xcodeproj @@ -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() +} |