The Best Without X

Alessandro Rubini

Issue #19, November 1995

Small computers, especially those with little memory, don't run the X Window System—or any other graphic environment—very smoothly. An intelligent keyboard configuration and use of the gpm mouse server will help you exploit your small Linux box to its fullest.

If your system doesn't run X-Windows, you may miss the mouse support that makes interactive programs so easy to use. gpm, the general purpose mouse server, is designed with you in mind. Instead of having a multitude of mouse drivers, several from each mouse vendor, some that work well, others that don't, you can run gpm, which can talk to all mice, and works quite well. This article explains how to set up gpm to work with your mouse and programs, and also explains how to set up your text console to work the best for you.

The gpm program is derived from the older selection program, which was solely for cut-and-paste on the Linux console. gpm acts like selection until a client requests mouse events. Because gpm manages each console as an independent entity, you can use your multi-console text screen like a multi-window graphic environment. This article refers to gpm-1.0.

Configuring the Mouse Device

One major problem with Linux is hardware compatibility, and the mouse is no exception. Companies are always releasing new mice, and each of them provides a different mouse driver for DOS. Linux users are left alone with their device and no driver. Fortunately, companies tend to converge on a few “standard” protocols, which are supported by both XFree86 and gpm. Moreover, the gpm package includes gpm-test, which can help in detecting your own mouse port and protocol, and which suggests which command-line options you should use to invoke the daemon.

You must provide the protocol name and options to gpm on the command line, together with your own preferences. These will affect all mouse response until the server dies. One preference allows button reordering: left-handed people can reorder the buttons by using the command line option -B 321, and owners of two-button devices can use -B 132 to use the right button as if it were the middle one, a useful way to paste the cut-buffer in Emacs without modifying Emacs itself. The current version of the gpm server duplicates the functionality of both mconv2 and MultiMouse, and can act as a “repeater”. You can merge the events from two different devices and pass them along to the X server. This is useful if you use a laptop with both an internal pointer and an external mouse. If you'd like to use one mouse in each hand but keep the internal trackball active, however, gpm can't help you—no more than two mouse devices can be read at a time.

The “repeater” option is automatically enabled if you read two mice, but can be triggered independently; if you use gpm as a repeater, the X server can be configured to read /dev/gpmdata, a fifo named pipe, where gpm puts mouse packets received while the console is in graphic mode. This option is meant to be used by owners of busmice who want to multiplex text-only and X operation without killing and restarting the daemon. Owners of new dual-mode mice, which run the three-button protocol only if the middle button is kept down at mouse initialization, will enjoy it as well, because the device is initialized only at boot time.

How Does gpm Work?

The core of the gpm daemon is currently built around the select()system call and the process runs in the user space of the systems memory. The main loop of the daemon listens to a Unix-domain socket and to the mouse, and uses them in conjunction to multiplex event retrieval and management of new clients. The main loop of gpm can be (and has been) used to build a concurrent daemon for network services by modifying just a few details.

The choice of a user-space server for the mouse was originally meant to help owners of low-end boxes—the process could be swapped out when not in use and thus save a little precious memory. Unfortunately, when you use Emacs, a perceptible delay in delivery of mouse events can severely degrade performance, and combined use of mouse and keyboard is completely unreasonable on a slightly loaded machine.

The swap-in delay can be removed by locking the process in memory, but in the case of Emacs two processes should be locked in memory. The goal for gpm-2.0, which will supersede the current version, is to provide the choice between a user process and a kernel module. The advantage of running a kernel module is mainly fewer context-switches (and no swap-in delay whatsoever), while the main disadvantage is the waste of memory. The module alternative will offer the same interface to client applications, but will use a device node instead of a socket.

Configuring the Keyboard

The Linux keyboard is fully customizable (could you doubt it?) and can be tailored for smart text-only usage. The idea is to reduce context-switch time to get more performance out of your multitasking brain. This is the basic idea behind virtual consoles.

