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

Re: gEDA-user: command autocomplete (gtk)



This one should be a complete autocomplete implementation,
including history callback. I would like some feedback
before commiting anything.


diff --git a/src/hid/common/actions.c b/src/hid/common/actions.c
index 43c50f8..f511cc4 100644
--- a/src/hid/common/actions.c
+++ b/src/hid/common/actions.c
@@ -37,6 +37,19 @@ check_action_name (const char *s)
   return NULL;
 }
 
+/* Accessors needed by autocomplete list */
+int
+get_n_actions (void)
+{
+  return n_actions;
+}
+
+HID_Action **
+get_all_actions (void)
+{
+  return all_actions;
+}
+
 void
 hid_register_actions (HID_Action * a, int n)
 {
diff --git a/src/hid/common/actions.h b/src/hid/common/actions.h
index 1cc6f24..a90d923 100644
--- a/src/hid/common/actions.h
+++ b/src/hid/common/actions.h
@@ -3,5 +3,7 @@
 #define __HID_ACTIONS_INCLUDED__
 
 void print_actions (void);
+HID_Action **get_all_actions (void);
+int get_n_actions (void);
 
 #endif
diff --git a/src/hid/gtk/gui-command-window.c b/src/hid/gtk/gui-command-window.c
index b08836e..f95febf 100644
--- a/src/hid/gtk/gui-command-window.c
+++ b/src/hid/gtk/gui-command-window.c
@@ -35,6 +35,7 @@
 #include "gui.h"
 #include <gdk/gdkkeysyms.h>
 
+#include "hid/common/actions.h"
 #include "command.h"
 #include "crosshair.h"
 
@@ -46,10 +47,20 @@ RCSID ("$Id$");
 
 static GtkWidget *command_window;
 static GtkWidget *combo_vbox;
-static GList *history_list;
 static gchar *command_entered;
 static GMainLoop *loop;
 
+#define AUTO_MAX_HEIGHT	250
+static GtkListStore *auto_complete_list;
+static GtkTreeModel *auto_complete;
+static gint auto_row_height;
+static bool is_auto_complete_change;
+static bool is_history_change;
+static const char *auto_complete_prefix;
+
+static GList *history;
+static GList *history_cursor;
+
 
 /* gui-command-window.c provides two interfaces for getting user input
 |  for executing a command.
@@ -135,60 +146,65 @@ static gchar *command_ref_text[] = {
   N_("\tLoad a vendor file.  If 'filename' omitted, pop up file select dialog.\n"),
 };
 
-
-  /* Put an allocated string on the history list and combo text list
-     |  if it is not a duplicate.  The history_list is just a shadow of the
-     |  combo list, but I think is needed because I don't see an api for reading
-     |  the combo strings.  The combo box strings take "const gchar *", so the
-     |  same allocated string can go in both the history list and the combo list.
-     |  If removed from both lists, a string can be freed.
-   */
-static void
-command_history_add (gchar * cmd)
+static gboolean
+autocomplete_visible_func (GtkTreeModel *model, GtkTreeIter  *iter, gpointer data)
 {
-  GList *list;
-  gchar *s;
-  gint i;
-
-  if (!cmd || !*cmd)
-    return;
+  /* Visible if row is non-empty and first column is "HI" */
+  gchar *str;
+  gboolean visible = FALSE;
 
-  /* Check for a duplicate command.  If found, move it to the
-     |  top of the list and similarly modify the combo box strings.
-   */
-  for (i = 0, list = history_list; list; list = list->next, ++i)
-    {
-      s = (gchar *) list->data;
-      if (!strcmp (cmd, s))
-	{
-	  history_list = g_list_remove (history_list, s);
-	  history_list = g_list_prepend (history_list, s);
-	  gtk_combo_box_remove_text (GTK_COMBO_BOX
-				     (ghidgui->command_combo_box), i);
-	  gtk_combo_box_prepend_text (GTK_COMBO_BOX
-				      (ghidgui->command_combo_box), s);
-	  return;
-	}
-    }
+  gtk_tree_model_get (model, iter, 0, &str, -1);
+  if (str && auto_complete_prefix &&
+      strncasecmp (str, auto_complete_prefix, strlen (auto_complete_prefix)) == 0)
+    visible = TRUE;
+  g_free (str);
 
-  /* Not a duplicate, so put first in history list and combo box text list.
-   */
-  s = g_strdup (cmd);
-  history_list = g_list_prepend (history_list, s);
-  gtk_combo_box_prepend_text (GTK_COMBO_BOX (ghidgui->command_combo_box), s);
+  return visible;
+}
 
-  /* And keep the lists trimmed!
-   */
-  if (g_list_length (history_list) > ghidgui->history_size)
+static GtkTreeModel *
+create_autocomplete_model (void)
+{
+  int i;
+  int n = get_n_actions ();
+  HID_Action **actions = get_all_actions ();
+  GtkTreeIter iter;
+
+  auto_complete_prefix = NULL;
+  auto_complete_list = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+  auto_complete = gtk_tree_model_filter_new (GTK_TREE_MODEL (auto_complete_list), NULL);
+  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (auto_complete),
+                                          autocomplete_visible_func, NULL, NULL);
+  /* First entry will be filled with textentry contents */
+  gtk_list_store_append (auto_complete_list, &iter);
+  gtk_list_store_set (auto_complete_list, &iter, 0, "", 1, "", -1);
+  for (i = 0; i < n; ++i)
     {
-      s = (gchar *) g_list_nth_data (history_list, ghidgui->history_size);
-      history_list = g_list_remove (history_list, s);
-      gtk_combo_box_remove_text (GTK_COMBO_BOX (ghidgui->command_combo_box),
-				 ghidgui->history_size);
-      g_free (s);
+      gtk_list_store_append (auto_complete_list, &iter);
+      gtk_list_store_set (auto_complete_list, &iter,
+                          0, actions[i]->name, 
+                          1, actions[i]->description,
+                          -1);
     }
+
+  return GTK_TREE_MODEL (auto_complete);
 }
 
