From 4aaaa1a7fa9d5f80121f07a01adb79d41ab77684 Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Mon, 8 Oct 2012 22:01:30 +0200 Subject: [PATCH] Bug 378334 - Plugins with image drop-list crash when image is closed Let image and item combo boxes connect to their own "changed" signal first, and if the chosen image/item doesn't exist any longer, reinitialize the combo box and select the first item instead. Also fixes the type macros in gimpitemcombobox.h which were lacking a ')' and introduces an internal GimpItemComboBox class to hold the common functionality. --- libgimp/gimpimagecombobox.c | 62 ++++++++-- libgimp/gimpitemcombobox.c | 227 +++++++++++++++++++++--------------- libgimp/gimpitemcombobox.h | 8 +- 3 files changed, 187 insertions(+), 110 deletions(-) diff --git a/libgimp/gimpimagecombobox.c b/libgimp/gimpimagecombobox.c index 55533c74d4..d723d84a1f 100644 --- a/libgimp/gimpimagecombobox.c +++ b/libgimp/gimpimagecombobox.c @@ -51,7 +51,10 @@ typedef struct _GimpImageComboBoxClass GimpImageComboBoxClass; struct _GimpImageComboBox { - GimpIntComboBox parent_instance; + GimpIntComboBox parent_instance; + + GimpImageConstraintFunc constraint; + gpointer data; }; struct _GimpImageComboBoxClass @@ -60,6 +63,7 @@ struct _GimpImageComboBoxClass }; +static void gimp_image_combo_box_populate (GimpImageComboBox *combo_box); static void gimp_image_combo_box_model_add (GtkListStore *store, gint num_images, gint32 *images, @@ -74,6 +78,8 @@ static void gimp_image_combo_box_drag_data_received (GtkWidget *widget, guint info, guint time); +static void gimp_image_combo_box_changed (GimpImageComboBox *combo_box); + static const GtkTargetEntry target = { "application/x-gimp-image-id", 0 }; @@ -123,30 +129,46 @@ GtkWidget * gimp_image_combo_box_new (GimpImageConstraintFunc constraint, gpointer data) { - GtkWidget *combo_box; - GtkTreeModel *model; - GtkTreeIter iter; - gint32 *images; - gint num_images; + GimpImageComboBox *combo_box; combo_box = g_object_new (GIMP_TYPE_IMAGE_COMBO_BOX, "width-request", WIDTH_REQUEST, "ellipsize", PANGO_ELLIPSIZE_MIDDLE, NULL); + combo_box->constraint = constraint; + combo_box->data = data; + + gimp_image_combo_box_populate (combo_box); + + g_signal_connect (combo_box, "changed", + G_CALLBACK (gimp_image_combo_box_changed), + NULL); + + return GTK_WIDGET (combo_box); +} + +static void +gimp_image_combo_box_populate (GimpImageComboBox *combo_box) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gint32 *images; + gint num_images; + model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)); images = gimp_image_list (&num_images); gimp_image_combo_box_model_add (GTK_LIST_STORE (model), num_images, images, - constraint, data); + combo_box->constraint, + combo_box->data); + g_free (images); if (gtk_tree_model_get_iter_first (model, &iter)) gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter); - - return combo_box; } static void @@ -225,3 +247,25 @@ gimp_image_combo_box_drag_data_received (GtkWidget *widget, g_free (str); } + +static void +gimp_image_combo_box_changed (GimpImageComboBox *combo_box) +{ + gint image_ID; + + if (gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (combo_box), + &image_ID)) + { + if (! gimp_image_is_valid (image_ID)) + { + GtkTreeModel *model; + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)); + + g_signal_stop_emission_by_name (combo_box, "changed"); + + gtk_list_store_clear (GTK_LIST_STORE (model)); + gimp_image_combo_box_populate (combo_box); + } + } +} diff --git a/libgimp/gimpitemcombobox.c b/libgimp/gimpitemcombobox.c index 39b98d0037..762e0bedab 100644 --- a/libgimp/gimpitemcombobox.c +++ b/libgimp/gimpitemcombobox.c @@ -49,73 +49,86 @@ #define THUMBNAIL_SIZE 24 #define WIDTH_REQUEST 200 -typedef enum -{ - DRAWABLE_COMBO_BOX, - CHANNEL_COMBO_BOX, - LAYER_COMBO_BOX, - VECTORS_COMBO_BOX -} GimpComboBoxType; +#define GIMP_TYPE_ITEM_COMBO_BOX (gimp_item_combo_box_get_type ()) +#define GIMP_ITEM_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_ITEM_COMBO_BOX, GimpItemComboBox)) +#define GIMP_IS_ITEM_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_ITEM_COMBO_BOX)) +GType gimp_item_combo_box_get_type (void) G_GNUC_CONST; + +typedef struct _GimpItemComboBox GimpItemComboBox; + +typedef struct _GimpItemComboBoxClass GimpItemComboBoxClass; typedef struct _GimpDrawableComboBoxClass GimpDrawableComboBoxClass; typedef struct _GimpChannelComboBoxClass GimpChannelComboBoxClass; typedef struct _GimpLayerComboBoxClass GimpLayerComboBoxClass; typedef struct _GimpVectorsComboBoxClass GimpVectorsComboBoxClass; +struct _GimpItemComboBox +{ + GimpIntComboBox parent_instance; + + GimpItemConstraintFunc constraint; + gpointer data; +}; + +struct _GimpItemComboBoxClass +{ + GimpIntComboBoxClass parent_class; +}; + struct _GimpDrawableComboBox { - GimpIntComboBox parent_instance; + GimpItemComboBox parent_instance; }; struct _GimpDrawableComboBoxClass { - GimpIntComboBoxClass parent_class; + GimpItemComboBoxClass parent_class; }; struct _GimpChannelComboBox { - GimpIntComboBox parent_instance; + GimpItemComboBox parent_instance; }; struct _GimpChannelComboBoxClass { - GimpIntComboBoxClass parent_class; + GimpItemComboBoxClass parent_class; }; struct _GimpLayerComboBox { - GimpIntComboBox parent_instance; + GimpItemComboBox parent_instance; }; struct _GimpLayerComboBoxClass { - GimpIntComboBoxClass parent_class; + GimpItemComboBoxClass parent_class; }; struct _GimpVectorsComboBox { - GimpIntComboBox parent_instance; + GimpItemComboBox parent_instance; }; struct _GimpVectorsComboBoxClass { - GimpIntComboBoxClass parent_class; + GimpItemComboBoxClass parent_class; }; -static GtkWidget * gimp_item_combo_box_new (GimpComboBoxType type, +static GtkWidget * gimp_item_combo_box_new (GType type, GimpItemConstraintFunc constraint, gpointer data); -static void gimp_item_combo_box_model_add (GtkListStore *store, +static void gimp_item_combo_box_populate (GimpItemComboBox *combo_box); +static void gimp_item_combo_box_model_add (GimpItemComboBox *combo_box, + GtkListStore *store, gint32 image, gint num_items, gint32 *items, - gint tree_level, - GimpComboBoxType type, - GimpItemConstraintFunc constraint, - gpointer data); + gint tree_level); static void gimp_item_combo_box_drag_data_received (GtkWidget *widget, GdkDragContext *context, @@ -125,6 +138,8 @@ static void gimp_item_combo_box_drag_data_received (GtkWidget *widget, guint info, guint time); +static void gimp_item_combo_box_changed (GimpItemComboBox *combo_box); + static const GtkTargetEntry targets[] = { @@ -134,18 +149,31 @@ static const GtkTargetEntry targets[] = }; -G_DEFINE_TYPE (GimpDrawableComboBox, gimp_drawable_combo_box, +G_DEFINE_TYPE (GimpItemComboBox, gimp_item_combo_box, GIMP_TYPE_INT_COMBO_BOX) - static void -gimp_drawable_combo_box_class_init (GimpDrawableComboBoxClass *klass) +gimp_item_combo_box_class_init (GimpItemComboBoxClass *klass) { GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); widget_class->drag_data_received = gimp_item_combo_box_drag_data_received; } +static void +gimp_item_combo_box_init (GimpItemComboBox *combo_box) +{ +} + + +G_DEFINE_TYPE (GimpDrawableComboBox, gimp_drawable_combo_box, + GIMP_TYPE_ITEM_COMBO_BOX) + +static void +gimp_drawable_combo_box_class_init (GimpDrawableComboBoxClass *klass) +{ +} + static void gimp_drawable_combo_box_init (GimpDrawableComboBox *combo_box) { @@ -180,22 +208,17 @@ GtkWidget * gimp_drawable_combo_box_new (GimpDrawableConstraintFunc constraint, gpointer data) { - return gimp_item_combo_box_new (DRAWABLE_COMBO_BOX, constraint, data); + return gimp_item_combo_box_new (GIMP_TYPE_DRAWABLE_COMBO_BOX, + constraint, data); } -G_DEFINE_TYPE(GimpChannelComboBox, - gimp_channel_combo_box, - GIMP_TYPE_INT_COMBO_BOX); +G_DEFINE_TYPE (GimpChannelComboBox, gimp_channel_combo_box, + GIMP_TYPE_ITEM_COMBO_BOX) static void gimp_channel_combo_box_class_init (GimpChannelComboBoxClass *klass) { - GtkWidgetClass *widget_class; - - widget_class = GTK_WIDGET_CLASS (klass); - - widget_class->drag_data_received = gimp_item_combo_box_drag_data_received; } static void @@ -225,20 +248,17 @@ GtkWidget * gimp_channel_combo_box_new (GimpDrawableConstraintFunc constraint, gpointer data) { - return gimp_item_combo_box_new (CHANNEL_COMBO_BOX, constraint, data); + return gimp_item_combo_box_new (GIMP_TYPE_CHANNEL_COMBO_BOX, + constraint, data); } -G_DEFINE_TYPE(GimpLayerComboBox, - gimp_layer_combo_box, - GIMP_TYPE_INT_COMBO_BOX); +G_DEFINE_TYPE (GimpLayerComboBox, gimp_layer_combo_box, + GIMP_TYPE_ITEM_COMBO_BOX) static void gimp_layer_combo_box_class_init (GimpLayerComboBoxClass *klass) { - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - widget_class->drag_data_received = gimp_item_combo_box_drag_data_received; } static void @@ -268,19 +288,17 @@ GtkWidget * gimp_layer_combo_box_new (GimpDrawableConstraintFunc constraint, gpointer data) { - return gimp_item_combo_box_new (LAYER_COMBO_BOX, constraint, data); + return gimp_item_combo_box_new (GIMP_TYPE_LAYER_COMBO_BOX, + constraint, data); } G_DEFINE_TYPE (GimpVectorsComboBox, gimp_vectors_combo_box, - GIMP_TYPE_INT_COMBO_BOX) + GIMP_TYPE_ITEM_COMBO_BOX) static void gimp_vectors_combo_box_class_init (GimpVectorsComboBoxClass *klass) { - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - widget_class->drag_data_received = gimp_item_combo_box_drag_data_received; } static void @@ -294,6 +312,7 @@ gimp_vectors_combo_box_init (GimpVectorsComboBox *combo_box) GDK_ACTION_COPY); } + /** * gimp_vectors_combo_box_new: * @constraint: a #GimpVectorsConstraintFunc or %NULL @@ -317,44 +336,44 @@ GtkWidget * gimp_vectors_combo_box_new (GimpVectorsConstraintFunc constraint, gpointer data) { - return gimp_item_combo_box_new (VECTORS_COMBO_BOX, constraint, data); + return gimp_item_combo_box_new (GIMP_TYPE_VECTORS_COMBO_BOX, + constraint, data); } static GtkWidget * -gimp_item_combo_box_new (GimpComboBoxType type, +gimp_item_combo_box_new (GType type, GimpItemConstraintFunc constraint, gpointer data) { - GType combo_box_type = G_TYPE_NONE; - GtkWidget *combo_box; + GimpItemComboBox *combo_box; + + combo_box = g_object_new (type, + "width-request", WIDTH_REQUEST, + "ellipsize", PANGO_ELLIPSIZE_MIDDLE, + NULL); + + combo_box->constraint = constraint; + combo_box->data = data; + + gimp_item_combo_box_populate (combo_box); + + g_signal_connect (combo_box, "changed", + G_CALLBACK (gimp_item_combo_box_changed), + NULL); + + return GTK_WIDGET (combo_box); +} + +static void +gimp_item_combo_box_populate (GimpItemComboBox *combo_box) +{ GtkTreeModel *model; GtkTreeIter iter; gint32 *images; gint num_images; gint i; - switch (type) - { - case DRAWABLE_COMBO_BOX: - combo_box_type = GIMP_TYPE_DRAWABLE_COMBO_BOX; - break; - case CHANNEL_COMBO_BOX: - combo_box_type = GIMP_TYPE_CHANNEL_COMBO_BOX; - break; - case LAYER_COMBO_BOX: - combo_box_type = GIMP_TYPE_LAYER_COMBO_BOX; - break; - case VECTORS_COMBO_BOX: - combo_box_type = GIMP_TYPE_VECTORS_COMBO_BOX; - break; - } - - combo_box = g_object_new (combo_box_type, - "width-request", WIDTH_REQUEST, - "ellipsize", PANGO_ELLIPSIZE_MIDDLE, - NULL); - model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)); images = gimp_image_list (&num_images); @@ -364,35 +383,32 @@ gimp_item_combo_box_new (GimpComboBoxType type, gint32 *items; gint num_items; - if (type == DRAWABLE_COMBO_BOX || - type == LAYER_COMBO_BOX) + if (GIMP_IS_DRAWABLE_COMBO_BOX (combo_box) || + GIMP_IS_LAYER_COMBO_BOX (combo_box)) { items = gimp_image_get_layers (images[i], &num_items); - gimp_item_combo_box_model_add (GTK_LIST_STORE (model), + gimp_item_combo_box_model_add (combo_box, GTK_LIST_STORE (model), images[i], - num_items, items, 0, type, - constraint, data); + num_items, items, 0); g_free (items); } - if (type == DRAWABLE_COMBO_BOX || - type == CHANNEL_COMBO_BOX) + if (GIMP_IS_DRAWABLE_COMBO_BOX (combo_box) || + GIMP_IS_CHANNEL_COMBO_BOX (combo_box)) { items = gimp_image_get_channels (images[i], &num_items); - gimp_item_combo_box_model_add (GTK_LIST_STORE (model), + gimp_item_combo_box_model_add (combo_box, GTK_LIST_STORE (model), images[i], - num_items, items, 0, type, - constraint, data); + num_items, items, 0); g_free (items); } - if (type == VECTORS_COMBO_BOX) + if (GIMP_IS_VECTORS_COMBO_BOX (combo_box)) { items = gimp_image_get_vectors (images[i], &num_items); - gimp_item_combo_box_model_add (GTK_LIST_STORE (model), + gimp_item_combo_box_model_add (combo_box, GTK_LIST_STORE (model), images[i], - num_items, items, 0, type, - constraint, data); + num_items, items, 0); g_free (items); } } @@ -401,20 +417,15 @@ gimp_item_combo_box_new (GimpComboBoxType type, if (gtk_tree_model_get_iter_first (model, &iter)) gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter); - - return combo_box; } - static void -gimp_item_combo_box_model_add (GtkListStore *store, +gimp_item_combo_box_model_add (GimpItemComboBox *combo_box, + GtkListStore *store, gint32 image, gint num_items, gint32 *items, - gint tree_level, - GimpComboBoxType type, - GimpItemConstraintFunc constraint, - gpointer data) + gint tree_level) { GtkTreeIter iter; gint i; @@ -434,7 +445,8 @@ gimp_item_combo_box_model_add (GtkListStore *store, for (i = 0; i < num_items; i++) { - if (! constraint || (* constraint) (image, items[i], data)) + if (! combo_box->constraint || + (* combo_box->constraint) (image, items[i], combo_box->data)) { gchar *image_name = gimp_image_get_name (image); gchar *item_name = gimp_item_get_name (items[i]); @@ -448,7 +460,7 @@ gimp_item_combo_box_model_add (GtkListStore *store, g_free (item_name); g_free (image_name); - if (type == VECTORS_COMBO_BOX) + if (GIMP_IS_VECTORS_COMBO_BOX (combo_box)) thumb = NULL; else thumb = gimp_drawable_get_thumbnail (items[i], @@ -473,11 +485,10 @@ gimp_item_combo_box_model_add (GtkListStore *store, gint n_children; children = gimp_item_get_children (items[i], &n_children); - gimp_item_combo_box_model_add (store, + gimp_item_combo_box_model_add (combo_box, store, image, n_children, children, - tree_level + 1, type, - constraint, data); + tree_level + 1); g_free (children); } } @@ -521,3 +532,25 @@ gimp_item_combo_box_drag_data_received (GtkWidget *widget, g_free (str); } + +static void +gimp_item_combo_box_changed (GimpItemComboBox *combo_box) +{ + gint item_ID; + + if (gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (combo_box), + &item_ID)) + { + if (! gimp_item_is_valid (item_ID)) + { + GtkTreeModel *model; + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)); + + g_signal_stop_emission_by_name (combo_box, "changed"); + + gtk_list_store_clear (GTK_LIST_STORE (model)); + gimp_item_combo_box_populate (combo_box); + } + } +} diff --git a/libgimp/gimpitemcombobox.h b/libgimp/gimpitemcombobox.h index d0d58feb5d..91760ae067 100644 --- a/libgimp/gimpitemcombobox.h +++ b/libgimp/gimpitemcombobox.h @@ -34,19 +34,19 @@ G_BEGIN_DECLS #define GIMP_TYPE_DRAWABLE_COMBO_BOX (gimp_drawable_combo_box_get_type ()) #define GIMP_DRAWABLE_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_DRAWABLE_COMBO_BOX, GimpDrawableComboBox)) -#define GIMP_IS_DRAWABLE_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_DRAWABLE_COMBO_BOX) +#define GIMP_IS_DRAWABLE_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_DRAWABLE_COMBO_BOX)) #define GIMP_TYPE_CHANNEL_COMBO_BOX (gimp_channel_combo_box_get_type ()) #define GIMP_CHANNEL_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_CHANNEL_COMBO_BOX, GimpChannelComboBox)) -#define GIMP_IS_CHANNEL_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_CHANNEL_COMBO_BOX) +#define GIMP_IS_CHANNEL_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_CHANNEL_COMBO_BOX)) #define GIMP_TYPE_LAYER_COMBO_BOX (gimp_layer_combo_box_get_type ()) #define GIMP_LAYER_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_LAYER_COMBO_BOX, GimpLayerComboBox)) -#define GIMP_IS_LAYER_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_LAYER_COMBO_BOX) +#define GIMP_IS_LAYER_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_LAYER_COMBO_BOX)) #define GIMP_TYPE_VECTORS_COMBO_BOX (gimp_vectors_combo_box_get_type ()) #define GIMP_VECTORS_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_VECTORS_COMBO_BOX, GimpVectorsComboBox)) -#define GIMP_IS_VECTORS_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_VECTORS_COMBO_BOX) +#define GIMP_IS_VECTORS_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_VECTORS_COMBO_BOX)) typedef gboolean (* GimpItemConstraintFunc) (gint32 image_id,