This is UxMethod.c in view mode; [Download] [Up]
/*---------------------------------------------------------------------
* $Date: 93/07/12 19:02:08 $ $Revision: 2.12.6.1 $
*---------------------------------------------------------------------
*
*
* Copyright (c) 1992, Visual Edge Software Ltd.
*
* 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 name of Visual Edge Software not be
* used in advertising or publicity pertaining to distribution of
* the software without specific, written prior permission. The year
* included in the notice is the year of the creation of the work.
*-------------------------------------------------------------------*/
/*------------------------------------------------------------------------
* Method registration and dispatch for swidget interfaces.
* This version supports the default macros and generated code,
* using a simple (and fast) table lookup approach.
*------------------------------------------------------------------------*/
#ifdef XT_CODE
# include "UxXt.h"
#else /* XT_CODE */
# include "UxLib.h"
# include "method.h"
#endif /* XT_CODE */
#ifdef DESIGN_TIME
#include "veos.h"
#include "swidget.h"
#endif
/* Global environment variable supplied for the user's convenience */
Environment UxEnv = {NO_EXCEPTION};
static char **Names; /* All method names as registered */
static int NameLen = 0; /* Gross length of names array */
static int NumNames = 0; /* Num Elements in names array */
static void ***MethodTable; /* All method pointers */
static int *BaseTable; /* Base class id's by class id. */
static int NumClasses = 0; /* Active width of method table */
static int *MethodCounts; /* Height by row in method table */
#ifdef _NO_PROTO
static int UndefinedMethod ();
#else /* _NO_PROTO */
static int UndefinedMethod (void);
#endif /* _NO_PROTO */
#ifdef XT_CODE
static XContext xcontext_mid = 0;
#endif /* XT_CODE */
/*------------------------------------------------------------------------
* NAME: UxMethodLookup
* INPUT: swidget sw; -- a swidget, usually an interface swidget
* int mid; -- a method id from UxMethodRegister
* RETURNS: Pointer to method function for this method.
* DESCRIPTION:
* This is the heart of virtual method lookup.
* The design-time routing functions and runtime macros
* use this function to fnd the implementation of a method.
* The return value is the actual function pointer
* for the implementation of the method associated with `sw's
* interface class.
*
* LAST REV: Feb 93 fix3910 Add support for subclassing.
*------------------------------------------------------------------------*/
#ifdef _NO_PROTO
void* UxMethodLookup(sw, mid, mname)
swidget sw;
int mid;
char * mname;
#else /* _NO_PROTO */
void* UxMethodLookup(swidget sw, int mid, char *mname)
#endif /* _NO_PROTO */
{
int cid = UxGetClassCode(sw);
if (mid < 0) {
mid = UxMessageIndex(mname);
if (mid < 0) {
return 0;
}
}
/*-----------------------------------------------------------
* The method may be registered on this class or a base class.
*-----------------------------------------------------------*/
while (cid > -1 && cid < NumClasses)
{
if (mid < MethodCounts[cid] && MethodTable[cid][mid])
{
return MethodTable[cid][mid];
}
cid = BaseTable[cid];
}
#ifndef DESIGN_TIME
return (void *) UndefinedMethod;
#else
return 0;
#endif
}
/*------------------------------------------------------------------------
* NAME: UxNewClassId
* RETURNS: a unique integer each time called.
* DESCRIPTION:
* This is to get a unique id for each interface class registered.
* The result is used for calls to UxMethodRegister, and
* is associated with each instance of the interface class:
* it is returned by UxGetClassId(sw) for each interface swidget sw
* that is an instance of the interface it represents.
*
* We have no subclassing. When it comes, parent class id's
* will be supplied in this call, and used to initialize the
* classes' method table with its parent's versions.
*
* LAST REV: Feb 93 fix3910 Add support for subclassing.
*------------------------------------------------------------------------*/
#ifdef _NO_PROTO
int UxNewClassId()
#else /* _NO_PROTO */
int UxNewClassId(void)
#endif /* _NO_PROTO */
{
static int GrossClasses = 0; /* Gross width of method table */
int cid = NumClasses++;
if (GrossClasses < NumClasses)
{
if (GrossClasses) {
MethodTable = (void***)
UxRealloc(MethodTable,
(GrossClasses += 10) * sizeof(void**));
MethodCounts = (int*)
UxRealloc(MethodCounts,
(GrossClasses * sizeof(int)));
BaseTable = (int*)
UxRealloc(BaseTable,
GrossClasses * sizeof(int));
} else {
MethodTable = (void***) UxCalloc((GrossClasses += 10),
sizeof(void**));
MethodCounts = (int*) UxCalloc(GrossClasses,
sizeof(int));
BaseTable = (int*) UxCalloc(GrossClasses,
sizeof(int));
}
}
MethodTable[cid] = (void**) UxCalloc(NumNames, sizeof(void*));
MethodCounts[cid] = NumNames;
BaseTable[cid] = -1;
return cid;
}
/*------------------------------------------------------------------------
* NAME: UxNewSubclassId (super)
* <register a new class as a subclass of an existing class>
* INPUT: super class id
* RETURNS: new class id of a subclass of the superclass.
*
* LAST REV: Feb 93 fix3910 Add support for subclassing.
*------------------------------------------------------------------------*/
#ifdef _NO_PROTO
int UxNewSubclassId(super)
int super;
#else /* _NO_PROTO */
int UxNewSubclassId( int super)
#endif /* _NO_PROTO */
{
int cid = UxNewClassId();
BaseTable[cid] = super;
return cid;
}
/*------------------------------------------------------------------------
* NAME: UxMessageIndex
* INPUT: char* name; -- name of a method being registered.
* RETURNS: A unique id number for this name.
* DESCRIPTION:
* Assigns a unique integer to a message name.
* Must return the same id for all calls with the same name.
*
* This is used while rgistering methods at startup time.
* The result is used when method calls are made
* (see UxMethodLookup). If a very large number of method names
* are being used, initialization could be speeded up by making
* this function faster (by sorting or hashing the names).
*
* LAST REV: June 92 fix3574 Created.
*------------------------------------------------------------------------*/
#ifdef _NO_PROTO
int UxMessageIndex (name)
char* name;
#else /* _NO_PROTO */
int UxMessageIndex ( char* name)
#endif /* _NO_PROTO */
{
int mid;
for (mid = 0 ; mid < NumNames; mid++)
{
if (UxStrEqual(Names[mid], name)) {
return mid;
}
}
if (mid >= NameLen) {
if (NameLen == 0) {
Names = (char**) UxMalloc((NameLen=64)*sizeof(char*));
} else {
Names = (char**) UxRealloc(Names,
(NameLen*=2)*sizeof(char*));
}
}
Names[NumNames] = (char*) UxMalloc(strlen(name)+1);
strcpy(Names[NumNames], name);
return NumNames++;
}
/*------------------------------------------------------------------------
* NAME: MethodTableSpace
* INPUT:
* int cid; -- class id from UxNewClassId ()
* int mid; -- method id from UxMessageIndex ()
* DESCRIPTION:
*
* Enlarges the method table for the given cid,
* so that it is at least big enough to register a method
* for the given message index. We also add a little more space
* (two more cells), but not a lot: there's one of these
* arrays for each class, so we don't want them growing too large.
*
* LAST REV: Feb 93 fix3910 Add support for subclassing.
*------------------------------------------------------------------------*/
#ifdef _NO_PROTO
static void MethodTableSpace (cid, mid)
int cid;
int mid;
#else /* _NO_PROTO */
static void MethodTableSpace (int cid, int mid)
#endif /* _NO_PROTO */
{
int old_cnt = MethodCounts[cid];
int i;
if (old_cnt < mid+1)
{
MethodTable[cid] = (void**) UxRealloc(MethodTable[cid],
(mid + 2) * sizeof(void*));
for (i = old_cnt; i < mid+2; i++)
{
MethodTable[cid][i] = 0;
}
MethodCounts[cid] = mid + 2;
}
}
/*------------------------------------------------------------------------
* NAME: UxMethodRegister
* INPUT: int cid; -- a class code from UxNewClassId()
* char *name; -- a method name
* void (*function) (); -- implementation of the method
* for the identified class.
*
* RETURNS: An identifier code for the given method name
* to be used in subsequent calls to UxMethodLookup.
* All calls to this function with the same method name
* return the same index.
*
* DESCRIPTION:
* Called during interface class initialization for each method
* implemented by the class.
* It builds the method lookup table for the class.
*
* LAST REV: June 92 fix3574 Created.
*------------------------------------------------------------------------*/
#ifdef _NO_PROTO
int UxMethodRegister(cid, name, function)
int cid;
char *name;
void (*function) ();
#else /* _NO_PROTO */
int UxMethodRegister(int cid, char *name, void (*function) ())
#endif /* _NO_PROTO */
{
int mid = UxMessageIndex (name);
MethodTableSpace(cid, mid);
MethodTable[cid][mid] = (void *) function;
return mid;
}
/*------------------------------------------------------------------------
* NAME: UxGetClassCode
*
* INPUT: some swidget
* RETURNS: its ifClassCode, or that of its nearest container
* that has a class code.
* DESCRIPTION:
*
* This makes calling methods a little more flexible.
* Class codes are assigned to top-level swidgets in interfaces,
* when their delarations are initialized.
*
* LAST REV:
*------------------------------------------------------------------------*/
#ifdef _NO_PROTO
int UxGetClassCode(sw)
swidget sw;
#else /* _NO_PROTO */
int UxGetClassCode(swidget sw)
#endif /* _NO_PROTO */
{
while (sw && UxGetIfClassCode(sw) < 0) {
sw = UxGetParent(sw);
}
if (sw)
return UxGetIfClassCode(sw);
return -1;
}
/******************************************************************************
NAME: UxPutClassCode( wgt, id )
INPUT: Widget wgt - Widget
int id; - Id od method
RETURN: int UX_ERROR / UX_NO_ERROR
DESCRIPTION: Uses the X Context manager to store the given id
in a memory location that is indexed by the given widget id.
EXT REFERENCES: UxTopLevel, xcontext_mid
EXT EFFECTS: xcontext_mid
CREATION: Visual Edge Software January 9 1993
-----------------------------------------------------------------------------*/
#ifdef XT_CODE
#ifdef _NO_PROTO
int UxPutClassCode( wgt, id)
Widget wgt;
int id;
#else
int UxPutClassCode( Widget wgt, int id)
#endif /* _NO_PROTO */
{
int status;
if ( xcontext_mid == 0 )
xcontext_mid = XUniqueContext();
if ( wgt == NULL )
return ( UX_ERROR );
status = XSaveContext( XtDisplay( UxTopLevel ),
(Window) wgt,
xcontext_mid,
(XtPointer) id );
if ( status != 0 )
return ( UX_ERROR );
XtAddCallback (wgt, XmNdestroyCallback,
UxDeleteContextCB, (XtPointer) xcontext_mid);
return ( UX_NO_ERROR );
}
#endif /* XT_CODE */
/******************************************************************************
NAME: UxGetIfClassCode( wgt )
INPUT: Widget wgt - widget
RETURN: caddr_t - the context pointer
DESCRIPTION: Uses the X Context manager to find the method id
stored in a memory location indexed by the given widget id.
EXT REFERENCES: UxTopLevel, xcontext_mid
CREATION: Visual Edge Software January 9 1993
-----------------------------------------------------------------------------*/
#ifdef XT_CODE
#ifdef _NO_PROTO
int UxGetIfClassCode( wgt )
Widget wgt;
#else
int UxGetIfClassCode( Widget wgt )
#endif /* _NO_PROTO */
{
int status;
XtPointer id;
if ( wgt == NULL )
return -1;
status = XFindContext( XtDisplay( UxTopLevel ),
(Window) wgt,
xcontext_mid,
(XtPointer) &id );
if ( status != 0 )
return -1;
return ( (int) id);
}
#endif /* XT_CODE */
/*------------------------------------------------------------------------
* UxChildSite (this)
* INPUT: swidget inst - user-defined component
* Gets the designatedChildSite by composing a call to the childSite
* method and calling that method. If the childSite is an intance,
* we recur by calling the childSite's childSite method and so on...
* LAST REV: March 1993 3988 - don't recur when childSite==this
*------------------------------------------------------------------------*/
#ifdef _NO_PROTO
swidget UxChildSite (inst)
swidget inst;
#else /* _NO_PROTO */
swidget UxChildSite (swidget inst)
#endif /* _NO_PROTO */
{
/*-----------------------------------------------------
* Index of "childSite" in low-level method dispatcher.
*-----------------------------------------------------*/
static int ChildSiteMID = -1;
swidget childSite = NULL;
#ifdef _NO_PROTO
void (*childSiteMethod) () ;
#else
void (*childSiteMethod) (swidget, Environment *);
#endif
if (ChildSiteMID == -1) {
ChildSiteMID = UxMessageIndex("childSite");
}
if (! inst) {
return childSite;
}
childSiteMethod = (void (*) ())
UxMethodLookup (inst, ChildSiteMID, "childSite");
if (childSiteMethod) {
childSite = ((swidget(*)())childSiteMethod) (inst, &UxEnv);
if (childSite && childSite != inst)
{
swidget nested = UxChildSite(childSite);
if (nested) {
childSite = nested;
}
}
}
if (!childSite) {
childSite = inst;
}
return childSite;
}
/*------------------------------------------------------------------------
* NAME: UxReclassifyCID (cid, super)
* <redefine a subclass as being derived from a new base.>
* INPUT: sub class id
* super class id
*
* LAST REV: 3988 Mar 93 Created.
*------------------------------------------------------------------------*/
#ifdef DESIGN_TIME
#ifdef _NO_PROTO
void UxReclassifyCID(cid, super)
int cid;
int super;
#else /* _NO_PROTO */
void UxReclassifyCID(int cid, int super)
#endif /* _NO_PROTO */
{
if (cid == super) {
UxInternalError(__FILE__, __LINE__, "Cid == Super Cid");
}
BaseTable[cid] = super;
}
#endif /* DESIGN_TIME */
/*------------------------------------------------------------------------
* NAME: UxInheritedMethodLookup
* INPUT: swidget sw; -- a swidget, usually an interface swidget
* int mid; -- a method id from UxMethodRegister
* RETURNS: Pointer to method function for this method.
* DESCRIPTION:
* Like UxMethodLookup, but starts searching at the first
* base class of the given sw, not at its own class.
*
* LAST REV: 3988 March 93 Created.
*------------------------------------------------------------------------*/
#ifdef DESIGN_TIME
#ifdef _NO_PROTO
void* UxInheritedMethodLookup (sw, mid, mname)
swidget sw;
int mid;
char * mname;
#else /* _NO_PROTO */
void* UxInheritedMethodLookup (swidget sw, int mid, char *mname)
#endif /* _NO_PROTO */
{
int cid = UxGetClassCode(sw);
if (cid < 0 || cid > NumClasses) {
return 0;
}
if (mid < 0) {
mid = UxMessageIndex(mname);
if (mid < 0) {
return 0;
}
}
cid = BaseTable[cid];
while (cid > -1 && cid < NumClasses)
{
if (mid < MethodCounts[cid] && MethodTable[cid][mid]) {
return MethodTable[cid][mid];
}
cid = BaseTable[cid];
}
return 0;
}
#endif /* DESIGN_TIME */
#ifndef DESIGN_TIME
/*------------------------------------------------------------------------
* NAME: UndefinedMethod
* INPUT:
* RETURNS: always 0.
* DESCRIPTION: Function used as a return value of UxMethodLookup
* in case the method lookup fails.
*
* LAST REV: April 8 1993
*------------------------------------------------------------------------*/
#ifdef _NO_PROTO
static int UndefinedMethod ()
#else /* _NO_PROTO */
static int UndefinedMethod (void)
#endif /* _NO_PROTO */
{
return 0;
}
#endif /* DESIGN_TIME */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.