ipcUtils.c


/*
   $Header: ipcUtils.c,v 1.10 97/04/14 16:18:35 doomer Exp $
   $Revision: 1.10 $
   $Date: 97/04/14 16:18:35 $
   $Author: doomer $
   Copyright (c) 1997 John Dumais.  All rights reserved.
*/

#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <Xm/Xm.h>
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
#include <stdio.h>

/*
   This file is the source for a library of routines that allows
   us to do some interesting stuff with the window a VEE process
   creates.
*/

/*
   The operations we supply to manipulate the VEE window.  We 
   give ourselves the capability to push VEE's run, stop, pause,
   and step buttons.
*/

enum VeeOperation{
	vOperNotDefined = -1,
	vRun,
	vPause,
	vStepInto,
	vContinue
};

/*
   We define a table that associates a given action with the series
   of keystrokes we send to the VEE window to make that action happen.
*/

struct{
	enum VeeOperation op;
	KeySym keySym;
	unsigned char sendControl	:1;
} VeeOperationStruct[]={
	{vRun, XK_g, 1},
	{vPause, XK_p, 1},
	{vStepInto, XK_t, 1},
	{vOperNotDefined, 0, 0}
};

/*
   A utility function that gives us the index into a table
   of keystrokes we need to send to a VEE program to get
   some action to take place.
*/

int tableIndexForOperation(veeOp)
enum VeeOperation veeOp;{

	int returnVal = -1;
	int index=0;

	while(VeeOperationStruct[index].op != vOperNotDefined){
		if(VeeOperationStruct[index].op == veeOp){
			returnVal=index;
			break;
		}

		index++;
	}

	return returnVal;
}

/*
   Set up a function to be called when X errors occur.  The most
   likely time for this is when we ask for a VEE window handle
   when there is no VEE window.  We don't want our application to
   terminate, we would rather handle this case gracefully.
*/

static errorHandler=0;

int xErrorHandler(aDisplay, xError)
Display *aDisplay;
XErrorEvent *xError;{
	return 0;
}

/*
   When a VEE process starts, it puts its window id in an atom.
   We read this atom to find a VEE window we can control.
*/

Atom wmVeeWindow=(Atom)0;

/*
   When a VEE process starts, it takes ownership of an atom.  
   Taking ownership means that the X window system associates 
   a window id with the atom.  If we find out who owns the atom,
   we have identified a VEE window.  We find out who owns an atom
   by making the X call XGetSelectionOwner().

   Because only one window can own an atom at a time, and because
   a VEE process only asserts ownership of the atom at startup
   time, we can only identify the last VEE window created.
*/

Window findVeeWin(aDisplay)
Display *aDisplay;{
   Window selectionOwner;

   if(!errorHandler){
	   XSetErrorHandler(xErrorHandler);
   }

   wmVeeWindow=XInternAtom(aDisplay, "WM_VEEWINDOW", True);
   if(!wmVeeWindow){
      return((Window) 0);
   }

   selectionOwner=XGetSelectionOwner(aDisplay, wmVeeWindow);

   if(selectionOwner == (Window)None){
	   return((Window)0);
   }

   return(selectionOwner);
}

/*
   Send a keystroke event to a VEE window.
*/

Status sendKeyEvent(aDisplay, keySym, sendControl)
Display *aDisplay;
KeySym keySym;
unsigned char sendControl;{

   Window aWindow;
   XEvent anEvent;
   Status sendEventStatus;

   aWindow=findVeeWin(aDisplay);

   if(!aWindow){
      return(0);
   }

   memset(&anEvent, '\0', sizeof(XEvent));

   anEvent.type=KeyPress;
   anEvent.xkey.type=KeyPress;
   anEvent.xkey.send_event=True;
   anEvent.xkey.display=aDisplay;
   anEvent.xkey.window=aWindow;
   anEvent.xkey.root=RootWindow(aDisplay, 0);
   anEvent.xkey.subwindow=aWindow;
   anEvent.xkey.time=CurrentTime;
   anEvent.xkey.x=0;
   anEvent.xkey.y=0;
   anEvent.xkey.x_root=0;
   anEvent.xkey.y_root=0;

   if(sendControl){
	   anEvent.xkey.state=ControlMask;
   }
   else{
	   anEvent.xkey.state=0;
   }

   anEvent.xkey.keycode=XKeysymToKeycode(aDisplay, keySym);
   anEvent.xkey.same_screen=True;

   sendEventStatus=XSendEvent(aDisplay, aWindow, True, KeyPressMask, &anEvent);

   return(sendEventStatus);
}

/*
   Press VEE's 'Run' button, which also happens to be the 'Resume' button.
*/

Status sendGoKeyEvent(aDisplay)
Display *aDisplay;{
	int tableIndex;

	tableIndex=tableIndexForOperation(vRun);
	if(tableIndex >= 0){
		return(sendKeyEvent(aDisplay, VeeOperationStruct[tableIndex].keySym,
							VeeOperationStruct[tableIndex].sendControl));
	}

	return 0;
}

