[comp.windows.x] XKillClient: What does it do, and how to stop it.

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();
  }