summaryrefslogtreecommitdiffstats
path: root/i3/.bin/i3-switch-workspace
diff options
context:
space:
mode:
Diffstat (limited to 'i3/.bin/i3-switch-workspace')
-rwxr-xr-xi3/.bin/i3-switch-workspace137
1 files changed, 137 insertions, 0 deletions
diff --git a/i3/.bin/i3-switch-workspace b/i3/.bin/i3-switch-workspace
new file mode 100755
index 0000000..b54afa1
--- /dev/null
+++ b/i3/.bin/i3-switch-workspace
@@ -0,0 +1,137 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use 5.014;
+
+use IO::Socket::UNIX;
+use JSON::PP;
+
+my $json = JSON::PP->new;
+
+my $virtual_workspace = 'virtual';
+
+my %message_types = (
+ command => 0,
+ get_workspaces => 1,
+ subscribe => 2,
+ get_outputs => 3,
+ get_tree => 4,
+ get_marks => 5,
+ get_bar_config => 6,
+ get_version => 7,
+);
+
+my %message_codes = (reverse %message_types);
+
+my $dir = $ARGV[0];
+
+chomp(my $path = qx(i3 --get-socketpath));
+my $sock = IO::Socket::UNIX->new(Peer => $path);
+
+my $workspace_data = $json->decode(i3_msg('get_workspaces'));
+my $tree_data = $json->decode(i3_msg('get_tree'));
+
+my $first = 99999;
+my $last = -99999;
+my $cur;
+my $cur_name;
+my $virtual_output;
+
+for my $i (0..$#$workspace_data) {
+ my $num = $workspace_data->[$i]{num};
+ if ($workspace_data->[$i]{focused}) {
+ $cur = $num;
+ $cur_name = $workspace_data->[$i]{name};
+ if ($cur_name eq $virtual_workspace) {
+ $virtual_output = $workspace_data->[$i]{output};
+ }
+ }
+
+ my $workspace_tree = find_workspace($tree_data, $num);
+ next unless
+ @{ $workspace_tree->{nodes} } ||
+ @{ $workspace_tree->{floating_nodes} };
+
+ $first = $num if $num < $first;
+ $last = $num if $num > $last;
+}
+
+if ($dir eq 'prev') {
+ if ($cur >= $first) {
+ i3_msg('command', "workspace ${\($cur - 1)}");
+ }
+}
+elsif ($dir eq 'next') {
+ if ($cur <= $last) {
+ i3_msg('command', "workspace ${\($cur + 1)}");
+ }
+}
+elsif ($dir eq $virtual_workspace) {
+ if (!defined $virtual_output || $virtual_output eq 'VIRTUAL1') {
+ i3_msg(
+ 'command',
+ "workspace $virtual_workspace; move workspace to output eDP1",
+ );
+ }
+ else {
+ i3_msg(
+ 'command',
+ "workspace $virtual_workspace; move workspace to output VIRTUAL1",
+ );
+ }
+}
+else {
+ die "unknown subcommand $dir";
+}
+
+sub find_workspace {
+ my ($tree, $num) = @_;
+ if (exists $tree->{num} && $tree->{num} == $num) {
+ return $tree;
+ }
+ for my $node (@{ $tree->{nodes} }) {
+ my $found = find_workspace($node, $num);
+ return $found if $found;
+ }
+ return;
+}
+
+sub build_i3_msg {
+ my ($type, $payload) = @_;
+
+ $payload = ''
+ unless $type eq 'command' || $type eq 'subscribe';
+
+ utf8::encode($payload);
+
+ return 'i3-ipc'
+ . pack('LL', length($payload), $message_types{$type})
+ . $payload;
+}
+
+sub get_i3_msg {
+ my $bytes = $sock->read(my $header, 14);
+ die "invalid read" if $bytes != 14;
+ die "invalid format: $header" if substr($header, 0, 6) ne 'i3-ipc';
+ my ($length, $type) = unpack('LL', substr($header, 6, 8));
+
+ if ($length) {
+ my $bytes = $sock->read(my $payload, $length);
+ die "invalid read" if $bytes != $length;
+ utf8::decode($payload);
+ return ($message_codes{$type}, $payload);
+ }
+ else {
+ return ($message_codes{$type});
+ }
+}
+
+sub i3_msg {
+ my ($type, $payload) = @_;
+ my $msg = build_i3_msg($type, $payload);
+ $sock->write($msg);
+ my ($got_type, $got_payload) = get_i3_msg();
+ die "got $got_type message, expected $type message"
+ unless $type eq $got_type;
+ return $got_payload;
+}