/**
 *
 * $Id: VaSimple.c,v 1.7 1999/08/14 12:17:14 danny Exp $
 *
 * Copyright (C) 1995 Free Software Foundation, Inc.
 *
 * This file is part of the GNU LessTif Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 * Portions of this work are derived from X11R6/xc/lib/Xt/Varargs.c, which
 * is distributed under the following copyright:
 *
 * Copyright (c) 1985, 1986, 1987, 1988, 1989, 1994  X Consortium
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 * Except as contained in this notice, the name of the X Consortium shall not be
 * used in advertising or otherwise to promote the sale, use or other dealings
 * in this Software without prior written authorization from the X Consortium.
 *
 **/

static const char rcsid[] = "$Id: VaSimple.c,v 1.7 1999/08/14 12:17:14 danny Exp $";

#include <LTconfig.h>
#include <XmI/XmI.h>

#include <Xm/XmP.h>
#include <Xm/ToggleBGP.h>
#include <Xm/PushBGP.h>
#include <Xm/CascadeBGP.h>
#include <Xm/SeparatoGP.h>
#include <Xm/RowColumnP.h>
#include <Xm/VaSimpleP.h>
#include <X11/Xfuncs.h>

#include <XmI/DebugUtil.h>

/* this seems realistic to me */
#define MAX_EMBEDDED_BUTTONS	512
static XmButtonType button_types[MAX_EMBEDDED_BUTTONS];
static XmString button_strings[MAX_EMBEDDED_BUTTONS];
static KeySym button_mnemonics[MAX_EMBEDDED_BUTTONS];
static String button_accel[MAX_EMBEDDED_BUTTONS];
static XmString button_acc_text[MAX_EMBEDDED_BUTTONS];


extern Widget _XtCreateWidget(String,
			      WidgetClass,
			      Widget,
			      ArgList, Cardinal,
			      XtTypedArgList, Cardinal);

/*
 *    Given a nested list, _XmCountNestedList() returns counts of the
 *    total number of attribute-value pairs and the count of those
 *    attributes that are typed. The list is counted recursively.
 */
static void
_XmCountNestedList(XtTypedArgList avlist, int *total_count, int *typed_count)
{
    for (; avlist->name != NULL; avlist++)
    {
	if (strcmp(avlist->name, XtVaNestedList) == 0)
	{
	    _XmCountNestedList((XtTypedArgList)avlist->value, total_count,
			       typed_count);
	}
	else
	{
	    if (avlist->type != NULL)
	    {
		++(*typed_count);
	    }
	    ++(*total_count);
	}
    }
}

/*
 *    Given a variable length attribute-value list, _XmCountVaList()
 *    returns counts of the total number of attribute-value pairs,
 *    and the count of the number of those attributes that are typed.
 *    The list is counted recursively.
 */
