/* $TOG: Synthetic.c /main/8 1999/04/13 13:21:09 mgreess $ */
/*
 * Motif
 *
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these librararies and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
 */
/*
 * HISTORY
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif


#include "XmI.h"
#include <Xm/ManagerP.h>
#include <Xm/PrimitiveP.h>
#include <Xm/GadgetP.h>
#include <Xm/VendorSEP.h>
#ifdef PRINTING_SUPPORTED
#include <Xm/PrintSP.h>
#endif
#include "SyntheticI.h"


/*******    Static Function Declarations    ********/

static void GetValuesHook(Widget w,
			  XtPointer base,
			  Widget alt_w,
			  XtPointer alt_base,
			  Cardinal alt_mask,
			  XmSyntheticResource *resources,
			  int num_resources,
			  ArgList args,
			  Cardinal num_args) ;
static void ConstraintGetValuesHook(Widget w,
				    Widget alt_w,
				    Cardinal alt_mask,
				    ArgList args,
				    Cardinal *num_args) ;
static void ImportArgs(Widget w,
		       XtPointer base,
		       Widget alt_w,
		       XtPointer alt_base,
		       Cardinal alt_mask,
		       XmSyntheticResource *resources,
		       int num_resources,
		       ArgList args,
		       Cardinal num_args) ;
static void ImportConstraintArgs(Widget w,
				 Widget alt_w,
				 Cardinal alt_mask,
				 ArgList args,
				 Cardinal *num_args) ;


/********    End Static Function Declarations    ********/

/**********************************************************************
 *
 *  _XmBuildResources
 *	Build up a new synthetic resource list based on a combination
 *	the the widget's class and super class resource list.
 *
 **********************************************************************/

void 
_XmBuildResources(XmSyntheticResource **wc_resources_ptr,
		  int *wc_num_resources_ptr,
		  XmSyntheticResource *sc_resources,
		  int sc_num_resources)
{
  XmSyntheticResource *wc_resources;
  int                  wc_num_resources;
  XmSyntheticResource *new_resources;
  int                  new_num_resources;
  int i, j;
  Boolean override;
  
  
  wc_resources = (XmSyntheticResource *) *wc_resources_ptr;
  wc_num_resources = (int) *wc_num_resources_ptr;
  
  
  /*  If there are no new resources, just use the super class data  */
  
  if (wc_num_resources == 0)
    {
      *wc_resources_ptr = sc_resources;
      *wc_num_resources_ptr = sc_num_resources;
      return;
    }
  
  
  /*
   * Allocate a new resource list to contain the combined set of
   * resources from the class and super class.  This allocation
   * may create to much space if there are overrides in the new
   * resource list.  Copy sc's resources into the space.
   */
  
  new_resources = (XmSyntheticResource *) 
    XtMalloc(sizeof (XmSyntheticResource) *
	     (wc_num_resources + sc_num_resources));
  if (sc_num_resources)
    memcpy ((char *) new_resources, (char *) sc_resources,
	    sc_num_resources * sizeof (XmSyntheticResource));
  
  
  /*
   * Loop through the wc resources and copy 
   * them into the new resources
   */
  
  new_num_resources = sc_num_resources;
  
  for (i = 0; i < wc_num_resources; i++)
    {
      
      /*  First check to see if this is an override  */
      
      override = False;
      for (j = 0; j < sc_num_resources; j++)
	{
	  /* ???
	   * We do name overrides while the intrinsics do offset overrides.
	   * Be sure to mask off alt_mask if we change this.
	   */
	  if (new_resources[j].resource_name == wc_resources[i].resource_name)
	    {
	      override = True;
	      new_resources[j].export_proc = wc_resources[i].export_proc;
	      new_resources[j].import_proc = wc_resources[i].import_proc;
	      break;
	    }
	}
      
      
      /*  If it wasn't an override stuff it into the list  */
      
      if (override == False)
	new_resources[new_num_resources++] = wc_resources[i];
    }
  
  
  /*  Replace the resource list and count will the new one.  */
  
  *wc_resources_ptr = new_resources;
  *wc_num_resources_ptr = new_num_resources;
}

/**********************************************************************
 *
 *  InitializeSyntheticResources
 *	Initialize a synthetic resource list.  This is called before
 *	Primitive, Manager and Gadgets build resources to convert the
 *	resource names to quarks in the class' synthetic processing
 *	lists.
 *
 **********************************************************************/

void 
_XmInitializeSyntheticResources(XmSyntheticResource *resources,
				int num_resources )
{
  register int i;
  
  for (i = 0; i < num_resources; i++)
    resources[i].resource_name = 
      (String) XrmPermStringToQuark (resources[i].resource_name);
}

/**********************************************************************
 *
 *  GetValuesHook
 *	This procedure is used as the synthetic hook in Primitive,
 *	Manager, and Gadget.  It uses the synthetic resource list
 *	attached to the class, comparing it to the input resource list,
 *	and for each match, calling the function to process the get
 *	value data.
 *
 **********************************************************************/

static void 
GetValuesHook(Widget w,
	      XtPointer base,
	      Widget alt_w,
	      XtPointer alt_base,
	      Cardinal alt_mask,
	      XmSyntheticResource *resources,
	      int num_resources,
	      ArgList args,
	      Cardinal num_args)
{
  int i, j;
  XrmQuark quark;
  XtArgVal value;
  XtArgVal orig_value;
  Cardinal value_size;
  XtPointer value_ptr;
  Widget value_widget;
  Cardinal value_offset;
  
  /*  Loop through each argument, quarkifing the name.  Then loop  */
  /*  through each synthetic resource to see if there is a match.  */
  
  for (i = 0; i < num_args; i++) 
    {
      quark = XrmStringToQuark (args[i].name);
      
      for (j = 0; j < num_resources; j++) 
	{
	  if ((resources[j].export_proc) &&
	      (XrmQuark)(resources[j].resource_name) == quark) 
	    {
	      value_size = resources[j].resource_size;

	      /* CR 5385: Use alt_w and alt_base if alt_mask is set in the */
	      /*	offset.  This lets extension sythetic resources */
	      /*	point to the "real" widget class resources. */
	      value_offset = resources[j].resource_offset;
	      if (value_offset & alt_mask)
		{
		  value_widget = alt_w;
		  value_offset &= ~alt_mask;
		  value_ptr = (XtPointer) ((char *) alt_base + value_offset);
		}
	      else
		{
		  value_widget = w;
		  value_ptr = (XtPointer) ((char *) base + value_offset);
		}
	      
	      if (value_size == sizeof(long))
		value = (XtArgVal)(*(long *)value_ptr);
	      else if (value_size == sizeof(int))
		value = (XtArgVal)(*(int *)value_ptr);
	      else if (value_size == sizeof(short))
		value = (XtArgVal)(*(short *)value_ptr);
	      else if (value_size == sizeof(char))
		value = (XtArgVal)(*(char *)value_ptr);
	      else 
		value = *(XtArgVal*)value_ptr;
	      
	      orig_value = value;
	      
	      (*(resources[j].export_proc))
		(value_widget, value_offset, &value);
	      
#if defined(GETVALUES_BUG)
	      /* if the value that was in the widget prior to calling 
		 the get hook is the same as the one put by Xt in the 
		 arg list, we are in the XtSetArg(args[i], XtNfoo, NULL)
		 case, where args[i].value is supposed to receive the 
		 result of the conversion. */
	      if (orig_value == args[i].value) 
		{
		  args[i].value = value;
		}
	      else
#endif
		{
		  value_ptr = (XtPointer) args[i].value;
		  
		  if (value_size == sizeof(long))
		    *(long *) value_ptr = (long) value;
		  else if (value_size == sizeof(int))
		    *(int *) value_ptr = (int) value;
		  else if (value_size == sizeof(short))
		    *(short *) value_ptr = (short) value;
		  else if (value_size == sizeof(char))
		    *(char *) value_ptr = (char) value;
		  else 
		    *(XtArgVal*) value_ptr = value;
		}
	      
	      break;
	    }
	}
    }
}

/**********************************************************************
 *
 *  ConstraintGetValuesHook
 *	When a widget is a child of a constraint manager, this function
 *	processes the synthetic arg list with for any constraint based
 *	resource processing that needs to be done.
 *
 **********************************************************************/