Here are some suggestions for improving your keyboard. I will describe some of the useful changes to make, and then give the appropriate lines for the loadkeys program to effect the change.

  • Caps_Lock: Why have a “Caps Lock” key near the “a” key? When caps lock was useful to write silly BASIC programs they put it far from alphabetic keys; now that it is not so useful, they turned it to a trap for your little finger. Just get rid of it and turn it into a Control key.

    alt-CapsLock will still yield CapsLock
    keycode 58 = Control
    control keycode 58 = Control
    
  • Control: The Control key on the bottom-left corner is a duplicate of the one we put by the “a”. You can turn it into Last_Console and thus have a fast editor/compiler context switch. Moreover, this makes your wrist useful in typing. Last_Console switches to the previous console you visited, and is one of the several exotic capabilities of the Linux keyboard.

    keycode 29 = Last_Console
    
  • The Numeric Keypad Unless you're used to desktop calculators, the numeric keypad is too far in the right to be useful in typing digits, and can be turned to a console-switch scratchpad: hitting Alt-F8 takes a whole hand, and Alt-F1 isn't easy, either, at least on keyboards with the function keys at the top. Similarly, X-Windows users can configure the keypad as a map to their virtual desktop, provided that the Num_Lock key is left alone: xmodmap can't differentiate a non-Num_Locked keypad from the arrow keys. The “0” key then is suitable to be another Last_Console, useful if you didn't get rid of Caps_Lock.

    keycode  29 = Last_Console # KP_0
    keycode  79 = Console_1    # KP_1
    keycode  80 = Console_2    # KP_2
    keycode  81 = Console_3    # KP_3
    keycode  75 = Console_4    # KP_4
    keycode  76 = Console_5    # KP_5
    keycode  77 = Console_6    # KP_6
    keycode  71 = Console_7    # KP_7
    keycode  72 = Console_8    # KP_8
    keycode  73 = Console_9    # KP_9
    keycode  98 = Console_10   # KP_Divide
    keycode  55 = Console_11   # KP_Multiply
    keycode  96 = Console_12   # KP_Enter
    keycode  78 = Console_13   # KP_Add
    keycode  74 = Console_14   # KP_Subtract
    
  • Home and End It can be useful to configure Home as Control -a and End as Control-e. This works with bash, tcsh and Emacs, without any other fiddling.

    keycode 102 = Control_a
    keycode 107 = Control_e
    
  • Escape: If you are used to Sparc2s, old PCs, or the old faithful Apple II you'll enjoy putting the Esc key near the “1”. This change forces you to reposition the backtick/tilde pair as well. The exact change made here may not work on your keyboard, you'd better check your keycodes with showkeys.

    keycode  41 = Escape  # Escape
    alt     keycode   1 = Meta_Escape
    # recycle grave/asciitilde near the Enter key
    keycode  43 = grave   # asciitilde
    control keycode  41 = nul
    alt     keycode  41 = Meta_grave
    
  • Backslash: The backslash/bar pair should be near “Z”, where the default keyboard configuration puts a duplicate of less/greater.

    keycode  86 = backslash        bar
    control keycode  43 = Control_backslash
    alt     keycode  43 = Meta_backslash
    

The modifications listed above work with my keyboard. Check your actual keycodes using showkeys before applying these changes. showkeys is part of the kbd package. If you're a real typist, you can make something really useful out of the twelve function keys. Read the keytables(5) man page to probe further. For more information on how to modify the keyboard, see Kernel Korner in Linux Journal #14.

Spawning New Consoles

“Why should I use the numeric keypad to switch between 15 consoles when I only have 6?” I hear you say. Linux can handle a s many as 63 virtual console, and 6 (or whatever else) is only the number of “login prompts” configured in your system. Actually, consoles are dynamically created and destroyed during your system's lifetime.

The different login: prompts are spawned by the init process, which knows what to do by reading the file /etc/inittab; this very file specifies where getty should be invoked. You can play with inittab even if you don't completely understand it: to open more (or fewer) than 6 consoles for login, you can simply duplicate (or remove) lines. You must be careful, however, about the first field in the line—it is a unique “key” for the line, and it must be exactly two letters long.

My choice for console login sessions above 9 is cA, cB and so on, with the first nine entries c1 through c9.

