[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

gEDA-user: [PCB] action context patch



Hi all,

lately I started to work again on my gpmi plugin for PCB. This plugin
would be able to load and run scripts written in different languages 
and expose PCB internals to the script. In other words, the user could use
lua, python, perl, etc., to write a PCB plugin, being able to display
dialog boxes on the current HID and manipulate the drawing.

As part of this effort, I probably need to extend different parts of the
current PCB code. For example, when the user script wants to register
actions, it's not (easily) possible to pass on unique callback function
for each action that directly calls a script function; instead the plugin
needs to install a "hub" action callback function that catches any and all
script-registered action delivers them in a way that scripts can find out
which action triggered the callback.

This is not possible with the current codebase as action callbacks do not
get any argument that tells the action name. After consulting dj on IRC, I
made up the attached patch. It adds a new hidden layer in the
hid/common/actions.c, called HID_ActionContext; this layer is used to
store every action with a context coming from the action register
function. A new function is provided where the user can set a context to
the list of actions being registered, while keeping the original
hid_register_actions() call for backward compatibility (it sets context
to NULL). When an action callback is triggered by hid_actionv(), a global
variable called hid_action_context will be set to the context given during
the registration. A side effect of the changes is that a mostly internal
function, hid_find_action() has a new optional argument in which it can
return the context for the action found.

I tested the patch with the gtk hid and it worked as expected. I made the
necessary modification in the lesstif hid so that it should also compile
but will not set hid_action_context. The reason is that lesstif seems to
implement it's own action dispatcher instead of calling hid_actionv(). Of
course it's not very hard to add the required context-handling code there
as well, but I suspect not using the common code is simply a bug that
should be fixed.

Please test my patch on lesstif and if it doesn't break anything, please
commit the patch.

TIA,

Tibor Palinkas

-- 
.O.
..O
OOO
diff -ur pcb.orig/src/hid/common/actions.c pcb/src/hid/common/actions.c
--- pcb.orig/src/hid/common/actions.c	2008-01-05 06:37:08.000000000 +0100
+++ pcb/src/hid/common/actions.c	2009-03-19 19:46:30.000000000 +0100
@@ -26,14 +26,25 @@
   struct HID_ActionNode *next;
   HID_Action *actions;
   int n;
+  /* The registrar the callback function may use this pointer to remember
+     context; the action infrastructure will just pass it along.  */
+  void *context;
 } HID_ActionNode;
 
-HID_ActionNode *hid_action_nodes = 0;
+/* The master list of all actions registered */ 
+typedef struct HID_ActionContext {
+	HID_Action action;
+	void *context;
+} HID_ActionContext;
 static int n_actions = 0;
-static HID_Action *all_actions = 0;
+static HID_ActionContext *all_actions = 0;
+
+HID_ActionNode *hid_action_nodes = 0;
+
+void *hid_action_context = NULL;
 
 void
-hid_register_actions (HID_Action * a, int n)
+hid_register_actions_context (HID_Action * a, int n, void *context)
 {
   HID_ActionNode *ha;
 
@@ -43,6 +54,7 @@
   hid_action_nodes = ha;
   ha->actions = a;
   ha->n = n;
+  ha->context = context;
   n_actions += n;
   if (all_actions)
     {
@@ -51,16 +63,22 @@
     }
 }
 
+void
+hid_register_actions (HID_Action * a, int n)
+{
+	hid_register_actions_context (a, n, NULL);
+}
+
 static int
 action_sort (const void *va, const void *vb)
 {
-  HID_Action *a = (HID_Action *) va;
-  HID_Action *b = (HID_Action *) vb;
-  return strcmp (a->name, b->name);
+  HID_ActionContext *a = (HID_ActionContext *) va;
+  HID_ActionContext *b = (HID_ActionContext *) vb;
+  return strcmp (a->action.name, b->action.name);
 }
 
 HID_Action *
