mirror of
https://gitlab.gnome.org/GNOME/gimp.git
synced 2025-07-03 17:33:25 +00:00
app: fix core crash when a plug-in calling a GimpPdbDialog crashes.
There are 2 parts for this fix: - First expect the GimpPdbDialog to possibly disappear while gimp_pdb_dialog_run_callback() is running. This can indeed happen as this core dialog is tied to a PDB call. If the calling processus crashes (which may happen, and has to be expected for third-party plug-ins), then this dialog may just end up closing at anytime (signal "plug-in-closed" from the plug-in manager which implies a GTK_RESPONSE_CLOSE, hence dialog destruction). To account for this, we check the dialog availability with a weak pointer and returns the info to the caller as well. - Don't connect to "value-changed" on the spacing adjustment because when a crash happened, I had cases when the adjustment was finalized while being set (crash in GTK code). This one is a bit harder to explain (I had to look long at backtraces) but having a proper signal "spacing-changed" on the GimpBrushFactoryView is actually much cleaner code than relying on a public object anyway and it fixes this crash. Note: this fix is related to my previous commit. When running gimp_brush_select_new() from Python code, the plug-in crashed when trying to run the callback, which also resulted into core crash (and this part is obviously not acceptable at all).
This commit is contained in:
parent
2967ab7f82
commit
4ee3a9caa1
5 changed files with 64 additions and 30 deletions
|
@ -42,6 +42,12 @@
|
||||||
|
|
||||||
#include "gimp-intl.h"
|
#include "gimp-intl.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SPACING_CHANGED,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static void gimp_brush_factory_view_dispose (GObject *object);
|
static void gimp_brush_factory_view_dispose (GObject *object);
|
||||||
|
|
||||||
|
@ -59,6 +65,8 @@ G_DEFINE_TYPE (GimpBrushFactoryView, gimp_brush_factory_view,
|
||||||
|
|
||||||
#define parent_class gimp_brush_factory_view_parent_class
|
#define parent_class gimp_brush_factory_view_parent_class
|
||||||
|
|
||||||
|
static guint gimp_brush_factory_view_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gimp_brush_factory_view_class_init (GimpBrushFactoryViewClass *klass)
|
gimp_brush_factory_view_class_init (GimpBrushFactoryViewClass *klass)
|
||||||
|
@ -69,6 +77,20 @@ gimp_brush_factory_view_class_init (GimpBrushFactoryViewClass *klass)
|
||||||
object_class->dispose = gimp_brush_factory_view_dispose;
|
object_class->dispose = gimp_brush_factory_view_dispose;
|
||||||
|
|
||||||
editor_class->select_item = gimp_brush_factory_view_select_item;
|
editor_class->select_item = gimp_brush_factory_view_select_item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GimpBrushFactoryView::spacing-changed:
|
||||||
|
* @view: the #GimpBrushFactoryView.
|
||||||
|
*
|
||||||
|
* Emitted when the spacing changed.
|
||||||
|
*/
|
||||||
|
gimp_brush_factory_view_signals[SPACING_CHANGED] =
|
||||||
|
g_signal_new ("spacing-changed",
|
||||||
|
G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_FIRST,
|
||||||
|
G_STRUCT_OFFSET (GimpBrushFactoryViewClass, spacing_changed),
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
G_TYPE_NONE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -249,4 +271,5 @@ gimp_brush_factory_view_spacing_update (GtkAdjustment *adjustment,
|
||||||
gimp_brush_factory_view_spacing_changed,
|
gimp_brush_factory_view_spacing_changed,
|
||||||
view);
|
view);
|
||||||
}
|
}
|
||||||
|
g_signal_emit (view, gimp_brush_factory_view_signals[SPACING_CHANGED], 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,10 @@ struct _GimpBrushFactoryView
|
||||||
struct _GimpBrushFactoryViewClass
|
struct _GimpBrushFactoryViewClass
|
||||||
{
|
{
|
||||||
GimpDataFactoryViewClass parent_class;
|
GimpDataFactoryViewClass parent_class;
|
||||||
|
|
||||||
|
/* Signals */
|
||||||
|
|
||||||
|
void (* spacing_changed) (GimpBrushFactoryView *view);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -76,8 +76,8 @@ static void gimp_brush_select_mode_changed (GimpContext *context
|
||||||
|
|
||||||
static void gimp_brush_select_opacity_update (GtkAdjustment *adj,
|
static void gimp_brush_select_opacity_update (GtkAdjustment *adj,
|
||||||
GimpBrushSelect *select);
|
GimpBrushSelect *select);
|
||||||
static void gimp_brush_select_spacing_update (GtkAdjustment *adj,
|
static void gimp_brush_select_spacing_update (GimpBrushFactoryView *view,
|
||||||
GimpBrushSelect *select);
|
GimpBrushSelect *select);
|
||||||
|
|
||||||
|
|
||||||
G_DEFINE_TYPE (GimpBrushSelect, gimp_brush_select, GIMP_TYPE_PDB_DIALOG)
|
G_DEFINE_TYPE (GimpBrushSelect, gimp_brush_select, GIMP_TYPE_PDB_DIALOG)
|
||||||
|
@ -207,7 +207,7 @@ gimp_brush_select_constructed (GObject *object)
|
||||||
if (select->spacing >= 0)
|
if (select->spacing >= 0)
|
||||||
gtk_adjustment_set_value (spacing_adj, select->spacing);
|
gtk_adjustment_set_value (spacing_adj, select->spacing);
|
||||||
|
|
||||||
g_signal_connect (spacing_adj, "value-changed",
|
g_signal_connect (dialog->view, "spacing-changed",
|
||||||
G_CALLBACK (gimp_brush_select_spacing_update),
|
G_CALLBACK (gimp_brush_select_spacing_update),
|
||||||
select);
|
select);
|
||||||
}
|
}
|
||||||
|
@ -313,7 +313,7 @@ gimp_brush_select_opacity_changed (GimpContext *context,
|
||||||
gimp_brush_select_opacity_update,
|
gimp_brush_select_opacity_update,
|
||||||
select);
|
select);
|
||||||
|
|
||||||
gimp_pdb_dialog_run_callback (GIMP_PDB_DIALOG (select), FALSE);
|
gimp_pdb_dialog_run_callback ((GimpPdbDialog **) &select, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -321,7 +321,7 @@ gimp_brush_select_mode_changed (GimpContext *context,
|
||||||
GimpLayerMode paint_mode,
|
GimpLayerMode paint_mode,
|
||||||
GimpBrushSelect *select)
|
GimpBrushSelect *select)
|
||||||
{
|
{
|
||||||
gimp_pdb_dialog_run_callback (GIMP_PDB_DIALOG (select), FALSE);
|
gimp_pdb_dialog_run_callback ((GimpPdbDialog **) &select, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -333,15 +333,15 @@ gimp_brush_select_opacity_update (GtkAdjustment *adjustment,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gimp_brush_select_spacing_update (GtkAdjustment *adjustment,
|
gimp_brush_select_spacing_update (GimpBrushFactoryView *view,
|
||||||
GimpBrushSelect *select)
|
GimpBrushSelect *select)
|
||||||
{
|
{
|
||||||
gdouble value = gtk_adjustment_get_value (adjustment);
|
gdouble value = gtk_adjustment_get_value (view->spacing_adjustment);
|
||||||
|
|
||||||
if (select->spacing != value)
|
if (select->spacing != value)
|
||||||
{
|
{
|
||||||
select->spacing = value;
|
select->spacing = value;
|
||||||
|
|
||||||
gimp_pdb_dialog_run_callback (GIMP_PDB_DIALOG (select), FALSE);
|
gimp_pdb_dialog_run_callback ((GimpPdbDialog **) &select, FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,34 +244,37 @@ gimp_pdb_dialog_response (GtkDialog *gtk_dialog,
|
||||||
{
|
{
|
||||||
GimpPdbDialog *dialog = GIMP_PDB_DIALOG (gtk_dialog);
|
GimpPdbDialog *dialog = GIMP_PDB_DIALOG (gtk_dialog);
|
||||||
|
|
||||||
gimp_pdb_dialog_run_callback (dialog, TRUE);
|
gimp_pdb_dialog_run_callback (&dialog, TRUE);
|
||||||
gtk_widget_destroy (GTK_WIDGET (dialog));
|
if (dialog)
|
||||||
|
gtk_widget_destroy (GTK_WIDGET (dialog));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gimp_pdb_dialog_run_callback (GimpPdbDialog *dialog,
|
gimp_pdb_dialog_run_callback (GimpPdbDialog **dialog,
|
||||||
gboolean closing)
|
gboolean closing)
|
||||||
{
|
{
|
||||||
GimpPdbDialogClass *klass = GIMP_PDB_DIALOG_GET_CLASS (dialog);
|
GimpPdbDialogClass *klass = GIMP_PDB_DIALOG_GET_CLASS (*dialog);
|
||||||
GimpObject *object;
|
GimpObject *object;
|
||||||
|
|
||||||
object = gimp_context_get_by_type (dialog->context, dialog->select_type);
|
g_object_add_weak_pointer (G_OBJECT (*dialog), (gpointer) dialog);
|
||||||
|
object = gimp_context_get_by_type ((*dialog)->context, (*dialog)->select_type);
|
||||||
|
|
||||||
if (object &&
|
if (*dialog && object &&
|
||||||
klass->run_callback &&
|
klass->run_callback &&
|
||||||
dialog->callback_name &&
|
(*dialog)->callback_name &&
|
||||||
! dialog->callback_busy)
|
! (*dialog)->callback_busy)
|
||||||
{
|
{
|
||||||
dialog->callback_busy = TRUE;
|
(*dialog)->callback_busy = TRUE;
|
||||||
|
|
||||||
if (gimp_pdb_lookup_procedure (dialog->pdb, dialog->callback_name))
|
if (gimp_pdb_lookup_procedure ((*dialog)->pdb, (*dialog)->callback_name))
|
||||||
{
|
{
|
||||||
GimpValueArray *return_vals;
|
GimpValueArray *return_vals;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
return_vals = klass->run_callback (dialog, object, closing, &error);
|
return_vals = klass->run_callback (*dialog, object, closing, &error);
|
||||||
|
|
||||||
if (g_value_get_enum (gimp_value_array_index (return_vals, 0)) !=
|
if (*dialog &&
|
||||||
|
g_value_get_enum (gimp_value_array_index (return_vals, 0)) !=
|
||||||
GIMP_PDB_SUCCESS)
|
GIMP_PDB_SUCCESS)
|
||||||
{
|
{
|
||||||
const gchar *message;
|
const gchar *message;
|
||||||
|
@ -281,15 +284,15 @@ gimp_pdb_dialog_run_callback (GimpPdbDialog *dialog,
|
||||||
else
|
else
|
||||||
message = _("The corresponding plug-in may have crashed.");
|
message = _("The corresponding plug-in may have crashed.");
|
||||||
|
|
||||||
gimp_message (dialog->context->gimp, G_OBJECT (dialog),
|
gimp_message ((*dialog)->context->gimp, G_OBJECT (*dialog),
|
||||||
GIMP_MESSAGE_ERROR,
|
GIMP_MESSAGE_ERROR,
|
||||||
_("Unable to run %s callback.\n%s"),
|
_("Unable to run %s callback.\n%s"),
|
||||||
g_type_name (G_TYPE_FROM_INSTANCE (dialog)),
|
g_type_name (G_TYPE_FROM_INSTANCE (*dialog)),
|
||||||
message);
|
message);
|
||||||
}
|
}
|
||||||
else if (error)
|
else if (*dialog && error)
|
||||||
{
|
{
|
||||||
gimp_message_literal (dialog->context->gimp, G_OBJECT (dialog),
|
gimp_message_literal ((*dialog)->context->gimp, G_OBJECT (*dialog),
|
||||||
GIMP_MESSAGE_ERROR,
|
GIMP_MESSAGE_ERROR,
|
||||||
error->message);
|
error->message);
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
|
@ -298,8 +301,12 @@ gimp_pdb_dialog_run_callback (GimpPdbDialog *dialog,
|
||||||
gimp_value_array_unref (return_vals);
|
gimp_value_array_unref (return_vals);
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog->callback_busy = FALSE;
|
if (*dialog)
|
||||||
|
(*dialog)->callback_busy = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (*dialog)
|
||||||
|
g_object_remove_weak_pointer (G_OBJECT (*dialog), (gpointer) dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
GimpPdbDialog *
|
GimpPdbDialog *
|
||||||
|
@ -332,7 +339,7 @@ gimp_pdb_dialog_context_changed (GimpContext *context,
|
||||||
GimpPdbDialog *dialog)
|
GimpPdbDialog *dialog)
|
||||||
{
|
{
|
||||||
if (object)
|
if (object)
|
||||||
gimp_pdb_dialog_run_callback (dialog, FALSE);
|
gimp_pdb_dialog_run_callback (&dialog, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -74,7 +74,7 @@ struct _GimpPdbDialogClass
|
||||||
|
|
||||||
GType gimp_pdb_dialog_get_type (void) G_GNUC_CONST;
|
GType gimp_pdb_dialog_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
void gimp_pdb_dialog_run_callback (GimpPdbDialog *dialog,
|
void gimp_pdb_dialog_run_callback (GimpPdbDialog **dialog,
|
||||||
gboolean closing);
|
gboolean closing);
|
||||||
|
|
||||||
GimpPdbDialog * gimp_pdb_dialog_get_by_callback (GimpPdbDialogClass *klass,
|
GimpPdbDialog * gimp_pdb_dialog_get_by_callback (GimpPdbDialogClass *klass,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue