/* $XConsortium: Create.c,v 1.78 90/09/04 10:50:33 swick Exp $ */

/***********************************************************
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
and the Massachusetts Institute of Technology, Cambridge, Massachusetts.

                        All Rights Reserved

Permission to use, copy, modify, and distribute this software and its 
documentation for any purpose and without fee is hereby granted, 
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in 
supporting documentation, and that the names of Digital or MIT not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.  

DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

******************************************************************/

#include "IntrinsicI.h"
#include "VarargsI.h"
#include "StringDefs.h"
/*#include "Shell.h"*/
#include "ShellP.h"
#include <stdio.h>

extern String XtCXtToolkitError;

static String XtNxtCreateWidget = "xtCreateWidget";
static String XtNxtCreatePopupShell = "xtCreatePopupShell";

extern void bcopy();

static void _XtHeapInit(heap)
    Heap*	heap;
{
    heap->start = NULL;
    heap->bytes_remaining = 0;
}

XtAppContext XtCreateApplicationContextP(app)
     XtAppContext app;
{
	app->process = _XtGetProcessContext();
	app->next = app->process->appContextList;
	app->process->appContextList = app;
	app->destroy_callbacks = NULL;
	app->list = NULL;
	app->count = app->max = app->last = 0;
	app->timerQueue = NULL;
	app->workQueue = NULL;
	app->input_list = NULL;
	app->outstandingQueue = NULL;
	app->errorDB = NULL;
	_XtSetDefaultErrorHandlers(&app->errorMsgHandler, 
		&app->warningMsgHandler, &app->errorHandler, 
		&app->warningHandler);
	app->action_table = NULL;
	_XtSetDefaultSelectionTimeout(&app->selectionTimeout);
	_XtSetDefaultConverterTable(&app->converterTable);
	app->sync = app->being_destroyed = app->error_inited = FALSE;
	app->in_phase2_destroy = NULL;
	app->fds.nfds = app->fds.count = 0;
	FD_ZERO(&app->fds.rmask);
	FD_ZERO(&app->fds.wmask);
	FD_ZERO(&app->fds.emask);
	_XtHeapInit(&app->heap);
	app->fallback_resources = NULL;
	_XtPopupInitialize(app);
	app->action_hook_list = NULL;
	app->destroy_list_size = app->destroy_count = app->dispatch_level = 0;
	app->destroy_list = NULL;
#ifndef NO_IDENTIFY_WINDOWS
	app->identify_windows = False;
#endif
	return app;
}

/**
XtAppContext XtCreateApplicationContext()
{
   XtAppContext app = XtNew(XtAppStruct);
   return XtCreateApplicationContextP(app);
}
**/

static void CallClassPartInit(ancestor, wc)
     WidgetClass ancestor, wc;
{
    if (ancestor->core_class.superclass != NULL) {
	CallClassPartInit(ancestor->core_class.superclass, wc);
    }
    if (ancestor->core_class.class_part_initialize != NULL) {
	(*(ancestor->core_class.class_part_initialize)) (wc);
    }
}

extern void XtInitializeWidgetClass();


static void CallInitialize (class, req_widget, new_widget, args, num_args)
    WidgetClass class;
    Widget      req_widget;
    Widget      new_widget;
    ArgList     args;
    Cardinal    num_args;
{
    if (class->core_class.superclass)
        CallInitialize (class->core_class.superclass,
	    req_widget, new_widget, args, num_args);
    if (class->core_class.initialize != NULL)
	(*class->core_class.initialize)
	    (req_widget, new_widget, args, &num_args);
    if (class->core_class.initialize_hook != NULL)
	(*class->core_class.initialize_hook) (new_widget, args, &num_args);
}

static void CallConstraintInitialize (class, req_widget, new_widget, args, num_args)
    ConstraintWidgetClass class;
    Widget	req_widget, new_widget;
    ArgList	args;
    Cardinal	num_args;
{
    if (class->core_class.superclass != constraintWidgetClass)
	CallConstraintInitialize(
	    (ConstraintWidgetClass) class->core_class.superclass,
	    req_widget, new_widget, args, num_args);
    if (class->constraint_class.initialize != NULL)
        (*class->constraint_class.initialize)
	    (req_widget, new_widget, args, &num_args);
}

