motifdeveloper.com
Sponsored by IST Limited
Formerly MW3: Motif on the World Wide Web [MW3 Logo]
Last Updated
November 18, 2002
 


X-Designer - The Leading X/Motif GUI Builder - Click to download a FREE evaluation
 

motifdeveloper.com
Home
Search
Frequently Asked Questions
The Motif FAQ
X/Motif FAQs
General FAQs
Ask Antony
Latest Q & A
All Q & As
Submit Question
Tips & Pointers
Code Examples
Software
OpenMotif
Widget Sets
GUI Toolkits & Libraries
Motif suppliers
Non-commercial S/W
Commercial Software
Multimedia
Miscellaneous
Organizations
Docs & Pubs
X/Motif Newsgroups
Security
Internationalization
Feedback
Feedback Form
Contributors
 

Error handling in Motif and Xt-based applications

30-Oct-02 18:00 GMT

Question: How do I handle errors emanating from the Motif, X Toolkit, and X libraries?

Introduction

Error handling in X/Motif based applications can be a tricky task in application programming, because of the asynchronous nature of the X system. Requests are sent to the X server, and any error or warning messages which result from the request are not handled immediately at the point of request. The X server sends special XErrorEvent events to the client, and these are delivered along with other normal events at some point down the line, possibly well after the request was issued.

There are a number of reasons why the application may want to intercept error and warning messages emanating from the various toolkits:

  • the application may want to attempt error recovery procedures, or save state in case of emergency
  • the application may want to log the error for later analysis
  • the toolkit does not inform with all the information it could about the error
  • the default behavior of the toolkit from which the error emanates is wrong for the application to hand
  • the way in which the toolkit reports the error to the user is an inconvenience or too crude
  • the message itself may require translation into a more user-friendly form
  • specific messages may need to be loaded from an application-specific error database

The default behavior of the toolkits

Each of the lower level toolkits (Motif, the X Toolkit Intrinsics, the lower level X library) provide their own error handling routines. Each of the layers utilize the services of the library below, and refine the behavior for their own purposes in various ways.

Where they differ is that Xt and Xlib provide hooks such that the application programmer can intercept the error and warning events, and modify the behavior to suit. Motif only adds handlers to change the output format of errors emanating from its own library: it does not provide handlers to intercept the library behavior. Since it uses Xt to deliver the message once the formatted message is in place, it is at the Xt level that handlers need to be installed if Motif error handling is to be modified.

Xlib Error handling

In general, client functions in the X library are asynchronous in nature: although some return a Status to the programmer at point of call, most rely on a later XErrorEvent event which arrives from the X server after the client function has been called.

The X library considers errors to be of two kinds: fatal, and non-fatal. It also groups errors into two distinct partitions: those which are related to I/O and the status of the connection to the X server itself, and those which are related to the contents of client requests in general.

In either grouping, whether I/O or protocol request related, the default behavior of the X library is to print a message to the standard error stream, and then immediately exit. Although logically some error conditions may well be non-fatal in nature, nonetheless the default behavior of Xlib is to exit regardless of whether the error is survivable, or whether the application could take the necessary corrective action.

Xt Error handling

In Xt, the situation is slightly easier for the programmer in that error and warning messages tend to be synchronous in nature: they are generally called by the toolkit as the result of a library procedure call being supplied with invalid data, and the error handlers are invoked immediately at the point of error.

Again, as in Xlib, errors and messages are considered to fall into two groups: fatal, and non-fatal. Unlike Xlib, error handlers generally are provided at two levels: a low level handler, which simply prints to the standard error (and, in the case of fatal errors, automatically exits the application), and a higher level handler, which looks into an error string database to translate an error key into a message, but which subsequently calls the lower level handler with the message as parameter. The advantage of the higher level handler is that it is not necessary to embed messages into the application - these can be externalized so that they can be customized or translated as required.

The behavior of the Xt Intrinsics is undefined once an error handler has been invoked and the toolkit believes that the error is fatal in nature. This is not to say that an application cannot override the default behavior and survive: simply that the authors make no claims about the potential subsequent robustness of the application in these circumstances.

Note that Xt provides two sets of routines for manipulating error and warning handlers: those which take an application context parameter (XtAppContext), and those which do not (but which internally deduce the default application context). This implies that applications can install per-application-context error and message handlers. It is difficult to envisage where this would be useful for the general round of applications, which tend to create a single application context. Be that as it may, the Xt routines without the XtAppContext parameter are strictly speaking deprecated.

