Scripting for X Productivity

Bend X to your will with scripting tools, keyboard customizations and dialog boxes.

Linux offers graphical user interfaces
(GUIs) with high
resolution, multiple windows and menus. But with a GUI, human/computer
interaction is the real speed bottleneck: as long as doing something requires
ten mouse clicks in ten different points, it takes the same amount of
time, regardless of the hardware.
At the command line, the traditional UNIX answer is the toolbox
philosophy. You can automate anything with a script and connect small
specialized programs with pipes.
A third solution combines the two approaches and is easy and
powerful enough to suit most needs. Any stock X environment, regardless
of the window manager or desktop environment, can become much faster
and more flexible than it usually is.

Making Your Own Mouse and Keyboard

We have more fingers than hands and 101 keys to one
mouse. Although drawing and similar tasks are quicker with mice or tablets,
often our fingers must stay on the keyboard anyway. If a command
or choice requires one single user action, pressing a key or two is much
faster than clicking mouse buttons, not to mention RSI issues. Also,
when we do touch the mouse, it should do what we need immediately.

Keys and mouse buttons can be shuffled around or mapped to
specific meanings (accented vowels) or GUI actions (maximize window)
using xmodmap. One of its beneficiaries has been left-handed people,
who use it to reverse the order of the mouse buttons. Add this line in .xinitrc, or put
the quoted part in a .xmodmaprc file:

xmodmap -e "pointer = 3 2 1"

Lately, xmodmap has been used to make mouse wheels work correctly under
Linux (see Resources). It also can make wheels work faster by binding your most frequent
actions to those extra keys available on the latest keyboards. For
example, the magic line for an IntelliMouse Explorer is:

xmodmap -e "pointer = 1 2 3 6 7 4 5"

When speaking about keyboards, modifier means a key that changes the
effect or state of other keys. The standard modifiers are Shift, Ctrl,
Lock, Alt and five more simply called modN, with N=1,2..5. xmodmap can
assign these meanings to any physical keys. The most frequent case is
probably the swapping of the Ctrl and Caps Lock keys, described in the man
page. On the same note, the meaning of the Windows key could be changed
to mod4 in this way, assuming its keycode is 115:

xmodmap -e 'keycode 115 = Alt_R Meta_R'

Keys can be programmed to start applications too, but this is
specific to window managers. In Blackbox 0.65, for example, keystrokes
are mapped to programs with the bbkeys utility. A line like the following
in $HOME/.bbkeysrc:

would allow you to start mutt in an 80 × 25 xterm window by simply pressing F1. Many
other window managers allow such bindings; check their documentation.

Point-and-Click Scripting

As already mentioned, any shell script can be given windows to
enable communication with the user, and any graphical client (and X itself)
can receive direct input from text programs. The first case happens when
a shell script needs user interaction, but it isn't possible; say
the user would rather die than type or there isn't a
keyboard (Internet kiosks). The second scenario includes users who need to pass some unpredictable
text to an X client from console programs without manual cut-and-paste
capabilities. This does happen in real life: mutt and lynx may be
all we need to read e-mail and surf the Net, but what if some e-mail or
Web page says “Check out this movie preview”, and you want to start
Mozilla on that page with one click.

Giving Windows to Shell Scripts

Starting an X window from a script has been possible for at least
ten years, with tools like the now defunct Xscript. A modern solution is
Xdialog, a GTK+-based widget generator. The script in Listing 1 shows
an almost real-life example; it lets the user choose the best ISP,
the account to be used and where to log the connection report. It then
starts a traditional pppd/chat script (called netconn in the example),
passing to it all the parameters collected graphically. Let's
examine the GUI side in detail.

The script starts removing the old version of the netsettings file,
which stores all the user choices. For each variable needed by
the netconn script, an assignment line in bash syntax is written
to /tmp/netsettings. The left part simply is echoed without newline
(echo -n). The second part, the actual value chosen by
the user, is captured by Xdialog.

Figure 1. Invoking Xdialog

The first invocation (see Figure 1) allows the user to choose the
best ISP. We also added some explanatory text (ISP selection menu)
and specified the height (20) and width (40) of the window, as well as the
height of each entry (5). In the case of Figure 1, after the user presses
the OK button, /tmp/netsettings will contain this one line:

PROVIDER=ISP_1

Error checking can and should happen by saving the exit code
of every call to Xdialog in a variable (RETVAL in Listing 1) and
checking it to know what the user really did. We omitted this code for
brevity, but keep in mind that a RETVAL of 1 means “Cancel
pressed”; 255 means the user closed the box, and 0 means
a choice actually was made.

The second Xdialog command allows the user to type in an account name
or to accept the default value (Figure 2). The
last one (Figure 3), displays a file selection window in which one can
type or select with the mouse the name and location of the
current log file. At this point, all the user choices are in
/tmp/netsettings, so we simply must source that file and launch the
connection.

Figure 2. Entering the Account Name

Figure 3. Finding the Log File

Xdialog offers many more types of input widgets, from radio buttons to range
slides and calendars. Quite a few of these provide feedback to the
user. The author uses the --msgbox option, for example, to pop up a window listing how
many messages have been downloaded by fetchmail, sorted by account. Other
possibilities include gauge and progress bars, info boxes with timeouts
and file display windows. Consequently, Xdialog can be attached to
scripts doing CD burning, audio and video playback, backups—you name it.

What if the same script must be used when X is not running? No problem;
menus and boxes can be drawn in character terminals, too. Simply use the
character-oriented equivalent, dialog.