/****************************************************************************/
/*   xmUsrDlg.C                                                             */
/****************************************************************************/
/*                                                                          */
/*   Copyright (c) 1992, 1993 Bernhard Strassl                              */
/*       Vienna User Interface Group                                        */
/*       Institute for Applied Computer Science and Information Systems     */
/*       University of Vienna, Austria                                      */
/*                                                                          */
/*   See file COPYRIGHT in this directory for details. If this file is      */
/*   missing please mail to xmpp@ani.univie.ac.at                           */
/****************************************************************************/

#include <stdarg.h>
#include <strstream.h>
#include <stream.h>

#include "xmObject.h"

extern "C"
{
void XtMoveWidget(Widget, int, int);
void XtResizeWidget(Widget, int, int, int);
void XtConfigureWidget(Widget, int, int, int, int, int);
}

#undef display
#undef screen
#undef mainWindow

#ifndef XAW
#define XmSDCS XmSTRING_DEFAULT_CHARSET
#endif

extern "C"
{
#include "xgif.h"
}
#include "default_bitmap"

char* XmImageDir = "./";
char* bmp_file_errors[] = { "open failed" , "invalid data", "no memory" };

Pixmap _createXmPixmap(char* wname, int w, int h)
{
	char* fname = new char[strlen(XmImageDir) + strlen(wname) + 1];
	Pixmap aBitmap, aPixmap = (Pixmap )NULL;
	unsigned int bmw, bmh;
	int rc;
	Display* d = App->getDisplay();

	if(w || h)
	{	if(!(w && h))
		{	cerr << "Bitmap error: invalid parameters, using default...\n";
			wname = default_bitmap_bits;
			w = default_bitmap_width;
			h = default_bitmap_height;
		}
		aPixmap = XCreatePixmapFromBitmapData(d, RootWindow(d, 0), wname, w, h, BlackPixel(d, 0), WhitePixel(d, 0), DefaultDepth(d, 0));
	}
	else
	{	strcpy(fname, XmImageDir);
		strcat(fname, wname);
		if(strstr(wname, ".gif"))
		{	theDisp = d;
			LoadGIF(fname);
			if(!loadOk || DefaultDepth(d, 0) != 8)
			{	cerr << "using default...\n";
				aPixmap = XCreatePixmapFromBitmapData(d, RootWindow(d, 0), default_bitmap_bits, default_bitmap_width, default_bitmap_height, BlackPixel(d, 0), WhitePixel(d, 0), DefaultDepth(d, 0));
			}
			else
			{	GC gc;
				int imgWidth = theImage->width;
				int imgHeight = theImage->height;
				aPixmap = XCreatePixmap(d, RootWindow(d, 0), imgWidth, imgHeight, DefaultDepth(d, 0));
#ifdef AIX
				gc = XCreateGC(d, aPixmap, (unsigned long )NULL, (XGCValues* )NULL);
#else
				gc = XCreateGC(d, aPixmap, (unsigned long )NULL, (struct XGCValues* )NULL);
#endif
				XPutImage(d, aPixmap, gc, theImage , 0, 0, 0, 0, imgWidth, imgHeight);
				XDestroyImage(theImage);
				XFreeGC(d, gc);
			}
		}
		else
		{	if((rc = XReadBitmapFile(d, RootWindow(d, 0), fname, &bmw, &bmh, &aBitmap, NULL, NULL)) != BitmapSuccess)
			{	cerr << "Bitmap file error: " << bmp_file_errors[rc - 1] << ", using default...\n";
				aPixmap = XCreatePixmapFromBitmapData(d, RootWindow(d, 0), default_bitmap_bits, default_bitmap_width, default_bitmap_height, BlackPixel(d, 0), WhitePixel(d, 0), DefaultDepth(d, 0));
			}
			else
			{	GC gc;
				aPixmap = XCreatePixmap(d, RootWindow(d, 0), bmw, bmh, DefaultDepth(d, 0));
#ifdef AIX
				gc = XCreateGC(d, aPixmap, (unsigned long )NULL, (XGCValues* )NULL);
#else
				gc = XCreateGC(d, aPixmap, (unsigned long )NULL, (struct XGCValues* )NULL);
#endif
				XCopyPlane(d, aBitmap, aPixmap, gc, 0, 0, bmw, bmh, 0, 0, 1);
				XFreePixmap(d, aBitmap);
				XFreeGC(d, gc);
			}
		}
	}
	return(aPixmap);
}

#ifdef XAW
extern "C" {
#include <X11/Xaw/Form.h>
}
#else
#include <X11/Xm/BulletinB.h>
#include <X11/Xm/Form.h>
#endif

extern void genericCallback(Widget, XtPointer, XtPointer);

XmDialogPane::~XmDialogPane()
{
	for(int i = 0; i < controlCount; i++)
		delete controls[i];
}

void XmDialogPane::getFocus(Widget)
{
}

int XmDialogPane::controlIndex(XmControl* aControl)
{
	for(int i = 0; i < controlCount; i++)
	{	if(controls[i] == aControl)
			return(i);
	}
	return(-1);
}

XmControl* XmDialogPane::findControl(ctrlType t, char* n, bool warn)
{
	ctrlType ct;

	for(int i = 0; i < controlCount; i++)
	{	ct = controls[i]->controlType();
		if(!strcmp(controls[i]->wname, n))
		{	if(ct == t)
				return(controls[i]);
			cerr << "class xmDialogPane: Error - invalid control type for " << n << " !\n";
			return(NULL);
		}
		XmControl* aControl;
		if(((ct == GroupBox || ct == PaneArea) && (aControl = ((XmGroupBox* )controls[i])->findControl(t, n, FALSE))) ||
			(ct == Pane && (aControl = ((XmPane* )controls[i])->getControl(t, n))))
			return(aControl);
	}
	if(warn)	// explain the following core dump...
		cerr << "class xmDialogPane: Error - control with name " << n << " not found !\n";
	return(NULL);
}

XmGroupBox* XmDialogPane::nextGroup(int& ndx)
{
	while(ndx < controlCount)
	{	if(controls[ndx]->controlType() == GroupBox)
			return((XmGroupBox* )controls[ndx++]);
		ndx++;
	}
	return(NULL);
}

bool XmDialogPane::add(XmControl* aControl, XmObject* rec, cbProc code, void* cl_data)
{
	XmGroupBox* g;
	int ndx = 0;

	while(g = nextGroup(ndx))
	{	if(g->parentFor(aControl))
			break;
	}
	if(g)
		return(g->addAbs(aControl, rec, code, cl_data));
	else
	{	if(!aControl->isA(Pane) && !aControl->isA(PaneArea) && !aControl->isA(ToolBar))
#ifdef XAW
		{	aControl->addArg(XtNleft, XtChainLeft);
			aControl->addArg(XtNright, XtChainLeft);
			aControl->addArg(XtNtop, XtChainTop);
			aControl->addArg(XtNbottom, XtChainTop);
			aControl->addArg(XtNhorizDistance, aControl->cx);
			aControl->addArg(XtNvertDistance, aControl->cy);
		}
#else
		{	aControl->addArg(XmNleftAttachment, XmATTACH_NONE);
			aControl->addArg(XmNrightAttachment, XmATTACH_NONE);
			aControl->addArg(XmNtopAttachment, XmATTACH_NONE);
			aControl->addArg(XmNbottomAttachment, XmATTACH_NONE);
			aControl->addArg(XmNresizable, FALSE);
		}
#endif
		if(aControl->createControl(this))
			controls[controlCount++] = (XmControl* )aControl->getBase();
		else
			return(FALSE);
		if(aControl->isA(RadioButton))
		{	XmRadioButton* r = (XmRadioButton* )aControl;
			if(curRadio)
				curRadio->chainTo(r);
			curRadio = r;
		}
		if(rec && validProc(code))
			aControl->setCallback(NULL, rec, code, TRUE, cl_data);
	}
	return(TRUE);
}

bool XmDialogPane::remove(char* n)
{
	XmControl* aControl = NULL;
	int i;

	for(i = 0; i < controlCount; i++)
	{	if(!strcmp(controls[i]->wname, n))
		{	aControl = controls[i];
			break;
		}
	}
	if(!aControl || !aControl->destroy())
		return(FALSE);
	controlCount--;
	while(i < controlCount)
	{	controls[i] = controls[i + 1];
		i++;
	}
	return(TRUE);
}

XmControl* XmDialogPane::find(char* n)
{
	for(int i = 0; i < controlCount; i++)
	{	if(!strcmp(controls[i]->wname, n))
			return(controls[i]);
	}
	return(NULL);
}


// Base class for user defined dialogs //////////////////////////


XmUserDialog::XmUserDialog(char* n, XmObject* par, xmStyle s) : XmDialog(n, par)
{
	initDialog(n, par, s);
}

XmUserDialog::XmUserDialog(char* n, XmObject* par, XmManager* mgr, xmStyle s) : XmDialog(n, par)
{
	manager = mgr;
	manager->addObject(this, DialogWindow);
	initDialog(n, par, s);
}

XmUserDialog::~XmUserDialog()
{
	if(manager)
		manager->removeObject(this);
#ifdef XAW
	parent = NULL;		// be sure to destroy the parent widget....!
#endif
}

void XmUserDialog::initDialog(char* n, XmObject* par, xmStyle s)
{
	ix = iy = iw = ih = 0;

	init(n, par);		// it seems that only the default constr of XmObject is called...
	basePtr = (XmObject* )((void* )this);		// override the base pointer !
#ifdef XAW
	addArg(XtNdefaultDistance, 0);
#else
	addArg(XmNunitType, App->getScreenUnitType());
	addArg(XmNhorizontalSpacing, 0);
	addArg(XmNverticalSpacing, 0);
	addArg(XmNrubberPositioning, TRUE);
	addArg(XmNresizePolicy, XmRESIZE_NONE);		// default...
#endif
#ifdef XAW
	if(FALSE && par)	// unsolved transient shell problem...
	{	ostrstream shName;
		shName << n << "-shell"; shName.put('\0');
		Widget aShell;
		Arg a;
		XtSetArg(a, XtNtransientFor, (XtArgVal )par->handle());
		aShell = XtCreateWidget(shName.str(), transientShellWidgetClass, par->handle(), &a, 1);
		XtManageChild(wid = XtCreateWidget(n, formWidgetClass, aShell, wargs, wargcount));
	}
#else
	if(par)
	{	addArg(XmNautoUnmanage, FALSE);
		wid = XmCreateFormDialog(par->handle(), n, wargs, wargcount);
		if(s)
		{	long func, decor;

			dlgStyle = s;
			translateWindowStyles(s, func, decor);
			addArg(XmNtransient, FALSE);
			if(func)
				addArg(XmNmwmFunctions, func);
			if(decor)
				addArg(XmNmwmDecorations, decor);
			XtSetValues(XtParent(wid), wargs, wargcount);
		}
	}
#endif
	else
	{	Widget aShell;
		aShell = App->newMainWindow(this, n, 0, 0, s);
#ifdef XAW
		XtManageChild(wid = XtCreateWidget(n, formWidgetClass, aShell, wargs, wargcount));
#else
		XtManageChild(wid = XmCreateForm(aShell, n, wargs, wargcount));
		wargcount = 0;
		// these values seem to be ignored by this @*^! dialog...
		addArg(XmNhorizontalSpacing, 0);
		addArg(XmNverticalSpacing, 0);
		addArg(XmNrubberPositioning, TRUE);
		addArg(XmNresizePolicy, XmRESIZE_NONE);		// default...
		XtSetValues(wid, wargs, wargcount);
#endif
	}
	wargcount = 0;
#ifdef XAW
	setCallback(XtNdestroyCallback, this, CB(XmUserDialog::destroyCb), TRUE, CB_XM_HANDLE);
#else
	setCallback(XmNfocusCallback, this, CB(XmUserDialog::getFocusCb), TRUE, CB_XM_HANDLE);
	setCallback(XmNdestroyCallback, this, CB(XmUserDialog::destroyCb), TRUE, CB_XM_HANDLE);
	XmAddTabGroup(wid);
#endif
	setLabelAndMode(n);
	destroyOnDelete();
}