Lastly, Xt does not override the default behavior of the Xlib layer: only in one place does Xt install error handlers over those of Xlib, in order to guard some protected critical code; post operations, prior Xlib error handlers are restored.

Motif Error handling

Motif is similar to Xt in that error handling is handled at the point of error. Like Xt, it does not override the default behavior of the Xlib layer: in a few isolated cases, Motif installs error handlers over those of Xlib, in order to guard some protected critical code; post operations, prior Xlib error handlers are again restored. Like Xt, it has two sets of routines for handling fatal and non-fatal errors.

There are subtle differences in behavior between Motif 1.2 and 2.1. In version 2.1, Motif installs its own handler methods by registering a message handler with the Xt higher level. It does this in the VendorShell class initialize routine. This does not happen in Motif 1.2.

Regardless, in either case, the logical behavior of Motif is identical to that of Xt, since all the Motif toolkit does is modify the system so that the format of output is in a style which suits the toolkit; it calls the lower level Xt handlers in both versions of the toolkit, so that the output and subsequent behavior of Motif is the same as that of Xt: logically "fatal" errors terminate the application after printing the message to the standard error stream.

Where Motif differs from Xt is the fact that Motif does not support application-defined message handler overrides: handling error and messages output in a Motif environment does not require any specific Motif codes, and any modifications to the messaging system are performed at the Xt and Xlib levels, which Motif uses for the ultimate delivery mechanism. In other words, if we want to modify the way Motif delivers error and warning messages to the user, we make the changes through Xt and Xlib calls.

Modifying X library error handling behavior

As discussed, Xlib supports two error interfaces: one concerned with I/0 and the connection to the X server, the other for reporting on the contents of a protocol request.

XSetErrorHandler

Taking the latter case first, the interface to the general error handling system is the routine XSetErrorHandler(), formerly specified as follows:

#include <X11/Xlib.h>

typedef int (*XErrorHandler)(Display *, XErrorEvent *) ;

extern XErrorHandler (*XSetErrorHandler)(XErrorHandler handler) ;

What this means is that XSetErrorHandler() is a routine which takes an application-specific error handler procedure as argument; it causes the X library to use handler whenever general errors arise ; the routine returns the previous error handler.

This means that an application program can use the routine to temporarily override Xlib error behavior, installing its own handler for a given purpose, and then later re-install the default handler when some critical piece of code is finished. Remember that the Xlib default handler will terminate the application; here we can, for example, add a handler of our own so that the termination behavior of Xlib is suspended:

An Example - ignoring Xlib error events

#include <stdio.h>
#include <X11/Xlib.h>

static XErrorHandler old_handler = (XErrorHandler) 0 ;

static int ApplicationErrorHandler(Display *display, XErrorEvent *theEvent)
{
    (void) fprintf(stderr,
		   "Ignoring Xlib error: error code %d request code %d\n",
		   theEvent->error_code,
		   theEvent->request_code) ;

    /* No exit! - but keep lint happy */

    return 0 ;
}

...
/* Install our error handler to override Xlib's termination behavior */
old_handler = XSetErrorHandler(ApplicationErrorHandler) ;
...
/* Do code which is survivable in case of error */
code_we_can_survive_in_case_of_error("it says here...") ;
...
/* Restore original X handler                                         */
/* Assumption: the X queue has been temporarily flushed/synchronized  */
/* at the end of the application-critical code, otherwise a possible  */
/* asynchronously arriving error might arrive further down the stream */
/* after the original handlers are restored.                          */
/* XFlush(display) */
/* XSync(display, False) ; */
(void) XSetErrorHandler(old_handler) ;

As an alternative, XSetErrorHandler() may be passed a NULL parameter, which reinstalls the default Xlib error handler in any case. This would be useful where it is not known whether code from a higher library level has installed its own handler, so that XSetErrorHandler(old_handler) is not re-installing default Xlib behavior but that of the intermediary code. Using NULL, we can force default termination behavior if we really need it.

Notes on XSetErrorHandler()

An error handler which an application installs should not itself generate internal X protocol requests.

XSetIOErrorHandler

I/O or system call errors on the X connection are by their very nature considered to be permanently fatal. Whether you like it or not, the client side of the X connection will terminate: your only choice here is to modify the output diagnostic mechanism. If we install an application specific I/O handler, Xlib will terminate after the handler returns in any case. It is however considered bad form to install an I/O error handler which does return - you should handle the message, and then issue the exit call yourself.

