Making GeekTool Menubar friendly

I wouldn't call this part 2 of my GeekTool post, but it is the follow up I mentioned in the last post. GeekTool needs a little tweak to make it play nice on newer systems. Do you need to do this? No... but you'll lose out on some of the features if you don't.

Who needs to do this? Well, I needed to when I installed it on my unibody 13" MacBook, which means Intel Leopard. It worked just fine on my PPC G4 iMac running Leopard without the change. So does that mean it's Intel Leopard or just Intel systems? I don't know... but if the happy little 'pizza' doesn't show up in your menu bar when you check on 'Show Menu' in the PrefPane, then this will fix you right up. In that case, read on.

So you've installed GeekTool, and you're left without pizza, so you can't access the Groups options, forced refresh, or disable/enable commands from your menu bar? The first thing you need to do is download the most recent version of MenuCracker from sourceforge.net. As of this post that would be version 1.4. Also as of this version, the .dmg seems to not actually have anything in it, so you'll want to get the file named UpgradeToUniversalMenuCracker1.4.zip.

Step 1: Download and open the file. That will give you an installer package. Don't actually run the installer.

Step 2: Right-click (control-click or two-finger tap... this is getting out of hand, Apple) the installer package and chose 'Show Package Contents'. You'll get a new Finder window with just a folder named Contents.

Step 3: Open that folder and double click on Archive.pax.gz which will give you another folder named Archive.

Step 4: Now open this folder and copy the file MenuCracker.menu into your work area of choice. The desktop works if you like. Now you can get rid of the installer package if you want, though I like to archive things like this as you never know when they'll vanish off the face of the net.

Now you need to put that file inside of the GeekTool PrefPane; which is a lot easier than it sounds. I will take this time to say that while if you do exactly what I tell you NOTHING BAD WILL HAPPEN™ if you go poking around in other files, and make other changes I will not take responsibility for loss of data, system failure, or all the Canadians bent on world domination (I know that was redundant) coming together and actually succeeding (I for one welcome our new Canadian Overlords) as a result of you not following my instructions to the letter. Come to think of it even if you do exactly what I say you're still on your own if Oh Canada becomes the world anthem.

Step 1: Locate the actual PrefPane file for GeekTool. If you installed it for all users then it will be in /Library/PreferencePanes/ from the root of your boot drive. If you installed it for just one user then it'll be in ~/Library/PreferencePanes/ (which means the Library directory in your home directory) The file is called GeekTool.prefPane and its icon will look just like it does inside of the PrefPane.

Step 2: Open the contents of the file just like you did the installer package, and open the Contents folder.

Step 3: Now open the Resources folder and locate GeekToolMenu.menu and do another Show Package Contents. (these are just directories which carry a special flag that makes them look different to the system and in Finder)

Step 4: Once again we're opening the Contents folder and then the Resources folder.

Step 5: Replace the MenuCracker.menu file with the one you copied out of the installer package. Now you should be able to just disable then enable GeekTool from within the PrefPane, but if that doesn't work a logout and login will take care of it.

You'll now have the pizza in your menu bar, and have access to some of the options without having to open the System Preferences; you'll also have faster access to the PrefPane for GeekTool.

Multi-Tools aren't the only GeekTool

Desktop customizing is about more than style; often times it's about workflow, and just being on top of what's happening on your network. Sometimes you just need to know, at a glance, what's running, how much traffic there is, or just that everything is as it should be. The best solution is usually the one that is out of the way, but ready at a moments notice... and if it can look good doing it, all the better.

I know I may have my Apple Cult Card revoked for admitting this in public, but Steve Jobs and his crew are not the best UI designers in the world. Is the Mac OS interface pretty, certainly, but is it awesome? Does it do what you want, when, and how? That's for each user to decide, and that's where customizing comes in.

Sure you can change the desktop image, move the Dock around, and in Leopard even make the menu bar translucent; when it comes to really tricking things out the best the fine folks in Cupertino did was make it very easy to change the file/folder/drive icons.

When it comes to displaying continuously updating text and images on the desktop Windows users have so many options it's hard to pick one. BSD/Linux users also have a fair amount of options for getting status information on their desktops. OS X just isn't feeling the love. Sure there are a lot of Dashboard Widgets, and there are ways to make those stay in the foreground. There are some menu bar status monitors, and even some apps to show basic info in the Dock by way of dynamic icons. That's not going to get server logs or the graphs output by tools like MRTG or RRD on your desktop.