void
_XmCountVaList(va_list var, int *button_count, int *args_count,
	       int *typed_count, int *total_count)
{
    String attr;

    *total_count = 0;
    *typed_count = 0;
    *button_count = 0;
    *args_count = 0;
    bzero((void *)button_types, MAX_EMBEDDED_BUTTONS * sizeof(unsigned char));
    bzero((void *)button_strings, MAX_EMBEDDED_BUTTONS * sizeof(XmString));
    bzero((void *)button_mnemonics, MAX_EMBEDDED_BUTTONS * sizeof(KeySym));
    bzero((void *)button_accel, MAX_EMBEDDED_BUTTONS * sizeof(String));
    bzero((void *)button_acc_text, MAX_EMBEDDED_BUTTONS * sizeof(XmString));

    for (attr = va_arg(var, String); attr != NULL;
	 attr = va_arg(var, String))
    {
	if (strcmp(attr, XtVaTypedArg) == 0)
	{
	    (void)va_arg(var, String);
	    (void)va_arg(var, String);
	    (void)va_arg(var, XtArgVal);
	    (void)va_arg(var, int);
	    ++(*total_count);
	    ++(*typed_count);
	}
	else if (strcmp(attr, XtVaNestedList) == 0)
	{
	    _XmCountNestedList(va_arg(var, XtTypedArgList),
			       total_count,
			       typed_count);
	}
	else if (strcmp(attr, XmVaCASCADEBUTTON) == 0)
	{
	    /* label - XmString, mnemonic - KeySym */
	    button_types[*button_count] = XmCASCADEBUTTON;
	    button_strings[*button_count] = va_arg(var, XmString);
	    button_mnemonics[*button_count] = va_arg(var, KeySym);
	    ++(*button_count);
	}
	else if (strcmp(attr, XmVaCHECKBUTTON) == 0 ||
		 strcmp(attr, XmVaPUSHBUTTON) == 0 ||
		 strcmp(attr, XmVaRADIOBUTTON) == 0 ||
		 strcmp(attr, XmVaTOGGLEBUTTON) == 0)
	{
	    if (strcmp(attr, XmVaCHECKBUTTON) == 0)
	    {
		button_types[*button_count] = XmCHECKBUTTON;
	    }

	    else if (strcmp(attr, XmVaPUSHBUTTON) == 0)
	    {
		button_types[*button_count] = XmPUSHBUTTON;
	    }

	    else if (strcmp(attr, XmVaRADIOBUTTON) == 0)
	    {
		button_types[*button_count] = XmRADIOBUTTON;
	    }

	    else if (strcmp(attr, XmVaTOGGLEBUTTON) == 0)
	    {
		button_types[*button_count] = XmTOGGLEBUTTON;
	    }

	    /* label - XmString, mnemonic - KeySym, accelerator - String,
	       accelerator_text - XmString */
	    button_strings[*button_count] = va_arg(var, XmString);
	    button_mnemonics[*button_count] = va_arg(var, KeySym);
	    button_accel[*button_count] = va_arg(var, String);
	    button_acc_text[*button_count] = va_arg(var, XmString);
	    ++(*button_count);
	}
	else if (strcmp(attr, XmVaTITLE) == 0)
	{
	    /* title - XmString */
	    if (strcmp(attr, XmVaTITLE) == 0)
	    {
		button_types[*button_count] = XmTITLE;
	    }
	    button_strings[*button_count] = va_arg(var, XmString);
	    ++(*button_count);
	}
	else if (strcmp(attr, XmVaDOUBLE_SEPARATOR) == 0 ||
		 strcmp(attr, XmVaSEPARATOR) == 0 ||
		 strcmp(attr, XmVaSINGLE_SEPARATOR) == 0)
	{
	    /* just eat it, and up the button count */
	    if (strcmp(attr, XmVaDOUBLE_SEPARATOR) == 0)
	    {
		button_types[*button_count] = XmDOUBLE_SEPARATOR;
	    }
	    else if (strcmp(attr, XmVaSEPARATOR) == 0)
	    {
		button_types[*button_count] = XmSEPARATOR;
	    }
	    else if (strcmp(attr, XmVaSINGLE_SEPARATOR) == 0)
	    {
		button_types[*button_count] = XmSEPARATOR;
	    }
	    ++(*button_count);
	}
	else
	{
	    (void)va_arg(var, XtArgVal);
	    ++(*total_count);
	    ++(*args_count);
	}
    }
}

/*
 *    _XmTypedArgToArg() invokes a resource converter to convert the
 *    passed typed arg into a name/value pair and stores the name/value
 *    pair in the passed Arg structure.  If memory is allocated for the
 *    converted value, the address is returned in the value field of 
 *    memory_return; otherwise that field is NULL.  The function returns
 *    1 if the conversion succeeded and 0 if the conversion failed.
 */
static int
_XmTypedArgToArg(Widget widget, XtTypedArgList typed_arg, ArgList arg_return,
		 XtResourceList resources, Cardinal num_resources,
		 ArgList memory_return)
{
    String to_type = NULL;
    XrmValue from_val, to_val;


    if (widget == NULL)
    {
	_XmWarning(NULL, "Attempt to convert TypedArg for NULL Widget.");
	return (0);
    }

    /* again we assume that the XtResourceList is un-compiled */

    for (; num_resources--; resources++)
    {
	if (strcmp(typed_arg->name, resources->resource_name) == 0)
	{
	    to_type = resources->resource_type;
	    break;
	}
    }

    if (to_type == NULL)
    {
	_XmWarning(widget, "Unable to find type of resource for conversion");
	return (0);
    }

    to_val.addr = NULL;
    from_val.size = typed_arg->size;
    if ((strcmp(typed_arg->type, XtRString) == 0) ||
	(typed_arg->size > sizeof(XtArgVal)))
    {
	from_val.addr = (XPointer)typed_arg->value;
    }
    else
    {
	from_val.addr = (XPointer)&typed_arg->value;
    }

    XtConvertAndStore(widget, typed_arg->type, &from_val, to_type, &to_val);

    if (to_val.addr == NULL)
    {
	_XmWarning(widget, "Type conversion failed");
	return (0);
    }

    arg_return->name = typed_arg->name;
    memory_return->value = (XtArgVal)NULL;

    if (strcmp(to_type, XtRString) == 0)
    {
	arg_return->value = (XtArgVal)to_val.addr;
    }
    else
    {
	if (to_val.size == sizeof(long))
	{
	    arg_return->value = (XtArgVal)*(long *)to_val.addr;
	}
	else if (to_val.size == sizeof(short))
	{
	    arg_return->value = (XtArgVal)*(short *)to_val.addr;
	}
	else if (to_val.size == sizeof(char))
	{
	    arg_return->value = (XtArgVal)*(char *)to_val.addr;
	}
	else if (to_val.size == sizeof(XtArgVal))
	{
	    arg_return->value = *(XtArgVal *)to_val.addr;
	}
	else if (to_val.size > sizeof(XtArgVal))
	{
	    arg_return->value = (XtArgVal)XtMalloc(to_val.size);
	    memory_return->value = (XtArgVal)arg_return->value;
	    bcopy(to_val.addr, (void *)arg_return->value, to_val.size);
	}
    }

    return (1);
}