If Xlib is going to exit whatever we do, why bother to install a handler? The answer to this is the fact that there are many reasons why you might want to intercept Xlib's error mechanisms: you might want to attempt a quick application save-state (although how successful this is likely to be, if you need to collect data from the X server to perform the feat, is a moot point), or collect as much information as you can prior to logging the error somewhere for later analysis.

The routine to install an application-speicfic I/O error handler is XSetIOErrorHandler(), formerly specified as follows:

#include <X11/Xlib.h>

typedef int (*XIOErrorHandler)(Display *) ;

extern XIOErrorHandler XSetIOErrorHandler(XIOErrorHandler handler) ;

Usage of XSetIOErrorHandler() is the same as XSetErrorHandler(): it installs a custom handler in place of the default Xlib routine, and it returns the previously installed handler. Again, NULL can be supplied as a parameter to re-install default toolkit operations.

An Example - saving application state

#include <stdio.h>
#include <X11/Xlib.h>

static XIOErrorHandler old_iohandler = (XIOErrorHandler) 0 ;

static int ApplicationIOErrorHandler(Display *display)
{
    (void) fprintf(stderr, "Oh Good Grief, what now? Saving...\n") ;

    save_state() ;

    (void) fprintf(stderr, "Saved.\n") ;

    log_diagnostics("Contact the fire department - the computer is on fire") ;

    (void) fprintf(stderr, "Thank you for your cooperation.\n") ;

    /* Bad form not to exit, but if you do not, Xlib will */

    exit(911) ;
}

...
old_iohandler = XSetIOErrorHandler(ApplicationIOErrorHandler) ;
...
/* 
** I cannot think of any logical reason why you would 
** really want to re-install the default behavior here, whilst
** your application is running: the application is doomed in any case.
**
** Use XSetIOErrorHandler(old_iohandler) or XSetIOErrorHandler(NULL)
** should you think of one.
*/
...

Notes on XSetIOErrorHandler

Installing an I/O handler is for emergency situations - where the application has to remain as fault tolerant as possible in the face of extreme adverse conditions. This does not mean that the average application can do without - if you want to avoid leaving a database in a locked or inconsistent state, even if the data is not particularly valuable in itself, it is not a bad idea to install one so that you potentially minimise the problem of cleaning up afterwards.

Notes on Xlib error handlers in general

As an aside, the routines XSetErrorHandler() and XSetIOErrorHandler() are unusual in that they are amongst the very few Xlib routines which do not require a Display * parameter.

Modifying Xt Intrinsics library error handling behavior

Xt provides two sets of diagnostic message handlers: warning handlers, which are non-fatal in nature, and error handlers which, by default, are. Each set has two associated levels: a low level handler, which outputs the message, and a higher level handler, which constructs and formats the message prior to calling the low level handler for dispatch.

There are therefore four primary routines which we need to consider:

  • XtAppSetWarningHandler()

    - modifies the way Xt outputs non-fatal warning messages

  • XtAppSetWarningMsgHandler()

    - modifies the way Xt formats and constructs non-fatal warning messages

  • XtAppSetErrorHandler()

    - modifies the way Xt outputs fatal error messages

  • XtAppSetErrorMsgHandler()

    - modifies the way Xt formats and constructs fatal error messages

There are also the routines XtSetWarningHandler(), XtSetWarningMsgHandler(), XtSetErrorHandler(), and XtSetErrorMsgHandler() which we shall ignore because they have been superseded by the above.

XtAppSetWarningHandler

The routine XtAppSetWarningHandler() is similar to the Xlib routines, in that it returns the previous error handler. It is formally specified as follows:

typedef void (*XtErrorHandler)(String) ;

extern XtErrorHandler XtAppSetWarningHandler(XtAppContext, XtErrorHandler) ;

The XtErrorHandler type is correct, even though this is a warning message routine: there is no putative XtWarningHandler type, and both XtAppSetWarningHandler() and XtAppSetErrorHandler() share the same message handler prototypes.

An Example: redirecting warnings to a popup window

#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/MessageB.h>

