/*@ cc -g -c @I @F @L -o @R.o */ /* ** A. J. Fountain, ** Imperial Software Technology, ** 120 Hawthorne Avenue, ** Suite 101, ** Palo Alto, ** CA 94301 ** ** Telephone: (650) 688-0200 ** Fax: (650) 688-1054 ** ** Imperial Software Technology (IST), ** Kings Court, ** 185 Kings Road, ** Reading, ** Berkshire, ** United Kingdom RG1 4EX. ** ** Telephone: +44 189 587055 ** Fax: +44 189 589005 ** ** http://www.ist-inc.com ** email: af@ist-inc.com */ #ifndef lint static char *sccsid[] = {"%Z%%Q%%M% %I%"} ; /* %E% */ #endif /* lint */ #include #include #include #include /* 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 ; /* ** 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 dont 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 ; } #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) ; } #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) ; } } #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) ; } #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) ; }