tNew article about status bar - monochromatic - monochromatic blog: http://blog.z3bra.org
 (HTM) git clone git://z3bra.org/monochromatic
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit de4e65b4240ca5739b3e1d7e210d98a29637fea3
 (DIR) parent 23af2ff1ceb80c450a83ba1f2af4827ac8822c45
 (HTM) Author: z3bra <willy@mailoo.org>
       Date:   Wed,  2 Apr 2014 12:33:49 +0200
       
       New article about status bar
       
       Diffstat:
         A 2014/04/meeting-at-the-bar.txt      |     517 +++++++++++++++++++++++++++++++
         M config.mk                           |      12 ++++++------
         M index.txt                           |       6 ++++++
       
       3 files changed, 529 insertions(+), 6 deletions(-)
       ---
 (DIR) diff --git a/2014/04/meeting-at-the-bar.txt b/2014/04/meeting-at-the-bar.txt
       t@@ -0,0 +1,517 @@
       +# [Meeting at the bar](#)
       +## &mdash; 02 April, 2014
       +
       +### Introduction
       +
       +Hi everybody ! This post is more or less the continuation of my previous one:
       +[Home, sweet home](/2013/10/home-sweet-home.html). We will take desktop
       +customisations a little further here, so I'll assume that you, the reader, know
       +the base of linux system administration.
       +
       +Status bar can display anything you feed them with, so let's make that food
       +useful to us. We will learn how to display system informations on your screen.
       +
       +Here we go!
       +
       +### Summary
       +
       +* [head-up display](#hud)
       +* [fetching informations](#grab)
       +
       +
       +<h3 id='hud'>head-up display</h3>
       +
       +First of all, let's understand what an HUD is. Gamers can go the the next
       +paragraph. An HUD display some information you (most of the time) wants to see.
       +In video-games, that will be your life/armor points, or the number of ammos
       +loaded in your gun. Those information are almost always visible and are updated
       +in real-time.
       +
       +But we're not playing video games here. And you're probably not reading with a
       +loaded gun in your hand. So, sitting in front of your computer, you want other
       +kind of informations. We will talk about those informations later.  
       +First, let's see HOW we will display them on-screen. I currently know 4 ways of
       +doing it (understand, I've not tried the alternatives):
       +
       +#### dzen
       +
       +From the official website:
       +
       +> Dzen is a general purpose messaging, notification and menuing program for
       +> X11. It was designed to be scriptable in any language and integrate well
       +> with window managers like dwm, wmii and xmonad though it will work with
       +> any windowmanger.
       +
       +Seems great ! Dzen is really simple to use, pipe text to it, and watch it
       +appear on your screen:
       +
       +    echo shblah | dzen2 -w 120 -x 10 -y 10 -p 5
       +
       +I'm not a huge fan of dzen anymore. I used to be (You can do awesome things
       +with dzen, just check [earsplit's dekstop](http://i.imgur.com/bZegioR.gif), but
       +I discovered a new tool that is basically dzen simplified, and written on top of
       +XCB (see the fourth alternative: bar).
       +
       +#### conky
       +
       +Here comes the king of HUDs, ladies and gentlmen, please put a knee to the
       +ground!  
       +Conky's job is to display every possible information on your screen, in a really
       +eye-candy way. I made
       +[this](http://pix.toile-libre.org/upload/original/1360670013.jpg) monthes ago
       +using conky (do not ask for configs or wallpaper, I don't have them anymore).
       +
       +It is extensible in lua and has a heavy set of features built-in.
       +Check this out: [conky's variables](http://conky.sourceforge.net/variables.html)
       +I've been using conky for weeks, but I just got bored. I realised that I did not
       +need so much infos in real-time. But that was a fun period !
       +
       +Conky reads its configuration from the `~/.conkyrc` file. A minimalist config
       +would be:
       +
       +    cat <<EOF > ~/.conkyrc
       +    alignment tl
       +    gap_x 10
       +    gap_y 40
       +
       +    TEXT
       +    shblah
       +    EOF
       +    conky &
       +
       +But for just a simple thing, that's a bit overkill.
       +Note that there is also conky-cli that output informations to stdout. That is
       +useful to build informations lines to feed a bar with. To have a quick idea of
       +how this works, check this
       +[nice forum post](http://nixers.net/showthread.php?tid=117) by jmbi.
       +
       +#### tmux statusbar
       +
       +This one is a bit out of competition, but worth mentionning. TMux stands for
       +terminal multiplexer. Short story, you can have multiple terminal within a
       +single terminal window. But it offers a nice feature: a status bar, that is
       +displayed at the bottom of the window. You can run any command in here, or even
       +shell scripts, and the output will sit just there.
       +
       +Tmux actually have a left and right status bar. So just pick one (or both) to
       +display some infos:
       +
       +    echo "set-option -g status-left "shblah" >> ~/.tmux.conf
       +    tmux
       +
       +Phyrne wrote a [nice article](http://calummacrae.blogspot.co.uk/2012/12/dropping-status-bars-for-tmux-as-im.html)
       +about it. Just read it.
       +
       +#### bar
       +
       +My last and prefered option, the bar made by LemonBoy !  
       +This small piece of software is a stripped down clone of dzen, written on top
       +of XCB (a better librairy to communicate with the X server). It's fast, it's
       +light and you can even script it, as it now has a clickable item that you can
       +use to start applications. More infos [here](https://github.com/LemonBoy/bar).
       +
       +Bar is pretty easy to use. It works the same way dzen does, by piping text to
       +it:
       +
       +    echo 'shblah' | bar -g 120x20+10+80 -p
       +
       +Starting from now, I will use bar as my tool of choice, but use the one you
       +prefer, they can all do such a thing (well, conky has pretty much everything
       +done for you, but meh) !
       +
       +<h3 id='grab'>fetching informations</h3>
       +
       +Once you now which tool you'll use to display your informations, you need to
       +decide which one you want. For the purpose of the article, I'll settle on 8 of
       +them:
       +
       +* current date / time
       +* battery level
       +* sound level
       +* CPU load
       +* RAM used
       +* network connection state
       +* window manager groups
       +* mpd's current playing song
       +
       +I choosed those to show you many way to fetch informations on your computer.
       +
       +Before going any further, I need to introduce to you the tools we'll need, and
       +that we just CAN'T avoid to fetch informations..
       +
       +* `awk` -- a powerfull script language, I don't know enough about this, though
       +* `cut` -- cut a string in small parts, and pick some parts of it
       +* `grep` -- should I really present 'grep' ?
       +* `sed` -- stream editor, it's useful to format outputs
       +* `test` -- test an expression and return 0 if it's true, >0 otherwise
       +
       +By the way, that would be a **HUGE** plus to know about [regular
       +expressions](https://en.wikipedia.org/wiki/Regular_expression).  
       +So, here we go!
       +
       +#### current date / time
       +
       +There is nothing hard with it. The `date` utility has a parameter to format its
       +output. So we'll just use that:
       +
       +    date '+%Y-%m-%d %H:%M' # print current date and time: yyyy-mm-dd HH:MM
       +
       +#### battery level
       +
       +There is this tool, `acpi` that can be used to output some infos on you system
       +power. But that's just not fun! We'll be messing with the `/sys` directory,
       +which is a goldmine. Feel free to navigate it, to see what you can find.
       +
       +Back to the battery. We are interested in two information, the current
       +charge of the battery (in percent) and if the charger is plugged in, or not. _on
       +my system_ (because it may be different on yours), I have those two files:
       +
       +    /sys/class/power_supply/BAT1/capacity   # contains a value from 0 to 100
       +    /sys/class/power_supply/BAT1/status     # either "Charging" or "Discharging"
       +
       +We will then be able to output the battery level, and do some action, depending
       +on the battery state. To get the info:
       +
       +    BATC=/sys/class/power_supply/BAT1/capacity
       +    BATS=/sys/class/power_supply/BAT1/status
       +
       +    # prepend percentage with a '+' if charging, '-' otherwise
       +    test "`cat $BATS`" = "Charging" && echo -n '+' || echo -n '-'
       +
       +    # append the character '%' after the number
       +    sed 's/$/%/' $BATC
       +
       +#### sound level
       +
       +This one is always a pain.. I will assume that you use ALSA as your sound
       +system (because I have no idea how OSS or PulseAudio works).
       +
       +First, you need to know which channel your want to watch. Most of the time,
       +'Master' is a good choice. I personnally use `alsamixer` to navigate between the
       +channels to see what they are related to. The `alsa-utils` packages (name may
       +vary depending on the distribution) contains a utility named `amixer` to
       +interact with the system. The special command `amixer get <CONTROL>` is used to
       +query informations about a channel. But the output is awful to look at, so we'll
       +need to format it. Example output:
       +
       +    ───── amixer get Master
       +    Simple mixer control 'Master',0
       +    Capabilities: pvolume pvolume-joined pswitch pswitch-joined
       +    Playback channels: Mono
       +    Limits: Playback 0 - 64
       +    Mono: Playback 53 [84%] [-10.00dB] [on]
       +
       +You can notice that the info we're interested in sits at the end of the output.
       +That will make things easier.
       +
       +    # parse amixer output to get ONLY the level. Will output "84%"
       +    amixer get Master | sed -n 's/^.*\[\([0-9]\+%\).*$/\1/p'
       +
       +#### CPU load
       +
       +There are many way to get the current CPU load. `iostat` is one of them, and as
       +it's easy to parse its output, i'll go with a trickier approach, using `ps` and
       +`bc`.
       +
       +To get the current CPU load used by every program, one can use this command:
       +
       +    # gives you the CPU load used by every running program
       +    # 'args' is used here just so you can see the programs command lines
       +
       +    ps -eo pcpu,argv
       +
       +We don't care about idling programs that uses '0.0' load or the header '%CPU',
       +so we can just remove them with `grep -vE '0.0|%CPU'`.
       +
       +    ps -eo pcpu | grep -vE '0.0|%CPU'
       +
       +We now have a list of the CPU loads actually used, but per program. We just need
       +to sum them up!  
       +The problem is: bash _CAN'T_ perform floating point operations. And thus, we
       +will need the help of the great `bc` to do so (if you don't have this installed,
       +I recommend that you just get it right away!).
       +
       +`bc` takes operations from stdin, and outputs to stdout. Pretty simple. Pretty
       +good.
       +
       +    # use the "here-line" feature.
       +    # tr replaces newlines with space, that we change in '+' through sed
       +    # The whole line goes to bc which outputs the result
       +
       +    CALC=`ps -eo pcpu | grep -vE '0.0|%CPU' | tr "\n" " " | sed 's/  / + /g'`
       +    echo `bc <<< $LINE`%
       +
       +#### RAM used
       +
       +To display RAM usage (in the form `xx% (<used>/<total>)`, we will use another
       +place of the filesystem: `/proc`. This will be easier to find memory usage here,
       +than battery level in `/sys`:
       +
       +    ───── ls /proc/ | grep 'mem'
       +    iomem
       +    meminfo
       +
       +If you take a quick look at `iomem`, you'll understand that it's **NOT** the
       +file we want here (I don't understand a bit of it)! Instead, let's take a look
       +at meminfo:
       +
       +    ───── sed 8q /proc/meminfo 
       +    MemTotal:        2748648 kB
       +    MemFree:         2209672 kB
       +    Buffers:           34016 kB
       +    Cached:           270728 kB
       +    SwapCached:            0 kB
       +    Active:           182292 kB
       +    Inactive:         272636 kB
       +    Active(anon):     150948 kB
       +
       +Good, good, exactly the information we want! So let's just extract them, using
       +`awk` to fetch _ONLY_ the column containing the value (Yeah, that's why I use
       +awk for mostly. I'll need to dive a little more in that language):
       +
       +    ───── grep -E 'Mem(Total|Free)' /proc/meminfo |awk '{print $2}'
       +    2748648
       +    2204288
       +
       +At this point, you might realise that those two number are not really useful. We
       +will need to modify them a little by converting them to Mib, and making a ratio
       +out of them:
       +
       +    # store the total and free memory in two variables
       +    read t f <<< `grep -E 'Mem(Total|Free)' /proc/meminfo |awk '{print $2}'`
       +
       +    # then, calcultate the percentage of memory used (scale=2 tells bc to
       +    # calculate two digits after the floating point)
       +    # cut will help us to get rid of the floating point that is useless here
       +    echo `bc <<< "scale=2; 100 - $f / $t * 100" | cut -d. -f1`%
       +
       +#### network connection state
       +
       +Mmh, this one can be tricky! Ther are two cases here:
       +
       +* You have one interface
       +* You have more than one interface
       +
       +The first one is quite simple: use your interface name directly, and skip the
       +following section.
       +
       +Now what if you have, let's say two interfaces: ethernet, and wifi. Let's find
       +out HOW to get the currently used.  
       +We will need two tools for that: `ip` (from `iproute2`) and `iwconfig` (from
       +`wireless_tools`). We will get the interfaces with `ip`, and recognize the wifi
       +interface using `iwconfig`. Sounds easy huh ?
       +
       +    # The following assumes you have 3 interfaces: loopback, ethernet, wifi
       +    read lo int1 int2 <<< `ip link | sed -n 's/^[0-9]: \(.*\):.*$/\1/p'`
       +
       +    # iwconfig returns an error code if the interface tested has no wireless
       +    # extensions
       +    if iwconfig $int1 2>&1 >/dev/null; then
       +        wifi=$int1
       +        eth0=$int2
       +    else
       +        wifi=$int2
       +        eth0=$int1
       +    fi
       +
       +    # this line will set the variable $int to $eth0 if it's up, and $wifi
       +    # otherwise. I assume that if ethernet is UP, then it has priority over
       +    # wifi. If you have a better idea, please share :)
       +    ip link show $eth0 | grep 'UP' >/dev/null && int=$eth0 || int=$wifi
       +
       +This is now the time to see if network is up or not. For that, a simple `ping`
       +would do the trick:
       +
       +    # just output the interface name. Could obviously be done in the 'ping'
       +    # query
       +    echo -n "$int"
       +
       +    # Send a single packet, to speed up the test. I use google's DNS 8.8.8.8,
       +    # but feel free to use any ip address you want. Be sure to put an IP, not a
       +    # domain name. You'll bypass the DNS resolution that can take some precious
       +    # miliseconds ;)
       +    ping -c 1 8.8.8.8 2>&1 >/dev/null && echo "connected" || echo "disconnected"
       +
       +
       +#### window manager groups
       +
       +Aaah, the information that has the most way to be fetched! The problem with
       +this, is that every window manager provide a different way to fetch the number
       +of workspaces, and the current one. If you're lucky, and that your WM is
       +[EWMH](https://en.wikipedia.org/wiki/EWMH) compliant, `xprop` will be the way to
       +go. For the others, you will need to find a proper way on your own. For exemple,
       +to get the number of groups and the current group with ratpoison:
       +
       +    echo "`ratpoison -c groups| cut -sd'*' -f1`/`ratpoison -c groups| wc -l`"
       +
       +iBack to the topic, fetching current group out of all the groups. To make this a
       +little more exiting, we will output something like `--o---`, 'o' being the
       +current desktop, '-' being the other desktops.
       +
       +The first step is to fetch the number of desktops, and the index of the current
       +one. To do that, let's use `xprop`
       +
       +    cur=`xprop -root _NET_CURRENT_DESKTOP | awk '{print $3}'
       +    tot=`xprop -root _NET_NUMBER_OF_DESKTOP | awk '{print $3}'
       +
       +If that enough for you, you can obviously just output `$cur/$tot` ;)  
       +But now, the desktop indicator. To do that, there is two solutions:
       +
       +* cicle through all the groups and output either '=' or '|'
       +* ouput the correct number of '|' before and after '|'
       +
       +I tried both versions, and `time` reports that they are they're _almost_ the
       +same:
       +
       +    ───── time cicle.sh; time fillup.sh 
       +    ==|=======
       +
       +    real    0m0.025s
       +    user    0m0.013s
       +    system  0m0.000s
       +    ==|=======
       +
       +    real    0m0.020s
       +    user    0m00m0.013s
       +    system  0m0.000s
       +
       +We will then use the 'fillup' one. To improve performances, we will first fill a
       +variable with the 'group line', and then output it. It goes like this:
       +
       +    # Desktop numbers start at 0. if you want desktop 2 to be in second place,
       +    # start counting from 1 instead of 0. But wou'll lose a group ;)
       +    for w in `seq 0 $((cur - 1))`; do line="${line}="; done
       +
       +    # enough =, let's print the current desktop
       +    line="${line}|"
       +
       +    # En then the other groups
       +    for w in `seq 1 $((cur + 2))`; do line="${line}="; done
       +
       +    # don't forget to print that line!
       +    echo $line
       +
       +#### mpd's current playing song
       +
       +After all that we did alredy, printing the current playing should bequite easy
       +as:
       +
       +    cur=`mpc current`
       +    test -n "$cur" && echo $cur || echo "- stopped -"
       +
       +Easy isn't it ? So let's add some difficulties to it. What if you have only 120
       +pixels to display that ?  
       +Aaaah trickyer isn't it ?
       +
       +Don't worry, I wrote a small tool for that:
       +[skroll](http://git.z3bra.org/cgit.cgi/skroll). You can see it in action
       +[here](http://blog.z3bra.org/img/2014-03-28-skroll.gif).
       +
       +So now, our output has just become:
       +
       +    cur=`mpc current`
       +    test -n "$cur" && echo $cur |skroll -n 20 -d0.5 -r || echo "- stopped -"
       +
       +A small drawback with this approach: you can't put other infos in the same bar
       +as a `skroll`ing output, because it uses a `\n` or a `\r` to print the output.
       +
       +#### wrap it all !
       +
       +Now that we have a whole bunch of informations, it's time to put them all in a
       +script, that we will pipe later to our HUD.
       +
       +    #!/bin/sh
       +    #
       +    # z3bra - (c) wtfpl 2014
       +    # Fetch infos on your computer, and print them to stdout every second.
       +
       +    clock() {
       +        date '+%Y-%m-%d %H:%M'
       +    }
       +
       +    battery() {
       +        BATC=/sys/class/power_supply/BAT1/capacity
       +        BATS=/sys/class/power_supply/BAT1/status
       +
       +        # prepend percentage with a '+' if charging, '-' otherwise
       +        test "`cat $BATS`" = "Charging" && echo -n '+' || echo -n '-'
       +
       +        # append the character '%' after the number
       +        sed 's/$/%/' $BATC
       +    }
       +
       +    volume() {
       +        amixer get Master | sed -n 's/^.*\[\([0-9]\+%\).*$/\1/p'
       +    }
       +
       +    cpuload() {
       +        CALC=`ps -eo pcpu |grep -vE '0.0|%CPU' |tr "\n" " " |sed 's/  / + /g'`
       +        echo `bc <<< $LINE`%
       +    }
       +
       +    memused() {
       +        read t f <<< `grep -E 'Mem(Total|Free)' /proc/meminfo |awk '{print $2}'`
       +        echo `bc <<< "scale=2; 100 - $f / $t * 100" | cut -d. -f1`%
       +    }
       +
       +    network() {
       +        if iwconfig $int1 2>&1 >/dev/null; then
       +            wifi=$int1
       +            eth0=$int2
       +        else
       +            wifi=$int2
       +            eth0=$int1
       +        fi
       +        ip link show $eth0 | grep 'UP' >/dev/null && int=$eth0 || int=$wifi
       +
       +        ping -c 1 8.8.8.8 2>&1 >/dev/null && 
       +            echo "$int connected" || echo "$int disconnected"
       +    }
       +
       +    groups() {
       +        cur=`xprop -root _NET_CURRENT_DESKTOP | awk '{print $3}'
       +        tot=`xprop -root _NET_NUMBER_OF_DESKTOP | awk '{print $3}'
       +
       +        for w in `seq 0 $((cur - 1))`; do line="${line}="; done
       +        line="${line}|"
       +        for w in `seq 1 $((cur + 2))`; do line="${line}="; done
       +        echo $line
       +    }
       +
       +    nowplaying() {
       +        cur=`mpc current`
       +        # this line allow to choose whether the output will scroll or not
       +        test "$1" = "scroll" && PARSER='skroll -n20 -d0.5 -r' || PARSER='cat'
       +        test -n "$cur" && $PARSER <<< $cur || echo "- stopped -"
       +    }
       +
       +    # This loop will fill a buffer with our infos, and output it to stdout.
       +    (while :; do
       +        buf=""
       +        buf="${buf} [$(groups)]   --  "
       +        buf="${buf} CLK: $(clock) -"
       +        buf="${buf} NET: $(network) -"
       +        buf="${buf} CPU: $(cpuload) -"
       +        buf="${buf} RAM: $(memused) -"
       +        buf="${buf} VOL: $(volume) -"
       +        buf="${buf} MPD: $(nowplaying)" # use $(nowplaying scroll) to get a
       +                                        # scrolling output!
       +        echo $buf
       +        sleep 1 # The HUD will be updated every second
       +    done)
       +
       +All you have to do now is to pipe this script to your status bar of choice:
       +`./bar-generator | bar -B \#1d1d1d`. 
       +
       +There you are! You now know how (ow ow ow) make your system talk to you.
       +Obviously, this is a raw script, and it can be heavily improved (eg, add some
       +colors, parse CLI arguments, etc..).
       +
       +But I'm pretty sure that it's a good start for your imagination. By the way, if
       +you find neat tricks to improve the performances of the functions listed above,
       +feel free to mail me these, I'll be glad to modify them!
       +
       +Now go ahead, and watch how your computer tell you how he (or she) feels...
       +Isn't that **amazing** ?!
       +
       +<!-- vim: set ft=markdown ts=4 et tw=80: -->
 (DIR) diff --git a/config.mk b/config.mk
       t@@ -4,16 +4,16 @@ NAME    = monochromatic
        PREFIX  = /srv/http/blog.z3bra.org
        
        PAGES   =   index.html \
       -            2013/12/love-me-some-latex.html \
       -            2013/11/plain-old-mails.html \
       -            2013/10/home-sweet-home.html \
       +            about.html \
                    2013/08/test-your-css.html \
                    2013/08/the-hard-way.html \
                    2013/09/java-without-eclipse.html \
       -            2014/03/unleash-your-desktop.html \
       -            2014/03/toolbox.html \
       +            2013/10/home-sweet-home.html \
       +            2013/11/plain-old-mails.html \
       +            2013/12/love-me-some-latex.html \
                    2014/01/images-in-terminal.html \
       -            about.html
       +            2014/03/toolbox.html \
       +            2014/04/meeting-at-the-bar.html
        
        FEEDS = rss/feed.xml
        EXTRA = css img favicon.ico
 (DIR) diff --git a/index.txt b/index.txt
       t@@ -1,3 +1,9 @@
       +# [Meeting at the bar](/2014/04/meeting-at-the-bar.html) 
       +## &mdash; 02 April, 2014
       +I know that I will deceive some people but I'm not talking about alcohol here!
       +This article is about building a status bar for your beloved desktop. And we
       +will do this **the hard way**...
       +
        # [Toolbox](/2014/03/toolbox.html) 
        ## &mdash; 12 March, 2014 
        Yeah, yet another list of unix tools. Feel free to avoid it, but you'll