Saturday, January 24, 2009

gschem, log files and X selections

Just over a week ago, I posted a series of [RFC] posts to the gEDA-user mailing list suggesting six reasonably non-trivial changes to libgeda and gschem. Although the discussions they started off weren't quite as productive as I was hoping, they did attract quite a bit of interest.

I haven't been afraid to put my money where my mouth is. Since then, I've implemented two of the changes I suggested: a modification of the way gEDA apps create logfiles, and support for copying and pasting bits of schematics between gschem windows. I thought I'd post here to explain the amount of careful design work that goes into even relatively minor changes to the gEDA suite.


Historically, gschem (and the other gEDA apps) have created logfiles in the current working directory when they were launched. This behaviour quickly resulted in a user's home directory becoming littered with the files, gschem.log files especially.

My initial suggestion was to just not create log files by default, and require users to specifically enable them. However, it was quickly pointed out that since one of the most common reasons for gschem failing to start was that a new user had made a mistake in their configuration file, and that it would be best to carry on with generating logfiles as the default behaviour.

Instead, it was suggested that the logfiles should be put in a centralised, out-of-the-way location, and ~/.gEDA/logs/ was suggested, with the caveat that it would be necessary to make sure that multiple copies of gschem accessing the directory would have to be supported safely, even on different machines, but also that a user could quickly easily find the most recent log file -- so just adding a random suffix with mktemp wouldn't work either!

Having worked out a way of doing this (a secure algorithm for generating sequentially numbered, dated log files), I then realised that on some operating systems, such as Microsoft Windows, $HOME might not even be defined, and that there might be platform-specific differences in the standardised place to keep configuration data. Since the gEDA applications had no existing way of handling these variations, I ended up abstracting out the methods for locating the system and user data and configuration files, and updating all of the gEDA apps to use them.

All in all, changing the location where log files are stored used up at least eight hours of development time.

Clipboard copy, cut and paste

For a long time, gschem has supported copying and pasting schematic data between pages and windows in the same gschem process, but it was never made clear to users that this mechanism didn't use the X clipboard, and thus sometimes copying and pasting didn't work when it would have made sense for it to.

X Window System selections are complicated. There are two selections normally used by X applications: the PRIMARY selection and the CLIPBOARD selection. Traditionally, the PRIMARY selection is contains the most recent piece of text selected by the user with the mouse, and can be pasted by clicking the middle mouse butten, while the CLIPBOARD selection is accessed via "copy" and "paste" actions explicitly invoked by the user. In order to match up with other applications (and because nothing like the PRIMARY selection is available on Microsoft Windows or OS X), we decided to use the CLIPBOARD.

For the same portability reasons (and also because the raw X API is horrendously complicated), we decided to use the GTK Clipboard API to manage the clipboard.

A neat feature of clipboards (and X selections in particular) is that it's possible for the source application to provide the data in different forms, depending on what the "pasting" application wants. We needed a format for transferring between gschem instances, so we decided to use the gEDA schematic format (application/x-geda-schematic). Fortunately, as part of my rewrite of the symbol library back in mid 2007, I'd made libgeda able to "load" and "save" schematics from memory buffers, so I simply hooked the clipboard code into that and things started working!

I then, of course, had to work through the boilerplate required to update the GUI to support it. This took as long as implementing the actual feature.

I've also been working on some other features, using some code that I've had floating around for a long time. But more of that another time!

No comments: