scripts/sway/popup-term.pl

130 lines
4.5 KiB
Perl
Executable File

#!/usr/bin/perl
use strict;
use warnings;
use feature ( 'signatures' );
use JSON::MaybeXS;
my $json = JSON::MaybeXS->new();
our ($workspace, $term_id, $term_ws, $ww, $wh, $tw, $th, $tc);
# Desired terminal dimensions (px or %) and corner (top-right, top-left, bottom-right, bottom-left)
$tw = '100%';
$th = '30%';
$tc = 'bottom-right';
# Workspace to push the terminal to when dismissed
my $hidden = 'grave';
# Terminal executable used for pop-up
my $term = 'alacritty';
# App ID
my $app_id = 'Alacritty-grave';
sub search($nodes, $o=undef, $w=undef, $depth=0) {
my $debug = 0;
my $term_id;
$depth++;
my $prefix = " "x($depth*4);
foreach my $n (@{$nodes}) {
print("${prefix}Checking node $n->{id}".(defined($n->{name}) ? " ($n->{name})" : "")."\n") if ($debug);
print("${prefix}Considering $n->{app_id}...\n") if ($debug && defined($n->{app_id}));
if ($n->{type} eq "output") {
$o = $n->{name};
print("${prefix}Searching output $o\n") if ($debug);
} elsif ($n->{type} eq "workspace") {
$w = $n->{name};
print("${prefix}Searching workspace $w\n") if ($debug);
} else {
print("${prefix}Currently on display $o, workspace $w\n") if ($debug);
if (defined($n->{app_id}) && $n->{app_id} eq $app_id) {
$term_id = $n->{id};
$term_ws = $w;
print("${prefix}Found $app_id with id $term_id on workspace $w\n") if ($debug);
return $term_id;
}
}
$term_id = search($n->{floating_nodes}, $o, $w, $depth);
$term_id = search($n->{nodes}, $o, $w, $depth) if ($term_id == 0);
print("${prefix}Found $term_id on $w\n") if ($debug && $term_id);
return $term_id if ($term_id);
}
print("${prefix}Not found, moving up a node\n") if ($debug);
return 0;
}
sub resize() {
my ($d, $r, $h, $w) = (0, 0);
if (my ($hit) = $tw =~ m/^(100|\d\d?)\%$/) {
$w = int(($ww * $hit) / 100);
$r = $ww - $w if ($tc =~ m/right$/);
} elsif (($tw =~ m/^\d+$/) && (1 < $tw <= $ww)) {
$d = $wh - $th if ($tc =~ m/^bottom/);
}
if (my ($hit) = $th =~ m/^(100|\d\d?)\%$/) {
$h = int(($wh * $hit) / 100);
$d = $wh - $h if ($tc =~ m/^bottom/);
} elsif (($tw =~ m/^\d+$/) && (1 < $tw <= $ww)) {
$r = $ww - $tw if ($tc =~ m/right$/);
}
`swaymsg "[con_id=$term_id]" resize set width ${w}px height ${h}px, move position ${r}px ${d}px`;
}
my $raw = join("\n",`swaymsg -t get_tree`);
my $root = $json->decode($raw);
$term_id = search($root->{nodes}) || undef;
my $focused = $root->{focus}->[0];
foreach my $d (@{$root->{nodes}}) {
last if (defined($workspace));
if ($d->{id} eq $focused) {
foreach my $w (@{$d->{nodes}}) {
if ($w->{id} eq $d->{focus}->[0]) {
$workspace = $w->{name};
$ww = $w->{rect}->{width};
$wh = $w->{rect}->{height};
last;
}
}
}
}
#print("Current workspace is $workspace ($ww x $wh)\n");
#print("Found terminal at node $term_id\n") if (defined($term_id));
#print("Found terminal on workspace $term_ws\n") if (defined($term_ws));
# If there is no terminal found, spawn one
my $resize = 0;
if (!defined($term_id)) {
my $pid = fork();
if ($pid) {
print "No term running, starting one with PID $pid\n";
sleep 1;
$raw = join("\n",`swaymsg -t get_tree`);
$root = $json->decode($raw);
$term_id = search($root->{nodes}) || undef;
die("Term not found after starting") unless (defined($term_id));
} else {
print("Starting in fork...\n");
`$term --config-file $ENV{HOME}/.dotfiles/alacritty/grave.toml --class $app_id & disown`;
print("Exitting\n");
exit(1);
}
resize();
}
# If the current workspace is known and terminal isn't on it, bring and focus
if (defined($term_ws) && $workspace ne $term_ws) {
print "Term not on current workspace, bringing it\n";
`swaymsg "[con_id=$term_id]" floating enable`;
resize();
`swaymsg "[con_id=$term_id]" sticky enable`;
`swaymsg "[con_id=$term_id]" move workspace $workspace`;
`swaymsg "[con_id=$term_id]" focus`;
# Otherwise hide it from whereever it is
} else {
print "Term is on current workspace or lost, moving to $hidden\n";
`swaymsg "[con_id=$term_id]" sticky disable`;
`swaymsg "[con_id=$term_id]" move workspace $hidden`;
`swaymsg "[con_id=$term_id]" floating disable`;
}