Archive for the ‘applet’ Category

Python and GConf

Friday, November 16th, 2007

The weather applet and clock/calendar applet for the Avant Window Navigator both use GConf to store their configuration settings. GConf is part of the GNOME environment on Linux. It maintains a hierarchical set of configuration data in (key,value) pairs, much like the registry on Windows or the “plist files” on OSX. One of the nice things about GConf is that you can register your application to receive notifications in a callback function whenever any interesting configuration values change.

I noticed that there weren’t a lot of tutorials out there on the topic of mixing Python with GConf, so I decided to write one.

First, you’ll need to import the Python bindings for GConf:

import gconf

Next, you want to create a GConf “client” in your Python app. You’ll probably want to do this in an __init__() function somewhere. You’ll also want to register your application to receive notifications when ever your configuration values change. The hierarchy of configuration values in GConf follows the familiar slash-separated path notation. For example, the configuration values for my AWN weather applet are stored in /apps/avant-window-navigator/applets/weather. So, if I want to register a callback named config_event to be called whenever configuration values on that path are modified, I’d do the following:

self.gconf_client = gconf.client_get_default()
self.gconf_client.notify_add("/apps/avant-window-navigator/applets/weather", self.config_event)

I usually write a generic “get_config” function, and have the callback call get_config. That way, I can use the same configuration code when I initialize. The config callback then looks simple… something like this:

def config_event(self, gconf_client, *args, **kwargs):
  self.get_config()

The kwargs parameter gives you a list of parameters that changed. You can fine-tune your configuration code based on this, but I usually just ignore it and re-read everything because I don’t usually have very many parameters.

GConf provides functions for reading your parameters. They look like this:

foo = self.gconf_client.get_string("/path/to/my/config/data/foo")
bar = self.gconf_client.get_int("/path/to/my/config/data/bar")
baz = self.gconf_client.get_bool("/path/to/my/config/data/baz")

All of the functions except get_boolreturn None if the key isn’t found. Oddly, get_bool seems to return False if the key isn’t found. In my configuration code, I like to initialize my GConf values when the key isn’t found. So when if my code were to read the “foo” parameter like the above example, it’d actually be coded something like this:

foo = self.gconf_client.get_string("/path/to/my/config/foo")
if foo == None:
  self.gconf_client.set_string("/path/to/my/config/foo", "Default Value")
  foo = "Default Value"


And I usually wrap the above idiom in its own function that accepts a key name and a default value.


Note that you can edit and interact with your GConf settings in realtime using the GNOME configuration tool. If you use Ubuntu, then this utility may be found under the “System Tools” menu. Editing configuration values in the configuration tool will result in your callback being executed as you might expect.

This also makes creating a configuration dialog easy. The configuration dialog just needs to write its updated values to gconf when the user clicks Apply or OK. If you’ve created a callback and generic configuration function, then the application will automatically reconfigure itself after the user applies their modifications!

Ten things I miss when switching from Ubuntu to OSX

Thursday, October 18th, 2007

