Linux Fu: Easy Widgets

Here’s a scenario. You have a microcontroller that reads a number of items — temperatures, pressures, whatever — and you want to have a display for your Linux desktop that sits on the panel and shows you the status. If you click on it, you get expanded status and can even issue some commands. Most desktops support the notion of widgets, but developing them is a real pain, right? And even if you develop one for KDE, what about the people using Gnome?

Turns out there is an easy answer and it was apparently inspired by, of all things, a tool from the Mac world. That tool was called BitBar (now XBar). That program places a widget on your menu bar that can display anything you want. You can write any kind of program you like — shell script, C, whatever. The output printed from the program controls what appears on the widget using a simple markup-like language.

That’s fine for the Mac, but what about Linux? If you use Gnome, there is a very similar project called Argos. It is largely compatible with XBar, although there are a few things that it adds that are specific to it. If you use KDE (like I do) then you’ll want Kargos, which is more or less a port of Argos and adds a few things of its own.

Good News, Bad News

The good news is that, in theory, you could write a script that would run under all three systems. The bad news is that each has its own differences and quirks. Obviously, too, if you use a complied program that could pose a problem on the Mac unless you recompile.

To exacerbate that problem, the documentation for Kargos seems to be wrong. This is partly because the version in the KDE repositories is out of date and even if you grab the latest release off GitHub, it is still out of date with the documentation. You really want to install from a clone of the GitHub, not from the release package or from the KDE repository for plasmoid. Part of the problem, too, is the documentation is terse and you sometimes have things that work but not in every case. It isn’t clear if this is by design or some interaction with the KDE desktop which is always changing.

Since I use KDE, I’m going to focus on Kargos, and I’ll point out a few things about Argos as I go. But you can expect to do some experimenting either way.

Basics

When you install the widget, you have to point it to a script. In general, the script will run periodically. For Kargos, you can set that interval in two different ways that we’ll talk about later.

In the simplest case, you’d have the script output a line of text that will appear on the panel, a separator, and then one or more lines of text that will appear when you click on the widget. Consider this:

#!/bin/bash
echo Hello Hackaday
echo ---
echo Test
echo 1
echo 2
echo 3
echo 4

If you put the Kargos widget on a panel and set it to read your script, you’ll wind up with just the text Hello Hackaday on your panel. When you click, you’d see something like this:

Excitement

A bit snazzier

As it is, this isn’t very exciting. However, each line of text can have a pipe character and some attributes to spruce things up and add function. Replace the one line that says Hello Hackaday with this:

