20
The Notifier
In this chapter, we look at the Notifier in greater detail, discussing its role in processing
events for an XView application. This chapter serves as an introduction to the Notifier and
covers its use for most applications. You should be familiar with the topics covered in Chap-
ter 6, Handling Input, before you read this chapter.
20.1 Basic Concepts
The Notifier maintains the flow of control in an application. To understand the basic con-
cepts of the Notifier, we must distinguish between two different styles of input handling,
mainline and event-driven input, and consider how they affect where the flow of control
resides within a program.
20.1.1 Mainline Input Handling
The traditional type of input handling of most text-based applications is mainline-based and
input-driven. The flow of control resides in the main routine and the program blocks when it
expects input. That is to say, no other portion of the program may be executed while the pro-
gram is waiting for input. For example, in a mainline-driven application, a C programmer
will use fgets() or getchar() to wait for characters that the user types. Based on the
user’s input, the program chooses an action to take. Sometimes, that action requires more
input, so the application calls getchar() again. The program does not return to the main
routine until the processing for the current input is done.
The tight control represented by this form of input handling is the easiest to program since
you have control at all times over what to expect from the user and you can control the direc-
tion that the application takes. There is only one source of input—the keyboard—and the
user can only respond to one interface element at a time. A user’s responses are predictable
in the sense that you know that the user is going to type something, even if you do not know
what it is.
Notifier
The Notifier 459
20.1.2 Event-driven Input Handling
Windowing systems are designed such that many sources of input are available to the user at
any given time. In addition to the keyboard, there are other input devices, such as the mouse.
Each keystroke and mouse movement causes an event that the application might consider.
These keystroke and mouse events are generated from the window system. Further, there are
other types of events that are generated from the window system itself and from other
processes. Another aspect of event-driven input handling is that you are not guaranteed to
have any predictable sequence of events from the user. That is, a user can position the mouse
on an object that receives text as input. Before the user is done typing, the user can move the
mouse to another window and select a panel button of some sort. The application cannot
(and should not) expect the user to type in window A first, then move to window B and select
the button. A well-written program should expect input from any window to happen at any
time.
20.2 Functions of the Notifier
The Notifier can do any of the following:
• Handle software interrupts—specifically, UNIX signals such as SIGINT or SIGCONT.
• Notice state changes in processes that your process has spawned (e.g., a child process that
has died).
• Read and write through file descriptors (e.g., files, pipes, and sockets).
• Receive notification of the expiration of timers so that you can regularly flash a caret or
display animation.
• Extend, modify, or monitor XView Notifier clients (e.g., noticing when a frame is opened,
closed, or about to be destroyed.)
• Use a non-notification-based control structure while running under XView (e.g., porting
programs to XView).
The Notifier also has provisions, to a limited degree, to allow programs to run in the Notifier
environment without inverting their control structure.
460 XView Programming Manual
20.3 How the Notifier Works
Up until now, we have been saying that you should register an event handler for objects when
they want to be notified of certain events such as mouse motion or selection or keyboard
input. What you may not have been aware of is that you are indirectly registering these event
handlers with the Notifier. When you specify callbacks or notify procedures, the XView
object specified is said to be the client of the Notifier. Look at the following code:
extern void my_event_handler();
xv_set(canvas,
CANVAS_PAINTWINDOW_ATTRS,
WIN_CONSUME_X_EVENT_MASK, ButtonPressMask | KeyPressMask,
WIN_EVENT_PROC, my_event_handler,
NULL,
NULL);
In the above code, each paint window of the canvas becomes a client of the Notifier.*
Generally stated, the Notifier detects events in which its clients have expressed an interest
and dispatches these events to the proper clients in a predictable order. In the X Window
System, events are delivered to the application by the X server. In XView, it is the Notifier
that receives the events from the server and dispatches them to its clients. After the client’s
notify procedure processes the event, control is returned to the Notifier.
20.3.1 Restrictions
The Notifier imposes some restrictions on its clients. Designers should be aware of these
restrictions when developing software to work in the Notifier environment. These restric-
tions exist so that the application and the Notifier do not interfere with each other. More pre-
cisely, since the Notifier is multiplexing access to user process resources, the application
needs to respect this effort so as not to violate the sharing mechanism.
For example, a client should not call signal (3). The Notifier is catching signals on behalf
of its clients. If a client sets up its own signal handler, then the Notifier will never notice the
signal. The program should call notify_set_signal_func() instead of signal (3)
(see Section 20.5, “Signal Handling”).
*CANVAS_PAINTWINDOW_ATTRS tells the CANVAS package to register the input mask and callback routine for
each of its paint windows.
Notifier
The Notifier 461
20.3.1.1 System calls to avoid
Assuming an environment with multiple clients and an unknown Notifier usage pattern, you
should not use any of the following system calls or C library routines:
signal (3) The Notifier is catching signals on behalf of its clients. If you set up your
own signal handler over the one that the Notifier has set up, then the Notif-
ier will never notice the signal.
sigvec (2) The same applies for sigvec (2) as for signal (3) above.
sigaction (2) The same applies for sigaction (2) as for signal (3) above.
setitimer (2) The Notifier is managing two of the process’s interval timers on behalf of
its many clients. If you access an interval timer directly, the Notifier could
miss a timeout. Use notify_set_itimer_func() instead of seti-
timer (2).
alarm (3) Because alarm (3) sets the process’s interval timer directly, the same
applies here as for setitimer (2) above.
getitimer (2) When using a Notifier-managed interval timer, you should call
notify_itimer_value() to get its current status. Otherwise, you
can get inaccurate results.
wait3 (2) The Notifier notices child process state changes on behalf of its clients. If
you do your own wait3 (2), then the Notifier may never notice the
change in a child process or you may get a change of state for a child pro-
cess in which you have no interest. Use notify_set
_wait3_func() instead of wait3 (2).
wait (2) The same applies for wait (2) as does for wait3 (2) above.
ioctl (2) ( . . . , FIONBIO, . . . )
This call sets the blocking status of a file descriptor. The Notifier needs to
know the blocking status of a file descriptor in order to determine if there
is activity on it. fcntl (2) has an analogous request that should be used
instead of ioctl (2).
ioctl (2) ( . . . , FIOASYNC, . . . )
This call controls a file descriptor’s asynchronous IO (input/output) mode
setting. The Notifier needs to know this mode in order to determine if
there is activity on it. fcntl (2) has an analogous request that should be
used instead of ioctl (2).
popen and pclose (2)
In the SunOS, these functions call wait (2). Hence, you should avoid
using these for the reasons mentioned above.
system (3) In the SunOS, this function calls signal (3) and wait (2). Hence, you
should avoid using this for the reasons mentioned above.
462 XView Programming Manual
20.4 What is a Notifier Client?
A client of the Notifier is anything that has registered a callback routine with it. In XView, a
client is an object such as a canvas or panel that you have created using xv_create().
Typically, most of the event registration happens at the time such clients are created. How-
ever, to the Notifier, a client is nothing more than an ID that distinguishes it from all other
Notifier clients. Thus, you could identify a client using a number such as “43” or the address
of an object as in &foo. XView objects are commonly used as Notifier clients because
xv_create() returns a unique handle to an object that has been allocated dynamically.
The client ID is of type Notify_client as declared in <xview/notify.h>.
Certain notify_* functions create Notifier clients. For example:
Notify_client client = (Notify_client)10101; /* arbitrary */
Notify_func destroy_func();
notify_set_destroy_func(client, destroy_func);
In this code fragment, up until the call to notify_set_destroy_func(), the client
may not have been registered as a client to the Notifier. When you call
notify_set_destroy_func(), internally, the Notifier package looks up in its table of
clients whether there is any other client using that identifier (the client handle is the identif-
ier, in this case this is an arbitrary value). If there is a client using the identifier, then the des-
troy function specified is set for that client’s destroy handling. Otherwise, a new Notifier cli-
ent is allocated and the client handle is also used as a handle to the new Notifier client.
Notifier clients are not XView objects for you to create or manipulate using xv_create()
or xv_set(). In fact, the Notifier is completely independent of XView and can be used in
applications that do not even use XView objects.
20.4.1 Types of Interaction
Client interaction with the Notifier falls into two general categories:
• Event Handling – A client may receive events and respond to them using event handlers.
As you have seen, event handlers (callbacks and notify procedures) do much of the work
in the Notifier environment.
• Interposition – A client may request that the Notifier install a special type of event han-
dler, supplied by the client, to be interposed ahead of the current event handler for a
given type of event and client. This allows clients to screen incoming events and redirect
them and to monitor and change the status of other clients. A thorough discussion of
interposition is presented later in this chapter.
A client establishes an interest in a certain type of event by registering an event handler to
respond to it. The following sections cover registration procedures for special signal and
UNIX-related event handlers, for application-defined client event handlers, and for interpos-
ing event handlers. All event handlers, including interposers, return a value of
NOTIFY_DONE, NOTIFY_IGNORED, or NOTIFY_UNEXPECTED, depending on how the event
Notifier
The Notifier 463
Get Volume 7A: XView Programming Manual now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.