From f5b0ee026fdafb6ac2aa16b6a4196f1dab571c2b Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Thu, 14 Aug 2025 22:59:38 +0200 Subject: [PATCH] implemented more stuff along with samples --- TODO.md | 8 + .../main.go | 0 .../tree.json | 0 _examples/get_bars/main.go | 40 ++ _examples/{tree => get_bars}/tree.json | 0 _examples/get_config/main.go | 28 ++ _examples/get_config/tree.json | 346 ++++++++++++++++++ _examples/get_marks/main.go | 28 ++ _examples/get_marks/tree.json | 346 ++++++++++++++++++ _examples/get_outputs/log | 124 +++++++ _examples/get_outputs/main.go | 28 ++ _examples/get_outputs/tree.json | 346 ++++++++++++++++++ _examples/{tree => get_tree}/main.go | 0 _examples/get_tree/tree.json | 346 ++++++++++++++++++ _examples/get_version/main.go | 28 ++ _examples/get_version/tree.json | 346 ++++++++++++++++++ _examples/get_workspaces/main.go | 28 ++ _examples/get_workspaces/tree.json | 346 ++++++++++++++++++ _examples/run_command/main.go | 44 +++ _examples/run_global_command/main.go | 28 ++ bar.go | 93 +++++ i3ipc.go | 130 ++++++- net.go | 2 - node.go | 24 ++ output.go | 44 +++ version.go | 27 ++ 26 files changed, 2768 insertions(+), 12 deletions(-) create mode 100644 TODO.md rename _examples/{focusedwindow => find_focused_window}/main.go (100%) rename _examples/{focusedwindow => find_focused_window}/tree.json (100%) create mode 100644 _examples/get_bars/main.go rename _examples/{tree => get_bars}/tree.json (100%) create mode 100644 _examples/get_config/main.go create mode 100644 _examples/get_config/tree.json create mode 100644 _examples/get_marks/main.go create mode 100644 _examples/get_marks/tree.json create mode 100644 _examples/get_outputs/log create mode 100644 _examples/get_outputs/main.go create mode 100644 _examples/get_outputs/tree.json rename _examples/{tree => get_tree}/main.go (100%) create mode 100644 _examples/get_tree/tree.json create mode 100644 _examples/get_version/main.go create mode 100644 _examples/get_version/tree.json create mode 100644 _examples/get_workspaces/main.go create mode 100644 _examples/get_workspaces/tree.json create mode 100644 _examples/run_command/main.go create mode 100644 _examples/run_global_command/main.go create mode 100644 bar.go create mode 100644 output.go create mode 100644 version.go diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..c0fef1c --- /dev/null +++ b/TODO.md @@ -0,0 +1,8 @@ +# to be implemented + +- subscribe +- events +- send_tick +- `get_binding_state` +- get_inputs +- get_seats diff --git a/_examples/focusedwindow/main.go b/_examples/find_focused_window/main.go similarity index 100% rename from _examples/focusedwindow/main.go rename to _examples/find_focused_window/main.go diff --git a/_examples/focusedwindow/tree.json b/_examples/find_focused_window/tree.json similarity index 100% rename from _examples/focusedwindow/tree.json rename to _examples/find_focused_window/tree.json diff --git a/_examples/get_bars/main.go b/_examples/get_bars/main.go new file mode 100644 index 0000000..eaefd73 --- /dev/null +++ b/_examples/get_bars/main.go @@ -0,0 +1,40 @@ +package main + +/* + Retrieve a list of running bars +*/ + +import ( + "fmt" + "log" + + "github.com/alecthomas/repr" + "github.com/tlinden/i3ipc" +) + +func main() { + ipc := i3ipc.NewI3ipc() + + err := ipc.Connect() + if err != nil { + log.Fatal(err) + } + + bars, err := ipc.GetBars() + if err != nil { + log.Fatal(err) + } + + fmt.Println("Current bars:") + repr.Println(bars) + + if len(bars) > 0 { + fmt.Println("First bar:") + bar, err := ipc.GetBar(bars[0]) + if err != nil { + log.Fatal(err) + } + + repr.Println(bar) + } +} diff --git a/_examples/tree/tree.json b/_examples/get_bars/tree.json similarity index 100% rename from _examples/tree/tree.json rename to _examples/get_bars/tree.json diff --git a/_examples/get_config/main.go b/_examples/get_config/main.go new file mode 100644 index 0000000..ee5272a --- /dev/null +++ b/_examples/get_config/main.go @@ -0,0 +1,28 @@ +package main + +/* + Retrieve the user config +*/ + +import ( + "fmt" + "log" + + "github.com/tlinden/i3ipc" +) + +func main() { + ipc := i3ipc.NewI3ipc() + + err := ipc.Connect() + if err != nil { + log.Fatal(err) + } + + config, err := ipc.GetConfig() + if err != nil { + log.Fatal(err) + } + + fmt.Println(config) +} diff --git a/_examples/get_config/tree.json b/_examples/get_config/tree.json new file mode 100644 index 0000000..24eaa5a --- /dev/null +++ b/_examples/get_config/tree.json @@ -0,0 +1,346 @@ +&i3ipc.Node{ + Id: 1, + Type: "root", + Name: "root", + Nodes: []*i3ipc.Node{ + { + Id: 2147483647, + Type: "output", + Name: "__i3", + Nodes: []*i3ipc.Node{ + { + Id: 2147483646, + Type: "workspace", + Name: "__i3_scratch", + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "output", + Orientation: "horizontal", + Focus: []int{ + 2147483646, + }, + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + { + Id: 4, + Type: "output", + Name: "HDMI-A-1", + Nodes: []*i3ipc.Node{ + { + Id: 7, + Type: "workspace", + Name: "2", + Nodes: []*i3ipc.Node{ + { + Id: 8, + Type: "con", + Name: "Terminal - 1:2:sh - \"tripod\" ", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.21511628, + X11Window: "xfce4-terminal", + Rect: i3ipc.Rect{ + Y: 26, + Width: 740, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 736, + }, + Geometry: i3ipc.Rect{ + Width: 882, + }, + }, + { + Id: 10, + Type: "con", + Name: "postgreslet - F-I-TS-Chat - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.78488374, + Window: 4194311, + Rect: i3ipc.Rect{ + X: 740, + Y: 26, + Width: 2700, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 2696, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 10, + 8, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 11, + Type: "workspace", + Name: "3", + Nodes: []*i3ipc.Node{ + { + Id: 14, + Type: "con", + Name: "AdZ Desktop (SSL/TLS Secured, 256 bit)", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.3604651, + Window: 14680067, + Rect: i3ipc.Rect{ + Y: 26, + Width: 1240, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1236, + }, + Geometry: i3ipc.Rect{ + Width: 2752, + }, + }, + { + Id: 12, + Type: "con", + Name: "E-Mail – Thomas.vonDein@f-i-ts.de - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.6395349, + Window: 4194324, + Rect: i3ipc.Rect{ + X: 1240, + Y: 26, + Width: 2200, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 2196, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 12, + 14, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 15, + Type: "workspace", + Name: "4", + Nodes: []*i3ipc.Node{ + { + Id: 16, + Type: "con", + Name: "AR System Customizable Home Page (Suchen) - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 1, + Window: 4194338, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + WindowRect: i3ipc.Rect{ + Width: 3440, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 16, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 17, + Type: "workspace", + Name: "5", + Nodes: []*i3ipc.Node{ + { + Id: 19, + Type: "con", + Name: "Terminal - 0:5:go - \"tripod\" ", + Focused: true, + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.50581396, + X11Window: "xfce4-terminal", + Rect: i3ipc.Rect{ + Y: 26, + Width: 1740, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1736, + }, + Geometry: i3ipc.Rect{ + Width: 882, + }, + }, + { + Id: 18, + Type: "con", + Name: "emacs /home/scip/dev/i3ipc/_examples/tree/main.go", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.49418604, + Window: 18874540, + Rect: i3ipc.Rect{ + X: 1740, + Y: 26, + Width: 1700, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1696, + }, + Geometry: i3ipc.Rect{ + Width: 752, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 19, + 18, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 20, + Type: "workspace", + Name: "6", + FloatingNodes: []*i3ipc.Node{ + { + Id: 21, + Type: "floating_con", + Name: "Home - Webex - Google Chrome", + Border: "csd", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.7971424, + X11Window: "google-chrome", + Rect: i3ipc.Rect{ + X: 481, + Y: 35, + Width: 2822, + }, + WindowRect: i3ipc.Rect{ + Width: 2822, + }, + Geometry: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 21, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "output", + Orientation: "none", + Percent: 1, + Focus: []int{ + 17, + 7, + 20, + 11, + 15, + }, + Current_workspace: "5", + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 4, + }, + Rect: i3ipc.Rect{ + Width: 3440, + }, +} +root: root +node: __i3 + focus: false +recursing +node: __i3_scratch + focus: false +recursing +nil diff --git a/_examples/get_marks/main.go b/_examples/get_marks/main.go new file mode 100644 index 0000000..ccfb9ef --- /dev/null +++ b/_examples/get_marks/main.go @@ -0,0 +1,28 @@ +package main + +/* + Retrieve a list of current set marks +*/ + +import ( + "log" + + "github.com/alecthomas/repr" + "github.com/tlinden/i3ipc" +) + +func main() { + ipc := i3ipc.NewI3ipc() + + err := ipc.Connect() + if err != nil { + log.Fatal(err) + } + + marks, err := ipc.GetMarks() + if err != nil { + log.Fatal(err) + } + + repr.Println(marks) +} diff --git a/_examples/get_marks/tree.json b/_examples/get_marks/tree.json new file mode 100644 index 0000000..24eaa5a --- /dev/null +++ b/_examples/get_marks/tree.json @@ -0,0 +1,346 @@ +&i3ipc.Node{ + Id: 1, + Type: "root", + Name: "root", + Nodes: []*i3ipc.Node{ + { + Id: 2147483647, + Type: "output", + Name: "__i3", + Nodes: []*i3ipc.Node{ + { + Id: 2147483646, + Type: "workspace", + Name: "__i3_scratch", + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "output", + Orientation: "horizontal", + Focus: []int{ + 2147483646, + }, + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + { + Id: 4, + Type: "output", + Name: "HDMI-A-1", + Nodes: []*i3ipc.Node{ + { + Id: 7, + Type: "workspace", + Name: "2", + Nodes: []*i3ipc.Node{ + { + Id: 8, + Type: "con", + Name: "Terminal - 1:2:sh - \"tripod\" ", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.21511628, + X11Window: "xfce4-terminal", + Rect: i3ipc.Rect{ + Y: 26, + Width: 740, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 736, + }, + Geometry: i3ipc.Rect{ + Width: 882, + }, + }, + { + Id: 10, + Type: "con", + Name: "postgreslet - F-I-TS-Chat - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.78488374, + Window: 4194311, + Rect: i3ipc.Rect{ + X: 740, + Y: 26, + Width: 2700, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 2696, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 10, + 8, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 11, + Type: "workspace", + Name: "3", + Nodes: []*i3ipc.Node{ + { + Id: 14, + Type: "con", + Name: "AdZ Desktop (SSL/TLS Secured, 256 bit)", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.3604651, + Window: 14680067, + Rect: i3ipc.Rect{ + Y: 26, + Width: 1240, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1236, + }, + Geometry: i3ipc.Rect{ + Width: 2752, + }, + }, + { + Id: 12, + Type: "con", + Name: "E-Mail – Thomas.vonDein@f-i-ts.de - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.6395349, + Window: 4194324, + Rect: i3ipc.Rect{ + X: 1240, + Y: 26, + Width: 2200, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 2196, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 12, + 14, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 15, + Type: "workspace", + Name: "4", + Nodes: []*i3ipc.Node{ + { + Id: 16, + Type: "con", + Name: "AR System Customizable Home Page (Suchen) - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 1, + Window: 4194338, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + WindowRect: i3ipc.Rect{ + Width: 3440, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 16, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 17, + Type: "workspace", + Name: "5", + Nodes: []*i3ipc.Node{ + { + Id: 19, + Type: "con", + Name: "Terminal - 0:5:go - \"tripod\" ", + Focused: true, + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.50581396, + X11Window: "xfce4-terminal", + Rect: i3ipc.Rect{ + Y: 26, + Width: 1740, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1736, + }, + Geometry: i3ipc.Rect{ + Width: 882, + }, + }, + { + Id: 18, + Type: "con", + Name: "emacs /home/scip/dev/i3ipc/_examples/tree/main.go", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.49418604, + Window: 18874540, + Rect: i3ipc.Rect{ + X: 1740, + Y: 26, + Width: 1700, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1696, + }, + Geometry: i3ipc.Rect{ + Width: 752, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 19, + 18, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 20, + Type: "workspace", + Name: "6", + FloatingNodes: []*i3ipc.Node{ + { + Id: 21, + Type: "floating_con", + Name: "Home - Webex - Google Chrome", + Border: "csd", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.7971424, + X11Window: "google-chrome", + Rect: i3ipc.Rect{ + X: 481, + Y: 35, + Width: 2822, + }, + WindowRect: i3ipc.Rect{ + Width: 2822, + }, + Geometry: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 21, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "output", + Orientation: "none", + Percent: 1, + Focus: []int{ + 17, + 7, + 20, + 11, + 15, + }, + Current_workspace: "5", + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 4, + }, + Rect: i3ipc.Rect{ + Width: 3440, + }, +} +root: root +node: __i3 + focus: false +recursing +node: __i3_scratch + focus: false +recursing +nil diff --git a/_examples/get_outputs/log b/_examples/get_outputs/log new file mode 100644 index 0000000..5e4b4da --- /dev/null +++ b/_examples/get_outputs/log @@ -0,0 +1,124 @@ +execve("/opt/bin/swaymsg", ["swaymsg", "-t", "get_bar_config", "bar-0"], 0x7ffca8a3d4b0 /* 96 vars */) = 0 +brk(NULL) = 0x57744ffbd000 +mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x70933d94d000 +access("/etc/ld.so.preload", R_OK) = 0 +openat(AT_FDCWD, "/etc/ld.so.preload", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 +close(3) = 0 +openat(AT_FDCWD, "glibc-hwcaps/x86-64-v3/libjson-c.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "glibc-hwcaps/x86-64-v2/libjson-c.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "libjson-c.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/opt/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/libjson-c.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +newfstatat(AT_FDCWD, "/opt/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/", 0x7fffe6d741a0, 0) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/opt/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/libjson-c.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +newfstatat(AT_FDCWD, "/opt/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/", 0x7fffe6d741a0, 0) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/opt/lib/x86_64-linux-gnu/libjson-c.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +newfstatat(AT_FDCWD, "/opt/lib/x86_64-linux-gnu/", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0 +openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=137987, ...}) = 0 +mmap(NULL, 137987, PROT_READ, MAP_PRIVATE, 3, 0) = 0x70933d92b000 +close(3) = 0 +openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libjson-c.so.5", O_RDONLY|O_CLOEXEC) = 3 +read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832 +fstat(3, {st_mode=S_IFREG|0644, st_size=80344, ...}) = 0 +mmap(NULL, 82416, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x70933d916000 +mmap(0x70933d91a000, 45056, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x4000) = 0x70933d91a000 +mmap(0x70933d925000, 16384, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xf000) = 0x70933d925000 +mmap(0x70933d929000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x12000) = 0x70933d929000 +close(3) = 0 +openat(AT_FDCWD, "glibc-hwcaps/x86-64-v3/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "glibc-hwcaps/x86-64-v2/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/opt/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 +read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@\247\2\0\0\0\0\0"..., 832) = 832 +pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 840, 64) = 840 +fstat(3, {st_mode=S_IFREG|0755, st_size=2178688, ...}) = 0 +pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 840, 64) = 840 +mmap(NULL, 2223736, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x70933d600000 +mmap(0x70933d628000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x70933d628000 +mmap(0x70933d7bd000, 323584, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x70933d7bd000 +mmap(0x70933d80c000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x20b000) = 0x70933d80c000 +mmap(0x70933d812000, 52856, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x70933d812000 +close(3) = 0 +mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x70933d913000 +arch_prctl(ARCH_SET_FS, 0x70933d913740) = 0 +set_tid_address(0x70933d913a10) = 97421 +set_robust_list(0x70933d913a20, 24) = 0 +rseq(0x70933d913680, 0x20, 0, 0x53053053) = 0 +mprotect(0x70933d80c000, 16384, PROT_READ) = 0 +mprotect(0x70933d929000, 4096, PROT_READ) = 0 +mprotect(0x577441241000, 4096, PROT_READ) = 0 +mprotect(0x70933d98f000, 8192, PROT_READ) = 0 +prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0 +munmap(0x70933d92b000, 137987) = 0 +ioctl(1, TCGETS, 0x7fffe6d74e80) = -1 ENOTTY (Inappropriate ioctl for device) +getrandom("\xf3\xb2\x5f\xb5\x3a\x0e\x13\x06", 8, GRND_NONBLOCK) = 8 +brk(NULL) = 0x57744ffbd000 +brk(0x57744ffde000) = 0x57744ffde000 +socket(AF_UNIX, SOCK_STREAM, 0) = 3 +connect(3, {sa_family=AF_UNIX, sun_path="/run/user/1000/sway-ipc.1000.3461.sock"}, 110) = 0 +setsockopt(3, SOL_SOCKET, SO_RCVTIMEO_OLD, "\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) = 0 +write(3, "i3-ipc\5\0\0\0\6\0\0\0", 14) = 14 +write(3, "bar-0", 5) = 5 +recvfrom(3, "i3-ipc\332\4\0\0\6\0\0\0", 14, 0, NULL, NULL) = 14 +recvfrom(3, "{ \"id\": \"bar-0\", \"mode\": \"dock\","..., 1242, 0, NULL, NULL) = 1242 +rt_sigprocmask(SIG_BLOCK, ~[], [], 8) = 0 +mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_DROPPABLE|MAP_ANONYMOUS, -1, 0) = 0x70933d94c000 +mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x70933d94b000 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +getrandom("\x92\xda\xab\x78\x81\x42\x79\x34\x6f\x90\x94\x8c\xb4\x47\xfb\x85\xc1\x00\x43\x1b\x00\x78\x10\x09\x87\x65\x09\x2e\x79\xdb\x4d\xf7", 32, 0) = 32 +fstat(1, {st_mode=S_IFREG|0644, st_size=5648, ...}) = 0 +close(3) = 0 +write(1, "{\n \"id\": \"bar-0\",\n \"mode\": \"do"..., 1387{ + "id": "bar-0", + "mode": "dock", + "hidden_state": "hide", + "position": "top", + "status_command": null, + "font": "monospace 10", + "gaps": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + }, + "bar_height": 0, + "status_padding": 1, + "status_edge_padding": 3, + "wrap_scroll": false, + "workspace_buttons": true, + "strip_workspace_numbers": false, + "strip_workspace_name": false, + "workspace_min_width": 0, + "binding_mode_indicator": true, + "verbose": false, + "pango_markup": true, + "colors": { + "background": "#000000ff", + "statusline": "#ffffffff", + "separator": "#666666ff", + "focused_background": "#000000ff", + "focused_statusline": "#ffffffff", + "focused_separator": "#666666ff", + "focused_workspace_border": "#4c7899ff", + "focused_workspace_bg": "#285577ff", + "focused_workspace_text": "#ffffffff", + "inactive_workspace_border": "#333333ff", + "inactive_workspace_bg": "#222222ff", + "inactive_workspace_text": "#888888ff", + "active_workspace_border": "#333333ff", + "active_workspace_bg": "#5f676aff", + "active_workspace_text": "#ffffffff", + "urgent_workspace_border": "#2f343aff", + "urgent_workspace_bg": "#900000ff", + "urgent_workspace_text": "#ffffffff", + "binding_mode_border": "#2f343aff", + "binding_mode_bg": "#900000ff", + "binding_mode_text": "#ffffffff" + }, + "tray_padding": 2 +} +) = 1387 +exit_group(0) = ? ++++ exited with 0 +++ diff --git a/_examples/get_outputs/main.go b/_examples/get_outputs/main.go new file mode 100644 index 0000000..5086e6d --- /dev/null +++ b/_examples/get_outputs/main.go @@ -0,0 +1,28 @@ +package main + +/* + Retrieve a list of current available outputs +*/ + +import ( + "log" + + "github.com/alecthomas/repr" + "github.com/tlinden/i3ipc" +) + +func main() { + ipc := i3ipc.NewI3ipc() + + err := ipc.Connect() + if err != nil { + log.Fatal(err) + } + + outputs, err := ipc.GetOutputs() + if err != nil { + log.Fatal(err) + } + + repr.Println(outputs) +} diff --git a/_examples/get_outputs/tree.json b/_examples/get_outputs/tree.json new file mode 100644 index 0000000..24eaa5a --- /dev/null +++ b/_examples/get_outputs/tree.json @@ -0,0 +1,346 @@ +&i3ipc.Node{ + Id: 1, + Type: "root", + Name: "root", + Nodes: []*i3ipc.Node{ + { + Id: 2147483647, + Type: "output", + Name: "__i3", + Nodes: []*i3ipc.Node{ + { + Id: 2147483646, + Type: "workspace", + Name: "__i3_scratch", + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "output", + Orientation: "horizontal", + Focus: []int{ + 2147483646, + }, + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + { + Id: 4, + Type: "output", + Name: "HDMI-A-1", + Nodes: []*i3ipc.Node{ + { + Id: 7, + Type: "workspace", + Name: "2", + Nodes: []*i3ipc.Node{ + { + Id: 8, + Type: "con", + Name: "Terminal - 1:2:sh - \"tripod\" ", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.21511628, + X11Window: "xfce4-terminal", + Rect: i3ipc.Rect{ + Y: 26, + Width: 740, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 736, + }, + Geometry: i3ipc.Rect{ + Width: 882, + }, + }, + { + Id: 10, + Type: "con", + Name: "postgreslet - F-I-TS-Chat - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.78488374, + Window: 4194311, + Rect: i3ipc.Rect{ + X: 740, + Y: 26, + Width: 2700, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 2696, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 10, + 8, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 11, + Type: "workspace", + Name: "3", + Nodes: []*i3ipc.Node{ + { + Id: 14, + Type: "con", + Name: "AdZ Desktop (SSL/TLS Secured, 256 bit)", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.3604651, + Window: 14680067, + Rect: i3ipc.Rect{ + Y: 26, + Width: 1240, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1236, + }, + Geometry: i3ipc.Rect{ + Width: 2752, + }, + }, + { + Id: 12, + Type: "con", + Name: "E-Mail – Thomas.vonDein@f-i-ts.de - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.6395349, + Window: 4194324, + Rect: i3ipc.Rect{ + X: 1240, + Y: 26, + Width: 2200, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 2196, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 12, + 14, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 15, + Type: "workspace", + Name: "4", + Nodes: []*i3ipc.Node{ + { + Id: 16, + Type: "con", + Name: "AR System Customizable Home Page (Suchen) - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 1, + Window: 4194338, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + WindowRect: i3ipc.Rect{ + Width: 3440, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 16, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 17, + Type: "workspace", + Name: "5", + Nodes: []*i3ipc.Node{ + { + Id: 19, + Type: "con", + Name: "Terminal - 0:5:go - \"tripod\" ", + Focused: true, + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.50581396, + X11Window: "xfce4-terminal", + Rect: i3ipc.Rect{ + Y: 26, + Width: 1740, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1736, + }, + Geometry: i3ipc.Rect{ + Width: 882, + }, + }, + { + Id: 18, + Type: "con", + Name: "emacs /home/scip/dev/i3ipc/_examples/tree/main.go", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.49418604, + Window: 18874540, + Rect: i3ipc.Rect{ + X: 1740, + Y: 26, + Width: 1700, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1696, + }, + Geometry: i3ipc.Rect{ + Width: 752, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 19, + 18, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 20, + Type: "workspace", + Name: "6", + FloatingNodes: []*i3ipc.Node{ + { + Id: 21, + Type: "floating_con", + Name: "Home - Webex - Google Chrome", + Border: "csd", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.7971424, + X11Window: "google-chrome", + Rect: i3ipc.Rect{ + X: 481, + Y: 35, + Width: 2822, + }, + WindowRect: i3ipc.Rect{ + Width: 2822, + }, + Geometry: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 21, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "output", + Orientation: "none", + Percent: 1, + Focus: []int{ + 17, + 7, + 20, + 11, + 15, + }, + Current_workspace: "5", + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 4, + }, + Rect: i3ipc.Rect{ + Width: 3440, + }, +} +root: root +node: __i3 + focus: false +recursing +node: __i3_scratch + focus: false +recursing +nil diff --git a/_examples/tree/main.go b/_examples/get_tree/main.go similarity index 100% rename from _examples/tree/main.go rename to _examples/get_tree/main.go diff --git a/_examples/get_tree/tree.json b/_examples/get_tree/tree.json new file mode 100644 index 0000000..24eaa5a --- /dev/null +++ b/_examples/get_tree/tree.json @@ -0,0 +1,346 @@ +&i3ipc.Node{ + Id: 1, + Type: "root", + Name: "root", + Nodes: []*i3ipc.Node{ + { + Id: 2147483647, + Type: "output", + Name: "__i3", + Nodes: []*i3ipc.Node{ + { + Id: 2147483646, + Type: "workspace", + Name: "__i3_scratch", + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "output", + Orientation: "horizontal", + Focus: []int{ + 2147483646, + }, + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + { + Id: 4, + Type: "output", + Name: "HDMI-A-1", + Nodes: []*i3ipc.Node{ + { + Id: 7, + Type: "workspace", + Name: "2", + Nodes: []*i3ipc.Node{ + { + Id: 8, + Type: "con", + Name: "Terminal - 1:2:sh - \"tripod\" ", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.21511628, + X11Window: "xfce4-terminal", + Rect: i3ipc.Rect{ + Y: 26, + Width: 740, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 736, + }, + Geometry: i3ipc.Rect{ + Width: 882, + }, + }, + { + Id: 10, + Type: "con", + Name: "postgreslet - F-I-TS-Chat - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.78488374, + Window: 4194311, + Rect: i3ipc.Rect{ + X: 740, + Y: 26, + Width: 2700, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 2696, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 10, + 8, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 11, + Type: "workspace", + Name: "3", + Nodes: []*i3ipc.Node{ + { + Id: 14, + Type: "con", + Name: "AdZ Desktop (SSL/TLS Secured, 256 bit)", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.3604651, + Window: 14680067, + Rect: i3ipc.Rect{ + Y: 26, + Width: 1240, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1236, + }, + Geometry: i3ipc.Rect{ + Width: 2752, + }, + }, + { + Id: 12, + Type: "con", + Name: "E-Mail – Thomas.vonDein@f-i-ts.de - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.6395349, + Window: 4194324, + Rect: i3ipc.Rect{ + X: 1240, + Y: 26, + Width: 2200, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 2196, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 12, + 14, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 15, + Type: "workspace", + Name: "4", + Nodes: []*i3ipc.Node{ + { + Id: 16, + Type: "con", + Name: "AR System Customizable Home Page (Suchen) - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 1, + Window: 4194338, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + WindowRect: i3ipc.Rect{ + Width: 3440, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 16, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 17, + Type: "workspace", + Name: "5", + Nodes: []*i3ipc.Node{ + { + Id: 19, + Type: "con", + Name: "Terminal - 0:5:go - \"tripod\" ", + Focused: true, + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.50581396, + X11Window: "xfce4-terminal", + Rect: i3ipc.Rect{ + Y: 26, + Width: 1740, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1736, + }, + Geometry: i3ipc.Rect{ + Width: 882, + }, + }, + { + Id: 18, + Type: "con", + Name: "emacs /home/scip/dev/i3ipc/_examples/tree/main.go", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.49418604, + Window: 18874540, + Rect: i3ipc.Rect{ + X: 1740, + Y: 26, + Width: 1700, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1696, + }, + Geometry: i3ipc.Rect{ + Width: 752, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 19, + 18, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 20, + Type: "workspace", + Name: "6", + FloatingNodes: []*i3ipc.Node{ + { + Id: 21, + Type: "floating_con", + Name: "Home - Webex - Google Chrome", + Border: "csd", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.7971424, + X11Window: "google-chrome", + Rect: i3ipc.Rect{ + X: 481, + Y: 35, + Width: 2822, + }, + WindowRect: i3ipc.Rect{ + Width: 2822, + }, + Geometry: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 21, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "output", + Orientation: "none", + Percent: 1, + Focus: []int{ + 17, + 7, + 20, + 11, + 15, + }, + Current_workspace: "5", + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 4, + }, + Rect: i3ipc.Rect{ + Width: 3440, + }, +} +root: root +node: __i3 + focus: false +recursing +node: __i3_scratch + focus: false +recursing +nil diff --git a/_examples/get_version/main.go b/_examples/get_version/main.go new file mode 100644 index 0000000..90a2f64 --- /dev/null +++ b/_examples/get_version/main.go @@ -0,0 +1,28 @@ +package main + +/* + Retrieve the wm version +*/ + +import ( + "log" + + "github.com/alecthomas/repr" + "github.com/tlinden/i3ipc" +) + +func main() { + ipc := i3ipc.NewI3ipc() + + err := ipc.Connect() + if err != nil { + log.Fatal(err) + } + + version, err := ipc.GetVersion() + if err != nil { + log.Fatal(err) + } + + repr.Println(version) +} diff --git a/_examples/get_version/tree.json b/_examples/get_version/tree.json new file mode 100644 index 0000000..24eaa5a --- /dev/null +++ b/_examples/get_version/tree.json @@ -0,0 +1,346 @@ +&i3ipc.Node{ + Id: 1, + Type: "root", + Name: "root", + Nodes: []*i3ipc.Node{ + { + Id: 2147483647, + Type: "output", + Name: "__i3", + Nodes: []*i3ipc.Node{ + { + Id: 2147483646, + Type: "workspace", + Name: "__i3_scratch", + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "output", + Orientation: "horizontal", + Focus: []int{ + 2147483646, + }, + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + { + Id: 4, + Type: "output", + Name: "HDMI-A-1", + Nodes: []*i3ipc.Node{ + { + Id: 7, + Type: "workspace", + Name: "2", + Nodes: []*i3ipc.Node{ + { + Id: 8, + Type: "con", + Name: "Terminal - 1:2:sh - \"tripod\" ", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.21511628, + X11Window: "xfce4-terminal", + Rect: i3ipc.Rect{ + Y: 26, + Width: 740, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 736, + }, + Geometry: i3ipc.Rect{ + Width: 882, + }, + }, + { + Id: 10, + Type: "con", + Name: "postgreslet - F-I-TS-Chat - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.78488374, + Window: 4194311, + Rect: i3ipc.Rect{ + X: 740, + Y: 26, + Width: 2700, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 2696, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 10, + 8, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 11, + Type: "workspace", + Name: "3", + Nodes: []*i3ipc.Node{ + { + Id: 14, + Type: "con", + Name: "AdZ Desktop (SSL/TLS Secured, 256 bit)", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.3604651, + Window: 14680067, + Rect: i3ipc.Rect{ + Y: 26, + Width: 1240, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1236, + }, + Geometry: i3ipc.Rect{ + Width: 2752, + }, + }, + { + Id: 12, + Type: "con", + Name: "E-Mail – Thomas.vonDein@f-i-ts.de - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.6395349, + Window: 4194324, + Rect: i3ipc.Rect{ + X: 1240, + Y: 26, + Width: 2200, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 2196, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 12, + 14, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 15, + Type: "workspace", + Name: "4", + Nodes: []*i3ipc.Node{ + { + Id: 16, + Type: "con", + Name: "AR System Customizable Home Page (Suchen) - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 1, + Window: 4194338, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + WindowRect: i3ipc.Rect{ + Width: 3440, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 16, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 17, + Type: "workspace", + Name: "5", + Nodes: []*i3ipc.Node{ + { + Id: 19, + Type: "con", + Name: "Terminal - 0:5:go - \"tripod\" ", + Focused: true, + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.50581396, + X11Window: "xfce4-terminal", + Rect: i3ipc.Rect{ + Y: 26, + Width: 1740, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1736, + }, + Geometry: i3ipc.Rect{ + Width: 882, + }, + }, + { + Id: 18, + Type: "con", + Name: "emacs /home/scip/dev/i3ipc/_examples/tree/main.go", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.49418604, + Window: 18874540, + Rect: i3ipc.Rect{ + X: 1740, + Y: 26, + Width: 1700, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1696, + }, + Geometry: i3ipc.Rect{ + Width: 752, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 19, + 18, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 20, + Type: "workspace", + Name: "6", + FloatingNodes: []*i3ipc.Node{ + { + Id: 21, + Type: "floating_con", + Name: "Home - Webex - Google Chrome", + Border: "csd", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.7971424, + X11Window: "google-chrome", + Rect: i3ipc.Rect{ + X: 481, + Y: 35, + Width: 2822, + }, + WindowRect: i3ipc.Rect{ + Width: 2822, + }, + Geometry: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 21, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "output", + Orientation: "none", + Percent: 1, + Focus: []int{ + 17, + 7, + 20, + 11, + 15, + }, + Current_workspace: "5", + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 4, + }, + Rect: i3ipc.Rect{ + Width: 3440, + }, +} +root: root +node: __i3 + focus: false +recursing +node: __i3_scratch + focus: false +recursing +nil diff --git a/_examples/get_workspaces/main.go b/_examples/get_workspaces/main.go new file mode 100644 index 0000000..7439994 --- /dev/null +++ b/_examples/get_workspaces/main.go @@ -0,0 +1,28 @@ +package main + +/* + Retrieve a list of current available workspaces +*/ + +import ( + "log" + + "github.com/alecthomas/repr" + "github.com/tlinden/i3ipc" +) + +func main() { + ipc := i3ipc.NewI3ipc() + + err := ipc.Connect() + if err != nil { + log.Fatal(err) + } + + workspaces, err := ipc.GetWorkspaces() + if err != nil { + log.Fatal(err) + } + + repr.Println(workspaces) +} diff --git a/_examples/get_workspaces/tree.json b/_examples/get_workspaces/tree.json new file mode 100644 index 0000000..24eaa5a --- /dev/null +++ b/_examples/get_workspaces/tree.json @@ -0,0 +1,346 @@ +&i3ipc.Node{ + Id: 1, + Type: "root", + Name: "root", + Nodes: []*i3ipc.Node{ + { + Id: 2147483647, + Type: "output", + Name: "__i3", + Nodes: []*i3ipc.Node{ + { + Id: 2147483646, + Type: "workspace", + Name: "__i3_scratch", + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "output", + Orientation: "horizontal", + Focus: []int{ + 2147483646, + }, + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + { + Id: 4, + Type: "output", + Name: "HDMI-A-1", + Nodes: []*i3ipc.Node{ + { + Id: 7, + Type: "workspace", + Name: "2", + Nodes: []*i3ipc.Node{ + { + Id: 8, + Type: "con", + Name: "Terminal - 1:2:sh - \"tripod\" ", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.21511628, + X11Window: "xfce4-terminal", + Rect: i3ipc.Rect{ + Y: 26, + Width: 740, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 736, + }, + Geometry: i3ipc.Rect{ + Width: 882, + }, + }, + { + Id: 10, + Type: "con", + Name: "postgreslet - F-I-TS-Chat - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.78488374, + Window: 4194311, + Rect: i3ipc.Rect{ + X: 740, + Y: 26, + Width: 2700, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 2696, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 10, + 8, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 11, + Type: "workspace", + Name: "3", + Nodes: []*i3ipc.Node{ + { + Id: 14, + Type: "con", + Name: "AdZ Desktop (SSL/TLS Secured, 256 bit)", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.3604651, + Window: 14680067, + Rect: i3ipc.Rect{ + Y: 26, + Width: 1240, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1236, + }, + Geometry: i3ipc.Rect{ + Width: 2752, + }, + }, + { + Id: 12, + Type: "con", + Name: "E-Mail – Thomas.vonDein@f-i-ts.de - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.6395349, + Window: 4194324, + Rect: i3ipc.Rect{ + X: 1240, + Y: 26, + Width: 2200, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 2196, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 12, + 14, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 15, + Type: "workspace", + Name: "4", + Nodes: []*i3ipc.Node{ + { + Id: 16, + Type: "con", + Name: "AR System Customizable Home Page (Suchen) - Chromium", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 1, + Window: 4194338, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + WindowRect: i3ipc.Rect{ + Width: 3440, + }, + Geometry: i3ipc.Rect{ + Width: 1142, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 16, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 17, + Type: "workspace", + Name: "5", + Nodes: []*i3ipc.Node{ + { + Id: 19, + Type: "con", + Name: "Terminal - 0:5:go - \"tripod\" ", + Focused: true, + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.50581396, + X11Window: "xfce4-terminal", + Rect: i3ipc.Rect{ + Y: 26, + Width: 1740, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1736, + }, + Geometry: i3ipc.Rect{ + Width: 882, + }, + }, + { + Id: 18, + Type: "con", + Name: "emacs /home/scip/dev/i3ipc/_examples/tree/main.go", + Border: "pixel", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.49418604, + Window: 18874540, + Rect: i3ipc.Rect{ + X: 1740, + Y: 26, + Width: 1700, + }, + WindowRect: i3ipc.Rect{ + X: 2, + Y: 2, + Width: 1696, + }, + Geometry: i3ipc.Rect{ + Width: 752, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 19, + 18, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + { + Id: 20, + Type: "workspace", + Name: "6", + FloatingNodes: []*i3ipc.Node{ + { + Id: 21, + Type: "floating_con", + Name: "Home - Webex - Google Chrome", + Border: "csd", + Layout: "none", + Orientation: "none", + CurrentBorderWidth: 2, + Percent: 0.7971424, + X11Window: "google-chrome", + Rect: i3ipc.Rect{ + X: 481, + Y: 35, + Width: 2822, + }, + WindowRect: i3ipc.Rect{ + Width: 2822, + }, + Geometry: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 21, + }, + Rect: i3ipc.Rect{ + Y: 26, + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "output", + Orientation: "none", + Percent: 1, + Focus: []int{ + 17, + 7, + 20, + 11, + 15, + }, + Current_workspace: "5", + Rect: i3ipc.Rect{ + Width: 3440, + }, + }, + }, + Border: "none", + Layout: "splith", + Orientation: "horizontal", + Focus: []int{ + 4, + }, + Rect: i3ipc.Rect{ + Width: 3440, + }, +} +root: root +node: __i3 + focus: false +recursing +node: __i3_scratch + focus: false +recursing +nil diff --git a/_examples/run_command/main.go b/_examples/run_command/main.go new file mode 100644 index 0000000..ddfe023 --- /dev/null +++ b/_examples/run_command/main.go @@ -0,0 +1,44 @@ +package main + +/* + This example toggles the current terminal window's floating + state. Execute repeatedly to toggle between full and floating + state. Run this from a terminal window to see the effect. +*/ + +import ( + "log" + + "github.com/alecthomas/repr" + "github.com/tlinden/i3ipc" +) + +func main() { + ipc := i3ipc.NewI3ipc() + + err := ipc.Connect() + if err != nil { + log.Fatal(err) + } + + // retrieve the sway tree + tree, err := ipc.GetTree() + if err != nil { + log.Fatal(err) + } + + // find the data for the current window + focused := tree.FindFocused() + + if focused == nil { + log.Fatal("no focused window found") + } + + // finally execute the given commands on it, you can use any run + // command, see sway(5) + responses, err := ipc.RunCommand(focused.Id, "floating toggle, border toggle") + if err != nil { + repr.Println(responses) + log.Fatal(err) + } +} diff --git a/_examples/run_global_command/main.go b/_examples/run_global_command/main.go new file mode 100644 index 0000000..41fc304 --- /dev/null +++ b/_examples/run_global_command/main.go @@ -0,0 +1,28 @@ +package main + +/* + This example toggles borders globally for all windows, execute + multiple time to see the toggling. +*/ + +import ( + "log" + + "github.com/alecthomas/repr" + "github.com/tlinden/i3ipc" +) + +func main() { + ipc := i3ipc.NewI3ipc() + + err := ipc.Connect() + if err != nil { + log.Fatal(err) + } + + responses, err := ipc.RunGlobalCommand("border toggle") + if err != nil { + repr.Println(responses) + log.Fatal(err) + } +} diff --git a/bar.go b/bar.go new file mode 100644 index 0000000..352a128 --- /dev/null +++ b/bar.go @@ -0,0 +1,93 @@ +package i3ipc + +import ( + "encoding/json" + "fmt" +) + +type Gaps struct { + Top int `json:"top"` + Right int `json:"right"` + Bottom int `json:"bottom"` + Left int `json:"left"` +} + +type Colors struct { + Background string `json:"background"` + Statusline string `json:"statusline"` + Separator string `json:"separator"` + FocusedBackground string `json:"focused_background"` + FocusedStatusline string `json:"focused_statusline"` + FocusedSeparator string `json:"focused_separator"` + FocusedWorkspaceBorder string `json:"focused_workspace_border"` + FocusedWorkspaceBg string `json:"focused_workspace_bg"` + FocusedWorkspaceText string `json:"focused_workspace_text"` + InactiveWorkspaceBorder string `json:"inactive_workspace_border"` + InactiveWorkspaceBg string `json:"inactive_workspace_bg"` + InactiveWorkspaceText string `json:"inactive_workspace_text"` + Active_workspaceBorder string `json:"active_workspace_border"` + Active_workspaceBg string `json:"active_workspace_bg"` + Active_workspaceText string `json:"active_workspace_text"` + Urgent_workspaceBorder string `json:"urgent_workspace_border"` + Urgent_workspaceBg string `json:"urgent_workspace_bg"` + Urgent_workspaceText string `json:"urgent_workspace_text"` + BindingModeBorder string `json:"binding_mode_border"` + BindingModeBg string `json:"binding_mode_bg"` + BindingModeText string `json:"binding_mode_text"` +} + +type Bar struct { + Id string `json:"id"` + Mode string `json:"mode"` + Position string `json:"position"` + Status_command string `json:"status_command"` + Font string `json:"font"` + Gaps *Gaps `json:"gaps"` + Height int `json:"bar_height"` + StatusPadding int `json:"status_padding"` + StatusEdgePadding int `json:"status_edge_padding"` + WorkspaceButtons bool `json:"workspace_buttons"` + WorkspaceMinWidth int `json:"workspace_min_width"` + BindingModeIndicator bool `json:"binding_mode_indicator"` + Verbose bool `json:"verbose"` + PangoMarkup bool `json:"pango_markup"` + Colors *Colors `json:"colors"` +} + +func (ipc *I3ipc) GetBars() ([]string, error) { + payload, err := ipc.get(GET_BAR_CONFIG) + if err != nil { + return nil, err + } + + bars := []string{} + if err := json.Unmarshal(payload, &bars); err != nil { + return nil, fmt.Errorf("failed to unmarshal json: %w", err) + } + + return bars, nil +} + +func (ipc *I3ipc) GetBar(id string) (*Bar, error) { + err := ipc.sendHeader(GET_BAR_CONFIG, uint32(len(id))) + if err != nil { + return nil, err + } + + err = ipc.sendPayload([]byte(id)) + if err != nil { + return nil, fmt.Errorf("failed to send get_bar_config payload: %w", err) + } + + payload, err := ipc.readResponse() + if err != nil { + return nil, err + } + + bar := &Bar{} + if err := json.Unmarshal(payload, &bar); err != nil { + return nil, fmt.Errorf("failed to unmarshal json: %w", err) + } + + return bar, nil +} diff --git a/i3ipc.go b/i3ipc.go index b03fabc..8d80877 100644 --- a/i3ipc.go +++ b/i3ipc.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "net" + "strings" ) const ( @@ -53,15 +54,24 @@ type Response struct { Error string `json:"error"` } -func NewI3ipc(file string) *I3ipc { - if file == "" { - file = "SWAYSOCK" - } - return &I3ipc{SocketFile: file} +type Config struct { + Config string `json:"config"` } -func (ipc *I3ipc) GetTree() (*Node, error) { - err := ipc.sendHeader(GET_TREE, 0) +func NewI3ipc(file ...string) *I3ipc { + ipc := &I3ipc{} + + if len(file) == 0 { + ipc.SocketFile = "SWAYSOCK" + } else { + ipc.SocketFile = file[0] + } + + return ipc +} + +func (ipc *I3ipc) get(command uint32) ([]byte, error) { + err := ipc.sendHeader(command, 0) if err != nil { return nil, err } @@ -71,10 +81,110 @@ func (ipc *I3ipc) GetTree() (*Node, error) { return nil, err } - node := &Node{} - if err := json.Unmarshal(payload, &node); err != nil { + return payload, nil +} + +func (ipc *I3ipc) RunGlobalCommand(command ...string) ([]Response, error) { + return ipc.RunCommand(0, command...) +} + +func (ipc *I3ipc) RunCommand(id int, command ...string) ([]Response, error) { + if len(command) == 0 { + return nil, fmt.Errorf("empty command arg") + } + + commands := strings.Join(command, ",") + + if id > 0 { + commands = fmt.Sprintf("[con_id=%d] %s", id, commands) + } + + err := ipc.sendHeader(RUN_COMMAND, uint32(len(commands))) + if err != nil { + return nil, fmt.Errorf("failed to send run_command to IPC %w", err) + } + + err = ipc.sendPayload([]byte(commands)) + if err != nil { + return nil, fmt.Errorf("failed to send switch focus command: %w", err) + } + + payload, err := ipc.readResponse() + if err != nil { + return nil, err + } + + responses := []Response{} + + if err := json.Unmarshal(payload, &responses); err != nil { + return nil, fmt.Errorf("failed to unmarshal json response: %w", err) + } + + if len(responses) == 0 { + return nil, fmt.Errorf("got zero IPC response") + } + + for _, response := range responses { + if !response.Success { + return responses, fmt.Errorf("one or more commands failed") + } + } + + return responses, nil +} + +func (ipc *I3ipc) GetWorkspaces() ([]*Node, error) { + payload, err := ipc.get(GET_WORKSPACES) + if err != nil { + return nil, err + } + + nodes := []*Node{} + if err := json.Unmarshal(payload, &nodes); err != nil { return nil, fmt.Errorf("failed to unmarshal json: %w", err) } - return node, nil + return nodes, nil +} + +func (ipc *I3ipc) GetMarks() ([]string, error) { + payload, err := ipc.get(GET_MARKS) + if err != nil { + return nil, err + } + + marks := []string{} + if err := json.Unmarshal(payload, &marks); err != nil { + return nil, fmt.Errorf("failed to unmarshal json: %w", err) + } + + return marks, nil +} + +func (ipc *I3ipc) GetBindingModes() ([]string, error) { + payload, err := ipc.get(GET_BINDING_MODES) + if err != nil { + return nil, err + } + + modes := []string{} + if err := json.Unmarshal(payload, &modes); err != nil { + return nil, fmt.Errorf("failed to unmarshal json: %w", err) + } + + return modes, nil +} + +func (ipc *I3ipc) GetConfig() (string, error) { + payload, err := ipc.get(GET_CONFIG) + if err != nil { + return "", err + } + + config := &Config{} + if err := json.Unmarshal(payload, &config); err != nil { + return "", fmt.Errorf("failed to unmarshal json: %w", err) + } + + return config.Config, nil } diff --git a/net.go b/net.go index fd0a836..89f6773 100644 --- a/net.go +++ b/net.go @@ -64,8 +64,6 @@ func (ipc *I3ipc) readResponse() ([]byte, error) { return nil, fmt.Errorf("failed to read header from ipc socket: %s", err) } - // slog.Debug("got IPC header", "header", hex.EncodeToString(buf)) - if string(buf[:6]) != IPC_MAGIC { return nil, fmt.Errorf("got invalid response from IPC socket") } diff --git a/node.go b/node.go index 55af93d..5bfbaf8 100644 --- a/node.go +++ b/node.go @@ -1,5 +1,10 @@ package i3ipc +import ( + "encoding/json" + "fmt" +) + type Node struct { Id int `json:"id"` Type string `json:"type"` // output, workspace or container @@ -27,6 +32,25 @@ type Node struct { var __focused *Node var __currentworkspace string +func (ipc *I3ipc) GetTree() (*Node, error) { + err := ipc.sendHeader(GET_TREE, 0) + if err != nil { + return nil, err + } + + payload, err := ipc.readResponse() + if err != nil { + return nil, err + } + + node := &Node{} + if err := json.Unmarshal(payload, &node); err != nil { + return nil, fmt.Errorf("failed to unmarshal json: %w", err) + } + + return node, nil +} + func (node *Node) FindFocused() *Node { searchFocused(node.Nodes) if __focused == nil { diff --git a/output.go b/output.go new file mode 100644 index 0000000..1c28a60 --- /dev/null +++ b/output.go @@ -0,0 +1,44 @@ +package i3ipc + +import ( + "encoding/json" + "fmt" +) + +type Mode struct { + Width int `json:"width"` + Height int `json:"height"` + Refresh int `json:"refresh"` +} + +type Output struct { + Name string `json:"name"` + Make string `json:"make"` + Serial string `json:"serial"` + Active bool `json:"active"` + Primary bool `json:"primary"` + SubpixelHinting string `json:"subpixel_hinting"` + Transform string `json:"transform"` + Current_workspace string `json:"current_workspace"` + Modes []*Mode `json:"modes"` + CurrentMode *Mode `json:"current_mode"` +} + +func (ipc *I3ipc) GetOutputs() ([]*Output, error) { + err := ipc.sendHeader(GET_OUTPUTS, 0) + if err != nil { + return nil, err + } + + payload, err := ipc.readResponse() + if err != nil { + return nil, err + } + + workspaces := []*Output{} + if err := json.Unmarshal(payload, &workspaces); err != nil { + return nil, fmt.Errorf("failed to unmarshal json: %w", err) + } + + return workspaces, nil +} diff --git a/version.go b/version.go new file mode 100644 index 0000000..625c69d --- /dev/null +++ b/version.go @@ -0,0 +1,27 @@ +package i3ipc + +import ( + "encoding/json" + "fmt" +) + +type Version struct { + HumanReadable string `json:"human_readable"` + Major int `json:"major"` + Minor int `json:"minor"` + Patch int `json:"patch"` +} + +func (ipc *I3ipc) GetVersion() (*Version, error) { + payload, err := ipc.get(GET_VERSION) + if err != nil { + return nil, err + } + + version := &Version{} + if err := json.Unmarshal(payload, &version); err != nil { + return nil, fmt.Errorf("failed to unmarshal json: %w", err) + } + + return version, nil +}