void XmUserDialog::getFocusCb(void* w)
{
	getFocus((Widget )w);
}

void XmUserDialog::destroyCb(void* w)
{
	if(magic == MAGIC_OBJECT_CONST && wid == (Widget )w)
	{	wid = NULL;
		delete this;
	}
}

bool XmUserDialog::realize()
{
	if(wid)
	{	int x = 0, y = 0, w = 0, h = 0;
		if(initWindowSize(x, y, w, h))
		{	ix = x; iy = y; iw = w; ih = h;
		}
		if(ix || iy || iw || ih)
		{	if(ix) addArg(XtNx, ix);
			if(iy) addArg(XtNy, iy);
			if(iw) addArg(XtNwidth, iw);
			if(ih) addArg(XtNheight, ih);
#ifdef XAW
			XtSetValues(XtParent(wid), wargs, wargcount);
			XtRealizeWidget(XtParent(wid));
			wargcount = 0;
		}
#else
			XtSetValues(parent ? wid : XtParent(wid), wargs, wargcount);
			wargcount = 0;
		}
		if(parent)
			XtManageChild(wid);							// manage a form dialog...
		else
			XtRealizeWidget(XtParent(wid));				// realize an app shell...
#endif
		return(TRUE);
	}
	return(FALSE);
}

bool XmUserDialog::setLabel(char* txt)
{
	Arg a;

	if(!wid)
		return(FALSE);
#ifdef XAW
	XtSetArg(a, XtNlabel, txt);
#else
	XtSetArg(a, XmNtitle, txt);
#endif
	XtSetValues(XtParent(wid), &a, 1);
	return(TRUE);
}

bool XmUserDialog::setFocus(char*)			{ return(FALSE); }

bool XmUserDialog::setDefaultButton(char* bName)
{
#ifndef XAW
	XmControl* aControl = find(bName);

	if(aControl && aControl->controlType() == PushButton && wid && aControl->handle())
	{	forceArg(XmNdefaultButton, (XtArgVal )aControl->handle());
		return(TRUE);
	}
#endif
	return(FALSE); 
}

#define do_single_arg(func) \
	XmControl* aControl; \
	if(aControl = find(first)) \
		aControl-> func (); \
	return(aControl ? TRUE : FALSE);

#define do_varargs(func) \
	char* aName = first; \
	XmControl* aControl; \
	va_list ap; \
	va_start(ap, first); \
	do \
	{	if(aControl = find(aName)) \
			aControl-> func (); \
	} \
	while((aName = va_arg(ap, char *)) != (char *)0); \
	va_end(ap); \
	return(TRUE);

#define do_ptrs(func) \
	char* aName = *list; \
	XmControl* aControl; \
	while(aName = *list++) \
	{	if(aControl = find(aName)) \
			aControl-> func (); \
	} \
	return(TRUE);

bool XmDialogPane::disable(char** list)
{
	do_ptrs( disable )
}

bool XmDialogPane::disable(char* first, ...)
{
#ifndef NO_VARARGS
	do_varargs( disable )
#else
	do_single_arg( disable )
#endif
}

bool XmDialogPane::enable(char** list)
{
	do_ptrs( enable )
}

bool XmDialogPane::enable(char* first, ...)
{
#ifndef NO_VARARGS
	do_varargs( enable )
#else
	do_single_arg( enable )
#endif
}

bool XmDialogPane::hideAll(char** list)
{
	do_ptrs( hide )
}

bool XmDialogPane::hideAll(char* first, ...)
{
#ifndef NO_VARARGS
	do_varargs( hide )
#else
	do_single_arg( hide )
#endif
}

bool XmDialogPane::showAll(char** list)
{
	do_ptrs( show )
}

bool XmDialogPane::showAll(char* first, ...)
{
#ifndef NO_VARARGS
	do_varargs( show )
#else
	do_single_arg( show )
#endif
}

// Controls /////////////////////////////////////////////

XmControl::XmControl(char* n, int x, int y, int w, int h, xmStyle s) : XmObject(n, (XmObject* )NULL)
{
	cx = x; cy = y; cw = w; ch = h;
	style = s;
#ifndef XAW
	addArg(XmNunitType, App->getScreenUnitType());
#endif
	long lx = 0, ly = 0, lw = 0, lh = 0;
	lx = x; ly = y; lw = w; lh = h;

	if(x)
		addArg(XtNx, (XtArgVal )lx);
	if(y)
		addArg(XtNy, (XtArgVal )ly);
	if(w)
		addArg(XtNwidth, (XtArgVal )lw);
	if(h)
		addArg(XtNheight, (XtArgVal )lh);
}

bool XmControl::setCbFor(Widget w, char* cbName, XmObject* rec, cbProc code, bool sr, void* cl_data)
{
	if(!rec || !(cbName || defaultCallback()))
	{	cerr << "xmControl: " << wname << " - invalid callback parameters, ignoring request...\n";
		return(FALSE);
	}
	if(!cbName)
		cbName = defaultCallback();
	if(hookedCb() && !strcmp(cbName, hookedCb()) && rec != this)
	{	userData.receiver = rec->getBase();
		userData.callback = code;
		userData.client_data = (cl_data == CB_OBJ_PTR) ? this : cl_data;
	}
	else 
		XmObject::setCbFor(w, cbName, rec, code, sr, (cl_data == CB_OBJ_PTR) ? this : cl_data);
	return(TRUE);
}

void XmControl::makeRelativeTo(XmGroupBox* aGroup)
{
	cx -= aGroup->cx;
	cy -= aGroup->cy;
	if(cx >= 0)
		changeArg(XtNx, cx);
	if(cy >= 0)
		changeArg(XtNy, cy);
}

void XmControl::initTabstop(bool force)
{
#ifndef XAW
	if(wid && (style & XmStabStop || force))
		XmAddTabGroup(wid);
#endif
}

char* XmControl::currentLabel()
{
	char* aStr = wname;
	int argNdx;
#ifdef XAW
	if((argNdx = argIndex(XtNlabel)) != -1)
	{	aStr = new char[strlen((const char* )wargs[argNdx].value) + 1];
		strcpy(aStr, (const char* )wargs[argNdx].value);
	}
#else
	if((argNdx = argIndex(XmNlabelString)) != -1)
	{	XmString xStr;
		xStr = (XmString )wargs[argNdx].value;
		aStr = new char[XmStringLength(xStr)];
		if(!XmStringGetLtoR(xStr, XmSDCS, &aStr))
			cerr << "xmControl: Error - something wrong with string arguments...\n";
		XmStringFree(xStr);
	}
#endif
	return(aStr);
}

