Compare commits
10 Commits
9851c59f48
...
1f4e242253
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f4e242253 | ||
|
|
91cf117ee8 | ||
|
|
371dc68667 | ||
|
|
08bf20d43a | ||
|
|
24b7a97372 | ||
|
|
c634ca1f40 | ||
|
|
fba1d3dc5d | ||
|
|
f63dba554c | ||
|
|
ab68a26e84 | ||
|
|
b801bf0a76 |
@@ -17,15 +17,15 @@
|
||||
* Температуру процессора (одно ядро, указывается файл-источник сведений)
|
||||
* Состояние клавиши CapsLock
|
||||
* Состояние одного интерфейса VPN (+ tcp health check, т.к. ovpn, например, умеет "залипать")
|
||||
* Уровень звука согласно pulse audio для default sink (придумывать "крутилочку" для звука я не стал, ибо там не всё так просто и "в процессе" fun скорее всего пропадёт.). Предполагается, что звук правляется через что-то ещё, например, через какой-нибудь pasystray, например.
|
||||
* Уровень звука согласно pulse audio для default sink (придумывать "крутилочку" для звука я не стал, ибо там не всё так просто и "в процессе" fun скорее всего пропадёт.). Предполагается, что звук управляется через что-то ещё, например, через какой-нибудь pasystray, например.
|
||||
* Состояние (up|down) любого набора существующих сетевых интерфейсов. Но каждый надо описать. IP не показываются, т.к. это сжирает место на панели, а его не так-то и много.
|
||||
* "Кнопки" для запуска произвольных приложений. Собственно, ради этого всё и затевалось :)
|
||||
* "Трекать" запуск приложенй "с кнопки" и подсвечивать соответствующую "кнопку". Работает через ивенты от самого i3: на появление и на исчезновения окна с рядом свойств.
|
||||
* "Трекать" запуск приложений "с кнопки" и подсвечивать соответствующую "кнопку". Работает через ивенты от самого i3: на появление и на исчезновения окна с рядом свойств.
|
||||
* Cron! Как ни забавно это звучит, но, да. И нужен он для показывания desktop notifications, ибо системный cron не прокидывает в environment переменную с текущим dbus session. Но в этот крон можно пихнуть что угодно.
|
||||
|
||||
## Как это заставить работать
|
||||
|
||||
Скрипт на perl-е, и чтобы заставить его работать нужен, собственно, сам perl, [cpanm][2], [carton][3], [cpm][4] или что-то ещё для управления перловыми модулями, а также крайне желательно наличие в системе библиотеки [lib::local][5].
|
||||
Скрипт на perl-е, и, чтобы заставить его работать, нужен, собственно, сам perl, [cpanm][2], [carton][3], [cpm][4] или что-то ещё для управления перловыми модулями, а также крайне желательно наличие в системе библиотеки [lib::local][5].
|
||||
|
||||
При запуске необходимо убедиться, что переменная [PERL5LIB][6] установлена корректно.
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ use utf8;
|
||||
use open qw (:std :utf8);
|
||||
use Fcntl qw (:seek);
|
||||
use AnyEvent;
|
||||
use AnyEvent::Timer::Cron;
|
||||
use AnyEvent::I3;
|
||||
use JSON::XS;
|
||||
use Encode;
|
||||
@@ -36,10 +35,19 @@ sub readconf ();
|
||||
sub active_win_borders ();
|
||||
|
||||
my $CONF = readconf ();
|
||||
|
||||
# load AnyEvent::Timer::Cron only if cron enabled in config
|
||||
if ($CONF->{'cron'}->{enabled}) {
|
||||
require AnyEvent::Timer::Cron;
|
||||
}
|
||||
|
||||
my $i3 = i3 ();
|
||||
my $done = AnyEvent->condvar;
|
||||
$i3->connect->recv or die 'Unable to connect to i3';
|
||||
|
||||
# Local Time Counter
|
||||
my $TC = time();
|
||||
|
||||
# event pool
|
||||
my @EP;
|
||||
|
||||
@@ -81,6 +89,8 @@ unless (-f $BATTERY_CHARGE_FULL_FILE) {
|
||||
}
|
||||
|
||||
my $CAPS_LED_PATH = find_caps_led ();
|
||||
my $CAPS_LED_SKIPS = 0;
|
||||
my $CAPS_LED_SKIPS_MAX = 180;
|
||||
|
||||
# opened windows info storage ref
|
||||
my $win;
|
||||
@@ -143,13 +153,6 @@ sub add_events () {
|
||||
}
|
||||
|
||||
# Register callbacks/event handlers
|
||||
push @EP, AnyEvent->timer (
|
||||
after => 1,
|
||||
interval => 120,
|
||||
cb => sub {
|
||||
AnyEvent->now_update;
|
||||
},
|
||||
);
|
||||
|
||||
# Actually print messages there
|
||||
push @EP, AnyEvent->timer (
|
||||
@@ -277,6 +280,7 @@ sub add_events () {
|
||||
cb => sub { # the callback to invoke
|
||||
my $caps_state = 0;
|
||||
my $CAPSHANDLE;
|
||||
my $xsetflag = 0;
|
||||
|
||||
if (defined $CAPS_LED_PATH) {
|
||||
unless (open $CAPSHANDLE, '<', $CAPS_LED_PATH) {
|
||||
@@ -284,13 +288,39 @@ sub add_events () {
|
||||
$caps_state = 2
|
||||
}
|
||||
} else {
|
||||
$caps_state = 2;
|
||||
# we can use "$ xset q | grep Caps" as fallback, but it is notably more expensive check
|
||||
my $xset = `xset q`;
|
||||
$xsetflag = 1;
|
||||
|
||||
if ($?) {
|
||||
# some kind of error, so we assume that we cannot update caps lock status
|
||||
$caps_state = 2;
|
||||
} else {
|
||||
$xset =~ /Caps Lock\:\s+(o[n|f]f?)\s+/;
|
||||
|
||||
if ($1 eq 'off') {
|
||||
$caps_state = 0;
|
||||
} elsif ($1 eq 'on') {
|
||||
$caps_state = 1;
|
||||
} else {
|
||||
$caps_state = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if ($CAPS_LED_SKIPS == $CAPS_LED_SKIPS_MAX) {
|
||||
$CAPS_LED_SKIPS = 0;
|
||||
$CAPS_LED_PATH = find_caps_led ();
|
||||
} else {
|
||||
$CAPS_LED_SKIPS++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($caps_state ne '2') {
|
||||
$caps_state = readline $CAPSHANDLE;
|
||||
close $CAPSHANDLE;
|
||||
chomp $caps_state;
|
||||
unless ($xsetflag) {
|
||||
$caps_state = readline $CAPSHANDLE;
|
||||
close $CAPSHANDLE;
|
||||
chomp $caps_state;
|
||||
}
|
||||
|
||||
if (! defined $O->{capslock}->{state}) {
|
||||
$O->{capslock}->{border} = $CONF->{capslock}->{background};
|
||||
@@ -374,8 +404,7 @@ sub add_events () {
|
||||
|
||||
while ($str = pop (@up)) {
|
||||
if (substr ($str, 4, 10) eq 'percentage') {
|
||||
$percentage = substr $str, 25;
|
||||
chomp $percentage;
|
||||
$percentage = substr $str, 25, -1; # chop % symbol ath the end of the string
|
||||
} elsif (substr ($str, 4, 5) eq 'state') {
|
||||
if (substr ($str, 25, 11) eq 'discharging') {
|
||||
$state = '▼';
|
||||
@@ -395,6 +424,18 @@ sub add_events () {
|
||||
return;
|
||||
}
|
||||
|
||||
my $color = '<span foreground="Blue">';
|
||||
|
||||
if ($percentage > 85) {
|
||||
$color = '<span foreground="LimeGreen">';
|
||||
} elsif ($percentage < 25 && $percentage > 15) {
|
||||
$color = '<span foreground="Goldenrod">';
|
||||
} elsif ($percentage <= 15 && $percentage > 11) {
|
||||
$color = '<span foreground="DarkOrange">';
|
||||
} elsif ($percentage <= 11) {
|
||||
$color = '<span foreground="Red">';
|
||||
}
|
||||
|
||||
if (defined $time_to) {
|
||||
chomp $time_to;
|
||||
|
||||
@@ -413,7 +454,7 @@ sub add_events () {
|
||||
$time_to = '00:00';
|
||||
}
|
||||
|
||||
my $charge = sprintf '<big>⚡</big> %s %s %s', $percentage, $state, $time_to;
|
||||
my $charge = sprintf '<b><big><span foreground="Goldenrod">⚡</span></big></b> %s%s%%</span> %s %s', $color, $percentage, $state, $time_to;
|
||||
|
||||
if (! defined $O->{battery}->{'full_text'}) {
|
||||
$O->{battery}->{'full_text'} = $charge;
|
||||
@@ -491,19 +532,19 @@ sub add_events () {
|
||||
}
|
||||
|
||||
my $capacity = int (100 * ($current_charge / $charge_max));
|
||||
my $color = '<span foreground="blue">';
|
||||
my $color = '<span foreground="Blue">';
|
||||
|
||||
if ($capacity > 85) {
|
||||
$color = '<span foreground="green">';
|
||||
$color = '<span foreground="LimeGreen">';
|
||||
} elsif ($capacity < 25 && $capacity > 15) {
|
||||
$color = '<span foreground="yellow">';
|
||||
$color = '<span foreground="Goldenrod">';
|
||||
} elsif ($capacity <= 15 && $capacity > 11) {
|
||||
$color = '<span foreground="orange">';
|
||||
$color = '<span foreground="DarkOrange">';
|
||||
} elsif ($capacity <= 11) {
|
||||
$color = '<span foreground="red">';
|
||||
$color = '<span foreground="Red">';
|
||||
}
|
||||
|
||||
my $charge = sprintf '<b><big><span foreground="yellow">⚡</span></big></b> %s%s%%</span> %s', $color, $capacity, $state;
|
||||
my $charge = sprintf '<b><big><span foreground="Goldenrod">⚡</span></big></b> %s%s%%</span> %s', $color, $capacity, $state;
|
||||
|
||||
if ($O->{battery}->{'full_text'} ne $charge) {
|
||||
$O->{battery}->{'full_text'} = $charge;
|
||||
@@ -617,15 +658,15 @@ sub add_events () {
|
||||
|
||||
if (defined $mtime) {
|
||||
if ((time () - $mtime) < $CONF->{vpn}->{mtime_threshold}) {
|
||||
$vpnstr .= '⍋';
|
||||
$vpnstr .= sprintf '<span foreground="%s">⍋</span>', $CONF->{vpn}->{up_color};
|
||||
} else {
|
||||
$vpnstr .= '⍒';
|
||||
$vpnstr .= sprintf '<span foreground="%s">⍒</span>', $CONF->{vpn}->{down_color};
|
||||
}
|
||||
|
||||
$file_check_mtime = $mtime;
|
||||
} else {
|
||||
$mtime = 0;
|
||||
$vpnstr .= '⍒';
|
||||
$vpnstr .= sprintf '<span foreground="%s">⍒</span>', $CONF->{vpn}->{down_color};
|
||||
}
|
||||
|
||||
# Try to tcp connect to server in vpn network
|
||||
@@ -644,13 +685,14 @@ sub add_events () {
|
||||
) {
|
||||
$sock->shutdown (SHUT_WR);
|
||||
$sock->close ();
|
||||
$vpnstr .= '✔';
|
||||
$vpnstr .= sprintf '<span foreground="%s">✔</span>', $CONF->{vpn}->{up_color};
|
||||
} else {
|
||||
$vpnstr .= '✘';
|
||||
$vpnstr .= sprintf '<span foreground="%s">✘</span>', $CONF->{vpn}->{down_color};
|
||||
}
|
||||
}
|
||||
|
||||
if (! defined $O->{vpn}->{'full_text'}) {
|
||||
$O->{vpn}->{'markup'} = 'pango';
|
||||
$O->{vpn}->{'full_text'} = $vpnstr;
|
||||
$O->{vpn}->{'color'} = '#3e78fd';
|
||||
$UPDATE = 1;
|
||||
@@ -663,7 +705,7 @@ sub add_events () {
|
||||
}
|
||||
|
||||
# poll pulseaudio volume on first sink in list
|
||||
if ($CONF->{'simple-volume-pa'}) {
|
||||
if ($CONF->{'simple-volume-pa'}->{enabled}) {
|
||||
push @EP, AnyEvent->timer (
|
||||
after => 0, # first invoke ASAP
|
||||
interval => 1, # then invoke every 1 second
|
||||
@@ -677,12 +719,15 @@ sub add_events () {
|
||||
|
||||
foreach my $str (split /\n/, $pactl) {
|
||||
if ($str =~ /^\s+Volume\:\s+[a-z|A-Z\\-]+\:\s+\d+\s+\/\s+(\d+)% /xms ) {
|
||||
my $volumestr = sprintf '<big>%s</big> %s%%', $CONF->{'simple-volume-pa'}->{symbol}, $1;
|
||||
|
||||
if (! defined $O->{'simple-volume-pa'}->{'full_text'}) {
|
||||
$O->{'simple-volume-pa'}->{'full_text'} = $1;
|
||||
$O->{'simple-volume-pa'}->{'full_text'} = $volumestr;
|
||||
$O->{'simple-volume-pa'}->{'color'} = '#3e78fd';
|
||||
$O->{'simple-volume-pa'}->{'markup'} = 'pango';
|
||||
$UPDATE = 1;
|
||||
} elsif ($O->{'simple-volume-pa'}->{'full_text'} ne $1) {
|
||||
$O->{'simple-volume-pa'}->{'full_text'} = $1;
|
||||
} elsif ($O->{'simple-volume-pa'}->{'full_text'} ne $volumestr) {
|
||||
$O->{'simple-volume-pa'}->{'full_text'} = $volumestr;
|
||||
$UPDATE = 1;
|
||||
}
|
||||
|
||||
@@ -746,6 +791,20 @@ sub add_events () {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
# also we need workaround for timers after sleep or hibernate
|
||||
push @EP, AnyEvent->timer (
|
||||
after => 60, # first invoke after 1 minute
|
||||
interval => 60, # then invoke every 1 second
|
||||
cb => sub { # the callback to invoke
|
||||
$TC = $TC + 60;
|
||||
my $timeskew = $TC - time ();
|
||||
|
||||
if (($timeskew > 60) || ($timeskew < -60)) {
|
||||
kill 'HUP', $$;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -760,7 +819,7 @@ sub spawn (@) {
|
||||
return;
|
||||
} elsif ($pid == 0) { # Child
|
||||
setsid ();
|
||||
# it seems that at least vscode creashes if we close stdio handles
|
||||
# it seems that at least vscode crashes if we close stdio handles
|
||||
open STDOUT, '>', '/dev/null'; ## no critic (InputOutput::RequireCheckedOpen)
|
||||
open STDERR, '>', '/dev/null'; ## no critic (InputOutput::RequireCheckedOpen)
|
||||
open STDIN, '<', '/dev/null'; ## no critic (InputOutput::RequireCheckedOpen)
|
||||
|
||||
@@ -53,6 +53,9 @@
|
||||
# state file and update its timestamp at least as frequent as mtime_threshold in seconds
|
||||
"vpn": {
|
||||
"enabled": 0,
|
||||
# html (actually, pango) notation
|
||||
"down_color" : "red",
|
||||
"up_color" : "green",
|
||||
"statusfile" : "/tmp/openvpn-status.stat",
|
||||
"mtime_threshold": 10,
|
||||
# Also we can tcp-ping some service inside vpn network to ensure that connection is not stoned
|
||||
@@ -67,7 +70,10 @@
|
||||
# Simplified volume indicator
|
||||
# it periodically polls pulseaudio via "pactl list sinks" command
|
||||
# so it's not light on system resources as i'd like
|
||||
"simple-volume-pa": 0,
|
||||
"simple-volume-pa": {
|
||||
"enabled": 0,
|
||||
"symbol": "🎶"
|
||||
},
|
||||
|
||||
"net-if" : {
|
||||
"enabled" : 0,
|
||||
|
||||
Reference in New Issue
Block a user