static Widget _XtCreate(
        placement,		       
	name, class, widget_class, parent, default_screen,
	args, num_args, typed_args, num_typed_args, parent_constraint_class)
    caddr_t     placement;
    char        *name, *class;
    WidgetClass widget_class;
    Widget      parent;
    Screen*     default_screen;
    ArgList     args;		/* must be NULL if typed_args is non-NULL */
    Cardinal    num_args;
    XtTypedArgList typed_args;	/* must be NULL if args is non-NULL */
    Cardinal	num_typed_args;
    ConstraintWidgetClass parent_constraint_class;
        /* NULL if not a subclass of Constraint or if child is popup shell */
{
    register _XtOffsetList  offsetList;
    XtCallbackList          *pCallbacks;
    /* need to use strictest alignment rules possible in next two decls. */
    double                  widget_cache[100];
    double                  constraint_cache[20];
    Widget                  req_widget;
    XtPointer               req_constraints;
    Cardinal                size;
    register Widget	    widget;
    XtCacheRef		    *cache_refs;
    register int	    i;

    if (! (widget_class->core_class.class_inited))
	XtInitializeWidgetClass(widget_class);
    widget = (Widget) placement;
    widget->core.self = widget;
    widget->core.parent = parent;
    widget->core.widget_class = widget_class;
    widget->core.xrm_name = StringToName((name != NULL) ? name : "");
    widget->core.being_destroyed =
	(parent != NULL ? parent->core.being_destroyed : FALSE);
    if (parent_constraint_class != NULL
	&& parent_constraint_class->constraint_class.constraint_size > 0)
       	widget->core.constraints = 
	    (XtPointer) XtMalloc((unsigned)parent_constraint_class->
                       constraint_class.constraint_size);
    else
	widget->core.constraints = NULL;
    if (XtIsWidget(widget)) {
	widget->core.name = XrmNameToString(widget->core.xrm_name);
        widget->core.screen = default_screen;
        widget->core.tm.translations = NULL;
    };
    if (XtIsApplicationShell(widget)) {
	ApplicationShellWidget a = (ApplicationShellWidget) widget;
	if (class != NULL)
	    a->application.xrm_class = StringToClass(class);
	else
	    a->application.xrm_class =
		StringToClass(widget_class->core_class.class_name);
	a->application.class = XrmQuarkToString(a->application.xrm_class);
    }

    /* fetch resources */
    cache_refs = _XtGetResources(widget, args, num_args, 
			          typed_args, &num_typed_args);

    /* Convert typed arg list to arg list */
    if (typed_args != NULL && num_typed_args > 0) {
	args = (ArgList)ALLOCATE_LOCAL(sizeof(Arg) * num_typed_args);
	if (args == NULL) _XtAllocError(NULL);
	for (i = 0; i < num_typed_args; i++) {
	    args[i].name = typed_args[i].name;
	    args[i].value = typed_args[i].value;
	}
	num_args = num_typed_args;
    }

    /* Compile any callback lists into internal form */
    for (offsetList = (_XtOffsetList)widget->core.widget_class->
				core_class.callback_private;
	 offsetList != NULL;
	 offsetList = offsetList->next) {
	 pCallbacks = (XtCallbackList *)
	     ((char *)widget - offsetList->offset - 1);
	if (*pCallbacks != NULL) {
	    extern CallbackStruct* _XtCompileCallbackList();
	    *pCallbacks =
		(XtCallbackList) _XtCompileCallbackList(widget, *pCallbacks);
	}
    }
    if (cache_refs != NULL) {
	extern void _XtCallbackReleaseCacheRefs();
	XtAddCallback( widget, XtNdestroyCallback,
		       XtCallbackReleaseCacheRefList, (XtPointer)cache_refs );
    }

    size = XtClass(widget)->core_class.widget_size;
    req_widget = (Widget) XtStackAlloc(size, widget_cache);
    bcopy ((char *) widget, (char *) req_widget, (int) size);
    CallInitialize (XtClass(widget), req_widget, widget, args, num_args);

    if (typed_args != NULL) {
	while (num_typed_args-- > 0) {
	
	    /* In GetResources we may have dynamically alloc'd store to hold */
	    /* a copy of a resource which was larger then sizeof(XtArgVal). */
	    /* We must free this store now in order to prevent a memory leak */
	    /* A typed arg that has a converted value in dynamic store has a */
	    /* negated size field. */

	    if (typed_args->type != NULL && typed_args->size < 0) {
		XtFree((char*)typed_args->value);
		typed_args->size = -(typed_args->size);
		}
	    typed_args++;
	}

	DEALLOCATE_LOCAL((char*)args);
    }

    if (parent_constraint_class != NULL) {
	if (size = parent_constraint_class->constraint_class.constraint_size){
	    req_constraints = XtStackAlloc(size, constraint_cache);
	    bcopy(widget->core.constraints, (char*)req_constraints,(int)size);
	    req_widget->core.constraints = req_constraints;
	} else req_widget->core.constraints = NULL;
	CallConstraintInitialize(parent_constraint_class, req_widget, widget,
				 args, num_args);
	if (size) XtStackFree(req_constraints, constraint_cache);
    }
    XtStackFree((XtPointer)req_widget, widget_cache);
    return (widget);
}


