 /*
  * Khoros: $Id: check.c,v 1.4 1991/12/18 09:00:17 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: check.c,v 1.4 1991/12/18 09:00:17 dkhoros Exp $";
#endif

 /*
  * $Log: check.c,v $
 * Revision 1.4  1991/12/18  09:00:17  dkhoros
 * HellPatch3
 *
  */ 


/*
 *----------------------------------------------------------------------
 *
 * 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 "cantata.h"


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>								<<<<
   >>>>	    file name:  check.c					<<<<
   >>>>								<<<<
   >>>>   description:						<<<<
   >>>>								<<<<
   >>>>      routines:  xvl_check_if_enabled()			<<<<
   >>>>                 xvl_check_if_external()			<<<<
   >>>>                 xvl_check_if_undo()			<<<<
   >>>>                 xvl_check_if_viewable()			<<<<
   >>>>                 xvl_check_if_modified()			<<<<
   >>>>                 xvl_check_if_runnable()			<<<<
   >>>>                 xvl_check_if_scheduled()		<<<<
   >>>>                 xvl_check_if_loop_node()		<<<<
   >>>>                 xvl_check_if_control_loop()		<<<<
   >>>>                 xvl_check_if_remote()			<<<<
   >>>>                 xvl_check_if_remote_connection()	<<<<
   >>>>                 xvl_check_motion_event()		<<<<
   >>>>								<<<<
   >>>> modifications:						<<<<
   >>>>								<<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */



/************************************************************
*
* Routine Name:  xvl_check_if_enabled
*
*      Purpose:  This routine is used to check to see if a glyph
*		 can be run by the cantata automatic scheduler.
*		 This is done by looking at the glyph's input
*		 nodes.  If the dav (data available) is true
*		 for all input nodes then we say that the glyph
*		 is enabled to be dispatched.  The only exception
*		 to this is for control glyphs which can have just
*		 one data path in order to be enabled.
*
*
*        Input:  glyph - the glyph we want to check to see if enabled.
*
*       Output:  returns True is the glyph is enabled otherwise False
*		 is returned.
*
*
*   Written By: Mark Young
*
*************************************************************/


int xvl_check_if_enabled(glyph)

Glyph	*glyph;
{
	NodeList *input;


	input = glyph->input_list;
	if (glyph->type != CONTROL ||
	    strcmp(glyph->label_str,"trigger") == 0 ||
	    strcmp(glyph->label_str,"switch") == 0)
	{
	   /*
	    *  Need to check the input list to see if any of the data
	    *  availables are set.  If so then we say that the glyph
	    *  is ready to be scheduled.
	    */
	   while (input != NULL)
	   {
	      if (input->node->dav == False && input->node->selected == True)
	         return(False);

	      input = input->next;
	   }
	   return(True);
	}
	else
	{
	   /*
	    *  Need to check the input list to see if all of the data
	    *  availables are set.  If so then we say that the glyph
	    *  is ready to be scheduled.
	    */
	   if (input->node->selected == False)
	   {
	      if ((strcmp(glyph->label_str, "count_loop") == 0) ||
	          (strcmp(glyph->label_str, "while_loop") == 0))
	         return(True);
	   }

	   while (input != NULL)
	   {
	      if (input->node->dav == True && input->node->selected == True)
		 return(True);

	      input = input->next;
	   }
	   return(False);
	}
}



/************************************************************
*
* Routine Name:  xvl_check_if_external
*
*      Purpose:  This routine is used to check to see if both
*		 glyphs belong to the same workspace.
*
*        Input:  glyph1 - the first glyph we want to check
*		 glyph2 - the second glyph we want to check
*
*       Output:  returns False if glyph1 and glyph2 have the
*		 same workspace.
*
*
*   Written By: Mark Young
*
*************************************************************/


int xvl_check_if_external(glyph1, glyph2)

Glyph	*glyph1, *glyph2;
{
	if (glyph1->workspace == glyph2->workspace)
	   return(False);
	else
	   return(True);
}



/************************************************************
*
* Routine Name:  xvl_check_if_undo
*
*      Purpose:  This routine is used to check to see if either
*		 glyph is in the undo workspace buffer.
*
*        Input:  glyph1 - the first glyph we want to check
*		 glyph2 - the second glyph we want to check
*
*       Output:  returns False if neither glyph1 or glyph2 is in
*		 the workspace's undo buffer (workspace).
*
*
*   Written By: Mark Young
*
*************************************************************/


