Skip to content

Commit

Permalink
Status: add example scripts
Browse files Browse the repository at this point in the history
This adds example scripts for processing the JSON output from Fvwm3.

Fixes fvwmorg#253
  • Loading branch information
ThomasAdam authored and mikeandmore committed Nov 28, 2020
1 parent 1b55c02 commit 9597928
Show file tree
Hide file tree
Showing 4 changed files with 250 additions and 0 deletions.
29 changes: 29 additions & 0 deletions contrib/status/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
Scripts
=======

In this directory are a few files:

`.`:

* panel -- a wrapper sh script which chains together a perl script and
lemonbar, so that a panel can be formed. Has a crude understanding of job
control so that only one instance can be started at any one time. It will
also start conky.

* read_status.pl -- listens on any defined FIFOs from `fvwm3`, and parses the
JSON information sent down them. It formats the information into
something which `lemonbar` can understand. It will also send the conky output
to `lemonbar`.

* conkyrc -- example RC file for use with conky.

`./config`
* Example config(s)

In order to support RandR correctly, a forked version of Lemonbar is needed.
The version lives on the `ta/keep-output-monitor` see:

https://github.com/ThomasAdam/bar/tree/ta/keep-output-monitor

Compiling this should replace any othe version of `lemonbar` which might be in
use.
22 changes: 22 additions & 0 deletions contrib/status/conkyrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
conky.config = {
out_to_x = false,
out_to_console = true,
background = false,
update_interval = 60,
total_run_times = 0,
use_spacer = 'none',
default_color = 'ffaf5f',
draw_graph_borders = true,
short_units = true,
use_spacer = 'left',
pad_percents = 1
}

