diff options
Diffstat (limited to 'xmu/xmu.go')
-rw-r--r-- | xmu/xmu.go | 66 |
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 +} |