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