ICON=$( curl -s "https://hackaday.com/favicon.ico | base64 -w 0 )
echo "Hello Hackaday | image='$ICON' href=http://www.hackaday.com"

Now the panel will look a bit snazzier and if you click the little chain link icon, you’ll visit your favorite website. Of course, the real interesting thing is when you can make items change. If you set a refresh interval on the configuration screen, the script will run that often. You can also name the script with a repeat interval. For example, a script of haddemo.10s.sh will run every 10 seconds but haddemo.2m.sh will run every two minutes.

You can also add a refresh=true attribute to a text line to make clicking it run the script again. Suppose you want to ping google on demand. You can set the timer to 0 and do this:

#!/bin/bash
OUTPUT=$( ping -c 1 -q google.com | grep ^rtt | cut -d ' ' -f 4 | cut -d '/' -f 1 )
if [ -z "$OUTPUT" ]
then
   echo "Error click to refresh | refresh=true color=orange" bash="'/usr/bin/systemsettings kcm_networkmanagement'" terminal=false
fi
# get an integer to compare (bash doesn't like floats)
IOUT=$( echo $OUTPUT | sed s/\\.// )
COLOR=green
if [ $IOUT -gt 90000 ] # 900000 is 90 ms
then
   COLOR=red
fi 
echo "Google.com: $OUTPUT ms | refresh=true color=$COLOR" bash="'/usr/bin/systemsettings kcm_networkmanagement'" terminal=false
echo ---

Now you’ll get a ping time from Google on your bar. It will turn color if it is slow or unable to ping. A small button will let you open network management.

However…

Colors don’t seem to work on the dropdown menus, which may be the desktop manager forcing theme colors, so your mileage might vary. There are also some differences compared to Argos. For example, Argos has an environment variable that tells you if the widget is open or not. That allows you to not run unnecessary parts of your script for better performance.

There are other differences, too, but if you stick to the basics, you should be fine. Even where things are different, it is still easier than writing two completely different widgets for the different systems.

There also seems to be some odd behavior. For example, the onclick attribute doesn’t work in dropdown items, either. Of course, it is open source, so if you hate it that much, feel free to go fix it!

Big Example

Since I like to follow the headlines on Hackday, I decided to take advantage of a feature of Kargos. In the previous examples, I only had one line before the dropdown separator (“—“). But if you have more than one line, the widget will rotate through them with a delay you can set in the widget settings.

Using awk it is easy to read the Hackaday RSS feed and pull out titles and links. A few images and you wind up with a nice RSS display. The parsing might not work for an arbitrary RSS feed as it is pretty simple-minded, but — in theory — you should be able to adapt this for other feeds.

Here’s the code:

</pre>
#!/bin/bash
curl "https://hackaday.com/feed/" 2>/dev/null |
  awk '
   BEGIN { n=-1; }  # skip first item
/<title>/ {
# read titles
    if (n==-1) next;
    gsub("[[:space:]]*</?title>[[:space:]]*",""); item[n]=$0; next;
   }
/<link>/ {
# read links
   if (n==-1) { n=0; next; }
   gsub("[[:space:]]*</?link>[[:space:]]*", ""); link[n++]=$0; next
   }
END {
# output widget text
   for (i=0;i<n;i++) {
   printf("%s | href=\"%s\" imageURL=https://hackaday.com/wp-content/themes/hackaday-2/img/logo.png\n",item[i],link[i]);
   }

print "---"
# output dropdown lines
for (i=0;i<n;i++) {
   printf("%s | href=\"%s\"\n",item[i],link[i]);
   }
}
'
<pre>

That’s not a lot of code for a full-blown RSS reader. You can see the stories in the panel and either click on them there or open up the widget to see a list all at one time.

Next Steps

Since the data is just text, it is simple to whip out little widgets using this system. For example, this is a pretty handy memory status widget:

#!/bin/bash
cat /proc/meminfo
echo ---
echo "<b>Tools</b>"
echo "--System status | bash=/usr/bin/ksysguard onclick=bash"
echo "--Htop | bash=/usr/bin/htop" terminal=true
cat /proc/meminfo

Obviously, having a script that reads data from an ESP32 or an Arduino would be trivial. Since a lot of what you want to do with something like this is operating system agnostic, browsing some of the plugins for xbar might give you an idea.

If you want something more sophisticated for just KDE, have a look at Scriptinator. You can tailor it more, but it is a bit more complex to manage.

For some reason, I’m obsessed with the Hackaday feed. I’ve turned it into a filesystem. It also greets me when I log in. Some of the plugins you’ll find are in bash and some are in Python. Don’t forget you can mix them together, too.

5 thoughts on “Linux Fu: Easy Widgets

  1. heh i don’t use any desktop environment (i like fvwm). to achieve this, I run from .xinitrc:

    xterm -ut -T status -n status -geometry 40×1-0+0 -cr black -fn -e status_script &

    in .fvwm2rc:

    Style “status” NoTitle, NoHandles, Sticky, WindowListSkip, CirculateSkip, BorderWidth 0,StaysOnTop

    and then status_script is some perl that spits out the CPU temp, wifi AP name (colored by signal strength using ANSI terminal escape codes), battery %, battery Wh, watts being drawn, date and time. who needs images. :)

  2. “This is partly because the version in the KDE repositories is out of date and even if you grab the latest release off GitHub, it is still out of date with the documentation. ”

    Ah, but code is the documentation. ;-)

  3. Building a widget for a specific desktop environment is a colossal waste of time, as they often change and break for no reason, and it makes it harder to switch to a different desktop environment when your needs change. Besides that nobody agrees on what a system bar should do, and some desktop environments do away with them entirely, so you’re better off just not getting invested in any particular implementation.

    I’d rather use Conky for displaying simple metrics and feeds. And if I want to be able to interact with the elements, I’ll build a web page.

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.