From 52c44d7d337ef558af92f6fd89c432a7850bf7fc Mon Sep 17 00:00:00 2001 From: Anon1234 Date: Mon, 15 Feb 2016 20:51:54 +0200 Subject: [PATCH 1/2] Update I3Node struct and set the parent for each node --- tree.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tree.go b/tree.go index f753b07..c3f2464 100644 --- a/tree.go +++ b/tree.go @@ -18,17 +18,51 @@ import ( type I3Node struct { Id int32 Name string + Type string Border string Current_Border_Width int32 Layout string + Orientation string Percent float64 Rect Rect Window_Rect Rect + Deco_Rect Rect Geometry Rect Window int32 Urgent bool Focused bool + Floating_Nodes []I3Node Nodes []I3Node + Parent *I3Node + + // Properties, not listed in docs: + Window_Properties struct { + // Transient_for ? + Title string + Instance string + Class string + } + // Swallows []I3Node ? + Sticky bool + Floating string + Last_Split_Layout string + // Focus []I3Node ? + Fullscreen_Mode int32 + Scratchpad_State string + Workspace_Layout string +} + +// Traverses the tree setting correct reference to a parent node. +func setParent(node, parent *I3Node) { + + node.Parent = parent + + for i := range node.Nodes { + setParent(&node.Nodes[i], node) + } + for i := range node.Floating_Nodes { + setParent(&node.Floating_Nodes[i], node) + } } // GetTree fetches the layout tree. @@ -38,6 +72,8 @@ func (self *IPCSocket) GetTree() (root I3Node, err error) { return } + defer setParent(&root, nil) + err = json.Unmarshal(json_reply, &root) if err == nil { return From 049c92b5617bca03b91a831810049fa4f1ce2c42 Mon Sep 17 00:00:00 2001 From: Anon1234 Date: Mon, 15 Feb 2016 21:06:38 +0200 Subject: [PATCH 2/2] Add a layout tree traversing methods --- tree_utils.go | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 tree_utils.go diff --git a/tree_utils.go b/tree_utils.go new file mode 100644 index 0000000..f58fa88 --- /dev/null +++ b/tree_utils.go @@ -0,0 +1,133 @@ +package i3ipc + +import ( + "regexp" + "strings" +) + +// Returns the root node of the tree. +func (self *I3Node) Root() *I3Node { + if self.Parent == nil { + return self + } + return self.Parent.Root() +} + +// Returns a slice of all descendent nodes. +func (self *I3Node) Descendents() []*I3Node { + + var collectDescendents func(*I3Node, []*I3Node) []*I3Node + + // Collects descendent nodes recursively + collectDescendents = func(n *I3Node, collected []*I3Node) []*I3Node { + for i := range n.Nodes { + collected = append(collected, &n.Nodes[i]) + collected = collectDescendents(&n.Nodes[i], collected) + } + for i := range n.Floating_Nodes { + collected = append(collected, &n.Floating_Nodes[i]) + collected = collectDescendents(&n.Floating_Nodes[i], collected) + } + return collected + } + + return collectDescendents(self, nil) +} + +// Returns nodes that has no children nodes (leaves). +func (self *I3Node) Leaves() (leaves []*I3Node) { + + nodes := self.Descendents() + + for i := range nodes { + node := nodes[i] + + is_dockarea := node.Parent != nil && node.Parent.Type == "dockarea" + + if len(node.Nodes) == 0 && node.Type == "con" && !is_dockarea { + leaves = append(leaves, node) + } + } + return +} + +// Returns all nodes of workspace type. +func (self *I3Node) Workspaces() (workspaces []*I3Node) { + + nodes := self.Descendents() + + for i := range nodes { + i3_special := strings.HasPrefix(nodes[i].Name, "__") + if nodes[i].Type == "workspace" && !i3_special { + workspaces = append(workspaces, nodes[i]) + } + } + return +} + +// Returns a node that is being focused now. +func (self *I3Node) FindFocused() *I3Node { + + nodes := self.Descendents() + + for i := range nodes { + if nodes[i].Focused { + return nodes[i] + } + } + return nil +} + +// Returns a node that has given id. +func (self *I3Node) FindByID(id int32) *I3Node { + + nodes := self.Descendents() + + for i := range nodes { + if nodes[i].Id == id { + return nodes[i] + } + } + return nil +} + +// Returns a node that has given window id. +func (self *I3Node) FindByWindow(window int32) *I3Node { + + nodes := self.Descendents() + + for i := range nodes { + if nodes[i].Window == window { + return nodes[i] + } + } + return nil +} + +// Returns nodes which name matches the regexp. +func (self *I3Node) FindNamed(name string) []*I3Node { + + nodes := self.Descendents() + reName := regexp.MustCompile(name) + var found []*I3Node + + for _, node := range nodes { + if reName.MatchString(node.Name) { + found = append(found, node) + } + } + return found +} + +// Looks for a workspace up the tree. +func (self *I3Node) Workspace() *I3Node { + + if self.Parent == nil { // the root node + return nil + } + if self.Parent.Type == "workspace" { + return self.Parent + } + + return self.Parent.Workspace() +}