/*
 *    _XmNestedArgtoArg() converts the passed nested list into
 *    an ArgList/count.
 */
static int
_XmNestedArgtoArg(Widget widget, XtTypedArgList avlist, ArgList args,
		  XtResourceList resources, Cardinal num_resources,
		  ArgList memory_return)
{
    int count = 0;

    for (; avlist->name != NULL; avlist++)
    {
	if (avlist->type != NULL)
	{
	    /* If widget is NULL, the typed arg is ignored */
	    if (widget != NULL)
	    {
		/* this is a typed arg */
		count += _XmTypedArgToArg(widget, avlist, (args + count),
					  resources, num_resources,
					  (memory_return + count));
	    }
	}
	else if (strcmp(avlist->name, XtVaNestedList) == 0)
	{
	    count += _XmNestedArgtoArg(widget, (XtTypedArgList)avlist->value,
				       (args + count), resources, num_resources,
				       (memory_return + count));
	}
	else
	{
	    (args + count)->name = avlist->name;
	    (args + count)->value = avlist->value;
	    ++count;
	}
    }

    return (count);
}

/*
 * Free memory allocated through _XmVaToArgList.  The actual args array
 * size is expected to be total_count * 2, where total_count is the number
 * of elements needed for resource representations.  The lower half of the
 * array contains pairs of resource names and values as usual.  For each
 * element [n] in the lower half of the array, the value field of the
 * corresponding element [n + total_count] in the upper half of the array
 * has been pressed into service in order to note whether the resource value
 * is a pointer to memory that was allocated in _XmTypedArgToArg.  In the
 * upper half, if the value field is not NULL, it contains the address of
 * memory which should now be freed.  That memory could have been allocated
 * only as a result of the conversion of typed arguments.  Therefore, if
 * there were no typed arguments in the original varargs, there is no need
 * to examine the upper half of the array.  In the choice of data structure
 * to make this representation, priority was given to the wish to retrofit
 * the release of memory around the existing signature of _XmVaToArgList.
 */
static void
_XmFreeArgList(ArgList args, int total_count, int typed_count)
{
    ArgList p;

    if (args)
    {
	if (typed_count)
	{
	    for (p = args + total_count; total_count--; ++p)
	    {
		if (p->value)
		    XtFree((char *)p->value);
	    }
	}
	XtFree((char *)args);
    }
}


/*
 * Description: Retreives the normal and constraint resources
 *              for this widget.
 * Arguments: widget - the widget.
 * RETURNED        res_list - the list of resource for this widget
 * RETURNED        number - the number of resources in the above list.
 * Returns: none
 */
static void
_XmGetResources(Widget widget, XtResourceList *res_list, Cardinal *number)
{
    Widget parent = XtParent(widget);

    XtInitializeWidgetClass(XtClass(widget));
    XtGetResourceList(XtClass(widget), res_list, number);

    if (!XtIsShell(widget) && parent && XtIsConstraint(parent))
    {
	XtResourceList res, constraint, cons_top;
	Cardinal num_constraint, temp;

	XtGetConstraintResourceList(XtClass(parent), &constraint,
				    &num_constraint);

	cons_top = constraint;
	*res_list = (XtResourceList)XtRealloc((char *)*res_list,
					      ((*number + num_constraint) *
					       sizeof(XtResource)));

	for (temp = num_constraint, res = *res_list + *number;
	     temp != 0; temp--)
	{
	    *res++ = *constraint++;
	}

	*number += num_constraint;
	XtFree((XtPointer)cons_top);
    }
}