That's where the deceptively versatile PrefPane GeekTool comes in. It's been around for a while, but it surprises me still how many long-time Mac users have never heard of it. The most current version is 2.1.2 and is meant to run on Panther and Tiger as a Universal Binary. I had no problem getting it to run on my PPC Leopard machine and only took one simple modification to make it run perfectly on my Intel Leopard laptop (I'll cover that next post), though it will run without the change.

So just what does it do? At its core GeekTool just embeds images, text files, or the output of scripts into the desktop at a defined refresh rate... but that's where its power comes from. With even the most basic of shell commands you can output a simple calendar, show how long your system has been running, or display the name of the currently logged in user. Toss in sed, awk, or grep, and now you can display CPU load, memory usage, and process information formatted in any way you like.

Ready to go beyond one or two line shell commands, point GeekTool at a shebang (or hashbang if you prefer) coded file, and run PHP, Python, or Perl (what's with all the P's anyway?) scripts too.

It works just as well with existing files as it does running commands, so showing the content of a log file, or keeping an RRD graph refreshed is just as simple.

The displayed text and background can be any color, or font. Images can be local files or via HTTP. Both can be done borderless or with a choice of border types and drop shadows, as well as any level of transparency. Always on top can also be chosen if you want something important visible at all times.

While there is no obvious multi-display support, making use of more than one display is trivial. Items are positioned on screen by clicking and dragging them into position or by entering X, Y, Height, and Width values; X and Y can be negative numbers. So entering numbers that extend beyond the boundaries of your main display will push the item onto the display that is positioned there in your Display PrefPane.

GeekTool also allows items to be enabled and disabled in groups. So when your MacBook isn't connected to the second monitor just switch groups to one that doesn't include that monitor so those processes don't run.

So just what am I doing with it? I'm pretty boring in that way; I've got the usual CPU, memory, uptime stuff. A calendar that marks the current day. A tail of my system log and firewall log. As well as my current internal IPv4, and external IPv4 and IPv6 addresses. I think about prettying it up from time to time, but in the end, I just like seeing what's going on. I usually have far too many windows open to see my desktop anyway, so the glitz doesn't matter. I just do a quick four finger up swipe, see my desktop and all the status info, then another down swipe, and back to work. Now I do have my memory, CPU, and uptime/load averages right along the bottom edge of the screen so I can usually see them no matter what. I toy with putting disk space down there too but haven't committed to the idea just yet.

Some good references for settings and scripts to get you started down your own GeekTool powered information nirvana (and where I got most of my ideas):

Ultimate GeekTool Setup by Nick Young

GeekTool and Bash One-Liners by Rupa Deadwyler

Monitor Your Mac and More with GeekTool by Gina Trapani

Before I wrap this up, I want to impress upon you just how important the DIY nature of GeekTool is to its power. Though you can't really tell from a still image, that LED is showing me my CPU load by color. The LED was actually a reddish yellow (because I haven't worked out the exact values for yellow just yet) because I was testing and had the threshold set to trigger all colors easily.

Since I don't plan on leaving this rig setup (because I don't have a stash of Teensy's laying around) it's running with its own entry in GeekTool, and it's own shell script, but it wouldn't be hard to make it part of the primary CPU status script with a condition check to make sure the /dev entry for the Teensy was there.

For reference, though, and so you can't say I never gave you anything. Here is the shell script and Arduino sketch to get that last bit of fun working.


#!/bin/sh
# geektool_cpu_teensy.sh
# Trigger LED colour change based on
# CPU ldle status as read from top
# This code requires catty be installed
# http://sourceforge.net/projects/catty

idleCPU=$(top -l 2 | awk '/CPU usage/ && NR > 5 {print $12}'
 | awk -F '.' '{print $1}')

if [ $idleCPU -gt 80 ]
  then
    catty -d /dev/cu.usbmodem12341 -b 9600 -w 'Gr'
elif [ $idleCPU -gt 65 ]
  then
    catty -d /dev/cu.usbmodem12341 -b 9600 -w 'Y'
else
    catty -d /dev/cu.usbmodem12341 -b 9600 -w 'Rg'
fi


// rgb_led.pde
// Switch LED colours based on serial input

int incomingByte = 0;

byte r_pin = PIN_B7;
byte g_pin = PIN_C5;
byte b_pin = PIN_C6;

void setup() {
  Serial.begin(9600);
  pinMode(PIN_D6, OUTPUT);
  digitalWrite(PIN_D6, LOW);
  delay(1000);
  digitalWrite(PIN_D6, HIGH);
  delay(1000);
  digitalWrite(PIN_D6, LOW);
  pinMode(r_pin, OUTPUT);
  pinMode(g_pin, OUTPUT);
  pinMode(b_pin, OUTPUT);
  Serial.flush();
  digitalWrite(PIN_D6, HIGH);
}

void loop() {
  incomingByte = Serial.read();
  if (incomingByte >= 0) {
    if (char(incomingByte) == 'Y') {
      analogWrite(r_pin, 255);
      analogWrite(g_pin, 125);
    }
    else if (char(incomingByte) == 'y') {
      analogWrite(r_pin, 0);
      analogWrite(g_pin, 0);
    }
    else if (char(incomingByte) == 'u') {
      analogWrite(r_pin, 125);
      analogWrite(g_pin, 125);
    }
    else if (char(incomingByte) == 'r') {
      analogWrite(r_pin, 0);
    }
    else if (char(incomingByte) == 'R') {
      analogWrite(r_pin, 255);
    }
    else if (char(incomingByte) == 't') {
      analogWrite(r_pin, 125);
    }
    else if (char(incomingByte) == 'g') {
      analogWrite(g_pin, 0);
    }
    else if (char(incomingByte) == 'G') {
      analogWrite(g_pin, 255);
    }
    else if (char(incomingByte) == 'h') {
      analogWrite(g_pin, 125);
    }
    else if (char(incomingByte) == 'b') {
      analogWrite(b_pin, 0);
    }
    else if (char(incomingByte) == 'B') {
      analogWrite(b_pin, 255);
    }
    else if (char(incomingByte) == 'n') {
      analogWrite(b_pin, 125);
    }
  }
}


