summaryrefslogtreecommitdiff
path: root/xmu/xmu.go
diff options
context:
space:
mode:
Diffstat (limited to 'xmu/xmu.go')
-rw-r--r--xmu/xmu.go66
1 files changed, 66 insertions, 0 deletions
diff --git a/xmu/xmu.go b/xmu/xmu.go
new file mode 100644
index 0000000..449eea6
--- /dev/null
+++ b/xmu/xmu.go
@@ -0,0 +1,66 @@
+package xmu
+
+import (
+ "xgob"
+ "xgob/util"
+ "xgob/xproto"
+)
+
+/* The main difference between this and C/libXmu is that this version
+ searches for the client window in the shallowest windows first, and
+ C/libXmu searches the topmost windows first.
+
+ This change allows us to avoid as many round-trips as possible.
+*/
+
+func tryChildren(c *xgob.Connection, children []xproto.Window) xproto.Window {
+ queryCookies := make([]chan xproto.QueryTreeReply, 0)
+ propCookies := make([]chan xproto.GetPropertyReply, 0)
+
+ state := util.Atom(c, "WM_STATE")
+
+ for {
+ if len(children) == 0 {
+ break
+ }
+
+ // Reset cookie jars
+ queryCookies = queryCookies[:0]
+ propCookies = propCookies[:0]
+
+ for _, child := range children {
+ propCookies = append(propCookies, xproto.GetProperty(c, false, child, state, xproto.Atom(0), 0, 0))
+ queryCookies = append(queryCookies, xproto.QueryTree(c, child))
+ }
+ c.Flush()
+ for i, cookie := range propCookies {
+ s := <-cookie
+ if s.Error == nil && s.Type != xproto.Atom(0) {
+ return children[i]
+ }
+ }
+
+ children = children[:0]
+ for _, cookie := range queryCookies {
+ children = append(children, (<-cookie).Children...)
+ }
+
+ }
+ return 0
+}
+
+func ClientWindow(c *xgob.Connection, win xproto.Window) xproto.Window {
+ stateCookie := xproto.GetProperty(c, false, win, util.Atom(c, "WM_STATE"), xproto.Atom(0), 0, 0)
+ treeCookie := xproto.QueryTree(c, win)
+ c.Flush()
+ state := <-stateCookie
+ if state.Error != nil && state.Type != xproto.Atom(0) {
+ return win
+ }
+
+ tree := <-treeCookie
+ if rv := tryChildren(c, tree.Children); rv != 0 {
+ win = rv
+ }
+ return win
+}