static void PopupWarningHandler(String message)
{
    extern Widget application_shell ; /* Session shell ? */

    static Widget   warning_dialog = (Widget) 0 ;
	   XmString xms            = (XmString) 0 ;

    if (warning_dialog == (Widget) 0) {
	warning_dialog = XmCreateWarningDialog(application_shell,
					       "WarningsDialog",
					       (ArgList) 0,
					       (Cardinal) 0) ;
    }

    xms = XmStringCreateLocalized(message) ;

    XtVaSetValues(warning_dialog, XmNmessageString, xms, NULL) ;
    XmStringFree(xms) ;

    XtManageChild(warning_dialog) ;
}
...

static XtErrorHandler old_message_handler = (XtErrorHandler) 0 ;

void InstallPopupWarningHandler(XtAppContext app_context)
{
    old_message_handler = XtAppSetWarningHandler(app_context, PopupWarningHandler) ;
}

void UninstallPopupWarningHandler(XtAppContext app_context) 
{
    (void) XtAppSetWarningHandler(app_context, old_message_handler) ;
}

XtAppSetErrorHandler

As for XtAppSetWarningHandler(), the routine XtAppSetErrorHandler() returns the previous error handler. It is formally specified as follows:

typedef void (*XtErrorHandler)(String) ;

extern XtErrorHandler XtAppSetErrorHandler(XtAppContext, XtErrorHandler) ;

Recall that the behavior of the Xt Intrinsics is undefined subsequent to error messages emanating from the library. We could redirect errors to a popup, but there is no guarantee that the popup will appear. The correct action to take will therefore depend on the mission-critical status of the application, and how user-friendly we are prepared to be. What we can do is install our own handler to try and save application state, analogously to the Xlib XSetErrorHandler routine.

An Example: a specimen Xt Error Handler

The following code sketches out a scheme which saves application state, logs the error, and lastly attempts a popup message (of which there is no guarantee of success).

static void DoExitCallback(Widget w, XtPointer clientData, XtPointer callData)
{
    exit(911) ;
}

static void PopupErrorDialog(String error)
{
    extern Widget application_shell ; /* Session shell ? */

    static Widget   error_dialog = (Widget) 0 ;
	   XmString xms          = (XmString) 0 ;

    if (error_dialog == (Widget) 0) {
	/* These strings should really be picked up from X resources */
	/* So the dialog can be internationalised as appropriate     */

	XmString ok      = XmStringCreateLocalized("Exit") ;
	XmString recover = XmStringCreateLocalized("Continue") ;
	Arg      argv[2] ;
	Cardinal argc = 0 ;

	XtSetArg(argv[argc], XmNokLabelString,     ok) ;      argc++ ;
	XtSetArg(argv[argc], XmNcancelLabelString, recover) ; argc++ ;

	error_dialog = XmCreateErrorDialog(application_shell,
					   "ErrorsDialog",
					   argv,
					   argc) ;

	XtAddCallback(error_dialog, XmNokCallback, DoExitCallback, (XtPointer) 0) ;
    }

    xms = XmStringCreateLocalized(error) ;

    XtVaSetValues(error_dialog, XmNmessageString, xms, NULL) ;
    XmStringFree(xms) ;

    XtManageChild(error_dialog) ;
}

static void IntrinsicsErrorHandler(String error)
{
    (void) fprintf(stderr, "Here we go again...\n") ;

    /* Save the application state */

    save_state() ;

    (void) fprintf(stderr, "Saved.") ;

    log_diagnostics("Looks like we need the Marines this time") ;

    /* This may or may not work */

    PopupErrorDialog(error) ;
}

...

static XtErrorHandler old_error_handler = (XtErrorHandler) 0 ;

void InstallErrorHandler(XtAppContext app_context)
{
    old_error_handler = XtAppSetErrorHandler(app_context, IntrinsicsErrorHandler) ;
}

void UninstallErrorHandler(XtAppContext app_context) 
{
    (void) XtAppSetErrorHandler(app_context, old_error_handler) ;
}

XtAppSetWarningMsgHandler and XtAppSetErrorMsgHandler

XtAppSetWarningMsgHandler and XtAppSetErrorMsgHandler are concerned not with the way in which the error messages are presented to the user, but with the format and contents of the messages themselves. They do, however, call the lower-level interfaces internally, so that if you install your own high level message handlers, you must also remember to invoke the lower level. Invoking the relevant lower level handlers will be convered below.

These two routines will be handled as a piece: generally, if you want to change the format of one type of message, you will also want to change the format of the other.

