195 lines
5.7 KiB
Go
195 lines
5.7 KiB
Go
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 i3’s 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
|
||
}
|