int xvl_check_if_undo(glyph1, glyph2)

Glyph	*glyph1, *glyph2;
{
	Workspace *workspace, *undo;


	workspace = glyph1->workspace;
	if (workspace->undo_workspace != NULL)
	{
	   undo = workspace->undo_workspace;
	   if (xvl_check_if_glyphlist(glyph2, undo->glyphs) == True)
	      return(True);
	}

	workspace = glyph2->workspace;
	if (workspace->undo_workspace != NULL)
	{
	   undo = workspace->undo_workspace;
	   if (xvl_check_if_glyphlist(glyph1, undo->glyphs) == True)
	      return(True);
	}
	return(False);
}



/************************************************************
*
* Routine Name: xvl_check_if_viewable
*
*      Purpose: This routine is used to see if a glyph is currently
*		viewable
*
*       Output: return True is the glyph is on the screen otherwise
*		we return False.
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


int xvl_check_if_viewable(glyph)

Glyph	*glyph;
{
	Widget		  widget;
	XWindowAttributes xwa;


	widget = glyph->toplevel;
	if (!XGetWindowAttributes(XtDisplay(widget), XtWindow(widget), &xwa))
	   return(False);

	if (xwa.map_state == IsViewable)
	   return(True);
	else
	   return(False);
}



/************************************************************
*
* Routine Name: xvl_check_if_modified
*
*      Purpose: This routine is used to see if any glyph's on
*		a workspace have been modified.
*
*       Output: return True if any glyph has been modified.
*		otherwise we return False.
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


int xvl_check_if_modified(workspace)

Workspace *workspace;
{
	Workspace *macro;
	Glyph	  *glyph;
	GlyphList *glyphlist;


	glyphlist = workspace->glyphs;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   if (glyph->modified == True)
	      return(True);
	   else if (glyph->type == PROCEDURE)
	   {
	      macro = glyph->val.macro;
	      if (xvl_check_if_modified(macro))
		 return(True);
	   }
	   glyphlist = glyphlist->next;
	}
	return(False);
}



/************************************************************
*
* Routine Name: xvl_check_if_runnable
*
*      Purpose: This routine is used to see if the glyph
*		can be run.  We say a glyph is runnable if
*		none of it's children are running.  Note:
*		for regular glyphs we just check just the first
*		generation, but for control loops we call
*		xvl_control_running() to see if there are any
*		descendants running.
*
*        Input: glyph  - to be checked if can be run
*
*       Output: return True if the glyph can be run, otherwise
*		return False.
*
*    Called By:
*
*   Written By: Mark Young
*
*
*************************************************************/


int xvl_check_if_runnable(glyph)

Glyph *glyph;
{
	Glyph	  *child;
	int	  running;
	Workspace *workspace;
	NodeList  *output, *links;


	/*
	 *  Check to see if any of the control loop glyph is running.  If
	 *  xvl_control_running() returns False then we are still going to
	 *  check the glyph to see if it's final output connection, or in
	 *  the case if a "merge" & "if_else" we check it like a regular
	 *  glyph.
	 */
	if (glyph->type == CONTROL)
	{
	   if ((strcmp(glyph->label_str, "count_loop") == 0) ||
	       (strcmp(glyph->label_str, "while_loop") == 0))
	   {
	      if (xvl_control_running(glyph) == True)
		 return(False);
	      else
		 return(True);
	   }
	}

	workspace = glyph->workspace;
	output = glyph->output_list;
	while (output != NULL)
	{
	   links = output->node->links;
	   while (links != NULL)
	   {
	      /*
	       *  Check to see if this child is running, if it then return
	       *  False to indicate that we are not ready to run since one
	       *  of our children is currently running.  The only exception
	       *  to this check is ourself.  (control loops can drive
	       *  themselves).
	       */
	      child = links->node->glyph;
	      running = xvl_check_if_glyphlist(child, workspace->running);
	      if (running == True && child->run_type != SINK)
	      {
	         return(False);
	      }
	      links = links->next;
	   }
	   output = output->next;
	}
	return(True);
}