The routines are formally specified as follows:

typedef void (*XtErrorMsgHandler)(String, /* name       */
				  String,        /* type       */
				  String,        /* class      */
				  String,        /* default    */
				  String   *,    /* params     */
				  Cardinal *) ;  /* num_params */

extern XtErrorMsgHandler XtAppSetWarningMsgHandler(XtAppContext, XtErrorMsgHandler) ;
extern XtErrorMsgHandler XtAppSetErrorMsgHandler(XtAppContext, XtErrorMsgHandler) ;

The name parameter identifies this error or message - typically, it will be a key used to lookup a message in an Error string database through the routine XtGetErrorDatabaseText() or similar.

The type parameter indicates the general kind of error; typically, when used by widget authors, it identifies the routine which detects the problem, so for example in Motif it might read "CvtStringToWidget", "CvtPixelToRenditionPixel", and so on.

The class parameter specifies the general class of error or message - for example, in Motif it might read "XtToolkitError" or "ToolkitError", depending on where Motif believes the error to have emanated.

The default parameter typically is a description of the error as detected in the software, but in the language of the programmer; typically it is output if the error or message handler fails to find a localized string associated with the given name and class.

The params and num_params arguments specify extra detail associated with the error message; the error or message handler will presumably have to format and concatenate this data when present prior to output. In Motif 2.x, there is a protocol such that the toolkit adds parameters with the first such parameter being the value "XmeWarning", so that the toolkit can identify whether the error hs emanated from within the toolkit's standard warning handlers, or elsewhere.

As an example, a typical warning handler will have the following design:

void WarningHandler(String    name, 
		    String    type,
		    String    s_class, 
		    String    message, 
		    String   *params, 
		    Cardinal *num_params)
{
    /*
    ** Whatever the application context is...
    */
    extern XtAppContext app_context ;

    /*
    ** MAX_MESSAGE_STRING to be defined, something like 1024, to
    ** allow plenty of space for formatting.
    **
    ** Naturally, a safer approach would dynamically allocate space...
    */
    char buffer[MAX_MESSAGE_STRING] ;
    int  i ;

    /* Look up any localized version of the message */
    XtGetErrorDatabaseText(name, type, s_class, message, buffer, MAX_MESSAGE_STRING) ;

    /* Format the message and parameters in our style */

    for (i = 0 ; i < *num_params ; i++) {
	(void) strcat(buffer, "\n") ;
	(void) strcat(buffer, params[i]) ;
    }

    /*
    ** Use Xt as the delivery mechanism.
    **
    ** XtWarning(buffer) can be used if the
    ** default application context is sufficient.
    */
    XtAppWarning(app_context, buffer) ;
}

Invoking the lower level message delivery handlers from the higher level

There are four routines to consider: XtAppError() and XtError(), which call the lower level installed error handler, XtAppWarning() and XtWarning(), which invoke the lower level installed message handler. The function prototypes are as follows:

    extern void XtAppError(XtAppContext  app_context,   String error) ;
    extern void XtError(String error) ;
    extern void XtAppWarning(XtAppContext app_context, String warning) ;
    extern void XtWarning(String warning) ;

A sample error handler

The routines defined below are typical of experiences with various widget sets and the X environment in general. We can categorize the reasons for the handler as follows:

  • Not all widgets are equal, and freeware ones in particular tend to be not sufficiently robust in all circumstances. The errors which they raise can however sometimes be survived.
  • Not all window managers are equal, and some have certain anti-social behavior such as grabbing the mouse at certain times, although this also can be corrected by suitable application code.
  • Not all X implementations are equal, and various X errors are logically survivable.
  • The application needs to save state in the face of errors in order to avoid data loss when the X system is going down.

Firstly, we define some types for plug-in application save routines:

#ifndef   _NO_PROTO
typedef void (*XApplicationSaveHandler)(XtPointer applicationData) ;
#else  /* _NO_PROTO */
typedef void (*XApplicationSaveHandler)() ;
#endif /* _NO_PROTO */

This allows us to pass application-specific data through to any plug-in save handler we may wish to call from the error handling routines we will define.

Secondly, we define some variables to hold state:

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>

