diff options
Diffstat (limited to 'vendor/x11iraf/obm/widget.c')
-rw-r--r-- | vendor/x11iraf/obm/widget.c | 5017 |
1 files changed, 5017 insertions, 0 deletions
diff --git a/vendor/x11iraf/obm/widget.c b/vendor/x11iraf/obm/widget.c new file mode 100644 index 00000000..e33723ff --- /dev/null +++ b/vendor/x11iraf/obm/widget.c @@ -0,0 +1,5017 @@ +/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc. + */ + +#include <ObmP.h> +#include "widget.h" + +/* + * WIDGET class. + * -------------------------- + * The Widget class is the generic or base class for the window system + * toolkit widgets supported by the object manager. The Widget class + * supports a number of different Xt widget classes using a table driven + * approach to describe each widget. Any widget may be created, destroyed, + * and manipulated in various ways using only the generic Widget class + * procedures and Widget-specific resources. The Widget class may be + * subclassed to support complex Widgets that require custom class-specific + * commands for use by the GUI code. + * + * Generic Widget-class commands: + * + * set resource-name value + * get resource-name + * + * addCallback procedure-name [callback-name] + * deleteCallback procedure-name + * setSensitive sensitive + * isSensitive + * + * realize + * unrealize + * isRealized + * map + * unmap + * manage child [child ...] + * unmanage child [child ...] + * popup [grab-kind] + * popdown + * popupSpringLoaded + * + * move x y + * resize width height border-width + * configure x y width height border-width + * parseGeometry user_geom def_geom x y width height + * geom = getGeometry x y width height [nogravity] + * + * setTTName name # for call($name...) + * name = getTTName + * + * The most important Widget commands are set/get resource, and the + * callbacks. The widget sensitivity can be set and queried using set/get + * resource, but special procedures are provided to make this common operation + * more convenient. + * + * Class specific functions: + * + * append text # text widget + * value = getValue # dialog widget + * + * setList list [resize] # list widget + * value = getItem itemno + * highlight itemno + * unhighlight [itemno] + * + * getThumb x [y [width height]] # sliders + * moveThumb x [y] + * resizeThumb width [height] + * + * setScrollbar position size # scrollbars + * + * setLocation x y # viewport + * setCoordinates x y + * + * setTop widget # tabs + * + * setListTree list # list tree + * listTreeSelect item [top [child_only] ] + * listTreeHighlight item [top [child_only] ] + * listTreeDelete item [top] + * + * setTable nrows ncols data # table + * attr = getCellAttr row col attr + * setCellAttr row col attr value + * attr = getColAttr col attr + * setColAttr col attr value + * attr = getRowAttr row attr + * setRowAttr row attr value + * deleteCol col + * deleteRow row + * addCol col width [where] + * addRow row [where] + * setTableSize nrows ncols + * getTableSize nrows ncols + * + * + * Ideally the widget class should be subclassed for widgets that require + * class-specific functions, but in simple cases involving standard widgets + * the support is built into the widget class code as a special case. + * + * Special actions (used in translations): + * + * call (proc [,arg, ...]) + * popup (menu-name [xoffset [yoffset]]) + * popdown (menu-name) + * + * The "call" action is a very general mechanism which allows any GUI procedure + * to be registered with any translation using the X translation table + * mechanism. The popup and popdown actions are used for popup menus. The + * menu will be popped up at the event coordinates plus the optional offsets + * if given. + * + * Event handling: + * + * addEventHandler <procname> <event-mask> [<event-mask>...] + * + * Event callback: + * + * userEventHandler widget event-type time wx wy rx ry other + * + * In most cases translations are preferable to events, but a GUI can capture + * raw events if it wishes by adding event handlers. Nearly all of the X + * event types are supported. The callback syntax employs a number of + * standard arguments, followed by a number of event-specific arguments. + */ + +typedef struct rtype *Rtype; +#define LEN_RHASH 197 +Rtype rhash[LEN_RHASH]; + +#define MAX_TREE_LEVELS 10 + +/* Global widget resources table. */ +struct rtype { + char *name; /* resource name */ + char *type; /* resource type */ + unsigned long flag1, flag2; /* widgets using resource */ + struct rtype *next; /* next entry on hash thread */ +} ObmResources[] = { +#include "obmres.dat" +}; + +struct callbackType { + int type; + char *name; +}; + +/* Widget callback types. */ +struct callbackType callbackTypes[] = { + { Ctcallback, "callback" }, + { Ctcharmode, "charmode" }, + { Ctlinemode, "linemode" }, + { CtgetValue, "getValue" }, + { CtjumpProc, "jump" }, + { CtscrollProc, "scroll" }, + { CtpopupCallback, "popup" }, + { CtpopdownCallback, "popdown" }, + { CtreportCallback, "report" }, + { CtstartCallback, "start" }, + { CtstopCallback, "stop" }, +}; + + + +enum scaleType { /* MF016 */ + atom, pixel_size, point_size, /* /|\ */ + resolution, resolution_x, resolution_y, average_width, /* / | \ */ + scaledX, scaledY, unscaled, scaledXoverY, uncomputed, /* | */ +}; /* | */ + /* | */ +typedef struct _fontProp { /* | */ + char *name; /* | */ + Atom atom; /* | */ + enum scaleType type; /* | */ + char found; /* | */ +} fontProp; /* | */ + /* | */ +static fontProp fontNamePropTable[] = { /* | */ + { "FOUNDRY", 0, atom, 0}, /* | */ + { "FAMILY_NAME", 0, atom, 0}, /* | */ + { "WEIGHT_NAME", 0, atom, 0}, /* | */ + { "SLANT", 0, atom, 0}, /* | */ + { "SETWIDTH_NAME", 0, atom, 0}, /* | */ + { "ADD_STYLE_NAME", 0, atom, 0}, /* | */ + { "PIXEL_SIZE", 0, pixel_size, 0}, /* | */ + { "POINT_SIZE", 0, point_size, 0}, /* | */ + { "RESOLUTION_X", 0, resolution_x, 0}, /* | */ + { "RESOLUTION_Y", 0, resolution_y, 0}, /* | */ + { "SPACING", 0, atom, 0}, /* | */ + { "AVERAGE_WIDTH", 0, average_width, 0}, /* | */ + { "CHARSET_REGISTRY", 0, atom, 0}, /* | */ + { "CHARSET_ENCODING", 0, atom, 0}, /* | */ +}; /* | */ + /* | */ +#define NUMITEMS(arr) ((int) (sizeof(arr) / sizeof(arr[0]))) /* \ | / */ + /* \|/ */ +static char *widgetGetFontName(); /* MF016 */ + + +static void do_text(); +static void do_userproc(); +static void do_popup(); +static void do_popdown(); +static XtActionsRec widget_actions[] = { + {"call", do_userproc}, + {"do_text", do_text}, + {"popup", do_popup}, + {"popdown", do_popdown}, +}; + +static void call_callbacks(); +static void widgetEvent(), widgetSetDestroy(), widgetDestroy(); +static void widgetCallback(), widgetSCCallback(), widgetJPCallback(); +static void widgetSPCallback(), widgetPUCallback(), widgetPDCallback(); +static void widgetSBCallback(), widgetSECallback(), widgetRPCallback(); +static void widgetRGCallback(), widgetLTHCallback(), widgetLTACallback(); +static void widgetTCCCallback(); +static int widgetSet(), widgetGet(), widgetMap(), widgetUnmap(); +static int widgetRealize(), widgetUnrealize(), widgetIsRealized(); +static int widgetPopup(), widgetPopupSpringLoaded(), widgetPopdown(); +static int widgetAddCallback(), widgetDeleteCallback(); +static int widgetMove(), widgetResize(), widgetConfigure(); +static int widgetParseGeometry(), widgetGetGeometry(); +static int widgetSetSensitive(), widgetIsSensitive(); +static int widgetManage(), widgetUnmanage(), widgetAppend(); +static int widgetAddEventHandler(), widgetRemoveEventHandler(); +static int widgetHighlight(), widgetUnhighlight(), widgetSetTop(); +static int widgetSetList(), widgetGetItem(), widgetGetValue(); +static int widgetGetThumb(), widgetMoveThumb(), widgetResizeThumb(); +static int widgetSetScrollbar(), widgetSetTTName(), widgetGetTTName(); +static int widgetSetListTree(), widgetListTreeSelect(); +static int widgetListTreeHighlight(), widgetListTreeDelete(); +static int widgetSetLocation(), widgetSetCoordinates(); +static int widgetSetTable(), widgetSetCellAttr(), widgetGetCellAttr(); +static int widgetGetColAttr(), widgetSetColAttr(), widgetSetRowAttr(); +static int widgetDeleteRow(), widgetAddRow(), widgetGetTableSize(); +static int widgetDeleteCol(), widgetAddCol(), widgetSetTableSize(); +static int get_itemno(), buildTreeList(), widgetGetRowAttr(); + + +/* WidgetClassInit -- Initialize the class record for the widget class. + */ +void +WidgetClassInit (obm, classrec) +ObmContext obm; +register ObjClassRec classrec; +{ + register int hashval, n; + register char *ip; + ObjClassRec widgetclass; + static int hashed = 0; + Tcl_Interp *tcl; + MsgContext msg; + Rtype rp, hp; + int i; + + /* The base class for all Widget classes is "Widget". */ + widgetclass = obmGetClassrec ("Widget"); + + /* Install the class methods. */ + classrec->ClassDestroy = WidgetClassDestroy; + classrec->Create = (ObmFunc) WidgetCreate; + classrec->Destroy = WidgetDestroy; + classrec->Evaluate = WidgetEvaluate; + + /* Since there can be many instances of the widget object and they + * all respond to the same class messages, a single interpreter is + * used for all widget instances. By default all Widget subclasses + * use the interperter for the base Widget class. + */ + if (!widgetclass->class_data) { + msg = (MsgContext) XtMalloc (sizeof (struct msgContext)); + msg->tcl = tcl = Tcl_CreateInterp(); + widgetclass->class_data = (XtPointer) msg; + msg->level = 0; + + /* Register widget-object actions. */ + Tcl_CreateCommand (tcl, + "addCallback", widgetAddCallback, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "deleteCallback", widgetDeleteCallback, (ClientData)msg, + NULL); + Tcl_CreateCommand (tcl, + "addEventHandler", widgetAddEventHandler, (ClientData)msg, + NULL); + Tcl_CreateCommand (tcl, + "removeEventHandler", widgetRemoveEventHandler, + (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "set", widgetSet, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "get", widgetGet, (ClientData)msg, NULL); + + /* Text Widget Callbacks */ + Tcl_CreateCommand (tcl, + "append", widgetAppend, (ClientData)msg, NULL); + + /* List Widget Callbacks */ + Tcl_CreateCommand (tcl, + "setList", widgetSetList, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "getItem", widgetGetItem, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "highlight", widgetHighlight, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "unhighlight", widgetUnhighlight, (ClientData)msg, NULL); + + /* Dialog Widget Callbacks */ + Tcl_CreateCommand (tcl, + "getValue", widgetGetValue, (ClientData)msg, NULL); + + /* Slider Widget Callbacks */ + Tcl_CreateCommand (tcl, + "getThumb", widgetGetThumb, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "moveThumb", widgetMoveThumb, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "resizeThumb", widgetResizeThumb, (ClientData)msg, NULL); + + /* Scrollbar Widget Callbacks */ + Tcl_CreateCommand (tcl, + "setScrollbar", widgetSetScrollbar, (ClientData)msg, NULL); + + /* Viewport Widget Callbacks */ + Tcl_CreateCommand (tcl, + "setLocation", widgetSetLocation, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "setCoordinates", widgetSetCoordinates, (ClientData)msg, NULL); + + /* Tabs Widget Callbacks */ + Tcl_CreateCommand (tcl, + "setTop", widgetSetTop, (ClientData)msg, NULL); + + /* Tree Widget Callbacks */ + Tcl_CreateCommand (tcl, + "setListTree", widgetSetListTree, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "listTreeSelect", widgetListTreeSelect, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "listTreeDelete", widgetListTreeDelete, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "listTreeHighlight", widgetListTreeHighlight, + (ClientData)msg, NULL); + + /* Table Widget Callbacks */ + Tcl_CreateCommand (tcl, + "setTable", widgetSetTable, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "getCellAttr", widgetGetCellAttr, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "setCellAttr", widgetSetCellAttr, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "setColAttr", widgetSetColAttr, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "getColAttr", widgetGetColAttr, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "setRowAttr", widgetSetRowAttr, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "getRowAttr", widgetGetRowAttr, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "deleteCol", widgetDeleteCol, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "deleteRow", widgetDeleteRow, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "addCol", widgetAddCol, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "addRow", widgetAddRow, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "setTableSize", widgetSetTableSize, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "getTableSize", widgetGetTableSize, (ClientData)msg, NULL); + + Tcl_CreateCommand (tcl, + "realize", widgetRealize, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "unrealize", widgetUnrealize, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "isRealized", widgetIsRealized, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "map", widgetMap, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "unmap", widgetUnmap, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "manage", widgetManage, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "unmanage", widgetUnmanage, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "popup", widgetPopup, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "popupSpringLoaded", widgetPopupSpringLoaded, + (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "popdown", widgetPopdown, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "setSensitive", widgetSetSensitive, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "isSensitive", widgetIsSensitive, (ClientData)msg, NULL); + + Tcl_CreateCommand (tcl, + "move", widgetMove, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "resize", widgetResize, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "configure", widgetConfigure, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "parseGeometry", widgetParseGeometry, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "getGeometry", widgetGetGeometry, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "setTTName", widgetSetTTName, (ClientData)msg, NULL); + Tcl_CreateCommand (tcl, + "getTTName", widgetGetTTName, (ClientData)msg, NULL); + + /* Register any actions. */ + XtAppAddActions (obm->app_context, widget_actions, + XtNumber(widget_actions)); + XtRegisterGrabAction (do_popup, True, + (unsigned)(ButtonPressMask | ButtonReleaseMask), + GrabModeAsync, GrabModeAsync); + } + + /* Build a hash index for the global widget resources table. */ + if (!hashed) { + for (i=0; i < XtNumber(ObmResources); i++) { + rp = &ObmResources[i]; + n = MAX_HASHCHARS; + for (hashval=0, ip=rp->name; --n >= 0 && *ip; ip++) + hashval += (hashval + *ip); + if (hp = rhash[hashval%LEN_RHASH]) { + for ( ; hp->next; hp = hp->next) + ; + hp->next = rp; + } else + rhash[hashval%LEN_RHASH] = rp; + } + hashed++; + } +} + + +/* WidgetClassDestroy -- Custom destroy procedure for the widget class. + */ +void +WidgetClassDestroy (obm, classrec) +ObmContext obm; +register ObjClassRec classrec; +{ + register MsgContext msg = (MsgContext) classrec->class_data; + + if (msg) { + if (msg->tcl) + Tcl_DeleteInterp (msg->tcl); + XtFree ((char *)msg); + classrec->class_data = NULL; + } +} + + +/* WidgetCreate -- Create an instance of a widget object. + */ +ObmObject +WidgetCreate (obm, name, classrec, parent, args, nargs) +ObmContext obm; +char *name; +ObjClassRec classrec; +char *parent; +ArgList args; +int nargs; +{ + register WidgetObject obj, pobj; + Widget w, pw; + + /* Create the widget object descriptor. */ + obj = (WidgetObject) XtCalloc (1, sizeof (struct widgetObject)); + obj->widget.obm = obm; + + /* The widget "toplevel" is a special case. This is the toplevel + * widget of the entire application and it is created separately + * when the application starts up. When we are called to "create" + * this widget all we do is create a descriptor for it, so that it + * will appear in the object list like any other widget. + */ + if (strcmp (name, "toplevel") == 0) { + w = obm->toplevel; + pw = NULL; + } else { + /* Convert parent name to Widget. */ + if ((pobj = (WidgetObject) obmFindObject (obm, parent)) == NULL) + return (NULL); + pw = pobj->widget.w; + + /* Create the widget. */ + if (classrec->object_type == OtShell) { + w = XtCreatePopupShell (name, + *classrec->widget_class, pw, args, nargs); + } else if (obmClass (classrec, WtObject)) { + w = XtCreateWidget (name, + *classrec->widget_class, pw, args, nargs); + } else { + w = XtCreateManagedWidget (name, + *classrec->widget_class, pw, args, nargs); + } + } + + /* Set the pointer to the superclass if subclass of Widget. */ + if (strcmp (classrec->name, "Widget") != 0) + obj->core.superclass = obmGetClassrec ("Widget"); + + /* Register any class callback procedures. */ + if (obmClass (classrec, WtGrip) || + obmClass (classrec, WtList) || + obmClass (classrec, WtMultiList) || + obmClass (classrec, WtSmeBSB) || + obmClass (classrec, WtCommand) || + obmClass (classrec, WtMenuButton) || + obmClass (classrec, WtTabs) || + obmClass (classrec, WtToggle) || + obmClass (classrec, WtArrow)) { + + XtAddCallback (w, XtNcallback, widgetCallback, obj); + + } else if (obmClass (classrec, WtListTree)) { + XtAddCallback (w, XtNhighlightCallback, widgetLTHCallback, obj); + XtAddCallback (w, XtNactivateCallback, widgetLTACallback, obj); + + } else if (obmClass (classrec, WtRepeater)) { + XtAddCallback (w, XtNcallback, widgetCallback, obj); + XtAddCallback (w, XtNstartCallback, widgetSBCallback, obj); + XtAddCallback (w, XtNstopCallback, widgetSECallback, obj); + + } else if (obmClass (classrec, WtStripChart)) { + XtAddCallback (w, XtNgetValue, widgetSCCallback, obj); + + } else if (obmClass (classrec, WtScrollbar)) { + XtAddCallback (w, XtNjumpProc, widgetJPCallback, obj); + XtAddCallback (w, XtNscrollProc, widgetSPCallback, obj); + + } else if (obmClass (classrec, WtShell) || + obmClass (classrec, WtSimpleMenu)) { + + XtAddCallback (w, XtNpopupCallback, widgetPUCallback, obj); + XtAddCallback (w, XtNpopdownCallback, widgetPDCallback, obj); + + } else if (obmClass (classrec, WtPanner) || + obmClass (classrec, WtPorthole) || + obmClass (classrec, WtViewport)) { + + XtAddCallback (w, XtNreportCallback, widgetRPCallback, obj); + + } else if (obmClass (classrec, WtTextButton) || + obmClass (classrec, WtIcon)) { + XtAddCallback (w, XtNactivate, widgetCallback, obj); + + } else if (obmClass (classrec, WtGroup) || + obmClass (classrec, WtRadioGroup)) { + XtAddCallback (w, XtNactivate, widgetRGCallback, obj); + + } else if (obmClass (classrec, WtTextToggle)) { + XtAddCallback (w, XtNonCallback, widgetCallback, obj); + XtAddCallback (w, XtNoffCallback, widgetCallback, obj); + + } else if (obmClass (classrec, WtSlider2d) || + obmClass (classrec, WtScrollbar2)) { + + XtVaGetValues (w, "scrollResponse", &obj->widget.response_cb, NULL); + XtAddCallback (w, XtNscrollCallback, widgetJPCallback, obj); + XtAddCallback (w, XtNscrollCallback, widgetSPCallback, obj); + } + + obj->widget.w = w; + strcpy (obj->widget.translation_table_name, name); + return ((ObmObject) obj); +} + + +/* WidgetDestroy -- Destroy an instance of a widget object. + */ +void +WidgetDestroy (object) +ObmObject object; +{ + register WidgetObject obj = (WidgetObject) object; + register WidgetPrivate wp = &obj->widget; + register ObmCallback cb, next; + + /* Ignore the second call to Destroy. */ + if (obj->core.being_destroyed++) + return; + + /* Free any callback descriptors. */ + for (cb = wp->callback; cb; cb = next) { + next = cb->next; + XtFree ((char *)cb); + } + + /* Free any event handler descriptors. */ + for (cb = wp->event_handler; cb; cb = next) { + next = cb->next; + XtFree ((char *)cb); + } + + /* Free any object data. Note that free is used, not XtFree, i.e. + * we can't assume that Xt allocated the buffer. + */ + if (wp->data) + free (wp->data); + + /* Mark any widget children as being destroyed so that we don't try + * to destroy them twice. + */ + if (!wp->widget_destroyed) { + widgetSetDestroy (object); + widgetDestroy (obj); + } +} + + +/* widgetSetDestroy -- Set the being_destroyed flag on all the children of a + * widget object to indicate that the widget itself has already been destroyed. + * This happens when a widget tree is destroyed in one toolkit call by + * destroying the top level widget, leaving the object descriptors intact + * while the widgets have already been destroyed. + */ +static void +widgetSetDestroy (obj) +register ObmObject obj; +{ + register int i; + ObmObject child; + int object_type; + + for (i=0; i < obj->core.nchildren; i++) { + child = obj->core.children[i]; + object_type = child->core.classrec->object_type; + if (object_type == OtShell || object_type == OtNonShell) + widgetSetDestroy (child); + } + + ((WidgetObject)obj)->widget.widget_destroyed = True; +} + + +/* widgetDestroy -- Destroy a widget and all of its descendents. We can't + * just call XtDestroyWidget to do this because while this will destroy all + * the normal and popup children of a widget, it won't destroy any top level + * shells and their children. + */ +static void +widgetDestroy (obj) +register ObmObject obj; +{ + register int i; + WidgetObject wobj = (WidgetObject) obj; + WidgetClass *widget_class; + ObmObject child; + int object_type; + + for (i=0; i < obj->core.nchildren; i++) { + child = obj->core.children[i]; + widget_class = child->core.classrec->widget_class; + if (widget_class == &topLevelShellWidgetClass) + widgetDestroy (child); + } + + XtUnrealizeWidget (wobj->widget.w); + XtDestroyWidget (wobj->widget.w); +} + + +/* WidgetEvaluate -- Evaluate a widget command or message. + */ +WidgetEvaluate (object, command) +ObmObject object; +char *command; +{ + register WidgetObject obj = (WidgetObject) object; + register Tcl_Interp *tcl, *server = obj->widget.obm->tcl; + MsgContext omsg = (MsgContext) obj->core.classrec->class_data; + MsgContext pmsg = (MsgContext) obj->core.superclass->class_data; + + /* Since the class wide interpreter is used to evaluate the message + * we can't pass the object descriptor directly to the class procedure + * referenced in the message. Instead we pass the object reference + * in the message descriptor. + */ + Tcl_SetResult (server, "", TCL_STATIC); + + /* First try to get the widget subclass to accept the message. */ + if (omsg && (tcl = omsg->tcl) && obmClientCommand(tcl,command)) { + omsg->object[++omsg->level] = object; + if (Tcl_Eval (tcl, command) == TCL_OK) { + if (*tcl->result) + Tcl_SetResult (server, tcl->result, TCL_VOLATILE); + omsg->level--; + return (TCL_OK); + + } else { + static char invalid[] = "invalid command name"; + omsg->level--; + + /* Exit with an error return if the class code recognized + * the command but failed to execute it. + */ + if (strncmp (tcl->result, invalid, strlen(invalid)) != 0) + goto error; + } + } + + /* If the subclass code did not recognize the command pass the + * message on to the base Widget class. + */ + if (pmsg && pmsg != omsg && (tcl = pmsg->tcl) && + obmClientCommand(tcl,command)) { + pmsg->object[++pmsg->level] = object; + if (Tcl_Eval (tcl, command) == TCL_OK) { + if (*tcl->result) + Tcl_SetResult (server, tcl->result, TCL_VOLATILE); + pmsg->level--; + return (TCL_OK); + } else + pmsg->level--; + } + +error: + if (*tcl->result) + Tcl_SetResult (server, tcl->result, TCL_VOLATILE); + else { + /* Supply a default error message if none was returned. */ + Tcl_SetResult (server, obmClientCommand (tcl, command) ? + "evaluation error" : "invalid command", TCL_VOLATILE); + } + server->errorLine = tcl->errorLine; + return (TCL_ERROR); +} + + +/* widgetGetPointer -- Return the widget descriptor for an object of class + * widget. Used by non-widget Obm code to get the widget handle from an + * object descriptor. + */ +Widget +widgetGetPointer (object) +ObmObject object; +{ + register WidgetObject obj = (WidgetObject) object; + return (obj->widget.w); +} + + +/* widgetToObject -- Convert a widget pointer to an OBM object name. + */ +WidgetObject +widgetToObject (obm, w) +ObmContext obm; +Widget w; +{ + register int i; + register WidgetPrivate wp; + ObmObject objs[256]; + int nobjs; + + obm_nameToObjectList (obm, XtName(w), NULL, &nobjs, objs); + for (i=0; i < nobjs; i++) + wp = &((WidgetObject)objs[i])->widget; + if (wp->w == w) + return ((WidgetObject)objs[i]); + + return (NULL); +} + + +/* widgetAddCallback -- Add a callback procedure to the callback list for + * a widget. If no callback name is given, "callback" is assumed. + * + * Usage: addCallback <procedure-name> [<callback-name>] + * + * Specific widgets only support certain types of callbacks. There is no + * checking that the callback type specified is supported by a widget; the + * wrong type of callback can be registered, but it will never be called. + */ +static int +widgetAddCallback (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + register WidgetObject obj = (WidgetObject) msg->object[msg->level]; + register WidgetPrivate wp = &obj->widget; + ObmCallback cb, new_cb; + char *s_proc, *s_type; + int callback_type, i; + + s_proc = argv[1]; + s_type = (argc > 2) ? argv[2] : NULL; + + /* Determine callback type. */ + if (s_type) { + callback_type = Ctcallback; + for (i=0; i < XtNumber(callbackTypes); i++) + if (strcmp (s_type, callbackTypes[i].name) == 0) { + callback_type = callbackTypes[i].type; + break; + } + } else if (obmClass (obj->core.classrec, WtAsciiText)) { + callback_type = Ctlinemode; + } else if (obmClass (obj->core.classrec, WtPanner) || + obmClass (obj->core.classrec, WtPorthole) || + obmClass (obj->core.classrec, WtViewport)) { + callback_type = CtreportCallback; + } else if (obmClass (obj->core.classrec, WtSlider2d) || + obmClass (obj->core.classrec, WtScrollbar2) || + obmClass (obj->core.classrec, WtScrollbar)) { + callback_type = CtjumpProc; + } else + callback_type = Ctcallback; + + /* Special handling for asciiText callbacks. */ + if (obmClass (obj->core.classrec, WtAsciiText)) + if (callback_type == Ctlinemode) { + char text_translations[SZ_LINE]; + XtTranslations translations; + sprintf (text_translations, "<Key>Return: do_text(0x%lx, %s) ", + wp->obm, XtName(wp->w)); + translations = XtParseTranslationTable (text_translations); + XtOverrideTranslations (wp->w, translations); + } else { + XtAddCallback (XawTextGetSource(wp->w), XtNcallback, + widgetCallback, obj); + } + + /* Create callback record. */ + new_cb = (ObmCallback) XtCalloc (1, sizeof (obmCallback)); + new_cb->callback_type = callback_type; + strncpy (new_cb->name, s_proc, SZ_NAME); + + /* Add callback to tail of callback list. */ + if (wp->callback) { + for (cb = wp->callback; cb->next; cb = cb->next) + ; + cb->next = new_cb; + } else + wp->callback = new_cb; + + return (TCL_OK); +} + + +/* widgetDeleteCallback -- Delete a callback procedure previously registered + * for a widget. + * + * Usage: deleteCallback <procedure-name> + */ +static int +widgetDeleteCallback (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + register WidgetObject obj = (WidgetObject) msg->object[msg->level]; + register WidgetPrivate wp = &obj->widget; + ObmCallback cb, prev; + + /* Locate and delete procedure entry in callback list. */ + for (prev=NULL, cb=wp->callback; cb; prev=cb, cb=cb->next) + if (strcmp (cb->name, argv[1]) == 0) { + if (prev) + prev->next = cb->next; + else + wp->callback = cb->next; + XtFree ((char *)cb); + break; + } + + return (TCL_OK); +} + + +/* widgetCallback -- Generic callback procedure, used for most widgets. + * The callback procedure is called with the widget name as the first + * argument, followed by zero or more additional arguments which depend upon + * the callback type. + */ +static void +widgetCallback (w, obj, call_data) +Widget w; +WidgetObject obj; +caddr_t call_data; +{ + register WidgetPrivate wp = &obj->widget; + register ObjClassRec classrec = obj->core.classrec; + char buffer[SZ_COMMAND]; + char *message = buffer; + int callback_type, i; + + /* Default callback type. */ + callback_type = Ctcallback; + + if (obmClass (classrec, WtAsciiSrc) || + obmClass (classrec, WtAsciiText)) { + + char *string; + Arg args[1]; + + XtSetArg (args[0], "string", &string); + XtGetValues (wp->w, args, 1); + sprintf (message, "{%s}", string); + callback_type = Ctcharmode; + + } else if (obmClass (classrec, WtGrip)) { + GripCallDataRec *grip = (GripCallDataRec *) call_data; + + /* The message, if any, is given in the grip translation table + * as the arguments to the GripAction routine. These differ + * depending upon the event; we just pass on the arguments and + * ignore the event attributes. + */ + message[0] = '\0'; + for (i=0; i < grip->num_params; i++) { + strcat (message, " "); + strcat (message, grip->params[i]); + } + + } else if (obmClass (classrec, WtList)) { + XawListReturnStruct *list = (XawListReturnStruct *) call_data; + + /* The message is the string value of the list element + * selected, followed by its index. + */ + sprintf (message, "{%s} %d", list->string, list->list_index); + + } else if (obmClass (classrec, WtMultiList)) { + XfwfMultiListReturnStruct *list = + (XfwfMultiListReturnStruct *) call_data; + Boolean state, sensitive; + register char *ip, *op; + int buflen, need, i; + char *string; + + /* The message consists of an array of string values of the + * currently selected list elements in the form { {s} {s} ...}, + * followed by a array of the indices { n n ...}. + */ + buflen = SZ_COMMAND; + if (!(message = XtMalloc (buflen))) + return; + + /* Generate list of item strings. */ + op = message; + *op++ = '{'; + for (i=0; i < list->num_selected; i++) { + XfwfMultiListGetItemInfo ((XfwfMultiListWidget)wp->w, + list->selected_items[i], &string, &state, &sensitive); + need = strlen(string)+3 + list->num_selected * 6; + if (buflen < (op-message)+need) { + buflen += max (need, SZ_COMMAND); + if (!(message = XtRealloc (buffer, buflen))) + return; + } + *op++ = ' '; + *op++ = '{'; + for (ip=string; *op = *ip++; op++) + ; + *op++ = '}'; + } + *op++ = ' '; + *op++ = '}'; + + /* Append list of indices. We allocated space for these above. */ + *op++ = ' '; + *op++ = '{'; + for (i=0; i < list->num_selected; i++) { + sprintf (op, " %d", list->selected_items[i]); + while (*op) + op++; + } + *op++ = ' '; + *op++ = '}'; + *op++ = '\0'; + + } else if (obmClass (classrec, WtToggle)) { + Arg args[1]; + Boolean state; + + /* The callback for a toggle does not pass any call data, + * but we return the value of the "state" resource anyway + * to indicate the state of the toggle. + */ + XtSetArg (args[0], XtNstate, &state); + XtGetValues (wp->w, args, 1); + sprintf (message, "%s", state ? TRUESTR : FALSESTR); + + } else if (obmClass (classrec, WtTextToggle)) { + Arg args[1]; + Boolean state; + + /* For this widget the value of the "on" resource indicates + * the state of the toggle. + */ + XtSetArg (args[0], XtNon, &state); + XtGetValues (wp->w, args, 1); + sprintf (message, "%s", state ? TRUESTR : FALSESTR); + + } else { + /* The default case, which works for most simple callbacks. + * Only the widget name is returned. + */ + message = NULL; + } + + call_callbacks (obj, callback_type, message); + + if (message && message != buffer) + XtFree (message); +} + + +/* widgetRGCallback -- Radiogroup or Group callback. The argument list for + * the callback is one of the following: + * + * selectionStyle = multiple: widget-name { label label ... } + * selectionStyle = one,single: widget-name [label | "none"] + * + * Here label refers to the label of the selected TextToggle widget or widgets. + * In the case of selectionStyle=multiple, the list will be empty if no widgets + * are currently selected. + */ +static void +widgetRGCallback (w, obj, call_data) +Widget w; +WidgetObject obj; +caddr_t call_data; +{ + register WidgetPrivate wp = &obj->widget; + long selection = (long) call_data; + register char *op; + register int i; + + char message[SZ_COMMAND]; + SelectionType selectionType; + WidgetList children; + Cardinal nchildren; + Arg args[10]; + char *label; + + /* Get list of child widgets in the group. */ + XtSetArg (args[0], XtNselectionStyle, &selectionType); + XtSetArg (args[1], XtNnumChildren, &nchildren); + XtSetArg (args[2], XtNchildren, &children); + XtGetValues (wp->w, args, 3); + + op = message; + if (selectionType == XfwfMultipleSelection) { + *op++ = '{'; + for (i=0; selection > 0 && i < min(32,nchildren); i++) + if (selection & (1 << i)) { + XtSetArg (args[0], XtNlabel, &label); + XtGetValues (children[i], args, 1); + *op++ = ' '; + sprintf (op, "\"%s\"", label); + while (*op) + op++; + } + *op++ = '}'; + + } else { + if (selection < 0 || selection >= nchildren) + label = "none"; + else { + XtSetArg (args[0], XtNlabel, &label); + XtGetValues (children[selection], args, 1); + } + sprintf (op, "\"%s\"", label); + while (*op) + op++; + } + *op++ = '\0'; + + call_callbacks (obj, Ctcallback, message); +} + + +/* widgetLTHCallback -- ListTree highlight callback. + */ +static void +widgetLTHCallback (w, obj, call_data) +Widget w; +WidgetObject obj; +caddr_t call_data; +{ + ListTreeMultiReturnStruct *list; + ListTreeItem *item; + char message[SZ_COMMAND], buf[SZ_LINE]; + register int i; + + list = (ListTreeMultiReturnStruct *) call_data; + if (!list->items) + return; + + + /* The message is the string value of the list element selected + * and a bottom-up path to the root. + */ + sprintf (message, "{%s %d} ", + list->items[0]->text, list->items[0]->open); + + strncat (message, "{ ", 2); + for (i=0; i < list->count; i++) { + item = list->items[i]; + sprintf (buf, "{ %s } ", item->text); + strcat (message, buf); + while (item->parent) { + item = item->parent; + sprintf (buf, "{ %s } ", item->text); + strcat (message, buf); + } + } + strncat (message, "}", 1); + + call_callbacks (obj, Ctcallback, message); +} + + +/* widgetLTACallback -- ListTree activate callback. + */ +static void +widgetLTACallback (w, obj, call_data) +Widget w; +WidgetObject obj; +caddr_t call_data; +{ + ListTreeActivateStruct *ret; + ListTreeMultiReturnStruct ret2; + ListTreeItem *item; + char message[SZ_COMMAND], buf[SZ_LINE]; + int i, count; + + ret = (ListTreeActivateStruct *) call_data; + + /* The message is the string value of the list element selected, + * and a bottom-up path to the root. + */ + sprintf (message, "{%s %d} ", ret->item->text, ret->item->open); + + strncat (message, "{ ", 2); + item = ret->item; + sprintf (buf, "{ %s } ", item->text); + strcat (message, buf); + while (item->parent) { + item = item->parent; + sprintf (buf, "{ %s } ", item->text); + strcat (message, buf); + } + strncat (message, "}", 1); + + call_callbacks (obj, Ctcallback, message); +} + + +/* widgetSBCallback -- Repeater start callback. + */ +static void +widgetSBCallback (w, obj, call_data) +Widget w; +WidgetObject obj; +caddr_t call_data; +{ + register WidgetPrivate wp = &obj->widget; + call_callbacks (obj, CtstartCallback, NULL); +} + + +/* widgetSECallback -- Repeater stop callback. + */ +static void +widgetSECallback (w, obj, call_data) +Widget w; +WidgetObject obj; +caddr_t call_data; +{ + register WidgetPrivate wp = &obj->widget; + call_callbacks (obj, CtstopCallback, NULL); +} + + +/* widgetRPCallback -- Report callback used by the panner, porthole, and + * viewport widgets to report any changes in the position or size of the + * thumb (panner) or child widget (porthole, viewport). + */ +static void +widgetRPCallback (w, obj, call_data) +Widget w; +WidgetObject obj; +caddr_t call_data; +{ + register WidgetPrivate wp = &obj->widget; + register XawPannerReport *rp = (XawPannerReport *) call_data; + char message[100]; + + /* Return args: changed x y w h cw ch */ + sprintf (message, "0%o %d %d %d %d %d %d", rp->changed, + rp->slider_x, rp->slider_y, rp->slider_width, rp->slider_height, + rp->canvas_width, rp->canvas_height); + + call_callbacks (obj, CtreportCallback, message); +} + + +/* widgetJPCallback -- Jump callback for the scroll bar widget. This is + * called when the thumb port of the scroll bar is dragged or moved (button 2). + */ +static void +widgetJPCallback (w, obj, call_data) +Widget w; +WidgetObject obj; +caddr_t call_data; +{ + register WidgetPrivate wp = &obj->widget; + XfwfScrollInfo *info = (XfwfScrollInfo *) call_data; + XfwfScrollInfo update_info; + register int flags = info->flags; + char message[100]; + + if (obmClass (obj->core.classrec, WtScrollbar)) { + /* Athena scrollbar. The call_data gives the position of the + * thumb in percent. + */ + sprintf (message, "%0.6f", *((float *)call_data)); + call_callbacks (obj, CtjumpProc, message); + + } else if (info->reason != XfwfSDrag) { + /* Slider2d callback: widget-name x y + * Scrollbar2 callback: widget-name fraction + * + * Scrollbars return the same fraction value regardless of + * whether the scrollbar is vertical or horizontal. + * widgetSPCallback below is always called when the slider moves, + * so we don't need to call response_cb here. + */ + if (obmClass (obj->core.classrec, WtSlider2d)) { + XfwfGetThumb (wp->w, &update_info); + sprintf (message, "%0.5f %0.5f", + (flags & XFWF_HPOS) ? info->hpos : update_info.hpos, + (flags & XFWF_VPOS) ? info->vpos : update_info.vpos); + } else { + if (info->flags & XFWF_HPOS) + sprintf (message, "%0.5f", info->hpos); + else if (info->flags & XFWF_VPOS) + sprintf (message, "%0.5f", info->vpos); + } + + /* Call the callbacks. */ + call_callbacks (obj, CtjumpProc, message); + } +} + + +/* widgetSPCallback -- Scroll callback for the scroll bar widget. This is + * used for incremental scrolling (button 1 or 3). + */ +static void +widgetSPCallback (w, obj, call_data) +Widget w; +WidgetObject obj; +caddr_t call_data; +{ + register WidgetPrivate wp = &obj->widget; + char message[100]; + + if (obmClass (obj->core.classrec, WtScrollbar)) { + /* Athena scrollbar. The call_data gives the distance in pixels + * of the pointer from the top of the scrollbar, and is positive + * for button 1 and negative for button 3. + */ + sprintf (message, "%d", (int)call_data); + call_callbacks (obj, CtscrollProc, message); + + } else { + /* FWF scrollbar2 or slider2d. + */ + XfwfScrollInfo *info = (XfwfScrollInfo *) call_data; + XfwfScrollInfo update_info; + register int flags = info->flags; + + /* Slider2d callback: widget-name x y + * Scrollbar2 callback: widget-name fraction + * + * Scrollbars return the same fraction value regardless of + * whether the scrollbar is vertical or horizontal. + */ + if (obmClass (obj->core.classrec, WtSlider2d)) { + XfwfGetThumb (wp->w, &update_info); + sprintf (message, "%0.5f %0.5f", + (flags & XFWF_HPOS) ? info->hpos : update_info.hpos, + (flags & XFWF_VPOS) ? info->vpos : update_info.vpos); + } else { + if (flags & XFWF_HPOS) + sprintf (message, "%0.5f", info->hpos); + else if (flags & XFWF_VPOS) + sprintf (message, "%0.5f", info->vpos); + } + + /* Call the callbacks. */ + call_callbacks (obj, CtscrollProc, message); + + /* Update the slider. */ + update_info = *info; + update_info.reason = XfwfSNotify; + wp->response_cb (NULL, w, (caddr_t) &update_info); + } +} + + +/* widgetSCCallback -- Strip chart callback procedure. This is called by the + * strip chart widget every "update" seconds to get the next value to be + * plotted. + */ +static void +widgetSCCallback (w, obj, call_data) +Widget w; +WidgetObject obj; +caddr_t call_data; +{ + register WidgetPrivate wp = &obj->widget; + register ObmContext obm = wp->obm; + char *callback_name; + ObmCallback cb; + double atof(); + int status, i; + + callback_name = "getValue"; + for (i=0; i < XtNumber(callbackTypes); i++) + if (callbackTypes[i].type == CtgetValue) { + callback_name = callbackTypes[i].name; + break; + } + + /* Call the callback procedure to get the next value to be plotted + * in the strip chart. This is a numeric (e.g. floating point) value + * returned as the function value of the callback procedure. Multiple + * callbacks can be registered, but only the first such procedure + * will be called. + */ + for (cb = wp->callback; cb; cb = cb->next) { + if (cb->callback_type != CtgetValue) + continue; + status = Tcl_VarEval (obm->tcl, + cb->name, " ", + obj->core.name, " ", + callback_name, " ", + NULL); + if (status == TCL_OK) + *((double *)call_data) = atof (obm->tcl->result); + else { + char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0); + fprintf (stderr, "Error on line %d in %s: %s\n", + obm->tcl->errorLine, cb->name, + errstr ? errstr : obm->tcl->result); + } + break; + } +} + + +/* widgetPUCallback -- Popup callback, used by the shell and simpleMenu + * widgets. Called when the window pops up. + */ +static void +widgetPUCallback (w, obj, call_data) +Widget w; +WidgetObject obj; +caddr_t call_data; +{ + register WidgetPrivate wp = &obj->widget; + call_callbacks (obj, CtpopupCallback, NULL); +} + + +/* widgetPDCallback -- Popdown callback, used by the shell and simpleMenu + * widgets. Called when the window pops down. + */ +static void +widgetPDCallback (w, obj, call_data) +Widget w; +WidgetObject obj; +caddr_t call_data; +{ + register WidgetPrivate wp = &obj->widget; + call_callbacks (obj, CtpopdownCallback, NULL); +} + + +/* call_callbacks -- Call all the callbacks of the given type for the given + * widget object, passing the given message on the argument list. + */ +static void +call_callbacks (obj, callback_type, message) +WidgetObject obj; +int callback_type; +char *message; +{ + register WidgetPrivate wp = &obj->widget; + register ObmContext obm = wp->obm; + register ObmCallback cb; + char *callback_name; + int status, i; + + callback_name = callbackTypes[0].name; + for (i=0; i < XtNumber(callbackTypes); i++) + if (callback_type == callbackTypes[i].type) { + callback_name = callbackTypes[i].name; + break; + } + + /* Deliver the message to all the callback procedures registered for + * this widget for which the callback type matches. The callback + * arguments are: + * + * widget-name callback-name callback-args + * + * where the callback-args depend on the callback. + */ + for (cb = wp->callback; cb; cb = cb->next) { + if (cb->callback_type != callback_type) + continue; + + if (message) { + status = Tcl_VarEval (obm->tcl, + cb->name, " ", + obj->core.name, " ", + callback_name, " ", + message, " ", + NULL); + } else { + status = Tcl_VarEval (obm->tcl, + cb->name, " ", + obj->core.name, " ", + callback_name, " ", + NULL); + } + + if (status != TCL_OK) { + char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0); + fprintf (stderr, "Error on line %d in %s: %s\n", + obm->tcl->errorLine, cb->name, + errstr ? errstr : obm->tcl->result); + } + } +} + + +/* do_text -- Translation action procedure for the text widget, called when + * return is typed to process an input string ("linemode" callback type). + */ +static void +do_text (w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + char *message, *s; + WidgetObject obj; + ObmCallback cb; + Arg args[1]; + + /* do_text (0xXXXX, object-name) */ + if (*num_params >= 2) { + ObmContext obm = (ObmContext) strtol (params[0], NULL, 0); + char *object = params[1]; + + if (obm && (obj = (WidgetObject) obmFindObject (obm, object))) { + XtSetArg (args[0], XtNstring, &s); + XtGetValues (obj->widget.w, args, 1); + + if (!(message = XtMalloc (strlen(s) + 10))) + return; + sprintf (message, "{%s}", s); + + call_callbacks (obj, Ctlinemode, message); + XtFree (message); + } + } +} + + +/* do_userproc -- Translation action procedure used to call general user + * action procedures in the interpreter. The name of the user procedure to + * be called is given as the first argument in the translation. For example, + * the translation "call(foo,a,b,c)" would cause procedure foo to be called + * with the arguments (a,b,c). The following arguments are special: + * + * Argument Replaced by + * + * $name translation table name (defaults to widget name) + * $time event->time + * $x event->x + * $y event->y + * $x_root event->x_root + * $y_root event->y_root + * + * The "user procedure" can be any server procedure. + */ +static void +do_userproc (w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + register char *ip, *op; + ObmContext obm = global_obm_handle; + char cmd[SZ_COMMAND], *param; + int x, y, x_root, y_root; + int status, arg; + Time time; + + if (*num_params < 1) + return; + + time = 0; + x = y = 0; + x_root = y_root = 0; + + /* Get common event parameters. */ + switch (event->type) { + case KeyPress: + case KeyRelease: + { XKeyEvent *ev = (XKeyEvent *) event; + time = ev->time; + x = ev->x; y = ev->y; + x_root = ev->x_root; y_root = ev->y_root; + } + break; + case ButtonPress: + case ButtonRelease: + { XButtonEvent *ev = (XButtonEvent *) event; + time = ev->time; + x = ev->x; y = ev->y; + x_root = ev->x_root; y_root = ev->y_root; + } + break; + case MotionNotify: + { XMotionEvent *ev = (XMotionEvent *) event; + time = ev->time; + x = ev->x; y = ev->y; + x_root = ev->x_root; y_root = ev->y_root; + } + break; + case EnterNotify: + case LeaveNotify: + { XCrossingEvent *ev = (XCrossingEvent *) event; + time = ev->time; + x = ev->x; y = ev->y; + x_root = ev->x_root; y_root = ev->y_root; + } + break; + } + + /* Copy name of server procedure to be called. */ + for (ip=params[0], op=cmd; *ip; ) + *op++ = *ip++; + *op++ = ' '; + + /* Copy the remaining arguments. */ + for (arg=1; arg < *num_params; arg++) { + param = params[arg]; + if (*param == '$') { + if (strcmp (param, "$name") == 0) { + /* Return the current translation table name for the + * widget (defaults to the widget name). + */ + WidgetObject obj; + char *name; + + if (obj = widgetToObject (obm, w)) + name = obj->widget.translation_table_name; + else + name = XtName (w); + + for (ip = name; *ip; ) + *op++ = *ip++; + *op++ = ' '; + + } else if (strcmp (param, "$time") == 0) { + sprintf (op, "%u ", time); + while (*op) + op++; + } else if (strcmp (param, "$x") == 0) { + sprintf (op, "%d ", x); + while (*op) + op++; + } else if (strcmp (param, "$y") == 0) { + sprintf (op, "%d ", y); + while (*op) + op++; + } else if (strcmp (param, "$x_root") == 0) { + sprintf (op, "%d ", x_root); + while (*op) + op++; + } else if (strcmp (param, "$y_root") == 0) { + sprintf (op, "%d ", y_root); + while (*op) + op++; + } else { + for (ip=param; *ip; ) + *op++ = *ip++; + *op++ = ' '; + } + } else { + for (ip=param; *ip; ) + *op++ = *ip++; + *op++ = ' '; + } + } + + *op = '\0'; + status = Tcl_Eval (obm->tcl, cmd); + if (status != TCL_OK) { + fprintf (stderr, "Error on line %d of %s: %s\n", + obm->tcl->errorLine, params[0], obm->tcl->result); + } +} + + +/* widgetSetTTName -- Set the translation table name for a widget. This + * is the name passed in the $name field of a translation table action + * procedure called with the "call" action from a translation table. + * + * Usage: setTTName name + * + * The default translation table name is the name of the widget. Note that + * some widget subclasses (e.g. marker) may set the translation table name + * automatically when the widget changes the translation table. + */ +static int +widgetSetTTName (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + register WidgetObject obj = (WidgetObject) msg->object[msg->level]; + register WidgetPrivate wp = &obj->widget; + + if (argc < 2) + return (TCL_ERROR); + + widget_setTTName (obj, argv[1]); + return (TCL_OK); +} + +void +widget_setTTName (obj, name) +WidgetObject obj; +char *name; +{ + register WidgetPrivate wp = &obj->widget; + strncpy (wp->translation_table_name, name, SZ_NAME); + wp->translation_table_name[SZ_NAME-1] = '\0'; +} + + +/* widgetGetTTName -- Get the translation table name for a widget. + * + * Usage: name = getTTName + */ +static int +widgetGetTTName (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + register WidgetObject obj = (WidgetObject) msg->object[msg->level]; + register WidgetPrivate wp = &obj->widget; + + Tcl_SetResult (wp->obm->tcl, widget_getTTName(obj), TCL_VOLATILE); + return (TCL_OK); +} + +char * +widget_getTTName (obj) +WidgetObject obj; +{ + register WidgetPrivate wp = &obj->widget; + return (wp->translation_table_name); +} + + +/* do_popup -- Popup a menu (or other spring loaded popup) at the location + * of the event which triggered this action. + * + * Usage: popup(menu-name [xoffset [yoffset]]) + */ +static void +do_popup (w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + register char *ip, *op; + ObmContext obm = global_obm_handle; + XKeyEvent *ev = (XKeyEvent *) event; + Boolean spring_loaded; + Dimension menu_width, menu_height, menu_borderWidth; + Position menu_x, menu_y; + int xoffset, yoffset; + char *menu_name; + WidgetObject obj; + Widget menu; + + if (*num_params < 1) + return; + + menu_name = params[0]; + xoffset = (*num_params >= 2) ? atoi(params[1]) : -10; + yoffset = (*num_params >= 3) ? atoi(params[2]) : -10; + + if (!(obj = (WidgetObject) obmFindObject (obm, menu_name))) + return; + else + menu = obj->widget.w; + + /* Evidently SimpleMenu requires that the following be called to + * properly initialize things. + */ + if (obmClass (obj->core.classrec, WtSimpleMenu)) + XtCallActionProc (XtParent(menu), "XawPositionSimpleMenu", + event, params, *num_params); + + XtVaGetValues (menu, + XtNwidth, &menu_width, + XtNheight, &menu_height, + XtNborderWidth, &menu_borderWidth, + NULL); + + menu_width = menu_width + 2 * menu_borderWidth; + menu_height = menu_height + 2 * menu_borderWidth; + menu_x = ev->x_root + xoffset; + menu_y = ev->y_root + yoffset; + + if (menu_x >= 0) { + int scr_width = WidthOfScreen(XtScreen(menu)); + if ((int)(menu_x + menu_width) > scr_width) + menu_x = scr_width - menu_width; + } + if (menu_x < 0) + menu_x = 0; + + if (menu_y >= 0) { + int scr_height = HeightOfScreen(XtScreen(menu)); + if ((int)(menu_y + menu_height) > scr_height) + menu_y = scr_height - menu_height; + } + if (menu_y < 0) + menu_y = 0; + + XtVaSetValues (menu, + XtNx, menu_x, + XtNy, menu_y, + NULL); + + if (event->type == ButtonPress) + spring_loaded = True; + else if (event->type == KeyPress || event->type == EnterNotify) + spring_loaded = False; + else { + /* should not happen. */ + spring_loaded = False; + } + + if (spring_loaded) + XtPopupSpringLoaded (menu); + else + XtPopup (menu, XtGrabNonexclusive); +} + + +/* do_popdown -- Pop down a menu. + * + * Usage: popdown(menu-name) + */ +static void +do_popdown (w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + register char *ip, *op; + ObmContext obm = global_obm_handle; + XKeyEvent *ev = (XKeyEvent *) event; + char *menu_name; + WidgetObject obj; + Widget menu; + + if (*num_params < 1) + return; + + menu_name = params[0]; + if (obj = (WidgetObject) obmFindObject (obm, menu_name)) { + menu = obj->widget.w; + XtPopdown (menu); + } +} + + +/* widgetSet -- Set a widget resource. + * + * Usage: set <resource-name> <value> + */ +static int +widgetSet (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + register char *ip; + register int hashval, n; + register Rtype rp; + XrmValue from, to; + Arg args[1]; + + /* Lookup resource. There can be multiple entries for a given resource + * if the resource has a different type in different widgets. A + * resource entry can be used only if both the name matches and the + * bitflags indicate that the target widget uses the resource. + */ + for (hashval=0, ip=argv[1], n=MAX_HASHCHARS; --n >= 0 && *ip; ip++) + hashval += (hashval + *ip); + + if (rp = rhash[hashval%LEN_RHASH]) { + for ( ; rp; rp = rp->next) + if (!strcmp(rp->name,argv[1]) && + obmClass (obj->core.classrec, rp->flag1, rp->flag2)) + break; + } + + /* For a string type resource, no value string arg indicates the + * null string. + */ + if (!rp || argc < 3 && strcmp (rp->type, XtRString)) + return (TCL_ERROR); + + /* If the resource entry was found, convert the resource value + * from a string to whatever the resource type is, and set the + * resource value. + */ + from.size = strlen (argv[2]) + 1; + from.addr = argv[2]; + + if (strcmp (rp->type, XtRString) == 0) { + XtSetArg (args[0], rp->name, argc < 3 ? "" : argv[2]); + XtSetValues (wp->w, args, 1); + + /* The following is for text widgets. */ + if (obmClass (obj->core.classrec, WtAsciiText)) { + register ObmCallback cb; + + wp->text_newline = 0; + wp->text_pos = strlen (argv[2]); + + /* If linemode is in effect set insertion point to EOL. */ + for (cb = wp->callback; cb; cb = cb->next) + if (cb->callback_type == Ctlinemode) { + XawTextSetInsertionPoint (wp->w, wp->text_pos); + break; + } + } + + } else if (strcmp (rp->type, XtRDimension) == 0 || + strcmp (rp->type, XtRPosition) == 0) { + + Dimension value; + to.addr = (caddr_t) &value; + to.size = sizeof(value); + + /* Convert resource value. */ + if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) { + XtSetArg (args[0], rp->name, value); + XtSetValues (wp->w, args, 1); + } + + } else if (strcmp (rp->type, XtRBool) == 0 || + strcmp (rp->type, XtRBoolean) == 0) { + + Boolean value; + to.addr = (caddr_t) &value; + to.size = sizeof(value); + + /* Convert resource value. The numeric values "0" and "1" are + * permitted as well as the resource values "true" and "false". + */ + if (strcmp (from.addr, "0") == 0) { + value = False; + goto set_bval; + } else if (strcmp (from.addr, "1") == 0) { + value = True; + goto set_bval; + } else if (XtConvertAndStore (wp->w,XtRString,&from,rp->type,&to)) { +set_bval: XtSetArg (args[0], rp->name, value); + XtSetValues (wp->w, args, 1); + } + + } else if (strcmp (rp->type, XtRAtom) == 0 || + strcmp (rp->type, XtRCardinal) == 0 || + strcmp (rp->type, XtRInt) == 0) { + + int value; + to.addr = (caddr_t) &value; + to.size = sizeof(value); + + /* Convert resource value. */ + if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) { + XtSetArg (args[0], rp->name, value); + XtSetValues (wp->w, args, 1); + } + + } else if (strcmp (rp->type, XtRFloat) == 0) { + union { + int int_value; + float float_value; + } value; + + to.addr = (caddr_t) &value.float_value; + to.size = sizeof(value); + + /* Convert resource value. */ + if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) { + XtSetArg (args[0], rp->name, value.int_value); + XtSetValues (wp->w, args, 1); + } + + } else if (strcmp (rp->type, XtRPixel) == 0) { + Pixel value; + to.addr = (caddr_t) &value; + to.size = sizeof(value); + + /* Convert resource value. */ + if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) { + XtSetArg (args[0], rp->name, value); + XtSetValues (wp->w, args, 1); + } + + } else if (strcmp (rp->type, XtRPixmap) == 0 || + strcmp (rp->type, XtRBitmap) == 0) { + + Pixmap value; + to.addr = (caddr_t) &value; + to.size = sizeof(value); + + /* Convert resource value. */ + if ((value = findPixmap (obm, (char *)from.addr)) || + XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) { + + XtSetArg (args[0], rp->name, value); + XtSetValues (wp->w, args, 1); + } + + } else if (strcmp (rp->type, XtRIcon) == 0) { + Icon *value; + to.addr = (caddr_t) &value; + to.size = sizeof(value); + + /* Convert resource value. */ + if ((value = findIcon (obm, (char *)from.addr)) || + XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) { + + XtSetArg (args[0], rp->name, value); + XtSetValues (wp->w, args, 1); + } + + } else if (strcmp (rp->type, XtRCursor) == 0) { + Cursor value; + to.addr = (caddr_t) &value; + to.size = sizeof(value); + + /* Convert resource value. */ + if ((value = findCursor (obm, (char *)from.addr)) || + XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) { + + XtSetArg (args[0], rp->name, value); + XtSetValues (wp->w, args, 1); + } + + } else if (strcmp (rp->type, XtRFontStruct) == 0) { + XFontStruct *value; + to.addr = (caddr_t) &value; + to.size = sizeof(value); + + /* Convert resource value. */ + if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) { + XtSetArg (args[0], rp->name, value); + XtSetValues (wp->w, args, 1); + } + + } else if (strcmp (rp->type, XtRVisual) == 0) { + Visual *value; + to.addr = (caddr_t) &value; + to.size = sizeof(value); + + /* Convert resource value. */ + if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) { + XtSetArg (args[0], rp->name, value); + XtSetValues (wp->w, args, 1); + } + + } else if (strcmp (rp->type, XtRWidget) == 0) { + Widget value; + + /* Convert resource value. */ + if (value = XtNameToWidget (obm->toplevel, argv[2])) { + XtSetArg (args[0], rp->name, value); + XtSetValues (wp->w, args, 1); + } + + } else if (strcmp (rp->type, XtRTranslationTable) == 0) { + XtTranslations value; + + /* Convert resource value. */ + value = XtParseTranslationTable (argv[2]); + XtSetArg (args[0], rp->name, value); + XtSetValues (wp->w, args, 1); + + } else { + caddr_t value; + to.addr = (caddr_t) &value; + to.size = sizeof(value); + + /* Convert resource value. */ + if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) { + XtSetArg (args[0], rp->name, value); + XtSetValues (wp->w, args, 1); + } + } + + return (TCL_OK); +} + + +/* widgetGet -- Get a widget resource value as a string. + * + * Usage: get <resource-name> + */ +static int +widgetGet (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + char rbuf[SZ_MESSAGE]; + char *result = rbuf; + register char *ip; + register int hashval, n; + register Rtype rp; + + if (argc < 2) + return (TCL_ERROR); + + /* Lookup widget. There can be multiple entries for a given resource + * if the resource has a different type in different widgets. A + * resource entry can be used only if both the name matches and the + * bitflags indicate that the target widget uses the resource. + */ + for (hashval=0, ip=argv[1], n=MAX_HASHCHARS; --n >= 0 && *ip; ip++) + hashval += (hashval + *ip); + + if (rp = rhash[hashval%LEN_RHASH]) { + for ( ; rp; rp = rp->next) + if (!strcmp(rp->name,argv[1]) && + obmClass (obj->core.classrec, rp->flag1, rp->flag2)) + break; + } + if (!rp) + return (TCL_ERROR); + + /* Return the resource value as a string. In general type converters + * are only registered for string-to-whatever conversions, so we + * cannot reproduce the original string value for all resource types. + * We can return a valid string value for the simple types (boolean, + * integer, floating, string). An attempt is made to convert widget + * pointers to widget names. For everything else, we just return + * the hex representation of the resource value. + */ + if (strcmp (rp->type, XtRBool) == 0 || + strcmp (rp->type, XtRBoolean) == 0) { + + Boolean value; Arg args[1]; + XtSetArg (args[0], rp->name, &value); + XtGetValues (wp->w, args, 1); + strcpy (result, value ? TRUESTR : FALSESTR); + + } else if ( + strcmp (rp->type, XtRDimension) == 0 || + strcmp (rp->type, XtRPosition) == 0) { + + short value; Arg args[1]; + XtSetArg (args[0], rp->name, &value); + XtGetValues (wp->w, args, 1); + sprintf (result, "%d", value); + + } else if ( + strcmp (rp->type, XtRAtom) == 0 || + strcmp (rp->type, XtRCardinal) == 0 || + strcmp (rp->type, XtRInt) == 0) { + + int value; Arg args[1]; + XtSetArg (args[0], rp->name, &value); + XtGetValues (wp->w, args, 1); + sprintf (result, "%d", value); + + } else if (strcmp (rp->type, XtRFloat) == 0) { + float value; Arg args[1]; + XtSetArg (args[0], rp->name, &value); + XtGetValues (wp->w, args, 1); + sprintf (result, "%g", value); + + } else if (strcmp (rp->type, XtRString) == 0) { + char *value; Arg args[1]; + XtSetArg (args[0], rp->name, &value); + XtGetValues (wp->w, args, 1); + result = (char *)value; + + } else if (strcmp (rp->type, XtRWidget) == 0) { + Widget value; Arg args[1]; + XtSetArg (args[0], rp->name, &value); + XtGetValues (wp->w, args, 1); + result = XtName (value); + + } else if (strcmp (rp->type, XtRFontStruct) == 0) { /* MF016 */ + caddr_t value; Arg args[1]; + XFontStruct *font_struct; + ObmContext obm = wp->obm; + char *name = NULL; + + XtSetArg (args[0], rp->name, &value); + XtGetValues (wp->w, args, 1); + sprintf (result, "0x%x", value); + + font_struct = (XFontStruct *) value; + name = widgetGetFontName (obm->display, font_struct); + + if (font_struct == NULL || name == NULL) + name = XtNewString("-*-*-*-R-*-*-*-120-*-*-*-*-ISO8859-1"); + strcpy (result, name); + free ((char *)name); + + } else { + caddr_t value; Arg args[1]; + XtSetArg (args[0], rp->name, &value); + XtGetValues (wp->w, args, 1); + sprintf (result, "0x%x", value); + } + + Tcl_SetResult (wp->obm->tcl, result, TCL_VOLATILE); + return (TCL_OK); +} + + +/* widgetAppend -- Append data to a text widget. + * + * Usage: append <text> + */ +static int +widgetAppend (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + + register char *ip, *op; + char buf[SZ_COMMAND]; + XawTextBlock tx; + char *text; + + if (!(obmClass (obj->core.classrec, WtAsciiText))) { + obm->tcl->result = "not a text widget"; + return (TCL_ERROR); + } + + if (argc < 2) { + obm->tcl->result = "missing argument"; + return (TCL_ERROR); + } else + text = argv[1]; + + if (wp->text_pos == 0) { + Arg args[1]; + XtSetArg (args[0], XtNstring, ""); + XtSetValues (wp->w, args, 1); + } + + op = buf; + if (wp->text_newline) + *op++ = '\n'; + + for (ip=text; *ip; ) + *op++ = *ip++; + + if (wp->text_newline = (*(ip-1) == '\n')) + op--; + + *op = '\0'; + + tx.ptr = buf; + tx.length = op - buf; + tx.format = FMT8BIT; + tx.firstPos = 0; + + XawTextReplace (wp->w, wp->text_pos, wp->text_pos, &tx); + XawTextSetInsertionPoint (wp->w, (wp->text_pos += (op - buf))); + + return (TCL_OK); +} + + +/* widgetSetList -- Set the item list of a list widget. + * + * Usage: setList list [resize] + * + * The list is a simple list of strings, passed as a single string argument to + * setList (quotes, braces, etc. may be used to quote strings containing + * special characters). + */ +static int +widgetSetList (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + Boolean resize; + String *items; + int nitems; + char *list; + + if (!(obmClass (obj->core.classrec, WtList) || + obmClass (obj->core.classrec, WtMultiList))) { + obm->tcl->result = "not a list widget"; + return (TCL_ERROR); + } + + if (argc < 2) { + obm->tcl->result = "missing argument"; + return (TCL_ERROR); + } else + list = argv[1]; + + resize = (argc > 2) ? (strcmp (argv[2], "resize") == 0) : False; + + if (Tcl_SplitList (obm->tcl, list, &nitems, &items) != TCL_OK) + return (TCL_ERROR); + + if ((obmClass (obj->core.classrec, WtList))) + XawListChange (wp->w, items, nitems, 0, resize); + else if ((obmClass (obj->core.classrec, WtMultiList))) + XfwfMultiListSetNewData ((XfwfMultiListWidget)wp->w, + items, nitems, 0, resize, NULL); + + if (wp->data) + free (wp->data); + + wp->data = (char *) items; + wp->datalen = nitems; + + return (TCL_OK); +} + + +/* widgetGetItem -- Get an item in a list widget. + * + * Usage: value = getItem itemno + * + * If ITEMNO is a number the indicated list item is returned, or the string + * "EOF" if the requested item is beyond the end of the list. Otherwise the + * currently selected item (or list of items in the case of a MultiList + * widget) is returned, and the index (list of indices) of the item is + * returned in the output variable ITEMNO. If no item is currently selected + * ITEMNO will be set to "none" ({}) on output. + */ +static int +widgetGetItem (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + + register nelem; + register String *list; + register char *ip, *op; + XawListReturnStruct *itemp; + char *s_itemno, *s_item; + char buf[SZ_NUMBER]; + int requested; + char *itemno; + + if (!(obmClass (obj->core.classrec, WtList) || + obmClass (obj->core.classrec, WtMultiList))) { + obm->tcl->result = "not a list widget"; + return (TCL_ERROR); + } + + if (argc < 2) { + obm->tcl->result = "missing argument"; + return (TCL_ERROR); + } else + itemno = argv[1]; + + if (isdigit (itemno[0])) { + /* Get indexed item. */ + requested = atoi (itemno); + list = (String *) wp->data; + nelem = wp->datalen; + if (requested < nelem) + s_item = list[requested]; + else + s_item = "EOF"; + + } else if (obmClass (obj->core.classrec, WtList)) { + /* Athena list: get the currently selected list item. + */ + itemp = XawListShowCurrent (wp->w); + if (!itemp || itemp->list_index == XAW_LIST_NONE) { + s_itemno = "none"; + s_item = ""; + } else { + sprintf (buf, "%d", itemp->list_index); + s_itemno = buf; + s_item = itemp->string; + } + if ((Tcl_SetVar (obm->tcl, itemno, s_itemno, 0)) == NULL) + return (TCL_ERROR); + + Tcl_SetResult (obm->tcl, s_item, TCL_VOLATILE); + + } else { + /* MultiList: get currently selected items. + */ + XfwfMultiListReturnStruct *list; + char *buffer, *strlist, *indexlist, *string; + Boolean state, sensitive; + int buflen, need, i; + + list = XfwfMultiListGetHighlighted ((XfwfMultiListWidget)wp->w); + buflen = SZ_COMMAND; + if (!(buffer = XtMalloc (buflen))) + return; + + /* Generate list of item strings. */ + strlist = op = buffer; + *op++ = '{'; + for (i=0; i < list->num_selected; i++) { + XfwfMultiListGetItemInfo ((XfwfMultiListWidget)wp->w, + list->selected_items[i], &string, &state, &sensitive); + need = strlen(string)+3 + list->num_selected * 6; + if (buflen < (op-buffer)+need) { + buflen += max (need, SZ_COMMAND); + if (!(buffer = XtRealloc (buffer, buflen))) + return; + } + *op++ = ' '; + *op++ = '{'; + for (ip=string; *op = *ip++; op++) + ; + *op++ = '}'; + } + *op++ = '}'; + *op++ = '\0'; + + /* Append list of indices. We allocated space for these above. */ + indexlist = op; + *op++ = '{'; + for (i=0; i < list->num_selected; i++) { + sprintf (op, " %d", list->selected_items[i]); + while (*op) + op++; + } + *op++ = '}'; + *op++ = '\0'; + + if ((Tcl_SetVar (obm->tcl, itemno, indexlist, 0)) == NULL) + return (TCL_ERROR); + + Tcl_SetResult (obm->tcl, strlist, TCL_VOLATILE); + XtFree (buffer); + } + + return (TCL_OK); +} + + +/* widgetHighlight -- Highlight an item in a list widget. + * + * Usage: highlight itemno + * + * The indicated item of the list is highlighted as if the item had been + * selected by the user. Any previously highlighted item is unhighlighted. + * List items may be specified by either the element number or by name. + */ +static int +widgetHighlight (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + int itemno; + + if (!(obmClass (obj->core.classrec, WtList) || + obmClass (obj->core.classrec, WtMultiList))) { + obm->tcl->result = "not a list widget"; + return (TCL_ERROR); + } + + if (argc < 2) { + obm->tcl->result = "missing argument"; + return (TCL_ERROR); + } else + itemno = get_itemno (obj, argv[1]); + + if (itemno >= 0 && itemno < wp->datalen) + if (obmClass (obj->core.classrec, WtList)) + XawListHighlight (wp->w, itemno); + else + XfwfMultiListHighlightItem ((XfwfMultiListWidget)wp->w, itemno); + + return (TCL_OK); +} + + +/* widgetUnhighlight -- Unhighlight the currently highlighted item in a + * list widget. + * + * Usage: unhighlight [itemno] + * + * If itemno is not given all list elements are unhighlighted, otherwise + * the given entry is unhighlighted. The itemno argument may be either + * the actual item number, or the name of the list element. + */ +static int +widgetUnhighlight (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + int itemno; + + if (!(obmClass (obj->core.classrec, WtList) || + obmClass (obj->core.classrec, WtMultiList))) { + obm->tcl->result = "not a list widget"; + return (TCL_ERROR); + } + + itemno = (argc > 1) ? get_itemno(obj,argv[1]) : -1; + + if (obmClass (obj->core.classrec, WtList)) { + if (itemno >= 0) { + XawListReturnStruct *itemp = XawListShowCurrent (wp->w); + if (itemp && itemp->list_index == itemno) + XawListUnhighlight (wp->w); + } else + XawListUnhighlight (wp->w); + } else { + if (itemno >= 0) { + XfwfMultiListUnhighlightItem ((XfwfMultiListWidget)wp->w, + itemno); + } else + XfwfMultiListUnhighlightAll ((XfwfMultiListWidget)wp->w); + } + + return (TCL_OK); +} + + +/* get_itemno -- Get the item number of an item in a list widget, given + * either the ascii representation of the item number, or the item string. + */ +static +get_itemno (obj, itemstr) +WidgetObject obj; +char *itemstr; +{ + WidgetPrivate wp = &obj->widget; + register int i; + + if (isdigit (*itemstr)) + return (atoi(itemstr)); + else { + /* Check first to see if the named item is the currently + * selected, or most recently referenced item. + */ + if (obmClass (obj->core.classrec, WtList)) { + XawListReturnStruct *itemp; + itemp = XawListShowCurrent (wp->w); + if (itemp && strcmp (itemp->string, itemstr) == 0) + return (itemp->list_index); + + } else if (obmClass (obj->core.classrec, WtMultiList)) { + XfwfMultiListReturnStruct *list; + list = XfwfMultiListGetHighlighted ((XfwfMultiListWidget)wp->w); + if (list->string && strcmp (list->string, itemstr) == 0) + return (list->item); + } + + /* Search the full list. */ + for (i=0; i < wp->datalen; i++) + if (strcmp (((String *)wp->data)[i], itemstr) == 0) + return (i); + } + + return (-1); +} + + +/* widgetGetValue -- Get the text value of a dialog widget. + * + * Usage: value = getValue + */ +static int +widgetGetValue (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + char *value; + + if (!(obmClass (obj->core.classrec, WtDialog))) { + obm->tcl->result = "not a dialog widget"; + return (TCL_ERROR); + } + + value = XawDialogGetValueString (wp->w); + Tcl_SetResult (obm->tcl, value, TCL_VOLATILE); + + return (TCL_OK); +} + + +/* widgetGetThumb -- Get the position and size of the thumb of a slider2d + * widget. + * + * Usage: getThumb x [y [width [height]]] + */ +static int +widgetGetThumb (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + XfwfScrollInfo info; + char buf[SZ_NUMBER]; + + if (!(obmClass (obj->core.classrec, WtSlider2d))) { + obm->tcl->result = "not a slider2d widget"; + return (TCL_ERROR); + } + + XfwfGetThumb (wp->w, &info); + + if (argc > 1) { + sprintf (buf, "%g", info.hpos); + if ((Tcl_SetVar (obm->tcl, argv[1], buf, 0)) == NULL) + return (TCL_ERROR); + } + if (argc > 2) { + sprintf (buf, "%g", info.vpos); + if ((Tcl_SetVar (obm->tcl, argv[2], buf, 0)) == NULL) + return (TCL_ERROR); + } + if (argc > 3) { + sprintf (buf, "%g", info.hsize); + if ((Tcl_SetVar (obm->tcl, argv[3], buf, 0)) == NULL) + return (TCL_ERROR); + } + if (argc > 4) { + sprintf (buf, "%g", info.vsize); + if ((Tcl_SetVar (obm->tcl, argv[4], buf, 0)) == NULL) + return (TCL_ERROR); + } + + return (TCL_OK); +} + + +/* widgetMoveThumb -- Move the thumb of a slider2D widget. + * + * Usage: moveThumb x [y] + * + * The thumb of a slider2D wiget is set to the given position specified as + * a fraction of the widget's width or height. The widget and height + * arguments should be floating point values in the range 0.0 to 1.0. + */ +static int +widgetMoveThumb (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + double x, y; + double atof(); + + if (!(obmClass (obj->core.classrec, WtSlider2d))) { + obm->tcl->result = "not a slider2D widget"; + return (TCL_ERROR); + } + + if (argc < 2) { + obm->tcl->result = "missing argument"; + return (TCL_ERROR); + } else { + x = atof (argv[1]); + y = (argc > 2) ? atof(argv[2]) : 0.0; + } + + x = max(0, min(1, x)); + y = max(0, min(1, y)); + + XfwfMoveThumb (wp->w, x, y); + return (TCL_OK); +} + + +/* widgetResizeThumb -- Resize the thumb of a slider2D widget. + * + * Usage: resizeThumb width [height] + * + * The thumb of a slider2D wiget is set to the given fraction of the widget's + * width or height. The widget and height arguments should be floating point + * values in the range 0.0 to 1.0. + */ +static int +widgetResizeThumb (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + double width, height; + double atof(); + + if (!(obmClass (obj->core.classrec, WtSlider2d))) { + obm->tcl->result = "not a slider2D widget"; + return (TCL_ERROR); + } + + if (argc < 2) { + obm->tcl->result = "missing argument"; + return (TCL_ERROR); + } else { + width = atof (argv[1]); + height = (argc > 2) ? atof(argv[2]) : 1.0; + } + + width = max(0, min(1, width)); + height = max(0, min(1, height)); + + XfwfResizeThumb (wp->w, width, height); + return (TCL_OK); +} + + +/* widgetSetScrollbar -- Set the position and size of a scrollbar. + * + * Usage: setScrollbar position size + * + * The thumb of a scrollbar wiget is set to the given position and size + * specified as a fraction of the widget's width or height. The position and + * height arguments should be floating point values in the range 0.0 to 1.0. + */ +static int +widgetSetScrollbar (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + double position, size; + double atof(); + + if (!(obmClass (obj->core.classrec, WtScrollbar) || + obmClass (obj->core.classrec, WtScrollbar2))) { + + obm->tcl->result = "not a scrollbar widget"; + return (TCL_ERROR); + } + + if (argc < 3) { + obm->tcl->result = "missing argument"; + return (TCL_ERROR); + } else { + position = atof (argv[1]); + size = atof (argv[2]); + } + + position = max(0, min(1, position)); + size = max(0, min(1, size)); + + if (obmClass (obj->core.classrec, WtScrollbar)) + XawScrollbarSetThumb (wp->w, position, size); + else + XfwfSetScrollbar (wp->w, position, size); + + return (TCL_OK); +} + + +/* widgetSetLocation -- Set the position of a Viewport. + * + * Usage: setLocation x y + * + */ +static int +widgetSetLocation (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + float x, y; + double atof(); + + if (!(obmClass (obj->core.classrec, WtViewport))) { + obm->tcl->result = "not a viewport widget"; + return (TCL_ERROR); + } + + if (argc < 3) { + obm->tcl->result = "missing argument"; + return (TCL_ERROR); + } else { + x = atof (argv[1]); + y = atof (argv[2]); + } + + XawViewportSetLocation (wp->w, x, y); + + return (TCL_OK); +} + + +/* widgetSetCoordinates -- Set the coordinates of a Viewport. + * + * Usage: setCoordinates x y + * + */ +static int +widgetSetCoordinates (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + int x, y; + double atof(); + + if (!(obmClass (obj->core.classrec, WtViewport))) { + obm->tcl->result = "not a viewport widget"; + return (TCL_ERROR); + } + + if (argc < 3) { + obm->tcl->result = "missing argument"; + return (TCL_ERROR); + } else { + x = atoi (argv[1]); + y = atoi (argv[2]); + } + + XawViewportSetCoordinates (wp->w, (int)x, (int)y); + + return (TCL_OK); +} + + +/* widgetSetTop -- Raise the child of a Tabs widget. + * + * Usage: setTop widget + * + */ +static int +widgetSetTop (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + ObmObject child = (ObmObject) NULL; + + if (!(obmClass (obj->core.classrec, WtTabs))) { + obm->tcl->result = "not a Tabs widget"; + return (TCL_ERROR); + } else if (argc < 2) { + obm->tcl->result = "missing argument"; + return (TCL_ERROR); + } + + /* Get the child object pointer and raise it. */ + child = obmFindObject (obm, argv[1]); + if (child) + XawTabsSetTop (widgetGetPointer (child), False); + + return (TCL_OK); +} + + +/* widgetSetListTree -- Set a ListTree hierarchy. + * + * Usage: setListTree list [append] + * + * The list is specified as a hierarchical Tcl list of the form + * + * {a1 {b1 {a2 {a3 b3}} b2} c1} + * + * This would produce an indented list something like: + * + * a1 + * b1 + * |- a2 + * |- a3 + * |- b3 + * |- b2 + * c1 + * + */ +static int +widgetSetListTree (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + Boolean append; + char *list, **items, buf[SZ_LINE]; + int nitems, item; + static char **sv_items = NULL; + static int sv_nitems; + ListTreeItem *val; + extern ListTreeItem *ListTreeAdd(), *ListTreeFirstItem(); + + + /* Do some error checking first. */ + if (!(obmClass (obj->core.classrec, WtListTree))) { + obm->tcl->result = "not a ListTree widget"; + return (TCL_ERROR); + } else if (argc < 2) { + obm->tcl->result = "missing list argument"; + return (TCL_ERROR); + } + + list = argv[1]; + append = (argc > 2) ? (strcmp (argv[2], "append") == 0) : False; + + /* Delete the old tree. */ + if (!append && sv_items) { + while ((val = ListTreeFirstItem(wp->w))) + ListTreeDelete (wp->w, val); + free ((char *) sv_items); + sv_items = NULL; + } + + /* Split the list so we can parse as needed. */ + if (Tcl_SplitList (tcl, list, &nitems, &items) != TCL_OK) + return (TCL_ERROR); + + /* Get local copy of argc and argv. */ + if (!sv_nitems) { + sv_items = (char **) XtMalloc (nitems * sizeof(char *)); + memmove (sv_items, items, nitems * sizeof(char *)); + } + + if (append && sv_items) { + sv_items = (char **) XtRealloc ((char *)sv_items, + (sv_nitems + nitems * 1) * sizeof(char *)); + memmove (sv_items+sv_nitems, items, nitems * sizeof(char *)); + } + + for (item=0; item < nitems; item++) { + /* Build the top-level tree, children are built recursively + * in the routine. + */ + if (buildTreeList (wp->w, tcl, NULL, items[item]) != TCL_OK) { + free ((char *) items); + return (TCL_ERROR); + } + } + +ret: free ((char *) items); + return (TCL_OK); +} + + +/* buildTreeList -- Recursively build a tree from a list of nested Tcl + * lists. This is used to fill out the ListTree widget values. + */ +static int +buildTreeList (w, tcl, parent, item) +Widget w; +Tcl_Interp *tcl; +ListTreeItem *parent; +char *item; +{ + char **fields, **entry; + int i, nentries, nfields, field; + char buf[SZ_LINE]; + ListTreeItem *level; + + /* Split the list so we can parse as needed. */ + if (Tcl_SplitList (tcl, item, &nfields, &fields) != TCL_OK) { + sprintf (buf, "bad item '%s' in tree list", item); + Tcl_AppendResult (tcl, buf, NULL); + return (TCL_ERROR); + } + + /* First item is always added to the list, it may be either the + * parent of another list or a single item. + */ + level = ListTreeAdd (w, parent, fields[0]); + + /* For each of the items, split it and recursively call ourselves + * until it gets added as a single item. + */ + for (field=1; field < nfields; field++) { + if (Tcl_SplitList (tcl, fields[field], &nentries, &entry) != TCL_OK) + return (TCL_ERROR); + + for (i=0; i < nentries; i++) + buildTreeList (w, tcl, level, entry[i]); + } + + free ((char *) fields); +/* free ((char *) entry);*/ + return (TCL_OK); +} + + +/* widgetListTreeSelect -- Select the specified item from a ListTree. + * + * Usage: listTreeSelect item [ top [children_only] ] + * + * The 'item' may be one of: + * + * all open all children in list + * none close all children in list + * + * If 'toplevel' is specified then 'item' is assumed to be a child of + * that node. If 'children_only' is set then only the children of the + * specified item will be opened (applies to all/none only). The return + * message is a pair of lists of the form + * + * { value state } { parent1 parent2 ... } + * + * where the 'value' is the label of the item selected, 'state' is an int + * indicating whether the node is open or closed, and 'parentN' is a list + * of node names chaining back to the top level of the tree. + * + */ +static int +widgetListTreeSelect (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + char *top, *name; + char message[SZ_COMMAND], buf[SZ_LINE]; + int i, count; + ListTreeItem *item, *titem, *first; + + extern ListTreeItem *ListTreeFindSiblingName(); + extern ListTreeItem *ListTreeFindChildName(); + extern ListTreeItem *ListTreeFindChildNameInTree(); + + + if (argc < 2) + return (TCL_ERROR); + + name = argv[1]; + first = ListTreeFirstItem (wp->w); + + if (strcmp(argv[1], "all") == 0) { + if (argc == 4) { + top = argv[2]; + titem = ListTreeFindSiblingName (wp->w, first, top); + item = ListTreeFindChildName (wp->w, titem, name); + ListTreeOpenAll (wp->w, (item ? item : titem), 1); + ListTreeHighlightItem (wp->w, (item ? item : titem)); + sprintf (message, "{%s 1} { }", + (item ? item->text : titem->text)); + } else { + ListTreeOpenAll (wp->w, (ListTreeItem *)NULL, 0); + strcpy (message, "{all 1} { }"); + } + + + } else if (strcmp(argv[1], "none") == 0) { + if (argc == 4) { + top = argv[2]; + titem = ListTreeFindSiblingName (wp->w, first, top); + item = ListTreeFindChildName (wp->w, titem, name); + ListTreeCloseAll (wp->w, (item ? item : titem), 0); + sprintf (message, "{%s 0} { }", + (item ? item->text : titem->text)); + } else { + ListTreeCloseAll (wp->w, (ListTreeItem *)NULL, 0); + strcpy (message, "{all 0} { }"); + } + + } else { + if (argc == 3) { + top = argv[2]; + titem = ListTreeFindSiblingName (wp->w, first, top); + if (titem) + ListTreeOpenAll (wp->w, titem, 0); + item = ListTreeFindChildNameInTree (wp->w, titem, name); + item = (item ? item : titem); + } else { + titem = ListTreeFindSiblingName (wp->w, first, name); + if (strcmp (name, titem->text) == 0) + item = titem; + else + item = ListTreeFindChildNameInTree (wp->w, titem, name); + } + ListTreeHighlightItem (wp->w, item); + ListTreeOpenAll (wp->w, item, 0); + + /* The message is the string value of the list element selected, + * and a bottom-up path to the root. + */ + sprintf (message, "{%s %d} ", item->text, item->open); + + strncat (message, "{ ", 2); + sprintf (buf, "{ %s } ", item->text); + strcat (message, buf); + while (item->parent) { + item = item->parent; + sprintf (buf, "{ %s } ", item->text); + strcat (message, buf); + } + + strncat (message, "}", 1); + + } + + /* Call all the callbacks with the message. */ + call_callbacks (obj, Ctcallback, message); + + return (TCL_OK); +} + + +/* widgetListTreeHighlight -- Highlight but do not select the specified item + * from a ListTree. + * + * Usage: listTreeHighlight item [ top ] + * + * The 'item' is given as a node name of the tree. If 'top' is specified + * then 'item' is assumed to be a child of that node. If 'children_only' is + * set then only the children of the specified item will be opened (applies + * to all/none only). The return message is a pair of lists of the form + * + * { value state } { parent1 parent2 ... } + * + * where the 'value' is the label of the item selected, 'state' is an int + * indicating whether the node is open or closed, and 'parentN' is a list + * of node names chaining back to the top level of the tree. + * + */ +static int +widgetListTreeHighlight (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + char *top, *name; + char message[SZ_COMMAND], buf[SZ_LINE]; + int i, count; + ListTreeItem *item, *titem, *first, *op; + + extern ListTreeItem *ListTreeFindSiblingName(); + extern ListTreeItem *ListTreeFindChildName(); + extern ListTreeItem *ListTreeFindChildNameInTree(); + + + if (argc < 2) + return (TCL_ERROR); + + name = argv[1]; + first = ListTreeFirstItem (wp->w); + + if (argc == 3) { + top = argv[2]; + titem = ListTreeFindSiblingName (wp->w, first, top); + item = ListTreeFindChildNameInTree (wp->w, titem, name); + item = (item ? item : titem); + + /* Now chain back up thru the parents and open the nodes. + */ + for (op=item ; op->parent && op->parent != first; op = op->parent) { + if (op->open == 0) + ListTreeOpenAll (wp->w, op, 1); + } + + } else { + if (first->open == 0) + ListTreeOpenAll (wp->w, first, 0); + titem = ListTreeFindChildNameInTree (wp->w, first, name); + if (titem && strcmp (name, titem->text) == 0) + item = titem; + else + item = ListTreeFindChildNameInTree (wp->w, titem, name); + } + ListTreeHighlightItem (wp->w, item); + + /* The message is the string value of the list element selected, + * and a bottom-up path to the root. + */ + sprintf (message, "{%s %d} ", item->text, item->open); + + strncat (message, "{ ", 2); + sprintf (buf, "{ %s } ", item->text); + strcat (message, buf); + while (item->parent) { + item = item->parent; + sprintf (buf, "{ %s } ", item->text); + strcat (message, buf); + } + strncat (message, "}", 1); + + /* Call all the callbacks with the message. */ + call_callbacks (obj, Ctcallback, message); + + return (TCL_OK); +} + + +/* widgetListTreeDelete -- Delete the specified item from a ListTree. + * + * Usage: listTreeDelete item [top] + * + * The 'item' may 'all' to delete the entire list or a named element. + * If 'toplevel' is specified then 'item' is assumed to be a child of + * that node. If 'children_only' is set then only the children of the + * specified item will be opened (applies to all/none only). The return + * message is a pair of lists of the form + * + * { value state } { parent1 parent2 ... } + * + * where the 'value' is the label of the item selected, 'state' is an int + * indicating whether the node is open or closed, and 'parentN' is a list + * of node names chaining back to the top level of the tree. + * + */ +static int +widgetListTreeDelete (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + char *top, *name; + ListTreeItem *item, *titem, *first; + + extern ListTreeItem *ListTreeFindSiblingName(); + extern ListTreeItem *ListTreeFindChildName(); + extern ListTreeItem *ListTreeFirstItem(); + + + if (argc < 2) + return (TCL_ERROR); + + name = argv[1]; + first = ListTreeFirstItem (wp->w); + + if (strcmp(argv[1], "all") == 0) { + if (argc == 3) { + top = argv[2]; + titem = ListTreeFindSiblingName (wp->w, first, top); + if (strcmp (top, titem->text) == 0) + item = titem; + else + item = ListTreeFindChildName (wp->w, titem, name); + + ListTreeDelete(wp->w, item); + + } else { + while ((item = ListTreeFirstItem(wp->w))) + ListTreeDelete (wp->w, item); + } + + } else { + if (argc == 3) { + top = argv[2]; + titem = ListTreeFindSiblingName (wp->w, first, top); + item = ListTreeFindChildName (wp->w, titem, name); + } else { + titem = ListTreeFindSiblingName (wp->w, first, name); + if (strcmp (name, titem->text) == 0) + item = titem; + else + item = ListTreeFindChildName (wp->w, titem, name); + } + + /* Now delete the item from the list. */ + ListTreeDelete(wp->w, item); + } + + + /* Call all the callbacks with the message. + call_callbacks (obj, Ctcallback, message); + */ + + return (TCL_OK); +} + + +/* widgetSetTable -- Set the contents of a Table widget. + * + * Usage: setTable nrows ncols data + * + * The table data is specified as a Tcl list of the form: + * + * { {r1c1 r1c2 ... r1cN} + * {r2c1 r2c2 ... r2cN} + * : + * {rNc1 rNc2 ... rNcN} } + * + * String values must be quoted, rows/cols will be truncated or cleared if + * the specified table size does not agree with the size of the data table + * being loaded. + * + */ +static int +widgetSetTable (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + + register int i, j; + int nrows, ncols, ndrows=0, ndcols=0, onrows, oncols; + char *list = NULL, **rows = NULL, **cols = NULL; + + + if (argc < 4) + return (TCL_ERROR); + + /* Get the arguments */ + nrows = atoi(argv[1]); + ncols = atoi(argv[2]); + list = argv[3]; + + /* Resize the table if needed. */ + XawTableGetSize (wp->w, &onrows, &oncols); + if (onrows != nrows || oncols != ncols) + XawTableSetNewSize (wp->w, nrows, ncols); + + /* Split the list so we can parse the rows. */ + if (Tcl_SplitList (tcl, list, &ndrows, &rows) != TCL_OK) + return (TCL_ERROR); + + /* Set the labels for the table. Clear any extra row or column + * labels in case we didn't get enough data, ignore extra data in + * the table if it's more than the size we're trying to create. + */ + for (i=0; i < ndrows; i++) { + if (Tcl_SplitList (tcl, rows[i], &ndcols, &cols) != TCL_OK) + return (TCL_ERROR); + + for (j=0; j < ndcols; j++) + XawTableSetLabel (wp->w, i, j, cols[j]); + } + + free ((char *) rows); + free ((char *) cols); + return (TCL_OK); +} + + +/* widgetGetCellAttr -- Get the given attribute of a Table cell. + * + * Usage: setGellAttr row col attribute value + * + * + * The cell position is given as a 1-indexed array element where the UL + * of the table is cell (1,1). Allowed attributes for a cell include: + * + * label label text (string) + * background background color (string) + * foreground foreground color (string) + * + */ +static int +widgetGetCellAttr (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + XrmValue from, to; + unsigned long bg, fg; + int row, col; + char *attr, *value; + + + if (argc < 4) + return (TCL_ERROR); + + row = atoi(argv[1]) - 1; + col = atoi(argv[2]) - 1; + attr = argv[3]; + + if (strcmp(attr, "label") == 0) + value = XawTableGetLabelByPosition (wp->w, row, col); + else + return (TCL_ERROR); + + Tcl_SetResult (wp->obm->tcl, value, TCL_VOLATILE); + return (TCL_OK); +} + + +/* widgetSetCellAttr -- Set the given attribute of a Table cell. + * + * Usage: setCellAttr row col attribute value + * + * + * The cell position is given as a 1-indexed array element where the UL + * of the table is cell (1,1). Allowed attributes for a cell include: + * + * label label text (string) + * background background color (string) + * foreground foreground color (string) + * + */ +static int +widgetSetCellAttr (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + XrmValue from, to; + unsigned long bg, fg; + int row, col; + char *attr, *value; + + + if (argc < 5) + return (TCL_ERROR); + + /* Get the arguments. */ + row = atoi(argv[1]) - 1; + col = atoi(argv[2]) - 1; + attr = argv[3]; + value = argv[4]; + + if (strcmp(attr, "label") == 0) { + XawTableSetLabel (wp->w, row, col, value); + + } else if (strcmp(attr, "background") == 0) { + from.size = strlen (value) + 1; + from.addr = value; + to.addr = (caddr_t) &bg; + to.size = sizeof(bg); + + if (!XtConvertAndStore (wp->w, XtRString, &from, XtRPixel, &to)) + bg = BlackPixelOfScreen (obm->screen); + + XawTableSetCellBackground (wp->w, row, col, bg); + + } else if (strcmp(attr, "foreground") == 0) { + from.size = strlen (value) + 1; + from.addr = value; + to.addr = (caddr_t) &fg; + to.size = sizeof(fg); + + if (!XtConvertAndStore (wp->w, XtRString, &from, XtRPixel, &to)) + fg = BlackPixelOfScreen (obm->screen); + + XawTableSetCellForeground (wp->w, row, col, fg); + } + + return (TCL_OK); +} + + +/* widgetSetColAttr -- Set the given attribute of a Table column. + * + * Usage: setColAttr col attribute value + * + * The column position is given as a 1-indexed array element where the UL + * of the table is cell (1,1). Allowed attributes for a column include: + * + * width column width (pixels) + * background background color (string) + * foreground foreground color (string) + * justify text justification (string) + * + */ +static int +widgetSetColAttr (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + XrmValue from, to; + unsigned long bg, fg; + int cols[128], widths[128]; + int nitems, row, col, nrows, ncols, i; + String *items; + char *attr; + + + if (argc < 4) + return (TCL_ERROR); + + /* Get the arguments. NOTE: need to bounds check the length of the + * list with the array. + */ + if (Tcl_SplitList (tcl, argv[1], &nitems, &items) != TCL_OK) + return (TCL_ERROR); + else { + if (nitems == 1) + col = atoi(argv[1]) - 1; + else { + if (nitems > 128) + return (TCL_ERROR); + for (i=0; i < nitems; i++) + cols[i] = atoi(items[i]) - 1; + } + } + attr = argv[2]; + + /* Get current table size. */ + XawTableGetSize (wp->w, &nrows, &ncols); + + if (strcmp(attr, "width") == 0) { + /* Reset the column width. */ + if (nitems == 1) + XawTableSetColumnWidth (wp->w, col, atoi(argv[3])); + else { + if (Tcl_SplitList (tcl, argv[3], &nitems, &items) != TCL_OK) + return (TCL_ERROR); + if (nitems > 128) + return (TCL_ERROR); + for (i=0; i < nitems; i++) + widths[i] = atoi(items[i]) - 1; + XawTableSetMultiColumnWidths (wp->w, cols, widths, nitems); + } + + } else if (strcmp(attr, "background") == 0) { + /* Reset the column background color. */ + from.size = strlen (argv[3]) + 1; + from.addr = argv[3]; + to.addr = (caddr_t) &bg; + to.size = sizeof(bg); + + if (!XtConvertAndStore (wp->w, XtRString, &from, XtRPixel, &to)) + bg = BlackPixelOfScreen (obm->screen); + + for (i=0; i < nrows; i++) + XawTableSetCellBackground (wp->w, i, col, bg); + + } else if (strcmp(attr, "foreground") == 0) { + /* Reset the column foreground color. */ + from.size = strlen (argv[3]) + 1; + from.addr = argv[3]; + to.addr = (caddr_t) &fg; + to.size = sizeof(fg); + + if (!XtConvertAndStore (wp->w, XtRString, &from, XtRPixel, &to)) + fg = BlackPixelOfScreen (obm->screen); + + for (i=0; i < nrows; i++) + XawTableSetCellForeground (wp->w, i, col, fg); + + } else if (strcmp(attr, "justify") == 0) { + /* Reset the column text justification. */ + if (strcmp(argv[3], "left") == 0) + XawTableSetColumnJustify (wp->w, col, XtJustifyLeft); + else if (strcmp(argv[3], "center") == 0) + XawTableSetColumnJustify (wp->w, col, XtJustifyCenter); + else if (strcmp(argv[3], "right") == 0) + XawTableSetColumnJustify (wp->w, col, XtJustifyRight); + else + XawTableSetColumnJustify (wp->w, col, XtJustifyLeft); + } + + return (TCL_OK); +} + + +/* widgetGetColAttr -- Get the requested attribute of a Table column. + * + * Usage: attr = getColAttr col attribute + * + * + * The column position is given as a 1-indexed array element where the UL + * of the table is cell (1,1). Allowed attributes for a column include: + * + * width column width + * pixelWidth foreground color + * justify text justification + * + */ +static int +widgetGetColAttr (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + char rbuf[SZ_MESSAGE]; + char *result = rbuf, *attr; + int col, nrows, ncols, width, pixelWidth; + XtJustify justify; + + + if (argc < 3) + return (TCL_ERROR); + + /* Get the arguments. */ + col = atoi(argv[1]) - 1; + attr = argv[2]; + + /* Get current table size. */ + XawTableGetSize (wp->w, &nrows, &ncols); + + if (strcmp(attr, "width") == 0) { + width = XawTableGetColumnWidth (wp->w, col); + + } else if (strcmp(attr, "pixelWidth") == 0) { + pixelWidth = XawTableGetColumnPixelWidth (wp->w, col); + + } else if (strcmp(attr, "justify") == 0) { + justify = XawTableGetColumnJustify (wp->w, col); + + /* Reset the column text justification. */ + if (justify == XtJustifyLeft) + strcpy (result, "left"); + else if (justify == XtJustifyCenter) + strcpy (result, "center"); + else if (justify == XtJustifyRight) + strcpy (result, "right"); + else + strcpy (result, "left"); + } + + Tcl_SetResult (wp->obm->tcl, result, TCL_VOLATILE); + return (TCL_OK); +} + + +/* widgetSetRowAttr -- Set the given attribute of a Table row. + * + * Usage: setRowAttr row attribute value + * + * The row position is given as a 1-indexed array element where the UL + * of the table is cell (1,1). Allowed attributes for a row include: + * + * background background color + * foreground foreground color + */ +static int +widgetSetRowAttr (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + XrmValue from, to; + unsigned long bg, fg; + int row, col, nrows, ncols, i; + char *attr; + + + if (argc < 4) + return (TCL_ERROR); + + /* Get the arguments. */ + row = atoi(argv[1]) - 1; + attr = argv[2]; + + /* Get current table size. */ + XawTableGetSize (wp->w, &nrows, &ncols); + + if (strcmp(attr, "background") == 0) { + /* Reset the column background color. */ + from.size = strlen (argv[3]) + 1; + from.addr = argv[3]; + to.addr = (caddr_t) &bg; + to.size = sizeof(bg); + + if (!XtConvertAndStore (wp->w, XtRString, &from, XtRPixel, &to)) + bg = BlackPixelOfScreen (obm->screen); + + for (i=0; i < ncols; i++) + XawTableSetCellBackground (wp->w, row, i, bg); + + } else if (strcmp(attr, "foreground") == 0) { + /* Reset the column foreground color. */ + from.size = strlen (argv[3]) + 1; + from.addr = argv[3]; + to.addr = (caddr_t) &fg; + to.size = sizeof(fg); + + if (!XtConvertAndStore (wp->w, XtRString, &from, XtRPixel, &to)) + fg = BlackPixelOfScreen (obm->screen); + + for (i=0; i < ncols; i++) + XawTableSetCellForeground (wp->w, row, i, fg); + } + + return (TCL_OK); +} + + +/* widgetGetRowAttr -- Get the requested attribute of a Table column. + * + * Usage: attr = getRowAttr row attribute + * + * + * The column position is given as a 1-indexed array element where the UL + * of the table is cell (1,1). Allowed attributes for a column include: + * + * <none yet> + * + */ +static int +widgetGetRowAttr (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + char rbuf[SZ_MESSAGE]; + char *result = rbuf, *attr; + int row, nrows, ncols, width, pixelWidth; + XtJustify justify; + + + if (argc < 3) + return (TCL_ERROR); + + /* Get the arguments. */ + row = atoi(argv[1]) - 1; + attr = argv[2]; + + /* Get current table size. */ + XawTableGetSize (wp->w, &nrows, &ncols); + + return (TCL_OK); +} + + +/* widgetDeleteCol -- Delete the specified columns from the table. + * + * Usage: deleteCol column + * + */ +static int +widgetDeleteCol (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + int col; + + + if (argc < 2) + return (TCL_ERROR); + + /* Get the arguments. */ + col = atoi(argv[1]) - 1; + + /* Delete the specified row. */ + XawTableDeleteColumn (wp->w, col); + + return (TCL_OK); +} + + +/* widgetAddCol -- Add a new column to the Table. + * + * Usage: addCol col width + * + * The column may be specified in one of the following ways: + * + * first make column the first column in the table + * last make column the last column in the table + * <num> make column the N-th column in the table + * + * The column width is specified as a character width. Data for the + * column must be added separately using the setColAttr function to + * set individual labels. + * + */ +static int +widgetAddCol (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + char *col = NULL; + int nrows, ncols, width, colnum = 0; + + + if (argc < 3) + return (TCL_ERROR); + + /* Get the arguments. */ + col = argv[1]; + width = atoi(argv[2]); + + /* Add the specified column. */ + XawTableGetSize (wp->w, &nrows, &ncols); + colnum = max (0, min (ncols, atoi (col) - 1)); + + if (colnum == 0 || streq(col, "first")) + XawTablePrependColumn (wp->w, width); + else if (colnum == ncols || streq (col, "last")) + XawTableAppendColumn (wp->w, width); + else + XawTableInsertColumn (wp->w, colnum, width); + + return (TCL_OK); +} + + +/* widgetDeleteRow -- Delete the specified rows from the table. + * + * Usage: deleteRow row + * + */ +static int +widgetDeleteRow (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + int row; + + + if (argc < 2) + return (TCL_ERROR); + + /* Get the arguments. */ + row = atoi(argv[1]) - 1; + + /* Delete the specified row. */ + XawTableDeleteRow (wp->w, row); + + return (TCL_OK); +} + + +/* widgetAddRow -- Add a new row to the Table. + * + * Usage: addRow row + * + * The row may be specified in one of the following ways: + * + * first make row the first row in the table + * last make row the last row in the table + * <num> make row the N-th row in the table + * + * Data for the column must be added separately using the setColAttr + * function to set individual labels. + * + */ +static int +widgetAddRow (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + char *row = NULL; + int nrows, ncols, rownum = 0; + + + if (argc < 2) + return (TCL_ERROR); + + /* Get the arguments. */ + row = argv[1]; + + /* Add the specified column. */ + XawTableGetSize (wp->w, &nrows, &ncols); + rownum = max (0, min (nrows, atoi (row) - 1)); + + if (rownum == 0 || streq(row, "first")) + XawTablePrependRow (wp->w); + else if (rownum == nrows || streq (row, "last")) + XawTableAppendRow (wp->w); + else + XawTableInsertRow (wp->w, rownum); + + return (TCL_OK); +} + + +/* widgetSetTableSize -- Set the size of the specified table. + * + * Usage: setTableSize nrows ncols + * + */ +static int +widgetSetTableSize (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + int nrows, ncols; + + + if (argc < 3) + return (TCL_ERROR); + + nrows = atoi (argv[1]); + ncols = atoi (argv[2]); + if (XawTableSetNewSize (wp->w, nrows, ncols) >= 0) + return (TCL_OK); + else + return (TCL_ERROR); +} + + + +/* widgetGetTableSize -- Get the size of the specified table. + * + * Usage: getTableSize nrows ncols + * + */ +static int +widgetGetTableSize (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + char buf[16], *nrows, *ncols; + int nr, nc; + + + if (argc < 3) + return (TCL_ERROR); + + nrows = argv[1]; + ncols = argv[2]; + + XawTableGetSize (wp->w, &nr, &nc); + + sprintf (buf, "%d", nr); + Tcl_SetVar (wp->obm->tcl, nrows, buf, 0); + sprintf (buf, "%d", nc); + Tcl_SetVar (wp->obm->tcl, ncols, buf, 0); + + return (TCL_OK); +} + + + +/* widgetRealize -- Realize a widget. This activates and assigns windows for + * a widget and all of its descendants. Realizing a widget does not in itself + * cause it to appear on the screen. + * + * Usage: realize + */ +static int +widgetRealize (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + + XtRealizeWidget (wp->w); + return (TCL_OK); +} + + +/* widgetUnrealize -- Unrealize a widget. This destroys the windows assigned + * to a widget and all of its descendants. + * + * Usage: unrealize + */ +static int +widgetUnrealize (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + + XtUnrealizeWidget (wp->w); + return (TCL_OK); +} + + +/* widgetIsRealized -- Test whether a widget is realized. + * + * Usage: isRealized + */ +static int +widgetIsRealized (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + Boolean sensitive; + + if (XtIsRealized (wp->w)) + Tcl_SetResult (wp->obm->tcl, TRUESTR, TCL_STATIC); + else + Tcl_SetResult (wp->obm->tcl, FALSESTR, TCL_STATIC); + return (TCL_OK); +} + + +/* widgetMap -- Map a widget. + * + * Usage: map + */ +static int +widgetMap (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + + XtRealizeWidget (wp->w); + XtMapWidget (wp->w); + return (TCL_OK); +} + + +/* widgetUnmap -- Unmap a widget. + * + * Usage: unmap + */ +static int +widgetUnmap (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + Widget w = wp->w; + + if (!XtIsRealized(w) || !XtWindow(w)) + return (TCL_ERROR); + + XmuUpdateMapHints (obm->display, XtWindow(w), NULL); + XWithdrawWindow (obm->display, XtWindow(w), + XScreenNumberOfScreen(obm->screen)); + + return (TCL_OK); +} + + +/* widgetManage -- Manage a list of child widgets. These should share the + * same common parent, a geometry widget of some sort. Managing the + * children makes them appear in the window, possibly causing the other + * children to be rearranged in the window. + * + * Usage: manage child [child ...] + * + * This message should be sent to the geometry widget which is the parent + * of the children. + */ +static int +widgetManage (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + Widget w, children[512]; + int nchildren, i; + + for (i=1, nchildren=0; i < argc; i++) + if (w = XtNameToWidget (wp->w, argv[i])) + children[nchildren++] = w; + + XtManageChildren (children, nchildren); + return (TCL_OK); +} + + +/* widgetUnmanage -- Unmanage a list of child widgets. These should share the + * same common parent, a geometry widget of some sort. Unmanaging the + * children makes them disappear from the window and be removed from geometry + * management, possibly causing the other children to be rearranged in the + * window. + * + * Usage: unmanage child [child ...] + * + * This message should be sent to the geometry widget which is the parent + * of the children. + */ +static int +widgetUnmanage (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + Widget w, children[512]; + int nchildren, i; + + for (i=1, nchildren=0; i < argc; i++) + if (w = XtNameToWidget (wp->w, argv[i])) + children[nchildren++] = w; + + XtUnmanageChildren (children, nchildren); + return (TCL_OK); +} + + +/* widgetPopup -- Popup a shell widget. If no grab is indicated the popup + * can remain up while other windows accept input. + * + * Usage: popup [grab-kind] + */ +static int +widgetPopup (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + XtGrabKind grab; + + grab = XtGrabNone; + if (argc >= 2) { + if (strcmp (argv[1], "GrabNone") == 0) + grab = XtGrabNone; + else if (strcmp (argv[1], "GrabNonexclusive") == 0) + grab = XtGrabNonexclusive; + else if (strcmp (argv[1], "GrabExclusive") == 0) + grab = XtGrabExclusive; + } + + XtPopup (wp->w, grab); + return (TCL_OK); +} + + +/* widgetPopdown -- Popdown a shell widget. + * + * Usage: popdown + */ +static int +widgetPopdown (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + + XtPopdown (wp->w); + return (TCL_OK); +} + + +/* widgetPopupSpringLoaded -- Popup a shell widget, e.g., a popup menu. + * This implies an exclusive grab. + * + * Usage: popupSpringLoaded + */ +static int +widgetPopupSpringLoaded (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + + XtPopupSpringLoaded (wp->w); + return (TCL_OK); +} + + +/* widgetMove -- Move a widget to the given window relative coordinates. + * + * Usage: move x y + */ +static int +widgetMove (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + Arg args[10]; int nargs=0; + + if (argc < 3) + return (TCL_ERROR); + + XtSetArg (args[nargs], XtNx, atoi(argv[1])); nargs++; + XtSetArg (args[nargs], XtNy, atoi(argv[2])); nargs++; + + XtSetValues (wp->w, args, nargs); + + return (TCL_OK); +} + + +/* widgetResize -- Resize a widget. + * + * Usage: resize width height [border-width] + */ +static int +widgetResize (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + Arg args[10]; int nargs=0; + + if (argc < 3) + return (TCL_ERROR); + + XtSetArg (args[nargs], XtNwidth, atoi(argv[1])); nargs++; + XtSetArg (args[nargs], XtNheight, atoi(argv[2])); nargs++; + if (argc > 3) { + XtSetArg (args[nargs], XtNborderWidth, atoi(argv[3])); + nargs++; + } + + XtSetValues (wp->w, args, nargs); + + return (TCL_OK); +} + + +/* widgetConfigure -- Configure a widget, i.e., execute a simultaneous + * move and resize. + * + * Usage: configure x y width height [border-width] + */ +static int +widgetConfigure (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + Arg args[10]; int nargs=0; + + if (argc < 3) + return (TCL_ERROR); + + XtSetArg (args[nargs], XtNx, atoi(argv[1])); nargs++; + XtSetArg (args[nargs], XtNy, atoi(argv[2])); nargs++; + XtSetArg (args[nargs], XtNwidth, atoi(argv[3])); nargs++; + XtSetArg (args[nargs], XtNheight, atoi(argv[4])); nargs++; + if (argc > 5) { + XtSetArg (args[nargs], XtNborderWidth, atoi(argv[5])); + nargs++; + } + + XtSetValues (wp->w, args, nargs); + + return (TCL_OK); +} + + +/* widgetParseGeometry -- Compute the position and size of a region within + * a window , given a user defined geometry and a default geometry. + * + * Usage: parseGeometry user_geom def_geom x y width height + * + * Geometries are specified as in X, e.g. 123x456+5-5. The default geometry + * must be fully specified. + */ +static int +widgetParseGeometry (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + + register int uflags, dflags; + Dimension winWidth, winHeight; + int need, x, y, width, height; + char *user_geom, *def_geom; + char *s_x, *s_y, *s_width, *s_height; + unsigned int u_width, u_height; + unsigned int d_width, d_height; + int u_x, u_y, d_x, d_y; + char buf[SZ_NUMBER]; + + if (argc != 7) + return (TCL_ERROR); + + user_geom = argv[1]; + def_geom = argv[2]; + s_x = argv[3]; + s_y = argv[4]; + s_width = argv[5]; + s_height = argv[6]; + + XtVaGetValues (wp->w, + XtNwidth, &winWidth, + XtNheight, &winHeight, + NULL); + + /* Parse the default geometry. */ + dflags = XParseGeometry (def_geom, &d_x, &d_y, &d_width, &d_height); + need = (XValue | YValue | WidthValue | HeightValue); + if ((dflags & need) != need) { + Tcl_SetResult (obm->tcl, + "default geometry not fully qualified", TCL_VOLATILE); + return (TCL_ERROR); + } + + /* Parse the user supplied geometry. */ + uflags = XParseGeometry (user_geom, &u_x, &u_y, &u_width, &u_height); + + /* Compute the final geometry. This is constrained to fit within + * the given window. + */ + width = (uflags & WidthValue) ? u_width : d_width; + width = max(0, min((int)winWidth, width)); + + height = (uflags & HeightValue) ? u_height : d_height; + height = max(0, min((int)winHeight, height)); + + if (uflags & XValue) + x = (uflags & XNegative) ? winWidth + u_x - width : u_x; + else + x = (dflags & XNegative) ? winWidth + d_x - width : d_x; + x = max(0, min((int)winWidth-width, x)); + + if (uflags & YValue) + y = (uflags & YNegative) ? winHeight + u_y - height : u_y; + else + y = (dflags & YNegative) ? winHeight + d_y - height : d_y; + y = max(0, min((int)winHeight-height, y)); + + /* Output the results. + */ + sprintf (buf, "%d", x); + if ((Tcl_SetVar (obm->tcl, s_x, buf, 0)) == NULL) + return (TCL_ERROR); + sprintf (buf, "%d", y); + if ((Tcl_SetVar (obm->tcl, s_y, buf, 0)) == NULL) + return (TCL_ERROR); + sprintf (buf, "%d", width); + if ((Tcl_SetVar (obm->tcl, s_width, buf, 0)) == NULL) + return (TCL_ERROR); + sprintf (buf, "%d", height); + if ((Tcl_SetVar (obm->tcl, s_height, buf, 0)) == NULL) + return (TCL_ERROR); + + return (TCL_OK); +} + + +/* widgetGetGeometry -- Given a subregion within a rectangular window compute + * the geometry specification which best describes the region. + * + * Usage: geom = getGeometry x y width height [nogravity] + * + * If gravity is enabled (the default) and the rect is near an edge or corner + * the specified geometry will be in the form -X-Y to cause the region to + * track the edge or corner of the window. Otherwise the absolute coordinates + * of the region are returned. + */ +static int +widgetGetGeometry (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + + register char *op; + Dimension winWidth, winHeight; + int dist, gravity, x, y, width, height; + char buf[128]; + + if (argc < 5) + return (TCL_ERROR); + + x = atoi(argv[1]); + y = atoi(argv[2]); + width = atoi(argv[3]); + height = atoi(argv[4]); + gravity = (argc < 6 || strncmp(argv[5],"no",2) != 0); + + XtVaGetValues (wp->w, + XtNwidth, &winWidth, + XtNheight, &winHeight, + NULL); + + sprintf (buf, "%dx%d", width, height); + for (op=buf; *op; ) + op++; + + if (gravity && (dist = winWidth - (x + width)) < 10) + sprintf (op, "-%d", dist); + else + sprintf (op, "+%d", x); + while (*op) + op++; + + if (gravity && (dist = winHeight - (y + height)) < 10) + sprintf (op, "-%d", dist); + else + sprintf (op, "+%d", y); + + Tcl_SetResult (wp->obm->tcl, buf, TCL_VOLATILE); + return (TCL_OK); +} + + +/* widgetSetSensitive -- Set the sensitivity of a widget. + * + * Usage: setSensitive <sensitive> + */ +static int +widgetSetSensitive (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + Boolean sensitive; + + sensitive = FALSE; + if (argc >= 2) + if (strcmp (argv[1], "true") == 0 || + strcmp (argv[1], "True") == 0 || + strcmp (argv[1], "TRUE") == 0 || + strcmp (argv[1], "1") == 0) { + + sensitive = TRUE; + } + + XtSetSensitive (wp->w, sensitive); + return (TCL_OK); +} + + +/* widgetIsSensitive -- Test the sensitivity of a widget. + * + * Usage: isSensitive + */ +static int +widgetIsSensitive (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + WidgetPrivate wp = &obj->widget; + Boolean sensitive; + + if (XtIsSensitive (wp->w)) + Tcl_SetResult (wp->obm->tcl, TRUESTR, TCL_STATIC); + else + Tcl_SetResult (wp->obm->tcl, FALSESTR, TCL_STATIC); + + return (TCL_OK); +} + + +/* + * Event handling facility. + */ + +/* Event masks. */ +#define NonMaskable 0 +struct evMask { + char *name; + int mask; +} eventMasks[] = { + { "nonMaskable", NonMaskable }, + { "button1MotionMask", Button1MotionMask }, + { "button2MotionMask", Button2MotionMask }, + { "button3MotionMask", Button3MotionMask }, + { "button4MotionMask", Button4MotionMask }, + { "button5MotionMask", Button5MotionMask }, + { "buttonMotionMask", ButtonMotionMask }, + { "buttonPressMask", ButtonPressMask }, + { "buttonReleaseMask", ButtonReleaseMask }, + { "colormapChangeMask", ColormapChangeMask }, + { "enterWindowMask", EnterWindowMask }, + { "exposureMask", ExposureMask }, + { "focusChangeMask", FocusChangeMask }, + { "keyPressMask", KeyPressMask }, + { "keyReleaseMask", KeyReleaseMask }, + { "keymapStateMask", KeymapStateMask }, + { "leaveWindowMask", LeaveWindowMask }, + { "noEventMask", NoEventMask }, + { "ownerGrabButtonMask", OwnerGrabButtonMask }, + { "pointerMotionHintMask", PointerMotionHintMask }, + { "pointerMotionMask", PointerMotionMask }, + { "propertyChangeMask", PropertyChangeMask }, + { "resizeRedirectMask", ResizeRedirectMask }, + { "structureNotifyMask", StructureNotifyMask }, + { "substructureNotifyMask", SubstructureNotifyMask }, + { "substructureRedirectMask", SubstructureRedirectMask }, + { "visibilityChangeMask", VisibilityChangeMask }, +}; + +/* Event types. */ +struct evType { + char *name; + int type; +} eventTypes[] = { + { "buttonPress", ButtonPress }, + { "buttonRelease", ButtonRelease }, + { "circulateNotify", CirculateNotify }, + { "circulateRequest", CirculateRequest }, + { "clientMessage", ClientMessage }, + { "colormapNotify", ColormapNotify }, + { "configureNotify", ConfigureNotify }, + { "configureRequest", ConfigureRequest }, + { "createNotify", CreateNotify }, + { "destroyNotify", DestroyNotify }, + { "enterNotify", EnterNotify }, + { "expose", Expose }, + { "focusIn", FocusIn }, + { "focusOut", FocusOut }, + { "graphicsExpose", GraphicsExpose }, + { "gravityNotify", GravityNotify }, + { "keyPress", KeyPress }, + { "keyRelease", KeyRelease }, + { "keymapNotify", KeymapNotify }, + { "leaveNotify", LeaveNotify }, + { "mapNotify", MapNotify }, + { "mapRequest", MapRequest }, + { "mappingNotify", MappingNotify }, + { "motionNotify", MotionNotify }, + { "noExpose", NoExpose }, + { "propertyNotify", PropertyNotify }, + { "reparentNotify", ReparentNotify }, + { "resizeRequest", ResizeRequest }, + { "selectionClear", SelectionClear }, + { "selectionNotify", SelectionNotify }, + { "selectionRequest", SelectionRequest }, + { "unmapNotify", UnmapNotify }, + { "visibilityNotify", VisibilityNotify }, +}; + + +/* widgetAddEventHandler -- Add a custom event handler to a widget. A list + * of event masks is given to define the classes of events the user supplied + * event handling procedure is to receive. + * + * Usage: addEventHandler <procname> <event-mask> [<event-mask>...] + */ +static int +widgetAddEventHandler (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + register WidgetPrivate wp = &obj->widget; + register ObmContext obm = wp->obm; + ObmCallback cb, new_cb; + int event_mask, i, j; + Boolean nonmaskable; + + if (argc < 3) + return (TCL_ERROR); + + event_mask = 0; + nonmaskable = FALSE; + + /* Get the event mask. */ + for (j=2; j < argc; j++) { + for (i=0; i < XtNumber(eventMasks); i++) { + if (strcmp (eventMasks[i].name, argv[j]) == 0) { + if (eventMasks[i].mask == NonMaskable) + nonmaskable = TRUE; + else + event_mask |= eventMasks[i].mask; + break; + } + } + } + + /* Create event handler record. */ + new_cb = (ObmCallback) XtCalloc (1, sizeof (obmCallback)); + strcpy (new_cb->name, argv[1]); + new_cb->u.obj = (ObmObject) obj; + new_cb->client_data = (XtPointer) event_mask; + + /* Add record to tail of event handler list. */ + if (wp->event_handler) { + for (cb = wp->event_handler; cb->next; cb = cb->next) + ; + cb->next = new_cb; + } else + wp->event_handler = new_cb; + + /* Post event handler. */ + XtAddEventHandler (wp->w, event_mask, nonmaskable, widgetEvent, new_cb); + + return (TCL_OK); +} + +/* widgetRemoveEventHandler -- Remove an event handler previously posted + * with addEventHandler, above. + * + * Usage: removeEventHandler procname + */ +static int +widgetRemoveEventHandler (msg, tcl, argc, argv) +MsgContext msg; +Tcl_Interp *tcl; +int argc; +char **argv; +{ + WidgetObject obj = (WidgetObject) msg->object[msg->level]; + register WidgetPrivate wp = &obj->widget; + register ObmContext obm = wp->obm; + register ObmCallback cb, pcb; + Boolean nonmaskable; + char *procname; + + if (argc < 2) + return (TCL_ERROR); + + procname = argv[1]; + nonmaskable = False; + + for (cb = wp->event_handler, pcb=NULL; cb; pcb=cb, cb = cb->next) + if (strcmp (cb->name, procname) == 0) + break; + + if (cb) { + XtRemoveEventHandler (wp->w, (int) cb->client_data, nonmaskable, + widgetEvent, cb); + if (pcb) + pcb->next = cb->next; + else + wp->event_handler = NULL; + XtFree ((char *)cb); + } + + return (TCL_OK); +} + + +/* widgetEvent -- Generic event handler called when a widget event handler + * posted by addEventHandler is called. + * + * The user event handler is called as + * + * userEventHandler widget event-type time wx wy rx ry other + * + * where "other" is an event-type specific list of fields describing the + * the event. + */ +static void +widgetEvent (w, cb, event, continue_to_dispatch) +Widget w; +ObmCallback cb; +XEvent *event; +Boolean *continue_to_dispatch; +{ + WidgetObject obj = (WidgetObject) cb->u.obj; + WidgetPrivate wp = &obj->widget; + ObmContext obm = wp->obm; + char cmd[SZ_COMMAND]; + register char *ip, *op; + register int i, j; + int status; + + /* Our job is to translate the X event into a call to a widget server + * procedure. Start with the callback procedure name. + */ + for (ip = cb->name, op=cmd; *ip; ) + *op++ = *ip++; + *op++ = ' '; + + /* Add the name of the widget that received the event. */ + for (ip = obj->core.name; *ip; ) + *op++ = *ip++; + *op++ = ' '; + + /* Add the event type. */ + for (i=0; i < XtNumber(eventTypes); i++) { + if (eventTypes[i].type == event->type) { + for (ip = eventTypes[i].name; *ip; ) + *op++ = *ip++; + *op++ = ' '; + break; + } + + /* Ignore events we don't know anything about. */ + if (i >= XtNumber(eventTypes)) + return; + } + + /* Add the event specific fields. */ + switch (event->type) { + case KeyPress: + case KeyRelease: + { XKeyPressedEvent *ev = (XKeyPressedEvent *) event; + char buf[20]; + int n; + + sprintf (op, "%u %d %d %d %d ", + ev->time, ev->x, ev->y, ev->x_root, ev->y_root); + while (*op) op++; + + *op++ = '{'; + if ((n = XLookupString(ev,buf,sizeof(buf),NULL,NULL)) > 0) { + for (ip=buf; --n >= 0; ) + if (*ip <= ' ') { + *op++ = '^'; + *op++ = *ip++ + 'A' - 1; + } else if (isprint (*ip)) { + *op++ = *ip++; + } else + ip++; + } else { + /* This case occurs when only a modifier is typed. */ + for (ip = "??"; *op++ = *ip++; ) + ; + } + *op++ = ' '; + op = widgetEventState (op, ev->state); + while (op > cmd && isspace (*(op-1))) + --op; + *op++ = '}'; + } + break; + + case ButtonPress: + case ButtonRelease: + { XButtonPressedEvent *ev = (XButtonPressedEvent *) event; + + sprintf (op, "%u %d %d %d %d ", + ev->time, ev->x, ev->y, ev->x_root, ev->y_root); + while (*op) op++; + + *op++ = '{'; + sprintf (op, "%d ", ev->button); while (*op) op++; + op = widgetEventState (op, ev->state); + while (op > cmd && isspace (*(op-1))) + --op; + *op++ = '}'; + } + break; + + case KeymapNotify: + { XKeymapEvent *ev = (XKeymapEvent *) event; + KeySym keysym; + + sprintf (op, "0 0 0 0 0 "); + while (*op) op++; + + *op++ = '{'; + for (j=0; j < 32; j++) { + for (i=0; i < 8; i++) + if ((ev->key_vector[j]) & (1 << i)) { + keysym = XKeycodeToKeysym (obm->display, + j * 8 + i, 0); + if (ip = XKeysymToString (keysym)) { + while (*ip) + *op++ = *ip++; + *op++ = ' '; + } + } + } + *op++ = '}'; + } + break; + + case MotionNotify: + case EnterNotify: + case LeaveNotify: + { XPointerMovedEvent *ev = (XPointerMovedEvent *) event; + + sprintf (op, "%u %d %d %d %d ", + ev->time, ev->x, ev->y, ev->x_root, ev->y_root); + while (*op) op++; + + *op++ = '{'; + op = widgetEventState (op, ev->state); + while (op > cmd && isspace (*(op-1))) + --op; + *op++ = '}'; + } + break; + + case FocusIn: + case FocusOut: + { XFocusChangeEvent *ev = (XFocusChangeEvent *) event; + + sprintf (op, "0 0 0 0 0 "); + while (*op) op++; + } + break; + + case Expose: + { XExposeEvent *ev = (XExposeEvent *) event; + + sprintf (op, "0 %d %d 0 0 ", ev->x, ev->y); + while (*op) op++; + + *op++ = '{'; + sprintf (op, "%d ", ev->width); while (*op) op++; + sprintf (op, "%d ", ev->height); while (*op) op++; + sprintf (op, "%d ", ev->count); while (*op) op++; + *op++ = '}'; + } + break; + + case GraphicsExpose: + { XGraphicsExposeEvent *ev = (XGraphicsExposeEvent *) event; + + sprintf (op, "0 %d %d 0 0 ", ev->x, ev->y); + while (*op) op++; + + *op++ = '{'; + sprintf (op, "%d ", ev->width); while (*op) op++; + sprintf (op, "%d ", ev->height); while (*op) op++; + sprintf (op, "%d ", ev->count); while (*op) op++; + *op++ = '}'; + } + break; + + case NoExpose: + case ColormapNotify: + case PropertyNotify: + case VisibilityNotify: + case ResizeRequest: + case CirculateNotify: + case ConfigureNotify: + case CreateNotify: + case DestroyNotify: + case GravityNotify: + case MapNotify: + case MappingNotify: + case ReparentNotify: + case SelectionNotify: + case UnmapNotify: + { + sprintf (op, "0 0 0 0 0 "); + while (*op) op++; + } + break; + + case CirculateRequest: + case ConfigureRequest: + case MapRequest: + case SelectionRequest: + { + sprintf (op, "0 0 0 0 0 "); + while (*op) op++; + } + break; + + + case ClientMessage: + case SelectionClear: + { + sprintf (op, "0 0 0 0 0 "); + while (*op) op++; + } + break; + } + *op = '\0'; + + /* Call the user supplied event handler. */ + status = Tcl_Eval (obm->tcl, cmd); + if (status != TCL_OK) { + fprintf (stderr, "Error on line %d of %s: %s\n", + obm->tcl->errorLine, cb->name, obm->tcl->result); + } +} + + +/* widgetEventState -- Encode the "state" field of an event struct. + */ +char * +widgetEventState (op, state) +register char *op; +unsigned int state; +{ + if (state & ShiftMask) + { sprintf (op, "shift "); while (*op) op++; } + if (state & LockMask) + { sprintf (op, "lock "); while (*op) op++; } + if (state & ControlMask) + { sprintf (op, "control "); while (*op) op++; } + if (state & Mod1Mask) + { sprintf (op, "mod1 "); while (*op) op++; } + if (state & Mod2Mask) + { sprintf (op, "mod2 "); while (*op) op++; } + if (state & Mod3Mask) + { sprintf (op, "mod3 "); while (*op) op++; } + if (state & Mod4Mask) + { sprintf (op, "mod4 "); while (*op) op++; } + if (state & Mod5Mask) + { sprintf (op, "mod5 "); while (*op) op++; } + + *op = '\0'; + return (op); +} + + + +/* widgetGetFontName -- Encode the font name in a string in XLFD format. + */ + +#define SZ_FONT_NAME 128 + +static char * +widgetGetFontName (display, fs) /* MF016 */ +Display *display; +XFontStruct *fs; +{ + register int i; + unsigned long val; + char *name = (char *) malloc (SZ_FONT_NAME), *str, *lp; + + name[0] = '\0'; + if (fs) { + for (i=0; i < NUMITEMS(fontNamePropTable); i++) { + fontNamePropTable[i].atom = + XInternAtom(display, fontNamePropTable[i].name, 0); + if (XGetFontProperty (fs, fontNamePropTable[i].atom, &val)) { + switch (fontNamePropTable[i].type) { + case atom: + str = XGetAtomName (display, (Atom)val); + for (lp=str; *lp; lp++) + if (isupper(*lp)) + *lp = tolower(*lp); + strcat (name, str); + XFree (str); + break; + + case pixel_size: + case point_size: + case resolution: + case resolution_x: + case resolution_y: + case average_width: + case scaledX: + case scaledY: + case unscaled: + case scaledXoverY: + case uncomputed: + sprintf(name, "%s%d", name, val); + break; + } + } else + strcat(name, "*"); + + if (i != (NUMITEMS(fontNamePropTable)-1)) + strcat(name, "-"); + } + } + + return (name); +} |