+/* Populates the autocomplete model with all actions 
+ * that start with prefix; returns the number of actions
+ * added. */
+static int
+populate_autocomplete_model (const char *prefix)
+{
+  GtkTreeIter first;
+  auto_complete_prefix = prefix;
+
+  gtk_tree_model_get_iter_first (GTK_TREE_MODEL (auto_complete_list), &first);
+  gtk_list_store_set (auto_complete_list, &first, 0, prefix, 1, "", -1);
+
+  gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (auto_complete));
+  return 1;
+}
 
   /* Called when user hits "Enter" key in command entry.  The action to take
      |  depends on where the combo box is.  If it's in the command window, we can
@@ -202,12 +218,11 @@ command_entry_activate_cb (GtkWidget * widget, gpointer data)
 {
   gchar *command;
 
-  command =
-    g_strdup (ghid_entry_get_text (GTK_WIDGET (ghidgui->command_entry)));
-  gtk_entry_set_text (ghidgui->command_entry, "");
-
+  command = g_strdup (ghid_entry_get_text (ghidgui->command_entry));
+  gtk_entry_set_text (GTK_ENTRY (ghidgui->command_entry), "");
   if (*command)
-    command_history_add (command);
+    history = g_list_prepend (history, g_strdup (command));
+  history_cursor = history;
 
   if (ghidgui->use_command_window)
     {
@@ -222,29 +237,209 @@ command_entry_activate_cb (GtkWidget * widget, gpointer data)
     }
 }
 
-  /* Create the command_combo_box.  Called once, either by
+static gboolean
+command_changed_cb (GtkEntry *entry, GtkTreeSelection *select)
+{
+  gchar *text;
+  gint x, y, height;
+  GtkAllocation allocation;
+
+  text = ghid_entry_get_text (GTK_WIDGET (entry));
+
+  /* Copy width, origin from text entry */
+  gtk_widget_get_allocation (ghidgui->command_entry, &allocation);
+  gdk_window_get_origin (gtk_widget_get_window (ghidgui->command_entry), &x, &y);
+
+  if (is_auto_complete_change)
+    {
+      gtk_editable_set_position (GTK_EDITABLE (ghidgui->command_entry), -1);
+      return FALSE;
+    }
+  else if (is_history_change)
+    {
+      gtk_editable_set_position (GTK_EDITABLE (ghidgui->command_entry), -1);
+      return FALSE;
+    }
+
+  if (text)
+    {
+      int n;
+      if (*text)
+        populate_autocomplete_model (text);
+      else
+        populate_autocomplete_model (NULL);
+      n = gtk_tree_model_iter_n_children (auto_complete, NULL);
+      if (*text && n > 1)
+        {
+          GtkTreePath *first = gtk_tree_path_new_first ();
+          height = MIN (AUTO_MAX_HEIGHT, n * auto_row_height);
+          /* Position and show autocomplete */
+          gtk_widget_set_size_request (ghidgui->command_hist_window, allocation.width, height);
+          gtk_window_resize (GTK_WINDOW (ghidgui->command_hist_window), allocation.width, height);
+          gtk_window_move (GTK_WINDOW (ghidgui->command_hist_window), x, y - height);
+          gtk_widget_show_all (ghidgui->command_hist_window);
+          /* Select first entry so that up/down can work cleanly. */
+          gtk_tree_view_set_cursor (GTK_TREE_VIEW (ghidgui->command_hist_tree_view),
+                                    first, NULL, FALSE);
+        }
+      else
+        gtk_widget_hide (ghidgui->command_hist_window);
+    }
+  else
+    gtk_widget_hide (ghidgui->command_hist_window);
+
+  return FALSE;
+}
+
+static void
+tree_selection_changed_cb (GtkTreeSelection *selection, gpointer data)
+{
+  GtkTreeIter iter;
+  GtkTreeModel *model;
+  gchar *text;
+
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+    {
+      is_auto_complete_change = true;
+      gtk_tree_model_get (model, &iter, 0, &text, -1);
+      gtk_entry_set_text (GTK_ENTRY (ghidgui->command_entry), text);
+      is_auto_complete_change = false;
+      g_free (text);
+    }
+}
+
+static gboolean
+command_keyboard_cb (GtkWidget * widget, GdkEventKey * kev, gpointer data)
+{
+  GtkTreePath *path;
+  gint ksym = kev->keyval;
+  gchar *text = ghid_entry_get_text (GTK_WIDGET (ghidgui->command_entry));
+
+  if (ksym == GDK_Tab)
+    ksym = (kev->state & GDK_SHIFT_MASK) ? GDK_Up : GDK_Down;
+  if (ksym == GDK_ISO_Left_Tab)
+    ksym = GDK_Up;
+
+  /* Up and down scroll the autocomplete list, unless this list
+   * is empty. In this case they scroll the history. */
+  switch (ksym)
+    {
+    case GDK_Up:
+      if (*text == '\0' || history_cursor != history)
+        {
+          if (history_cursor)
+            {
+              is_history_change = true;
+              gtk_entry_set_text (GTK_ENTRY (ghidgui->command_entry), history_cursor->data);
+              if (history_cursor->next)
+                history_cursor = history_cursor->next;
+              is_history_change = false;
+            }
+        }
+      else if (auto_complete_prefix)
+        {
+          gtk_tree_view_get_cursor (GTK_TREE_VIEW (ghidgui->command_hist_tree_view),
+                                &path, NULL);
+          gtk_tree_path_prev (path);
+          if (gtk_tree_row_reference_new (GTK_TREE_MODEL (auto_complete), path) != NULL)
+           gtk_tree_view_set_cursor (GTK_TREE_VIEW (ghidgui->command_hist_tree_view),
+                                      path, NULL, FALSE);
+        }
+      return TRUE;
+    case GDK_Down:
+      if (history_cursor != history)
+        {
+          if (history_cursor)
+            {
+              is_history_change = true;
+              if (history_cursor->prev)
+                {
+                  history_cursor = history_cursor->prev;
+                  gtk_entry_set_text (GTK_ENTRY (ghidgui->command_entry), history_cursor->data);
+                }
+              is_history_change = false;
+            }
+        }
+      else if (auto_complete_prefix)
+        {
+          gtk_tree_view_get_cursor (GTK_TREE_VIEW (ghidgui->command_hist_tree_view),
+                                    &path, NULL);
+          gtk_tree_path_next (path);
+          if (gtk_tree_row_reference_new (GTK_TREE_MODEL (auto_complete), path) != NULL)
+            gtk_tree_view_set_cursor (GTK_TREE_VIEW (ghidgui->command_hist_tree_view),
+                                      path, NULL, FALSE);
+        }
+      else
+        gtk_entry_set_text (GTK_ENTRY (ghidgui->command_entry), "");
+      return TRUE;
+    case GDK_Escape:
+      if (loop && g_main_loop_is_running (loop))	/* should always be */
+        g_main_loop_quit (loop);
+      history_cursor = history;
+      command_entered = NULL;	/* We are aborting */
+      return TRUE;
+    default:
+      return FALSE;
+    }
+}
+
+  /* Create the command_entry.  Called once, either by
      |  ghid_command_window_show() or ghid_command_entry_get().  Then as long as
-     |  ghidgui->use_command_window is TRUE, the command_combo_box will live
+     |  ghidgui->use_command_window is TRUE, the command_enty will live
      |  in a command window vbox or float if the command window is not up.
-     |  But if ghidgui->use_command_window is FALSE, the command_combo_box
+     |  But if ghidgui->use_command_window is FALSE, the command_entry
      |  will live in the status_line_hbox either shown or hidden. 
-     |  Since it's never destroyed, the combo history strings never need
-     |  rebuilding and history is maintained if the combo box location is moved.
    */
 static void