/* 
 *    Given a variable argument list, _XmVaToArgList() returns the 
 *    equivalent ArgList and count. _XmVaToArgList() handles nested 
 *    lists and typed arguments.  If typed arguments are present, the
 *    ArgList should be freed with _XmFreeArgList.
 */
static void
_XmVaToArgList(Widget widget, va_list var, int max_count,
	       ArgList *args_return, Cardinal *num_args_return)
{
    String attr;
    int count;
    ArgList args = (ArgList)NULL;
    XtTypedArg typed_arg;
    XtResourceList resources = (XtResourceList)NULL;
    Cardinal num_resources;
    Boolean fetched_resource_list = False;

    if (max_count == 0)
    {
	*num_args_return = 0;
	*args_return = (ArgList)NULL;
	return;
    }

    max_count *= 2;
    args = (ArgList)XtMalloc((unsigned)(max_count * sizeof(Arg)));
    for (count = max_count; --count >= 0;)
    {
	args[count].value = (XtArgVal)NULL;
    }
    max_count /= 2;
    count = 0;

    for (attr = va_arg(var, String); attr != NULL;
	 attr = va_arg(var, String))
    {
	if (strcmp(attr, XtVaTypedArg) == 0)
	{
	    typed_arg.name = va_arg(var, String);
	    typed_arg.type = va_arg(var, String);
	    typed_arg.value = va_arg(var, XtArgVal);
	    typed_arg.size = va_arg(var, int);

	    /* if widget is NULL, typed args are ignored */
	    if (widget != NULL)
	    {
		if (!fetched_resource_list)
		{
		    _XmGetResources(widget, &resources, &num_resources);
		    fetched_resource_list = True;
		}
		count += _XmTypedArgToArg(widget, &typed_arg, &args[count],
					  resources, num_resources,
					  &args[max_count + count]);
	    }
	}
	else if (strcmp(attr, XtVaNestedList) == 0)
	{
	    if (widget != NULL || !fetched_resource_list)
	    {
		_XmGetResources(widget, &resources, &num_resources);
		fetched_resource_list = True;
	    }

	    count += _XmNestedArgtoArg(widget, va_arg(var, XtTypedArgList),
				       &args[count], resources, num_resources,
				       &args[max_count + count]);
	}
	else if (strcmp(attr, XmVaCASCADEBUTTON) == 0)
	{
	    /* label - XmString, mnemonic - KeySym */
	    (void)va_arg(var, XmString);
	    (void)va_arg(var, KeySym);
	}
	else if (strcmp(attr, XmVaCHECKBUTTON) == 0 ||
		 strcmp(attr, XmVaPUSHBUTTON) == 0 ||
		 strcmp(attr, XmVaRADIOBUTTON) == 0 ||
		 strcmp(attr, XmVaTOGGLEBUTTON) == 0)
	{
	    /* label - XmString, mnemonic - KeySym, accelerator - String,
	       accelerator_text - XmString */
	    (void)va_arg(var, XmString);
	    (void)va_arg(var, KeySym);
	    (void)va_arg(var, String);
	    (void)va_arg(var, XmString);
	}
	else if (strcmp(attr, XmVaTITLE) == 0)
	{
	    /* title - XmString */
	    (void)va_arg(var, XmString);
	}
	else if (strcmp(attr, XmVaDOUBLE_SEPARATOR) == 0 ||
		 strcmp(attr, XmVaSEPARATOR) == 0 ||
		 strcmp(attr, XmVaSINGLE_SEPARATOR) == 0)
	{
	    /* just eat it */
	}
	else
	{
	    args[count].name = attr;
	    args[count].value = va_arg(var, XtArgVal);
	    count++;
	}
    }

    XtFree((XtPointer)resources);

    *num_args_return = (Cardinal)count;
    *args_return = (ArgList)args;
}

