/* X11suHelper.c -- helper process for magic on X windows which signals the
 *		  parent (magic) whenever there is input available.
 */

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

/* 
 * Portability stuff
 */

#if     (defined(MIPSEB) && defined(SYSTYPE_BSD43)) || ibm032
# define        SIG_RETURNS_INT
#endif

/* Some machines have signal handlers returning an int, while other machines
 * have it returning a void.  If you have a machine that requires ints put 
 * it in the list of machines in misc/magic.h.
 */
#ifdef	SIG_RETURNS_INT
#define	sigRetVal	int
#else
#define	sigRetVal	void
#endif


/*
 * Main program
 */

int readPipe,writePipe;	/* pipe file descriptor to magic process */
int parentID;		/* process id of parent */
Display *grXdpy;

KeySym UpArrow, DnArrow, LtArrow, RtArrow; /* keysym values */
enum {
  UP_ARROW = 'P'-64,
  DN_ARROW = 'N'-64,
  LT_ARROW = 'B'-64,
  RT_ARROW = 'F'-64
};

sigRetVal MapWindow();

main (argc, argv)
    int argc;
    char **argv;
{
    XEvent xevent;

#ifdef macII
    set42sig();
#endif macII

    if (argc <= 1) {
	fprintf(stderr, "%s: expecting two file-descriptor numbers.\n\
	    \t(This program should be run only by magic itself.)\n", argv[0]);
	exit(1);
    }

    sscanf(argv[1], "%d %d", &readPipe,&writePipe);
    grXdpy = XOpenDisplay(0);
    if (grXdpy == (Display *) 0) {
	fprintf(stderr,"%s: XOpenDisplay failed.\n", argv[0]);
	exit(1);
    }

    UpArrow= XStringToKeysym ("Up");
    DnArrow= XStringToKeysym ("Down");
    LtArrow= XStringToKeysym ("Left");
    RtArrow= XStringToKeysym ("Right");

    parentID = getppid();

    signal(SIGINT,SIG_IGN);
    signal(SIGQUIT,SIG_IGN);
    signal(SIGTERM,MapWindow); 
#ifdef SIGTSTP
    signal(SIGTSTP,SIG_IGN);
#endif
#ifdef SIGCONT
    signal(SIGCONT,SIG_IGN);
#endif

    while (1)
    {
	XNextEvent(grXdpy, &xevent);
	if (isString(xevent) ==0) 
	{
	    write(writePipe, &xevent, sizeof(XEvent));
#ifndef USE_IO_PROBE
	    kill(parentID, SIGIO);
#endif
	}
    }
}

isString (event)
    XEvent event;
{
    if (event.type == KeyPress) 
    {
	XKeyPressedEvent *KeyPressedEvent = (XKeyPressedEvent *) &event;
	char inChar[10],c,*p;
	int nbytes;
	KeySym keysym;

	nbytes = XLookupString(KeyPressedEvent,inChar,sizeof(inChar),
			 &keysym,NULL);
	
	if (keysym == UpArrow || keysym == DnArrow 
	    || keysym == LtArrow || keysym == RtArrow) {
	  if (keysym == UpArrow) c = UP_ARROW;
	  else if (keysym == DnArrow) c = DN_ARROW;
	  else if (keysym == LtArrow) c = LT_ARROW;
	  else if (keysym == RtArrow) c = RT_ARROW;
	  write (writePipe, &event, sizeof(XEvent));
	  write (writePipe, &c, sizeof(char));
	}
	else {
	  p = inChar;
	  while (nbytes--)
	  {
	     if ( (c = *p++) == 3)
	     {
	     	  kill(parentID, SIGINT);
	     } 
	     else
	     {
	          write(writePipe, &event, sizeof(XEvent));
	          write(writePipe, &c, sizeof(char));
#ifndef USE_IO_PROBE
	          kill(parentID, SIGIO);
#endif
	     }
	  } 
	}
	return 1;
    }
    else return 0;
}

sigRetVal
MapWindow()
{
    Window window;

    if ( read(readPipe, (char *)&window, sizeof(Window)) == sizeof(Window))
    {
	XSelectInput(grXdpy, window,
		     KeyPressMask|ButtonPressMask|
		     ButtonReleaseMask|ExposureMask|
		     StructureNotifyMask|
		     OwnerGrabButtonMask);
	XSync(grXdpy,1);
#ifdef SYSV
    /* Note:  HAS NOT BEEN TESTED.  Just a "good guess" based upon some mods
     * to a similar driver which was tested.	1/19/89, Livermore.
     */
    signal(SIGTERM, MapWindow);
#endif SYSV
    }
    else
	fprintf(stderr,"xhelper: read on pipe failed\n");
}
