diff --git a/config.json b/config.json index 8872978..3cd5791 100644 --- a/config.json +++ b/config.json @@ -23,7 +23,7 @@ # Also we can tcp-ping some service inside vpn network to ensure that connection is not stoned "tcp_check" : { "enabled": 0, - "host": "somehost.com", + "host": "somehost.tld", "port": "443", "timeout" : 3 } @@ -36,6 +36,7 @@ "cmd" : "killall -9 fbpanel", "color": "#aa0000", "border": "#adadad", + "border_active": "#3e78fd", "separator": false, "separator_block_width": 2 }, @@ -43,18 +44,23 @@ "full_text" : " Term ", "name" : "lilyterm", "cmd" : "lilyterm", + "instance" : "lilyterm", + "class" : "LilyTerm", "color" : "#666666", "border": "#adadad", + "border_active": "#3e78fd", "separator": false, "separator_block_width": 2 - }, { "full_text" : " Ff ", "name" : "firefox", "cmd" : "firefox", + "instance" : "Navigator", + "class" : "Firefox", "color" : "#ffa500", "border": "#adadad", + "border_active": "#3e78fd", "separator": false, "separator_block_width": 2 }, @@ -62,8 +68,11 @@ "full_text" : " V ", "name" : "vivaldi", "cmd" : "vivaldi", + "instance" : "vivaldi-stable", + "class" : "Vivaldi-stable", "color" : "#ffa500", "border": "#adadad", + "border_active": "#3e78fd", "separator": false, "separator_block_width": 2 }, @@ -71,8 +80,11 @@ "full_text" : " Chr ", "name" : "chrome", "cmd" : "chrome", + "instance" : "google-chrome", + "class" : "Google-chrome", "color" : "#ffa500", "border": "#adadad", + "border_active": "#3e78fd", "separator": false, "separator_block_width": 2 }, @@ -80,8 +92,11 @@ "full_text" : " O ", "name" : "opera", "cmd" : "opera", + "instance" : "Opera", + "class" : "Opera", "color" : "#ffa500", "border": "#adadad", + "border_active": "#3e78fd", "separator": false, "separator_block_width": 2 }, @@ -89,8 +104,11 @@ "full_text" : " @ ", "name" : "thunderbird", "cmd" : "thunderbird", + "instance" : "Mail", + "class" : "Thunderbird", "color" : "#006994", "border": "#adadad", + "border_active": "#3e78fd", "separator": false, "separator_block_width": 2 }, @@ -98,8 +116,11 @@ "full_text" : " Tg ", "name" : "telegram", "cmd" : "Telegram", + "instance" : "Telegram", + "class" : "TelegramDesktop", "color" : "#5a8850", "border": "#adadad", + "border_active": "#3e78fd", "separator": false, "separator_block_width": 2 }, @@ -107,8 +128,11 @@ "full_text" : " M ", "name" : "myteam", "cmd" : "myteam", + "instance" : "myteam", + "class" : "myteam", "color" : "#5a8850", "border": "#adadad", + "border_active": "#3e78fd", "separator": false, "separator_block_width": 2 }, @@ -116,8 +140,11 @@ "full_text" : " S ", "name" : "slack", "cmd" : "slack", + "instance" : "slack", + "class" : "Slack", "color" : "#5a8850", "border": "#adadad", + "border_active": "#3e78fd", "separator": false, "separator_block_width": 2 }, @@ -125,7 +152,10 @@ "full_text" : " Txt ", "name" : "mousepad", "cmd" : "mousepad", + "instance" : "mousepad", + "class" : "Mousepad", "border": "#adadad", + "border_active": "#3e78fd", "separator": false, "separator_block_width": 2 }, @@ -133,7 +163,10 @@ "full_text" : " VSC ", "name" : "code", "cmd" : "code", + "instance" : "code", + "class" : "Code", "border": "#adadad", + "border_active": "#3e78fd", "separator": false, "separator_block_width": 2 }, @@ -141,8 +174,11 @@ "full_text" : " K ", "name" : "keepassxc", "cmd" : "keepassxc", + "instance" : "keepassxc", + "class" : "KeePassXC", "color" : "#7ec850", - "border": "#adadad" + "border" : "#adadad", + "border_active" : "#3e78fd" } ] -} \ No newline at end of file +} diff --git a/i3status-anyevent b/i3status-anyevent index 92ba1b7..fa669e6 100644 --- a/i3status-anyevent +++ b/i3status-anyevent @@ -16,6 +16,7 @@ use utf8; use open qw (:std :utf8); use Fcntl qw (:seek); use AnyEvent; +use AnyEvent::I3; use JSON::XS; use Net::DBus; use Encode; @@ -26,9 +27,12 @@ sub spawn (@); sub find_caps_led (); sub to_hours ($); sub readconf (); +sub active_win_borders (); my $CONF = readconf (); +my $i3 = i3 (); my $done = AnyEvent->condvar; +$i3->connect->recv or die 'Unable to connect to i3'; # event pool my @EP; @@ -36,6 +40,7 @@ my @EP; # reload config and re-apply it on SIGHUP $SIG{HUP} = sub { $CONF = readconf (); + active_win_borders (); $#EP = -1; add_events (); }; @@ -68,14 +73,55 @@ my $CAPS_LED_PATH = find_caps_led (); # for fetching battery stats via dee-boos :) my $properties; +# opened windows info storage ref +my $win; + # capture click events and do not override sigstop and sigcont numbers syswrite STDOUT, << 'EOJSON'; {"version": 1, "click_events": true} [ [], EOJSON +# i3 events should persist over config relads +my $i3_subscription->{window} = sub { + my $w = shift; + + if (defined $w->{change}) { + if ($w->{change} eq 'new' ) { + if (defined $w->{container}->{window_properties}->{instance}) { + if (defined $win->{instance}->{$w->{container}->{window_properties}->{instance}}) { + $win->{instance}->{$w->{container}->{window_properties}->{instance}}++; + } else { + $win->{instance}->{$w->{container}->{window_properties}->{instance}} = 1; + } + } + } elsif ($w->{change} eq 'close') { + if (defined $w->{container}->{window_properties}->{instance}) { + if (defined $win->{instance}->{$w->{container}->{window_properties}->{instance}}) { + if ($win->{instance}->{$w->{container}->{window_properties}->{instance}} > 1) { + $win->{instance}->{$w->{container}->{window_properties}->{instance}} --; + } else { + delete $win->{instance}->{$w->{container}->{window_properties}->{instance}}; + } + } + } + } + + active_win_borders (); + } +}; + +$i3_subscription->{_error} = sub { + my ($msg) = @_; + die "Connection to i3 closed: $msg"; +}; + +$i3->subscribe($i3_subscription)->recv->{success} || die 'Unable to subscribe to i3 events'; + +# now we can add other events add_events (); -warn "events added"; + +# and start eventloop $done->recv (); exit 0; @@ -107,22 +153,22 @@ sub add_events () { if ($CONF->{capslock}) { unless ($caps_state) { - push @{$OUTPUT}, { "color" => "#3e78fd", "background" => "#edeceb", border => "#edeceb", "full_text" => "caps", "markup" => "pango"}; + push @{$OUTPUT}, { color => '#3e78fd', background => '#edeceb', border => '#edeceb', full_text => 'caps', markup => 'pango'}; } else { - push @{$OUTPUT}, { "background" => "#3e78fd", "color" => "#edeceb", border => "#edeceb", "full_text" => "caps", "markup" => "pango"}; + push @{$OUTPUT}, { background => '#3e78fd', color => '#edeceb', border => '#edeceb', full_text => 'caps', markup => 'pango'}; } } if ($CONF->{cpu_temp}) { - push @{$OUTPUT}, { "color" => "#3e78fd", "full_text" => $cputemp }; + push @{$OUTPUT}, { color => '#3e78fd', full_text => $cputemp }; } if ($CONF->{mem}) { - push @{$OUTPUT}, { "color" => "#3e78fd", "full_text" => $meminfo }; + push @{$OUTPUT}, { color => '#3e78fd', full_text => $meminfo }; } if ($CONF->{la}) { - push @{$OUTPUT}, { "color" => "#3e78fd", "full_text" => "LA: $la" }; + push @{$OUTPUT}, { color => '#3e78fd', full_text => "LA: $la" }; } my $vpn_str = 'VPN:'; @@ -148,15 +194,15 @@ sub add_events () { } if ($CONF->{vpn}->{tcp_check}->{enabled} || $CONF->{vpn}->{enabled}) { - push @{$OUTPUT}, { "color" => "#3e78fd", "full_text" => $vpn_str }; + push @{$OUTPUT}, { color => '#3e78fd', full_text => $vpn_str }; } if ($CONF->{battery}) { - push @{$OUTPUT}, { "color" => "#3e78fd", "full_text" => $charge }; + push @{$OUTPUT}, { color => '#3e78fd', full_text => $charge }; } if ($CONF->{clock}) { - push @{$OUTPUT}, { "color" => "#000000", "full_text" => "$wallclock", "markup" => "pango"}; + push @{$OUTPUT}, { color => '#000000', full_text => "$wallclock", markup => 'pango'}; } $output_string = eval { encode_json ($OUTPUT) }; @@ -313,7 +359,7 @@ sub add_events () { open $LAHANDLE, '<', '/proc/loadavg'; } - $la = readline ($LAHANDLE); + $la = readline $LAHANDLE; seek $LAHANDLE, SEEK_SET, 0; $la = (split / /ms, $la, 2)[0]; } @@ -357,14 +403,14 @@ sub add_events () { if (defined $CPUTEMPHANDLE) { if (tell $CPUTEMPHANDLE == -1) { - if (open ($CPUTEMPHANDLE, '<', '/sys/class/hwmon/hwmon0/temp1_input')) { + if (open $CPUTEMPHANDLE, '<', '/sys/class/hwmon/hwmon0/temp1_input') { $hwmon = 1; } else { $hwmon = 0; } } } else { - open ($CPUTEMPHANDLE, '<', '/sys/class/hwmon/hwmon0/temp1_input') or do { + unless (open $CPUTEMPHANDLE, '<', '/sys/class/hwmon/hwmon0/temp1_input') { $hwmon = 0; }; } @@ -379,7 +425,7 @@ sub add_events () { $cputemp = int ($cputemp / 1000); } - $cputemp = sprintf('%s°', $cputemp); + $cputemp = sprintf '%s°', $cputemp; } } }, @@ -444,22 +490,17 @@ sub spawn (@) { # Parent, work done, return return; } elsif ($pid == 0) { - # Child, we need to exec() given prog with args - # it seems that at least vscode creashes if we close stdio handles - close STDOUT; - close STDERR; - close STDIN; -# open STDOUT, '>', '/dev/null'; -# open STDERR, '>', '/dev/null'; -# open STDIN, '<', '/dev/null'; + open STDOUT, '>', '/dev/null'; + open STDERR, '>', '/dev/null'; + open STDIN, '<', '/dev/null'; $pid = fork (); if ($pid) { # Parent # in this place parent quits exit 0; } elsif ($pid == 0) { # Child - my $prg = shift (@args); + my $prg = shift @args; # weird situation, silently quit here :) exit 0 unless (defined $prg); @@ -509,8 +550,12 @@ sub to_hours ($) { } sub readconf () { - my $file = "$ENV{HOME}/.i3/config.json"; - open (my $FH, '<', $file) or die "Unable to open $file: $!\n"; + my $file = "$ENV{HOME}/.i3/config.json"; + + unless (open my $FH, '<', $file) { + die "Unable to open $file: $!\n"; + } + my $len = (stat $file)[7]; my $data; use bytes; @@ -528,9 +573,27 @@ sub readconf () { my $config = eval { JSON::XS->new->utf8->relaxed->decode ($data) }; - if ($@) { + unless ($config) { die "Unable to decode $file: $@\n"; } return $config; } + +sub active_win_borders () { + foreach my $app (@{$CONF->{apps}}) { + unless (defined $app->{border_inactive}) { + $app->{border_inactive} = $app->{border}; + } + + unless (defined $app->{border_active}) { + $app->{border_active} = $app->{border}; + } + + if (defined ($app->{instance}) && defined ($win->{instance}->{$app->{instance}})) { + $app->{border} = $app->{border_active}; + } else { + $app->{border} = $app->{border_inactive}; + } + } +}