static void 
ConstraintGetValuesHook(Widget w,
			Widget alt_w,
			Cardinal alt_mask,
			ArgList args,
			Cardinal *num_args )
{
  XmManagerWidgetClass parent_wc = 
    (XmManagerWidgetClass) w->core.parent->core.widget_class;
  
  if (XmIsManager(w->core.parent) &&
      parent_wc->manager_class.num_syn_constraint_resources)
    GetValuesHook(w, w->core.constraints, 
		  alt_w, alt_w->core.constraints, alt_mask,
		  parent_wc->manager_class.syn_constraint_resources,
		  parent_wc->manager_class.num_syn_constraint_resources,
		  args, *num_args);
}

/**********************************************************************
 *
 *  _XmPrimitiveGetValuesHook
 *	Process the synthetic resources that need to be synthesized
 *
 **********************************************************************/

void 
_XmPrimitiveGetValuesHook(
        Widget w,
        ArgList args,
        Cardinal *num_args )
{
  XmPrimitiveWidgetClass wc;
  
  _XmProcessLock();
  wc = (XmPrimitiveWidgetClass) w->core.widget_class;
  if (wc->primitive_class.num_syn_resources != 0)
    GetValuesHook (w, (XtPointer)w, w, (XtPointer)w, None,
		   wc->primitive_class.syn_resources,
		   wc->primitive_class.num_syn_resources, 
		   args, *num_args);
  
  if (w->core.constraints != NULL) 
    ConstraintGetValuesHook (w, w, None, args, num_args);
  _XmProcessUnlock();
}

/**********************************************************************
 *
 *  _XmGadgetGetValuesHook
 *	Process the synthetic resources that need to be synthesized
 *
 **********************************************************************/

void 
_XmGadgetGetValuesHook(Widget w,
		       ArgList args,
		       Cardinal *num_args )
{
  XmGadgetClass wc;
  
  _XmProcessLock();
  wc = (XmGadgetClass) w->core.widget_class;
  if (wc->gadget_class.num_syn_resources != 0)
    GetValuesHook (w, (XtPointer) w, w, (XtPointer) w, None,
		   wc->gadget_class.syn_resources,
		   wc->gadget_class.num_syn_resources, 
		   args, *num_args);
  
  if (w->core.constraints != NULL)
    ConstraintGetValuesHook (w, w, None, args, num_args);
  _XmProcessUnlock();
}

/**********************************************************************
 *
 *  _XmManagerGetValuesHook
 *	Process the synthetic resources that need to be synthesized
 *
 **********************************************************************/

void 
_XmManagerGetValuesHook(Widget w,
			ArgList args,
			Cardinal *num_args)
{
  XmManagerWidgetClass wc; 
  
  _XmProcessLock();
  wc = (XmManagerWidgetClass) w->core.widget_class;
  if (wc->manager_class.num_syn_resources != 0)
    GetValuesHook (w, (XtPointer) w, w, (XtPointer) w, None,
		   wc->manager_class.syn_resources,
		   wc->manager_class.num_syn_resources, 
		   args, *num_args);
  
  if (w->core.constraints != NULL)
    ConstraintGetValuesHook (w, w, None, args, num_args);
  _XmProcessUnlock();
}


#ifdef PRINTING_SUPPORTED

/**********************************************************************
 *
 *  _XmPrintShellGetValuesHook
 *	Process the synthetic resources that need to be synthesized
 *
 **********************************************************************/

void 
_XmPrintShellGetValuesHook(Widget w,
			ArgList args,
			Cardinal *num_args)
{
  XmPrintShellWidgetClass wc; 
  
  _XmProcessLock();
  wc = (XmPrintShellWidgetClass) w->core.widget_class;
  if (wc->print_shell_class.num_syn_resources != 0)
    GetValuesHook (w, (XtPointer) w, w, (XtPointer) w, None,
		   wc->print_shell_class.syn_resources,
		   wc->print_shell_class.num_syn_resources, 
		   args, *num_args);
  
  _XmProcessUnlock();
}
#endif /* PRINTING_SUPPORTED */ 

/**********************************************************************
 *
 *  _XmExtGetValuesHook
 *	Process the synthetic resources that need to be synthesized
 *
 **********************************************************************/