/*
   Press VEE's 'Pause' button.
*/

Status sendPauseKeyEvent(aDisplay)
Display *aDisplay;{
	int tableIndex;

	tableIndex=tableIndexForOperation(vPause);
	if(tableIndex >= 0){
		return(sendKeyEvent(aDisplay, VeeOperationStruct[tableIndex].keySym,
							VeeOperationStruct[tableIndex].sendControl));
	}

	return 0;
}

/*
   Press VEE's 'Step Into' button.
*/

Status sendStepKeyEvent(aDisplay)
Display *aDisplay;{
	int tableIndex;

	tableIndex=tableIndexForOperation(vStepInto);
	if(tableIndex >= 0){
		return(sendKeyEvent(aDisplay, VeeOperationStruct[tableIndex].keySym,
							VeeOperationStruct[tableIndex].sendControl));
	}

	return 0;
}

/*
   Press VEE's 'Run' button, which also happens to be the 'Resume' button.
*/

Status sendContKeyEvent(aDisplay)
Display *aDisplay;{
	return(sendGoKeyEvent(aDisplay));
}

/*
   Send an 'F1' keystroke to a VEE window.  You can modify this function
   to send any keystroke value.
*/

Status sendF1KeyEvent(aDisplay)
Display *aDisplay;{
	return(sendKeyEvent(aDisplay, XK_F1, 0 /* control key? */));
}

/*
   Remove VEE's window and its associated icon from the workspace.
*/

Status hideWindow(aDisplay)
Display *aDisplay;{
   
   Window aWindow;

   aWindow=findVeeWin(aDisplay);

   if(!aWindow){
      return(0);
   }

   XUnmapWindow(aDisplay, aWindow);

   return(0);
}

/*
   Remove VEE's main window from the workspace and display its
   icon window.
*/

Status iconizeWindow(aDisplay)
Display *aDisplay;{
   
   Window aWindow;

   aWindow=findVeeWin(aDisplay);

   if(!aWindow){
      return(0);
   }

   return(XIconifyWindow(aDisplay, aWindow, DefaultScreen(aDisplay)));
}

/*
   Show VEE's main window in its last known location.
*/

Status restoreWindow(aDisplay)
Display *aDisplay;{
   
   Window aWindow;

   aWindow=findVeeWin(aDisplay);

   if(!aWindow){
      return(0);
   }

   return(XMapRaised(aDisplay, aWindow, DefaultScreen(aDisplay)));
}

/*
   This is a callback function that gets called when you press the
   'Run' button in our example application.
*/

void run(widget, clientData, cbs)
Widget widget;
XtPointer clientData;
XmPushButtonCallbackStruct *cbs;{
   
   sendGoKeyEvent(XtDisplay(widget));

   return;
}

/*
   This is a callback function that gets called when you press the
   'Pause' button in our example application.
*/

void pauseVee(widget, clientData, cbs)
Widget widget;
XtPointer clientData;
XmPushButtonCallbackStruct *cbs;{
   
   sendPauseKeyEvent(XtDisplay(widget));

   return;
}

/*
   This is a callback function that gets called when you press the
   'Step' button in our example application.
*/

void step(widget, clientData, cbs)
Widget widget;
XtPointer clientData;
XmPushButtonCallbackStruct *cbs;{
   
   sendStepKeyEvent(XtDisplay(widget));

   return;
}

/*
   This is a callback function that gets called when you press the
   'Cont' button in our example application.
*/

void cont(widget, clientData, cbs)
Widget widget;
XtPointer clientData;
XmPushButtonCallbackStruct *cbs;{
   
   sendContKeyEvent(XtDisplay(widget));

   return;
}

/*
   This is a callback function that gets called when you press the
   'F1' button in our example application.
*/

void f1(widget, clientData, cbs)
Widget widget;
XtPointer clientData;
XmPushButtonCallbackStruct *cbs;{
   
   sendF1KeyEvent(XtDisplay(widget));

   return;
}

/*
   This is a callback function that gets called when you press the
   'Hide' button in our example application.
*/

void hide(widget, clientData, cbs)
Widget widget;
XtPointer clientData;
XmPushButtonCallbackStruct *cbs;{
   
   hideWindow(XtDisplay(widget));

   return;
}

/*
   This is a callback function that gets called when you press the
   'Iconize' button in our example application.
*/

void iconize(widget, clientData, cbs)
Widget widget;
XtPointer clientData;
XmPushButtonCallbackStruct *cbs;{
   
   iconizeWindow(XtDisplay(widget));

   return;
}

/*
   This is a callback function that gets called when you press the
   'Restore' button in our example application.
*/

void restore(widget, clientData, cbs)
Widget widget;
XtPointer clientData;
XmPushButtonCallbackStruct *cbs;{
   
   restoreWindow(XtDisplay(widget));

   return;
}

/*
   $Log:	ipcUtils.c,v $
 * Revision 1.10  97/04/14  16:18:35  16:18:35  doomer (John Dumais)
 * documentation.
 * 
*/