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