void XmControl::setLabelAndMnemonic()
{
	char mm = 0;
		
#ifdef XAW
	if(!hasArg(XtNbitmap))
	{	if(hasArg(XtNlabel))
#else
	if(!hasArg(XmNlabelPixmap))
	{	if(hasArg(XmNlabelString))
#endif
		{	char* aStr = currentLabel();		// answers new allocated string...
			mm = parse(aStr);
#ifdef XAW
			changeArg(XtNlabel, aStr);
#else
			changeArg(XmNlabelString, (XtArgVal )XmStringCreateLtoR(aStr, XmSDCS));
#endif
//			delete aStr;	// produces garbage, I know...
		}
		else
		{	if(strchr(wname, '&'))
				mm = parse(wname);				// wname is also an allocated string...
			if(checkResource("labelString"))
				mm = 0;
		}
#ifndef XAW
		if(mm)
			addArg(XmNmnemonic, mm);
#endif
	}
}


XmUserDialog* XmControl::getDialog()
{
	return(parent->asDialog());
}

bool XmControl::move(int nx, int ny)
{
	cx = nx;
	cy = ny;
	if(wid)
		return(XmObject::move(cx, cy));
	else
	{	changeArg(XtNx, cx);
		changeArg(XtNy, cy);
	}
	return(TRUE);
}

bool XmControl::resize(int nw, int nh)
{
	cw = nw;
	ch = nh;
	if(wid)
		return(XmObject::resize(cw, ch));
	else
	{	changeArg(XtNwidth, cw);
		changeArg(XtNheight, ch);
	}
	return(TRUE);
}

bool XmControl::reframe(int nx, int ny, int nw, int nh)
{
	cx = nx;
	cy = ny;
	cw = nw;
	ch = nh;
	if(wid)
		return(XmObject::reframe(cx, cy, cw, ch));
	else
	{	changeArg(XtNx, cx);
		changeArg(XtNy, cy);
		changeArg(XtNwidth, cw);
		changeArg(XtNheight, ch);
	}
	return(TRUE);
}

bool XmControl::updateDimensions()
{
	if(wid)
	{	Arg a[4];
		XtSetArg(a[0], XtNx, (XtArgVal )&cx);
		XtSetArg(a[1], XtNy, (XtArgVal )&cy);
		XtSetArg(a[2], XtNwidth, (XtArgVal )&cw);
		XtSetArg(a[3], XtNheight, (XtArgVal )&ch);
		XtGetValues(wid, a, 4);
		return(TRUE);
	}
	return(FALSE);
}

XmControl* XmControl::setText(char* aStr)
{
#ifdef XAW
	addArg(XtNlabel, (XtArgVal )aStr);
#else
	addArg(XmNlabelString, (XtArgVal )XmStringCreateLtoR(aStr, XmSDCS));
#endif
	if(wid)
	{	XtSetValues(wid, wargs, wargcount);
		wargcount = 0;
	}
	return(this);
}

XmControl* XmControl::setFont(char* aStr)
{
	XFontStruct* font;

	if(!(font = XLoadQueryFont(App->getDisplay(), aStr)))
		cerr << "xmControl: unable to load font '" << aStr << "', using default.\n";
#ifdef XAW
	addArg(XtNfont, (XtArgVal )font);
#else
	addArg(XmNfontList, (XtArgVal )XmFontListCreate(font, XmSDCS));
#endif
	if(wid)
	{	XtSetValues(wid, wargs, wargcount);
		wargcount = 0;
	}
	return(this);
}

char* lastGetTextBuffer = NULL;

char* XmControl::getText()
{
	if(!wid)
		return(wname ? wname : "");
	char* curTxt = NULL;
	Arg a;
#ifdef XAW
	XtSetArg(a, XtNlabel, &curTxt);
#else
	XmString tmpTxt;
	XtSetArg(a, XmNlabelString, &tmpTxt);
#endif
	XtGetValues(wid, &a, 1);
#ifndef XAW
	lastGetTextBuffer = new char[XmStringLength(tmpTxt) + 1];
	if(XmStringGetLtoR(tmpTxt, XmSDCS, &lastGetTextBuffer))
		curTxt = lastGetTextBuffer;
#endif
	return(curTxt);
}

XmControl* XmControl::setImage(Pixmap aPixmap)
{
#ifdef XAW
	addArg(XtNbitmap, aPixmap);
#else
	addArg(XmNlabelType, XmPIXMAP);
	addArg(XmNlabelPixmap, (XtArgVal )aPixmap);
	addArg(XmNlabelInsensitivePixmap, (XtArgVal )aPixmap);	// missing: create a grayed copy...
#endif
	if(wid)
	{	Arg a;
		Pixmap oldImg = 0L;
#ifdef XAW
		XtSetArg(a, XtNbitmap, &oldImg);
#else
		XtSetArg(a, XmNlabelPixmap, &oldImg);
#endif
		XtGetValues(wid, &a, 1);
#ifdef XAW
		if(oldImg)
#else
		if(oldImg && oldImg != XmUNSPECIFIED_PIXMAP)
#endif
			XFreePixmap(App->getDisplay(), oldImg);
		XtSetValues(wid, wargs, wargcount);
		wargcount = 0;
	}
	return(this);
}

XmControl* XmControl::setFocus()
{
	XEvent e;
#ifndef XAW
	if(wid)
	{	XtCallActionProc(XtParent(wid), "ManagerFocusOut", &e, NULL, 0);
		XtCallActionProc(wid, "PrimitiveFocusIn", &e, NULL, 0);
	}
#endif
	return(this);
}

XmControl* XmControl::disable()
{
#ifdef XAW
	addArg(XtNsensitive, FALSE);
#else
	addArg(XmNsensitive, FALSE);
#endif
	if(wid)
	{	XtSetValues(wid, wargs, wargcount);
		wargcount = 0;
	}
	return(this);
}

XmControl* XmControl::enable()
{
#ifdef XAW
	addArg(XtNsensitive, TRUE);
#else
	addArg(XmNsensitive, TRUE);
#endif
	if(wid)
	{	XtSetValues(wid, wargs, wargcount);
		wargcount = 0;
	}
	return(this);
}

#ifdef XAW
extern "C" {
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Simple.h>
}
#else
#include <X11/Xm/BulletinB.h>
#include <X11/Xm/LabelG.h>
#endif

bool XmGroupBox::createControl(XmControlPane* par)
{
	int lNdx;

	parent = par->asObject();
#ifdef XAW
	addArg(XtNdefaultDistance, 0);
	if(controlType() == ComboBox)
		addArg(XtNborderWidth, 0);
	XtManageChild(wid = XtCreateWidget(wname, formWidgetClass, par->handle(), wargs, wargcount));
	if((lNdx = argIndex(XtNlabel)) != -1 || checkResource("group-label.labelString"))
#else
	addArg(XmNautoUnmanage, FALSE);
	addArg(XmNdefaultPosition, FALSE);
	addArg(XmNresizePolicy, XmRESIZE_NONE);
	addArg(XmNmarginWidth, 1);
	addArg(XmNmarginHeight, 1);
	if(controlType() != ComboBox)
	{	addArg(XmNshadowThickness, 3);
		addArg(XmNshadowType, XmSHADOW_ETCHED_IN);
	}
	XtManageChild(wid = XmCreateForm(par->handle(), wname, wargs, wargcount));
	if((lNdx = argIndex(XmNlabelString)) != -1 || checkResource("group-label.labelString"))
#endif
	{	wargcount = 0;
		addArg(XtNx, 20);
		addArg(XtNy, 2);
		if(lNdx != -1)
#ifdef XAW
			addArg(XtNlabel, wargs[lNdx].value);
		addArg(XtNborderWidth, 0);
		XtManageChild(XtCreateWidget("group-label", labelWidgetClass, wid, wargs, wargcount));
	}
	wargcount = 0;
	addArg(XtNleft, XtChainLeft);
	addArg(XtNright, XtChainLeft);
	addArg(XtNtop, XtChainTop);
	addArg(XtNbottom, XtChainTop);
	addArg(XtNwidth, 1);
	addArg(XtNheight, 1);
	addArg(XtNx, cw - 1);
	addArg(XtNy, ch - 1);
	addArg(XtNhorizDistance, cw - 1);
	addArg(XtNvertDistance, ch - 1);
	addArg(XtNborderWidth, 0);
	XtManageChild(XtCreateWidget("gb-dummy", simpleWidgetClass, wid, wargs, wargcount));

#else
			addArg(XmNlabelString, wargs[lNdx].value);
		XtManageChild(XmCreateLabelGadget(wid, "group-label", wargs, wargcount));
	}
#endif
	wargcount = 0;
#ifndef XAW
	setCallback(XmNfocusCallback, this, CB(XmGroupBox::getFocusCb), TRUE, CB_XM_HANDLE);
	initTabstop();
#endif
	return(wid ? TRUE : FALSE);
}

void XmGroupBox::getFocusCb(void* w)
{
	getFocus((Widget )w);
}

bool XmGroupBox::parentFor(XmControl* c)
{
	if(c->cx > cx && c->cx < cx + cw && c->cy > cy && c->cy < cy + ch)
		return(TRUE);
	return(FALSE);
}

bool XmGroupBox::addAbs(XmControl* c, XmObject* rec, cbProc cb, void* cd)	
{
	c->makeRelativeTo(this);
	return(XmDialogPane::add(c, rec, cb, cd));
}

bool XmGroupBox::remove(char* n)
{
	return(XmDialogPane::remove(n));
}

#ifdef XAW
extern "C" {
#include <X11/Xaw/Form.h>
}
#else
#include <X11/Xm/Form.h>
#endif

bool XmPane::createControl(XmControlPane* par)
{
	int lNdx;

	hLabel = NULL;

#ifdef XAW
	addArg(XtNdefaultDistance, 0);
	XtManageChild(wid = XtCreateWidget(wname, formWidgetClass, par->handle(), wargs, wargcount));
	if((lNdx = argIndex(XtNlabel)) != -1)
	{	wargcount = 0;
		addArg(XtNlabel, wargs[lNdx].value);
		XtManageChild(XtCreateWidget("pn-label", labelWidgetClass, wid, wargs, wargcount));
	}
#else
	addArg(XmNautoUnmanage, FALSE);
	XtManageChild(wid = XmCreateForm(par->handle(), wname, wargs, wargcount));
	if((lNdx = argIndex(XmNlabelString)) != -1)
	{	wargcount = 0;
		addArg(XmNlabelString, wargs[lNdx].value);
		addArg(XmNalignment, XmALIGNMENT_CENTER);
		addArg(XmNleftAttachment, XmATTACH_FORM);
		addArg(XmNrightAttachment, XmATTACH_FORM);
		addArg(XmNtopAttachment, XmATTACH_FORM);
		XtManageChild(hLabel = XmCreateLabelGadget(wid, "pn-label", wargs, wargcount));
	}
#endif
	wargcount = 0;
	parent = par->asObject();
	return(wid ? TRUE : FALSE);
}

bool XmPane::setContents(XmControl* c, XmObject* rec, cbProc cb)	
{
	if(contents)
	{	if(!contents->destroy())
			return(FALSE);
	}
	contents = NULL;
	if(c)
	{	if(!c->createControl(this))
			return(FALSE);
		contents = c;		// (XmControl* )aControl->asObjPtr();
		if(rec && c->defaultCallback())
			c->setCallback(c->defaultCallback(), rec, cb, TRUE, (void* )c);
		c->userData.receiver = (rec) ? rec->getBase() : rec;
		c->userData.callback = cb;
		if(handle() && XtWindow(handle()))
			c->realize();
	}
	return(TRUE);
}

