 /*
  * Khoros: $Id: jp_util.c,v 1.3 1992/03/20 22:48:04 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: jp_util.c,v 1.3 1992/03/20 22:48:04 dkhoros Exp $";
#endif

 /*
  * $Log: jp_util.c,v $
 * Revision 1.3  1992/03/20  22:48:04  dkhoros
 * VirtualPatch5
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 * 
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *----------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "forms.h"

#include "jp.h"

static void xvf_quit_jp_cb(), xvf_control_jp_cb();
static Widget find_widget(), find_xvutils_widget();

/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 
   >>>>                                                       	<<<<
   >>>>	       Journal Playback Utility Routines              	<<<<
   >>>>                                                       	<<<<
   >>>>                 xvf_find_window()                      	<<<<
   >>>>                 xvf_find_widget()                      	<<<<
   >>>>                 xvf_find_xvform_widget()               	<<<<
   >>>>                 xvf_find_name()                        	<<<<
   >>>>			xvf_popup_control()			<<<<
   >>>>			xvf_quit_jp_cb()			<<<<
   >>>>			xvf_control_jp_cb()			<<<<
   >>>>                                                       	<<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */



/************************************************************
*
*  Routine Name: xvf_find_window
*
*      Purpose:  This routine takes a full name 
*		 (example:great-grandparent.grandparent.parent.child)
*		 and returns the window that is so named.
*
*        Input:  parent   - the parent window from which we will begin search
*		 name     - the name of the window we're looking for
*		 toplevel - a flag telling if this window is a toplevel one.
*
*       Output:  window - the window found with the specified name
*
*   Written By:  Mark Young & Danielle Argiro
*
*************************************************************/

Window xvf_find_window(parent, name, toplevel)

Window parent;
char   *name;
int    *toplevel;
{
	int	 i, size;
	unsigned int num;
	char	 *temp, *child_name;
	Window	 *children, window, dummy;


	/*
	 *  Return NULL there are no more children to search but we 
	 *  still haven't found the window with the desired name.
	 */
	if (!XQueryTree(xvf_display, parent, &dummy, &dummy, &children, &num))
	   return(NULL);

	/*
	 *  Get the size of the first segment of the name.
	 */
	if ((temp = strchr(name, '.')) != NULL)
	   size = temp - name;
	else
	   size = xvf_strlen(name);

	/*
	 *  For each child, search for the window that matches
	 *  the segment of name.
	 */
	for (i = 0; i < num; i++)
	{
	    /*
	     *  Get the current child's name and see if it is a segment of the
	     *  name of the window we are searching for.
	     */
	    if (XFetchName(xvf_display, children[i], &child_name))
	    {
	       if (strncmp(child_name, name, size) == 0)
	       {
		  /*
		   *  If there is no other segment to be matched then we have
		   *  have found the window.  Otherwise we will need to recurse
		   *  on the children of this window.
		   */
		  if (temp == NULL)
		     return(children[i]);
		  else if ((window = xvf_find_window(children[i], &temp[1],
				toplevel)) != NULL)
		  {
		     *toplevel = false;
		     return(window);
		  }
	       }
	    }
	}

	/*
	 *  Didn't find the window.
	 */
	return(NULL);

} /* end xvf_find_window() */



/************************************************************
*
*  Routine Name: xvf_find_widget
*
*      Purpose:  This routine takes a full name 
*		 (example:great-grandparent.grandparent.parent.child)
*		 and returns the widget that is so named.
*
*        Input:  parent - the parent window from which we will begin search
*		 name   - the name of the widget we're looking for
*
*       Output:  widget - the widget found with the specified name
*
*   Written By:  Mark Young & Danielle Argiro
*
*************************************************************/


Widget xvf_find_widget(parent, name)