-command_combo_box_entry_create (void)
+command_text_entry_create (void)
 {
-  ghidgui->command_combo_box = gtk_combo_box_entry_new_text ();
-  ghidgui->command_entry =
-    GTK_ENTRY (GTK_BIN (ghidgui->command_combo_box)->child);
-
-  gtk_entry_set_width_chars (ghidgui->command_entry, 40);
-  gtk_entry_set_activates_default (ghidgui->command_entry, TRUE);
+  GtkWidget *scroll;
+  GtkAdjustment *hadj, *vadj;
+  GtkTreeSelection *select;
+  GtkCellRenderer *renderer1 = gtk_cell_renderer_text_new ();
+  GtkCellRenderer *renderer2 = gtk_cell_renderer_text_new ();
+
+  /* Build textbox and autocomplete popup */
+  ghidgui->command_entry = gtk_entry_new ();
+  ghidgui->command_hist_window = gtk_window_new (GTK_WINDOW_POPUP);
+  ghidgui->command_hist_tree_view = gtk_tree_view_new ();
+
+  hadj = gtk_tree_view_get_hadjustment (GTK_TREE_VIEW (ghidgui->command_hist_tree_view));
+  vadj = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (ghidgui->command_hist_tree_view));
+  scroll = gtk_scrolled_window_new (hadj, vadj);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+
+  gtk_container_add (GTK_CONTAINER (ghidgui->command_hist_window), scroll);
+  gtk_container_add (GTK_CONTAINER (scroll), ghidgui->command_hist_tree_view);
+
+  /* Configure treeview for minimalist look */
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_OUT);
+  gtk_cell_renderer_set_padding (renderer2, 15, 0);
+  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ghidgui->command_hist_tree_view),
+                                     FALSE);
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (ghidgui->command_hist_tree_view),
+                                               -1, "", renderer1, "text", 0, NULL);
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (ghidgui->command_hist_tree_view),
+                                               -1, "", renderer2, "text", 1, NULL);
+  gtk_cell_renderer_get_size (renderer1, ghidgui->command_hist_tree_view,
+                              NULL, NULL, NULL, NULL, &auto_row_height);
+
+  gtk_entry_set_activates_default (GTK_ENTRY (ghidgui->command_entry), TRUE);
+
+  /* Hookup autocomplete model */
+  gtk_tree_view_set_model (GTK_TREE_VIEW (ghidgui->command_hist_tree_view),
+                           create_autocomplete_model());
+  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (ghidgui->command_hist_tree_view));
+  gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
 
   g_signal_connect (G_OBJECT (ghidgui->command_entry), "activate",
 		    G_CALLBACK (command_entry_activate_cb), NULL);
