[comp.windows.x] XtCallActionProc - donated

mark@sunquest.UUCP (Mark Langley) (09/24/88)

  Better to curse the darkness than go around lighting
  small candles...

Not having anything better to do on a Friday afternoon I
wrote the function that I requested.  Namely, I think an application
program should be able to invoke actions in the same way the 
translation manager can.  Thus to invoke an XtActionProc called
foo, it should take no more than the following

	XtCallActionProc( "foo(abc,def)" );

The code to do this was not quite as easy as I had hoped, but 
straightforward nonetheless.  The context diff was short
enough (under 150 lines) that I post it here.  It's just
two functions that must go in TMstate.c.  Unfortunately they
can't be isolated because they need to access one private 
static variable called globalActionList...

BTW kudos to Charles Haynes @Dec who (I think) built the 
translation routines.  They are well done.

Have Fun
Mark Langley
mark@sunquest.com

------ Cut Here ------

*** /usr/src/local/x11r2/lib/Xt/TMstate.c	Sat Sep 24 07:30:04 1988
--- TMstate.c	Sat Sep 24 08:16:49 1988
***************
*** 641,660 ****
--- 641,783 ----
  }
  
  typedef struct _ActionListRec *ActionList;
  typedef struct _ActionListRec {
      ActionList		next;
      CompiledActionTable table;
  } ActionListRec;
  
  static ActionList globalActionList = NULL;
  
+ #define OPAREN '('
+ #define CPAREN ')'
+ #define COMMA  ','
+ 
+ /*
+  * sParseAction - Ad Hoc function to parse an action and return strings.
+  *   function returns 0 on ok, and a string on error.
+  *
+  * Note that there are no strings malloced if an error occurs,
+  * *size XtMalloced otherwise.  *size holds the max number
+  * to allocate on input.
+  *
+  * donated
+  *  Mark Langley
+  *  mark@sunquest.com
+  */
+ static char *sParseAction(s, name, strings, size)
+ char *s;
+ char *name;
+ char **strings;
+ int *size;
+ {int i, j, len, args, cparen, max;
+  char *tmp;
+ 
+  max = *size;
+  *size = 0;
+  for (i=0; s[i]; i++)
+    if (s[i] == OPAREN)
+      break;
+  if (s[i] != OPAREN)
+    return "Missing '('";
+ 
+  strncpy(name, s, i);
+  name[i] = '\0';
+  i++;
+  for (cparen=args=0; s[i] && !cparen; i++) {
+    for (j=i; s[i] && (s[i] != COMMA) && (s[i] != CPAREN); i++)
+ 	;
+    if (s[i] == CPAREN)
+      cparen = 1;
+    len = 1 + i - j;
+    if (len <= 1) 
+      break;
+    strncpy(tmp=XtMalloc(len), &s[j], len);
+    tmp[len-1] = '\0';
+    if (args < max)
+      strings[args++] = tmp;
+    }
+  if (!cparen) {
+    for (i=0; i<args;i++)
+      XtFree(strings[i]);
+    *size = 0;
+    return "Missing ')'";
+    }
+  strings[args] = 0;
+  *size = args;
+  return 0;
+ }
+ 
+ /*
+  * XtCallActionProc - invoke an ActionProc with an arglist
+  *  donated by
+  *    Mark Langley
+  *    mark@sunquest.com
+  */
+ XtCallActionProc(w, s)
+ Widget w;     
+ char *s;
+ {ActionList al;
+  CompiledActionTable t;
+  char *strings[32], *msg;
+  char name[256];
+  int i, size=32;
+  XtActionProc f=0;
+  register XrmQuark q;
+  register WidgetClass class=w->core.widget_class;
+ 
+  msg = sParseAction(s, name, strings, &size);
+  if (msg) {
+    XtWarning(msg);
+    return;
+    }
+  q = XrmStringToQuark(name);
+  /*
+   * First search the widget's superclass chain
+   */
+  for (;class != NULL && !f; class=class->core_class.superclass)
+    if (class->core_class.actions != NULL) {
+      t=(CompiledActionTable) class->core_class.actions;
+      for (i=0; t[i].name; i++) 
+        if (t[i].signature == q) {
+ 	 f = (XtActionProc) t[i].value;
+ 	 break;
+          }
+      }
+ 
+  /*
+   * search the global action procs
+   */
+  for (al=globalActionList; al && !f; al = al->next)
+    for (t=al->table; t->name; t++) 
+        if (t->signature == q) {
+ 	 f = (XtActionProc) t->value;
+ 	 break;
+          }
+  
+  if (f) {
+    XEvent event;
+    event.type=0;	/* What else? */
+    (*f)(w, &event, strings, &size);
+    }
+  else {
+    char message[256];
+    sprintf(message, "Action not found: %s ", name);
+    XtWarning(message);
+    }
+  /*
+   * free up strings allocated by sParse
+   */
+  for (i=0; i<size; i++)
+    XtFree(strings[i]);
+ }
+ 
  static void ReportUnboundActions(tm, stateTable)
      TMRec* tm;
      XtTranslations stateTable;
  {
      Cardinal num_unbound;
      char     message[10000];
      register Cardinal num_chars;
      register Cardinal i;
  
      num_unbound = 0;