static int
_XmNestedArgtoTypedArg(XtTypedArgList args,
		       XtTypedArgList avlist)
{
    int count = 0;

    for (; avlist->name != NULL; avlist++)
    {
	if (avlist->type != NULL)
	{
	    (args + count)->name = avlist->name;
	    (args + count)->type = avlist->type;
	    (args + count)->size = avlist->size;
	    (args + count)->value = avlist->value;
	    ++count;
	}
	else if (strcmp(avlist->name, XtVaNestedList) == 0)
	{
	    count += _XmNestedArgtoTypedArg((args + count),
					    (XtTypedArgList)avlist->value);
	}
	else
	{
	    (args + count)->name = avlist->name;
	    (args + count)->type = NULL;
	    (args + count)->value = avlist->value;
	    ++count;
	}
    }
    return (count);
}


/*
 *    Given a variable argument list, _XmVaToTypedArgList() returns 
 *    the equivalent TypedArgList. _XmVaToTypedArgList() handles nested
 *    lists.
 *    Note: _XmVaToTypedArgList() does not do type conversions.
 */
void
_XmVaToTypedArgList(va_list var, int max_count,
		    XtTypedArgList *args_return, Cardinal *num_args_return)
{
    XtTypedArgList args = NULL;
    String attr;
    int count;

    args = (XtTypedArgList)
	XtMalloc((unsigned)(max_count * sizeof(XtTypedArg)));

    for (attr = va_arg(var, String), count = 0; attr != NULL;
	 attr = va_arg(var, String))
    {
	if (strcmp(attr, XtVaTypedArg) == 0)
	{
	    args[count].name = va_arg(var, String);
	    args[count].type = va_arg(var, String);
	    args[count].value = va_arg(var, XtArgVal);
	    args[count].size = va_arg(var, int);
	    ++count;
	}
	else if (strcmp(attr, XtVaNestedList) == 0)
	{
	    count += _XmNestedArgtoTypedArg(&args[count],
					    va_arg(var, XtTypedArgList));
	}
	else if (strcmp(attr, XmVaCASCADEBUTTON) == 0)
	{
	    /* label - XmString, mnemonic - KeySym */
	    (void)va_arg(var, XmString);
	    (void)va_arg(var, KeySym);
	}
	else if (strcmp(attr, XmVaCHECKBUTTON) == 0 ||
		 strcmp(attr, XmVaPUSHBUTTON) == 0 ||
		 strcmp(attr, XmVaRADIOBUTTON) == 0 ||
		 strcmp(attr, XmVaTOGGLEBUTTON) == 0)
	{
	    /* label - XmString, mnemonic - KeySym, accelerator - String,
	       accelerator_text - XmString */
	    (void)va_arg(var, XmString);
	    (void)va_arg(var, KeySym);
	    (void)va_arg(var, String);
	    (void)va_arg(var, XmString);
	}
	else if (strcmp(attr, XmVaTITLE) == 0)
	{
	    /* title - XmString */
	    (void)va_arg(var, XmString);
	}
	else if (strcmp(attr, XmVaDOUBLE_SEPARATOR) == 0 ||
		 strcmp(attr, XmVaSEPARATOR) == 0 ||
		 strcmp(attr, XmVaSINGLE_SEPARATOR) == 0)
	{
	    /* just eat it */
	}
	else
	{
	    args[count].name = attr;
	    args[count].type = NULL;
	    args[count].value = va_arg(var, XtArgVal);
	    ++count;
	}
    }

    *args_return = args;
    *num_args_return = count;
}

/*

 * note: The Va version of the "Simple" routines wipe out any
 * "Simple" creation resources the caller specified in the va_list.
 * This is poorly documented, but is Motif 1.2 behavior.
 */

Widget
XmVaCreateSimpleCheckBox(Widget parent,
			 String name,
			 XtCallbackProc callback,
			 ...)
{
    ArgList arglist;
    Arg myarglist[8];
    Cardinal n = 0;
    int total_count = 0;
    int args_count = 0;
    int button_count = 0;
    int typed_count = 0;
    va_list var;
    Widget rc;

    DEBUGOUT(XdbDebug(__FILE__, parent, "XmVaCreateSimpleCheckBox();\n"));

#ifdef SIMPLE_WALKUP
    while (parent && !XtIsComposite(parent))
    {
	parent = XtParent(parent);
    }
#endif

    /* find out how many buttons, how many args, etc... we have 
     * (this also sets the button_strings, button_mnemonics, etc
     * arrays)
     */
    Va_start(var, callback);
    _XmCountVaList(var, &button_count, &args_count, &typed_count, &total_count);
    va_end(var);

    /* set Simple resources */
    XtSetArg(myarglist[n], XmNsimpleCallback, callback); n++;
    XtSetArg(myarglist[n], XmNbuttonCount, button_count); n++;
    XtSetArg(myarglist[n], XmNbuttons, button_strings); n++;

#if 0
    /* the XmVaCreateSimpleCheckBox man page says these Simple
     * resources aren't used in the 1.2 release of Motif 
     */
    XtSetArg(myarglist[n], XmNbuttonMnemonics, button_mnemonics); n++;
    XtSetArg(myarglist[n], XmNbuttonAccelerators, button_accel); n++;
    XtSetArg(myarglist[n], XmNbuttonAcceleratorText, button_acc_text); n++;
#endif

    rc = XmCreateSimpleCheckBox(parent, name, myarglist, n);

    /* I'm not sure if this (the callers valist) list should be merged
     * into the list passed to the above XmCreateSimpleCheckBox() or
     * if it can be set afterward, but it is easier to set it
     * afterward
     */
    Va_start(var, callback);
    _XmVaToArgList(rc, var, total_count, &arglist, &n);
    va_end(var);

    XtSetValues(rc, arglist, n);

    _XmFreeArgList(arglist, total_count, typed_count);

    return rc;
}