Both are Copyright Jody K Delauney 2009. Released under BSD two clause license. Full text of the license and commented sources are available for geektool_cpu_teensy.sh and rgb_led.pde.

Teensy = Arduino* (for small quantities of Arduino)

A fair amount of my free time lately has been consumed by getting back into electronics, specifically microcontrollers. I took two years of electronics in high school and dabbled with it a little after. Life kind of got in the way, and it fell so far to the back burner than it wasn't even warm anymore.

I recently became aware of the Arduino development platform, and about the same time, another little device called the Teensy. Since then my 'entertainment budget' has been funneled into the bank account of SparkFun for various transistors, switches, regulators, and the all-important LEDs; and of course to PJRC for a Teensy... but just what is a Teensy?

The result of a project by Paul Stoffregen, the Teensy is a microcontroller development board based on the Atmel AT90USB162 AVR. The Arduino, also based on Atmel AVRs, differs from the Teensy in a few important ways:


  • The Arduino is 100% open source. While almost everything about the Teensy is open, the bootloader is not.


  • Most Arduino form factors are MUCH larger than the Teensy. This is good for instant development, as most of them come with header blocks attached so you can just start plugging things in, but it can be limiting when it comes time to put your project into a case.


  • Despite most Arduinos having USB ports, it does not actually do USB communications. A USB/Serial converter is used, which limits the speed at which it can be communicated with.


  • The Teensy, using native on-chip USB can, with only a few simple commands, be made to show up as either a USB/Serial device, a mouse, a keyboard, and with a little more work a mass storage device. These can be done with the Arduino, but it's a fair bit more involved.


  • And while the Teensy's older brother Teensy++ also has analog inputs, the original Teensy lacks the Arduino's analog input options. It does have PWM output, though, just as the Arduino and one can always wire a DAC circuit in if needed.

  • So why Teensy; why didn't I go with the more popular Arduino? There are a lot of reasons I could state, but what it comes down to are two very important ones.


  • Cost... the Teensy is a little cheaper, and having more flash for code storage at less cost, it just made sense to my wallet.


  • Possibly more important... community.

  • "What? The Arduino has a huge community!" Yes, yes it does... and when I bought my Teensy I didn't know ANY OF THEM. I did, though, know someone that had a Teensy. A community of two is much more useful than one of thousands when you know each other personally, and can just show up on the other's doorstep at any time. I'm a visual learner; five minutes of watching someone else do something is worth weeks of reading about it for me, so having someone in my own little part of the world I could compare notes with if needed played a huge part in my decision.

    The best part is I am not separated from the very large and very active Arduino community. Paul is actively developing what he calls Teensyduino, a plugin for the Arduino IDE that lets most Arduino sketches (the source code for controlling an Arduino, so named because it's based off the Processing programming language whose IDE is called a sketchbook) run with only a little modification. So I get the small form factor, faster communications if I needed it, a local fellow developer, and most of the resources of the Arduino development community for $22 ($19 if you get it without header pins). That's a cost of entry I can deal with.

    Of course, it hasn't been all happiness and sunshine. Teensyduino is still in early beta, so some sketches aren't as easy to make work as I'd like just yet. I recently ran into a small issue with serial communications. Specifically the Serial.available() function. Per the Arduino website, it should return the number of characters waiting in the buffer to be read. As I don't have an actual Arduino to test the code on I can't be sure, but the example code agrees with the description. On the Teensy (at least as of Teensyduino v0.4) it returns something else, though I'm not sure just what the number means. So I had to come up with a far less elegant solution... the conversation went something like this:

    Me:
    void setup() {
      Serial.begin(9600);
    }

    void loop() {
      if (Serial.available() > 0) {
        Serial.println(Serial.read(), DEC);
      }
    }


    Teensy: -1

    Me: That shouldn't be happening, -1 means there's no data to read if there is no data Serial.available() should be 0, and you shouldn't be reading.

    Teensy: Whatever...

    Me: Don't give me any lip, I'll reflash you, and do something else.

    Teensy: As if, you're my beotch, and you'll do what I say now.

    Me:
    int receivedByte = 0;

    void setup() {
      Serial.begin(9600);
    }

    void loop() {
      receivedByte = Serial.read();
      if (receivedByte >= 0) {
        Serial.println(char(receivedByte));
      }
    }


    Teensy: I don't have anything to show you... you need to send me something.

    Me: HA!

    Teensy: Curses, foiled again!


    Yes, that's pretty much how it went... or at least that's how it went in my head. I blame Wil Wheaton... and his iTunes.

    So that's what I've been up to. That work has even fallen over into my still not released write up on GeekTool, which will be out by the end of this week. I just keep finding other things to put in it, so it's never actually done. I guess it's time for a 'feature freeze'.