conky.text = [[
clock:%{r}%{B-}%{U\#00FFFF}%{+u}%{+o} \
%{r}%{B-}%{U\#00FFFF}%{+u}%{+o} \
%{B\#4ECC4E}[CPU: ${cpu cpu0 11,12}]%{B-} \
%{B\#66B2FF}[MEM: ${mem}]%{B-} \
%{B\#D68C5A}[AVG: ${loadavg 1}]%{B-} \
%{B\#BF4356}[${time %b %d %H:%M:%S}]%{B-}%{-u}%{-o} \
]]
31 changes: 31 additions & 0 deletions contrib/status/panel
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/bash

pfile=${TMPDIR:-/tmp}/fvwm3-panel.pid

[ -f $pfile ] && kill -0 $(<$pfile) && {
echo "Already running..."
pkill -P $(<$pfile)
}

echo $$ > $pfile

pipe="$FVWM_STATUS_PIPE"

# Ascertain the DPI value. Anything over 100 is assumed to be on a HiDPI
# display, and as such, XFT fonts, and higher font sizes are used.
this_dpi=$(xdpyinfo | \
perl -wane '/resolution:\s+(?:(\d+)x(?:\d+))/ and print $1;')

# Assume we last started conky. Probably not ideal; we could go down the
# route of tracking the PID if it's a problem.
pkill conky
(conky -d > "$pipe" &)

font_opts=""
geom_opts="x16"
[ $this_dpi -gt 100 ] && {
font_opts="-f 'Book:pixelsize=25'"
geom_opts="x25"
}

~/read_status.pl | lemonbar -g $geom_opts $font_opts -p -d -B'#0000FF' -u2
168 changes: 168 additions & 0 deletions contrib/status/read_status.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#!/usr/bin/env perl
#
# A very crude example how to turn status output from CWM in to something
# that can be interpreted by lemonbar.
#
# https://github.com/LemonBoy/bar
#
# Patches improving this script is welcome; I threw it together in about
# fifteen minutes, there's no support for SIGPIPE or anything like that yet.
#
# -- Thomas Adam

use strict;
use warnings;

use JSON::XS;
use IO::Select;

use Data::Dumper;

$| = 1;
binmode STDOUT, ':encoding(UTF-8)';

my $pipe = $ENV{'FVWM_STATUS_PIPE'};
# If there are no pipes, that's OK.
unless (-e $pipe) {
warn "No pipe found ($pipe) - exiting.\n";
exit;
}

my %scr_map;
my $last_clock_line = '';
my %reply_map;

sub query_xrandr
{
my %lb = (
'global_monitor' => {
screen => '',
data => undef,
}
);

open(my $fh, '-|', 'xrandr -q') or die $!;
while (my $line = <$fh>) {
if ($line =~ /(.*?)\s+connected|connected primary\s*(\d+x\d+\d+\+\d+)\s+/) {
my $output = $1;
$lb{$output} = {
screen => $output,
}
}
}
close($fh);

return (\%lb);
}

sub format_output
{
my ($data) = @_;
my $skip_all_but_global = 0;

if (exists $data->{'screens'}->{'global_monitor'} and
(exists $scr_map{'global_monitor'} and scalar keys %scr_map >= 1)) {

delete $data->{'screens'}->{'global_monitor'};
$scr_map{'global_monitor'}->{'screen'} = 0;
}

foreach my $screen (keys %{ $data->{'screens'} }) {
my $extra_msg = '';
my $extra_urgent = '';
my $msg = "%{Sn$screen}";

my $scr_h = $data->{'screens'}->{$screen};

# For the list of desktops, we maintain the sort order based on the
# group names being 0 -> 9.
foreach my $deskname (
sort {
$scr_h->{'desktops'}->{$a}->{'number'} <=>
$scr_h->{'desktops'}->{$b}->{'number'}
} keys %{$scr_h->{'desktops'}})
{
my $desk_name = $scr_h->{'desktops'}->{$deskname};
my $sym_name = $desk_name->{'number'};
my $is_current = $desk_name->{'is_current'};
my $desk_count = $desk_name->{'number_of_clients'};
my $is_urgent = $desk_name->{'is_urgent'} ||= 0;
my $is_active = $desk_name->{'is_active'} ||= 0;

# If the window is active, give it a differnet colour.
if ($is_current) {
$msg .= "|%{B#39c488} $sym_name %{B-}";

$extra_msg .= "%{B#D7C72F}[Scr:$screen][A:$desk_count]%{B-}";
# Gather any other bits of information for the _CURRENT_
# group we might want.
if ($is_urgent) {
$extra_urgent = "%{B#FF0000}[U]%{B-}";
}
} else {
if ($is_urgent) {
$msg .= "|%{B#b82e2e} $sym_name %{B-}";
} elsif ($is_active) {
$msg .= "|%{B#007FFF} $sym_name %{B-}";

# If the deskname is in the active desktops lists then
# mark it as being viewed in addition to the currently
# active group.
} elsif ($desk_count > 0) {
# Highlight groups with clients on them.
$msg .= "|%{B#004C98} $sym_name %{B-}";
} elsif ($desk_count == 0) {
# Don't show groups which have no clients.
next;
}
}
}

$msg .= "%{F#FF00FF}|%{F-}$extra_msg$extra_urgent";

if (defined $scr_h->{'current_client'}) {
my $cc = $scr_h->{'current_client'};
$msg .= "%{c}%{U#00FF00}%{+u}%{+o}%{B#AC59FF}%{F-}" .
" " . $cc . " " . "%{-u}%{-o}%{B-}";
}
$reply_map{$screen} = $msg;
}
}

sub process_line
{
my ($fifo) = @_;
my $msg;

open (my $pipe_fh, '<', $fifo) or die "Cannot open $fifo: $!";

my $fifo_local = \*$pipe_fh;
my $select = IO::Select->new($fifo_local);

while (my @ready = $select->can_read()) {
foreach my $fd (@ready) {
while (my $line = <$pipe_fh>) {
chomp $line;
if ($line =~ s/^clock://) {
$last_clock_line = $line // '';
} else {
my $json;
eval {
$json = decode_json($line);
};
if ($@) {
warn "Couldn't parse: <<$line>>\n";
next;
}
format_output(decode_json($line));
}
foreach my $scr_key (keys %reply_map) {
print "$reply_map{$scr_key}$last_clock_line\n";
}
}
}
}
}

%scr_map = %{ query_xrandr() };
process_line($pipe);

0 comments on commit 9597928

Please sign in to comment.