+  g_signal_connect (G_OBJECT (ghidgui->command_entry), "changed",
+		    G_CALLBACK (command_changed_cb), select);
+  g_signal_connect (G_OBJECT (select), "changed",
+                    G_CALLBACK (tree_selection_changed_cb), NULL);
 
-  g_object_ref (G_OBJECT (ghidgui->command_combo_box));	/* so can move it */
+  g_object_ref (G_OBJECT (ghidgui->command_entry));	/* so can move it */
 }
 
 static void
@@ -253,7 +448,7 @@ command_window_close_cb (void)
   if (command_window)
     {
       gtk_container_remove (GTK_CONTAINER (combo_vbox),	/* Float it */
-			    ghidgui->command_combo_box);
+			    ghidgui->command_entry);
       gtk_widget_destroy (command_window);
     }
   combo_vbox = NULL;
@@ -267,7 +462,7 @@ command_destroy_cb (GtkWidget * widget, gpointer data)
 }
 
   /* If ghidgui->use_command_window toggles, the config code calls
-     |  this to ensure the command_combo_box is set up for living in the
+     |  this to ensure the command_entry is set up for living in the
      |  right place.
    */
 void
@@ -276,22 +471,22 @@ ghid_command_use_command_window_sync (void)
   /* The combo box will be NULL and not living anywhere until the
      |  first command entry.
    */