/* The previously-installed X error handler */
static XErrorHandler           default_error        = (XErrorHandler) 0 ;
/* The previously-installed X I/O error handler */
static XIOErrorHandler         default_ioerror      = (XIOErrorHandler) 0 ;
/* The current routine for saving the application */
static XApplicationSaveHandler current_save_handler = (XApplicationSaveHandler) 0 ;
/* Any application-specific data required by the above */
static XtPointer               current_save_data    = (XtPointer) 0 ;

Now we define the Xlib error handler itself, using gained knowledge of various X problems which are known to be survivable, and so forth. Not all cases need necessarily be copied - it depends on the widget sets and so forth used by the application.

/*
** The following routine is entirely heuristic, and
** attempts to survive in the face of some pretty hostile
** interactions between multiple third party widget sets,
** and so forth.
*/

#ifndef   _NO_PROTO
static int _XlibErrorHandler(Display *display, XErrorEvent *event)
#else  /* _NO_PROTO */
static int _XlibErrorHandler(display, event)
    Display     *display ;
    XErrorEvent *event ;
#endif /* _NO_PROTO */
{
    static Boolean property_warned = False ;
	   Boolean try_recovery    = False ;
	   Boolean probably_fatal  = False ;

    switch (event->request_code)
    {
	case  0 :
	    try_recovery = True ;
	    break ;

	/*
	** Generally caused by attempting to draw on a Canvas before it
	** is realized. Programmer error, really.
	*/

	default : if ((event->error_code != BadWindow)   &&
		  (event->error_code != BadDrawable) &&
		  (event->error_code != BadPixmap)) {
		   probably_fatal = True ;
	      }

	      /* FALLTHROUGH */

	/*
	** Some window managers (fvwm) grab the mouse
	** and do not release it properly when the application needs it.
	*/
	case X_GrabButton:
	    if ((event->request_code == X_GrabButton) &&
		    (event->error_code != BadAccess)) {
		probably_fatal = True ;
	    }

	    /* FALLTHROUGH */

	/*
	** X11R6 running on X11R5 WM server
	** Probably WM_NAME in XtAppCreateShell which is deprecated code
	** in any case.
	** This can show up running Linux displaying onto Solaris 8,
	** although there are reports of HPUX having the same issue.
	*/

	case X_DeleteProperty  : /* FALLTHROUGH */
	    if ((event->request_code == X_DeleteProperty) &&
		    (event->error_code == BadWindow)) {
		if (event->resourceid == (XID) 0) {
		    try_recovery = True ;
		}
		else {
		    probably_fatal = True ;
		}
	    }

	    /* FALLTHROUGH */

	/* X11R6 running on X11R5 WM server     */
	/* Probably WM_NAME in XtAppCreateShell */
	/* Which is deprecated code in any case */
	/* As above for context                 */
	case X_ChangeProperty  :
	    if ((event->request_code == X_ChangeProperty) &&
		    (event->error_code == BadAtom)) {
		if (event->resourceid == (XID) 0) {
		    try_recovery = True ;
		}
		else {
		    probably_fatal = True ;
		}
	    }

	    /* FALLTHROUGH */

	/*
	** Ignore XConfigureWindow errors that some third party widgets raise.
	** Again, a widget author error.
	*/
	case X_ConfigureWindow :
	    if (event->request_code == X_ConfigureWindow) {
		try_recovery = True ;
	    }

	    /* FALLTHROUGH */

	/*
	** XRT/Pane has/had this problem, if configured dynamically
	** for orientation post-manage.
	*/

	case X_CreateWindow:
	    if ((event->request_code == X_CreateWindow) &&
		    (event->error_code == BadValue)) {
		probably_fatal = True ;
		try_recovery   = True ;
	    }

	    /* FALLTHROUGH */

	/*
	** Colormap issue... system does not support virtual Colormaps.
	** This ought to be survivable unless there are hand-drawn graphics.
	*/
	case X_CreateColormap  :
	    if (event->request_code == X_CreateColormap) {
		try_recovery = True ;
	    }

	    /* FALLTHROUGH */

	/*
	** Out of colors... generally, this can be survived,
	** although what the result looks like is another issue.
	** The user should have sufficient of the GUI to exit
	** gracefully in whatever way is appropriate, close down
	** the typical color hoggers like the web browser (no names -
	** you know who you are) or desktop publishing package
	** (also no names) and then retry.
	*/
	case X_AllocColor       : /* FALLTHROUGH */
	case X_AllocColorCells  : /* FALLTHROUGH */
	case X_AllocNamedColor  : /* FALLTHROUGH */
	case X_AllocColorPlanes :
	       if ((event->request_code == X_AllocColor)       ||
		(event->request_code == X_AllocColorCells)  ||
		(event->request_code == X_AllocColorPlanes) ||
		(event->request_code == X_AllocNamedColor)) {
		if ((event->error_code == BadAlloc) ||
			 (event->error_code == BadColor)) {
		    try_recovery = True ;
		}
	    }

	    /* FALLTHROUGH */

	/*
	** Attempt to write into a read-only colormap
	** Survivable, if X doesn't exit on its own behalf...
	** Generally, a programming error, not taking sufficient
	** care over various Visual types and read/write Colormap
	** differences.
	*/
	case X_StoreColors:
	    if ((event->request_code == X_StoreColors) &&
		    (event->error_code == BadAccess)) {
		try_recovery = True ;
	    }

	    /* FALLTHROUGH */

	/*
	** Xaw3D shadow problems. Poor widget authoring in the face
	** of various Visual and Colormap types.
	*/
	case X_QueryColors:
	    if ((event->request_code == X_QueryColors) &&
		    (event->error_code == BadValue)) {
		try_recovery = True ;
	    }

	    /* FALLTHROUGH */

	/*
	** Some errors we regard as minor and ignorable - XFreeColors in particular
	*/
	case X_FreeColors:
	    if (probably_fatal == False) {
		try_recovery = True ;
	    }

	    break ;
    }

    /*
    ** Save the Application State, using the plug-in routines.
    */

    if ((try_recovery == FALSE) || (probably_fatal == TRUE)) {
	if (current_save_handler != (XApplicationSaveHandler) 0) {
	    (*current_save_handler)(current_save_data) ;
	}
    }

    if (try_recovery == False) {
	/*
	** Unstack our error handlers - the builtin X ones abort
	*/

	(void) XSetErrorHandler((XErrorHandler) 0) ;
	(void) XSetIOErrorHandler((XIOErrorHandler) 0) ;

	(void) fprintf(stderr, "Fatal Xlib Error for request code %d\n",
					   event->request_code) ;

	/* The builtin X handler aborts */

	if (default_error != (XErrorHandler) 0) {
	    (*default_error)(display, event) ;

	    /* NOT REACHED (Or is it) */
	}
    }

    if (try_recovery == True) {
	if ((event->request_code != 0) && (probably_fatal == False)) {
	    /*
	    ** The X11R5/X11R6 issue cross-display: only warn once,
	    ** or else we get the result per shell.
	    */

	    if (((event->request_code == X_ChangeProperty) &&
		    (event->error_code == BadAtom)) ||
		((event->request_code == X_DeleteProperty) &&
		    (event->error_code == BadWindow))) {
		if (property_warned == False) {
		(void) fprintf(stderr,
			       "Warning: Ignoring Xlib Error for request code %d\n",
			       event->request_code) ;

		property_warned = True ;
		}
	    }
	else {
	    (void) fprintf(stderr,
			   "Warning: Ignoring Xlib Error for request code %d\n",
			   event->request_code) ;
	    }
	}
	else if (probably_fatal == True) {
	    (void) fprintf(stderr,
			   "Warning: Probably fatal Xlib Error for request code %d\n",
			   event->request_code) ;
	}
    }

    return True ;
}