-hid_find_action (const char *name)
+hid_find_action (const char *name, void **context)
 {
   HID_ActionNode *ha;
   int i, n, lower, upper;
@@ -71,11 +89,14 @@
   if (all_actions == 0)
     {
       n = 0;
-      all_actions = malloc (n_actions * sizeof (HID_Action));
+      all_actions = malloc (n_actions * sizeof (HID_ActionContext));
       for (ha = hid_action_nodes; ha; ha = ha->next)
-	for (i = 0; i < ha->n; i++)
-	  all_actions[n++] = ha->actions[i];
-      qsort (all_actions, n_actions, sizeof (HID_Action), action_sort);
+	for (i = 0; i < ha->n; i++) {
+	  all_actions[n].action = ha->actions[i];
+	  all_actions[n].context = ha->context;
+		n++;
+	}
+      qsort (all_actions, n_actions, sizeof (HID_ActionContext), action_sort);
     }
 
 
@@ -85,10 +106,13 @@
   while (lower < upper - 1)
     {
       i = (lower + upper) / 2;
-      n = strcmp (all_actions[i].name, name);
+      n = strcmp (all_actions[i].action.name, name);
       /*printf("try [%d].%s, cmp %d\n", i, all_actions[i].name, n); */
-      if (n == 0)
-	return all_actions + i;
+      if (n == 0) {
+		if (*context != NULL)
+			*context = all_actions[i].context;
+		return &(all_actions[i].action);
+	}
       if (n > 0)
 	upper = i;
       else
@@ -96,8 +120,11 @@
     }
 
   for (i = 0; i < n_actions; i++)
-    if (strcasecmp (all_actions[i].name, name) == 0)
-      return all_actions + i;
+    if (strcasecmp (all_actions[i].action.name, name) == 0) {
+      if (*context != NULL)
+        *context = all_actions[i].context;
+      return &(all_actions[i].action);
+    }
 
   printf ("unknown action `%s'\n", name);
   return 0;
@@ -108,19 +135,19 @@
 {
   int i;
   /* Forces them to be sorted in all_actions */
-  hid_find_action (hid_action_nodes->actions[0].name);
+  hid_find_action (hid_action_nodes->actions[0].name, NULL);
   fprintf (stderr, "Registered Actions:\n");
   for (i = 0; i < n_actions; i++)
     {
-      if (all_actions[i].description)
-	fprintf (stderr, "  %s - %s\n", all_actions[i].name,
-		 all_actions[i].description);
+      if (all_actions[i].action.description)
+	fprintf (stderr, "  %s - %s\n", all_actions[i].action.name,
+		 all_actions[i].action.description);
       else
-	fprintf (stderr, "  %s\n", all_actions[i].name);
-      if (all_actions[i].syntax)
+	fprintf (stderr, "  %s\n", all_actions[i].action.name);
+      if (all_actions[i].action.syntax)
 	{
 	  const char *bb, *eb;
-	  bb = eb = all_actions[i].syntax;
+	  bb = eb = all_actions[i].action.syntax;
 	  while (1)
 	    {
 	      for (eb = bb; *eb && *eb != '\n'; eb++)
@@ -161,16 +188,16 @@
 {
   int i;
   /* Forces them to be sorted in all_actions */
-  hid_find_action (hid_action_nodes->actions[0].name);
+  hid_find_action (hid_action_nodes->actions[0].name, NULL);
   for (i = 0; i < n_actions; i++)
     {
-      const char *desc = all_actions[i].description;
-      const char *synt = all_actions[i].syntax;
+      const char *desc = all_actions[i].action.description;
+      const char *synt = all_actions[i].action.syntax;
 
       desc = desc ? desc : "";
       synt = synt ? synt : "";
 
-      printf ("A%s\n", all_actions[i].name);
+      printf ("A%s\n", all_actions[i].action.name);
       dump_string ('D', desc);
       dump_string ('S', synt);
     }
@@ -200,8 +227,10 @@
 int
 hid_actionv (const char *name, int argc, char **argv)
 {
-  int x = 0, y = 0, i;
+  int x = 0, y = 0, i, ret;
   HID_Action *a;
+	void *old_context;
+	void *context;
 
   if (Settings.verbose && name)
     {
@@ -211,12 +240,21 @@
       printf (")\033[0m\n");
     }
 
-  a = hid_find_action (name);
+  a = hid_find_action (name, &context);
   if (!a)
     return 1;
   if (a->need_coord_msg)
     gui->get_coords (a->need_coord_msg, &x, &y);
-  return a->trigger_cb (argc, argv, x, y);
+
+  /* save old action context and set it to the context associated with the action */
+  old_context = hid_action_context;
+  hid_action_context = context;
+
+  ret = a->trigger_cb (argc, argv, x, y);
+
+  /* restore old context and return */
+	hid_action_context = old_context;
+	return ret;
 }
 
 int
diff -ur pcb.orig/src/hid/hidint.h pcb/src/hid/hidint.h
--- pcb.orig/src/hid/hidint.h	2006-09-20 06:26:32.000000000 +0200
+++ pcb/src/hid/hidint.h	2009-03-19 09:02:17.000000000 +0100
@@ -35,7 +35,7 @@
 
 extern HID_AttrNode *hid_attr_nodes;
 
-HID_Action *hid_find_action (const char *name);
+HID_Action *hid_find_action (const char *name, void **context);
 
 HID_Flag *hid_find_flag (const char *name);
 
diff -ur pcb.orig/src/hid/lesstif/menu.c pcb/src/hid/lesstif/menu.c
--- pcb.orig/src/hid/lesstif/menu.c	2008-12-21 05:15:39.000000000 +0100
+++ pcb/src/hid/lesstif/menu.c	2009-03-19 18:47:38.000000000 +0100
@@ -818,7 +818,7 @@
 
   if (!aname)
     return 1;
-  a = hid_find_action (aname);
+  a = hid_find_action (aname, NULL);
   if (!a)
     {
       int i;
diff -ur pcb.orig/src/hid.h pcb/src/hid.h
--- pcb.orig/src/hid.h	2009-02-21 18:51:54.000000000 +0100
+++ pcb/src/hid.h	2009-03-19 09:01:41.000000000 +0100
@@ -86,7 +86,17 @@
     const char *syntax;
   } HID_Action;
 
+  /* This global variable is always set to the action context, 
+	   before an action callback is called. Action context can
+		 be specified when registering an action with hid_register_actions_context() */
+  extern void *hid_action_context;
+
+  /* Register a list of actions associated with an action context */
+	extern void hid_register_actions_context (HID_Action *, int, void *);
+
+  /* Register a list of actions without action context */
   extern void hid_register_actions (HID_Action *, int);
+
 #define REGISTER_ACTIONS(a) HIDCONCAT(void register_,a) ()\
 { hid_register_actions(a, sizeof(a)/sizeof(a[0])); }
 

_______________________________________________
geda-user mailing list
geda-user@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-user