I was following this topic but just recently had the time to do my own version.
I hacked watcher again (thanks Curaga) so it reads /tmp/watcher2msg and displays the contents of that file instead if its not empty. any app should be able to take advantage of this. I also renamed to watcher2 and put it in /usr/local/bin.
echo "testing" >/tmp/watcher2msg
displays "testing" instead of the normal watcher stuff
echo "" >/tmp/watcher2msg
clears that and goes back to the normal watcher stuff.
Watch out for the bug in this, if /tmp/watcher2msg does not exist there will be many error messages to stderr.
// Copyright 2008 Curaga
// A small app to be swallowed into JWM tray, to show cpu,mem,swap usage
// What do you know, mixing C with fltk C++ works just fine
// Licensed under the GPLv2, as scanf did not work for me, so
// I benefited from Open Source and copied the fgets block from
// wmbluemem :)
// Thank You Mihai Dr\ufffdghicioiu
// Changes from Softwaregurl:
// Moved letters after the values with percentages
// Gigabytes for swap and mem
// May 2009
// Reads a file and displays instead if not empty
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/filename.H>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char version[4]="1.5";
float timeout=1.5,mem=0,swap=0,cpu=0,used=0,oldused=0,cputotal=0,oldcputotal=0;
int arg_i=0, fontsize=10, mib=0;
char memind[2]="m",swapind[2]="m",newmsg[25];
FILE *meminfo,*cpuinfo,*msg;
void checkup(){
unsigned long memtotal,memfree,buffers,cache,swaptotal,swapfree;
unsigned long user,nice,sys,idle,iowait,irq,softirq,virt,virt2;
char buf[60],buf2[190];
char *p;
int i;
if((meminfo=fopen("/proc/meminfo","r"))==NULL){
fprintf(stderr,"Error opening meminfo");
exit(1);
}
if((cpuinfo=fopen("/proc/stat","r"))==NULL){
fprintf(stderr,"Error opening stat");
exit(1);
}
if((msg=fopen("/tmp/watcher2msg","r"))==NULL){
fprintf(stderr,"Error opening msg");
} else {
fgets(newmsg, 25, msg);
fclose(msg);
}
fgets(buf, 60, meminfo); strtok(buf, " "); p = strtok(NULL, " ");
memtotal = strtol(p, NULL, 10);
fgets(buf, 60, meminfo); strtok(buf, " "); p = strtok(NULL, " ");
memfree = strtol(p, NULL, 10);
fgets(buf, 60, meminfo); strtok(buf, " "); p = strtok(NULL, " ");
buffers = strtol(p, NULL, 10);
fgets(buf, 60, meminfo); strtok(buf, " "); p = strtok(NULL, " ");
cache = strtol(p, NULL, 10);
for(i = 1; i < 11; i++){
fgets(buf, 60, meminfo);
p=strtok(buf, " ");
if(strcmp("SwapTotal:",p)==0) break;
}
p = strtok(NULL, " ");
swaptotal = strtol(p, NULL, 10);
fgets(buf, 60, meminfo); strtok(buf, " "); p = strtok(NULL, " ");
swapfree = strtol(p, NULL, 10);
fclose(meminfo);
fgets(buf2,190,cpuinfo); strtok(buf2, " ");
p=strtok(NULL, " "); user=strtol(p, NULL, 10);
p=strtok(NULL, " "); nice=strtol(p, NULL, 10);
p=strtok(NULL, " "); sys=strtol(p, NULL, 10);
p=strtok(NULL, " "); idle=strtol(p, NULL, 10);
p=strtok(NULL, " "); iowait=strtol(p, NULL, 10);
p=strtok(NULL, " "); irq=strtol(p, NULL, 10);
p=strtok(NULL, " "); softirq=strtol(p, NULL,10);
p=strtok(NULL, " "); virt=strtol(p, NULL, 10);
p=strtok(NULL, " "); virt2=strtol(p, NULL, 10);
fclose(cpuinfo);
used=(float)(user+nice+sys+irq+softirq+virt+virt2);
cputotal=used+(float)idle+(float)iowait;
cpu=((used-oldused)/(cputotal-oldcputotal))*(float)100;
if(mib==1){
mem=(float)(memtotal-(memfree+buffers+cache))/(float)1024;
swap=(float)(swaptotal-swapfree)/(float)1024;
}
if(mib==2){
mem=(float)(memfree+buffers+cache)/(float)1024;
swap=(float)swapfree/(float)1024;
}
if(mib==0){
mem=((float)(memtotal-(memfree+buffers+cache))/ (float) memtotal)*(float)100;
swap=((float)(swaptotal-swapfree)/(float)swaptotal)*(float)100;
}
oldused=used;
oldcputotal=cputotal;
if(mem>999.9){
mem=mem/1024;
strcpy(memind,"g");
}
if(swap>999.9){
swap=swap/1024;
strcpy(swapind,"g");
}
if(swaptotal==0){
swap=0;
}
}
void tick(void* v){
checkup();
Fl_Box* box=(Fl_Box*)v;
char yeah[25]="";
if(mib) sprintf(yeah,"C%.1f%% M%.1f%s S%.1f%s",cpu,mem,memind,swap,swapind);
else sprintf(yeah,"%.1f%%C %.1f%%M %.1f%%S",cpu,mem,swap);
if ( strlen (newmsg) > 1) box->copy_label(newmsg);
else box->copy_label(yeah);
Fl::repeat_timeout(timeout,tick,box);
}
int parser(int argc, char **argv, int &z){
if(strcmp(argv[z], "-h")==0){
printf("Watcher %s\n" \
"(C) Curaga 2008\n" \
"Fixes from softwaregurl\n\n" \
"Switches: \n" \
"\t-bg <color> background color \n" \
"\t-fg <color> text color\n" \
"\t-m show used MiB instead of percent on mem/swap\n" \
"\t-r show remaining MiB instead of percent on mem/swap\n" \
"\t-s <float> check every s secs, default %.2f\n" \
"\t-f <size> use font size f (default %d)\n" \
"The color can be either named (green) or rgb ('#00ff00')\n",version,
timeout,fontsize);
exit(0);
}
if(strcmp(argv[z], "-s")==0){
timeout=strtof(argv[(z+1)],NULL);
z+=2;
return 1;
}
if(strcmp(argv[z], "-f")==0){
fontsize=atoi(argv[(z+1)]);
z+=2;
return 1;
}
if(strcmp(argv[z], "-m")==0){
mib=1;
z++;
return 1;
}
if(strcmp(argv[z], "-r")==0){
mib=2;
z++;
return 1;
}
return 0;
}
int main(int argc, char **argv) {
// Graphic stuff
Fl_Window *window = new Fl_Window(124,18);
Fl::args(argc,argv,arg_i,&parser);
Fl_Box *box = new Fl_Box(FL_NO_BOX,0,0,124,18,"Starting...");
box->labelsize(fontsize);
window->end();
window->show(argc, argv);
Fl::add_timeout(timeout,tick,box);
return Fl::run();
}
then this is what I wrote#!/usr/bin/perl
# adjvolume.pl adjusts volume by reading from a fifo
# Copyright 2009 Softwaregurl
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#### set volume up-down commands $$$$
# ????? (yes, five question marks) indicates where to insert the channel name/number.
$cmds{'vup'}="amixer set ????? 2%+";
$cmds{'vdn'}="amixer set ????? 2%-";
#### set controls display & names/numbers $$$$
# list of control names to display
@cnmd = ('Master',
'PCM',
'Line In'
);
# list of control names/numbers corresponding to above
@ctnn = ('Master',
'PCM',
'Line'
);
print "commands\n";
sub adjvolume {
$syscmd="$cmds{$cmd} >/dev/null";
$syscmd=~ s|\?\?\?\?\?|$ctnn[$ctlnn]|g;
$err = system ("$syscmd >/tmp/adjvolumedata");
if ($err) { print "$err bad volume command $syscmd\n";}
undef ($err);
&rdadjvolumedata;
&printout;
}
sub rdadjvolumedata {
open (vol1, "/tmp/adjvolumedata") || &error0recover;
@adjvolumedata0=<vol1>;
close (vol1);
$adjvolumedata1=@adjvolumedata0;
$adjvolumedata1--;
$adjvolumedata2="$adjvolumedata0[$adjvolumedata1]";
chomp ($adjvolumedata2);
$adjvolumedata2 =~ s/[^0-9]+/ /g;
chop ($adjvolumedata2);
$adjvolumedata2 = "$adjvolumedata2\%";
$adjvolumedata1--;
$adjvolumedata3="$adjvolumedata0[$adjvolumedata1]";
chomp ($adjvolumedata3);
$adjvolumedata3 =~ s/[^0-9]+/ /g;
$adjvolumedata3 = "$adjvolumedata2";
$adjvolumedata2="$adjvolumedata2 $adjvolumedata3";
}
sub changec {
$ctlnn++;
if ($ctlnn >= $ncnmd) { $ctlnn=0;}
&printout;
}
sub proccmd {
if ($cmd eq "vup" || $cmd eq "vdn") { &adjvolume;}
if ($cmd eq "cdn") { &changec;}
}
sub printout {
print "$cnmd[$ctlnn], $adjvolumedata2\n";
$tmp0="echo \"$cnmd[$ctlnn], $adjvolumedata2\" >/tmp/watcher2msg";
system ($tmp0);
}
sub error0recover {
exit;
}
sub rddata {
for ($j=0;$j<9;$j=1) {
$cmd=<vol0>;
chomp ($cmd);
&proccmd;
if ($cmd eq "" ) {
sleep 2;
$nulltime++;
if ($nulltime > 4) {
$tmp0="echo \"\" >/tmp/watcher2msg";
system ($tmp0);
$nulltime=0;
}
}
}
}
$ncnmd=@cnmd;
open (vol0, "/tmp/adjvolumefifo") || &error0recover;
&rddata;
print "exiting\n";
exit;
it reads commands from /tmp/adjvolumefifo and sends output to /tmp/watcher2msg then clears it about 10 seconds later as well as writing to the terminal. anything can send commands to it via the fifo.
and this is my .jwmrc-tray<JWM>
<!-- Additional tray attributes: autohide, width, border, layer, layout -->
<Tray x="0" y="0" height="20">
<!-- Additional TaskList attribute: maxwidth -->
<TaskList/>
<!-- Additional TrayButton attribute: label -->
<TrayButton label="_">showdesktop</TrayButton>
<TrayButton label="^">exec:echo "vup" >>/tmp/adjvolumefifo </TrayButton>
<TrayButton label="v">exec:echo "vdn" >>/tmp/adjvolumefifo </TrayButton>
<TrayButton label="C">exec:echo "cdn" >>/tmp/adjvolumefifo </TrayButton>
<TrayButton label="S">exec:echo "sel" >>/tmp/adjvolumefifo </TrayButton>
<!-- Additional Pager attributes; width, height -->
<Pager/>
<!-- Additional Swallow attribute: height -->
<Swallow name="watcher2" width="0"> watcher2 </Swallow>
<Clock format="%a %d %b %k:%M"></Clock>
<Dock/>
<TrayButton label="X">exec:exittc</TrayButton>
</Tray>
</JWM>
the "S" is for future use. it needs a fifo named /tmp/adjvolumefifomkfifo /tmp/adjvolumefifo
I was backgrounding it in a terminal so I could see which control i'm on. now I just do/usr/local/mediaswg/bin/adjvolume.pl >/dev/null &
to use it, C changes channel and the ^ and v adjust the level. Set the first four variables for your card. Output works with alsa and fits in watcher.
this requires perl5 and[ -e /usr/bin/perl ] || sudo ln -s /usr/local/bin/perl /usr/bin/perl
still a few bugs to work out and more features I want but so far it works.