Month of April, 2007

Adding Custom Actions to KDE Context Menus

One thing I always liked about Windows (compared to Linux) is that it's very easy to add custom actions to the context (right-click) menu for any given file types. For example, I used this ability with Universal Extractor to add UniExtract... entries to the context menu of archive files, and I use it with Open with Arguments to add Open with arguments... to .exe and .bat files. I missed that ability for quite some time once I began using Linux as my primary OS. Something as simple as extracting Zip files, for example, would require jumping to the command line and entering an appropriate unzip command[1]. However, a while back I stumbled across a tutorial entitled, "Creating Konqueror Service Menus", and was very pleasantly surprised to discover that this allowed me to do exactly what I had wanted for so long.

I setup a few custom actions (called "servicemenus" in KDE) a while back on my home system and pretty much forgot about it since it "just worked", but since I'm now using a new desktop system at home I'm already missing these custom actions. So, I figured I'd document them here while setting them up again. Hopefully this information will help out other Linux users. Much more thorough instructions can be found in the article referenced above - my instructions should be treated as more of a reference.

To begin, you'll need to create a new .desktop file for the action you want to perform. For the purposes of this article, I'm going to add a context menu item that will extract RAR files to the current directory. So, we'll create a new file named ~/.kde/share/apps/konqueror/servicemenus/rar.desktop. The file name is arbitrary, but it must be saved in the specified location, and must end with the .desktop extension. Next open the file in your favorite editor and add the following:

rar.desktop
[Desktop Entry]
ServiceTypes=application/x-rar,application/x-rar-compressed
Actions=unrar

[Desktop Action unrar]
Name=Extract Here
Exec=launch.sh %d unrar x \"%f\"
Icon=package

This code is not very intuitive, so I'll explain each option

  • ServiceTypes - specifies the type of files with which the action should be associated. The easiest way to determine this information is to run Konqueror, click Settings, Configure Konqueror, and select the File Associations section. Enter the file extension you want to associate the action with (in this case, rar, and then add the listed file types to the Service Types entry. Repeat for each extension if you want to associate with multiple types
  • Actions - specifies the name of the stanza that defines the action. Multiple actions can be specified, but we'll only use one here. Just make sure that the name entered here matches the [Desktop Action xxx] defined below.
  • Name - the name of the context menu entry that will appear when right-clicking on the given type of files
  • Exec - the action to perform when selected; more details below. Please also see this page for a full discussion of this item, including a list of valid field codes.
  • Icon - the name of the icon to associate with the context menu entry (optional). This can point to a real file if you want to use a custom icon, but you have to specify the full path and filename. In this case, I'm telling it to use the package icon from the current icon set. The easiest way (that I know of) to view these "pre-defined" icons is to right-click on any K-menu entry, select Edit Item, and click on the icon button for that item, It'll bring up an icon browser. Find the icon you like best, note the name, then close the windows and add it to the Icon entry.

Now, let's discuss the Exec entry. Ordinarily you'd probably want to call the binary directly; eg., unrar x \"%f\". In this case, however, I want to get feedback on the current progress of the operation, as well as any errors that might have occured. Since unrar is a CLI application, running it from a GUI wouldn't provide any feedback. It would simply run in the background and then exit. To work around this, I created a "wrapper" script called launch.sh that will accept arguments passed by KDE and run the command in a standalone xterm terminal[2]. Using this method, clicking the the action in the context menu will spawn a new xterm window, which will then display the current status of the operation. It will also allow you to enter any additional information that may be necessary, such as answering an overwrite prompt or providing an archive password.

The code for the wrapper script is listed below. The only dependency is that xterm must be installed in an your $PATH.

launch.sh
#!/bin/bash

# enable support for spaces
IFS=$'\r\n'

# check for number of arguments
if [ "$2" = "" ]; then
    echo "Usage: $0 <dir> <command>"
    exit 1
fi

# set directory and command
DIR=$1
shift
COM=$@

# execute command in xterm
cd $DIR
xterm -e $COM
exit

That should do it. Save both of those files, make sure that launch.sh is copied to a location in your $PATH, then try right-clicking on a RAR file. Under the Actions submenu, you should now see an entry called Extract Here. Click it, and if all goes well the contents of the RAR file should be extracted to that directory.

For reference, here's a list of all KDE servicemenus that I have created:

  • audacious.desktop - Enqueue and begin playing all selected audio files in Audacious (originally written for XMMS, and still contains the commented code if desired)
  • iso.desktop - Mount an ISO CD-Rom image in a subdirectory of the current folder to allow file browsing and copying; press Enter when complete to unmount the ISO and remove the temporary directory. This service menu requires my mountiso.sh script.
  • par.desktop - Repair damaged RAR archives using associated PAR files
  • rar.desktop - Extract contents of RAR archives
  • tbz.desktop - Extract contents of bzipped tarballs
  • tgz.desktop - Extract contents of gzipped tarballs
  • vmdk.desktop - Mount a VMware disk image in a subdirectory of the current folder to allow file browsing and copying; press Ctrl-C when complete to unmount the disk image and remove the temporary directory. This service menu requires my mountvmdk.sh script. More details can be found in the How to Mount VMware Disk Images under Linux article.
  • xine.desktop - Enque and begin playing all selected video files in Xine
  • zip.desktop - Extract contents of ZIP archives
  • launch.sh - Wrapper script to display service menu output in an xterm window; most of my servicemenus require this script

[1] Yes, I know that I can install a GUI archiving utility such as Ark. However, that's not really relevant here for two reasons:

  1. I want to right-click and extract directly withing Konqueror without first opening it in a separate utility
  2. File extraction is just an easy-to-visualize simple example - there are other cases where install a separate utility is not an option or just doesn't make any sense

[2] Yes, you could theoretically call xterm directly from the .desktop file rather than using a wrapper script, but I couldn't get it to work properly. I had issues with getting xterm and the associated command (in this case, unrar) to accept the correct path, as well as dealing with spaces in the filename. My wrapper script will handle anything that's thrown at it (so far, anyway...).

Lack of Updates

If it seems that I haven't spent much time working on my website recently, well, I haven't. :-) A whole lot has been keeping my busy for the last few weeks, including:

  • Accepting and preparing for a new job
  • Tying up loose ends at my old job before leaving
  • Purchasing/assembling/installing Gentoo on a new desktop system (which takes a while to work out all of the kinks)
  • Shopping/purchasing a new laptop since I lost my work-provided system

