1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <stdarg.h>
21 #include <string.h>
22 #include <sys/types.h>
23 
24 #include <gobject/gvaluecollector.h>
25 #include <gdk-pixbuf/gdk-pixbuf.h>
26 #include <gegl.h>
27 
28 #include "libgimpbase/gimpbase.h"
29 
30 #include "pdb-types.h"
31 
32 #include "core/gimp.h"
33 #include "core/gimp-memsize.h"
34 #include "core/gimpcontext.h"
35 #include "core/gimpmarshal.h"
36 #include "core/gimpprogress.h"
37 
38 #include "gimppdb.h"
39 #include "gimppdberror.h"
40 #include "gimpprocedure.h"
41 
42 #include "gimp-intl.h"
43 
44 
45 enum
46 {
47   REGISTER_PROCEDURE,
48   UNREGISTER_PROCEDURE,
49   LAST_SIGNAL
50 };
51 
52 
53 static void     gimp_pdb_finalize                  (GObject       *object);
54 static gint64   gimp_pdb_get_memsize               (GimpObject    *object,
55                                                     gint64        *gui_size);
56 static void     gimp_pdb_real_register_procedure   (GimpPDB       *pdb,
57                                                     GimpProcedure *procedure);
58 static void     gimp_pdb_real_unregister_procedure (GimpPDB       *pdb,
59                                                     GimpProcedure *procedure);
60 static void     gimp_pdb_entry_free                (gpointer       key,
61                                                     gpointer       value,
62                                                     gpointer       user_data);
63 static gint64   gimp_pdb_entry_get_memsize         (GList         *procedures,
64                                                     gint64        *gui_size);
65 
66 
67 G_DEFINE_TYPE (GimpPDB, gimp_pdb, GIMP_TYPE_OBJECT)
68 
69 #define parent_class gimp_pdb_parent_class
70 
71 static guint gimp_pdb_signals[LAST_SIGNAL] = { 0 };
72 
73 
74 static void
gimp_pdb_class_init(GimpPDBClass * klass)75 gimp_pdb_class_init (GimpPDBClass *klass)
76 {
77   GObjectClass    *object_class      = G_OBJECT_CLASS (klass);
78   GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
79 
80   gimp_pdb_signals[REGISTER_PROCEDURE] =
81     g_signal_new ("register-procedure",
82                   G_TYPE_FROM_CLASS (klass),
83                   G_SIGNAL_RUN_FIRST,
84                   G_STRUCT_OFFSET (GimpPDBClass, register_procedure),
85                   NULL, NULL,
86                   gimp_marshal_VOID__OBJECT,
87                   G_TYPE_NONE, 1,
88                   GIMP_TYPE_PROCEDURE);
89 
90   gimp_pdb_signals[UNREGISTER_PROCEDURE] =
91     g_signal_new ("unregister-procedure",
92                   G_TYPE_FROM_CLASS (klass),
93                   G_SIGNAL_RUN_FIRST,
94                   G_STRUCT_OFFSET (GimpPDBClass, unregister_procedure),
95                   NULL, NULL,
96                   gimp_marshal_VOID__OBJECT,
97                   G_TYPE_NONE, 1,
98                   GIMP_TYPE_PROCEDURE);
99 
100   object_class->finalize         = gimp_pdb_finalize;
101 
102   gimp_object_class->get_memsize = gimp_pdb_get_memsize;
103 
104   klass->register_procedure      = gimp_pdb_real_register_procedure;
105   klass->unregister_procedure    = gimp_pdb_real_unregister_procedure;
106 }
107 
108 static void
gimp_pdb_init(GimpPDB * pdb)109 gimp_pdb_init (GimpPDB *pdb)
110 {
111   pdb->procedures        = g_hash_table_new (g_str_hash, g_str_equal);
112   pdb->compat_proc_names = g_hash_table_new (g_str_hash, g_str_equal);
113 }
114 
115 static void
gimp_pdb_finalize(GObject * object)116 gimp_pdb_finalize (GObject *object)
117 {
118   GimpPDB *pdb = GIMP_PDB (object);
119 
120   if (pdb->procedures)
121     {
122       g_hash_table_foreach (pdb->procedures, gimp_pdb_entry_free, NULL);
123       g_hash_table_destroy (pdb->procedures);
124       pdb->procedures = NULL;
125     }
126 
127   if (pdb->compat_proc_names)
128     {
129       g_hash_table_destroy (pdb->compat_proc_names);
130       pdb->compat_proc_names = NULL;
131     }
132 
133   G_OBJECT_CLASS (parent_class)->finalize (object);
134 }
135 
136 static gint64
gimp_pdb_get_memsize(GimpObject * object,gint64 * gui_size)137 gimp_pdb_get_memsize (GimpObject *object,
138                       gint64     *gui_size)
139 {
140   GimpPDB *pdb     = GIMP_PDB (object);
141   gint64   memsize = 0;
142 
143   memsize += gimp_g_hash_table_get_memsize_foreach (pdb->procedures,
144                                                     (GimpMemsizeFunc)
145                                                     gimp_pdb_entry_get_memsize,
146                                                     gui_size);
147   memsize += gimp_g_hash_table_get_memsize (pdb->compat_proc_names, 0);
148 
149   return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
150                                                                   gui_size);
151 }
152 
153 static void
gimp_pdb_real_register_procedure(GimpPDB * pdb,GimpProcedure * procedure)154 gimp_pdb_real_register_procedure (GimpPDB       *pdb,
155                                   GimpProcedure *procedure)
156 {
157   const gchar *name;
158   GList       *list;
159 
160   name = gimp_object_get_name (procedure);
161 
162   list = g_hash_table_lookup (pdb->procedures, name);
163 
164   g_hash_table_replace (pdb->procedures, (gpointer) name,
165                         g_list_prepend (list, g_object_ref (procedure)));
166 }
167 
168 static void
gimp_pdb_real_unregister_procedure(GimpPDB * pdb,GimpProcedure * procedure)169 gimp_pdb_real_unregister_procedure (GimpPDB       *pdb,
170                                     GimpProcedure *procedure)
171 {
172   const gchar *name;
173   GList       *list;
174 
175   name = gimp_object_get_name (procedure);
176 
177   list = g_hash_table_lookup (pdb->procedures, name);
178 
179   if (list)
180     {
181       list = g_list_remove (list, procedure);
182 
183       if (list)
184         {
185           name = gimp_object_get_name (list->data);
186           g_hash_table_replace (pdb->procedures, (gpointer) name, list);
187         }
188       else
189         {
190           g_hash_table_remove (pdb->procedures, name);
191         }
192 
193       g_object_unref (procedure);
194     }
195 }
196 
197 
198 /*  public functions  */
199 
200 GimpPDB *
gimp_pdb_new(Gimp * gimp)201 gimp_pdb_new (Gimp *gimp)
202 {
203   GimpPDB *pdb;
204 
205   g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
206 
207   pdb = g_object_new (GIMP_TYPE_PDB,
208                       "name", "pdb",
209                       NULL);
210 
211   pdb->gimp = gimp;
212 
213   return pdb;
214 }
215 
216 void
gimp_pdb_register_procedure(GimpPDB * pdb,GimpProcedure * procedure)217 gimp_pdb_register_procedure (GimpPDB       *pdb,
218                              GimpProcedure *procedure)
219 {
220   g_return_if_fail (GIMP_IS_PDB (pdb));
221   g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
222 
223   if (! procedure->deprecated ||
224       pdb->gimp->pdb_compat_mode != GIMP_PDB_COMPAT_OFF)
225     {
226       g_signal_emit (pdb, gimp_pdb_signals[REGISTER_PROCEDURE], 0,
227                      procedure);
228     }
229 }
230 
231 void
gimp_pdb_unregister_procedure(GimpPDB * pdb,GimpProcedure * procedure)232 gimp_pdb_unregister_procedure (GimpPDB       *pdb,
233                                GimpProcedure *procedure)
234 {
235   g_return_if_fail (GIMP_IS_PDB (pdb));
236   g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
237 
238   g_signal_emit (pdb, gimp_pdb_signals[UNREGISTER_PROCEDURE], 0,
239                  procedure);
240 }
241 
242 GimpProcedure *
gimp_pdb_lookup_procedure(GimpPDB * pdb,const gchar * name)243 gimp_pdb_lookup_procedure (GimpPDB     *pdb,
244                            const gchar *name)
245 {
246   GList *list;
247 
248   g_return_val_if_fail (GIMP_IS_PDB (pdb), NULL);
249   g_return_val_if_fail (name != NULL, NULL);
250 
251   list = g_hash_table_lookup (pdb->procedures, name);
252 
253   if (list)
254     return list->data;
255 
256   return NULL;
257 }
258 
259 void
gimp_pdb_register_compat_proc_name(GimpPDB * pdb,const gchar * old_name,const gchar * new_name)260 gimp_pdb_register_compat_proc_name (GimpPDB     *pdb,
261                                     const gchar *old_name,
262                                     const gchar *new_name)
263 {
264   g_return_if_fail (GIMP_IS_PDB (pdb));
265   g_return_if_fail (old_name != NULL);
266   g_return_if_fail (new_name != NULL);
267 
268   g_hash_table_insert (pdb->compat_proc_names,
269                        (gpointer) old_name,
270                        (gpointer) new_name);
271 }
272 
273 const gchar *
gimp_pdb_lookup_compat_proc_name(GimpPDB * pdb,const gchar * old_name)274 gimp_pdb_lookup_compat_proc_name (GimpPDB     *pdb,
275                                   const gchar *old_name)
276 {
277   g_return_val_if_fail (GIMP_IS_PDB (pdb), NULL);
278   g_return_val_if_fail (old_name != NULL, NULL);
279 
280   return g_hash_table_lookup (pdb->compat_proc_names, old_name);
281 }
282 
283 GimpValueArray *
gimp_pdb_execute_procedure_by_name_args(GimpPDB * pdb,GimpContext * context,GimpProgress * progress,GError ** error,const gchar * name,GimpValueArray * args)284 gimp_pdb_execute_procedure_by_name_args (GimpPDB         *pdb,
285                                          GimpContext     *context,
286                                          GimpProgress    *progress,
287                                          GError         **error,
288                                          const gchar     *name,
289                                          GimpValueArray  *args)
290 {
291   GimpValueArray *return_vals = NULL;
292   GList          *list;
293 
294   g_return_val_if_fail (GIMP_IS_PDB (pdb), NULL);
295   g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
296   g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
297   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
298   g_return_val_if_fail (name != NULL, NULL);
299 
300   list = g_hash_table_lookup (pdb->procedures, name);
301 
302   if (list == NULL)
303     {
304       GError *pdb_error = g_error_new (GIMP_PDB_ERROR,
305                                        GIMP_PDB_ERROR_PROCEDURE_NOT_FOUND,
306                                        _("Procedure '%s' not found"), name);
307 
308       return_vals = gimp_procedure_get_return_values (NULL, FALSE, pdb_error);
309       g_propagate_error (error, pdb_error);
310 
311       return return_vals;
312     }
313 
314   g_return_val_if_fail (args != NULL, NULL);
315 
316   for (; list; list = g_list_next (list))
317     {
318       GimpProcedure *procedure = list->data;
319 
320       g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
321 
322       return_vals = gimp_procedure_execute (procedure,
323                                             pdb->gimp, context, progress,
324                                             args, error);
325 
326       if (g_value_get_enum (gimp_value_array_index (return_vals, 0)) ==
327           GIMP_PDB_PASS_THROUGH)
328         {
329           /*  If the return value is GIMP_PDB_PASS_THROUGH and there is
330            *  a next procedure in the list, destroy the return values
331            *  and run the next procedure.
332            */
333           if (g_list_next (list))
334             {
335               gimp_value_array_unref (return_vals);
336               g_clear_error (error);
337             }
338         }
339       else
340         {
341           /*  No GIMP_PDB_PASS_THROUGH, break out of the list of
342            *  procedures and return the current return values.
343            */
344           break;
345         }
346     }
347 
348   return return_vals;
349 }
350 
351 GimpValueArray *
gimp_pdb_execute_procedure_by_name(GimpPDB * pdb,GimpContext * context,GimpProgress * progress,GError ** error,const gchar * name,...)352 gimp_pdb_execute_procedure_by_name (GimpPDB       *pdb,
353                                     GimpContext   *context,
354                                     GimpProgress  *progress,
355                                     GError       **error,
356                                     const gchar   *name,
357                                     ...)
358 {
359   GimpProcedure  *procedure;
360   GimpValueArray *args;
361   GimpValueArray *return_vals;
362   va_list         va_args;
363   gint            i;
364 
365   g_return_val_if_fail (GIMP_IS_PDB (pdb), NULL);
366   g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
367   g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
368   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
369   g_return_val_if_fail (name != NULL, NULL);
370 
371   procedure = gimp_pdb_lookup_procedure (pdb, name);
372 
373   if (! procedure)
374     {
375       GError *pdb_error = g_error_new (GIMP_PDB_ERROR,
376                                        GIMP_PDB_ERROR_PROCEDURE_NOT_FOUND,
377                                        _("Procedure '%s' not found"), name);
378 
379       return_vals = gimp_procedure_get_return_values (NULL, FALSE, pdb_error);
380       g_propagate_error (error, pdb_error);
381 
382       return return_vals;
383     }
384 
385   args = gimp_procedure_get_arguments (procedure);
386 
387   va_start (va_args, name);
388 
389   for (i = 0; i < procedure->num_args; i++)
390     {
391       GValue *value;
392       GType   arg_type;
393       gchar  *error_msg = NULL;
394 
395       arg_type = va_arg (va_args, GType);
396 
397       if (arg_type == G_TYPE_NONE)
398         break;
399 
400       value = gimp_value_array_index (args, i);
401 
402       if (arg_type != G_VALUE_TYPE (value))
403         {
404           GError      *pdb_error;
405           const gchar *expected = g_type_name (G_VALUE_TYPE (value));
406           const gchar *got      = g_type_name (arg_type);
407 
408           gimp_value_array_unref (args);
409 
410           pdb_error = g_error_new (GIMP_PDB_ERROR,
411                                    GIMP_PDB_ERROR_INVALID_ARGUMENT,
412                                    _("Procedure '%s' has been called with a "
413                                      "wrong type for argument #%d. "
414                                      "Expected %s, got %s."),
415                                    gimp_object_get_name (procedure),
416                                    i + 1, expected, got);
417 
418           return_vals = gimp_procedure_get_return_values (procedure,
419                                                           FALSE, pdb_error);
420           g_propagate_error (error, pdb_error);
421 
422           va_end (va_args);
423 
424           return return_vals;
425         }
426 
427       G_VALUE_COLLECT (value, va_args, G_VALUE_NOCOPY_CONTENTS, &error_msg);
428 
429       if (error_msg)
430         {
431           GError *pdb_error = g_error_new_literal (GIMP_PDB_ERROR,
432                                                    GIMP_PDB_ERROR_INTERNAL_ERROR,
433                                                    error_msg);
434           g_warning ("%s: %s", G_STRFUNC, error_msg);
435           g_free (error_msg);
436 
437           gimp_value_array_unref (args);
438 
439           return_vals = gimp_procedure_get_return_values (procedure,
440                                                           FALSE, pdb_error);
441           g_propagate_error (error, pdb_error);
442 
443           va_end (va_args);
444 
445           return return_vals;
446         }
447     }
448 
449   va_end (va_args);
450 
451   return_vals = gimp_pdb_execute_procedure_by_name_args (pdb, context,
452                                                          progress, error,
453                                                          name, args);
454 
455   gimp_value_array_unref (args);
456 
457   return return_vals;
458 }
459 
460 /**
461  * gimp_pdb_get_deprecated_procedures:
462  * @pdb:
463  *
464  * Returns: A new #GList with the deprecated procedures. Free with
465  *          g_list_free().
466  **/
467 GList *
gimp_pdb_get_deprecated_procedures(GimpPDB * pdb)468 gimp_pdb_get_deprecated_procedures (GimpPDB *pdb)
469 {
470   GList *result = NULL;
471   GList *procs;
472   GList *iter;
473 
474   g_return_val_if_fail (GIMP_IS_PDB (pdb), NULL);
475 
476   procs = g_hash_table_get_values (pdb->procedures);
477 
478   for (iter = procs;
479        iter;
480        iter = g_list_next (iter))
481     {
482       GList *proc_list = iter->data;
483 
484       /* Only care about the first procedure in the list */
485       GimpProcedure *procedure = GIMP_PROCEDURE (proc_list->data);
486 
487       if (procedure->deprecated)
488         result = g_list_prepend (result, procedure);
489     }
490 
491   result = g_list_sort (result, (GCompareFunc) gimp_procedure_name_compare);
492 
493   g_list_free (procs);
494 
495   return result;
496 }
497 
498 
499 /*  private functions  */
500 
501 static void
gimp_pdb_entry_free(gpointer key,gpointer value,gpointer user_data)502 gimp_pdb_entry_free (gpointer key,
503                      gpointer value,
504                      gpointer user_data)
505 {
506   if (value)
507     g_list_free_full (value, (GDestroyNotify) g_object_unref);
508 }
509 
510 static gint64
gimp_pdb_entry_get_memsize(GList * procedures,gint64 * gui_size)511 gimp_pdb_entry_get_memsize (GList  *procedures,
512                             gint64 *gui_size)
513 {
514   return gimp_g_list_get_memsize_foreach (procedures,
515                                           (GimpMemsizeFunc)
516                                           gimp_object_get_memsize,
517                                           gui_size);
518 }
519