void 
_XmExtGetValuesHook(Widget w,
		    ArgList args,
		    Cardinal *num_args )
{
  XmExtObjectClass wc; 
  Widget parent;
  
  _XmProcessLock();
  wc = (XmExtObjectClass)XtClass(w);
  parent = ((XmExtObject)w)->ext.logicalParent;
  if (wc->ext_class.num_syn_resources != 0)
    GetValuesHook(w, (XtPointer) w, 
		  parent, (XtPointer) parent, XmLOGICAL_PARENT_RESOURCE,
		  wc->ext_class.syn_resources,
		  wc->ext_class.num_syn_resources, 
		  args, *num_args);
  _XmProcessUnlock();
}

/**********************************************************************
 *
 * ImportArgs
 * Convert the value in the arg list from the application type to the 
 * appropriate internal representation by calling the import_proc 
 * specified for the given resource.
 *
 **********************************************************************/

static void 
ImportArgs(Widget w,
	   XtPointer base,
	   Widget alt_w,
	   XtPointer alt_base,
	   Cardinal alt_mask,
	   XmSyntheticResource *resources,
	   int num_resources,
	   ArgList args,
	   Cardinal num_args )
{
  int i, j;
  XrmQuark quark;
  XtArgVal value;
  Cardinal value_size;
  XtPointer value_ptr;
  Cardinal value_offset;
  Widget value_widget;
  XtPointer value_base;
  XmImportOperator op;
  
  /*  Loop through each argument, quarkifing the name.  Then loop  */
  /*  through each synthetic resource to see if there is a match.  */
  
  for (i = 0; i < num_args; i++) 
    {
      quark = XrmStringToQuark (args[i].name);
      
      for (j = 0; j < num_resources; j++) 
	{
	  if ((resources[j].import_proc) &&
	      (XrmQuark)(resources[j].resource_name) == quark) 
	    {
	      value = args[i].value;
	      
	      /* CR 5385: Let VendorSE mix real and extension resources. */
	      value_offset = resources[j].resource_offset;
	      if (value_offset & alt_mask)
		{
		  value_offset &= ~alt_mask;
		  value_widget = alt_w;
		  value_base = alt_base;
		}
	      else
		{
		  value_base = base;
		  value_widget = w;
		}
	      
	      op = (*(resources[j].import_proc)) 
		(value_widget, value_offset, &value);
	      if ((op == XmSYNTHETIC_LOAD) && (value_base != NULL)) 
		{
		  /* Load the converted value into the structure */
		  value_size = resources[j].resource_size;
		  value_ptr = (XtPointer) ((char *) value_base + value_offset);
		  
		  if (value_size == sizeof(long))
		    *(long *) value_ptr = (long) value;
		  else if (value_size == sizeof(int))
		    *(int *) value_ptr = (int) value;
		  else if (value_size == sizeof(short))
		    *(short *) value_ptr = (short) value;
		  else if (value_size == sizeof(char))
		    *(char *) value_ptr = (char) value;
		  else
		    *(XtArgVal*) value_ptr= value;
		}
	      else
		{
		  args[i].value = value;
		}
	      
	      break;
	    }
	}
    }
}

/**********************************************************************
 *
 *  ImportConstraintArgs
 *	When a widget is a child of a constraint manager, this function
 *	processes the synthetic arg list with for any constraint based
 *	resource processing that needs to be done.
 *
 **********************************************************************/
static void 
ImportConstraintArgs(Widget w,
		     Widget alt_w,
		     Cardinal alt_mask,
		     ArgList args,
		     Cardinal *num_args )
{
  XmManagerWidgetClass parent_wc = 
    (XmManagerWidgetClass) w->core.parent->core.widget_class;
	
  if (XmIsManager(w->core.parent) && 
      parent_wc->manager_class.num_syn_constraint_resources)
    ImportArgs(w, w->core.constraints,
	       alt_w, alt_w->core.constraints, alt_mask,
	       parent_wc->manager_class.syn_constraint_resources,
	       parent_wc->manager_class.num_syn_constraint_resources,
	       args, *num_args);
}

/**********************************************************************
 *
 * _XmExtImportArgs
 * Does arg importing for sub-classes of VendorExt.
 *
 **********************************************************************/