/*
 * I'm not 100% sure the XmVaCreateSimple*Menu* calls are correct,
 * since I can't really test them.
 * 
 * note: The Va version of the "Simple" routines wipe out any
 * "Simple" creation resources the caller specified in the va_list.
 * This is poorly documented, but is Motif 1.2 behavior.
 */
Widget
XmVaCreateSimpleMenuBar(Widget parent,
			String name,
			...)
{
    ArgList arglist;
    Arg myarglist[8];
    Cardinal n = 0;
    int total_count = 0;
    int args_count = 0;
    int button_count = 0;
    int typed_count = 0;
    va_list var;
    Widget rc;

    DEBUGOUT(XdbDebug(__FILE__, parent, "XmVaCreateSimpleMenuBar();\n"));

#ifdef SIMPLE_WALKUP
    while (parent && !XtIsComposite(parent))
    {
	parent = XtParent(parent);
    }
#endif

    /* find out how many buttons, how many args, etc... we have 
     * (this also sets the button_strings, button_mnemonics, etc
     * arrays)
     */
    Va_start(var, name);
    _XmCountVaList(var, &button_count, &args_count, &typed_count, &total_count);
    va_end(var);

    /* set Simple resources */
    XtSetArg(myarglist[n], XmNbuttonCount, button_count); n++;
    XtSetArg(myarglist[n], XmNbuttons, button_strings); n++;
    XtSetArg(myarglist[n], XmNbuttonMnemonics, button_mnemonics); n++;

    rc = XmCreateSimpleMenuBar(parent, name, myarglist, n);

    /* I'm not sure if this (the callers valist) list should be merged
     * into the list passed to the above XmCreateSimpleMenuBar() or
     * if it can be set afterward, but it is easier to set it
     * afterward
     */
    Va_start(var, name);
    _XmVaToArgList(rc, var, total_count, &arglist, &n);
    va_end(var);

    XtSetValues(rc, arglist, n);

    _XmFreeArgList(arglist, total_count, typed_count);

    return rc;
}

/*
 * This sucker can be (and has been) tested with Xinvest, also with
 * testXm/vasimple/test4 .
 *
 * note: The Va version of the "Simple" routines wipe out any
 * "Simple" creation resources the caller specified in the va_list.
 * This is poorly documented, but is Motif 1.2 behavior.
 */
