summaryrefslogtreecommitdiff
path: root/xmu.go
blob: d7a6a13fbde4ddfb51d53ff9ecc24afac0ee8f2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package xmu

import (
	"xgob"
	"xgob/util/atom"
	"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 := atom.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, atom.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
	rv := tryChildren(c, tree.Children)
	if rv == 0 {
		return win
	}
	return rv
}