Now we define the I/O error handler. This is considerably simpler - because not survivable. We can only try and save state.

#ifndef   _NO_PROTO
static int _XlibIoErrorHandler(Display *display)
#else  /* _NO_PROTO */
static int _XlibIoErrorHandler(display)
	Display *display ;
#endif /* _NO_PROTO */
{
    /*
    ** Your chances of surviving this are precisely zero.
    ** Most likely, you have lost the connection to the X server.
    */

    if (current_save_handler != (XApplicationSaveHandler) 0) {
	(*current_save_handler)(current_save_data) ;
    }

    (void) XSetErrorHandler((XErrorHandler) 0) ;
    (void) XSetIOErrorHandler((XIOErrorHandler) 0) ;

    /*
    ** The default handler will abort.
    */

    if (default_ioerror != (XIOErrorHandler) 0) {
	(*default_ioerror)(display) ;
    }

    /*
    ** Just in case it doesn't...
    */

    exit(1) ;
}

That covers the Xlib layer. Now we define a few small routines to handle the Xt layer. Firstly, the general purpose handler:

#ifndef   _NO_PROTO
static void _XtErrorHandler(String message, Boolean fatal)
#else  /* _NO_PROTO */
static void _XtErrorHandler(message, fatal)
	String  message ;
	Boolean fatal ;