Window parent;
char   *name;
{
	int	 i;
	unsigned int num;
	Window	 window, *children, dummy;
	Widget   widget;

	/*
         *  Return NULL if we have no more children to search but still
         *  haven't found the window with the name.
         */
        if (!XQueryTree(xvf_display, parent, &dummy, &dummy, &children, &num))
	{
           return(NULL);
	}

	/*
	 *  For each window that exists in the root window
	 */
	for (i = 0; i < num; i++)
	{
	    /*
	     *  Check to see if the window is a widget.
	     */
	    window = XmuClientWindow(xvf_display, children[i]);
	    if ((widget = XtWindowToWidget(xvf_display, window)) != NULL)
	    {
#ifdef DEBUG
fprintf(stderr,"calling find_widget with name '%s' and widget '%s'\n",name,XtName(widget));
#endif
	       if ((widget = find_widget(widget, name)) != NULL)
		  return(widget);
	    }

	    /*
	     *  the window is not a widget -- but one of its children may be
	     *  the widget we're looking for (e.g, twm decorates the client's
	     *  applicationShell widgets);  recurse on children on window.
	    else if (widget = xvf_find_widget(children[i], name))
	       return(widget);
	     */
	}

	/*
	 *  failed to find widget with the desired name
	 */
	return(NULL);

} /* end xvf_find_widget() */



/************************************************************
*
*  Routine Name: xvf_find_xvform_widget
*
*      Purpose:  This routine takes a full name 
*		 (example:great-grandparent.grandparent.parent.child)
*		 and returns the widget that is so named.  It differs
*		 from the xvf_find_widget() routine since it only
*		 searches the form_list (ie, only widgets saved in the
*		 form tree)
*
*        Input:  name   - the name of the widget we're looking for
*
*       Output:  widget - the widget found with the specified name
*
*   Written By:  Mark Young & Danielle Argiro
*
*************************************************************/

Widget xvf_find_xvform_widget(name)

char   *name;
{
	xvf_list *current;
	xvf_form *form;
	xvf_sub_form *subform;
	Widget	 widget;


	if (xvf_toplevels != NULL)
	{
	   if ((widget = find_xvutils_widget(name)) != NULL)
	      return(widget);
	}

	current = form_list;
	while (current != NULL)
	{
	   form = current->form;
	   if (form->toplevel != NULL)
	   {
	       widget = find_widget(form->toplevel, name);
	       if (widget != NULL)
		   return(widget);
	   }
	   if (form->glyph_toplevel != NULL)
	   {
	       widget = find_widget(form->glyph_toplevel, name);
	       if (widget != NULL)
		   return(widget);
	   }

	   subform = form->subform;
	   while (subform != NULL)
	   {
	      if (subform->toplevel != NULL)
	      {
		 widget = find_widget(subform->toplevel, name);
		 if (widget != NULL)
		    return(widget);
	      }
	      if (subform->glyph_toplevel != NULL)
	      {
	          widget = find_widget(subform->glyph_toplevel, name);
	          if (widget != NULL)
		      return(widget);
	      }
	      subform = subform->next_subform;
	   }
	   current = current->next;
	}

	/*
	 *  Didn't find the widget so return NULL 
	 */
	return(NULL);

} /* end xvf_find_xvform_widget() */



/************************************************************
*
*  Routine Name: xvf_find_name
*
*      Purpose:  This routine takes a window and returns it's full
*		 name, made up of its full ancestor list.
*		 example: great-grandparent.grandparent.parent.child
*
*        Input:  window - the window which is to have its name found
*
*       Output:  type -  XVF_WINDOW or XVF_WIDGET, depending on whether the 
*			 name was originally created for a window or a widget
*			 (note:if it was the name of a widget, the widget
*			  can be extrapolated from the window)
*
*		 toplevel - indicates whether the window or widget is on
*			    the toplevel.
*			
*		 name  - full name string of window
*
*   Written By:  Mark Young & Danielle Argiro & Stephanie Hallett
*
*************************************************************/


char *xvf_find_name(window, type, toplevel)