void 
_XmExtImportArgs(Widget w,
		 ArgList args,
		 Cardinal *num_args )
{
  XmExtObjectClass wc;
  Widget parent; 
  
  _XmProcessLock();
  wc = (XmExtObjectClass)XtClass(w);
  parent = ((XmExtObject)w)->ext.logicalParent;
  if (wc->ext_class.num_syn_resources != 0)
    ImportArgs(w, (XtPointer) w, 
	       parent, (XtPointer)parent, XmLOGICAL_PARENT_RESOURCE,
	       wc->ext_class.syn_resources,
	       wc->ext_class.num_syn_resources, 
	       args, *num_args);
  _XmProcessUnlock();
}

/**********************************************************************
 *
 * _XmPrimitiveImportArgs
 * Does arg importing for sub-classes of XmPrimitive.
 *
 **********************************************************************/

void 
_XmPrimitiveImportArgs(Widget w,
		       ArgList args,
		       Cardinal *num_args )
{
  XmPrimitiveWidgetClass wc; 
  
  _XmProcessLock();
  wc = (XmPrimitiveWidgetClass) w->core.widget_class;
  if (wc->primitive_class.num_syn_resources != 0)
    ImportArgs (w, (XtPointer) w, w, (XtPointer) w, None,
		wc->primitive_class.syn_resources,
		wc->primitive_class.num_syn_resources, 
		args, *num_args);
  
  if (w->core.constraints != NULL) 
    ImportConstraintArgs (w, w, None, args, num_args);
  _XmProcessUnlock();
}

/**********************************************************************
 *
 *  _XmGadgetImportArgs
 * Does arg importing for sub-classes of XmGadget.
 *
 **********************************************************************/

void 
_XmGadgetImportArgs(Widget w,
		    ArgList args,
		    Cardinal *num_args )
{
  XmGadgetClass wc;
	
  /* Main object args */
  _XmProcessLock();
  wc = (XmGadgetClass) w->core.widget_class;
  if (wc->gadget_class.num_syn_resources != 0)
    ImportArgs (w, (XtPointer) w, w, (XtPointer) w, None,
		wc->gadget_class.syn_resources,
		wc->gadget_class.num_syn_resources, 
		args, *num_args);
	
  if (w->core.constraints != NULL)
    ImportConstraintArgs (w, w, None, args, num_args);
  _XmProcessUnlock();
}

/**********************************************************************
 *
 *  _XmGadgetImportSecondaryArgs
 * Does arg importing for sub-classes of XmGadget which have secondary
 * objects.
 *
 **********************************************************************/
void 
_XmGadgetImportSecondaryArgs(Widget w,
			     ArgList args,
			     Cardinal *num_args)
{
  XmGadgetClass wc;
  XmBaseClassExt *classExtPtr;
  XmExtClassRec *secondaryObjClass;

  _XmProcessLock();
  wc = (XmGadgetClass) w->core.widget_class;
  classExtPtr = _XmGetBaseClassExtPtr(wc, XmQmotif);
  secondaryObjClass = (XmExtClassRec *)
			((*classExtPtr)->secondaryObjectClass);
  /* Secondary object args */
  if ((secondaryObjClass != NULL) &&
      (secondaryObjClass->ext_class.num_syn_resources != 0))
    ImportArgs (w, NULL, w, NULL, None,
		secondaryObjClass->ext_class.syn_resources,
		secondaryObjClass->ext_class.num_syn_resources,
		args, *num_args);
  _XmProcessUnlock();
}

/**********************************************************************
 *
 *  _XmManagerImportArgs
 * Does arg importing for sub-classes of XmManager.
 *
 **********************************************************************/

void 
_XmManagerImportArgs(Widget w,
		     ArgList args,
		     Cardinal *num_args )
{
  XmManagerWidgetClass wc = (XmManagerWidgetClass) w->core.widget_class;
  
  _XmProcessLock();
  wc = (XmManagerWidgetClass) w->core.widget_class;
  if (wc->manager_class.num_syn_resources != 0)
    ImportArgs (w, (XtPointer) w, w, (XtPointer) w, None,
		wc->manager_class.syn_resources,
		wc->manager_class.num_syn_resources, 
		args, *num_args);
  
  if (w->core.constraints != NULL)
    ImportConstraintArgs (w, w, None, args, num_args);
  _XmProcessUnlock();
}