#endif /* _NO_PROTO */
{
    (void) fprintf(stderr,
		   "X Tookit %s: %s\n",
		   (fatal ? "Fatal error" : "Warning message"),
		   message) ;

    if (fatal) {
	/*
	** Save State.
	*/

	if (current_save_handler != (XApplicationSaveHandler) 0) {
	    (*current_save_handler)(current_save_data) ;
	}

	exit(1) ;
    }
}

Now a couple of wrappers which are to be registered with the X toolkit:

#ifndef   _NO_PROTO
static void _XtWarningErrorHandler(String message)
#else  /* _NO_PROTO */
static void _XtWarningErrorHandler(message)
	String message ;
#endif /* _NO_PROTO */
{
    _XtErrorHandler(message, False) ;
}

#ifndef   _NO_PROTO
static void _XtFatalErrorHandler(String message)
#else  /* _NO_PROTO */
static void _XtFatalErrorHandler(message)
	String message ;
#endif /* _NO_PROTO */
{
    _XtErrorHandler(message, True) ;
}

Lastly, we simply need a public interface, which initializes the handlers, and supplies the plug-in save handler for the application:

#ifndef   _NO_PROTO
void InitializeErrorHandlers(XtAppContext            context,
			     XApplicationSaveHandler save_handler, 
			     XtPointer               save_data)
#else  /* _NO_PROTO */
void InitializeErrorHandlers(context, save_handler, save_data)
	XtAppContext            context ;
	XApplicationSaveHandler save_handler ;
	XtPointer               save_data ;
#endif /* _NO_PROTO */
{
    current_save_handler = save_handler ;
    current_save_data    = save_data ;

    if (context != (XtAppContext) 0) {
	(void) XtAppSetErrorHandler(context,   _XtFatalErrorHandler) ;
	(void) XtAppSetWarningHandler(context, _XtWarningErrorHandler) ;
    }

    default_error   = XSetErrorHandler(_XlibErrorHandler) ;
    default_ioerror = XSetIOErrorHandler(_XlibIoErrorHandler) ;
}

Sources

The sources for the above are:

Bibliography

The following materials are available for further reading. Firstly, for reference materials on the Motif 2.1 toolkit:
    Motif Reference Manual for Motif 2.1,
    Antony Fountain and Paula Fergusson,
    O'Reilly and Associates,
    ISBN: 1-56592-654-4
    Buy it from Amazon.com or Amazon.co.uk
The companion Motif 2.1 Programming Manual is currently only available in electronic form. It, and the Reference Manual, can be downloaded variously in PDF or HTML format from www.ist.co.uk/motif/books (Reading, UK) or www.ist-inc.com/motif/books (Palo Alto, CA)
For a general Xt reference manual, the following is recommended:
    X Toolkit Intrinsics Reference Manual,
    Edited by David Flanagan,
    O'Reilly and Associates,
    ISBN: 1-56592-007-4
    Buy it from Amazon.com or Amazon.co.uk
For a general X11 library reference manual, the following is recommended:
    Xlib Reference Manual,
    Edited by Adrian Nye,
    O'Reilly and Associates,
    ISBN: 1-56592-006-6
    Buy it from Amazon.com or Amazon.co.uk
A good one-stop general purpose Motif programming manual is:
    Advanced Motif Programming Techniques,
    Alistair George and Mark Riches,
    Prentice Hall,
    ISBN 0-13-219965-3
    Unfortunately this book is out of print,
    but you may be able to buy it from Amazon.com
    
This last volume is Motif 1.2 specific, although the general techniques which are described remain invaluable, irrespective of the version of the toolkit you are using.

 


Sponsored by X-Designer - The Leading X/Motif GUI Builder - Click to download a FREE evaluation

 

Goto top of page

 

[IST Limited]
IST Limited is the
proud sponsor of motifdeveloper.com.
 

Thanks to all the contributors to these pages.

Privacy Policy

 
"Motif" is a registered trademark of The Open Group. All other trademarks are the property of their respective owners.

Some articles/papers here have their own copyright notice. All other information is copyright ©1999-2008 IST Limited

[CommerceOne] MW3 site originally by Ken Sall of Commerce One (formerly Century Computing).