Skip to content

Instantly share code, notes, and snippets.

@dru8274
Last active March 10, 2024 23:08
Show Gist options
  • Save dru8274/6c41d796b4728ac502a1 to your computer and use it in GitHub Desktop.
Save dru8274/6c41d796b4728ac502a1 to your computer and use it in GitHub Desktop.
Statusbar for FVWM
A Statusbar for FVWM
====================
My configs for the statusbar seen at the bottom of my screenshot
http://i.imgur.com/RaeCY46.png?1
3 files below :-
1] Lines from my main config that relate to the statusbar. On my laptop, whenever the
volume/brightness are changed, a SendToModule command is sent to the FuBarStats module
to update the volume/brightness in the statusbar.
2] modules/FuBar This file is Read during startup. It contains an FvwmButtons config,
and starts two modules, the Fvwmbuttons module and an fvwmperl module FuBarStats
3] lib/FuBarStats An fvwmperl module that monitors various system info, and continually
updates the FvwmButtons module via SendToModule commands. It is well enough commented, I hope.
Parts of this won't work for you. You will need your own icons within the ImagePath for the statusbar.
And parts of FuBarStats related to volume/brightness may not work on your laptop.
#### MORE INFO ABOUT FVWMPERL MODULES
## Read the hidden fvwmperl manpages
$ fvwm-perllib man index
## A folder full of simple fvwmperl examples
ftp://ftp.fvwm.org/pub/fvwm/devel/sources/tests/perl/
## An excellent fvwmperl module example
http://www.fvwmforums.org/phpBB3/viewtopic.php?f=38&t=3069&hilit=fvwmsleep
#### From my ~/.fvwm/config
## To start the FuBar module
AddToFunc StartFunction I Read modules/FuBar
## Win + S : Hide/Unhide the statusbar
Key S A 4 ToggleFuBar
Key XF86AudioRaiseVolume A A VolumeUp
Key XF86AudioLowerVolume A A VolumeDown
Key XF86MonBrightnessDown A A BrightDown
Key XF86MonBrightnessUp A A BrightUp
DestroyFunc BrightUp
AddToFunc BrightUp
+ I Exec sudo /root/bin/bl_up.sh
+ I Schedule 300 SendToModule FuBarStats show_bright
DestroyFunc BrightDown
AddToFunc BrightDown
+ I Exec sudo /root/bin/bl_down.sh
+ I Schedule 300 SendToModule FuBarStats show_bright
DestroyFunc VolumeUp
AddToFunc VolumeUp
+ I Exec amixer set Master "3%+" -q &>/dev/null
+ I Schedule 300 SendToModule FuBarStats show_volume
DestroyFunc VolumeDown
AddToFunc VolumeDown
+ I Exec amixer set Master "3%-" -q &>/dev/null
+ I Schedule 300 SendToModule FuBarStats show_volume
## vim: syntax=fvwm:
##
## FBBar - a combined system-tray and status-bar.
##
## The statusbar is implemented as an FvwmButtons module. An fvwmperl
## module FuBarStats uses Sys::Statistics::Linux to monitor system info,
## and to keep FuBar updated with the info.
DestroyModuleConfig FuBar: *
*FuBar: Geometry 1366x20
*FuBar: Columns 1366
*FuBar: Rows 20
*FuBar: Padding 0 0
*FuBar: BoxSize fixed
*FuBar: Frame 0
*FuBar: Fore gray65
*FuBar: Back gray9
*FuBar: Font -misc-tamsyn-bold-r-normal--20-145-100-100-c-100-iso8859-1
## DESKTOP 120x
*FuBar: (20x20)
*FuBar: (80x20, id z1, Back gray10, Fore gray60, Title "four")
#*FuBar: (220x20)
*FuBar: (20x20)
## VOLUME 100x
*FuBar: (20x20, Colorset 73, Icon volume.xbm)
*FuBar: (20x20)
*FuBar: (40x20, id q1, Title (Right) "54%")
*FuBar: (35x20)
## BRIGHTNESS 100x
*FuBar: (20x20, Colorset 73, Icon bright.xbm)
*FuBar: (15x20)
*FuBar: (40x20, id q2, Title (Right) "54%")
*FuBar: (35x20)
# 60p = 40p + 20p
## CELCIUS 80x
*FuBar: (20x20, Colorset 73, Icon celcius.xbm)
*FuBar: (15x20)
*FuBar: (40x20, id celsius, Title (Right) "54°")
*FuBar: (30x20)
## NETRX 140x
*FuBar: (30x20, Colorset 73, Icon bar_down.xbm)
*FuBar: (20x20)
*FuBar: (80x20, id z5, Title (Right) "234KB/s")
*FuBar: (30x20)
# 76p = 56p + 20p
## NETTX 140x
*FuBar: (30x20, Colorset 73, Icon bar_up.xbm)
*FuBar: (20x20)
*FuBar: (80x20, id z6, Title (Right) "234KB/s")
*FuBar: (30x20)
## MEMORY 140x
*FuBar: (25x20, Colorset 73, Icon mem.xbm)
*FuBar: (20x20)
*FuBar: (60x20, id z4, Title (Right) "528M")
*FuBar: (35x20)
## CPU 130x
*FuBar: (25x20, Colorset 73, Icon bar_cpu2.xbm)
*FuBar: (20x20)
*FuBar: (40x20, id z2, Title (Right) "99%")
*FuBar: (40x20)
*FuBar: (97x20)
## DATE/TIME 235x
*FuBar: (24x20, Colorset 73, Icon bar_clock3.xbm)
*FuBar: (25x20)
*FuBar: (60x20, id z7, Title (Right) " 3 Jul")
*FuBar: (10x20)
*FuBar: (70x20, id z8, Title (Right) " 15:58:")
*FuBar: (20x20, id z9, Title (Right) "22")
*FuBar: (25x20)
#*FuBar: (1x20, Colorset 74)
## TOTAL 1185x
## PADDING = 1366-1185 = 181
#### FUBAR STYLES
## tamsyn-bold-20 char == 10px * 20px
## Each gohufont-14 char is 8p wide.
Colorset 72 fg gray60, bg gray10
#Colorset 73 fg LightSlateGray, bg Gray20
Colorset 73 fg #5B80A6, bg Gray20
#DestroyStyle FuBar
Style FuBar !Title, !Handles, !Borders,
Style FuBar Sticky, StaysOnTop, WindowListSkip, CirculateSkip, NeverFocus, Layer 7
Style FuBar PositionPlacement 0p 748p, InitialMapCommand Move 0p 748p
UpdateStyles
DestroyFunc ToggleFuBar
AddToFunc ToggleFuBar
+ I Next (CirculateHit, FuBar, Sticky) LowerFuBar
+ I Next (CirculateHit, FuBar, Sticky) Break
+ I Next (CirculateHit, FuBar, !Sticky) RaiseFuBar
DestroyFunc LowerFuBar
AddToFunc LowerFuBar
+ I Move 0p 753p
+ I Schedule 200 Move 0p 758p
+ I Schedule 400 Move 0p 763p
+ I Schedule 600 Move 0p 768p
+ I Schedule 620 ThisWindow WindowStyle !Sticky
DestroyFunc RaiseFuBar
AddToFunc RaiseFuBar
+ I Move 0p 763p
+ I Schedule 200 Move 0p 758p
+ I Schedule 400 Move 0p 753p
+ I Schedule 600 Move 0p 748p
+ I Schedule 620 ThisWindow WindowStyle Sticky
UpdateStyles
KillModule FvwmButtons FuBar
KillModule FuBarStats
Module FvwmButtons FuBar
Module FuBarStats
#!/usr/bin/perl
## Fvwm module to collect system stats, and use them to update
## the various values and fields of the FvwmButtons statusbar.
use strict ;
use warnings ;
use v5.18 ;
use lib `fvwm-perllib dir`;
use FVWM::Module;
use Sys::Statistics::Linux ;
use POSIX ;
#use Data::Dump qw( dump ) ;
## Name of the target FvwmButtons statusbar module.
my $fbmodname = "FuBar" ;
## Seconds duration between each statusbar update.
my $pollinterval = 1 ;
## Count of the total number of updates so far.
my $cnt = 0 ;
## Vars to store date and time.
my $last_hrsmins = my $last_date = "" ;
## To queue up fvwm cmnds before they are sent.
my @cmds = () ;
## Hash ref to store info from the stats module $lxs
my $stats ;
## Desktop number, from the last time it was checked.
my $last_desk = 1 ;
## Text labels associated with each desktop number.
my @desks = (
"zero ", " one ", " two ", "three", "four ",
"five ", " six ", "seven", "eight", "nine ",
) ;
## To gather system info from /proc
my $lxs = Sys::Statistics::Linux->new(
cpustats => 1,
diskstats => 1,
netstats => 1,
) ;
## memstats => 1,
## To send commands to the statusbar via FVWM.
my $module = new FVWM::Module(
Name => 'FuBarStats',
Debug => 0,
);
## Store the name of this fvwmperl module.
my $modname = $module->name ;
## Initialize the stats module.
$lxs->init ;
## Setup alarm for periodic statusbar updates.
$SIG{ALRM} = \&polling ;
## Tracker to detect and update any desktop changes.
my $page_tracker = $module->track("PageInfo") ;
$page_tracker->observe(sub {
my ($module, $tracker, $info) = @_;
update_desk($info->{desk_n}) ;
});
## Handler to intercept SendToModule cmnds sent from FVWM
$module->addHandler(M_STRING, \&process_cmd);
## Start by refreshing all statusbar fields.
update_bar() ;
show_bright() ;
show_volume() ;
update_celsius() ;
## Begin the periodic updates.
alarm($pollinterval) ;
## Continually listen to events from fvwm, except when
## interrupted periodically by alarm.
$module->event_loop ;
#### SUBROUTINES
## To process fvwm events and act upon them. In this case, the events are
## generated by SendToModule cmnds that prompt us to check the values for
## volume/brightness, and display their updated values accordingly.
sub process_cmd {
my ($module, $event) = @_ ;
my ($s) = $event->_text ;
my ($command, $arg) = $s =~ /\s*(\w+)\s*(.*)/ ;
my %cmd = (
show_volume => sub { show_volume() },
show_bright => sub { show_bright() },
) ;
if (defined $cmd{$command}) {
$cmd{$command}() ;
} else {
$module->showMessage("unknown command \"$command\"");
}
}
## Help to set up periodic updates via alarm()
sub polling {
update_bar() if not -e '/tmp/stopfubar' ;
alarm($pollinterval) ;
return ;
}
## The main subroutine is run periodically via alarm() to
## update the various statusbar values and fields.
sub update_bar {
## Refresh the system stats.
$stats = $lxs->get ;
update_datetime() ;
update_cpustats() ;
update_memstats() if $cnt%5 == 0 ;
update_celsius() if $cnt%10 == 0 ;
update_netstats() ;
sendcmds() ;
$cnt++ ;
}
sub update_celsius {
my $celsius = readpipe("cat /sys/devices/virtual/thermal/thermal_zone0/temp") ;
$celsius = rounded($celsius/1000) ;
$celsius .= "°" ;
addcmd("SendToModule $fbmodname ChangeButton celsius Title \"${celsius}\"") ;
}
sub update_datetime {
my ( $sec, $min, $hr, $mday, $mnth, $foo ) = localtime() ;
my @mnths = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ) ;
my $padsec = sprintf "%02d", $sec ;
my $date = "$mday ".$mnths[$mnth] ;
my $hrsmins = sprintf "%02d:%02d:", $hr, $min ;
addcmd("SendToModule $fbmodname ChangeButton z9 Title $padsec") ;
if ($date ne $last_date) {
addcmd("SendToModule $fbmodname ChangeButton z7 Title \"${date}\"") ;
$last_date = $date ;
}
if ($hrsmins ne $last_hrsmins) {
addcmd("SendToModule $fbmodname ChangeButton z8 Title ${hrsmins}") ;
$last_hrsmins = $hrsmins ;
}
}
sub update_cpustats {
## The cpu equation for Sys::Statistics::Linux::CpuStats:
## user + system + iowait = 100 - idle = total
## Here we seek total cpu minus iowait.
my $user = $stats->{cpustats}->{cpu}->{user} ;
my $system = $stats->{cpustats}->{cpu}->{system} ;
my $cpu = rounded($user + $system) ;
$cpu = 99 if $cpu == 100 ;
addcmd("SendToModule $fbmodname ChangeButton z2 Title ${cpu}%") ;
}
## sub update_memstats {
##
## ## After some investigation, it seems that the memory usage
## ## is being over-reported by the Sys::Statistics::Linux::MemStats
## ## module when compared to the free cmnd. So obviously, a
## ## different method of calculating memory usage is being used.
##
## my $total = $stats->{memstats}->{memtotal} ;
## my $realfree = $stats->{memstats}->{realfree} ;
## my $realused = rounded(($total - $realfree)/1024) ;
## addcmd("SendToModule $fbmodname ChangeButton z4 Title ${realused}Mb") ;
## }
sub update_memstats {
## It turns out the stats module over-reports memory usage,
## so I'm using free cmnd instead.
my $used = 0 ;
foreach (`free -m`) {
if (/^Mem:\s+\d+\s+(\d+)\s/) {
$used = $1
}
}
if ($used) {
addcmd("SendToModule $fbmodname ChangeButton z4 Title ${used}Mb")
}
}
sub update_netstats {
## Gather disk read/write stats.
my $rxbyts = my $txbyts = 0 ;
foreach my $netdev (keys %{$stats->{netstats}}) {
next if $netdev eq "lo" ;
$rxbyts += $stats->{netstats}->{$netdev}->{rxbyt} ;
$txbyts += $stats->{netstats}->{$netdev}->{txbyt} ;
} ;
## Reformat rx/tx to use KB/s or MB/s .
my $netrx = $rxbyts < 1048576 ?
sprintf "%4.0fKB/s", $rxbyts/1024 :
sprintf "%4.1fMB/s", $rxbyts/1048576 ;
my $nettx = $txbyts < 1048576 ?
sprintf "%4.0fKB/s", $txbyts/1024 :
sprintf "%4.1fMB/s", $txbyts/1048576 ;
addcmd("SendToModule $fbmodname ChangeButton z5 Title ${netrx}") ;
addcmd("SendToModule $fbmodname ChangeButton z6 Title ${nettx}") ;
}
sub update_desk {
my $curr_desk = shift ;
return 0 if $curr_desk == $last_desk ;
my $desk = $desks[$curr_desk] ;
$last_desk = $curr_desk ;
addcmd("SendToModule $fbmodname ChangeButton z1 Title \"${desk}\"") ;
sendcmds() ;
}
sub show_bright {
my $bright_max = 255 ;
my $bl_device="/sys/class/backlight/radeon_bl0/brightness" ;
my $actual = `cat $bl_device` ;
chomp $actual ;
my $bright = ceiling($actual, $bright_max) ;
addcmd("SendToModule $fbmodname ChangeButton q2 Title ${bright}%") ;
sendcmds() ;
}
sub show_volume {
foreach my $x (`amixer scontents` ) {
if ($x =~ /^\s+Mono:\s+Playback.+\[(\d\d?\d?)%\].+$/) {
my $vol = $1 < 100 ? $1 : 99 ;
addcmd("SendToModule $fbmodname ChangeButton q1 Title ${vol}%") ;
sendcmds() ;
}
}
}
sub ceiling {
my ($num, $max) = @_ ;
$num = 0 unless defined $num ;
$num = $num > $max ? $max : $num ;
$num = nearest(1, $num*100/$max) ;
return $num < 100 ? $num : 99 ;
}
## Cribbed from Math::Round
sub nearest {
my $targ = abs(shift);
my $half = 0.50000000000008 ;
my @res = map {
if ($_ >= 0) { $targ * int(($_ + $half * $targ) / $targ); }
else { $targ * POSIX::ceil(($_ - $half * $targ) / $targ); }
} @_ ;
return (wantarray) ? @res : $res[0] ;
}
## Cribbed from Math::Round
sub rounded {
my $x;
my $half = 0.50000000000008 ;
my @res = map {
if ($_ >= 0) { POSIX::floor($_ + $half); }
else { POSIX::ceil($_ - $half); }
} @_;
return (wantarray) ? @res : $res[0];
}
## Two subroutines that add/store and send fvwm cmnds.
sub addcmd { push @cmds, $_[0] } ;
sub sendcmds {
foreach (@cmds) { $module->send($_) } ;
@cmds = () ;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment