WindowMaker Menus in a Distributed Environment
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 (www.kde.org), Gnome (www.gnome.org),
WindowMaker (www.windowmaker.org), 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
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 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: http://www.sysadminmag.com.)
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 docklinks.pl*
-rwxr-xr-x 1 root other 1431 Feb 22 16:17 launch.sh*
lrwxrwxrwx 1 root other 9 Jan 25 09:41 moon -> launch.sh
lrwxrwxrwx 1 root other 9 Feb 2 15:04 netscape -> launch.sh*
lrwxrwxrwx 1 root other 9 Jan 25 09:41 raven -> launch.sh*
I'll use /usr/local/menu/netscape in my examples. Notice
that the file "netscape" is nothing more than a symbolic
link to launch.sh. In fact, all of the menu links are
nothing more than symbolic links to launch.sh.
launch.sh is shown in Listing 2. Because this is the heart
of the menu system, I'll discuss the highlights of this script.
First, launch.sh 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, launch.sh 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.
launch.sh 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.
launch.sh greps for the command name, then pulls the name
of the remote host from there. If there is no entry in the aliases
file, launch.sh 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, launch.sh 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, launch.sh 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 (http://www.ssh.com/) and OpenSSH (http://www.openssh.org/)
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 launch.sh to <command>. Add an entry in
the alias.<hostname> file, keyed to the name of the
remote server, like this:
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 docklinks.pl will expand
to /usr/local/menu/netscape. The filename should be just
as reported in the error window (Figure 2).
Running the Perl script docklinks.pl (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
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
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 docklinks.pl. 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
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
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: firstname.lastname@example.org.