Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
133 changes: 133 additions & 0 deletions tree_utils.go
Original file line number Diff line number Diff line change
@@ -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()
}