Reinstated the 'object' property for multi attrib widget in place of
the 'selection' one: the widget does not have to mess with selections,
it is only interested in objects. Moved the selection watch stuff
outside.
---
gschem/include/x_multiattrib.h | 3 -
gschem/src/x_multiattrib.c | 363 ++++++++++++++++++++--------------------
2 files changed, 181 insertions(+), 185 deletions(-)
diff --git a/gschem/include/x_multiattrib.h b/gschem/include/x_multiattrib.h
index 4190bcf..90010f0 100644
--- a/gschem/include/x_multiattrib.h
+++ b/gschem/include/x_multiattrib.h
@@ -44,7 +44,6 @@ struct _MultiattribClass {
struct _Multiattrib {
GschemDialog parent_instance;
- SELECTION *selection;
OBJECT *object;
GtkTreeView *treeview;
@@ -57,8 +56,6 @@ struct _Multiattrib {
GtkWidget *frame_add;
GdkColor value_normal_text_color; /* Workaround for lameness in
GtkTextView */
-
- gulong selection_changed_id;
};
diff --git a/gschem/src/x_multiattrib.c b/gschem/src/x_multiattrib.c
index 6519fb0..60a10ac 100644
--- a/gschem/src/x_multiattrib.c
+++ b/gschem/src/x_multiattrib.c
@@ -42,6 +42,146 @@
#include "../include/gschem_dialog.h"
#include "../include/x_multiattrib.h"
+/*! \brief Update the multiattrib editor dialog when the page's
+ * selection changes.
+ * \par Function Description
+ * When the page's selection changes this function identifies how
+ * many objects which can have attributes are currently selected. If
+ * this number is 1, the dialog is set to edit the attributes of the
+ * first selected object..
+ *
+ * \param [in] selection The SELECTION object of page being edited.
+ * \param [in] user_data The multi-attribute editor dialog.
+ */
+static void callback_selection_changed (SELECTION *selection,
+ gpointer user_data)
+{
+ Multiattrib *multiattrib = MULTIATTRIB (user_data);
+ GList *iter;
+ OBJECT *object;
+ gint object_count = 0;
+
+ for (iter = geda_list_get_glist (selection);
+ iter != NULL;
+ iter = g_list_next (iter)) {
+ object = (OBJECT *)iter->data;
+ g_assert (object != NULL);
+
+ if (object->type == OBJ_COMPLEX ||
+ object->type == OBJ_PLACEHOLDER ||
+ object->type == OBJ_NET ||
+ object->type == OBJ_BUS ||
+ object->type == OBJ_PIN) {
+ object_count++;
+ }
+ }
+
+ if (object_count == 0) {
+ /* TODO: If the user selects a single attribute which is
+ * not floating, should we find its parent object and
+ * display the multi-attribute editor for that?
+ * Bonus marks for making it jump to the correct attrib.
+ */
+ object = NULL;
+ } else if (object_count == 1) {
+ object = (OBJECT *)((geda_list_get_glist (selection))->data);
+ } else {
+ /* TODO: Something clever with multiple objects selected */
+ object = NULL;
+ }
+
+ g_object_set (multiattrib,
+ "object", object,
+ NULL);
+}
+
+#define DIALOG_DATA_SELECTION "current-selection"
+
+/*! \brief Update the dialog when the current page's SELECTION object
+ * is destroyed
+ * \par Function Description
+ * This handler is called when the g_object_weak_ref() on the
+ * SELECTION object we're watching expires. We reset our
+ * multiattrib->selection pointer to NULL to avoid attempting to
+ * access the destroyed object.
+ *
+ * \note
+ * Our signal handlers were automatically disconnected during the
+ * destruction process.
+ *
+ * \param [in] data Pointer to the multi-attrib dialog
+ * \param [in] where_the_object_was Pointer to where the object was
+ * just destroyed
+ */
+static void callback_selection_finalized (gpointer data,
+ GObject *where_the_object_was)
+{
+ Multiattrib *multiattrib = MULTIATTRIB (data);
+ g_object_set (multiattrib,
+ "object", NULL,
+ NULL);
+ g_object_set_data (G_OBJECT (multiattrib), DIALOG_DATA_SELECTION, NULL);
+}
+
+/*! \brief Add link between multiattrib dialog and current selection.
+ * \par Function Description
+ * This function connects a handler to the "changed" signal of
+ * current selection to let the dialog watch it. It also adds a weak
+ * reference on the selection.
+ *
+ * \param [in] multiattrib The Multiattrib dialog.
+ * \param [in] selection The selection to watch.
+ */
+static void connect_selection (Multiattrib *multiattrib,
+ SELECTION *selection)
+{
+ g_assert (g_object_get_data (G_OBJECT (multiattrib),
+ DIALOG_DATA_SELECTION) == NULL);
+ g_object_set_data (G_OBJECT (multiattrib), DIALOG_DATA_SELECTION, selection);
+ g_object_weak_ref (G_OBJECT (selection),
+ callback_selection_finalized,
+ multiattrib);
+ g_signal_connect (selection,
+ "changed",
+ (GCallback)callback_selection_changed,
+ multiattrib);
+ /* Synthesise a selection changed update to refresh the view */
+ callback_selection_changed (selection, multiattrib);
+}
+
+/*! \brief Remove the link between multiattrib dialog and selection.
+ * \par Function Description
+ * If the dialog is watching a selection, this function disconnects
+ * the "changed" signal and removes the weak reference it previously
+ * added on it.
+ *
+ * \param [in] multiattrib The Multiattrib dialog.
+ */
+static void disconnect_selection (Multiattrib *multiattrib) {
+ SELECTION *selection;
+
+ /* get selection watched from dialog data */
+ selection = (SELECTION*)g_object_get_data (G_OBJECT (multiattrib),
+ DIALOG_DATA_SELECTION);
+ if (selection == NULL) {
+ /* no selection watched */
+ return;
+ }
+
+ g_signal_handlers_disconnect_matched (selection,
+ G_SIGNAL_MATCH_FUNC |
+ G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL,
+ callback_selection_changed,
+ multiattrib);
+ g_object_weak_unref (G_OBJECT (selection),
+ callback_selection_finalized,
+ multiattrib);
+
+ /* reset dialog data */
+ g_object_set_data (G_OBJECT (multiattrib), DIALOG_DATA_SELECTION, NULL);
+}
+
/*! \brief Process the response returned by the multi-attribte dialog.
* \par Function Description
* This function handles the response <B>arg1</B> of the multi-attribute
@@ -61,6 +201,8 @@ multiattrib_callback_response (GtkDialog *dialog,
switch (arg1) {
case GTK_RESPONSE_CLOSE:
case GTK_RESPONSE_DELETE_EVENT:
+ /* cut link from dialog to selection */
+ disconnect_selection (MULTIATTRIB (w_current->mawindow));
gtk_widget_destroy (GTK_WIDGET (dialog));
w_current->mawindow = NULL;
break;
@@ -76,20 +218,23 @@ multiattrib_callback_response (GtkDialog *dialog,
void x_multiattrib_open (GSCHEM_TOPLEVEL *w_current)
{
if ( w_current->mawindow == NULL ) {
- w_current->mawindow = GTK_WIDGET (g_object_new (TYPE_MULTIATTRIB,
- "selection",
w_current->toplevel->page_current->selection_list,
- /* GschemDialog */
- "settings-name", "multiattrib",
- "gschem-toplevel", w_current,
- NULL));
-
- g_signal_connect (w_current->mawindow,
- "response",
- G_CALLBACK (multiattrib_callback_response),
- w_current);
+ w_current->mawindow =
+ GTK_WIDGET (g_object_new (TYPE_MULTIATTRIB,
+ "object", NULL,
+ /* GschemDialog */
+ "settings-name", "multiattrib",
+ "gschem-toplevel", w_current,
+ /* GtkWindow */
+ "transient-for", w_current->main_window,
+ NULL));
+
+ g_signal_connect (w_current->mawindow,
+ "response",
+ G_CALLBACK (multiattrib_callback_response),
+ w_current);
- gtk_window_set_transient_for (GTK_WINDOW(w_current->mawindow),
- GTK_WINDOW(w_current->main_window));
+ /* attach dialog to selection of current page */
+ x_multiattrib_update (w_current);
gtk_widget_show (w_current->mawindow);
} else {
@@ -109,12 +254,13 @@ void x_multiattrib_open (GSCHEM_TOPLEVEL *w_current)
void x_multiattrib_close (GSCHEM_TOPLEVEL *w_current)
{
if (w_current->mawindow != NULL) {
+ /* cut link from dialog to selection */
+ disconnect_selection (MULTIATTRIB (w_current->mawindow));
gtk_widget_destroy (w_current->mawindow);
w_current->mawindow = NULL;
}
}
-
/*! \brief Update the multiattrib editor dialog for a GSCHEM_TOPLEVEL.
*
* \par Function Description
@@ -126,10 +272,15 @@ void x_multiattrib_close (GSCHEM_TOPLEVEL *w_current)
*/
void x_multiattrib_update( GSCHEM_TOPLEVEL *w_current )
{
- if (w_current->mawindow != NULL) {
- g_object_set (G_OBJECT (w_current->mawindow), "selection",
- w_current->toplevel->page_current->selection_list, NULL);
+ if (!IS_MULTIATTRIB (w_current->mawindow)) {
+ return;
}
+
+ /* disconnect dialog from previous selection */
+ disconnect_selection (MULTIATTRIB (w_current->mawindow));
+ /* connect the dialog to the selection of the current page */
+ connect_selection (MULTIATTRIB (w_current->mawindow),
+ w_current->toplevel->page_current->selection_list);
}
@@ -428,7 +579,7 @@ static void
cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass
enum {
- PROP_SELECTION = 1
+ PROP_OBJECT = 1
};
enum {
@@ -1314,154 +1465,6 @@ GType multiattrib_get_type()
return multiattrib_type;
}
-
-/*! \brief Update the multiattrib editor dialog when the page's selection
changes.
- *
- * \par Function Description
- *
- * When the page's selection changes this function identifies how many objects
- * which can have attributes are currently selected. If this number is 1, the
- * dialog is set to edit its attributes.
- *
- * \todo The dialog doesn't currently support editing multiple objects at once
- *
- * \param [in] selection The SELECTION object of page being edited.
- * \param [in] multiattrib The multi-attribute editor dialog.
- */
-static void selection_changed_cb (SELECTION *selection, Multiattrib
*multiattrib)
-{
- int object_count = 0;
- GList *selection_glist;
- GList *iter;
- OBJECT *object;
-
- selection_glist = geda_list_get_glist (selection);
-
- for ( iter = selection_glist;
- iter != NULL;
- iter = g_list_next (iter) ) {
- object = (OBJECT *)iter->data;
- g_assert( object != NULL );
-
- if (object->type == OBJ_COMPLEX ||
- object->type == OBJ_PLACEHOLDER ||
- object->type == OBJ_NET ||
- object->type == OBJ_BUS ||
- object->type == OBJ_PIN) {
- object_count++;
- }
- }
-
- if (object_count == 0) {
- /* TODO: If the user selects a single attribute which is
- * not floating, should we find its parent object and
- * display the multi-attribute editor for that?
- * Bonus marks for making it jump to the correct attrib.
- */
- multiattrib->object = NULL;
- } else if (object_count == 1) {
- multiattrib->object = (OBJECT *)selection_glist->data;
- } else {
- /* TODO: Something clever with multiple objects selected */
- multiattrib->object = NULL;
- }
-
- multiattrib_update (multiattrib);
-}
-
-
-/*! \brief Update the dialog when the current page's SELECTION object is
destroyed
- *
- * \par Function Description
- *
- * This handler is called when the g_object_weak_ref() on the SELECTION object
- * we're watching expires. We reset our multiattrib->selection pointer to NULL
- * to avoid attempting to access the destroyed object. NB: Our signal handlers
- * were automatically disconnected during the destruction process.
- *
- * \param [in] data Pointer to the multi-attrib dialog
- * \param [in] where_the_object_was Pointer to where the object was just
destroyed
- */
-static void selection_weak_ref_cb (gpointer data, GObject
*where_the_object_was)
-{
- Multiattrib *multiattrib = (Multiattrib *)data;
-
- multiattrib->selection = NULL;
- multiattrib_update (multiattrib);
-}
-
-
-/*! \brief Connect signal handler and weak_ref on the SELECTION object
- *
- * \par Function Description
- *
- * Connect the "changed" signal and add a weak reference
- * on the SELECTION object we are going to watch.
- *
- * \param [in] multiattrib The Multiattrib dialog.
- * \param [in] selection The SELECTION object to watch.
- */
-static void connect_selection( Multiattrib *multiattrib, SELECTION *selection )
-{
- multiattrib->selection = selection;
- if (multiattrib->selection != NULL) {
- g_object_weak_ref (G_OBJECT (multiattrib->selection),
- selection_weak_ref_cb,
- multiattrib);
- multiattrib->selection_changed_id =
- g_signal_connect (G_OBJECT (multiattrib->selection),
- "changed",
- G_CALLBACK (selection_changed_cb),
- multiattrib);
- /* Synthesise a selection changed update to refresh the view */
- selection_changed_cb (multiattrib->selection, multiattrib);
- } else {
- /* Call an update to set the sensitivities */
- multiattrib_update (multiattrib);
- }
-}
-
-
-/*! \brief Disconnect signal handler and weak_ref on the SELECTION object
- *
- * \par Function Description
- *
- * If the dialog is watching a SELECTION object, disconnect the
- * "changed" signal and remove our weak reference on the object.
- *
- * \param [in] multiattrib The Multiattrib dialog.
- */
-static void disconnect_selection( Multiattrib *multiattrib )
-{
- if (multiattrib->selection != NULL) {
- g_signal_handler_disconnect (multiattrib->selection,
- multiattrib->selection_changed_id);
- g_object_weak_unref(G_OBJECT( multiattrib->selection ),
- selection_weak_ref_cb,
- multiattrib );
- }
-}
-
-
-/*! \brief GObject finalise handler
- *
- * \par Function Description
- *
- * Just before the Multiattrib GObject is finalized, disconnect from
- * the SELECTION object being watched and then chain up to the parent
- * class's finalize handler.
- *
- * \param [in] object The GObject being finalized.
- */
-static void multiattrib_finalize (GObject *object)
-{
- Multiattrib *multiattrib = MULTIATTRIB(object);
-
- disconnect_selection( multiattrib );
- G_OBJECT_CLASS (multiattrib_parent_class)->finalize (object);
-}
-
-
/*! \brief GType class initialiser for Multiattrib
*
* \par Function Description
@@ -1479,11 +1482,10 @@ static void multiattrib_class_init(MultiattribClass
*klass)
gobject_class->set_property = multiattrib_set_property;
gobject_class->get_property = multiattrib_get_property;
- gobject_class->finalize = multiattrib_finalize;
g_object_class_install_property (
- gobject_class, PROP_SELECTION,
- g_param_spec_pointer ("selection",
+ gobject_class, PROP_OBJECT,
+ g_param_spec_pointer ("object",
"",
"",
G_PARAM_READWRITE));
@@ -1811,7 +1813,7 @@ static void multiattrib_init(Multiattrib *multiattrib)
/*! \brief GObject property setter function
*
* \par Function Description
- * Setter function for Multiattrib's GObject property, "selection".
+ * Setter function for Multiattrib's GObject property, "object".
*
* \param [in] object The GObject whose properties we are setting
* \param [in] property_id The numeric id. under which the property was
@@ -1828,9 +1830,9 @@ static void multiattrib_set_property (GObject *object,
Multiattrib *multiattrib = MULTIATTRIB (object);
switch(property_id) {
- case PROP_SELECTION:
- disconnect_selection (multiattrib);
- connect_selection (multiattrib, g_value_get_pointer (value));
+ case PROP_OBJECT:
+ multiattrib->object = (OBJECT*)g_value_get_pointer (value);
+ multiattrib_update (multiattrib);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -1841,7 +1843,7 @@ static void multiattrib_set_property (GObject *object,
/*! \brief GObject property getter function
*
* \par Function Description
- * Getter function for Multiattrib's GObject property, "selection".
+ * Getter function for Multiattrib's GObject property, "object".
*
* \param [in] object The GObject whose properties we are getting
* \param [in] property_id The numeric id. under which the property was
@@ -1857,8 +1859,8 @@ static void multiattrib_get_property (GObject *object,
Multiattrib *multiattrib = MULTIATTRIB (object);
switch(property_id) {
- case PROP_SELECTION:
- g_value_set_pointer (value, (gpointer)multiattrib->selection);
+ case PROP_OBJECT:
+ g_value_set_pointer (value, (gpointer)multiattrib->object);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -1871,11 +1873,8 @@ static void multiattrib_get_property (GObject *object,
*
* \par Function Description
*
- * Update the dialog to reflect the attributes of the currently selected
- * object. If no (or multiple) objects are selected, the dialog's controls
- * are set insensitive.
- *
- * \todo The dialog doesn't currently support editing multiple objects at once
+ * Update the dialog to reflect the attributes of the object. If
+ * there is no object set, the dialog's controls are set insensitive.
*
* \param [in] multiattrib The multi-attribute editor dialog.
*/
@@ -1895,7 +1894,7 @@ void multiattrib_update (Multiattrib *multiattrib)
gtk_list_store_clear (liststore);
/* Update sensitivities */
- sensitive = (multiattrib->selection != NULL && multiattrib->object != NULL);
+ sensitive = (multiattrib->object != NULL);
gtk_widget_set_sensitive (GTK_WIDGET (multiattrib->frame_attributes),
sensitive);
gtk_widget_set_sensitive (GTK_WIDGET (multiattrib->frame_add), sensitive);
--
1.5.6
_______________________________________________
geda-dev mailing list
[email protected]
http://www.seul.org/cgi-bin/mailman/listinfo/geda-dev