was handled. These three return values are sometimes used to convey important information
about the status of the event in the Notifier (usually the function that called
notify_next_*_func() looks at the return value). These return values and their signif-
icance are covered in Section 20.9.4, “Invoking the Next Function.”
20.5 Signal Handling
Signals are UNIX software interrupts. The Notifier multiplexes access to the UNIX signal
mechanism. A Notifier client may ask to be notified that a UNIX signal occurred either when
it is received (asynchronously) and/or later during normal processing (synchronously).
Clients may define and register a signal event handler to respond to any UNIX signal desired.
However, some of the signals that you might catch in a traditional UNIX program should be
caught instead by the Notifier.
CAUTION
Clients of the Notifier should not directly catch any
UNIX signals using signal
(3), sigvec (2), or sigaction (2). There are critical stages of event reading
and dispatching that, if interrupted, could cause the program to jump to another
location and interrupt the communication protocol between the X server and the
application.
Exceptions to this are noted later in this section.
20.5.1 Signals to Avoid
Clients should not have to catch any of the following signals (even via notify_set_
signal_func() described below). If they are, you are probably utilizing the Notifier
inappropriately. The Notifier catches these signals itself under a variety of circumstances and
handles them appropriately.
SIGALRM Caught by the Notifier’s interval timer manager. Use notify_set_
itimer_func() instead.
SIGVTALRM The same applies for SIGVTALRM as for SIGALRM above.
SIGTERM
Caught by the Notifier so that it can tell its clients that the process is going
away. Use notify_set_destroy_func() if that is why you are catch-
ing SIGTERM.
SIGCHLD Caught by the Notifier so that it can do child process management. Use
notify_set_wait3_func() instead.
464 XView Programming Manual
SIGIO Caught by the Notifier so that it can manage its file descriptors that are run-
ning in asynchronous I/O mode. Use notify_set_input_func() or
notify_set_output_func() if you want to know when there is activity
on your file descriptor.
SIGURG Caught by the Notifier so that it can dispatch exception activity on a file
descriptor to its clients. Use notify_set_exception_func() if you
are looking for out-of-band communications when using a socket.
The last two signals in the list are considered advanced topics and are not covered in this
manual.
20.5.2 A Replacement for signal()
Instead of using signal() to catch signals delivered by UNIX, you should register a signal
event handler by calling notify_set_signal_func(). This function allows you to call
another function when a specified signal is generated. Its form is as follows:
Notify_func
notify_set_signal_func(client, signal_func, sig, when)
Notify_client client;
Notify_func signal_func;
int sig;
Notify_signal_mode when;
signal_func is the function to call when the signal described by sig occurs.*
The when parameter is either
NOTIFY_SYNC or NOTIFY_ASYNC. NOTIFY_SYNC causes notifi-
cation during normal processing. In other words, the delivery of the signal is delayed to avoid
interrupting Xlib Protocol communication between the X server and the application. When it
is safe to do so, your signal_func function is called and you can display a notice, exit, or
jump to another place in the program. Typically, there is a very short time between signal
delivery and notification to your callback routine. It is only a little slower than when you use
signal().
NOTIFY_ASYNC causes notification as soon as the signal is received. This mode mimics the
UNIX signal (3) semantics.
CAUTION
When using asynchronous signals, your routine may set a variable, a condition,
or a flag indicating that the signal was received, or it may change any internal
state to your program. Do not make any XView, Xlib, or Notifier calls or call
any function that might manipulate any XView data structures. Also, do not call
longjmp() or setjmp(); they can cause a condition that can interfere with
the X11 Protocol.
*See <signal.h> for a list of signals and definitions.
Notifier
The Notifier 465
notify_set_signal_func() returns a pointer to the function that was
installed before you set the new function. You should use this to reset the func-
tion if you want to unregister your installed function.
When the specified signal occurs, your signal_func is called:
Notify_value
signal_func(client, sig, when)
Notify_client client;
int sig;
Notify_signal_mode when;
The parameters to the signal handler are not the same as the ones given to a signal han-
dler in the call to signal (3). However, it is not advisable to use either one, except in
unusual circumstances. As a general rule, you should use notify_set_
signal_func() for all signal handling. If you want the signal code or context from
the signal that was generated (two parameters that are passed to a normal
UNIX signal
handler), you can use:
int
notify_get_signal_code()
struct sigcontext *
notify_get_signal_context()
These two functions take no parameters—they return the signal code and context
(respectively) of the last signal generated. If you wish to save these values, you can
copy them.
Using the Notifier, you can catch any signal except SIGKILL and SIGSTOP, which can-
not be caught by a
UNIX application. Attempting to do so generates an error.
An example of common signal handling is shown below:
#include <xview/notify.h>
...
extern Notify_value sigint_func();
notify_set_signal_func(frame, sigint_func, SIGINT, NOTIFY_SYNC);
...
Notify_value
sigint_func(client, sig, when)
Notify_client client;
int sig;
{
puts("received interrupt -- exiting");
xv_destroy_safe(frame);
return NOTIFY_DONE;
}
The return value of your signal handler tells whether you handled the signal or ignored
it.*
*Currently, the return value is ignored.
466 XView Programming Manual
20.5.3 Timers
One specific type of signal is a timer. Timers can be set up to call a routine after the passage
of a specified amount of time.* Such a routine may cause a caret to flash at regular intervals
or allow a clock application to change the time display. The timer is handled differently from
other signals in that multiple timers can be installed for various clients (say a flashing caret
and a clock in the same application). There can only be one timer function (timer_func)
per client.
Because the Notifier handles timers, you should not make calls to such routines as sleep()
or setitimer() (see Section 20.11, “Emulating a Sleep Call,” for information on how to
“sleep” in XView). As pointed out above, you should not attempt to use signal() to catch
SIGALRM or SIGVTALRM to trap timer signals. To set timers and be notified when they expire,
use notify_set_itimer_func(). The form of the call is:
Notify_func
notify_set_itimer_func(client, timer_func, which, value, ovalue)
Notify_client client;
Notify_func timer_func;
int which;
struct itimerval *value, *ovalue;
The parameter which indicates which type of timer you want to use. Its value is either
ITIMER_REAL or ITIMER_VIRTUAL.
The value parameter is a pointer to an itimerval which indicates the initial timeout and
an interval timeout. The interval timeout is what is used after the initial timeout times out. If
the initial timeout is 0, then the timer is not called, regardless of the value of the interval
timer. The granularity of the timer is dependent on your hardware architecture and operating
system. It is perhaps unwise to assume that you will be notified as frequently as 30 mil-
liseconds or less. Some cases may have higher minimum limits—your mileage may vary.
The ovalue is also a pointer to an itimerval structure. If there was a previous timeout
that has yet to expire, itimerval will have that time filled in. You may pass a NULL as
ovalue if you are not interested in this value.
The timer_func parameter is the function to call when the timer expires.
notify_set_itimer_func() returns the function that was previously set for this client
(see notify_set_signal_func above). The form of the timer_func is:
Notify_value
timer_func(client, which)
Notify_client client;
int which;
Example 20-1 demonstrates one possible use of notify_set_itimer_func(). This
program displays an animation of several icons stored in the icon font. When animating, the
next icon in a sequence is displayed using XDrawString() (since the icon is actually part
of the font). The slider controls the rate at which the next icon is drawn. If the slider is set to
0, the animation stops. The slider is a panel item whose callback routine makes calls to
*Event processing still takes place during this time segment.
Notifier
The Notifier 467
notify_set_itimer_func() to set the timer to the new value or to turn it off by set-
ting the function to NOTIFY_FUNC_NULL.
Example 20-1. The animate.c program
/*
* animate.c -- use glyphs from the "icon" font distributed with XView
* to do frame-by-frame animation.
*/
#include <stdio.h>
#include <ctype.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xos.h> /* for <sys/time.h> */
#include <xview/xview.h>
#include <xview/panel.h>
#include <xview/font.h>
#include <xview/notify.h>
Frame frame;
Display *dpy;
GC gc;
Window canvas_win;
Notify_value animate();
struct itimerval timer;
#define ArraySize(x) (sizeof(x)/sizeof(x[0]))
char *horses[ ] = { "N", "O", "P", "Q", "R" };
char *boys[ ] = { "\007", "\005", "\007", "\010" };
char *men[ ] = { "\\", "]", "Y", "Z", "[" };
char *eyes[ ] = {
"2", "5", "4", "3", "4", "5",
"2", "1", "0", "/", "0", "1"
};
int max_images = ArraySize(horses);
char **images = horses;
int cnt;
main(argc, argv)
int argc;
char *argv[ ];
{
Panel panel;
Canvas canvas;
XGCValues gcvalues;
Xv_Font _font;
XFontStruct *font;
void adjust_speed(), change_glyph();
extern void exit();
xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);
frame = (Frame)xv_create(XV_NULL, FRAME,
FRAME_LABEL, argv[0],
NULL);
468 XView Programming Manual
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.