Window window;
int    *type, *toplevel;
{
	char temp_name[MaxLength];
	char *child_name, *parent_name;
	Widget widget_parent, widget;

	/*
	 *  if the window is also a widget
 	 */
	if ((widget = XtWindowToWidget(xvf_display, window)) != NULL)
	{
	    /*
	     *  get the name of this child, and find its parent
	     */
	    child_name = XtName(widget);
	    widget_parent= XtParent(widget);
	    strcpy(temp_name, child_name);

	    if (widget_parent == NULL)
	       *toplevel = true;
	    else
	       *toplevel = false;

	    /*
	     *  put together its full name, marking its full ancestry
	     */
	    while (widget_parent != NULL)
	    {
	        parent_name = XtName(widget_parent);
	        sprintf(temp_name,"%s.%s", parent_name, child_name);
	        child_name = xvf_strcpy(temp_name);
	        widget_parent = XtParent(widget_parent);
	    }
	    *type = XVF_WIDGET;
	}

	/*
	 *  if it is only window, not a widget
 	 */
	else
	{
	    /*
	     *  Not working yet.
	     */
	    return(NULL);

	    /*
	     *  get the name of this child, and find its parent
	    rootwindow = XRootWindow(xvf_display, xvf_screen_num);
	    XFetchName(xvf_display, window, &child_name);
	    XGetGeometry(xvf_display, window, &window_parent, &x, &y, 
			 &dummy, &dummy, &dummy, &dummy);
	    strcpy(temp_name, child_name);

	    if (window_parent == rootwindow)
	       *toplevel = true;
	    else
	       *toplevel = false;
	     */

	    /*
	     *  put together its full name, marking its full ancestry
	    while (window_parent != rootwindow)
	    {
	       XFetchName(xvf_display, window_parent, &parent_name);
	       sprintf(temp_name,"%s.%s", parent_name, child_name);
	       child_name = xvf_strcpy(temp_name);
	       window = window_parent;
	       XGetGeometry(xvf_display, window, &window_parent, &x, &y, 
	 		     &dummy, &dummy, &dummy, &dummy);
	    }
	    *type = XVF_WINDOW;
	     */
	}
	return(xvf_strcpy(temp_name));

} /* end xvf_find_name() */



/************************************************************
*
*  Routine Name: find_widget
*
*      Purpose:  This routine takes a widget and compares its name to the
*		 name passed in.  If they are the same, it returns the widget;
*		 otherwise, it will see if any of the children or grandchildren
*		 widgets' names match the desired name, and return one of them.
*		 Will return NULL if no widget is found with a name matching
*		 the name passed in.
*
*        Input:  parent - the parent widget to search from
*		 name   - the name of the widget we're looking for
*
*       Output:  widget - the widget found with the specified name
*
*   Written By:  Mark Young & Danielle Argiro
*
*************************************************************/


static Widget find_widget(parent, name)

Widget parent;
char   *name;
{
	int	 size;
	char	 *temp, *parents_name, word[MaxLength];
	Widget	 widget;

	/*
         *  Get the first segment of the name and its size
         */
        if ((temp = strchr(name, '.')) != NULL)
           size = temp - name;
        else
           size = xvf_strlen(name);
	strncpy(word, name, size);
        word[size] = '\0';

	/*
	 *  if the window is a widget, and the widget's name is
	 *  the same as the first segment of the name 
	 *  we're looking for...
	 */
	parents_name = XtName(parent);
	if (parents_name == NULL) return(NULL);
 	if (strcmp(word, parents_name) == 0)
        {
	    /*
	     *  the parent name only has one segment - since it matches
	     *  the name we're looking for, return it.
	     */
	    if (temp == NULL)
		return(parent);

	    /*
	     *  the parent name has more than one segment - see if 
	     *  the rest of the name matches the parent name, and if
	     *  it does, return it.
	     */
	    else
	    {
		if ((widget = XtNameToWidget(parent, &temp[1])) != NULL)
		    return(widget);
	    }
	}
	else
	    return(NULL);

} /* end find_widget() */

static Widget find_xvutils_widget(name)
char   *name;
{
       Widget widget;
       xvf_toplevel_list *ptr;

       ptr = xvf_toplevels;
       
       while (ptr != NULL)
       {
           if ((widget = find_widget(ptr->toplevel, name)) != NULL)
              return(widget);
           ptr = ptr->next;
       }
       return(NULL);
}


