Scripting for X Productivity
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.
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:
KeyToGrab(F1),WithModifier(None),WithAction(ExecCommand),\ DoThis(xterm -geometry 80x25 -e mutt)
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.
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.
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.
Listing 1. GUI Front End for an Internet Connection Script
#! /bin/bash /bin/rm -f /tmp/netsettings echo -n "PROVIDER=" > /tmp/netsettings Xdialog --menubox "ISP selection menu" 20 40 5 \ "ISP_1" "Lowest price in business hours" \ "ISP_2" "More economic on weekends" \ "ISP_3" "Fastest ftp server" 2>> /tmp/netsettings RETVAL=$? # add control code here echo -n "ACCOUNT=" >> /tmp/netsettings Xdialog --inputbox "Enter account name" 10 25 \ "son" 2>> /tmp/netsettings echo -n "LOGFILE=" >> /tmp/netsettings Xdialog -fselect /tmp 20 80 2>> /tmp/netsettings source /tmp/netsettings netconn $PROVIDER $ACCOUNT $LOGFILE
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.
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:
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.
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.
Articles about Digital Rights and more at http://stop.zona-m.net CV, talks and bio at http://mfioretti.com