xg00@GTE.COM (Xev Gittler) (10/31/89)
I am trying to find out how to stop an XKillClient from actually killing the client. A little background: We are starting to get in X terminals, all run off a central VAX. Just about everybody is going to want to run an xclock, xbiff, etc, and it seems sort of ridiculous to have two dozen of these processes running, particularly when one would do the job adequately. So I set out to right a re-entrant X program (using Xt) that would run in one process and handle multiple displays. The problem I run into is how X handles a killclient. If one person does a killclient on a window running from this application, all windows on all displays will die. Obviously, this is not a good solution. So the question is: Is there a way to get X to ignore a killclient, or at least have the application know that a killclient has been issued, rather then just killing the windows? -- Xev Gittler xg00@gte.com, or xg00%gte.com@relay.cs.net
swick@ATHENA.MIT.EDU (Ralph R. Swick) (11/02/89)
> What does it do XKillClient shuts down the specified client's server connection. The client had better not try to exercise the connection any longer. > Is there a way to get X to ignore a killclient, or > at least have the application know that a killclient has been issued, > rather then just killing the windows? Depends what you mean by "X". There's no way to get the server to ignore the request, nor is there any guaranteed portable way to learn that your connection has been shutdown by someone else. Most probably, a KillClient will result in an Xlib IO error in the affected client, so you could hook your exception handler into Xlib with XSetIOErrorHandler. I considered this an interesting enough problem to do some experimentation. The following diffs to /x/examples/Xaw/xlabel.c will produce a multi-display client which attempts to survive a KillClient on either of its windows. This client doesn't work under R3 (the fault probably lies in Xt) but does with our current pre-R4 sources (and may even continue to work when R4 is released. :-) It assumes that the Display pointer passed to the error handler can actually be used for something (the Xlib spec doesn't seem to guarantee this; in particular that an XCloseDisplay will not result in further errors) and it has a large memory leak, since it doesn't (and currently can't) destroy the widget data structures on the defunct display, but it may give some directions to pursue. You'll need to compile it with -DR3 if you haven't created /usr/include/X11/Xaw/. *** /R3/x/examples/Xaw/xlabel.c --- kill.c Wed Nov 1 10:15:43 1989 *************** *** 1,7 **** #include <X11/Intrinsic.h> ! #include <X11/Cardinals.h> #include <X11/Label.h> ! #include <stdio.h> /* Command line options table. Only resources are entered here...there is a pass over the remaining options after XtParseCommand is let loose. */ --- 1,17 ---- + #include <stdio.h> + #include <X11/Intrinsic.h> ! #include <X11/Shell.h> ! #include <sys/errno.h> ! #include <setjmp.h> ! ! #ifndef R3 ! #include <X11/Xaw/Label.h> ! #include <X11/Xaw/Cardinals.h> ! #else #include <X11/Label.h> ! #include <X11/Cardinals.h> ! #endif /* Command line options table. Only resources are entered here...there is a pass over the remaining options after XtParseCommand is let loose. */ *************** *** 17,39 **** Syntax(call) char *call; { ! fprintf( stderr, "Usage: %s\n", call ); } void main(argc, argv) unsigned int argc; char **argv; { Widget toplevel; toplevel = XtInitialize( NULL, "XLabel", options, XtNumber(options), &argc, argv ); ! if (argc != 1) Syntax(argv[0]); XtCreateManagedWidget( "label", labelWidgetClass, toplevel, NULL, ZERO ); XtRealizeWidget(toplevel); XtMainLoop(); } --- 27,88 ---- Syntax(call) char *call; { ! fprintf( stderr, "Usage: %s alternatehost:dpy\n", call ); } + static jmp_buf env; + static dpy_count; + + IOErrorHandler(dpy) + Display *dpy; + { + Boolean try_to_continue = False; + extern int errno; + if (errno == EPIPE) { + printf( "connection closed on %s.\n", DisplayString(dpy) ); + try_to_continue = True; + } + XtCloseDisplay( dpy ); + if (try_to_continue && --dpy_count) longjmp(env, 1); + printf( "no more displays; exiting\n" ); + exit(0); + } + void main(argc, argv) unsigned int argc; char **argv; { Widget toplevel; + XtAppContext app; + Display *dpy2; toplevel = XtInitialize( NULL, "XLabel", options, XtNumber(options), &argc, argv ); ! dpy_count++; ! if (argc != 2) Syntax(argv[0]); + app = XtWidgetToApplicationContext(toplevel); XtCreateManagedWidget( "label", labelWidgetClass, toplevel, NULL, ZERO ); XtRealizeWidget(toplevel); + + if ((dpy2 = XtOpenDisplay(app, argv[1], NULL, "XLabel", NULL, ZERO, + &argc, argv)) + == NULL) { + printf( "?couldn't open alternate display %s\n", argv[1] ); + } else { + Widget top2 = XtAppCreateShell( NULL, "XLabel", + applicationShellWidgetClass, + dpy2, NULL, ZERO ); + XtCreateManagedWidget( "label", labelWidgetClass, top2, NULL, ZERO ); + XtRealizeWidget(top2); + dpy_count++; + } + + XSetIOErrorHandler(IOErrorHandler); + if (setjmp(env)) setjmp(env); + XtMainLoop(); }