-  if (!ghidgui->command_combo_box)
+  if (!ghidgui->command_entry)
     return;
 
   if (ghidgui->use_command_window)
     gtk_container_remove (GTK_CONTAINER (ghidgui->status_line_hbox),
-			  ghidgui->command_combo_box);
+			  ghidgui->command_entry);
   else
     {
-      /* Destroy the window (if it's up) which floats the command_combo_box
+      /* Destroy the window (if it's up) which floats the command_entry
          |  so we can pack it back into the status line hbox.  If the window
-         |  wasn't up, the command_combo_box was already floating.
+         |  wasn't up, the command_entry was already floating.
        */
       command_window_close_cb ();
-      gtk_widget_hide (ghidgui->command_combo_box);
+      gtk_widget_hide (ghidgui->command_entry);
       gtk_box_pack_start (GTK_BOX (ghidgui->status_line_hbox),
-			  ghidgui->command_combo_box, FALSE, FALSE, 0);
+			  ghidgui->command_entry, FALSE, FALSE, 5);
     }
 }
 
@@ -321,10 +516,10 @@ ghid_command_window_show (gboolean raise)
   gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
   gtk_container_add (GTK_CONTAINER (command_window), vbox);
 
-  if (!ghidgui->command_combo_box)
-    command_combo_box_entry_create ();
+  if (!ghidgui->command_entry)
+    command_text_entry_create ();
 
-  gtk_box_pack_start (GTK_BOX (vbox), ghidgui->command_combo_box,
+  gtk_box_pack_start (GTK_BOX (vbox), ghidgui->command_entry,
 		      FALSE, FALSE, 0);
   combo_vbox = vbox;
 
@@ -355,42 +550,26 @@ ghid_command_window_show (gboolean raise)
   gtk_widget_show_all (command_window);
 }
 
-
-static gboolean
-command_escape_cb (GtkWidget * widget, GdkEventKey * kev, gpointer data)
-{
-  gint ksym = kev->keyval;
-
-  if (ksym != GDK_Escape)
-    return FALSE;
-
-  if (loop && g_main_loop_is_running (loop))	/* should always be */
-    g_main_loop_quit (loop);
-  command_entered = NULL;	/* We are aborting */
-
-  return TRUE;
-}
-
-
   /* This is the command entry function called from ActionCommand() when
-     |  ghidgui->use_command_window is FALSE.  The command_combo_box is already
+     |  ghidgui->use_command_window is FALSE.  The command_text_entry is already
      |  packed into the status line label hbox in this case.
    */
 gchar *
 ghid_command_entry_get (gchar * prompt, gchar * command)
 {
   gchar *s;
-  gint escape_sig_id;
+  gint keyboard_sig_id;
   GHidPort *out = &ghid_port;
 
   /* If this is the first user command entry, we have to create the
      |  command_combo_box and pack it into the status_line_hbox.
    */
-  if (!ghidgui->command_combo_box)
+  if (!ghidgui->command_entry)
     {
-      command_combo_box_entry_create ();
+      command_text_entry_create ();
       gtk_box_pack_start (GTK_BOX (ghidgui->status_line_hbox),
-			  ghidgui->command_combo_box, FALSE, FALSE, 0);
+			  GTK_WIDGET (ghidgui->command_entry),
+                          TRUE, TRUE, 0);
     }
 
   /* Make the prompt bold and set the label before showing the combo to
@@ -402,12 +581,12 @@ ghid_command_entry_get (gchar * prompt, gchar * command)
 
   /* Flag so output drawing area won't try to get focus away from us and
      |  so resetting the status line label can be blocked when resize
-     |  callbacks are invokded from the resize caused by showing the combo box.
+     |  callbacks are invoked (from the resize caused by showing the entry!).
    */
   ghidgui->command_entry_status_line_active = TRUE;
 
