Writing a Mouse-Sensitive Application

Terminal-oriented programs tend to have an unwieldy interface, while writing X-Windows applications is difficult. By using the gpm client library you can easily turn a text-oriented program into an easy-to-port mouse-sensitive application.

Stacking Applications

Typically, a smart program allows itself to be temporarily
stopped or offers the user the option of spawning a shell. This
ability is often overlooked during program development, because
programmers tend to concentrate on the application itself, rather
than on escaping from it. Before giving away tty control, any
mouse-sensitive program should release the mouse to avoid stealing
events from a user trying to run the selection mechanism within a
shell environment. The preferred way to release the mouse in this
case is to invoke Gpm_Open with connection
parameters indicating that all events are passed along to the next
service. When the program resumes the user focus, it can simply
Gpm_Close to restore the previous event masks.
If the application forgets to release the mouse before releasing
the tty, weird things happen.

Using curses

Usually mouse-sensitive applications manage the screen using
curses or the compatible
ncurses library. [See page ?? for
an introduction to ncurses—Ed] From the point of view of mouse
handling, this doesn't make much difference. You need only to call
Gpm_Getch() or Gpm_Wgetch()
in place of the getc or getchar. These replacement functions take
the same arguments as the original curses calls.

From the mouse-handling point of view, the only difference
between a full-featured curses application and one using normal tty
is in the possible subdivision of the screen into different
windows. Using a single mouse handler makes management non-trivial
if the screen is split into multiple windows. The scenario is dealt
with by the so-called high level library, which is a simple yet
effective set of functions to manage a stack of “regions of
interest”, easing the dispatch of events to multiple
recipients.

The High-Level Library

The high-level part of the gpm library offers entry points to
a centralized data structure responsible for delivering events to
multiple mouse handlers.

In practice, a double linked list of ROIs (regions of
interest) is maintained, and each ROI is responsible for handling
events for a specific user function with specific “clientdata”.
Each region is identified by its rectangular limits and by
minimum-modifier and maximum-modifier sets. Thus you can choose to
deliver events to different windows, according to either the event
position or the modifiers used, in a way similar to the
multiplexing of applications on a single console described
earlier.

When you use a windowed interface, you can take full
advantage of the high level library by creating one or more ROIs
associated with each curses window. In addition to events happening
in the ROI, the handler associated with a region will get “enter”
events when the mouse cursor enters the region and “leave” events
when it leaves. This means that a single mouse motion can generate
multiple callbacks to help keep a consistent screen state without
needing a huge set of global state variables.

Unfortunately, the high level library has been available only
since gpm version 1.0. If you have an older version of gpm you
would do best to upgrade. Lack of the high level library was the
main reason that gpm's version numbers were
0.x for such a long time.

Xterm Support

Within the X Window System, terminal applications are run
within xterm, and xterm is the only usable tty
you can find on most workstations—usually workstations are
terribly slow and unusably hostile before X-Windows is
started.

Fortunately, xterm is able to report mouse events, made up of
escape sequences, which are reported to the client application
through the same channel as normal data.

Unfortunately, the range of events it is able to report is
severely limited. Moreover, because events are reported through the
same stream as keyboard events, all the nice design of multiple
input channels breaks, and any application which wants to sense
mouse and keyboard events independently fails.

Fortunately, using Gpm_Getc() and friends
works quite well, as you can check by running mev under an
xterm.

If you consider ever running your application under an xterm,
you must be sure to not depend on a full event reporting.
Specifically, you won't be informed of any motion or drag events,
and button-release events won't specify which button of a set has
been released. This means, in practice, that if you need precise
reporting of a double-button press, your application will not work
properly under xterm.

I strongly urge you to be careful; if the application can
only run under the Linux console, it is of limited use, and you'll
surely swear at yourself sooner than you may expect. If, on the
contrary, the application is able to run under xterm, it is better
exploiting the ability to (at least) invoke buttons by a simple
mouse press, rather than forcing the user to use keyboard-only
interaction.