That's the highlights, but I've been dealing with some other stuff as well. I have some projects I'm trying to get done before I start my new job on Monday, and of course once I do begin my new job I'm sure it'll keep my busy for a while. So, to be honest I don't know when I'm going to be able to start posting regular updates again, but hopefully it won't be too far off.

One important task I'd like to finish up is putting out an update for Universal Extractor 1.5.1. I had mostly completed it about a month ago, but just haven't had time to fix a couple remaining issues and get the updated translation files. I'd like to start working on that again this weekend if I can finish my other projects in time, so keep an eye out for it in the next week or two.

LegRoom Changes, Part 3

For my third and last post in this series, I'd like to discuss overall site management design changes. Prior to this latest change, I had always run LegRoom off of PostNuke. Now, PostNuke has been good to me over the years. It's been around for a while so it was a pretty mature product even in 2002, it has a huge community behind it, and it's been flexible enough to let me do pretty much anything I wanted during the previous couple redesigns. I'm very appreciative of all the hard work that the PostNuke devs and community have put into the product, and I certainly do no regret choosing PostNuke for my site.

With the latest redesign, however, I felt the need for something different. I could've just slapped a new theme on top of my PostNuke install, as I did previously, but I really wanted to migrate to a new content management system altogether to give me a chance to truly redesign the site from the ground up, as well as clean out a lot of the cruft that had been gathered over the years (see Part 2 for some examples of this). Additionally, while PostNuke was a capable and mature CMS, I wanted to move away from it for three main reasons:

  • Development progress seems almost non-existent. Take version 0.8, for example. If I recall correctly, initial development of 0.8 began in 2003, possibly even 2002. However, version 0.8 has still not been released. Now, I'm quite sure there are a lot of factors contributing to this delay, and I don't even pretend to know all of the facts, but just from a pure end-user perspective this is ridiculous. There have been minor updates to the 0.7x branch during that time, but to go so long without a major release gives the impression that either development is stalled or non-existent, there are severe technical difficulties involved (which can shake confidence in the developers involved), or there are severe personnel and/or communication difficulties within the developer community (which, again, can shake confidence). Personally, I just got tired of waiting.
  • PostNuke is a heavy system, and the generated output (at least from my older version) was just plain ugly. I wanted a CMS that produces cleaner, more efficient, and standards-compliant code, something that doesn't use several levels of nested tables for positioning. From what I read, this situation has supposedly improved significantly in the current PostNuke releases, but that doesn't help me much because of the next reason.
  • In order to make PostNuke work how I wanted, I had to make some fairly extensive modifications to the codebase. I completely rewrote the menu generation code and RSS publication module, for example, as well as made various changes here and there to several of the other modules. The problem with this approach is that it makes an in-place upgrade nearly impossible. The end-result is that I was left running an extremely vulnerable version of PostNuke for several years. I was honestly surprised that I was able to hold off the hackers until I was able to complete the Drupal migration. Now, this isn't PostNuke's fault in any way, but simply another factor that has to be considered. I need a CMS that will do what I want without requiring modification of the codebase. PostNuke couldn't provide that.

So, after a rather extensive search, I settled on Drupal. As of version 5.0 it seems to offer the best combination of capability, flexibility, efficiency, and standards compliance out of all of the open source CMSes that I examined. (By the way, I'd really like to thank the admins of OpenSourceCMS for making it easy to "test drive" so many website management systems. If you're a webmaster that's not familiar with this site, check it out ASAP.)

So, aside from the CMS change, what else is new? While migrating all web content over to the new site I spent a lot of time "updating" all content to use a specific look and feel. My previous site was something of a testing ground for me, and was originally started when I just didn't know much beyond pure HTML. Each page that I added to the site was essentially created using whatever level of experience I had mastered at the time, resulting in a hodgepodge of styles and techniques. This is especially true of the Tips and Tricks pages, of which some had to be nearly completely rewritten. Now, however, I was able to apply the same coding styles uniformly across all pages on the site. Yay!

In addition to the common style, you may also notice a common layout for all of the pages. Each has a navbar across the top that will take you to any location in the page. Each page is broken up into the same sections, where appropriate, for consistency and easy of use. I also added section breaks, along with "return to top" links, to cleanly separate each section. These are a lot of subtle changes, to be sure, but they really do a lot to enhance site usability.

Other page-specific changes:

  • The Bookmarks page is now properly styles to match the rest of the site (thanks again, Steve)
  • As previously mentioned, I added a new Coming Soon section
  • DailyStrips has also been restyled to match the site, including rewriting the output engine to work better in the context of a website module (and no more tables!)
  • The Metasearch page (aka, Search Internet) has been tweaked and has had a couple more sites added

I think that pretty much covers it. I hope you enjoyed this brief look into the redesign process for this site. Up next - the conversion script I used to migrate from PostNuke to Drupal. It is truly one of the most ugly pieces of code I've ever written, but it got the job done. As promised, I'll make it available to everyone else to use, along with an explanation of the details and shortcomings of the script. I just need a bit more time to clean it up and write the details.