bool XmPane::changeLabel(char* txt)
{
	if(hLabel)
#ifdef XAW
	{	addArg(XtNlabel, (XtArgVal )txt);
#else
	{	addArg(XmNlabelString, (XtArgVal )XmStringCreateLtoR(txt, XmSDCS));
#endif
		XtSetValues(hLabel, wargs, wargcount);
		wargcount = 0;
		return(TRUE);
	}
	return(FALSE);
}


#ifdef XAW
extern "C" {
#include <X11/Xaw/Paned.h>
}
#else
#include <X11/Xm/PanedW.h>
#endif

bool XmPaneArea::createControl(XmControlPane* par)
{
#ifdef XAW
	addArg(XtNborderWidth, 1);
	XtManageChild(wid = XtCreateWidget(wname, panedWidgetClass, par->handle(), wargs, wargcount));
#else
	addArg(XmNborderWidth, 1);
	XtManageChild(wid = XmCreatePanedWindow(par->handle(), wname, wargs, wargcount));
#endif
	wargcount = 0;
	parent = par->asObject();
	return(wid ? TRUE : FALSE);
}

void XmPaneArea::changed(void*)
{
}

bool XmPaneArea::add(XmControl* aControl, XmObject* rec, cbProc p, void* cd)
{
	if(XmDialogPane::add(aControl, rec, p, cd))
	{	subPaneCount++;
		return(TRUE);
	}
	return(FALSE);
}

bool XmPaneArea::remove(char* name)
{
	if(!XmDialogPane::remove(name))
	{	char namebuf[100];
		XmPane* aPane;

		strcpy(namebuf, name);
		strcat(namebuf, "Pane");
		if((aPane = (XmPane* )find(namebuf)) && aPane->controlType() == Pane)
		{	if(aPane->setContents(NULL))
			{	XmDialogPane::remove(namebuf);
				delete aPane;
				subPaneCount--;
				return(TRUE);
			}
		}
		cerr << "xmPaneArea: Error - remove " << name << " failed...\n";
		return(FALSE);
	}
	subPaneCount--;
	return(TRUE);
}

bool XmPaneArea::addSubpane(XmControl* aControl, char* title, XmObject* rec, cbProc p)
{
	int nh = aControl->ch;		// (ch * relSize) / 100;
	XmPane* aPane;

	if(aControl->controlType() == Edit)
		aControl->changeStyle(aControl->style | XmSmultiLine);	// ensure multi-line...

	if(title)
	{	char namebuf[100];
		strcpy(namebuf, aControl->getName());
		strcat(namebuf, "Pane");
		aPane = new XmPane(namebuf, 0, aControl->cy /* subPaneCount * nh */, cw, nh);
#ifdef XAW
		aPane->addArg(XtNallowResize, TRUE);
		aPane->addArg(XtNmin, 150); // ch / (subPaneCount + 1));
#else
		aPane->addArg(XmNallowResize, TRUE);
		aPane->addArg(XmNpaneMinimum, 150); // ch / (subPaneCount + 1));
#endif
		aPane->setText(title);
		if(add(aPane))
		{	aControl->changeArg(XtNwidth, (aControl->cw = cw - 30));
			aControl->changeArg(XtNheight, (aControl->ch = nh - 20));
#ifdef XAW
			// constraining should go here...
			aPane->forceArg(XtNmin, 50);
#else
			aControl->addArg(XmNleftAttachment, XmATTACH_POSITION);
			aControl->addArg(XmNleftPosition, 1);
			aControl->addArg(XmNtopAttachment, XmATTACH_WIDGET);
			aControl->addArg(XmNtopWidget, (XtArgVal )aPane->hLabel);
			aControl->addArg(XmNrightAttachment, XmATTACH_POSITION);
			aControl->addArg(XmNrightPosition, 99);
			aControl->addArg(XmNbottomAttachment, XmATTACH_POSITION);
			aControl->addArg(XmNbottomPosition, 98);
			aPane->forceArg(XmNpaneMinimum, 50);
#endif
			return(aPane->setContents(aControl, rec, p));
		}
		delete aPane;
		return(FALSE);
	}
	aControl->changeArg(XtNwidth, (aControl->cw = cw));
	aControl->changeArg(XtNheight, (aControl->ch = 150)); // ch / (subPaneCount + 1)));
#ifdef XAW
	aControl->addArg(XtNallowResize, TRUE);
	aControl->addArg(XtNmin, aControl->ch);
#else
	aControl->addArg(XmNallowResize, TRUE);
	aControl->addArg(XmNpaneMinimum, aControl->ch);
#endif
	if(add(aControl, rec, p))
#ifdef XAW
	{	aControl->addArg(XtNtop, XtChainTop);
		aControl->addArg(XtNleft, XtChainLeft);
		aControl->addArg(XtNright, XtChainRight);
		aControl->addArg(XtNbottom, XtChainBottom);
		aControl->forceArg(XtNmin, 50);
#else
	{	aControl->forceArg(XmNpaneMinimum, 50);
#endif
		return(TRUE);
	}
	return(FALSE);
}

bool XmPaneArea::changeSubpaneLabel(char* name, char* txt)
{
	char namebuf[100];
	XmPane* aPane;

	strcpy(namebuf, name);
	strcat(namebuf, "Pane");
	if(((aPane = (XmPane* )find(name)) || (aPane = (XmPane* )find(namebuf))) && aPane->controlType() == Pane)
		return(aPane->changeLabel(txt));
	cerr << "xmPaneArea: change label error - no pane " << namebuf << " found (" << hex(long(aPane)) << ")\n";
	return(FALSE);
}


#ifdef XAW
extern "C" {
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Label.h>
}
#else
#include <X11/Xm/RowColumn.h>
#include <X11/Xm/LabelG.h>
#endif

bool XmToolBar::createControl(XmControlPane* par)
{
	addArg(XtNborderWidth, 1);
#ifdef XAW
	addArg(XtNallowResize, TRUE);
	addArg(XtNorientation, (style & XmShorizontal) ? XtorientHorizontal : XtorientVertical);
	XtManageChild(wid = XtCreateManagedWidget(wname, boxWidgetClass, par->handle(), wargs, wargcount));
#else
	addArg(XmNorientation, (style & XmShorizontal) ? XmHORIZONTAL : XmVERTICAL);
	addArg(XmNadjustLast, FALSE);
	addArg(XmNadjustMargin, FALSE);
	if(rows > 1)
	{	addArg(XmNpacking, XmPACK_COLUMN);
		addArg(XmNnumColumns, rows);
	}
	addArg(XmNisAligned, FALSE);
	XtManageChild(wid = XmCreateRowColumn(par->handle(), wname, wargs, wargcount));
#endif
	wargcount = 0;
	parent = par->asObject();
	return(wid ? TRUE : FALSE);
}

bool XmToolBar::add(XmControl* c, XmObject* rec, cbProc cb, void* cd)	
{
	if(c->isAn(Edit))
		c->changeStyle(c->getStyle() | XmStabStop);
	return(XmGroupBox::add(c, rec, cb, cd));
}

bool XmStatusBar::createControl(XmControlPane* par)
{
#ifdef XAW
	return(FALSE);		// not implemented yet... (use a bottom toolbar instead!)
#else
	addArg(XmNunitType, App->getScreenUnitType());
	addArg(XmNautoUnmanage, FALSE);
	addArg(XmNshadowThickness, 1);
	addArg(XmNhorizontalSpacing, 2);
	addArg(XmNverticalSpacing, 2);
	XtManageChild(wid = XmCreateForm(par->handle(), wname, wargs, wargcount));
	wargcount = 0;
	statusLine = new XmEdit("statusDisplay");
	statusLine->addArg(XmNleftAttachment, XmATTACH_FORM);
	statusLine->addArg(XmNrightAttachment, XmATTACH_FORM);
	statusLine->addArg(XmNtopAttachment, XmATTACH_FORM);
	statusLine->addArg(XmNtopOffset, 10);
	statusLine->addArg(XmNbottomAttachment, XmATTACH_FORM);
	statusLine->addArg(XmNbottomOffset, 10);
	XmGroupBox::add(statusLine);
	statusLine->disable();
	return(wid ? TRUE : FALSE);
#endif
}

bool XmStatusBar::add(XmControl* aControl, XmObject* anObj, cbProc aProc, void* cl_data)
{
	XmControl* lastControl = controls[controlCount - 1];

#ifdef XAW
	;
#else
	aControl->addArg(XmNrightAttachment, XmATTACH_FORM);
	if(aControl->isAn(Edit))
		aControl->changeStyle(aControl->getStyle() | XmStabStop);
	if(XmGroupBox::add(aControl, anObj, aProc, cl_data))
	{	lastControl->addArg(XmNrightAttachment, XmATTACH_WIDGET);
		lastControl->addArg(XmNrightWidget, (XtArgVal )aControl->handle());
		lastControl->forceArg(NULL, (XtArgVal )NULL);
		return(TRUE);
	}
#endif
	return(FALSE);
}

bool XmStatusBar::remove(char* aName)
{
	XmControl* prevControl, * aControl = find(aName);
	int ndx = controlIndex(aControl);

#ifdef XAW
	;
#else
	if(!aControl)
		return(FALSE);
	prevControl = controls[ndx - 1];
	if(XmGroupBox::remove(aName))
	{	if(ndx < controlCount)
			prevControl->addArg(XmNrightWidget, (XtArgVal )controls[ndx]->handle());
		else
			prevControl->addArg(XmNrightAttachment, XmATTACH_FORM);
		prevControl->forceArg(NULL, (XtArgVal )NULL);
		return(TRUE);
	}
#endif
	return(FALSE);
}

bool XmStatusBar::setMessage(char* msg)
{
	return(statusLine ? (statusLine->setText(msg) ? TRUE : FALSE) : FALSE);
}


#ifdef XAW
extern "C" {
#include <X11/Xaw/Label.h>
}
#else
#include <X11/Xm/LabelG.h>
#endif

bool XmStaticText::createControl(XmControlPane* par)
{
#ifdef XAW
	addArg(XtNborderWidth, 0);
	addArg(XtNjustify, (style & XmScenter ? XtJustifyCenter : (style & XmSright ? XtJustifyRight : XtJustifyLeft)));
	XtManageChild(wid = XtCreateWidget(wname, labelWidgetClass, par->handle(), wargs, wargcount));
#else
	addArg(XmNalignment, (style & XmScenter ? XmALIGNMENT_CENTER : (style & XmSright ? XmALIGNMENT_END : XmALIGNMENT_BEGINNING)));
	XtManageChild(wid = XmCreateLabelGadget(par->handle(), wname, wargs, wargcount));
#endif
	wargcount = 0;
	parent = par->asObject();
	return(wid ? TRUE : FALSE);
}

bool XmStaticImage::createControl(XmControlPane* par)
{
#ifdef XAW
	if(!hasArg(XtNbitmap))
#else
	if(!hasArg(XmNlabelPixmap))
#endif
#ifndef SUN
		setImage(getCompiledImage(default_bitmap));
#else
		setImage(getCompiledImage(default_bitmap_bits, default_bitmap_width, default_bitmap_height));
#endif
#ifdef XAW
	addArg(XtNborderWidth, 0);
	XtManageChild(wid = XtCreateWidget(wname, labelWidgetClass, par->handle(), wargs, wargcount));
#else
	XtManageChild(wid = XmCreateLabelGadget(par->handle(), wname, wargs, wargcount));
#endif
	wargcount = 0;
	parent = par->asObject();
	return(wid ? TRUE : FALSE);
}

#ifdef XAW
extern "C" {
#include <X11/Xaw/Command.h>
}
#else
#include <X11/Xm/PushBG.h>
#endif

bool XmPushButton::createControl(XmControlPane* par)
{
	parent = par->asObject();
	setLabelAndMnemonic();
#ifdef XAW
	if(!hasArg(XtNbitmap))
		addArg(XtNjustify, (style & XmScenter ? XtJustifyCenter : (style & XmSright ? XtJustifyRight : XtJustifyLeft)));
	XtManageChild(wid = XtCreateWidget(wname, commandWidgetClass, par->handle(), wargs, wargcount));
#else
	if(!hasArg(XmNlabelPixmap))
		addArg(XmNalignment, (style & XmSleft ? XmALIGNMENT_BEGINNING : (style & XmSright ? XmALIGNMENT_END : XmALIGNMENT_CENTER)));
	XtManageChild(wid = XmCreatePushButtonGadget(par->handle(), wname, wargs, wargcount));
	initTabstop();
#endif
	wargcount = 0;
	return(wid ? TRUE : FALSE);
}

#ifdef XAW
extern "C" {
#include <X11/Xaw/Toggle.h>
}
#else
#include <X11/Xm/ToggleBG.h>
#endif

bool XmCheckBox::createControl(XmControlPane* par)
{
	parent = par->asObject();
	setLabelAndMnemonic();
#ifdef XAW
	if(!hasArg(XtNbitmap))
		addArg(XtNjustify, (style & XmScenter ? XtJustifyCenter : (style & XmSright ? XtJustifyRight : XtJustifyLeft)));
	XtManageChild(wid = XtCreateWidget(wname, toggleWidgetClass, par->handle(), wargs, wargcount));
#else
	if(!hasArg(XmNlabelPixmap))
		addArg(XmNalignment, (style & XmScenter ? XmALIGNMENT_CENTER : (style & XmSright ? XmALIGNMENT_END : XmALIGNMENT_BEGINNING)));
	XtManageChild(wid = XmCreateToggleButtonGadget(par->handle(), wname, wargs, wargcount));
	initTabstop();
#endif
	wargcount = 0;
	return(wid ? TRUE : FALSE);
}

bool XmCheckBox::setState(bool newState)
{
	bool oldState = getState();

	if(oldState != newState)
#ifdef XAW
	{	addArg(XtNstate, newState);
#else
	{	addArg(XmNset, newState);
#endif
		if(wid)
		{	XtSetValues(wid, wargs, wargcount);
			wargcount = 0;
		}
	}
	return(oldState);
}

bool XmCheckBox::getState()
{
	if(wid)
	{	Arg a;
		int state = 0;
#ifdef XAW
		XtSetArg(a, XtNstate, &state);
#else
		XtSetArg(a, XmNset, &state);
#endif
		XtGetValues(wid, &a, 1);
		return(state ? TRUE : FALSE);
	}
	return(FALSE);
}

bool XmRadioButton::createControl(XmControlPane* par)
{
	parent = par->asObject();
	setLabelAndMnemonic();
#ifdef XAW
	if(!hasArg(XtNbitmap))
		addArg(XtNjustify, (style & XmScenter ? XtJustifyCenter : (style & XmSright ? XtJustifyRight : XtJustifyLeft)));
	XtManageChild(wid = XtCreateWidget(wname, toggleWidgetClass, par->handle(), wargs, wargcount));
#else
	if(!hasArg(XmNlabelPixmap))
		addArg(XmNalignment, (style & XmScenter ? XmALIGNMENT_CENTER : (style & XmSright ? XmALIGNMENT_END : XmALIGNMENT_BEGINNING)));
	addArg(XmNindicatorType, XmONE_OF_MANY);
	XtManageChild(wid = XmCreateToggleButtonGadget(par->handle(), wname, wargs, wargcount));
	initTabstop();
#endif
	wargcount = 0;
	initTabstop();
#ifdef XAW
	setCallback(XtNcallback, this, (cbProc )&XmRadioButton::selected, TRUE, NULL);
#else
	setCallback(XmNvalueChangedCallback, this, (cbProc )&XmRadioButton::selected, TRUE, NULL);
#endif
	return(wid ? TRUE : FALSE);
}

void XmRadioButton::selected(void* cd)
{
	bool curState = getState();

	if(curState)
	{	if(next)
			next->reset(TRUE);
		if(prev)
			prev->reset(FALSE);
		if(userData.receiver && validProc(userData.callback))
			genericCallback(wid, (XtPointer )&userData, (XtPointer )cd);
	}
	else
		setState(TRUE);
}

void XmRadioButton::reset(bool direction)
{
	if(getState())
		setState(FALSE);
	if(direction)
	{	if(next)
			next->reset(direction);
	}
	else
	{	if(prev)
			prev->reset(direction);
	}
}

bool XmRadioButton::setState(bool newState)
{
	if(newState && !getState())
	{	if(next)
			next->reset(TRUE);
		if(prev)
			prev->reset(FALSE);
	}
	return(XmCheckBox::setState(newState));
}

#ifdef XAW
extern "C" {
#include <X11/Xaw/AsciiText.h>
}
#define EH 25
#else
#include <X11/Xm/Text.h>
#define EH 34
#endif


XmEdit::~XmEdit()
{
	delete pasteBuffer;
	delete lastVersion;
}

static char MULTI_LINE_TRANSLATIONS[] =
    "Shift<Key>Tab:    next-tab-group() \n\
     <Key>Return:   newline()";

bool XmEdit::createControl(XmControlPane* par)
{
    XtTranslations ttbl;

	multiLine = (style & XmSmultiLine ? TRUE : FALSE);
	hScroll = (style & XmSautohscroll ? TRUE : FALSE);
	vScroll = (style & XmSautovscroll ? TRUE : FALSE);

	setText("");
#ifndef XAW
	if(multiLine)
		addArg(XmNeditMode, XmMULTI_LINE_EDIT);
	if(style & XmSautoCursor)
		addArg(XmNautoShowCursorPosition, TRUE);
	if(ch < EH)
		changeArg(XtNheight, (ch = EH));
#endif
#ifdef XAW
	addArg(XtNeditType, XawtextEdit);
	addArg(XtNstring, (XtArgVal )"");
	addArg(XtNscrollHorizontal, (multiLine && hScroll) ? XawtextScrollWhenNeeded : XawtextScrollNever);
	addArg(XtNscrollVertical, (multiLine && vScroll) ? XawtextScrollWhenNeeded : XawtextScrollNever);
	XtManageChild(wid = XtCreateWidget(wname, asciiTextWidgetClass, par->handle(), wargs, wargcount));
#else
	if(multiLine && (hScroll || vScroll))
	{	addArg(XmNscrollHorizontal, hScroll);
		addArg(XmNscrollVertical, vScroll);
		XtManageChild(wid = XmCreateScrolledText(par->handle(), wname, wargs, wargcount));
	}
	else
		XtManageChild(wid = XmCreateText(par->handle(), wname, wargs, wargcount));
#endif
	if(wid && multiLine)
	{	ttbl = XtParseTranslationTable(MULTI_LINE_TRANSLATIONS);
    	XtOverrideTranslations(wid, ttbl);
	}
	wargcount = 0;
	initTabstop(multiLine);
#ifdef XAW
//	setCallback(XtNcallback, this, (cbProc )&XmEdit::changed, TRUE);
#else
	setCallback(XmNfocusCallback, this, (cbProc )&XmEdit::changed, TRUE, (void* )111L);
	setCallback(XmNlosingFocusCallback, this, (cbProc )&XmEdit::changed, TRUE, (void* )222L);
#endif
	parent = par->asObject();
	return(wid ? TRUE : FALSE);
}

bool XmEdit::resize(int nw, int nh)
{
#ifdef XAW
	return(XmControl::resize(nw, nh));
#else
	if(XmControl::resize(nw, nh) && (hScroll || vScroll))
	{	addArg(XmNrightAttachment, XmATTACH_SELF);
		addArg(XmNrightOffset, nw);
		addArg(XmNbottomAttachment, XmATTACH_SELF);
		addArg(XmNbottomOffset, nh);
		if(wid)
		{	XtSetValues(XtParent(wid), wargs, wargcount);
			XtSetValues(wid, wargs, wargcount);
			wargcount = 0;
		}
	}
	return(TRUE);
#endif
}

bool XmEdit::reframe(int nx, int ny, int nw, int nh)
{
#ifdef XAW
	return(XmControl::reframe(nx, ny, nw, nh));
#else
	if(XmControl::reframe(nx, ny, nw, nh) && (hScroll || vScroll))
	{	addArg(XmNleftAttachment, XmATTACH_FORM);
		addArg(XmNleftOffset, nx);
		addArg(XmNtopAttachment, XmATTACH_FORM);
		addArg(XmNtopOffset, ny);
		addArg(XmNrightAttachment, XmATTACH_SELF);
		addArg(XmNrightOffset, nw);
		addArg(XmNbottomAttachment, XmATTACH_SELF);
		addArg(XmNbottomOffset, nh);
		if(wid)
		{	XtSetValues(XtParent(wid), wargs, wargcount);
			XtSetValues(wid, wargs, wargcount);
			wargcount = 0;
		}
	}
	return(TRUE);
#endif
}

void XmEdit::changed(void* begEnd)
{
	if(begEnd == (void* )111L)
	{	char* cur = getText();
		lastVersion = strcpy(new char[strlen(cur) + 1], cur);
	}
	else
	{	if((!lastVersion || strcmp(lastVersion, getText())) && userData.receiver && validProc(userData.callback))
			genericCallback(wid, (XtPointer )&userData, (XtPointer )NULL);
		delete lastVersion;
		lastVersion = NULL;
	}
}

XmControl* XmEdit::setText(char* txt)
{
#ifdef XAW
	addArg(XtNstring, (XtArgVal )txt);
	if(wid)
	{	XtSetValues(wid, wargs, wargcount);
		wargcount = 0;
	}
#else
	if(wid)
	{	XmTextSetString(wid, txt);
		if(lastVersion)
		{	delete lastVersion;
			lastVersion = strcpy(new char[strlen(txt) + 1], txt);
		}
	}
	else
		addArg(XmNvalue, (XtArgVal )txt);
#endif
	return(this);
}

char* lastEditGetBuffer = NULL;

char* XmEdit::getText()
{
	if(!wid)
		return((char* )NULL);
#ifdef XAW
	Arg a;
	XtSetArg(a, XtNstring, (XtArgVal )&lastEditGetBuffer);
	XtGetValues(wid, &a, 1);
	return(lastEditGetBuffer);
#else
	XtFree(lastEditGetBuffer);
	return(lastEditGetBuffer = XmTextGetString(wid));
#endif
}

long XmEdit::getInsertPosition(int* x, int* y)
{
	long p;
	Position px, py;

	if(!wid)
		return(0);
#ifdef XAW
	return(0);
#else
	p = XmTextGetInsertionPosition(wid);
	if(x || y)
	{	XmTextPosToXY(wid, p, &px, &py);
		if(x)
			*x = px;
		if(y)
			*y = py;
	}
	return(p);
#endif
}

char* XmEdit::getSelection()
{
	return(NULL);
}

bool XmEdit::setSelection(int, int)
{
	return(FALSE);
}

bool XmEdit::clearSelection()
{
	return(FALSE);
}

bool XmEdit::cut()
{
#ifdef XAW
	return(FALSE);
#else
	return(XmTextCut(wid, CurrentTime) ? TRUE : FALSE);
#endif
}

bool XmEdit::copy()
{
#ifdef XAW
	return(FALSE);
#else
	return(XmTextCopy(wid, CurrentTime) ? TRUE : FALSE);
#endif
}

bool XmEdit::paste()
{
#ifdef XAW
	return(FALSE);
#else
	return(XmTextPaste(wid) ? TRUE : FALSE);
#endif
}


#ifdef XAW
extern "C" {
#include <X11/Xaw/List.h>
#include <X11/Xaw/Viewport.h>
}
#else
#include <X11/Xm/List.h>
#endif

bool XmListBox::createControl(XmControlPane* par)
{
#ifdef XAW
	Widget vp;
	ostrstream vpname;
	vpname << wname << "-viewport"; vpname.put('\0');
	addArg(XtNallowHoriz, TRUE);
	addArg(XtNallowVert, TRUE);
	XtManageChild(vp = XtCreateWidget(vpname.str(), viewportWidgetClass, par->handle(), wargs, wargcount));
	wargcount = 0;
	char** cont = new char*[1];
	cont[0] = NULL;
	addArg(XtNdefaultColumns, 1);
	addArg(XtNforceColumns, TRUE);
	addArg(XtNlist, (XtArgVal )cont);
	addArg(XtNnumberStrings, 0);
	XtManageChild(wid = XtCreateWidget(wname, listWidgetClass, vp, wargs, wargcount));
#else
	addArg(XmNselectionPolicy, (multiSel ? XmEXTENDED_SELECT : XmBROWSE_SELECT));
	addArg(XmNvisualPolicy, XmCONSTANT);
	XtManageChild(wid = XmCreateScrolledList(par->handle(), wname, wargs, wargcount));
	initTabstop();
#endif
	wargcount = 0;
	parent = par->asObject();
	return(wid ? TRUE : FALSE);
}

void XmListBox::cleanup()
{
#ifdef XAW
	Arg a[2];
	int numStrings = 0, count = 0;
	char** cur;
	XtSetArg(a[0], XtNlist, (XtArgVal )&cur);
	XtSetArg(a[1], XtNnumberStrings, (XtArgVal )&numStrings);
	XtGetValues(wid, a, 2);

	for(int i = 0; i < numStrings; i++)
		delete cur[i];
	delete cur;
#endif
}

bool XmListBox::resize(int nw, int nh)
{
#ifdef XAW
	Widget l = wid;
	wid = XtParent(l);
	XmControl::resize(nw, nh);
	wid = l;
#else
	XmControl::resize(nw, nh);
	addArg(XmNrightAttachment, XmATTACH_SELF);
	addArg(XmNrightOffset, nw);
	addArg(XmNbottomAttachment, XmATTACH_SELF);
	addArg(XmNbottomOffset, nh);
	if(wid)
	{	XtSetValues(XtParent(wid), wargs, wargcount);
		XtSetValues(wid, wargs, wargcount);
		wargcount = 0;
	}
#endif
	return(TRUE);
}

bool XmListBox::reframe(int nx, int ny, int nw, int nh)		// a 'russian' solution...
{
#ifdef XAW
	Widget l = wid;
	wid = XtParent(l);
	XmControl::reframe(nx, ny, nw, nh);
	wid = l;
#else
	XmControl::reframe(nx, ny, nw, nh);
	addArg(XmNleftAttachment, XmATTACH_FORM);
	addArg(XmNleftOffset, nx);
	addArg(XmNtopAttachment, XmATTACH_FORM);
	addArg(XmNtopOffset, ny);
	addArg(XmNrightAttachment, XmATTACH_SELF);
	addArg(XmNrightOffset, nw);
	addArg(XmNbottomAttachment, XmATTACH_SELF);
	addArg(XmNbottomOffset, nh);
	if(wid)
	{	XtSetValues(XtParent(wid), wargs, wargcount);
		XtSetValues(wid, wargs, wargcount);
		wargcount = 0;
	}
#endif
	return(TRUE);
}

bool XmListBox::change(char*, char*)
{
	return(FALSE);		// should be implemented...!
}

bool XmListBox::change(int, char*)
{
	return(FALSE);		// should be implemented...!
}

XmListBox* XmListBox::addAll(char** list)
{
	if(!wid)
		return(this);
#ifdef XAW
	return(insertAll(-1, list));
#else
	while(*list)
		XmListAddItemUnselected(wid, XmStringCreateLtoR(*list++, XmSDCS), 0);
	return(this);
#endif
}

XmListBox* XmListBox::addAll(char* first,...)
{
	if(!wid)
		return(this);
#ifndef NO_VARARGS
	va_list ap;
	char* anItem = first;

	va_start(ap, first);
	while(anItem)
#ifdef XAW
	{	char* list[2];
		list[0] = anItem;
		list[1] = NULL;
		insertAll(-1, list);
#else
	{	XmListAddItemUnselected(wid, XmStringCreateLtoR(anItem, XmSDCS), 0);
#endif
		anItem = va_arg(ap, char*);
	}
	va_end(ap);
#else
	XmListAddItemUnselected(wid, XmStringCreateLtoR(first, XmSDCS), 0);
#endif
	return(this);
}

char* tmpListBuf[500];

XmListBox* XmListBox::insertAll(int start, char** list)
{
	if(!wid)
		return(this);
#ifdef XAW
	Arg a[2];
	int i, numStrings = 0, ndx = 0;
	char** cur;
	XtSetArg(a[0], XtNnumberStrings, (XtArgVal )&numStrings);
	XtSetArg(a[1], XtNlist, (XtArgVal )&cur);
	XtGetValues(wid, a, 2);

	if(start < 1 || start > numStrings)
		start = -1;

	if(start == -1)
	{	for(i = 0; i < numStrings; i++)
			tmpListBuf[ndx++] = cur[i];
	}
	else
	{	for(i = 0; i < numStrings && i < start - 1; i++)
			tmpListBuf[ndx++] = cur[i];
	}
	while(*list)
	{	tmpListBuf[ndx++] = strcpy((new char[strlen(*list) + 1]), *list);
		list++;
	}
	if(start != -1)
	{	for(i = start - 1; i < numStrings; i++)
			tmpListBuf[ndx++] = cur[i];
	}
	delete cur;
	cur = new char*[ndx];
	for(i = 0; i < ndx; i++)
		cur[i] = tmpListBuf[i];
	XawListChange(wid, cur, ndx, 0, FALSE);
#else
	while(*list)
		XmListAddItemUnselected(wid, XmStringCreateLtoR(*list++, XmSDCS), start++);
#endif
	return(this);
}

XmListBox* XmListBox::insertAll(int start, char* first,...)
{
	if(!wid)
		return(this);

	va_list ap;
	char* anItem = first;

	va_start(ap, first);
	while(anItem)
#ifdef XAW
	{	char* list[2];
		list[0] = anItem;
		list[1] = NULL;
		insertAll(start++, list);
#else
	{	XmListAddItemUnselected(wid, XmStringCreateLtoR(anItem, XmSDCS), start++);
#endif
		anItem = va_arg(ap, char*);
	}
	va_end(ap);
	return(this);
}

bool XmListBox::removeAll(char** list)
{
	XmString aStr;

	if(!wid)
		return(FALSE);
#ifdef XAW
	Arg a[2];
	int numStrings = 0, ndx = 0;
	char** cur;
	XtSetArg(a[0], XtNnumberStrings, (XtArgVal )&numStrings);
	XtSetArg(a[1], XtNlist, (XtArgVal )&cur);
	XtGetValues(wid, a, 2);
	bool rc = FALSE;
	if(numStrings)
	{	int* rm = new int[numStrings];
		for(int i = 0; i < numStrings; i++)
		{	int j = 0;
			while(list[j++])
			{	if(!strcmp(cur[i], list[j - 1]))
					rm[ndx++] = i + 1;
			}
		}
		if(ndx)
		{	rm[ndx] = 0;
			rc = removeAll(rm);
		}
		delete rm;
	}
	return(rc);
#else
	while(*list)
	{	XmListDeleteItem(wid, (aStr = XmStringCreateLtoR(*list++, XmSDCS)));
		XmStringFree(aStr);
	}
	return(TRUE);
#endif
}

bool XmListBox::removeAll(char* first,...)
{
	XmString aStr;

	if(!wid)
		return(FALSE);

	va_list ap;
	char* anItem = first;
	va_start(ap, first);
	while(anItem)
#ifdef XAW
	{	char* list[2];
		list[0] = anItem;
		list[1] = NULL;
		removeAll(list);
#else
	{	XmListDeleteItem(wid, (aStr = XmStringCreateLtoR(anItem, XmSDCS)));
		XmStringFree(aStr);
#endif
		anItem = va_arg(ap, char*);
	}
	va_end(ap);
	return(TRUE);
}

bool XmListBox::removeAll(int* list)
{
	if(!wid)
		return(FALSE);
#ifdef XAW
	Arg a[2];
	int i, numStrings = 0, ndx = 0, count = 0;
	char** cur, ** nwp;
	XtSetArg(a[0], XtNnumberStrings, &numStrings);
	XtSetArg(a[1], XtNlist, (XtArgVal )&cur);
	XtGetValues(wid, a, 2);

	for(i = 0; i < numStrings; i++)
	{	if(*list && i == ((*list) - 1))
		{	delete cur[i];
			cur[i] = NULL;
			list++;
			count++;
		}
	}
	if(numStrings - count > 0)
	{	nwp = new char*[numStrings - count];
		for(i = 0; i < numStrings; i++)
		{	if(cur[i])
				nwp[ndx++] = cur[i];
		}
	}
	else
	{	nwp = new char*[1];
		nwp[0] = NULL;
	}
	delete cur;
	XawListChange(wid, nwp, ndx, 0, FALSE);
#else
	while(*list)
		XmListDeletePos(wid, *list++);
#endif
	return(TRUE);
}

bool XmListBox::removeAll(int first,...)
{
	if(!wid)
		return(FALSE);

	va_list ap;
	int anIndex = first;

	va_start(ap, first);
	while(anIndex)
#ifdef XAW
	{	int all[2];
		all[0] = anIndex;
		all[1] = 0;
		removeAll(all);
#else
	{	XmListDeletePos(wid, anIndex);
#endif
		anIndex = va_arg(ap, int);
	}
	va_end(ap);
	return(TRUE);
}

bool XmListBox::clear()
{
	if(!wid)
		return(FALSE);
#ifdef XAW
	Arg a;
	char** cur;
	XtSetArg(a, XtNlist, (XtArgVal )&cur);
	XtGetValues(wid, &a, 1);
	delete cur;
	cur = new char*[1];
	cur[0] = NULL;
	XawListChange(wid, cur, -1, -1, FALSE);
#else
	XmListDeleteAllItems(wid);
#endif
	return(TRUE);
}	

bool XmListBox::selectText(char* anItem, bool notify)
{
	if(!wid)
		return(FALSE);
#ifdef XAW
	Arg a[2];
	int numStrings = 0;
	char** cur;
	XtSetArg(a[0], XtNnumberStrings, (XtArgVal )&numStrings);
	XtSetArg(a[1], XtNlist, (XtArgVal )&cur);
	XtGetValues(wid, a, 2);
	bool rc = FALSE;
	if(numStrings)
	{	for(int i = 0; i < numStrings; i++)
		{	if(!strcmp(cur[i], anItem))
				rc = selectIndex(i + 1, notify);
		}
	}
	return(rc);
#else
	XmListSelectItem(wid, XmStringCreateLtoR(anItem, XmSDCS), notify);
	return(TRUE);
#endif
}

bool XmListBox::selectIndex(int anIndex, bool notify)
{
	if(!wid)
		return(FALSE);
#ifdef XAW
	XawListHighlight(wid, anIndex);
#else
	XmListSelectPos(wid, anIndex, notify);
#endif
	return(TRUE);
}

bool XmListBox::deselectText(char* anItem)
{
	XmString aStr;

	if(!wid)
		return(FALSE);
#ifdef XAW
	XawListUnhighlight(wid);	// only single selection list...
#else
	XmListDeselectItem(wid, (aStr = XmStringCreateLtoR(anItem, XmSDCS)));
	XmStringFree(aStr);
#endif
	return(TRUE);
}

bool XmListBox::deselectIndex(int anIndex)
{
	if(!wid)
		return(FALSE);
#ifdef XAW
	XawListUnhighlight(wid);	// only single selection list...
#else
	XmListDeselectPos(wid, anIndex);
#endif
	return(TRUE);
}

bool XmListBox::deselectAll()
{
	if(!wid)
		return(FALSE);
#ifdef XAW
	XawListUnhighlight(wid);
#else
	XmListDeselectAllItems(wid);
#endif
	return(TRUE);
}

bool XmListBox::setDoubleClickProc(XmObject* rec, cbProc proc)
{
#ifdef XAW
	cerr << "xmListBox: sorry, double click not implemented.\n";
	return(FALSE);
#else
	return(setCallback(XmNdefaultActionCallback, rec, proc, TRUE, NULL));
#endif
}

int XmListBox::selectedCount()
{
	if(!wid)
		return(0);
#ifdef XAW
	return(*selectedIndices() ? 1 : 0);
#else
	getArg(XmNselectedItemCount);
	XtGetValues(wid, wargs, wargcount);
	wargcount = 0;
	return((int )wargs[0].value);
#endif
}

char** XmListBox::selectedItems()
{
	char** items;
	int count = 0;

	if(!wid)
		return(NULL);

#ifdef XAW
	XawListReturnStruct* rs = XawListShowCurrent(wid);
	if(rs->list_index != XAW_LIST_NONE)
	{	items = new char*[2];
		items[0] = rs->string;
		count = 1;
	}
#else // XAW
	XmStringTable itemStrings;
#ifndef __GNUG__
	getArg(XmNselectedItems);
	getArg(XmNselectedItemCount);
	XtGetValues(wid, wargs, wargcount);
	wargcount = 0;
	itemStrings = (XmStringTable )wargs[0].value;
	count = (int )wargs[1].value;
#else // __GNUG__
	Arg a[2];
	a[0].name = XmNselectedItems;
	a[0].value = (XtArgVal )&itemStrings;
	a[1].name = XmNselectedItemCount;
	a[1].value = (XtArgVal )&count;
	XtGetValues(wid, a, 2);
#endif // __GNUG__
	items = new char*[count + 1];
	for(int i = 0; i < count; i++)
	{	items[i] = new char[XmStringLength(itemStrings[i]) + 1];
		if(!XmStringGetLtoR(itemStrings[i], XmSDCS, &items[i]))
			cerr << "xmListBox: Error - cannot get string contents...\n";
	}
#endif // XAW
	items[count] = NULL;
	return(items);
}

extern "C" { void free(void*); }

int* XmListBox::selectedIndices()
{
	int posCount = 0, * posArray, * anArray, ndx;
#ifdef XAW
	if(wid)
	{	XawListReturnStruct* rs = XawListShowCurrent(wid);
		if(rs->list_index != XAW_LIST_NONE)
		{	anArray = new int[2];
			anArray[0] = rs->list_index + 1;
			posCount = 1;
		}
#else
	if(wid && XmListGetSelectedPos(wid, &posArray, &posCount))
	{	anArray = new int[posCount + 1];
		for(ndx = 0; ndx < posCount; ndx++)
			anArray[ndx] = posArray[ndx];
		free(posArray);
#endif
	}
	else
		anArray = new int[1];
	anArray[posCount] = 0;		// was -1 (nonsens...!)
	return(anArray);
}


#ifdef XAW
#define CAW 25
#define CAH 25
#define CAS 2
#else
#define CAW 32
#define CAH 32
#define CAS 2
#endif

#ifdef AIX
#undef CB
typedef void (XmComboBox::*comboProc)(void*);
inline cbProc makeCbProc(comboProc p)
{ cbProc px; memcpy(&px, &p, sizeof(cbProc)); return(px); }
#define CB(x) makeCbProc(&x)
#endif


XmComboBox::XmComboBox(char* name, int x, int y, int w, int h, xmStyle s) :
	XmGroupBox(name, x, y, w, (s & XmSsimple) ? h : CAH, s),
	XmPushButton(name, x + w - CAW, y, CAW, CAH),
	XmEdit(name, x, y, w - CAW - CAS, CAH),
	XmListBox(name, x + CAW, y + CAH, w - CAW, h - CAH)
{
	popup = NULL;
	cbStyle = ((s & XmSdropdownlist) ? DROPDOWNLIST : ((s & XmSsimple) ? SIMPLE : DROPDOWN));
	lbMapped = FALSE;
}

XmComboBox::~XmComboBox()
{
	if(popup)
		XtDestroyWidget(popup);
}

#ifndef XAW
#include <X11/Xm/ArrowBG.h>
#include <X11/Xm/MenuShell.h>
#endif

bool XmComboBox::createControl(XmControlPane* par)
{
	XmGroupBox::createControl(par);		// XmGroupBox:: seems to br the gnu default pointer....

	if(cbStyle == DROPDOWNLIST)
#ifndef __GNUG__
#ifdef XAW
		XmEdit::addArg(XtNsensitive, FALSE);
#else // XAW
		XmEdit::addArg(XmNeditable, FALSE);
#endif // XAW
#else // __GNUG__
#ifdef XAW
		((XmEdit* )this)->addArg(XtNsensitive, FALSE);
#else // XAW
		((XmEdit* )this)->addArg(XmNeditable, FALSE);
#endif // XAW
#endif // __GNUG__
	XmEdit::reframe(0, 0, XmGroupBox::cw - CAW - (cbStyle == DROPDOWN ? CAS : 0), CAH);
	XmEdit::createControl((XmGroupBox* )this);
#ifndef XAW
	XmEdit::setCallback((XmGroupBox* )this, CB(XmComboBox::changeText), TRUE, NULL);
#endif
#ifndef __GNUG__
#ifdef XAW
	XmPushButton::addArg(XtNlabel, (XtArgVal )"V");
	XmPushButton::move(((XmGroupBox* )this)->cw - CAW, 0);
	XmPushButton::addArg(XtNleft, XtChainLeft);
	XmPushButton::addArg(XtNright, XtChainLeft);
	XmPushButton::addArg(XtNtop, XtChainTop);
	XmPushButton::addArg(XtNbottom, XtChainTop);
	XmPushButton::addArg(XtNhorizDistance, XmPushButton::cx);
	XmPushButton::addArg(XtNvertDistance, XmPushButton::cy);
	XtManageChild(XmPushButton::wid = XtCreateWidget(XmPushButton::wname, commandWidgetClass, XmGroupBox::wid, XmPushButton::wargs, XmPushButton::wargcount));
#else // XAW
	XmPushButton::addArg(XmNarrowDirection, XmARROW_DOWN);
	XmPushButton::move(((XmGroupBox* )this)->cw - CAW, 0);
	XtManageChild(XmPushButton::wid = XmCreateArrowButtonGadget(XmGroupBox::wid, XmPushButton::wname, XmPushButton::wargs, XmPushButton::wargcount));
#endif // XAW
	XmPushButton::wargcount = 0;
	XmPushButton::parent = (XmGroupBox* )this;
#else // __GNUG__
#ifdef XAW
	((XmPushButton* )this)->addArg(XtNlabel, (XtArgVal )"V");
	((XmPushButton* )this)->move(((XmGroupBox* )this)->cw - CAW, 0);
	((XmPushButton* )this)->addArg(XtNleft, XtChainLeft);
	((XmPushButton* )this)->addArg(XtNright, XtChainLeft);
	((XmPushButton* )this)->addArg(XtNtop, XtChainTop);
	((XmPushButton* )this)->addArg(XtNbottom, XtChainTop);
	((XmPushButton* )this)->addArg(XtNhorizDistance, ((XmPushButton* )this)->cx);
	((XmPushButton* )this)->addArg(XtNvertDistance, ((XmPushButton* )this)->cy);
	XtManageChild(((XmPushButton* )this)->wid = XtCreateWidget(((XmPushButton* )this)->wname, commandWidgetClass, XmGroupBox::wid, ((XmPushButton* )this)->wargs, ((XmPushButton* )this)->wargcount));
#else // XAW
	((XmPushButton* )this)->addArg(XmNarrowDirection, XmARROW_DOWN);
	((XmPushButton* )this)->move(((XmGroupBox* )this)->cw - CAW, 0);
	XtManageChild(((XmPushButton* )this)->wid = XmCreateArrowButtonGadget(XmGroupBox::wid, ((XmPushButton* )this)->wname, ((XmPushButton* )this)->wargs, ((XmPushButton* )this)->wargcount));
#endif // XAW
	((XmPushButton* )this)->wargcount = 0;
	((XmPushButton* )this)->parent = (XmGroupBox* )this;
#endif // __GNUG__

#ifndef __GNUG__
#ifdef XAW
//	XmPushButton::setCallback(XtNcallback, (XmGroupBox* )this, CB(XmComboBox::selectArrow), TRUE, NULL);
	XmGroupBox::setCallback(XmPushButton::wid, XtNcallback, (XmGroupBox* )this, CB(XmComboBox::selectArrow), TRUE, NULL);
#else // XAW
	XmPushButton::setCallback(XmNactivateCallback, (XmGroupBox* )this, CB(XmComboBox::selectArrow), TRUE, NULL);
#endif // XAW
#else // __GNUG__
#ifdef XAW
	((XmPushButton* )this)->setCallback(XtNcallback, (XmGroupBox* )this, CB(XmComboBox::selectArrow), TRUE, NULL);
#else // XAW
	((XmPushButton* )this)->setCallback(XmNactivateCallback, (XmGroupBox* )this, CB(XmComboBox::selectArrow), TRUE, NULL);
#endif // XAW
#endif // __GNUG__

	XmListBox::makeRelativeTo((XmGroupBox* )this);
	if(cbStyle == SIMPLE)
	{	XtSetMappedWhenManaged(XmPushButton::wid, FALSE);
		XmListBox::createControl((XmGroupBox* )this);
	}
	else
	{	popup = XtCreateWidget(XmListBox::wname, overrideShellWidgetClass, XmGroupBox::wid, XmListBox::wargs, XmListBox::wargcount);
		XmListBox::changeArg(XtNx, (XtArgVal )0);
		XmListBox::changeArg(XtNy, (XtArgVal )0);
#ifndef XAW
		XmListBox::addArg(XmNselectionPolicy, (multiSel ? XmEXTENDED_SELECT : XmBROWSE_SELECT));
#endif
#ifndef __GNUG__
#ifdef XAW
		Widget vp;
		ostrstream vpname;
		vpname << XmListBox::wname << "-viewport"; vpname.put('\0');
		XmListBox::addArg(XtNallowHoriz, TRUE);
		XmListBox::addArg(XtNallowVert, TRUE);
		XtManageChild(vp = XtCreateWidget(vpname.str(), viewportWidgetClass, popup, XmListBox::wargs, XmListBox::wargcount));
		XmListBox::wargcount = 0;
		char** cont = new char*[1];
		cont[0] = NULL;
		XmListBox::addArg(XtNdefaultColumns, 1);
		XmListBox::addArg(XtNforceColumns, TRUE);
		XmListBox::addArg(XtNlist, (XtArgVal )cont);
		XtManageChild(XmListBox::wid = XtCreateWidget(XmListBox::wname, listWidgetClass, vp, XmListBox::wargs, XmListBox::wargcount));
#else // XAW
		XtManageChild(XmListBox::wid = XmCreateScrolledList(popup, XmListBox::wname, XmListBox::wargs, XmListBox::wargcount));
#endif // XAW
		XmListBox::wargcount = 0;
		XmListBox::parent = (XmGroupBox* )this;
#else // __GNUG__
#ifdef XAW
		Widget vp;
		ostrstream vpname;
		vpname << ((XmListBox* )this)->wname << "-viewport"; vpname.put('\0');
		((XmListBox* )this)->addArg(XtNallowHoriz, TRUE);
		((XmListBox* )this)->addArg(XtNallowVert, TRUE);
		XtManageChild(vp = XtCreateWidget(vpname.str(), viewportWidgetClass, popup, ((XmListBox* )this)->wargs, ((XmListBox* )this)->wargcount));
		((XmListBox* )this)->wargcount = 0;
		char** cont = new char*[1];
		cont[0] = NULL;
		((XmListBox* )this)->addArg(XtNdefaultColumns, 1);
		((XmListBox* )this)->addArg(XtNforceColumns, TRUE);
		((XmListBox* )this)->addArg(XtNlist, (XtArgVal )cont);
		XtManageChild(((XmListBox* )this)->wid = XtCreateWidget(((XmListBox* )this)->wname, listWidgetClass, vp, ((XmListBox* )this)->wargs, ((XmListBox* )this)->wargcount));
#else // XAW
		XtManageChild(((XmListBox* )this)->wid = XmCreateScrolledList(popup, ((XmListBox* )this)->wname, ((XmListBox* )this)->wargs, ((XmListBox* )this)->wargcount));
#endif // XAW
		((XmListBox* )this)->wargcount = 0;
		((XmListBox* )this)->parent = (XmGroupBox* )this;
#endif // __GNUG__
	}
#ifndef __GNUG__
#ifdef XAW
//	XmListBox::setCallback(XtNcallback, (XmGroupBox* )this, CB(XmComboBox::selectInList), TRUE, NULL);
	XmGroupBox::setCallback(XmListBox::wid, XtNcallback, (XmGroupBox* )this, CB(XmComboBox::selectInList), TRUE, NULL);
#else // XAW
	XmListBox::setCallback(XmNbrowseSelectionCallback, (XmGroupBox* )this, CB(XmComboBox::selectInList), TRUE, NULL);
	if(cbStyle != SIMPLE)
		XmEdit::setCallback(XmNlosingFocusCallback, (XmGroupBox* )this, CB(XmComboBox::cleanupCb), TRUE, NULL);
	XmGroupBox::initTabstop(TRUE);
#endif
#else // __GNUG__
#ifdef XAW
	((XmListBox* )this)->setCallback(XtNcallback, (XmGroupBox* )this, CB(XmComboBox::selectInList), TRUE, NULL);
#else // XAW
	((XmListBox* )this)->setCallback(XmNbrowseSelectionCallback, (XmGroupBox* )this, CB(XmComboBox::selectInList), TRUE, NULL);
	if(cbStyle != SIMPLE)
		((XmEdit* )this)->setCallback(XmNlosingFocusCallback, (XmGroupBox* )this, CB(XmComboBox::cleanupCb), TRUE, NULL);
	((XmGroupBox* )this)->initTabstop(TRUE);
#endif // XAW
#endif // __GNUG__
	return(XmGroupBox::wid ? TRUE : FALSE);
}

void XmComboBox::makeRelativeTo(XmGroupBox* aGroup)
{
	XmGroupBox::makeRelativeTo(aGroup);
	if(cbStyle != SIMPLE)
		XmListBox::makeRelativeTo(aGroup);
}

void XmComboBox::cleanup()
{
}

#include <time.h>

XmComboBox* lastCombo = NULL;
time_t lastPopDown;

void XmComboBox::selectArrow(void*)
{
	if(cbStyle != SIMPLE && lbMapped)
	{	// cerr << "unmapping \n";
		XtPopdown(popup);
		lbMapped = FALSE;
	}
	else
	{	if(lastCombo == this && lastPopDown == time(NULL))
			goto ignore;
		Position nx, ny;
		Arg a[2];
		a[0].name = XtNx;
		a[1].name = XtNy;
		a[0].value = (XtArgVal )&nx;
		a[1].value = (XtArgVal )&ny;
		XtGetValues(XmGroupBox::wid, a, 2);
#ifdef LINUX
		if(XtClass(XtParent(((XmGroupBox* )this)->handle())) != boxWidgetClass)
			nx = ny = 0;	// XtTranslateCoords seems to work different...
#endif
#ifndef __GNUG__
		XtTranslateCoords(XtParent(XmGroupBox::wid), nx + XmListBox::cx, ny + XmListBox::cy, &nx, &ny);
#else
		XtTranslateCoords(XtParent(XmGroupBox::wid), nx + ((XmListBox* )this)->cx, ny + ((XmListBox* )this)->cy, &nx, &ny);
#endif
		a[0].value = nx;
		a[1].value = ny;
		XtSetValues(popup, a, 2);
		XtPopup(popup, XtGrabNone);		// XtGrabExclusive); ...requires callback...
		lbMapped = TRUE;
ignore:	lastCombo = NULL;
	}
	// XmEdit::setFocus();	would be fine but doesn't work...
	XEvent e;
#ifndef XAW
#ifndef __GNUG__
	XtCallActionProc(XtParent(XmPushButton::wid), "ManagerGadgetTraversePrev", &e, NULL, 0);
#else
	XtCallActionProc(XtParent(((XmPushButton* )this)->wid), "ManagerGadgetTraversePrev", &e, NULL, 0);
#endif
#endif
}

void XmComboBox::changeText(void* cd)
{
	Entry ud = XmGroupBox::userData;
#ifndef __GNUG__
	if(XmGroupBox::userData.receiver && validProc(XmGroupBox::userData.callback))
#else
	if(((XmGroupBox* )this)->userData.receiver && validProc(((XmGroupBox* )this)->userData.callback))
#endif
		genericCallback(XmGroupBox::wid, (XtPointer )&ud, (XtPointer )cd);
}

void XmComboBox::selectInList(void*)
{
	char** aList;

	XmEdit::setText((aList = selectedItems())[0]);
#ifndef XAW
	delete aList[0];	// list should contain only one item...
#endif
	delete aList;

	if(cbStyle == DROPDOWN)
	{	XtPopdown(popup);
		lbMapped = FALSE;
	}
	changeText(NULL);
}

void XmComboBox::cleanupCb(void*)
{
	if(lbMapped)
	{	XtPopdown(popup);
		lbMapped = FALSE;
		lastCombo = this;
		lastPopDown = time(NULL);
	}
}

bool XmComboBox::realize()
{
	return(XmGroupBox::realize());
}

bool XmComboBox::move(int nx, int ny)
{
	if(cbStyle != SIMPLE)
#ifndef __GNUG__
	{	XmListBox::cx = nx;
		XmListBox::cy = ny;
		XtMoveWidget(popup, XmListBox::cx, XmListBox::cy);
	}
	return(bool(XmGroupBox::move(nx, ny)));
#else
	{	((XmListBox* )this)->cx = nx;
		((XmListBox* )this)->cy = ny;
		XtMoveWidget(popup, ((XmListBox* )this)->cx, ((XmListBox* )this)->cy);
	}
	return(bool(((XmGroupBox* )this)->move(nx, ny)));
#endif
}

bool XmComboBox::resize(int x, int y)
{
	return(XmGroupBox::resize(x, y));
}

bool XmComboBox::reframe(int x, int y, int w, int h)
{
	return(XmGroupBox::reframe(x, y, w, h));
}

XmControl* XmComboBox::setFocus()	{ return((XmPushButton* )this); }

XmControl* XmComboBox::disable()
{
	Widget gbh;
	Arg a;
#ifndef __GNUG__
	gbh = XmGroupBox::handle();
#else
	gbh = ((XmGroupBox* )this)->handle();
#endif
	if(gbh)
	{	XtSetArg(a, XtNsensitive, FALSE);
		XtSetValues(gbh, &a, 1);
	}
	return((XmGroupBox* )this);
}

XmControl* XmComboBox::enable()
{
	Widget gbh;
	Arg a;
#ifndef __GNUG__
	gbh = XmGroupBox::handle();
#else
	gbh = ((XmGroupBox* )this)->handle();
#endif
	if(gbh)
	{	XtSetArg(a, XtNsensitive, FALSE);
		XtSetValues(gbh, &a, 1);
	}
	return((XmGroupBox* )this);
}