-  gtk_entry_set_text (ghidgui->command_entry, command ? command : "");
-  gtk_widget_show_all (ghidgui->command_combo_box);
+  gtk_entry_set_text (GTK_ENTRY (ghidgui->command_entry), command ? command : "");
+  gtk_widget_show (ghidgui->command_entry);
 
   /* Remove the top window accel group so keys intended for the entry
      |  don't get intercepted by the menu system.  Set the interface
@@ -420,9 +599,9 @@ ghid_command_entry_get (gchar * prompt, gchar * command)
   ghid_interface_input_signals_disconnect ();
   ghid_interface_set_sensitive (FALSE);
   gtk_widget_grab_focus (GTK_WIDGET (ghidgui->command_entry));
-  escape_sig_id = g_signal_connect (G_OBJECT (ghidgui->command_entry),
+  keyboard_sig_id = g_signal_connect (G_OBJECT (ghidgui->command_entry),
 				    "key_press_event",
-				    G_CALLBACK (command_escape_cb), NULL);
+				    G_CALLBACK (command_keyboard_cb), NULL);
 
   loop = g_main_loop_new (NULL, FALSE);
   g_main_loop_run (loop);
@@ -434,7 +613,7 @@ ghid_command_entry_get (gchar * prompt, gchar * command)
 
   /* Restore the damage we did before entering the loop.
    */
-  g_signal_handler_disconnect (ghidgui->command_entry, escape_sig_id);
+  g_signal_handler_disconnect (ghidgui->command_entry, keyboard_sig_id);
   ghid_interface_input_signals_connect ();
   ghid_interface_set_sensitive (TRUE);
   gtk_window_add_accel_group (GTK_WINDOW (out->top_window),
@@ -443,7 +622,8 @@ ghid_command_entry_get (gchar * prompt, gchar * command)
 
   /* Restore the status line label and give focus back to the drawing area
    */
-  gtk_widget_hide (ghidgui->command_combo_box);
+  gtk_widget_hide (ghidgui->command_hist_window);
+  gtk_widget_hide (ghidgui->command_entry);
   gtk_widget_grab_focus (out->drawing_area);
 
   return command_entered;
@@ -460,7 +640,7 @@ ghid_handle_user_command (gboolean raise)
     ghid_command_window_show (raise);
   else
     {
-      command = ghid_command_entry_get (_("Enter command:"),
+      command = ghid_command_entry_get (_("Command:"),
 					(Settings.SaveLastCommand && previous) ? previous : (gchar *)"");
       if (command != NULL)
 	{
diff --git a/src/hid/gtk/gui.h b/src/hid/gtk/gui.h
index 31ee636..2e1bc40 100644
--- a/src/hid/gtk/gui.h
+++ b/src/hid/gtk/gui.h
@@ -106,7 +106,7 @@ typedef struct
     *cursor_position_relative_label,
     *cursor_position_absolute_label,
     *grid_units_label, *status_line_hbox, *command_combo_box;
-  GtkEntry *command_entry;
+  GtkWidget *command_entry, *command_hist_window, *command_hist_tree_view;
 
   GtkWidget *top_hbox,
     *menu_hbox, *compact_vbox, *compact_hbox, *position_hbox, *label_hbox,



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