go-i3/tree.go
2023-10-22 16:19:10 +02:00

195 lines
5.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package i3
import (
"encoding/json"
)
// NodeType indicates the specific kind of Node.
type NodeType string
// i3 currently implements the following node types:
const (
Root NodeType = "root"
OutputNode NodeType = "output"
Con NodeType = "con"
FloatingCon NodeType = "floating_con"
WorkspaceNode NodeType = "workspace"
DockareaNode NodeType = "dockarea"
)
// Layout indicates the layout of a Node.
type Layout string
// i3 currently implements the following layouts:
const (
SplitH Layout = "splith"
SplitV Layout = "splitv"
Stacked Layout = "stacked"
Tabbed Layout = "tabbed"
DockareaLayout Layout = "dockarea"
OutputLayout Layout = "output"
)
// BorderStyle indicates the border style of a node.
type BorderStyle string
// i3 currently implements the following border styles:
const (
NormalBorder BorderStyle = "normal"
NoBorder BorderStyle = "none"
PixelBorder BorderStyle = "pixel"
)
// Rect is a rectangle, used for various dimensions in Node, for example.
type Rect struct {
X int64 `json:"x"`
Y int64 `json:"y"`
Width int64 `json:"width"`
Height int64 `json:"height"`
}
// WindowProperties correspond to X11 window properties
//
// See https://build.i3wm.org/docs/ipc.html#_tree_reply
type WindowProperties struct {
Title string `json:"title"`
Instance string `json:"instance"`
Class string `json:"class"`
Role string `json:"window_role"`
Transient NodeID `json:"transient_for"`
}
// NodeID is an i3-internal ID for the node, which can be used to identify
// containers within the IPC interface.
type NodeID int64
// FullscreenMode indicates whether the container is fullscreened, and relative
// to where (its output, or globally). Note that all workspaces are considered
// fullscreened on their respective output.
type FullscreenMode int64
const (
FullscreenNone FullscreenMode = 0
FullscreenOutput FullscreenMode = 1
FullscreenGlobal FullscreenMode = 2
)
// FloatingType indicates the floating type of Node.
type FloatingType string
// i3 currently implements the following node types:
const (
AutoOff FloatingType = "auto_off"
AutoOn FloatingType = "auto_on"
UserOn FloatingType = "user_on"
UserOff FloatingType = "user_off"
)
// Node is a node in a Tree.
//
// See https://i3wm.org/docs/ipc.html#_tree_reply for more details.
type Node struct {
ID NodeID `json:"id"`
Name string `json:"name"` // window: title, container: internal name
Type NodeType `json:"type"`
Border BorderStyle `json:"border"`
CurrentBorderWidth int64 `json:"current_border_width"`
Layout Layout `json:"layout"`
Percent float64 `json:"percent"`
Rect Rect `json:"rect"` // absolute (= relative to X11 display)
WindowRect Rect `json:"window_rect"` // window, relative to Rect
DecoRect Rect `json:"deco_rect"` // decoration, relative to Rect
Geometry Rect `json:"geometry"` // original window geometry, absolute
Window int64 `json:"window"` // X11 window ID of the client window
WindowProperties WindowProperties `json:"window_properties"`
Urgent bool `json:"urgent"` // urgency hint set
Marks []string `json:"marks"`
Focused bool `json:"focused"`
WindowType string `json:"window_type"`
FullscreenMode FullscreenMode `json:"fullscreen_mode"`
Focus []NodeID `json:"focus"`
Nodes []*Node `json:"nodes"`
FloatingNodes []*Node `json:"floating_nodes"`
Floating FloatingType `json:"floating"`
ScratchpadState string `json:"scratchpad_state"`
AppID string `json:"app_id"` // if talking to Sway: Wayland App ID
Sticky bool `json:"sticky"`
Output string `json:"output"`
}
// FindChild returns the first Node matching predicate, using pre-order
// depth-first search.
func (n *Node) FindChild(predicate func(*Node) bool) *Node {
if predicate(n) {
return n
}
for _, c := range n.Nodes {
if con := c.FindChild(predicate); con != nil {
return con
}
}
for _, c := range n.FloatingNodes {
if con := c.FindChild(predicate); con != nil {
return con
}
}
return nil
}
// FindFocused returns the first Node matching predicate from the sub-tree of
// directly and indirectly focused containers.
//
// As an example, consider this layout tree (simplified):
//
// root
// │
// HDMI2
//
// … workspace 1
//
// XTerm Firefox
//
// In this example, if Firefox is focused, FindFocused will return the first
// container matching predicate of root, HDMI2, workspace 1, Firefox (in this
// order).
func (n *Node) FindFocused(predicate func(*Node) bool) *Node {
if predicate(n) {
return n
}
if len(n.Focus) == 0 {
return nil
}
first := n.Focus[0]
for _, c := range n.Nodes {
if c.ID == first {
return c.FindFocused(predicate)
}
}
for _, c := range n.FloatingNodes {
if c.ID == first {
return c.FindFocused(predicate)
}
}
return nil
}
// Tree is an i3 layout tree, starting with Root.
type Tree struct {
// Root is the root node of the layout tree.
Root *Node
}
// GetTree returns i3s layout tree.
//
// GetTree is supported in i3 ≥ v4.0 (2011-07-31).
func GetTree() (Tree, error) {
reply, err := roundTrip(messageTypeGetTree, nil)
if err != nil {
return Tree{}, err
}
var root Node
err = json.Unmarshal(reply.Payload, &root)
return Tree{Root: &root}, err
}