Cover V10, I07
Figure 1
Figure 2


Simplifying WindowMaker Menus in a Distributed Environment

Anthony Taylor

Choosing a window manager for a distributed system is tough. When a single system serves up the desktop for many users, the window manager must be efficient; there's always a trade-off between functionality and memory and CPU use.

When we at Southeast Alaska Regional Health Consortium (SEARHC) moved to the SunRay thin client, we left behind X terminals and ncdwm (the mwm-like window manager). Although mwm (Motif Window Manager) was a mainstay of the X desktop, it definitely shows its age. mwm takes the role of window manager very literally; it restricts its job to window decorations (titlebar, minimize/maximize buttons, window frame, etc.) and a simple menu used to launch applications.

The move to the SunRay device was an opportunity to change to a more modern window manager. In our quest for the perfect balance of ease-of-use, power, and low memory footprint, we tested several desktops, including KDE (, Gnome (, WindowMaker (, and the Solaris default desktop, CDE. There are many other excellent window managers, but these were the only ones we tested.

During testing, it became apparent that the full-fledged CORBA-enabled KDE and Gnome desktops were too memory- and CPU-intensive to be a viable option for us. Although both are excellent workstation environments, the resources required would have been much too expensive.

On the test system, a 300-MHz Sun Ultra 10 with 512 MB RAM, both KDE and Gnome would comfortably handle about 4-5 users. Adding more memory would certainly have increased that number, but would have defeated the point of the test -- to get a rough idea of the resource requirements for the various desktops.

Both CDE and WindowMaker appear to have similar memory requirements. CDE is a technically advanced window manager, but WindowMaker is easier for non-technical users. WindowMaker also has a menu system similar in functionality to the mwm menu, easing the transition from ncdwm.

Running either CDE or WindowMaker on the same Ultra 10 supported nine users with memory to spare. Ultimately, our very precise and extremely scientific research results pointed to WindowMaker as the best option in terms of memory, usability, and manageability. Note that although we used the SunRay network device for the desktop, the problems and solutions presented here are applicable to any distributed X Window system-based desktop -- whether the underlying hardware is thin client, X terminal, or workstation based.

WindowMaker Unplugged

WindowMaker is designed after the NeXT desktop. It sports a versatile menu system, easy configuration, and a "dock." A configuration utility is included, which greatly simplifies end-user customization of everything from focus behavior to desktop themes.

The dock is a special icon on the desktop that resides along one side of the screen. Other icons are placed on the dock by dragging them to the dock; applications are then launched by simply double-clicking the icon on the dock. Several applets can be docked as well, such as the calendar and CPU meter in Figure 1.

The menu is accessed by clicking on the background with the right mouse button. The menu itself is a simple text file, but submenus can be directories filled with executables (in which case the menu items are listed as the names of the executables), programs that return menu structures, or internal commands. This provides great flexibility in designing and implementing dynamic menus.

WindowMaker in a Distributed Environment

The SunRay architecture is a strange mix of thin client and X. The Xsun server process running on a SunRay server is displayed to the SunRay client device. This makes the clients extremely inexpensive, reducing total cost of ownership. This savings on the client side is offset somewhat by the additional server resources required to run the window manager. However, in the final analysis, it is still a cost-effective desktop.

SEARHC has three main sites using SunRays. While implementing WindowMaker, we used a single menu for all three sites to keep the menus from diverging. Since each site runs their applications from different servers, we needed a method for selecting the appropriate server for each site, while maintaining a homogeneous menu.

Listing 1 is a very abbreviated menu. It has two main entries, a regular submenu, a couple of filesystem-based submenus, and a standard "Exit" submenu. Note that most of the menu entries reference files in /usr/local/menu. We decided to place our homegrown menu framework in this single non-standard directory to make maintenance easy. (Listings for this article are available from the Sys Admin Web site:

This is the content of /usr/local/menu:

-rw-r--r--   1 root   other   322 Feb 22 16:18 aliases.razor
-rw-r--r--   1 root   other   219 Feb  2 11:29 aliases.turing
-rw-r--r--   1 root   other   158 Jan 25 10:15 dockinglist
-rwxr-xr-x   1 root   other  1088 Jan 25 10:17*
-rwxr-xr-x   1 root   other  1431 Feb 22 16:17*
lrwxrwxrwx   1 root   other     9 Jan 25 09:41 moon ->
lrwxrwxrwx   1 root   other     9 Feb  2 15:04 netscape ->*
lrwxrwxrwx   1 root   other     9 Jan 25 09:41 raven ->*
I'll use /usr/local/menu/netscape in my examples. Notice that the file "netscape" is nothing more than a symbolic link to In fact, all of the menu links are nothing more than symbolic links to is shown in Listing 2. Because this is the heart of the menu system, I'll discuss the highlights of this script. First, ensures that the PATH environment variable is set to included common program directories. This would be customized depending upon a company's local policy.

Next, iterates through the command-line arguments, stripping out the -display options. This is necessary because of the way the dock works (which I will cover in a moment), and the way the SunRay server handles Xsun display names. This step also collects the command line into a single variable, $args. This simplifies program invocation in the last step. then determines the name of the machine on which it is running. It uses this name to determine the machine from which it should run the menu pick. This customization is kept in the file aliases.<machinename> (Listing 3), where <machinename> is the canonical name reported by uname -n.

The next step involves the little-used shell variable $0, which is the name of the program being executed. Since the program name is /usr/local/netscape (in this example), that is the contents of $0. Stripping the path part of the command leaves us with "netscape". The grep bit merely determines whether $0 is a bare command, or contains a path. If it does contain a path, the sed statement strips out everything before the final /.

This trick is useful any time you find yourself repeating a command, changing only one parameter. Simply create a single script, and create a symbolic link based on the single parameter you wish changed. There is great precedence in UNIX -- as an example, consider this symbolic link:

ln -s /usr/bin/rlogin /usr/bin/razor
Invoking the command razor will cause rlogin to try to rlogin to the machine named razor.

Now that we have the name of the program we wish to run, we determine which server to contact. This is where the aliases.<hostname> file comes in. A sample aliases file is in Listing 3. greps for the command name, then pulls the name of the remote host from there. If there is no entry in the aliases file, assumes the command name is also the name of the remote machine. This works particularly well for machines that provide one service. For instance, we run our RPMS medical database on dedicated systems. Those systems are known by their hostnames -- Raven and Moon. This allows an alternative to the /usr/local/menu/aliases.<hostname> file: add an entry to the /etc/hosts file instead, with the IP of the remote host keyed to the name of the command.

One special alias is "local." An entry assigned to "local" runs on the same server as WindowMaker. Some would prefer no special case; if a command does not appear in the aliases file, it is assumed to be local. This is personal preference. The script could be adjusted to either preference; also, this would do away with the /etc/hosts alternative, which some may prefer.

Next, sets up the remote PATH and DISPLAY environment variables. Since the C shell uses a different syntax from the Bourne and Korn shell, we adjust the commands appropriately. Finally, executes the command remotely using rsh.

The remote command is exactly the same as the symbolic link called from the menu. In this example (/usr/local/menu/netscape), the command will be "netscape". Because /usr/local/bin is guaranteed to be in the path (since we explicitly add it to PATH), "netscape" can be a shell script that resides in /usr/local/bin on the remote machine.

A Quick Note on rsh and Security

Many systems administrators consider rsh insecure. This is a valid concern; opening your system to rsh takes careful planning. Both SSH ( and OpenSSH ( are excellent and more-secure alternatives, with stronger authentication and stream encryption. The security-minded sys admin should consider ssh or OpenSSH.

Adding a Menu Item

Adding a new menu item to WindowMaker is pretty straightforward. Simply add an entry to /usr/local/etc/WindowMaker/WMRootMenu (the menu file, as shown in Listing 1), and make the command /usr/local/menu/<command>. In the directory /usr/local/menu, create a symbolic link from to <command>. Add an entry in the alias.<hostname> file, keyed to the name of the remote server, like this:

<remoteserver>: <command>
You can list more than one command per entry.

This means editing three files instead of one (the WMRootMenu); but for sites with multiple desktop servers, the menu system (including WMRootMenu) can be copied wholesale from one machine to the next, maintaining consistency across all desktops.

Installing on a new server is quite simple -- just copy the WMRootMenu file, and the contents of /usr/local/menu, to the new desktop server. Then create an aliases.<hostname> file for the new server.

Using the Dock

The dock is a convenient feature of WindowMaker. Residing along either side of the workspace, the end user may place often-used application icons in a convenient location. Applications are then available with a double-click on the appropriate icon.

WindowMaker assigns an icon to each running application. These icons are generally placed at the bottom of the workspace; as more applications are launched, icons collect along the bottom. Each icon is associated with a single running program. For example, if the user launces two copies of xterm, the "icon box" will contain two xterm icons.

The user may drag one of these icons to the dock. The icon then becomes a persistent part of the desktop, and the user may launch the xterm simply by double-clicking on the icon. When the icon is docked, WindowMaker queries the window for the program name. However, WindowMaker assumes the program was launched from the local machine. This network ignorance results in error messages (like that in Figure 2), as WindowMaker tries to launch the program from the local machine.

To hack around this problem, I install shell scripts in place of the application. So, using the error message from Figure 2, I install a shell script named /usr/netscape/netscape that simply calls /usr/local/menu/netscape. This ties the docked icons with the script that launches the application. Because I'm lazy, I wrote a Perl script to automate the management of these scripts (Listing 4). This Perl script simply iterates through the file /usr/local/menu/dockinglist, making a customized shell script if the file does not already exist.

/usr/local/menu/dockinglist is a simple file, as illustrated in Listing 5 -- it is simply a key, followed by a filename. The key is the same as the file used to launch the application -- in this example, netscape, which will expand to /usr/local/menu/netscape. The filename should be just as reported in the error window (Figure 2).

Running the Perl script (Listing 4) will step through the dockinglist file, creating (on the local machine) the shell scripts necessary to launch the applications from the remote machine. The script will create any required subdirectories, as well.

It's Not as Complicated as It Seems

Really, the process is pretty simple, once the infrastructure is in place. Simple follow these easy steps:

1. Edit /usr/local/etc/WindowMaker/WMRootMenu. Add an entry for each new application; the executable bit should point to a link in /usr/local/menu.

2. Create a link in /usr/local/menu. This should correlate to the WMRootMenu entry from Step 1.

3. Add an entry to /usr/local/menu/aliases.<machinename>. Associate the application with its server, so the menu system knows where to go.

4. Make sure the application is in the path on the remote server.

The command from Step 2 should also work on the remote machine. For instance, if we are adding /usr/local/menu/netscape to our menu on Razor, our WindowMaker host, and netscape resides on the server Helios, we must make sure the command netscape is in the path on Helios. The simplest way to accomplish this is to create a script called netscape on Helios, in /usr/local/bin, a directory that is guaranteed to be in the path.

At this point, the menu pick for "Netscape" should work. Now we have only to make Netscape cooperate with the dock.

5. Add the command to /usr/local/menu/dockinglist

Launch the program (netscape, in our example) from the menu. Dock the resulting icon. Exit the program, then attempt to launch the program from the docked icon. The resulting error message will tell you specifically which command the WindowMaker dock is attempting to run.

6. Run This will create a shell script in the location the dock expects to find the application.

At this point, the docked icon should also work.


Although these troubleshooting tips are geared to Solaris, they can (generally) be applied to other operating systems. Although the names and locations of log files may differ, there should be similar log files on all makes of UNIX (and Linux).

If you run into problems, you can check the contents of /var/dt/Xerrors for clues. Often the problem is "command not found," or something similar. This indicates that the command being run from /usr/local/menu on the local WindowMaker machine does not have an equivalent command on the remote application server.

Try running the command in /usr/local/menu by hand (with the DISPLAY environment variable set appropriately, of course). If the application launches successfully, check the menu entry in /usr/local/etc/WindowMaker/WMRootMenu.

If the application launches properly from the menu, but not the dock, ensure the file (as reported by the error window that WindowMaker should pop up) exists. If it does not, add the appropriate entry to /usr/local/menu/dockinglist. If it does exist, check the type and contents of this file.

If you get an "unknown host" error in /var/dt/Xerrors, make sure there is a proper entry in /usr/local/menu/aliases.<machinename>, where <machinename> is the canonical name of the local machine as reported by uname -n.


This wraps up the tour of SEARHC's ad hoc menu system for WindowMaker. For small installations, where WindowMaker will have only one or two hosts, this may be overkill. But for larger installations, a good menu-management system is needed. Also, the menu system employs a few interesting techniques -- the use of the $0 variable in shell scripts, configuration files to control the behavior of the shell scripts, and the automation of shell script creation using Perl. A shell script could handle this last step just as easily, but I enjoyed using Perl. And isn't having fun what it's all about?

Anthony Taylor is the Senior DBA for Southeast Alaska Regional Health Consortium. He occasionally takes time from his busy day of slacking to simplify his life with rococco menu systems and opaque scripts. He can be reached at: