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

gEDA-cvs: branch: master updated (1.0-20070526-89-gca4571b)



The branch, master has been updated
       via  ca4571b1a6a49c97feb8fc6cc8cb926acc287ece (commit)
       via  96f9c87ef4063b52dd4d13f51958b916ba4e5939 (commit)
       via  b1733d4d69d3a2e6fcb64e91a26dab2768f4e171 (commit)
       via  cb6e4e5e98ed45427f60d718f7dbb5d5439eecef (commit)
       via  7c6419f49cb211ce74e7a8787148d2fd624482e7 (commit)
       via  ab0fef1d36d05088f3891397103ebb15b3e3c2d0 (commit)
      from  62b214780e34aea9b56993f2b699cb78d50d4769 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


=========
 Summary
=========

 gschem/include/x_compselect.h |    9 +-
 gschem/src/a_zoom.c           |   17 ++
 gschem/src/x_compselect.c     |  597 ++++++++++++++++++++++++++++-------------
 libgeda/include/prototype.h   |    7 +-
 libgeda/src/g_rc.c            |   36 ++-
 libgeda/src/g_register.c      |    2 +-
 libgeda/src/s_clib.c          |  190 ++++++-------
 7 files changed, 548 insertions(+), 310 deletions(-)


=================
 Commit Messages
=================

commit ca4571b1a6a49c97feb8fc6cc8cb926acc287ece
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Date:   Wed Jul 4 18:03:53 2007 +0100

    libgeda: s_clib_toplevel_get_symbol_names() is poorly named.
    
    s_clib_toplevel_get_symbol_names() returns symbols, not names of
    symbols, so rename it to s_clib_toplevel_get_symbols().

:100644 100644 b2f0682... 296c6ca... M	gschem/src/x_compselect.c
:100644 100644 6c10844... 4225762... M	libgeda/include/prototype.h
:100644 100644 347c4c2... 14b486e... M	libgeda/src/s_clib.c

commit 96f9c87ef4063b52dd4d13f51958b916ba4e5939
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Date:   Wed Jul 4 18:03:53 2007 +0100

    gschem: Add "In Use" view to component selector.
    
    The "In Use" view shows symbols which are instantiated in open
    schematics, for ease of adding more symbols similar to the ones
    already present.  This is particularly useful for frequently-used
    symbols such as resistors and capacitors.

:100644 100644 5a7245f... 8b40806... M	gschem/include/x_compselect.h
:100644 100644 9f6e5d5... b2f0682... M	gschem/src/x_compselect.c

commit b1733d4d69d3a2e6fcb64e91a26dab2768f4e171
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Date:   Wed Jul 4 18:03:53 2007 +0100

    gschem: Add a "Refresh" button to component selector.
    
    In order to update the symbol library, a "Refresh" button is needed
    (because we don't do it automatically any more).

:100644 100644 a66e30a... 5a7245f... M	gschem/include/x_compselect.h
:100644 100644 4c2ccf8... 9f6e5d5... M	gschem/src/x_compselect.c

commit cb6e4e5e98ed45427f60d718f7dbb5d5439eecef
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Date:   Wed Jul 4 18:03:53 2007 +0100

    gschem: Don't use generic response IDs for compselect actions.
    
    The component selector "OK" and "Apply" buttons aren't actually "OK"
    and "Apply" actions, so they shouldn't use those response IDs -- it's
    confusing.
    
    This patch adds special response IDs for these actions. This is a
    preparation for using "proper" Place and Hide icons & text.

:100644 100644 18d718f... a66e30a... M	gschem/include/x_compselect.h
:100644 100644 bbab75f... 4c2ccf8... M	gschem/src/x_compselect.c

commit 7c6419f49cb211ce74e7a8787148d2fd624482e7
Author: Alex Precosky <precosky@xxxxxxx>
Date:   Sun Jul 1 16:55:13 2007 -0700

    gschem: Fix a race condition with mouse wheel scroll events (1740327)
    
    If more than one mouse wheel scroll events are received into the event
    queue before the first one can be processed, then the program was
    zooming in to the wrong location.  This is because the mouse moved
    event handler, which is triggered by a call to warp the cursor in the
    scroll event handler, must run to update the mouse postion global
    variables that the scroll event handler needs.

:100644 100644 23edb4a... 8f431f3... M	gschem/src/a_zoom.c

commit ab0fef1d36d05088f3891397103ebb15b3e3c2d0
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Date:   Wed Jul 4 18:03:53 2007 +0100

    libgeda: Make command-backed component sources more flexible.
    
    Allow different commands to be specified for 'list' and 'get' with
    custom command-line arguments.

:100644 100644 57a64b9... 6c10844... M	libgeda/include/prototype.h
:100644 100644 6844aa8... d23cb9b... M	libgeda/src/g_rc.c
:100644 100644 00607b4... 9d9443f... M	libgeda/src/g_register.c
:100644 100644 712d390... 347c4c2... M	libgeda/src/s_clib.c

=========
 Changes
=========

commit ca4571b1a6a49c97feb8fc6cc8cb926acc287ece
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Date:   Wed Jul 4 18:03:53 2007 +0100

    libgeda: s_clib_toplevel_get_symbol_names() is poorly named.
    
    s_clib_toplevel_get_symbol_names() returns symbols, not names of
    symbols, so rename it to s_clib_toplevel_get_symbols().

diff --git a/gschem/src/x_compselect.c b/gschem/src/x_compselect.c
index b2f0682..296c6ca 100644
--- a/gschem/src/x_compselect.c
+++ b/gschem/src/x_compselect.c
@@ -560,7 +560,7 @@ compselect_callback_behavior_changed (GtkOptionMenu *optionmenu,
 /* \brief Create the tree model for the "In Use" view.
  * \par Function Description
  * Creates a straightforward list of symbols which are currently in
- * use, using s_toplevel_get_symbol_names().
+ * use, using s_toplevel_get_symbols().
  */
 static GtkTreeModel*
 create_inuse_tree_model (void)
@@ -571,7 +571,7 @@ create_inuse_tree_model (void)
 
   store = (GtkListStore *) gtk_list_store_new (1, G_TYPE_POINTER);
 
-  symhead = s_toplevel_get_symbol_names (global_window_current);
+  symhead = s_toplevel_get_symbols (global_window_current);
 
   for (symlist = symhead;
        symlist != NULL;
diff --git a/libgeda/include/prototype.h b/libgeda/include/prototype.h
index 6c10844..4225762 100644
--- a/libgeda/include/prototype.h
+++ b/libgeda/include/prototype.h
@@ -496,7 +496,7 @@ GList *s_clib_search (const gchar *pattern, const CLibSearchMode mode);
 void s_clib_flush_cache ();
 const CLibSymbol *s_clib_get_symbol_by_name (const gchar *name);
 gchar *s_clib_symbol_get_data_by_name (const gchar *name);
-GList *s_toplevel_get_symbol_names (const TOPLEVEL *w_current);
+GList *s_toplevel_get_symbols (const TOPLEVEL *w_current);
 
 /* s_color.c */
 void s_color_init(void);
diff --git a/libgeda/src/s_clib.c b/libgeda/src/s_clib.c
index 347c4c2..14b486e 100644
--- a/libgeda/src/s_clib.c
+++ b/libgeda/src/s_clib.c
@@ -1265,9 +1265,9 @@ gchar *s_clib_symbol_get_data_by_name (const gchar *name)
  *  should (probably) also appear in the list.
  *
  *  \param w_current #TOPLEVEL structure to scan.
- *  \return GList of symbol names.
+ *  \return GList of symbols.
  */
-GList *s_toplevel_get_symbol_names (const TOPLEVEL *w_current)
+GList *s_toplevel_get_symbols (const TOPLEVEL *w_current)
 {
   GList *result = NULL;
   GList *iter = NULL;

commit 96f9c87ef4063b52dd4d13f51958b916ba4e5939
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Date:   Wed Jul 4 18:03:53 2007 +0100

    gschem: Add "In Use" view to component selector.
    
    The "In Use" view shows symbols which are instantiated in open
    schematics, for ease of adding more symbols similar to the ones
    already present.  This is particularly useful for frequently-used
    symbols such as resistors and capacitors.

diff --git a/gschem/include/x_compselect.h b/gschem/include/x_compselect.h
index 5a7245f..8b40806 100644
--- a/gschem/include/x_compselect.h
+++ b/gschem/include/x_compselect.h
@@ -61,7 +61,8 @@ struct _CompselectClass {
 struct _Compselect {
   GschemDialog parent_instance;
 
-  GtkTreeView *treeview;
+  GtkTreeView *libtreeview, *inusetreeview;
+  GtkNotebook *viewtabs;
   Preview     *preview;
   GtkEntry    *entry_filter;
   GtkButton   *button_clear;
diff --git a/gschem/src/x_compselect.c b/gschem/src/x_compselect.c
index 9f6e5d5..b2f0682 100644
--- a/gschem/src/x_compselect.c
+++ b/gschem/src/x_compselect.c
@@ -87,7 +87,7 @@ x_compselect_callback_response (GtkDialog *dialog,
 
   switch (arg1) {
       case COMPSELECT_RESPONSE_PLACE: {
-	CLibSymbol *symbol;
+	CLibSymbol *symbol = NULL;
         CompselectBehavior behavior;
         
         g_object_get (compselect,
@@ -247,28 +247,54 @@ static void compselect_get_property (GObject *object,
                                      GParamSpec *pspec);
 
 
-/*! \brief Sets data for a particular cell of the treeview.
+
+/*! \brief Sets data for a particular cell of the in use treeview.
+ *  \par Function Description
+ *  This function determines what data is to be displayed in the
+ *  "in use" symbol selection view.
+ *
+ *  The model is a list of symbols. s_clib_symbol_get_name() is called
+ *  to get the text to display.
+ */
+static void
+inuse_treeview_set_cell_data (GtkTreeViewColumn *tree_column,
+                            GtkCellRenderer   *cell,
+                            GtkTreeModel      *tree_model,
+                            GtkTreeIter       *iter,
+                            gpointer           data)
+{
+  GValue value = { 0, };
+  GValue strvalue = { 0, };
+  CLibSymbol *symbol;
+
+  gtk_tree_model_get_value (tree_model, iter, 0, &value);
+
+  g_value_init (&strvalue, G_TYPE_STRING);
+
+  symbol = (CLibSymbol *) g_value_get_pointer (&value);
+  g_value_set_string (&strvalue, s_clib_symbol_get_name (symbol));
+
+  g_object_set_property ((GObject*)cell, "text", &strvalue);
+
+  g_value_unset (&value);
+  g_value_unset (&strvalue);
+}
+
+/*! \brief Sets data for a particular cell of the library treeview.
  *  \par Function Description
  *  This function determines what data is to be displayed in the
- *  component column of the selection tree.
+ *  selection selection view.
  *
  *  The top level of the model contains sources, and the next symbols.
  *  s_clib_source_get_name() or s_clib_symbol_get_name() as
  *  appropriate is called to get the text to display.
- *
- *  \param [in] tree_column The GtkTreeColumn.
- *  \param [in] cell        The GtkCellRenderer that is being rendered
- *                          by tree_column.
- *  \param [in] tree_model  The tree model for components.
- *  \param [in] iter        An iterator on the current row to render.
- *  \param [in] data        Unused user data.
  */
 static void
-compselect_treeview_set_cell_data (GtkTreeViewColumn *tree_column,
-                                   GtkCellRenderer   *cell,
-                                   GtkTreeModel      *tree_model,
-                                   GtkTreeIter       *iter,
-                                   gpointer           data)
+lib_treeview_set_cell_data (GtkTreeViewColumn *tree_column,
+                            GtkCellRenderer   *cell,
+                            GtkTreeModel      *tree_model,
+                            GtkTreeIter       *iter,
+                            gpointer           data)
 {
   GtkTreeIter parent;
   GValue value = { 0, };
@@ -295,7 +321,7 @@ compselect_treeview_set_cell_data (GtkTreeViewColumn *tree_column,
   g_value_unset (&strvalue);
 }
 
-/*! \brief Determines visibility of items of the treeview.
+/*! \brief Determines visibility of items of the library treeview.
  *  \par Function Description
  *  This is the function used to filter entries of the component
  *  selection tree.
@@ -306,7 +332,7 @@ compselect_treeview_set_cell_data (GtkTreeViewColumn *tree_column,
  *  \returns TRUE if item should be visible, FALSE otherwise.
  */
 static gboolean
-compselect_model_filter_visible_func (GtkTreeModel *model,
+lib_model_filter_visible_func (GtkTreeModel *model,
                                       GtkTreeIter  *iter,
                                       gpointer      data)
 {
@@ -332,7 +358,7 @@ compselect_model_filter_visible_func (GtkTreeModel *model,
     gtk_tree_model_iter_children (model, &iter2, iter);
     ret = FALSE;
     do {
-      if (compselect_model_filter_visible_func (model, &iter2, data)) {
+      if (lib_model_filter_visible_func (model, &iter2, data)) {
         ret = TRUE;
         break;
       }
@@ -357,12 +383,11 @@ compselect_model_filter_visible_func (GtkTreeModel *model,
 /*! \brief Handles changes in the treeview selection.
  *  \par Function Description
  *  This is the callback function that is called every time the user
- *  select a row in the component treeview of the dialog.
+ *  select a row in either component treeview of the dialog.
  *
  *  If the selection is not a selection of a component (a directory
- *  name), it does nothing. Otherwise it retrieves the component and
- *  directory name from the model (the directory name is build from
- *  the ancestors of the row in the model).
+ *  name), it does nothing. Otherwise it retrieves the #CLibSymbol
+ *  from the model.
  *
  *  It then emits the dialog's <B>apply</B> signal to let its parent
  *  know that a component has been selected.
@@ -374,6 +399,7 @@ static void
 compselect_callback_tree_selection_changed (GtkTreeSelection *selection,
                                             gpointer          user_data)
 {
+  GtkTreeView *view;
   GtkTreeModel *model;
   GtkTreeIter iter, parent;
   Compselect *compselect = (Compselect*)user_data;
@@ -384,12 +410,20 @@ compselect_callback_tree_selection_changed (GtkTreeSelection *selection,
     return;
   }
 
-  if (!gtk_tree_model_iter_parent (model, &parent, &iter)) {
-    /* selected element is not a leaf -> not a component name */
-    return;
+  view = gtk_tree_selection_get_tree_view (selection);
+
+  if (view == compselect->inusetreeview) {
+    /* No special handling at the moment */
+  } else if (view == compselect->libtreeview) {
+    if (!gtk_tree_model_iter_parent (model, &parent, &iter)) {
+      /* selected element is not a leaf -> not a component name */
+      return;
+    }
+  } else {
+    /* Something's gone wrong */
+   g_assert_not_reached();
   }
   
-  /* build full path to component looking at parents */
   gtk_tree_model_get (model, &iter, 0, &sym, -1);
 
   buffer = s_clib_symbol_get_data (sym);
@@ -428,7 +462,7 @@ compselect_filter_timeout (gpointer data)
   /* resets the source id in compselect */
   compselect->filter_timeout = 0;
   
-  model = gtk_tree_view_get_model (compselect->treeview);
+  model = gtk_tree_view_get_model (compselect->libtreeview);
 
   if (model != NULL) {
     gtk_tree_model_filter_refilter ((GtkTreeModelFilter*)model);
@@ -523,9 +557,45 @@ compselect_callback_behavior_changed (GtkOptionMenu *optionmenu,
                          NULL);
 }
 
+/* \brief Create the tree model for the "In Use" view.
+ * \par Function Description
+ * Creates a straightforward list of symbols which are currently in
+ * use, using s_toplevel_get_symbol_names().
+ */
+static GtkTreeModel*
+create_inuse_tree_model (void)
+{
+  GtkListStore *store;
+  GList *symhead, *symlist;
+  GtkTreeIter iter;
+
+  store = (GtkListStore *) gtk_list_store_new (1, G_TYPE_POINTER);
+
+  symhead = s_toplevel_get_symbol_names (global_window_current);
 
+  for (symlist = symhead;
+       symlist != NULL;
+       symlist = g_list_next (symlist)) {
+
+    gtk_list_store_append (store, &iter);
+
+    gtk_list_store_set (store, &iter,
+                        0, symlist->data,
+                        -1);
+  }
+
+  g_list_free (symlist);
+
+  return (GtkTreeModel*)store;
+}
+
+/* \brief Create the tree model for the "Library" view.
+ * \par Function Description
+ * Creates a tree where the branches are the available component
+ * sources and the leaves are the symbols.
+ */
 static GtkTreeModel*
-compselect_create_child_model (void)
+create_lib_tree_model (void)
 {
   GtkTreeStore *store;
   GList *srchead, *srclist;
@@ -583,141 +653,94 @@ compselect_callback_refresh_library (Compselect *compselect,
   /* Rescan the libraries for symbols */
   s_clib_refresh ();
 
+  /* Refresh the "Library" view */
   model = (GtkTreeModel *)
     g_object_new (GTK_TYPE_TREE_MODEL_FILTER,
-                  "child-model", compselect_create_child_model (),
+                  "child-model", create_lib_tree_model (),
                   "virtual-root", NULL,
                   NULL);
 
-  gtk_tree_view_set_model (compselect->treeview, model);
-}
-
+  gtk_tree_view_set_model (compselect->libtreeview, model);
 
+  /* Refresh the "In Use" view */
+  model = create_inuse_tree_model ();
+  gtk_tree_view_set_model (compselect->inusetreeview, model);
+}
 
-/*! \brief Create the combo box for behaviors.
- *  \par Function Description
- *  This function creates and returns a <B>GtkComboBox</B> for
- *  selecting the behavior when a component is added to the sheet.
- */
+/*! \brief Creates the treeview for the "In Use" view. */
 static GtkWidget*
-compselect_create_behaviors_combo_box (void)
+create_inuse_treeview (Compselect *compselect)
 {
-  GtkWidget *combobox;
+  GtkWidget *scrolled_win, *treeview;
+  GtkTreeModel *model;
+  GtkTreeSelection *selection;
+  GtkCellRenderer *renderer;
+  GtkTreeViewColumn *column;
 
-  combobox = gtk_combo_box_new_text ();
+  model = create_inuse_tree_model ();
 
-  /* Note: order of items in menu is important */
-  /* COMPSEL_BEHAVIOR_REFERENCE */
-  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox),
-                             _("Default behavior - reference component"));
-  /* COMPSEL_BEHAVIOR_EMBED */
-  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox), 
-                             _("Embed component in schematic"));
-  /* COMPSEL_BEHAVIOR_INCLUDE */
-  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox),
-                             _("Include component as individual objects"));
+  /* Create a scrolled window to accomodate the treeview */
+  scrolled_win = GTK_WIDGET (
+    g_object_new (GTK_TYPE_SCROLLED_WINDOW,
+                  /* GtkScrolledWindow */
+                  "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
+                  "vscrollbar-policy", GTK_POLICY_ALWAYS,
+                  "shadow-type",       GTK_SHADOW_ETCHED_IN,
+                  NULL));
 
-  gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0);
-  
-  return combobox;
-}
+  /* Create the treeview */
+  treeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
+                                       /* GtkTreeView */
+                                       "model",      model,
+                                       "rules-hint", TRUE,
+                                       "headers-visible", FALSE,
+                                       NULL));
 
-GType
-compselect_get_type ()
-{
-  static GType compselect_type = 0;
-  
-  if (!compselect_type) {
-    static const GTypeInfo compselect_info = {
-      sizeof(CompselectClass),
-      NULL, /* base_init */
-      NULL, /* base_finalize */
-      (GClassInitFunc) compselect_class_init,
-      NULL, /* class_finalize */
-      NULL, /* class_data */
-      sizeof(Compselect),
-      0,    /* n_preallocs */
-      (GInstanceInitFunc) compselect_init,
-    };
-                
-    compselect_type = g_type_register_static (GSCHEM_TYPE_DIALOG,
-                                              "Compselect",
-                                              &compselect_info, 0);
-  }
-  
-  return compselect_type;
-}
+  /* Connect callback to selection */
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+  gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+  g_signal_connect (selection,
+                    "changed",
+                    G_CALLBACK (compselect_callback_tree_selection_changed),
+                    compselect);
 
-static void
-compselect_class_init (CompselectClass *klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  /* Insert a column for symbol name */
+  renderer = GTK_CELL_RENDERER (
+    g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
+                  /* GtkCellRendererText */
+                  "editable", FALSE,
+                  NULL));
+  column = GTK_TREE_VIEW_COLUMN (
+    g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
+                  /* GtkTreeViewColumn */
+                  "title", _("Components"),
+                  NULL));
+  gtk_tree_view_column_pack_start (column, renderer, TRUE);
+  gtk_tree_view_column_set_cell_data_func (column, renderer,
+                                           inuse_treeview_set_cell_data,
+                                           NULL, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
-  compselect_parent_class = g_type_class_peek_parent (klass);
-  
-  gobject_class->finalize     = compselect_finalize;
-  gobject_class->set_property = compselect_set_property;
-  gobject_class->get_property = compselect_get_property;
+  /* Add the treeview to the scrolled window */
+  gtk_container_add (GTK_CONTAINER (scrolled_win), treeview);
+  /* set the inuse treeview of compselect */
+  compselect->inusetreeview = GTK_TREE_VIEW (treeview);
 
-  g_object_class_install_property (
-    gobject_class, PROP_SYMBOL,
-    g_param_spec_pointer ("symbol",
-			  "",
-			  "",
-			  G_PARAM_READABLE));
-  g_object_class_install_property (
-    gobject_class, PROP_BEHAVIOR,
-    g_param_spec_enum ("behavior",
-                       "",
-                       "",
-                       COMPSELECT_TYPE_BEHAVIOR,
-                       COMPSELECT_BEHAVIOR_REFERENCE,
-                       G_PARAM_READWRITE));
-  g_object_class_install_property (
-    gobject_class, PROP_HIDDEN,
-    g_param_spec_boolean ("hidden",
-			  "",
-			  "",
-			  FALSE,
-			  G_PARAM_READWRITE));
-  
+  return scrolled_win;
 }
 
-static void
-compselect_init (Compselect *compselect)
+/*! \brief Creates the treeview for the "Library" view */
+static GtkWidget *
+create_lib_treeview (Compselect *compselect)
 {
-  GtkWidget *hbox, *vbox, *filter_hbox;
-  GtkWidget *scrolled_win, *treeview, *label, *entry, *preview, *combobox;
-  GtkWidget *button;
+  GtkWidget *libtreeview, *vbox, *scrolled_win, *label, 
+    *hbox, *entry, *button;
   GtkTreeModel *child_model, *model;
+  GtkTreeSelection *selection;
   GtkCellRenderer *renderer;
   GtkTreeViewColumn *column;
-  GtkTreeSelection *selection;
 
-  GtkWidget *alignment, *frame;
-  
-  /* dialog initialization */
-  g_object_set (G_OBJECT (compselect),
-                /* GtkWindow */
-                "type",            GTK_WINDOW_TOPLEVEL,
-                "title",           _("Select Component..."),
-                "default-height",  300,
-                "default-width",   400,
-                "modal",           FALSE,
-                "window-position", GTK_WIN_POS_NONE,
-                /* GtkDialog */
-                "has-separator",   TRUE,
-                NULL);
-  g_object_set (GTK_DIALOG (compselect)->vbox,
-                "homogeneous", FALSE,
-                NULL);
-
-  /* horizontal box selection and preview */
-  hbox = GTK_WIDGET (g_object_new (GTK_TYPE_HBOX,
-                                   /* GtkBox */
-                                   "homogeneous", FALSE,
-                                   "spacing",     5,
-                                   NULL));
+  /* -- library selection view -- */
 
   /* vertical box for component selection and search entry */
   vbox = GTK_WIDGET (g_object_new (GTK_TYPE_VBOX,
@@ -727,17 +750,12 @@ compselect_init (Compselect *compselect)
                                    "homogeneous",  FALSE,
                                    "spacing",      5,
                                    NULL));
-  
-  /* -- directory/component selection -- */
-  child_model  = compselect_create_child_model ();
+
+  child_model  = create_lib_tree_model ();
   model = (GtkTreeModel*)g_object_new (GTK_TYPE_TREE_MODEL_FILTER,
                                        "child-model",  child_model,
                                        "virtual-root", NULL,
                                        NULL);
-/*   gtk_tree_model_filter_set_visible_func ((GtkTreeModelFilter*)model, */
-/*                                           compselect_model_filter_visible_func, */
-/*                                           compselect, */
-/*                                           NULL); */
   
   scrolled_win = GTK_WIDGET (
     g_object_new (GTK_TYPE_SCROLLED_WINDOW,
@@ -747,20 +765,21 @@ compselect_init (Compselect *compselect)
                   "shadow-type",       GTK_SHADOW_ETCHED_IN,
                   NULL));
   /* create the treeview */
-  treeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
-                                       /* GtkTreeView */
-                                       "model",      model,
-                                       "rules-hint", TRUE,
-                                       NULL));
+  libtreeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
+                                          /* GtkTreeView */
+                                          "model",      model,
+                                          "rules-hint", TRUE,
+                                          "headers-visible", FALSE,
+                                          NULL));
   /* connect callback to selection */
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (libtreeview));
   gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
   g_signal_connect (selection,
                     "changed",
                     G_CALLBACK (compselect_callback_tree_selection_changed),
                     compselect);
 
-  /* insert a column to treeview for directory name */
+  /* insert a column to treeview for library/symbol name */
   renderer = GTK_CELL_RENDERER (
     g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
                   /* GtkCellRendererText */
@@ -773,14 +792,14 @@ compselect_init (Compselect *compselect)
                   NULL));
   gtk_tree_view_column_pack_start (column, renderer, TRUE);
   gtk_tree_view_column_set_cell_data_func (column, renderer,
-                                           compselect_treeview_set_cell_data,
+                                           lib_treeview_set_cell_data,
                                            NULL, NULL);
-  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (libtreeview), column);
   
   /* add the treeview to the scrolled window */
-  gtk_container_add (GTK_CONTAINER (scrolled_win), treeview);
+  gtk_container_add (GTK_CONTAINER (scrolled_win), libtreeview);
   /* set directory/component treeview of compselect */
-  compselect->treeview = GTK_TREE_VIEW (treeview);
+  compselect->libtreeview = GTK_TREE_VIEW (libtreeview);
 
   /* add the scrolled window for directories to the vertical box */
   gtk_box_pack_start (GTK_BOX (vbox), scrolled_win,
@@ -788,7 +807,7 @@ compselect_init (Compselect *compselect)
 
   
   /* -- filter area -- */
-  filter_hbox = GTK_WIDGET (g_object_new (GTK_TYPE_HBOX,
+  hbox = GTK_WIDGET (g_object_new (GTK_TYPE_HBOX,
                                           /* GtkBox */
                                           "homogeneous", FALSE,
                                           "spacing",     3,
@@ -802,7 +821,7 @@ compselect_init (Compselect *compselect)
                                     "label",  _("Filter:"),
                                     NULL));
   /* add the search label to the filter area */
-  gtk_box_pack_start (GTK_BOX (filter_hbox), label,
+  gtk_box_pack_start (GTK_BOX (hbox), label,
                       FALSE, FALSE, 0);
   
   /* create the text entry for filter in components */
@@ -814,8 +833,15 @@ compselect_init (Compselect *compselect)
                     "changed",
                     G_CALLBACK (compselect_callback_filter_entry_changed),
                     compselect);
+
+  /* now that that we have an entry, set the filter func of model */
+  gtk_tree_model_filter_set_visible_func ((GtkTreeModelFilter*)model,
+                                          lib_model_filter_visible_func,
+                                          compselect,
+                                          NULL);
+
   /* add the filter entry to the filter area */
-  gtk_box_pack_start (GTK_BOX (filter_hbox), entry,
+  gtk_box_pack_start (GTK_BOX (hbox), entry,
                       TRUE, TRUE, 0);
   /* set filter entry of compselect */
   compselect->entry_filter = GTK_ENTRY (entry);
@@ -837,26 +863,158 @@ compselect_init (Compselect *compselect)
                     G_CALLBACK (compselect_callback_filter_button_clicked),
                     compselect);
   /* add the clear button to the filter area */
-  gtk_box_pack_start (GTK_BOX (filter_hbox), button,
+  gtk_box_pack_start (GTK_BOX (hbox), button,
                       FALSE, FALSE, 0);
   /* set clear button of compselect */
   compselect->button_clear = GTK_BUTTON (button);
                                      
   /* add the filter area to the vertical box */
-  gtk_box_pack_start (GTK_BOX (vbox), filter_hbox,
+  gtk_box_pack_start (GTK_BOX (vbox), hbox,
                       FALSE, FALSE, 0);
 
+  compselect->libtreeview = GTK_TREE_VIEW (libtreeview);
+
+  return vbox;
+}
+
+/*! \brief Create the combo box for behaviors.
+ *  \par Function Description
+ *  This function creates and returns a <B>GtkComboBox</B> for
+ *  selecting the behavior when a component is added to the sheet.
+ */
+static GtkWidget*
+create_behaviors_combo_box (void)
+{
+  GtkWidget *combobox;
+
+  combobox = gtk_combo_box_new_text ();
+
+  /* Note: order of items in menu is important */
+  /* COMPSEL_BEHAVIOR_REFERENCE */
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox),
+                             _("Default behavior - reference component"));
+  /* COMPSEL_BEHAVIOR_EMBED */
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox),
+                             _("Embed component in schematic"));
+  /* COMPSEL_BEHAVIOR_INCLUDE */
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox),
+                             _("Include component as individual objects"));
+
+  gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0);
+  
+  return combobox;
+}
+
+GType
+compselect_get_type ()
+{
+  static GType compselect_type = 0;
   
+  if (!compselect_type) {
+    static const GTypeInfo compselect_info = {
+      sizeof(CompselectClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) compselect_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof(Compselect),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) compselect_init,
+    };
+                
+    compselect_type = g_type_register_static (GSCHEM_TYPE_DIALOG,
+                                              "Compselect",
+                                              &compselect_info, 0);
+  }
+  
+  return compselect_type;
+}
+
+static void
+compselect_class_init (CompselectClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  compselect_parent_class = g_type_class_peek_parent (klass);
+  
+  gobject_class->finalize     = compselect_finalize;
+  gobject_class->set_property = compselect_set_property;
+  gobject_class->get_property = compselect_get_property;
+
+  g_object_class_install_property (
+    gobject_class, PROP_SYMBOL,
+    g_param_spec_pointer ("symbol",
+			  "",
+			  "",
+			  G_PARAM_READABLE));
+  g_object_class_install_property (
+    gobject_class, PROP_BEHAVIOR,
+    g_param_spec_enum ("behavior",
+                       "",
+                       "",
+                       COMPSELECT_TYPE_BEHAVIOR,
+                       COMPSELECT_BEHAVIOR_REFERENCE,
+                       G_PARAM_READWRITE));
+  g_object_class_install_property (
+    gobject_class, PROP_HIDDEN,
+    g_param_spec_boolean ("hidden",
+			  "",
+			  "",
+			  FALSE,
+			  G_PARAM_READWRITE));
+  
+}
+
+static void
+compselect_init (Compselect *compselect)
+{
+  GtkWidget *hbox, *notebook;
+  GtkWidget *libview, *inuseview;
+  GtkWidget *preview, *combobox;
+  
+  GtkWidget *alignment, *frame;
+  
+  /* dialog initialization */
+  g_object_set (G_OBJECT (compselect),
+                /* GtkWindow */
+                "type",            GTK_WINDOW_TOPLEVEL,
+                "title",           _("Select Component..."),
+                "default-height",  300,
+                "default-width",   400,
+                "modal",           FALSE,
+                "window-position", GTK_WIN_POS_NONE,
+                /* GtkDialog */
+                "has-separator",   TRUE,
+                NULL);
+  g_object_set (GTK_DIALOG (compselect)->vbox,
+                "homogeneous", FALSE,
+                NULL);
+
+  /* horizontal box selection and preview */
+  hbox = GTK_WIDGET (g_object_new (GTK_TYPE_HBOX,
+                                   /* GtkBox */
+                                   "homogeneous", FALSE,
+                                   "spacing",     5,
+                                   NULL));
+
+  /* notebook for library and inuse views */
+  notebook = GTK_WIDGET (g_object_new (GTK_TYPE_NOTEBOOK,
+                                       NULL));
+  compselect->viewtabs = GTK_NOTEBOOK (notebook);
+
+  inuseview = create_inuse_treeview (compselect);
+  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), inuseview,
+                            gtk_label_new (_("In Use")));  
+
+  libview = create_lib_treeview (compselect);
+  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), libview,
+                            gtk_label_new (_("Libraries")));
+
   /* include the vertical box in horizontal box */
-  gtk_box_pack_start (GTK_BOX (hbox), vbox,
+  gtk_box_pack_start (GTK_BOX (hbox), notebook,
                       TRUE, TRUE, 0);
 
-  /* now that that we have an entry, set the filter func of model */
-  gtk_tree_model_filter_set_visible_func ((GtkTreeModelFilter*)model,
-                                          compselect_model_filter_visible_func,
-                                          compselect,
-                                          NULL);
-
                      
   /* -- preview area -- */
   frame = GTK_WIDGET (g_object_new (GTK_TYPE_FRAME,
@@ -893,7 +1051,7 @@ compselect_init (Compselect *compselect)
   
 
   /* -- behavior combo box -- */
-  combobox = compselect_create_behaviors_combo_box ();
+  combobox = create_behaviors_combo_box ();
   g_signal_connect (combobox,
                     "changed",
                     G_CALLBACK (compselect_callback_behavior_changed),
@@ -986,21 +1144,34 @@ compselect_get_property (GObject *object,
 	{
 	  GtkTreeModel *model;
 	  GtkTreeIter iter, parent;
-	  CLibSymbol *symbol;
-	  if (gtk_tree_selection_get_selected (
-		gtk_tree_view_get_selection (compselect->treeview),
-		&model,
-		&iter)
-	      && gtk_tree_model_iter_parent (model, &parent, &iter)) {
-	    
-	    gtk_tree_model_get (model, &iter, 0, &symbol, -1);
-	    g_value_set_pointer (value, symbol);
-
-	  } else {
-	    g_value_set_pointer (value, NULL);
-	  }
-	}
-        break;
+	  CLibSymbol *symbol = NULL;
+
+          /* FIXME assumes pages are in a specific order */
+          switch (gtk_notebook_get_current_page(compselect->viewtabs)) {
+          case 0: /* In Use page */
+            if (gtk_tree_selection_get_selected (
+                  gtk_tree_view_get_selection (compselect->inusetreeview),
+                  &model,
+                  &iter)) {
+              gtk_tree_model_get (model, &iter, 0, &symbol, -1);
+            }
+            break;
+          case 1:
+            if (gtk_tree_selection_get_selected (
+                  gtk_tree_view_get_selection (compselect->libtreeview),
+                  &model,
+                  &iter)
+                && gtk_tree_model_iter_parent (model, &parent, &iter)) {
+              gtk_tree_model_get (model, &iter, 0, &symbol, -1);
+            }
+            break;
+          default:
+            g_assert_not_reached();
+          }
+
+          g_value_set_pointer (value, symbol);
+          break;
+        }
       case PROP_BEHAVIOR:
         g_value_set_enum (value,
                           gtk_combo_box_get_active (

commit b1733d4d69d3a2e6fcb64e91a26dab2768f4e171
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Date:   Wed Jul 4 18:03:53 2007 +0100

    gschem: Add a "Refresh" button to component selector.
    
    In order to update the symbol library, a "Refresh" button is needed
    (because we don't do it automatically any more).

diff --git a/gschem/include/x_compselect.h b/gschem/include/x_compselect.h
index a66e30a..5a7245f 100644
--- a/gschem/include/x_compselect.h
+++ b/gschem/include/x_compselect.h
@@ -77,7 +77,8 @@ GType compselect_get_type (void);
 /* Response IDs for special dialog buttons */
 typedef enum {
   COMPSELECT_RESPONSE_PLACE = 1,
-  COMPSELECT_RESPONSE_HIDE = 2
+  COMPSELECT_RESPONSE_HIDE = 2,
+  COMPSELECT_RESPONSE_REFRESH = 3
 } CompselectResponseType;
 
 #endif /* __X_COMPSEL_H__ */
diff --git a/gschem/src/x_compselect.c b/gschem/src/x_compselect.c
index 4c2ccf8..9f6e5d5 100644
--- a/gschem/src/x_compselect.c
+++ b/gschem/src/x_compselect.c
@@ -163,7 +163,9 @@ x_compselect_callback_response (GtkDialog *dialog,
   
         break;
       default:
-        g_assert_not_reached ();
+        /* Do nothing, in case there's another handler function which
+           can handle the response ID received. */
+        break;
   }
   
 }
@@ -521,6 +523,7 @@ compselect_callback_behavior_changed (GtkOptionMenu *optionmenu,
                          NULL);
 }
 
+
 static GtkTreeModel*
 compselect_create_child_model (void)
 {
@@ -561,6 +564,36 @@ compselect_create_child_model (void)
   return (GtkTreeModel*)store;
 }
 
+/* \brief On-demand refresh of the component library.
+ * \par Function Description
+ * Requests a rescan of the component library in order to pick up any
+ * new signals, and then updates the component selector.  Handler for
+ * the #COMPSELECT_RESPONSE_REFRESH response ID.
+ */
+static void
+compselect_callback_refresh_library (Compselect *compselect,
+                                     gint response_id,
+                                     gpointer user_data) {
+  GtkTreeModel *model;
+
+  if (response_id != COMPSELECT_RESPONSE_REFRESH) {
+    return;
+  }
+
+  /* Rescan the libraries for symbols */
+  s_clib_refresh ();
+
+  model = (GtkTreeModel *)
+    g_object_new (GTK_TYPE_TREE_MODEL_FILTER,
+                  "child-model", compselect_create_child_model (),
+                  "virtual-root", NULL,
+                  NULL);
+
+  gtk_tree_view_set_model (compselect->treeview, model);
+}
+
+
+
 /*! \brief Create the combo box for behaviors.
  *  \par Function Description
  *  This function creates and returns a <B>GtkComboBox</B> for
@@ -870,7 +903,6 @@ compselect_init (Compselect *compselect)
   gtk_widget_show_all (combobox);
   /* set behavior combo box of compselect */
   compselect->combobox_behaviors = GTK_COMBO_BOX (combobox);
-
   
   /* now add buttons in the action area */
   gtk_dialog_add_buttons (GTK_DIALOG (compselect),
@@ -879,16 +911,25 @@ compselect_init (Compselect *compselect)
                           /*  - update button */
                           GTK_STOCK_APPLY, COMPSELECT_RESPONSE_PLACE,
 			  GTK_STOCK_OK, COMPSELECT_RESPONSE_HIDE,
+                          /*  - refresh button */
+                          GTK_STOCK_REFRESH, COMPSELECT_RESPONSE_REFRESH,
                           NULL);
 
 #if GTK_CHECK_VERSION (2,6,0)
   /* Set the alternative button order (ok, cancel, help) for other systems */
   gtk_dialog_set_alternative_button_order(GTK_DIALOG(compselect),
+                                          COMPSELECT_RESPONSE_REFRESH,
 					  COMPSELECT_RESPONSE_HIDE,
 					  COMPSELECT_RESPONSE_PLACE,
 					  GTK_RESPONSE_CLOSE,
 					  -1);
 #endif
+
+  /* Add refresh handler */
+  g_signal_connect (compselect, "response",
+                    G_CALLBACK (compselect_callback_refresh_library),
+                    NULL);
+
   /* Initialize the hidden property */
   compselect->hidden = FALSE;
 }

commit cb6e4e5e98ed45427f60d718f7dbb5d5439eecef
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Date:   Wed Jul 4 18:03:53 2007 +0100

    gschem: Don't use generic response IDs for compselect actions.
    
    The component selector "OK" and "Apply" buttons aren't actually "OK"
    and "Apply" actions, so they shouldn't use those response IDs -- it's
    confusing.
    
    This patch adds special response IDs for these actions. This is a
    preparation for using "proper" Place and Hide icons & text.

diff --git a/gschem/include/x_compselect.h b/gschem/include/x_compselect.h
index 18d718f..a66e30a 100644
--- a/gschem/include/x_compselect.h
+++ b/gschem/include/x_compselect.h
@@ -74,5 +74,10 @@ struct _Compselect {
 
 GType compselect_get_type (void);
 
+/* Response IDs for special dialog buttons */
+typedef enum {
+  COMPSELECT_RESPONSE_PLACE = 1,
+  COMPSELECT_RESPONSE_HIDE = 2
+} CompselectResponseType;
 
 #endif /* __X_COMPSEL_H__ */
diff --git a/gschem/src/x_compselect.c b/gschem/src/x_compselect.c
index bbab75f..4c2ccf8 100644
--- a/gschem/src/x_compselect.c
+++ b/gschem/src/x_compselect.c
@@ -86,7 +86,7 @@ x_compselect_callback_response (GtkDialog *dialog,
   GValue value = { 0, };
 
   switch (arg1) {
-      case GTK_RESPONSE_APPLY: {
+      case COMPSELECT_RESPONSE_PLACE: {
 	CLibSymbol *symbol;
         CompselectBehavior behavior;
         
@@ -133,12 +133,13 @@ x_compselect_callback_response (GtkDialog *dialog,
 
         break;
       }
-      case GTK_RESPONSE_OK:
+      case COMPSELECT_RESPONSE_HIDE:
 	/* Response when clicking on the "hide" button */
 
 	/* If there is no component in the complex place list, set the current one */
 	if (toplevel->page_current->complex_place_list == NULL) {
-	  gtk_dialog_response (GTK_DIALOG (compselect), GTK_RESPONSE_APPLY);
+	  gtk_dialog_response (GTK_DIALOG (compselect), 
+                               COMPSELECT_RESPONSE_PLACE);
 	}
 
 	/* Hide the component selector */
@@ -399,7 +400,7 @@ compselect_callback_tree_selection_changed (GtkTreeSelection *selection,
   /* signal a component has been selected to parent of dialog */
   g_signal_emit_by_name (compselect,
                          "response",
-                         GTK_RESPONSE_APPLY,
+                         COMPSELECT_RESPONSE_PLACE,
                          NULL);
 
   g_free (buffer);
@@ -516,7 +517,7 @@ compselect_callback_behavior_changed (GtkOptionMenu *optionmenu,
 
   g_signal_emit_by_name (compselect,
                          "response",
-                         GTK_RESPONSE_APPLY,
+                         COMPSELECT_RESPONSE_PLACE,
                          NULL);
 }
 
@@ -876,15 +877,15 @@ compselect_init (Compselect *compselect)
                           /*  - close button */
                           GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
                           /*  - update button */
-                          GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
-			  GTK_STOCK_OK, GTK_RESPONSE_OK,
+                          GTK_STOCK_APPLY, COMPSELECT_RESPONSE_PLACE,
+			  GTK_STOCK_OK, COMPSELECT_RESPONSE_HIDE,
                           NULL);
 
 #if GTK_CHECK_VERSION (2,6,0)
   /* Set the alternative button order (ok, cancel, help) for other systems */
   gtk_dialog_set_alternative_button_order(GTK_DIALOG(compselect),
-					  GTK_RESPONSE_OK,
-					  GTK_RESPONSE_APPLY,
+					  COMPSELECT_RESPONSE_HIDE,
+					  COMPSELECT_RESPONSE_PLACE,
 					  GTK_RESPONSE_CLOSE,
 					  -1);
 #endif

commit 7c6419f49cb211ce74e7a8787148d2fd624482e7
Author: Alex Precosky <precosky@xxxxxxx>
Date:   Sun Jul 1 16:55:13 2007 -0700

    gschem: Fix a race condition with mouse wheel scroll events (1740327)
    
    If more than one mouse wheel scroll events are received into the event
    queue before the first one can be processed, then the program was
    zooming in to the wrong location.  This is because the mouse moved
    event handler, which is triggered by a call to warp the cursor in the
    scroll event handler, must run to update the mouse postion global
    variables that the scroll event handler needs.

diff --git a/gschem/src/a_zoom.c b/gschem/src/a_zoom.c
index 23edb4a..8f431f3 100644
--- a/gschem/src/a_zoom.c
+++ b/gschem/src/a_zoom.c
@@ -133,6 +133,23 @@ void a_zoom(TOPLEVEL *w_current, int dir, int selected_from, int pan_flags)
   /* calculate new window and draw it */
   a_pan_general(w_current, world_pan_center_x, world_pan_center_y,
                 relativ_zoom_factor, pan_flags);
+
+  /* Before warping the cursor, filter out any consecutive scroll events 
+   * from the event queue.  If the program receives more than one scroll 
+   * event before it can process the first one, then the globals mouse_x 
+   * and mouse_y won't contain the proper mouse position,
+   * because the handler for the mouse moved event needs to 
+   * run first to set these values.
+   */
+  GdkEvent *topEvent = gdk_event_get();
+  while( topEvent != NULL ) {
+    if( topEvent->type != GDK_SCROLL ) {
+      gdk_event_put( topEvent );
+      break;
+    }
+    gdk_event_free( topEvent );
+    topEvent = gdk_event_get();
+  }
 	
   /* warp the cursor to the right position */ 
   if (w_current->warp_cursor) {

commit ab0fef1d36d05088f3891397103ebb15b3e3c2d0
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Date:   Wed Jul 4 18:03:53 2007 +0100

    libgeda: Make command-backed component sources more flexible.
    
    Allow different commands to be specified for 'list' and 'get' with
    custom command-line arguments.

diff --git a/libgeda/include/prototype.h b/libgeda/include/prototype.h
index 57a64b9..6c10844 100644
--- a/libgeda/include/prototype.h
+++ b/libgeda/include/prototype.h
@@ -44,7 +44,7 @@ void g_rc_parse(TOPLEVEL *w_current, const gchar* rcname,
                 const gchar* specified_rc_filename);
 gint g_rc_parse_specified_rc(TOPLEVEL *w_current, const gchar *rcfilename);
 SCM g_rc_component_library(SCM path, SCM name);
-SCM g_rc_component_library_command (SCM command, SCM name);
+SCM g_rc_component_library_command (SCM listcmd, SCM getcmd, SCM name);
 SCM g_rc_component_library_funcs (SCM listfunc, SCM getfunc, SCM name);
 SCM g_rc_component_library_search(SCM path);
 SCM g_rc_source_library(SCM path);
@@ -481,7 +481,8 @@ const CLibSource *s_clib_get_source_by_name (const gchar *name);
 void s_clib_refresh ();
 const CLibSource *s_clib_add_directory (const gchar *directory, 
 					const gchar *name);
-const CLibSource *s_clib_add_command (const gchar *command,
+const CLibSource *s_clib_add_command (const gchar *list_cmd,
+                                      const gchar *get_cmd,
 				      const gchar *name);
 const CLibSource *s_clib_add_scm (SCM listfunc, SCM getfunc, 
 				  const gchar *name);
diff --git a/libgeda/src/g_rc.c b/libgeda/src/g_rc.c
index 6844aa8..d23cb9b 100644
--- a/libgeda/src/g_rc.c
+++ b/libgeda/src/g_rc.c
@@ -404,27 +404,39 @@ SCM g_rc_component_library(SCM path, SCM name)
  *  \param [in] name    Optional descriptive name for component source.
  *  \return SCM_BOOL_T on success, SCM_BOOL_F otherwise.
  */
-SCM g_rc_component_library_command (SCM command, SCM name)
+SCM g_rc_component_library_command (SCM listcmd, SCM getcmd, 
+                                    SCM name)
 {
   gchar *namestr = NULL;
-  gchar *cmdstr = NULL;
-  SCM_ASSERT (scm_is_string (command), command, SCM_ARG1, 
+  gchar *lcmdstr = NULL;
+  gchar *gcmdstr = NULL;
+  const CLibSource *src;
+  SCM_ASSERT (scm_is_string (listcmd), listcmd, SCM_ARG1, 
 	      "component-library-command");
-  cmdstr = g_strdup(SCM_STRING_CHARS (command));
+  lcmdstr = scm_to_locale_string (listcmd);
 
-  if (name != SCM_UNDEFINED) {
-    SCM_ASSERT (scm_is_string (name), name, SCM_ARG2, 
+  SCM_ASSERT (scm_is_string (getcmd), getcmd, SCM_ARG2, 
 	      "component-library-command");
-    namestr = SCM_STRING_CHARS (name);
-  }
+  gcmdstr = scm_to_locale_string (getcmd);
+
+  SCM_ASSERT (scm_is_string (name), name, SCM_ARG3, 
+	      "component-library-command");
+  namestr = scm_to_locale_string (name);
+  
   /* take care of any shell variables */
-  cmdstr = expand_env_variables(cmdstr);
+  /*! \bug this may be a security risk! */
+  lcmdstr = expand_env_variables(lcmdstr);
+  gcmdstr = expand_env_variables(gcmdstr);
 
-  s_clib_add_command (cmdstr, namestr);
+  src = s_clib_add_command (lcmdstr, gcmdstr, namestr);
 
-  g_free (cmdstr);
+  g_free (lcmdstr);
+  g_free (gcmdstr);
+  g_free (namestr);
 
-  return SCM_BOOL_T;
+  if (src != NULL) return SCM_BOOL_T;
+
+  return SCM_BOOL_F;
 }
 
 /*! \brief Guile callback for adding library functions.
diff --git a/libgeda/src/g_register.c b/libgeda/src/g_register.c
index 00607b4..9d9443f 100644
--- a/libgeda/src/g_register.c
+++ b/libgeda/src/g_register.c
@@ -59,7 +59,7 @@ struct gsubr_t {
 /*! \brief */
 static struct gsubr_t libgeda_funcs[] = {
   { "component-library",        1, 1, 0, g_rc_component_library },
-  { "component-library-command", 1, 1, 0, g_rc_component_library_command },
+  { "component-library-command", 3, 0, 0, g_rc_component_library_command },
   { "component-library-funcs",  3, 0, 0, g_rc_component_library_funcs },
   { "component-library-search", 1, 0, 0, g_rc_component_library_search },
   { "source-library",           1, 0, 0, g_rc_source_library },
diff --git a/libgeda/src/s_clib.c b/libgeda/src/s_clib.c
index 712d390..347c4c2 100644
--- a/libgeda/src/s_clib.c
+++ b/libgeda/src/s_clib.c
@@ -74,44 +74,23 @@
  *
  *  \page libcmds Library Commands
  *
- *  A library command should implement this specification.  Note that
- *  as additional features may be added to the component library in
- *  the future, ideally a library command should only respond to the
- *  commands detailed here.
+ *  A program or set of programs can be used as a component source.  The procedure used to add such a source from a gEDA rc file is:
  *
- *  The command line syntax for a library command is:
- *
- *  \code
- *  libcmd <mode> [mode arguments]
- *  \endcode
- *
- *  All diagnostic and error information should be printed to standard
- *  error.  Only data should be printed to standard output.  All data
- *  output from a library command should be encoded using UTF8.
- *
- *  If an error occurs, the command must exit with non-zero exit
- *  status, with any diagnostic information should be printed on
- *  standard error.
- *
- *  \section libcmds_modes Modes
- *
- *  \code
- *  libcmd list
- *  \endcode
- *
- *  If \b list is passed as the mode, a command must output a list of
- *  the symbols it provides, separated by newlines.  Lines beginning
- *  with a period '.' are ignored.  If an error occurs, the command
- *  must exit with non-zero exit status.
+ *  <code>
+ *  (component-library-command listcmd getcmd name)
+ *  </code>
  *
- *  \code
- *  libcmd get <symbolname>
- *  \endcode
+ *  This is implemented by g_rc_component_library_command(), which is
+ *  a wrapper for s_clib_add_command().
  *
- *  If \b get is passed as the mode, a command must output the symbol
- *  data corresponding to \b symbolname.  If \b symbolname is unknown
- *  to the command, the command must exit with non-zero exit status.
+ *  The list command will be executed with no further arguments, and
+ *  should output a list of available symbol names on stdout.  The get
+ *  command will have a symbol name appended to it as the final
+ *  argument, and should output gEDA symbol data on stdout.
  *
+ *  If the command cannot successfully complete, it should exit with
+ *  non-zero exit status.  Anything it has output on stdout will be
+ *  ignored, and any stderr output displayed to the user.
  *
  *  \page libscms Library Scheme Procedures
  *
@@ -189,13 +168,19 @@ enum CLibSourceType {
 struct _CLibSource {
   /*! Type of source */
   enum CLibSourceType type;
-  /*! Path to directory or name of executable */
-  gchar *path_cmd;
   /*! Name of source */
   gchar *name;
   /*! Available symbols (#CLibSymbol) */
   GList *symbols;
 
+  /*! Path to directory */
+  gchar *directory;
+
+  /*! Command & arguments for listing symbols */
+  gchar *list_cmd;
+  /*! Command & arguments for retrieving symbol data */
+  gchar *get_cmd;
+
   /*! Scheme function for listing symbols */
   SCM list_fn;
   /*! Scheme function for retrieving symbol data */
@@ -227,7 +212,7 @@ static void free_symbol (gpointer data, gpointer user_data);
 static void free_source (gpointer data, gpointer user_data);
 static gint compare_source_name (gconstpointer a, gconstpointer b);
 static gint compare_symbol_name (gconstpointer a, gconstpointer b);
-static gchar *run_source_command (gchar **argv);
+static gchar *run_source_command (const gchar *command);
 static CLibSymbol *source_has_symbol (const CLibSource *source, 
 				      const gchar *name);
 static void refresh_directory (CLibSource *source);
@@ -286,10 +271,6 @@ static void free_source (gpointer data, gpointer user_data)
 {
   CLibSource *source = data;
   if (source != NULL) {
-    if (source->path_cmd != NULL) {
-      g_free (source->path_cmd);
-      source->path_cmd = NULL;
-    }
     if (source->name != NULL) {
       g_free (source->name);
       source->name = NULL;
@@ -299,6 +280,18 @@ static void free_source (gpointer data, gpointer user_data)
       g_list_free (source->symbols);
       source->symbols = NULL;
     }
+    if (source->directory != NULL) {
+      g_free (source->directory);
+      source->directory = NULL;
+    }
+    if (source->list_cmd != NULL) {
+      g_free (source->list_cmd);
+      source->list_cmd = NULL;
+    }
+    if (source->get_cmd != NULL) {
+      g_free (source->get_cmd);
+      source->get_cmd = NULL;
+    }
     if (source->type == CLIB_SCM) {
       scm_gc_unprotect_object (source->list_fn);
       scm_gc_unprotect_object (source->get_fn);
@@ -379,32 +372,24 @@ static gint compare_symbol_name (gconstpointer a, gconstpointer b)
  *
  *  Private function used only in s_clib.c.
  *
- *  \param argv null-terminated list of arguments.  The name of the
- *              program to execute should appear first.
+ *  \todo This is probably generally useful.
  *
+ *  \param argv Command string to execute.
  *  \return The program's output, or \b NULL on failure.
  */
-static gchar *run_source_command (gchar **argv)
+static gchar *run_source_command (const gchar *command)
 {
   gchar *standard_output = NULL;
   gchar *standard_error = NULL;
   gint exit_status;
   GError *e = NULL;
-  gchar *command = NULL;
   gboolean success = FALSE;
   
-  g_spawn_sync (NULL, /* Use gschem's CWD */
-		argv,
-		NULL, /* No special environment */
-		G_SPAWN_SEARCH_PATH,
-		NULL, /* No setup function (not portable anyway) */
-		NULL, /* No user data */
-		&standard_output,
-		&standard_error,
-		&exit_status,
-		&e);
-
-  command = g_strjoinv (" ", argv);
+  g_spawn_command_line_sync (command,
+                             &standard_output,
+                             &standard_error,
+                             &exit_status,
+                             &e);
 
   if (e != NULL) {
     s_log_message ("Library command failed [%s]: %s\n", command, 
@@ -423,7 +408,6 @@ static gchar *run_source_command (gchar **argv)
     success = TRUE;
   }
 
-  g_free (command);
   g_free (standard_error);
   
   if (success) return standard_output;
@@ -505,11 +489,11 @@ static void refresh_directory (CLibSource *source)
   source->symbols = NULL;  
 
   /* Open the directory for reading. */
-  dir = g_dir_open (source->path_cmd, 0, &e);
+  dir = g_dir_open (source->directory, 0, &e);
 
   if (e != NULL) {
     s_log_message ("Failed to open directory [%s]: %s\n",
-		   source->path_cmd, e->message);
+		   source->directory, e->message);
     g_error_free (e);
     return;
   }
@@ -519,7 +503,7 @@ static void refresh_directory (CLibSource *source)
     if (entry[0] == '.') continue;
 
     /* skip subdirectories (for now) */
-    fullpath = g_build_filename (source->path_cmd, entry, NULL);
+    fullpath = g_build_filename (source->directory, entry, NULL);
     isfile = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
     g_free (fullpath);
     if (!isfile) continue;
@@ -570,7 +554,6 @@ static void refresh_command (CLibSource *source)
   const gchar *line;
   CLibSymbol *symbol;
   gchar *name;
-  gchar *argv[3];
 
   g_assert (source != NULL);
   g_assert (source->type == CLIB_CMD);
@@ -581,10 +564,7 @@ static void refresh_command (CLibSource *source)
   source->symbols = NULL;  
 
   /* Run the command to get the list of symbols */
-  argv[0] = source->path_cmd;
-  argv[1] = CLIB_LIST_CMD;
-  argv[2] = NULL;
-  cmdout = run_source_command ( argv );
+  cmdout = run_source_command (source->list_cmd);
   if (cmdout == NULL) return;
 
   /* Use a TextBuffer to help reading out the lines of the output */
@@ -779,7 +759,7 @@ const CLibSource *s_clib_add_directory (const gchar *directory,
 
   source = g_new0 (CLibSource, 1);
   source->type = CLIB_DIR;
-  source->path_cmd = g_strdup (directory);
+  source->directory = g_strdup (directory);
   source->name = realname;
 
   refresh_directory (source);
@@ -790,47 +770,52 @@ const CLibSource *s_clib_add_directory (const gchar *directory,
   return source;
 }
 
-/*! \brief Add a symbol-generating command to the library
+/*! \brief Add symbol-generating commands to the library
  *  \par Function Description
- *  Adds a command which can generate symbols to the library.  See
- *  page \ref libcmds for more information on library commands.  A \a
- *  name may be specified for the source; if \a name is \b NULL, the
- *  command is used as the name.
+ *  Adds a set of commands which can generate symbols to the
+ *  library. \a list_cmd and \a get_cmd should be strings consisting
+ *  of an executable name followed by any arguments required.
+ *  Executables are resolved using the current PATH.  See page \ref
+ *  libcmds for more information on library commands.
  *  
- *  \param command The executable to run, resolved using the \b PATH
- *                 environment variable.
- *  \param name    A descriptive name for the command.
- *  \return The CLibSource associated with the command.
+ *  \param list_cmd The executable & arguments used to list available
+ *                   symbols.
+ *  \param get_cmd  The executable & arguments used to retrieve symbol
+ *                   data.
+ *  \param name      A descriptive name for the component source.
+ *  \return The CLibSource associated with the component source.
  */
-const CLibSource *s_clib_add_command (const gchar *command,
+const CLibSource *s_clib_add_command (const gchar *list_cmd,
+                                      const gchar *get_cmd,
 				      const gchar *name)
 {
   const CLibSource *oldsource;
   CLibSource *source;
-  gchar *realname;
-
-  if (command == NULL) {
-    return NULL;
-  }
-
+  
   if (name == NULL) {
-    realname = g_strdup (command);
-  } else {
-    realname = g_strdup (name);
+    s_log_message ("Cannot add library: name not specified\n");
+    return NULL;
   }
   
-  oldsource = s_clib_get_source_by_name (realname);
+  oldsource = s_clib_get_source_by_name (name);
   if (oldsource != NULL) {
     s_log_message ("Cannot add library [%s]: name in use.\n",
-		   realname);
-    g_free (realname);
+		   name);
     return NULL;
   }
 
+  if (list_cmd == NULL || get_cmd == NULL) {
+    s_log_message ("Cannot add library [%s]: both 'list' and "
+                   "'get' commands must be specified.\n",
+		   name);
+  }
+
   source = g_new0 (CLibSource, 1);
   source->type = CLIB_CMD;
-  source->path_cmd = g_strdup (command);
-  source->name = realname;
+  source->name = g_strdup(name);
+
+  source->list_cmd = g_strdup (list_cmd);
+  source->get_cmd = g_strdup (get_cmd);
 
   refresh_command (source);
 
@@ -958,7 +943,7 @@ gchar *s_clib_symbol_get_filename (const CLibSymbol *symbol)
 
   if (symbol->source->type != CLIB_DIR) return NULL;
 
-  return g_build_filename(symbol->source->path_cmd, symbol->name, NULL);
+  return g_build_filename(symbol->source->directory, symbol->name, NULL);
 }
 
 /*! \brief Get the source to which a symbol belongs.
@@ -993,7 +978,7 @@ static gchar *get_data_directory (const CLibSymbol *symbol)
   g_assert (symbol != NULL);
   g_assert (symbol->source->type == CLIB_DIR);
 
-  filename = g_build_filename(symbol->source->path_cmd, 
+  filename = g_build_filename(symbol->source->directory, 
 			      symbol->name, NULL);
 
   g_file_get_contents (filename, &data, NULL, &e);
@@ -1020,17 +1005,20 @@ static gchar *get_data_directory (const CLibSymbol *symbol)
  */
 static gchar *get_data_command (const CLibSymbol *symbol)
 {
-  gchar *argv[4];
+  gchar *command;
+  gchar *result;
 
   g_assert (symbol != NULL);
   g_assert (symbol->source->type == CLIB_CMD);
   
-  argv[0] = symbol->source->path_cmd;
-  argv[1] = CLIB_DATA_CMD;
-  argv[2] = symbol->name;
-  argv[3] = NULL;
+  command = g_strdup_printf ("%s %s", symbol->source->get_cmd, 
+                          symbol->name);
 
-  return run_source_command ( argv );
+  result = run_source_command ( command );
+
+  g_free (command);
+
+  return result;
 }
 
 /*! \brief Get symbol data from a Scheme-based component source.




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