/************************************************************
*
* Routine Name: xvl_check_if_scheduled
*
*      Purpose: This routine is used to see if a glyph is scheduled
*		to be run.
*
*       Output: return True if this glyph is scheduled, otherwise
*		we return False.
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


int xvl_check_if_scheduled(glyph)

Glyph *glyph;
{
	if (xvl_check_if_glyphlist(glyph, glyph->workspace->frontlist) == True)
	   return(True);
	else
	   return(False);
}



/************************************************************
*
* Routine Name: xvl_check_if_loop_node
*
*      Purpose: This routine is used to see if the node for the
*		given glyph is part of the control loop.  This is
*		done to see if the input or output is actually
*		part of the lower (or inside) the loop's control
*		flow.
*
*       Output: return True if part of the control loop, otherwise
*		we return False.
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


int xvl_check_if_loop_node(glyph, node)

Glyph	  *glyph;
Node	  *node;
{
	/*
	 *  Quick check to see if the node is valid.
	 */
	if (node == NULL)
	   return(False);

	/*
	 *  Make sure the glyph is a control glyph and is either a
	 *  count or while loop.
	 */
	if (((strcmp(glyph->label_str, "count_loop") != 0) &&
	     (strcmp(glyph->label_str, "while_loop") != 0)) ||
	    glyph->type != CONTROL)
	{
	   return(False);
	}

	if ((node == glyph->input_list->next->node) ||
	    (node == glyph->output_list->next->node))
	   return(True);
	else
	   return(False);
}



/************************************************************
*
* Routine Name: xvl_check_if_control_loop
*
*      Purpose: This routine is used to see if the glyph is really
*		a control loop glyph "while" or "count" loops.
*		flow.
*
*       Output: return True if the glyph is a control loop, otherwise
*		we return False.
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


int xvl_check_if_control_loop(glyph)

Glyph	  *glyph;
{
	/*
	 *  Make sure the glyph is a control glyph and is either a
	 *  count or while loop.
	 */
	if (((strcmp(glyph->label_str, "count_loop") != 0) &&
	     (strcmp(glyph->label_str, "while_loop") != 0)) ||
	    glyph->type != CONTROL)
	{
	   return(False);
	}
	else
	   return(True);
}



/************************************************************
*
* Routine Name: xvl_check_if_remote
*
*      Purpose: This routine is used to see if the glyph is to
*		be executed remotely.  If the glyph were to be
*		run at this time would it be scheduled to execute
*	        locally or remotely.
*
*       Output: return True glyph is to be executed remotely
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


int xvl_check_if_remote(glyph)

Glyph	  *glyph;
{
	char	*machine, temp[MaxLength];

	/*
	 *  Quick check to see if the glyph the machine's info is NULL, in
	 *  which case it will be executed locally.
	 */
	if (xvl_get_machname(glyph, temp) == NULL)
	   return(False);

	/*
	 *  Check to see where the machine info indicates that the glyph
	 *  will be executed remote or locally.
	 */
	if ((machine = xvl_get_machname(glyph, temp)) == NULL)
	   return(False);
	else
	   return(khost_remote(machine));
}



/************************************************************
*
* Routine Name: xvl_check_if_remote_connection
*
*      Purpose: This routine is used to see if the two routines
*		are remote from each other.
*
*       Output: return True if part of the control loop, otherwise
*		we return False.
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


int xvl_check_if_remote_connection(glyph1, glyph2)

Glyph	  *glyph1, *glyph2;
{
	char	*mach1, *mach2, temp1[MaxLength], temp2[MaxLength];

	/*
	 *  Quick check to see if the glyph the machine's info is NULL, in
	 *  which case it will be executed locally.
	 */
	mach1 = xvl_get_machname(glyph1, temp1);
	mach2 = xvl_get_machname(glyph2, temp2);

	if (VStrcmp(mach1, mach2) == 0)
	   return(False);
	else if (khost_remote(mach1) == False && khost_remote(mach2) == False)
	   return(False);
	else
	   return(True);
}



/************************************************************
*
* Routine Name: xvl_check_motion_event
*
*      Purpose: This routine is used to tell if the event is
*		of type MotionNotify.  The routine is used to
*		aid other routines in compressing motion events.
*
*       Output: returns true if the next event is a MotionNotify
*		for the given window.  Otherwise it queries the
*		mouse and returns the x and y position.
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


int  xvl_check_motion_event(widget, x, y)

Widget	 widget;
Position *x, *y;
{
	XEvent   next;
	int	 motion   = False;
	Display	 *display = XtDisplay(widget);
	Window	 window   = XtWindow(widget);


	if (XEventsQueued(display, QueuedAfterReading))
	{
	   XPeekEvent(display, &next);
	   if (next.type == MotionNotify)
	   {
	      if (next.xmotion.window == window)
		 motion = TRUE;
	   }
	}
	xvl_query_position(widget, NULL, x, y, True);
	return(motion);
}
