aboutsummaryrefslogtreecommitdiff
path: root/vendor/x11iraf/obm/param.c
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/x11iraf/obm/param.c')
-rw-r--r--vendor/x11iraf/obm/param.c401
1 files changed, 401 insertions, 0 deletions
diff --git a/vendor/x11iraf/obm/param.c b/vendor/x11iraf/obm/param.c
new file mode 100644
index 00000000..27226330
--- /dev/null
+++ b/vendor/x11iraf/obm/param.c
@@ -0,0 +1,401 @@
+/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <ObmP.h>
+
+
+/*
+ * UI PARAMETER class.
+ * --------------------------
+ * The UI parameter class is used for client-UI communications. The client
+ * does not control the user interface directly, rather the UI defines a set
+ * of abstract UI parameters, and during execution the client application
+ * assigns values to these parameters. These UI parameters should be thought
+ * of as describing the runtime state of the client as viewed by the GUI.
+ * The GUI is free to interpret this state information in any way, including
+ * ignoring it. Many GUIs can be written which use the same client state
+ * as described by the UI parameters.
+ *
+ * Assigning a value to a UI parameter causes the new value to be stored, and
+ * any parameter action procedures registered by the UI to be called.
+ * The action or actions (if any) taken when a parameter value changes are
+ * arbitrary, e.g. the action might be something as simple as changing a
+ * displayed value of a UI widget, or something more complex like displaying
+ * a popup.
+ *
+ * UI Parameter class commands:
+ *
+ * getValue
+ * setValue <new-value>
+ * addCallback <procedure-name>
+ * deleteCallback <procedure-name>
+ * notify
+ *
+ * The most common usage is for the GUI to post one or more callbacks for
+ * each UI parameter. When the UI parameter value is changed (with setValue,
+ * e.g. by the client) the GUI callback procedures are called with the old
+ * and new UI parameter values on the command line. addCallback is used to
+ * add a callback procedure, and deleteCallback to delete one. Multiple
+ * callbacks may be registered for a single UI parameter. notify is used
+ * to simulate a parameter value change, causing any callback procedures to
+ * be invoked.
+ *
+ * The callback procedure is called as follows:
+ *
+ * user-procedure param-name {old-value} {new-value}
+ *
+ * The important thing to note here is that the old and new value strings
+ * are quoted with braces. This prevents any interpretation of the string
+ * by Tcl when the callback is executed, which is necessary because the
+ * strings can contain arbitrary data. When Tcl calls the callback the
+ * first level of braces will be stripped off, leaving old-value and new-value
+ * each as a single string argument.
+ */
+
+struct parameterPrivate {
+ ObmContext obm;
+ char *value;
+ int len_value;
+ ObmCallback callback;
+};
+
+typedef struct parameterPrivate *ParameterPrivate;
+
+struct parameterObject {
+ struct obmObjectCore core;
+ struct parameterPrivate parameter;
+};
+
+typedef struct parameterObject *ParameterObject;
+
+/* Object message context. */
+struct msgContext {
+ Tcl_Interp *tcl; /* class interpreter */
+ ObmObject object[MAX_LEVELS]; /* object which received last message */
+ int level;
+};
+typedef struct msgContext *MsgContext;
+
+static void ParameterDestroy();
+static int ParameterEvaluate();
+static ObmObject ParameterCreate();
+static void ParameterClassDestroy();
+static int parameterSetValue(), parameterGetValue(), parameterNotify();
+static int parameterAddCallback(), parameterDeleteCallback();
+
+
+/* ParameterClassInit -- Initialize the class record for the parameter class.
+ */
+void
+ParameterClassInit (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+ register Tcl_Interp *tcl;
+ register MsgContext msg;
+
+ /* Install the class methods. */
+ classrec->ClassDestroy = ParameterClassDestroy;
+ classrec->Create = (ObmFunc) ParameterCreate;
+ classrec->Destroy = ParameterDestroy;
+ classrec->Evaluate = ParameterEvaluate;
+
+ /* Since there can be many instances of the parameter object and
+ * they all respond to the same class messages, a single interpreter
+ * is used for all objects.
+ */
+ msg = (MsgContext) XtMalloc (sizeof (struct msgContext));
+ classrec->class_data = (XtPointer) msg;
+ msg->tcl = tcl = Tcl_CreateInterp();
+ msg->level = 0;
+
+ /* Register parameter-object actions. */
+ Tcl_CreateCommand (tcl, "setValue",
+ parameterSetValue, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl, "getValue",
+ parameterGetValue, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl, "addCallback",
+ parameterAddCallback, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl, "deleteCallback",
+ parameterDeleteCallback, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl, "notify",
+ parameterNotify, (ClientData)msg, NULL);
+}
+
+
+/* ParameterClassDestroy -- Custom destroy procedure for the parameter
+ * class.
+ */
+static void
+ParameterClassDestroy (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;
+ }
+}
+
+
+/* ParameterCreate -- Create an instance of a parameter object.
+ */
+static ObmObject
+ParameterCreate (obm, name, classrec, parent, args, nargs)
+ObmContext obm;
+char *name;
+ObjClassRec classrec;
+char *parent;
+ArgList args;
+int nargs;
+{
+ register ParameterObject obj;
+
+ obj = (ParameterObject) XtCalloc (1, sizeof (struct parameterObject));
+ obj->parameter.obm = obm;
+
+ return ((ObmObject) obj);
+}
+
+
+/* ParameterDestroy -- Destroy an instance of a parameter object.
+ */
+static void
+ParameterDestroy (object)
+ObmObject object;
+{
+ register ParameterObject obj = (ParameterObject) object;
+ register ObmCallback cb, next;
+
+ /* Destroy the object in the second final call to Destroy. */
+ if (!obj->core.being_destroyed++)
+ return;
+
+ XtFree ((char *)obj->parameter.value);
+ for (cb = obj->parameter.callback; cb; cb = next) {
+ next = cb->next;
+ XtFree ((char *)cb);
+ }
+}
+
+
+/* ParameterEvaluate -- Evaluate a parameter command or message.
+ */
+static int
+ParameterEvaluate (object, command)
+ObmObject object;
+char *command;
+{
+ register ParameterObject obj = (ParameterObject) object;
+ register MsgContext msg = (MsgContext) obj->core.classrec->class_data;
+ register ObmContext obm = obj->parameter.obm;
+ int status;
+
+ /* 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.
+ */
+ msg->object[++msg->level] = object;
+ Tcl_SetResult (obm->tcl, "", TCL_VOLATILE);
+
+ if (!obmClientCommand (msg->tcl, command)) {
+ Tcl_SetResult (obm->tcl, "invalid command", TCL_VOLATILE);
+ status = TCL_ERROR;
+ } else {
+ status = Tcl_Eval (msg->tcl, command);
+ if (status == TCL_ERROR) {
+ if (*msg->tcl->result)
+ Tcl_SetResult (obm->tcl, msg->tcl->result, TCL_VOLATILE);
+ else {
+ /* Supply a default error message if none was returned. */
+ Tcl_SetResult (obm->tcl, "evaluation error", TCL_VOLATILE);
+ }
+ obm->tcl->errorLine = msg->tcl->errorLine;
+
+ } else if (*msg->tcl->result)
+ Tcl_SetResult (obm->tcl, msg->tcl->result, TCL_VOLATILE);
+ }
+
+ msg->level--;
+ return (status);
+}
+
+
+/* parameterSetValue -- Set the value of a parameter, and notify all clients
+ * via the posted callback procedures that the parameter value has changed.
+ *
+ * Usage: setValue <new-value>
+ */
+static int
+parameterSetValue (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ParameterObject obj = (ParameterObject) msg->object[msg->level];
+ register ObmContext obm = obj->parameter.obm;
+ register ParameterPrivate pp = &obj->parameter;
+ char *new_value, *old_value;
+ ObmCallback cb, cbl[128];
+ int ncb, status, i;
+
+ /* Assign new value. */
+ old_value = pp->value;
+ pp->len_value = strlen (argv[1]);
+ pp->value = new_value = XtMalloc (pp->len_value + 1);
+ memmove (pp->value, argv[1], pp->len_value + 1);
+
+ /* Safeguard callback list against changes by callback procs. */
+ for (cb = pp->callback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = cb;
+
+ /* Notify clients that value has changed. */
+ for (i=0; i < ncb && (cb = cbl[i]) != NULL; i++) {
+/*printf ("setValue: i=%d obj='%s' cb='%s' new='%s'\n",
+i, obj->core.name, cb->name, new_value);*/
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ "{", old_value ? old_value : "", "} ",
+ "{", new_value, "} ",
+ 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);
+ }
+ }
+
+ XtFree ((char *)old_value);
+ Tcl_SetResult (obm->tcl, "", TCL_STATIC);
+ return (TCL_OK);
+}
+
+
+/* parameterGetValue -- Get the value of a parameter.
+ *
+ * Usage: getValue
+ */
+static int
+parameterGetValue (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ParameterObject obj = (ParameterObject) msg->object[msg->level];
+ register ObmContext obm = obj->parameter.obm;
+ register ParameterPrivate pp = &obj->parameter;
+
+ Tcl_SetResult (obm->tcl, pp->value, TCL_STATIC);
+ return (TCL_OK);
+}
+
+
+/* parameterNotify -- Notify the registered clients of a parameter as if the
+ * value had changed.
+ *
+ * Usage: notify
+ */
+static int
+parameterNotify (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ParameterObject obj = (ParameterObject) msg->object[msg->level];
+ register ObmContext obm = obj->parameter.obm;
+ register ParameterPrivate pp = &obj->parameter;
+ ObmCallback cb;
+ int status;
+
+ /* Notify clients. */
+ for (cb = pp->callback; cb; cb = cb->next) {
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ "{", pp->value, "} ",
+ "{", pp->value, "} ",
+ 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);
+ }
+ }
+
+ Tcl_SetResult (obm->tcl, "", TCL_STATIC);
+ return (TCL_OK);
+}
+
+
+/* parameterAddCallback -- Add a callback procedure to the callback list for
+ * a parameter.
+ *
+ * Usage: addCallback <procedure-name>
+ */
+static int
+parameterAddCallback (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ParameterObject obj = (ParameterObject) msg->object[msg->level];
+ register ParameterPrivate pp = &obj->parameter;
+ ObmCallback cb, new_cb;
+
+ /* Create callback record. */
+ new_cb = (ObmCallback) XtCalloc (1, sizeof (obmCallback));
+ strcpy (new_cb->name, argv[1]);
+
+ /* Add callback to tail of callback list. */
+ if (pp->callback) {
+ for (cb = pp->callback; cb->next; cb = cb->next)
+ ;
+ cb->next = new_cb;
+ } else
+ pp->callback = new_cb;
+
+ return (TCL_OK);
+}
+
+
+/* parameterDeleteCallback -- Delete a callback procedure previously registered
+ * for a parameter.
+ *
+ * Usage: deleteCallback <procedure-name>
+ */
+static int
+parameterDeleteCallback (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ParameterObject obj = (ParameterObject) msg->object[msg->level];
+ register ParameterPrivate pp = &obj->parameter;
+ ObmCallback cb, prev;
+
+ /* Locate and delete procedure entry in callback list. */
+ for (prev=NULL, cb=pp->callback; cb; prev=cb, cb=cb->next)
+ if (strcmp (cb->name, argv[1]) == 0) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ pp->callback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ }
+
+ return (TCL_OK);
+}