Widget
XmVaCreateSimpleOptionMenu(Widget parent,
			   String name,
			   XmString option_label,
			   KeySym option_mnemonic,
			   int button_set,
			   XtCallbackProc callback,
			   ...)
{
    ArgList arglist, combined;
    Arg myarglist[11];
    Cardinal n = 0;
    int total_count = 0, args_count = 0, button_count = 0, typed_count = 0,
      mine;
    va_list var;
    Widget rc = NULL;

    DEBUGOUT(XdbDebug(__FILE__, parent, "XmVaCreateSimpleOptionMenu();\n"));

#ifdef SIMPLE_WALKUP
    while (parent && !XtIsComposite(parent))
    {
	parent = XtParent(parent);
    }
#endif

    /* find out how many buttons, how many args, etc... we have 
     * (this also sets the button_strings, button_mnemonics, etc
     * arrays)
     */
    Va_start(var, callback);
    _XmCountVaList(var, &button_count, &args_count, &typed_count, &total_count);
    va_end(var);

    Va_start(var, callback);
    _XmVaToArgList(rc, var, total_count, &arglist, &n);
    va_end(var);

    /* set Simple resources */
    mine = 0;
    XtSetArg(myarglist[mine], XmNbuttonSet, button_set); mine++;
    XtSetArg(myarglist[mine], XmNoptionLabel, option_label); mine++;
    XtSetArg(myarglist[mine], XmNoptionMnemonic, option_mnemonic); mine++;
    XtSetArg(myarglist[mine], XmNsimpleCallback, callback); mine++;
    XtSetArg(myarglist[mine], XmNbuttonCount, button_count); mine++;
    XtSetArg(myarglist[mine], XmNbuttonType, button_types); mine++;
    XtSetArg(myarglist[mine], XmNbuttons, button_strings); mine++;
    XtSetArg(myarglist[mine], XmNbuttonMnemonics, button_mnemonics); mine++;
    XtSetArg(myarglist[mine], XmNbuttonAccelerators, button_accel); mine++;
    XtSetArg(myarglist[mine], XmNbuttonAcceleratorText, button_acc_text);
    mine++;

    combined = XtMergeArgLists(myarglist, mine, arglist, n);
    rc = XmCreateSimpleOptionMenu(parent, name, combined, n + mine);
    XtFree((XtPointer)combined);

    return rc;
}

/*
 * I'm not 100% sure the XmVaCreateSimple*Menu* calls are correct,
 * since I can't really test them.
 * 
 * note: The Va version of the "Simple" routines wipe out any
 * "Simple" creation resources the caller specified in the va_list.
 * This is poorly documented, but is Motif 1.2 behavior.
 */
Widget
XmVaCreateSimplePopupMenu(Widget parent,
			  String name,
			  XtCallbackProc callback,
			  ...)
{
    ArgList arglist;
    Arg myarglist[11];
    Cardinal n = 0;
    int total_count = 0;
    int args_count = 0;
    int button_count = 0;
    int typed_count = 0;
    va_list var;
    Widget rc;

    DEBUGOUT(XdbDebug(__FILE__, parent, "XmVaCreateSimplePopupMenu();\n"));

#ifdef SIMPLE_WALKUP
	/*
	 * Jex demonstrates that this shouldn't happen.
	 * TFM also says
	 *	"parent - Specifies the widget ID of the parent of the MenuShell"
	 * which seems to confirm that.
	 */
    while (parent && !XtIsComposite(parent))
    {
	parent = XtParent(parent);
    }
#endif

    /* find out how many buttons, how many args, etc... we have 
     * (this also sets the button_strings, button_mnemonics, etc
     * arrays)
     */
    Va_start(var, callback);
    _XmCountVaList(var, &button_count, &args_count, &typed_count, &total_count);
    va_end(var);

    /* set Simple resources */
    XtSetArg(myarglist[n], XmNsimpleCallback, callback); n++;
    XtSetArg(myarglist[n], XmNbuttonCount, button_count); n++;
    XtSetArg(myarglist[n], XmNbuttonType, button_types); n++;
    XtSetArg(myarglist[n], XmNbuttons, button_strings); n++;
    XtSetArg(myarglist[n], XmNbuttonMnemonics, button_mnemonics); n++;
    XtSetArg(myarglist[n], XmNbuttonAccelerators, button_accel); n++;
    XtSetArg(myarglist[n], XmNbuttonAcceleratorText, button_acc_text); n++;

    rc = XmCreateSimplePopupMenu(parent, name, myarglist, n);

    /* I'm not sure if this (the callers valist) list should be merged
     * into the list passed to the above XmCreateSimplePopupMenu() or
     * if it can be set afterward, but it is easier to set it
     * afterward
     */
    Va_start(var, callback);
    _XmVaToArgList(rc, var, total_count, &arglist, &n);
    va_end(var);

    XtSetValues(rc, arglist, n);

    _XmFreeArgList(arglist, total_count, typed_count);

    return rc;
}

/*
 * I'm not 100% sure the XmVaCreateSimple*Menu* calls are correct,
 * since I can't really test them.
 * 
 * note: The Va version of the "Simple" routines wipe out any
 * "Simple" creation resources the caller specified in the va_list.
 * This is poorly documented, but is Motif 1.2 behavior.
 */