A more interesting, and memory-saving, approach to your Linux session is to spawn only one or two gettys using /etc/inittab, and dynamically allocate other as you need them. There are a number of ways to spawn a new console:

  • gpm-root: This tool can spawn a new getty on the lowest-numbered free console in your system: just press control-mouse to wake the program, then press the mouse button again on the correct menu entry, and you will soon be presented with a newly-created login: prompt—it's that easy. When you log out from that console, everything is cleaned up automatically. This way of spawning consoles has the advantage that the /etc/utmp file is kept up to date, and thus the who command tells you the truth.

  • open: The tiny open utility spawns a new console and executes a program in it. You can use loadkeys to create a hot key which invokes open. Thus a single keypress (or meta-key) can log you in. This approach doesn't update the utmp database and works only when the hotkey is fed to a shell prompt.

  • spawn_console: The daemon spawn_console is part of the kbd package. It creates a console in response to a signal sent by the kernel in response to a Spawn_Console keysym. This approach works even if there isn't a shell to get your key, and doesn't update the utmp database.

What's the Difference?

The first proposed approach requires no intervention on your side—you should invoke the gpm server and the gpm-root client only at bootup, which you're already supposed to do. The gpm-root client then takes care of it all. Actually, a console is created only by opening it, so little more than fork() and exec() is required. Cleaning up is performed when the child process dies.

The other approaches are explained in the documentation for kbd-0.90, and are slightly more difficult only in that you need to change your keyboard configuration again, run an extra daemon program, or retrieve an extra package—open isn't part of the kbd package. The extra effort is small, because all of the hard work is implemented in the kernel.

Changing the Text Mode

Older versions of Linux couldn't allow console resizing, and a single video mode should be used for the console from boot to shutdown, and it usually was the bare 80x25. Linux-95 (Linux-1.2) allows console resizing. The user program SVGATextMode, despite its cumbersome name, is a nice utility to change the appearance of your text console on-the-fly.

The tool makes use of the ioctl(VT_RESIZE) system call to change the way the video buffer is managed in the kernel, and modifies the internal registers in your video board in order to send the right signals to your monitor. The program must run with root permissions because both tasks are privileged. SVGATextMode isn't alone in the field of console resizing, but it currently is the most flexible choice.

Installing the program is easy—just make && make install. Then configure the file /etc/TextConfig—you need to tell SVGATextMode which chipset is in your video board. The TextConfig file is full of helpful comments.

The single tricky task is resequencing running applications to the new tty size. The configuration file provides a ResetProg line, where you can put a pathname of an executable file that will handle this; it will generally consist of sending SIGWINCH to applications, as outlined in the sample ResetProg.

The definitions for the specific modes are modeled on the XF86Config lines. The X-Windows configuration documentation and any previous experience with with X-Windows configuration can help in playing with text modes. If you're going to fine-tune your X-Windows screen, you can easily run your tests with SVGATextMode. Its fast cycle time makes trial-and-error better because you needn't restart the X server for each trial. Fine-tuning screen timings for text modes can lead to a good configuration to be pasted in your XF86Config file. Alternately, if you have set up X-Windows already, you can use that knowledge to set up SVGATextMode.

Other facilities offered by SVGATextMode are automatic font loading and cursor reshaping. This last feature alone is a good reason to run SVGATextMode on your laptop—no more kernel patch to have a block cursor.

Problems Related to Console Resizing

If you use SVGATextMode, especially on small machines, you'll notice that sometimes console resizing will fail, even if you have plenty of swap available, and sometimes even with plenty of RAM. The problem is related to the kind of memory needed; the kernel needs to complete the system call (an ioctl()) atomically, and it needs to get a contiguous chunk of memory for each active console. There's no time to swap out some process or to shrink the buffer cache, and the kernel keeps only 1/64 of the available RAM for these “urgent” issues. As a result, the smaller the box, the more consoles you use, the more you're prone to fail resizing. Resizing to a smaller estate won't always help, because the kernel must be sure to have place for all the active consoles before it starts copying video data to the new area, and only at the end can the old buffer be released. If it fails, simply try again; it will probably succeed the second time.

Another issue is the role of the ResetProg. Why do some applications do resize well (like jed), others become completely stuck (like selection) and still others need to be sent the SIGWINCH signal? Because a resizing of the surrounding window is an asynchronous event, which doesn't fit the normal environment of the application.