Widget _XtCreateWidgetP(placement, name, widget_class, parent, args, num_args,
		       typed_args, num_typed_args)
    caddr_t     placement;
    String      name;
    WidgetClass widget_class;
    Widget      parent;
    ArgList     args;
    Cardinal    num_args;
    XtTypedArgList typed_args;
    Cardinal	num_typed_args;
{
    register Widget	    widget;
    ConstraintWidgetClass   cwc;
    XtWidgetProc	    insert_child;
    Screen*                 default_screen;

    if (parent == NULL) {
	XtErrorMsg("invalidParent",XtNxtCreateWidget,XtCXtToolkitError,
                "XtCreateWidget requires non-NULL parent",
                  (String *)NULL, (Cardinal *)NULL);
    } else if (widget_class == NULL) {
	XtAppErrorMsg(XtWidgetToApplicationContext(parent),
		"invalidClass",XtNxtCreateWidget,XtCXtToolkitError,
                "XtCreateWidget requires non-NULL widget class",
                  (String *)NULL, (Cardinal *)NULL);
    }
    if (!widget_class->core_class.class_inited)
	XtInitializeWidgetClass(widget_class);
    if ((widget_class->core_class.class_inited & WidgetClassFlag) == 0) {
	/* not a widget */
	if (XtIsComposite(parent)) {
	    CompositeClassExtension ext;
	    for (ext = (CompositeClassExtension)
		       ((CompositeWidgetClass)XtClass(parent))
			 ->composite_class.extension;
		 ext != NULL && ext->record_type != NULLQUARK;
		 ext = (CompositeClassExtension)ext->next_extension);
	    if (ext != NULL &&
		(ext->version != XtCompositeExtensionVersion
		 || ext->record_size != sizeof(CompositeClassExtensionRec))) {
		String params[1];
		Cardinal num_params = 1;
		params[0] = XtClass(parent)->core_class.class_name;
		XtAppWarningMsg(XtWidgetToApplicationContext(parent),
		  "invalidExtension", XtNxtCreateWidget, XtCXtToolkitError,
		  "widget class %s has invalid CompositeClassExtension record",
		  params, &num_params);
		ext = NULL;
	    }
	    if (ext == NULL || !ext->accepts_objects) {
		String params[2];
		Cardinal num_params = 2;
		params[0] = name;
		params[1] = XtName(parent);
		XtAppErrorMsg(XtWidgetToApplicationContext(parent),
			      "nonWidget",XtNxtCreateWidget,XtCXtToolkitError,
			      "attempt to add non-widget child \"%s\" to parent \"%s\" which supports only widgets",
			      params, &num_params);
	    }
	}
    }

    if (XtIsConstraint(parent)) {
	cwc = (ConstraintWidgetClass) parent->core.widget_class;
    } else {
	cwc = NULL;
    }
    default_screen = parent->core.screen;
    widget = _XtCreate(placement, name, (char *)NULL, widget_class, parent,
		       default_screen, args, num_args,
		       typed_args, num_typed_args, cwc);
    if (XtIsComposite(parent)) {
        insert_child = ((CompositeWidgetClass) parent->core.widget_class)->
	    composite_class.insert_child;
    } else {
	return(widget);
    }
    if (insert_child == NULL) {
	XtAppErrorMsg(XtWidgetToApplicationContext(parent),
		"nullProc","insertChild",XtCXtToolkitError,
                "NULL insert_child procedure",
                  (String *)NULL, (Cardinal *)NULL);
    } else {
	(*insert_child) (widget);
    }
    return (widget);
}

Widget XtCreateWidgetP(placement, name, widget_class, parent, args, num_args)
    caddr_t     placement;
    String	name;
    WidgetClass widget_class;
    Widget   	parent;
    ArgList 	args;
    Cardinal    num_args;
{
    return(_XtCreateWidgetP(placement, name, widget_class, parent,
			    args, num_args,
			    (XtTypedArgList)NULL, (Cardinal)0));
}