I saw this article on Digg the other day, and I decided to write a response to it. I use both OSX (at home) and Ubuntu (Feisty, at work), and believe it or not, there are some things I like better about Ubuntu. This is all anecdotal, and I don’t profess to be an expert on either environment, so don’t be surprised if I’m just flat-out wrong about some of these things. Yes, I’ve used other distros (including Slackware, Fedora, RedHat, Mandrake, and Gentoo), but Ubuntu is the one with which I’m most familiar right now.

  1. Java Support – I’m a Java developer by trade. Ever try to download the Java 6 SDK for the Mac? You can’t. Java 5 is fine for most things, but we’re using Java 6 at work.
  2. VPN Client (and other corporate IT software) availability – This is probably specific to me. We use a SonicWall VPN where I work. There’s no OSX client available, but you can connect via Linux. Even though this problem is specific to my situation, the general lack of software is still occasionally a problem for OSX. Of course, I can pay for a commercial solution like this one, but it kinda sucks that I have to pay for one, while none of my Windows or Linux using colleagues do.
  3. Internet Explorer – OK, I know what you’re thinking (I usually prefer Camino). There is occasionally a site that needs IE. And, as a web developer, I sometimes need to preview stuff in IE. With WINE, I can do that fairly seamlessly on my Linux desktop. With my Mac, I needed to pay for Parallels, then I need to buy a windows license, then I need to run IE in a separate virtual desktop. Yuck.
  4. Finder – The OSX Finder just sucks. Nautilus is better. Konqueror is better. Hell, even Thunar is better. Finder’s side pane is virtually useless and isn’t customizable. Navigating by entering a path is awkward. Renaming requires you to right-click and “view file info.” I guess they’re fixing it in Leopard. We’ll see.
  5. Free GTK-based Linux Software Doesn’t Run Natively (Yet) – There are several free programs that run natively under the Windows port of GTK (GIMP and Pidgin come to mind), but to run it on OSX, assuming it compiles, you need to run X11.app. Running X software under X11.app is clumsy, because you don’t get the “normal” menu at the top of the screen. I do some open source development in my free time. Currently, I’m learning some Python by working primarily on applets for the Avant Window Navigator. I’d love to be able to run my projects on my Mac, but I can’t. I need to boot into Linux to do so.
  6. Filesystem Layout – When I do get to do UNIXy stuff on my Mac, at the command line, the layout of the filesystem is just bizzare. There’s a Dr. Jekyll/Mr. Hyde thing where Linux Ports go in /opt/local, and native apps go in /Applications. It’s weird.
  7. Microsoft Office – The OSX version of Office has a bizarre UI. Just personal preference. And it hasn’t been built for Intel Macs yet, so it runs under Rosetta, which is a little sluggish and makes it slow to start up. I haven’t tried the latest iWork yet, so maybe I don’t need it anymore. I could use previous versions of iWork because I wanted spreadsheets. I didn’t want OpenOffice because it needs X11.app. I didn’t try NeoOffice because I heard that people don’t like it… in fairness, I guess I should’ve tried it out. However, I already plunked down $125 for the “Student Version” of Office, so I just stick with it even though I don’t like it.
  8. Hardware Interoperability – Don’t believe the Mac Fanboys. In my experience, it doesn’t always “just work.” I have an HP printer that was very difficult to get working with my Mac under OSX. It was virtually plug-and-play when I dual-booted into Linux. Surprised? Yeah, me too.
  9. Customizability - This is both Linux’s strength and it’s downfall. In Ubuntu, If I want KDE, I use KDE. If I want GNOME, I use that. Maybe I’m minimalist and want XFCE. Perhaps I’d like a Dock, I use Avant Window Navigator. If I don’t, I can use the panel/kicker/whatever. I can add lots of eyecandy like wobbly windows with Compiz, or I don’t even need to install it. I can choose among hundreds of “themes” for each environment. Ubuntu (and other Linux distros) is just more conducive to tweaking. Truth be told, you can use a tool like Mac Pilot to customize some things, but the fact that I need to download a separate, third-party tool underscores my feeling that the whole OS X environment is generally less friendly to such things.
  10. The “Apple Tax” and other Misc. Expenses – A recurring theme among all of these bullet-points has been that I need to pay for stuff. When Leopard comes out, I’ll have to plunk down over $100 for the upgrade. Ubuntu’s Gutsy Gibbon will be free. So far, I’ve paid for Parallels (with one non-free upgrade), Office, a VPN client, and a raft of other software for my Mac. I haven’t spent one red cent on Linux software yet, and I don’t feel guilty about it because I’m contributing back to Open Source by donating some of my own free software.

So, there you have it. Having said all of this, I still love OSX. It’s polished, it’s stable, it’s pretty, and it works seamlessly with my iPod and my MacBook Pro (I can’t exactly say that for Linux… I did had to dork around w/ Ubuntu a bit to make it work well on my laptop). There are things I love about both operating systems, so it isn’t surprising that there are things that I miss in both operating systems. As a geek, I consider myself lucky to be able to use both of them!

Developing Applets for AWN: Drawing the Icon

Monday, October 8th, 2007

(Continued from previous two posts)
If you’re familiar with the Avant Window Navigator, then you know that a fair amount of the project revolves around eye candy and visual effects. Making an applet that is consistent with the user’s expectations with respect to visual effects (e.g., reflection, bouncing, rotating, etc.) is very important. Fortunately, Neil and Co. have made this quite straightforward. By simply sub-classing the awn.AppletSimple class, your applet will inherit all of the special effects that it should.

Unfortunately, there’s one small trick you need to work around. If your applet is so simple that it just needs a single, static icon, then sub-classing awn.AppletSimple, followed by a call to set_icon, works great. It gets more difficult if you need to draw dynamic content in the area usually occupied by the icon.

The problem is that set_icon (as well as its misunderstood cousin, set_temp_icon) takes a Pixbuf as its input parameter. However, the drawing framework for doing just about anything, especially loading PNGs, is cairo. Cairo has no native support for converting a surface to a Pixbuf. I discovered a trick for doing this by looking at the source code for the PyClock and BlingSwitcher applets. Let’s say you have a Cairo image surface that you’ve created from an existing PNG, thusly:

cs = cairo.ImageSurface.create_from_png(iconName)
ct = cairo.Context(cs)
ct.set_source_surface(cs)
ct.paint()

…and you want to get a Pixbuf from that image. The following function takes the surface, writes it to a PNG that is stored in a string, then uses the Pixbuf loader to load it from that PNG string:

# Stolen from diogodivision's "BlingSwitcher"
def get_pixbuf_from_surface(self, surface):
  sio = StringIO()
  surface.write_to_png(sio)
  sio.seek(0)
  loader = gtk.gdk.PixbufLoader()
  loader.write(sio.getvalue())
  loader.close()
  return loader.get_pixbuf()

Neat, huh? This is how I manage to display the temperature on the weather applet. I load up the icon into an ImageSurface, write the text on top of it by calling show_text, call the function above to convert the ImageSurface to a PixBuf, then call set_temp_icon using the new PixBuf.

You can see it in action by downloading the weather applet, and looking in weather.py. The relevant code is in the draw_current_conditions function.


© 2012 Mike Desjardins. All Rights Reserved.