Widget
XmVaCreateSimplePulldownMenu(Widget parent,
			     String name,
			     int post_from_button,
			     XtCallbackProc callback,
			     ...)
{
    ArgList arglist;
    Arg myarglist[11];
    Cardinal n = 0;
    int total_count = 0;
    int args_count = 0;
    int button_count = 0;
    int typed_count = 0;
    va_list var;
    Widget rc;


    DEBUGOUT(XdbDebug(__FILE__, parent, "XmVaCreateSimplePulldownMenu();\n"));

#ifdef SIMPLE_WALKUP
    while (parent && !XtIsComposite(parent))
    {
	parent = XtParent(parent);
    }
#endif


    /* find out how many buttons, how many args, etc... we have 
     * (this also sets the button_strings, button_mnemonics, etc
     * arrays)
     */
    Va_start(var, callback);
    _XmCountVaList(var, &button_count, &args_count, &typed_count, &total_count);
    va_end(var);

    /* set Simple resources */
    XtSetArg(myarglist[n], XmNpostFromButton, post_from_button); n++;
    XtSetArg(myarglist[n], XmNsimpleCallback, callback); n++;
    XtSetArg(myarglist[n], XmNbuttonCount, button_count); n++;
    XtSetArg(myarglist[n], XmNbuttonType, button_types); n++;
    XtSetArg(myarglist[n], XmNbuttons, button_strings); n++;
    XtSetArg(myarglist[n], XmNbuttonMnemonics, button_mnemonics); n++;
    XtSetArg(myarglist[n], XmNbuttonAccelerators, button_accel); n++;
    XtSetArg(myarglist[n], XmNbuttonAcceleratorText, button_acc_text); n++;

    rc = XmCreateSimplePulldownMenu(parent, name, myarglist, n);

    /* I'm not sure if this (the callers valist) list should be merged
     * into the list passed to the above XmCreateSimplePulldownMenu() or
     * if it can be set afterward, but it is easier to set it
     * afterward
     */
    Va_start(var, callback);
    _XmVaToArgList(rc, var, total_count, &arglist, &n);
    va_end(var);

    XtSetValues(rc, arglist, n);

    _XmFreeArgList(arglist, total_count, typed_count);

    return rc;
}

/*

 * note: The Va version of the "Simple" routines wipe out any
 * "Simple" creation resources the caller specified in the va_list.
 * This is poorly documented, but is Motif 1.2 behavior.
 */
Widget
XmVaCreateSimpleRadioBox(Widget parent,
			 String name,
			 int button_set,
			 XtCallbackProc callback,
			 ...)
{
    ArgList arglist;
    Arg myarglist[8];
    Cardinal n = 0;
    int total_count = 0;
    int args_count = 0;
    int button_count = 0;
    int typed_count = 0;
    va_list var;
    Widget rc;

    DEBUGOUT(XdbDebug(__FILE__, parent, "XmVaCreateSimpleRadioBox();\n"));

#ifdef SIMPLE_WALKUP
    while (parent && !XtIsComposite(parent))
    {
	parent = XtParent(parent);
    }
#endif

    /* find out how many buttons, how many args, etc... we have 
     * (this also sets the button_strings, button_mnemonics, etc
     * arrays)
     */
    Va_start(var, callback);
    _XmCountVaList(var, &button_count, &args_count, &typed_count, &total_count);
    va_end(var);

    /* set Simple resources */
    XtSetArg(myarglist[n], XmNbuttonSet, button_set); n++;
    XtSetArg(myarglist[n], XmNsimpleCallback, callback); n++;
    XtSetArg(myarglist[n], XmNbuttonCount, button_count); n++;
    XtSetArg(myarglist[n], XmNbuttons, button_strings); n++;

#if 0
    /* the XmVaCreateSimpleRadioButton man page says these Simple
     * resources aren't used in the 1.2 release of Motif 
     */
    XtSetArg(myarglist[n], XmNbuttonMnemonics, button_mnemonics); n++;
    XtSetArg(myarglist[n], XmNbuttonAccelerators, button_accel); n++;
    XtSetArg(myarglist[n], XmNbuttonAcceleratorText, button_acc_text); n++;
#endif

    rc = XmCreateSimpleRadioBox(parent, name, myarglist, n);

    /* I'm not sure if this (the callers valist) list should be merged
     * into the list passed to the above XmCreateSimpleRadioBox() or
     * if it can be set afterward, but it is easier to set it
     * afterward
     */
    Va_start(var, callback);
    _XmVaToArgList(rc, var, total_count, &arglist, &n);
    va_end(var);

    XtSetValues(rc, arglist, n);

    _XmFreeArgList(arglist, total_count, typed_count);

    return rc;
}
