1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimppdbdialog.c
5 * Copyright (C) 2004 Michael Natterer <mitch@gimp.org>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <string.h>
24
25 #include <gegl.h>
26 #include <gtk/gtk.h>
27
28 #include "libgimpbase/gimpbase.h"
29 #include "libgimpwidgets/gimpwidgets.h"
30
31 #include "widgets-types.h"
32
33 #include "core/gimp.h"
34 #include "core/gimpcontext.h"
35
36 #include "pdb/gimppdb.h"
37
38 #include "gimpmenufactory.h"
39 #include "gimppdbdialog.h"
40 #include "gimpwidgets-utils.h"
41
42 #include "gimp-intl.h"
43
44
45 enum
46 {
47 PROP_0,
48 PROP_PDB,
49 PROP_CONTEXT,
50 PROP_SELECT_TYPE,
51 PROP_INITIAL_OBJECT,
52 PROP_CALLBACK_NAME,
53 PROP_MENU_FACTORY
54 };
55
56
57 static void gimp_pdb_dialog_constructed (GObject *object);
58 static void gimp_pdb_dialog_dispose (GObject *object);
59 static void gimp_pdb_dialog_set_property (GObject *object,
60 guint property_id,
61 const GValue *value,
62 GParamSpec *pspec);
63
64 static void gimp_pdb_dialog_response (GtkDialog *dialog,
65 gint response_id);
66
67 static void gimp_pdb_dialog_context_changed (GimpContext *context,
68 GimpObject *object,
69 GimpPdbDialog *dialog);
70 static void gimp_pdb_dialog_plug_in_closed (GimpPlugInManager *manager,
71 GimpPlugIn *plug_in,
72 GimpPdbDialog *dialog);
73
74
G_DEFINE_ABSTRACT_TYPE(GimpPdbDialog,gimp_pdb_dialog,GIMP_TYPE_DIALOG)75 G_DEFINE_ABSTRACT_TYPE (GimpPdbDialog, gimp_pdb_dialog, GIMP_TYPE_DIALOG)
76
77 #define parent_class gimp_pdb_dialog_parent_class
78
79
80 static void
81 gimp_pdb_dialog_class_init (GimpPdbDialogClass *klass)
82 {
83 GObjectClass *object_class = G_OBJECT_CLASS (klass);
84 GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
85
86 parent_class = g_type_class_peek_parent (klass);
87
88 object_class->constructed = gimp_pdb_dialog_constructed;
89 object_class->dispose = gimp_pdb_dialog_dispose;
90 object_class->set_property = gimp_pdb_dialog_set_property;
91
92 dialog_class->response = gimp_pdb_dialog_response;
93
94 klass->run_callback = NULL;
95
96 g_object_class_install_property (object_class, PROP_CONTEXT,
97 g_param_spec_object ("context", NULL, NULL,
98 GIMP_TYPE_CONTEXT,
99 GIMP_PARAM_WRITABLE |
100 G_PARAM_CONSTRUCT_ONLY));
101
102 g_object_class_install_property (object_class, PROP_PDB,
103 g_param_spec_object ("pdb", NULL, NULL,
104 GIMP_TYPE_PDB,
105 GIMP_PARAM_WRITABLE |
106 G_PARAM_CONSTRUCT_ONLY));
107
108 g_object_class_install_property (object_class, PROP_SELECT_TYPE,
109 g_param_spec_gtype ("select-type",
110 NULL, NULL,
111 GIMP_TYPE_OBJECT,
112 GIMP_PARAM_WRITABLE |
113 G_PARAM_CONSTRUCT_ONLY));
114
115 g_object_class_install_property (object_class, PROP_INITIAL_OBJECT,
116 g_param_spec_object ("initial-object",
117 NULL, NULL,
118 GIMP_TYPE_OBJECT,
119 GIMP_PARAM_WRITABLE |
120 G_PARAM_CONSTRUCT_ONLY));
121
122 g_object_class_install_property (object_class, PROP_CALLBACK_NAME,
123 g_param_spec_string ("callback-name",
124 NULL, NULL,
125 NULL,
126 GIMP_PARAM_WRITABLE |
127 G_PARAM_CONSTRUCT_ONLY));
128
129 g_object_class_install_property (object_class, PROP_MENU_FACTORY,
130 g_param_spec_object ("menu-factory",
131 NULL, NULL,
132 GIMP_TYPE_MENU_FACTORY,
133 GIMP_PARAM_WRITABLE |
134 G_PARAM_CONSTRUCT_ONLY));
135 }
136
137 static void
gimp_pdb_dialog_init(GimpPdbDialog * dialog)138 gimp_pdb_dialog_init (GimpPdbDialog *dialog)
139 {
140 gtk_dialog_add_button (GTK_DIALOG (dialog),
141 _("_Close"), GTK_RESPONSE_CLOSE);
142 }
143
144 static void
gimp_pdb_dialog_constructed(GObject * object)145 gimp_pdb_dialog_constructed (GObject *object)
146 {
147 GimpPdbDialog *dialog = GIMP_PDB_DIALOG (object);
148 GimpPdbDialogClass *klass = GIMP_PDB_DIALOG_GET_CLASS (object);
149 const gchar *signal_name;
150
151 G_OBJECT_CLASS (parent_class)->constructed (object);
152
153 klass->dialogs = g_list_prepend (klass->dialogs, dialog);
154
155 gimp_assert (GIMP_IS_PDB (dialog->pdb));
156 gimp_assert (GIMP_IS_CONTEXT (dialog->caller_context));
157 gimp_assert (g_type_is_a (dialog->select_type, GIMP_TYPE_OBJECT));
158
159 dialog->context = gimp_context_new (dialog->caller_context->gimp,
160 G_OBJECT_TYPE_NAME (object),
161 NULL);
162
163 gimp_context_set_by_type (dialog->context, dialog->select_type,
164 dialog->initial_object);
165
166 dialog->initial_object = NULL;
167
168 signal_name = gimp_context_type_to_signal_name (dialog->select_type);
169
170 g_signal_connect_object (dialog->context, signal_name,
171 G_CALLBACK (gimp_pdb_dialog_context_changed),
172 dialog, 0);
173 g_signal_connect_object (dialog->context->gimp->plug_in_manager,
174 "plug-in-closed",
175 G_CALLBACK (gimp_pdb_dialog_plug_in_closed),
176 dialog, 0);
177 }
178
179 static void
gimp_pdb_dialog_dispose(GObject * object)180 gimp_pdb_dialog_dispose (GObject *object)
181 {
182 GimpPdbDialog *dialog = GIMP_PDB_DIALOG (object);
183 GimpPdbDialogClass *klass = GIMP_PDB_DIALOG_GET_CLASS (object);
184
185 klass->dialogs = g_list_remove (klass->dialogs, object);
186
187 g_clear_object (&dialog->pdb);
188 g_clear_object (&dialog->caller_context);
189 g_clear_object (&dialog->context);
190
191 g_clear_pointer (&dialog->callback_name, g_free);
192
193 g_clear_object (&dialog->menu_factory);
194
195 G_OBJECT_CLASS (parent_class)->dispose (object);
196 }
197
198 static void
gimp_pdb_dialog_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)199 gimp_pdb_dialog_set_property (GObject *object,
200 guint property_id,
201 const GValue *value,
202 GParamSpec *pspec)
203 {
204 GimpPdbDialog *dialog = GIMP_PDB_DIALOG (object);
205
206 switch (property_id)
207 {
208 case PROP_PDB:
209 dialog->pdb = g_value_dup_object (value);
210 break;
211
212 case PROP_CONTEXT:
213 dialog->caller_context = g_value_dup_object (value);
214 break;
215
216 case PROP_SELECT_TYPE:
217 dialog->select_type = g_value_get_gtype (value);
218 break;
219
220 case PROP_INITIAL_OBJECT:
221 /* don't ref, see constructor */
222 dialog->initial_object = g_value_get_object (value);
223 break;
224
225 case PROP_CALLBACK_NAME:
226 if (dialog->callback_name)
227 g_free (dialog->callback_name);
228 dialog->callback_name = g_value_dup_string (value);
229 break;
230
231 case PROP_MENU_FACTORY:
232 dialog->menu_factory = g_value_dup_object (value);
233 break;
234
235 default:
236 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
237 break;
238 }
239 }
240
241 static void
gimp_pdb_dialog_response(GtkDialog * gtk_dialog,gint response_id)242 gimp_pdb_dialog_response (GtkDialog *gtk_dialog,
243 gint response_id)
244 {
245 GimpPdbDialog *dialog = GIMP_PDB_DIALOG (gtk_dialog);
246
247 gimp_pdb_dialog_run_callback (dialog, TRUE);
248 gtk_widget_destroy (GTK_WIDGET (dialog));
249 }
250
251 void
gimp_pdb_dialog_run_callback(GimpPdbDialog * dialog,gboolean closing)252 gimp_pdb_dialog_run_callback (GimpPdbDialog *dialog,
253 gboolean closing)
254 {
255 GimpPdbDialogClass *klass = GIMP_PDB_DIALOG_GET_CLASS (dialog);
256 GimpObject *object;
257
258 object = gimp_context_get_by_type (dialog->context, dialog->select_type);
259
260 if (object &&
261 klass->run_callback &&
262 dialog->callback_name &&
263 ! dialog->callback_busy)
264 {
265 dialog->callback_busy = TRUE;
266
267 if (gimp_pdb_lookup_procedure (dialog->pdb, dialog->callback_name))
268 {
269 GimpValueArray *return_vals;
270 GError *error = NULL;
271
272 return_vals = klass->run_callback (dialog, object, closing, &error);
273
274 if (g_value_get_enum (gimp_value_array_index (return_vals, 0)) !=
275 GIMP_PDB_SUCCESS)
276 {
277 const gchar *message;
278
279 if (error && error->message)
280 message = error->message;
281 else
282 message = _("The corresponding plug-in may have crashed.");
283
284 gimp_message (dialog->context->gimp, G_OBJECT (dialog),
285 GIMP_MESSAGE_ERROR,
286 _("Unable to run %s callback.\n%s"),
287 g_type_name (G_TYPE_FROM_INSTANCE (dialog)),
288 message);
289 }
290 else if (error)
291 {
292 gimp_message_literal (dialog->context->gimp, G_OBJECT (dialog),
293 GIMP_MESSAGE_ERROR,
294 error->message);
295 g_error_free (error);
296 }
297
298 gimp_value_array_unref (return_vals);
299 }
300
301 dialog->callback_busy = FALSE;
302 }
303 }
304
305 GimpPdbDialog *
gimp_pdb_dialog_get_by_callback(GimpPdbDialogClass * klass,const gchar * callback_name)306 gimp_pdb_dialog_get_by_callback (GimpPdbDialogClass *klass,
307 const gchar *callback_name)
308 {
309 GList *list;
310
311 g_return_val_if_fail (GIMP_IS_PDB_DIALOG_CLASS (klass), NULL);
312 g_return_val_if_fail (callback_name != NULL, NULL);
313
314 for (list = klass->dialogs; list; list = g_list_next (list))
315 {
316 GimpPdbDialog *dialog = list->data;
317
318 if (dialog->callback_name &&
319 ! strcmp (callback_name, dialog->callback_name))
320 return dialog;
321 }
322
323 return NULL;
324 }
325
326
327 /* private functions */
328
329 static void
gimp_pdb_dialog_context_changed(GimpContext * context,GimpObject * object,GimpPdbDialog * dialog)330 gimp_pdb_dialog_context_changed (GimpContext *context,
331 GimpObject *object,
332 GimpPdbDialog *dialog)
333 {
334 if (object)
335 gimp_pdb_dialog_run_callback (dialog, FALSE);
336 }
337
338 static void
gimp_pdb_dialog_plug_in_closed(GimpPlugInManager * manager,GimpPlugIn * plug_in,GimpPdbDialog * dialog)339 gimp_pdb_dialog_plug_in_closed (GimpPlugInManager *manager,
340 GimpPlugIn *plug_in,
341 GimpPdbDialog *dialog)
342 {
343 if (dialog->caller_context && dialog->callback_name)
344 {
345 if (! gimp_pdb_lookup_procedure (dialog->pdb, dialog->callback_name))
346 {
347 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
348 }
349 }
350 }
351