Applications belong to three types: over-attentive ones look at the window size often, and perceive the new situation right when it happens; more conventional applications wait for an asynchronous notification of the event (a signal, namely SIGWINCH, for WINdow CHange), and respond to the notification in the right way; and some applications simply don't respond to changes in window size, and ignore SIGWINCH---the current version of selection was written before console resizing was available. Thus, while a resizing xterm sends SIGWINCH by itself, a resizing console doesn't send anything, and an external ResetProg is needed to fill the gap.

Tools for the Text Console

The following tools work particularly well on the text console, sometimes even better than in graphics mode.

  • gpm-root: gpm-root is a root-window manager. Its role is to draw menus on the screen background, like you do in the X environment. By default it responds to control-mouse events, since mouse-only is left to the selection mechanism, a vital feature if you work on a text console. The menus drawn by gpm-root are read from a user-local configuration file, and can be tailored to your own preferences. gpm-root allows console-switching, console locking, opening a new console to create a new system login, retrieving system information and executing external commands, as well as recursive menus. The user configuration file is reparsed when needed, to ease trial-and-error menu writing.

  • Emacs The Emacs editor is made mouse-sensitive by loading the t-mouse.el package, which comes in the gpm distribution. All the functionality available under the X Window System is duplicated on the text console, including the scrollbar. The scrollbar acts on the last column of the screen and smooth scroll is accomplished through a variable resolution widget—the more you move your mouse to the left, the less scrolling takes place in response to vertical motions. A meta- mouse button press triggers the scrollbar independently of the position of the mouse.

  • Jed: The Jed editor is mouse-sensitive as well. Mouse support has been developed by Jed's author, and thus is perfectly integrated. Jed is a good alternative to Emacs if you own a small computer—it is considerably smaller, both in disk usage and memory occupation, but offers the same basic commands and interface, as well as its own extension language. Well, if you learned “elisp” to configure Emacs, won't you learn “slang” to configure Jed?

  • dialog: The dialog program is nothing special, except that it runs definitely better on the text console than under an xterm. Managing a Slackware installation with the dialog menus on the console is a breeze, especially if you can interact with your mouse. Under xterm, on the contrary, a dialog menu looks ugly, and available mouse events are limited to button press, so you're almost forced to use the keyboard. Moreover, the curses libraries tend to use the alternate screen provided by xterm, and thus message boxes are simply invisible, and you wonder why the terminal is idling around without any message on it.

  • mc: mc (The Midnite Commander) a powerful file manager, is modeled on the famous DOS command nc, though much more powerful than the original. mc is fully configurable and extendable, and does a good job of managing your file system status. You can use its menus with the mouse as well as the keyboard, while shift-mouse runs selection as usual.

  • screen: The screen utility is a viable alternative to opening a lot of consoles. It manages up to ten terminal sessions running on a single physical connection. screen offers a lot of functionality, and is a must if you use a vt100 or an old PC running kermit to connect to your linux box. It is useful also if you're really console-hungry and you don't have enough consoles. The major drawback of screen is that it emulates a vt100, so you lose all the extra features offered by the Linux console. Specifically, you can't run gpm-aware programs under screen. One really nice feature of screen is the visual-bell facility. It offers a cut-and-paste facility, too, but mouse-based selection is easier to use.

  • minicom: minicom is an easy-to-use communication package resembling DOS's telix with a menu-oriented setup. It offers a good scripting utility, which makes your programs talk directly with the remote end of your serial connections. I use minicom to remotely control a Nicolet oscilloscope, with no concern about communication parameters.

  • gnuplot: Its name says a lot about it. A drawing program that can read external ASCII files, its major advantage is the ability to manage a many different output devices—including a bare terminal. This means you can look at your data graphs without starting X-Windows. The granularity of a tty plot is coarse, but gnuplot does its job well. It has a fairly complete internal help facility, and you can produce nice PostScript (or other graphic format) graphs without entering your graphic environment.

Further Readings

All the tools described above come with manual pages or info files. mc has a good internal help utility. gpm-root and the lisp library t-mouse.el are part of the gpm package.

Text-Only Resources

Alessandro Rubini is taking his PhD course in computer science and is breeding two small Linux boxes at home. Wild by his very nature, he loves trekking, canoeing and riding his bike. He wrote gpm, and can be reached as rubini@ipvvis.unipv.it.