/************************************************************
*
*  Routine Name: xvf_create_jp_control
*
*      Purpose:  this routine creates the journal playback control widget 
*
*        Input:  widget - the Journal Playback Control popup widget
*		 clientData - not used
*		 event  - the event that caused control to be directed to
*			  this event handler
*
*       Output:  the journal playback control widget
*
*   Written By:  Danielle Argiro
*
*************************************************************/


Widget xvf_create_jp_control ()
{
    Cardinal	i;
    Arg		args[25];

    unsigned int mask;
    Widget	toplevel, popup, back, quit;
    Widget	jplabel, hclabel, qlabel;
    void	xvf_popup_control();

    jp_data = (JP_Data *) malloc (sizeof(JP_Data));


    /*
     * create the form's toplevel widget
     */
    i = 0;
    XtSetArg(args[i], XtNscreen, xvf_screen);        i++;
    XtSetArg(args[i], XtNargc, xvf_ac);              i++;
    XtSetArg(args[i], XtNargv, xvf_av);              i++;
    XtSetArg(args[i], XtNwinGravity, StaticGravity); i++; 
    toplevel = XtAppCreateShell("jp_control_wid","JP_Control_Wid",
               		applicationShellWidgetClass, xvf_display, args, i);


    i = 0;
    XtSetArg(args[i], XtNx, 500);				i++;
    XtSetArg(args[i], XtNy, 700);				i++;
    popup = XtCreatePopupShell("prompt", transientShellWidgetClass, toplevel,
			       args, i);

    back = XtCreateManagedWidget("label",formWidgetClass, popup, NULL, 0);

    i = 0;
    XtSetArg(args[i], XtNfromVert, NULL);			i++;
    XtSetArg(args[i], XtNfromHoriz, NULL);			i++;
    XtSetArg(args[i], XtNlabel, "   Journal Playback: ");	i++;
    XtSetArg(args[i], XtNborder, 0); 				i++;
    jplabel = XtCreateManagedWidget("label", labelWidgetClass, back, args, i);

    i = 0;
    XtSetArg(args[i], XtNfromVert, NULL);			i++;
    XtSetArg(args[i], XtNfromHoriz, jplabel);			i++;
    XtSetArg(args[i], XtNlabel, "running");			i++;
    XtSetArg(args[i], XtNborder, 0); 				i++;
    jp_data->status = XtCreateManagedWidget("status", labelWidgetClass, back,
					   args, i);

    i = 0;
    XtSetArg(args[i], XtNfromVert, jplabel);			i++;
    XtSetArg(args[i], XtNfromHoriz, NULL);			i++;
    XtSetArg(args[i], XtNlabel, "type 'h' to halt, 'c' to continue");	i++;
    XtSetArg(args[i], XtNborder, 0); 				i++;
    hclabel = XtCreateManagedWidget("label", labelWidgetClass, back, args, i);

    i = 0;
    XtSetArg(args[i], XtNfromVert, hclabel);			i++;
    XtSetArg(args[i], XtNfromHoriz, NULL);			i++;
    XtSetArg(args[i], XtNlabel, "type 'q' to quit, or " );	i++;
    XtSetArg(args[i], XtNborder, 0); 				i++;
    qlabel = XtCreateManagedWidget("label", labelWidgetClass, back, args, i);

    i = 0;
    XtSetArg(args[i], XtNfromVert, hclabel);			i++;
    XtSetArg(args[i], XtNfromHoriz, qlabel);			i++;
    XtSetArg(args[i], XtNlabel, "Quit" );			i++;
    quit = XtCreateManagedWidget("label", commandWidgetClass, back, args, i);
    XtAddCallback(quit, XtNcallback, xvf_quit_jp_cb, NULL);
    XtAddEventHandler(popup, StructureNotifyMask, False, xvf_popup_control,
		      NULL);

    mask = KeyPressMask;
    XtAddEventHandler(back, mask, FALSE, xvf_control_jp_cb, jp_data);
    return(popup);
}