Widget XtCreateManagedWidgetP(placement, name, widget_class, parent,
			      args, num_args)
    caddr_t     placement;
    String      name;
    WidgetClass widget_class;
    Widget      parent;
    ArgList     args;
    Cardinal    num_args;
{
    register Widget	    widget;

    XtCheckSubclass(parent, compositeWidgetClass, "in XtCreateManagedWidget");
    widget = XtCreateWidgetP(placement, name, widget_class, 
			    parent, args, num_args);
    XtManageChild(widget);
    return widget;
}

Widget _XtCreatePopupShellP(placement,
			   name, widget_class, parent, args, num_args,
			   typed_args, num_typed_args)
    caddr_t     placement;
    String      name;
    WidgetClass widget_class;
    Widget      parent;
    ArgList     args;
    Cardinal    num_args;
    XtTypedArgList      typed_args;
    Cardinal            num_typed_args;
{
    register Widget widget;
    Screen* default_screen;

    if (parent == NULL) {
	XtErrorMsg("invalidParent",XtNxtCreatePopupShell,XtCXtToolkitError,
                "XtCreatePopupShell requires non-NULL parent",
                  (String *)NULL, (Cardinal *)NULL);
    } else if (widget_class == NULL) {
	XtAppErrorMsg(XtWidgetToApplicationContext(parent),
		"invalidClass",XtNxtCreatePopupShell,XtCXtToolkitError,
                "XtCreatePopupShell requires non-NULL widget class",
                  (String *)NULL, (Cardinal *)NULL);
    }
    XtCheckSubclass(parent, coreWidgetClass, "in XtCreatePopupShell");
    default_screen = parent->core.screen;
    widget = _XtCreate(placement,
		       name, (char *)NULL, widget_class, parent,
		       default_screen, args, num_args, typed_args,
		       num_typed_args, (ConstraintWidgetClass)NULL);

    parent->core.popup_list =
	(WidgetList) XtRealloc((char*) parent->core.popup_list,
               (unsigned) (parent->core.num_popups+1) * sizeof(Widget));
    parent->core.popup_list[parent->core.num_popups++] = widget;
    return(widget);
}


Widget XtCreatePopupShellP(placement, name, widget_class, parent,
			   args, num_args)
    caddr_t     placement;
    String      name;
    WidgetClass widget_class;
    Widget      parent;
    ArgList     args;
    Cardinal    num_args;
{
    return _XtCreatePopupShellP(placement, name, widget_class, parent, 
					  args, num_args,
					  (XtTypedArgList)NULL, (Cardinal)0);
}


Widget _XtAppCreateShellP(placement,
			  name, class, widget_class, display, args, num_args,
			  typed_args, num_typed_args)
    caddr_t     placement;
    String      name, class;
    WidgetClass widget_class;
    Display*    display;
    ArgList     args;
    Cardinal    num_args;
    XtTypedArgList typed_args;
    Cardinal	num_typed_args;
{
    if (widget_class == NULL) {
	XtAppErrorMsg(XtDisplayToApplicationContext(display),
	       "invalidClass","xtAppCreateShell",XtCXtToolkitError,
               "XtAppCreateShell requires non-NULL widget class",
                 (String *)NULL, (Cardinal *)NULL);
    }

    if (name == NULL)
	name = XrmNameToString(_XtGetPerDisplay(display)->name);

    return _XtCreate(placement,name, class, widget_class, (Widget)NULL,
	    (Screen*)DefaultScreenOfDisplay(display),
	    args, num_args, typed_args, num_typed_args,
	    (ConstraintWidgetClass) NULL);
}

Widget XtAppCreateShellP(placement,name, class, widget_class, display, 
			 args, num_args)
    caddr_t             placement;
    String              name, class;
    WidgetClass         widget_class;
    Display             *display;
    ArgList             args;
    Cardinal            num_args;
{
    return _XtAppCreateShellP(placement, name, class, widget_class, 
			      display, args, 
			      num_args, (XtTypedArgList)NULL, (Cardinal)0);
}

/* ARGSUSED */
Widget XtCreateApplicationShellP(placement, name, widget_class, args, num_args)
    caddr_t     placement;
    String      name;		/* unused in R3 and later */
    WidgetClass widget_class;
    ArgList     args;
    Cardinal    num_args;
{
    Display *dpy = _XtDefaultAppContext()->list[0];
    XrmClass class = _XtGetPerDisplay(dpy)->class;

    return _XtAppCreateShellP(placement, (String)NULL, 
			     XrmQuarkToString((XrmQuark)class),
			     widget_class, dpy, args, num_args,
			     (XtTypedArgList)NULL, (Cardinal)0);
}