/************************************************************
*
*  Routine Name: xvf_popup_control
*
*      Purpose:  this is the event handler for the Journal Playback 
*		 Control popup widget that grabs & ungrabs the keyboard
*
*        Input:  widget - the Journal Playback Control popup widget
*		 clientData - not used
*		 event  - the event that caused control to be directed to
*			  this event handler
*
*       Output:  none
*
*   Written By:  Mark Young
*
*************************************************************/

void xvf_popup_control(widget, clientData, event)

Widget  widget;
caddr_t clientData; XEvent  *event;
{
    int stat;

    if (jp_grab == False)
       return;

    if (event->type == MapNotify)
    {
       stat = XGrabKeyboard(XtDisplay(widget), XtWindow(widget), FALSE,
			   GrabModeAsync, GrabModeAsync, CurrentTime);

       if (stat == GrabNotViewable)
	  fprintf(stderr, "cant grab, not viewable\n");
    }
    else if (event->type == UnmapNotify)
       XUngrabKeyboard(XtDisplay(widget), CurrentTime);
}



/************************************************************
*
*  Routine Name: xvf_quit_popup_cb
*
*      Purpose:  this is the callback for the Quit button on the
*		 Journal Playback Control popup widget. Destroys the 
*		 popup widget, ends journal playback.
*
*        Input:  widget - the Journal Playback Control popup widget
*		 clientData - not used
*		 event  - the event that caused control to be directed to
*			  this event handler
*       Output:  none
*
*   Written By:  Mark Young
*
*************************************************************/

static void xvf_quit_jp_cb(widget, client_data, call_data)

Widget	  widget;		
XtPointer client_data, call_data;
{
	XtDestroyWidget(widget);
	jp_playing = false;
}


/************************************************************
*
*  Routine Name: xvf_control_jp_cb
*
*      Purpose:  this is the callback for the Journal Playback Control 
*		 popup widget. It gets KeyPress events, and looks for
*		 the commands we are interested in: 'f', 'F', '-', 
*		 's', 'S', '+', 'H', 'h', 'C', 'c', 'Q', and 'q'.
*
*        Input:  widget - the Journal Playback Control popup widget
*		 clientData - used to pass the jp_data
*		 event  - the event that caused control to be directed to
*			  this event handler
*       Output:  none
*
*   Written By:  Danielle Argiro & Mark Young
*
*************************************************************/

static void xvf_control_jp_cb(widget, client_data, event)
Widget	  widget;		
XtPointer client_data; 
XEvent    *event;
{
	JP_Data *jp_data = (JP_Data *) client_data;

	int i;
	Arg args[25];
	KeySym keysym_return;
	XComposeStatus status;
	char ascii_return;
	Widget popup;


	if (event->type == KeyPress) 
	{
	   if (XLookupString(&(event->xkey), &ascii_return, 1, 
			     &keysym_return,&status) == 0) return;

/*	   fprintf(stderr, "key pressed: key code %d; ascii interpretation \
'%c'\n", event->xkey.keycode, ascii_return);  */

	   switch (ascii_return)
	   {
		/* make jp halt */
		case 'h':
		case 'H':
			 jp_halt = true;
			 fprintf(stderr, "Halting\n");

			 i = 0;
		         XtSetArg(args[i], XtNlabel, "halted");  i++;
			 XtSetValues(jp_data->status, args, i);
			 break;

		/* make jp continue */
		case 'c':
		case 'C':
			 jp_halt = false;
			 fprintf(stderr, "Continuing\n");

			 i = 0;
		         XtSetArg(args[i], XtNlabel, "running");  i++;
			 XtSetValues(jp_data->status, args, i);
			 jp_start_playback();
			 break;

		/* make jp quit (note: character 3 is a ^C character) */
		case  3:
		case 'q':
		case 'Q':
			 jp_playing = false;
			 fprintf(stderr, "Quitting journal playback session--\n");
			 fprintf(stderr, "You may now continue on your own.\n");
			 popup = XtParent(widget);
			 XtPopdown(popup);
			 break;
	   }
	}
}
