summaryrefslogtreecommitdiffstats
path: root/app/pdb/gimppdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/pdb/gimppdb.c')
-rw-r--r--app/pdb/gimppdb.c518
1 files changed, 518 insertions, 0 deletions
diff --git a/app/pdb/gimppdb.c b/app/pdb/gimppdb.c
new file mode 100644
index 0000000..cff9051
--- /dev/null
+++ b/app/pdb/gimppdb.c
@@ -0,0 +1,518 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <gobject/gvaluecollector.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gegl.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "pdb-types.h"
+
+#include "core/gimp.h"
+#include "core/gimp-memsize.h"
+#include "core/gimpcontext.h"
+#include "core/gimpmarshal.h"
+#include "core/gimpprogress.h"
+
+#include "gimppdb.h"
+#include "gimppdberror.h"
+#include "gimpprocedure.h"
+
+#include "gimp-intl.h"
+
+
+enum
+{
+ REGISTER_PROCEDURE,
+ UNREGISTER_PROCEDURE,
+ LAST_SIGNAL
+};
+
+
+static void gimp_pdb_finalize (GObject *object);
+static gint64 gimp_pdb_get_memsize (GimpObject *object,
+ gint64 *gui_size);
+static void gimp_pdb_real_register_procedure (GimpPDB *pdb,
+ GimpProcedure *procedure);
+static void gimp_pdb_real_unregister_procedure (GimpPDB *pdb,
+ GimpProcedure *procedure);
+static void gimp_pdb_entry_free (gpointer key,
+ gpointer value,
+ gpointer user_data);
+static gint64 gimp_pdb_entry_get_memsize (GList *procedures,
+ gint64 *gui_size);
+
+
+G_DEFINE_TYPE (GimpPDB, gimp_pdb, GIMP_TYPE_OBJECT)
+
+#define parent_class gimp_pdb_parent_class
+
+static guint gimp_pdb_signals[LAST_SIGNAL] = { 0 };
+
+
+static void
+gimp_pdb_class_init (GimpPDBClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
+
+ gimp_pdb_signals[REGISTER_PROCEDURE] =
+ g_signal_new ("register-procedure",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GimpPDBClass, register_procedure),
+ NULL, NULL,
+ gimp_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ GIMP_TYPE_PROCEDURE);
+
+ gimp_pdb_signals[UNREGISTER_PROCEDURE] =
+ g_signal_new ("unregister-procedure",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GimpPDBClass, unregister_procedure),
+ NULL, NULL,
+ gimp_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ GIMP_TYPE_PROCEDURE);
+
+ object_class->finalize = gimp_pdb_finalize;
+
+ gimp_object_class->get_memsize = gimp_pdb_get_memsize;
+
+ klass->register_procedure = gimp_pdb_real_register_procedure;
+ klass->unregister_procedure = gimp_pdb_real_unregister_procedure;
+}
+
+static void
+gimp_pdb_init (GimpPDB *pdb)
+{
+ pdb->procedures = g_hash_table_new (g_str_hash, g_str_equal);
+ pdb->compat_proc_names = g_hash_table_new (g_str_hash, g_str_equal);
+}
+
+static void
+gimp_pdb_finalize (GObject *object)
+{
+ GimpPDB *pdb = GIMP_PDB (object);
+
+ if (pdb->procedures)
+ {
+ g_hash_table_foreach (pdb->procedures, gimp_pdb_entry_free, NULL);
+ g_hash_table_destroy (pdb->procedures);
+ pdb->procedures = NULL;
+ }
+
+ if (pdb->compat_proc_names)
+ {
+ g_hash_table_destroy (pdb->compat_proc_names);
+ pdb->compat_proc_names = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gint64
+gimp_pdb_get_memsize (GimpObject *object,
+ gint64 *gui_size)
+{
+ GimpPDB *pdb = GIMP_PDB (object);
+ gint64 memsize = 0;
+
+ memsize += gimp_g_hash_table_get_memsize_foreach (pdb->procedures,
+ (GimpMemsizeFunc)
+ gimp_pdb_entry_get_memsize,
+ gui_size);
+ memsize += gimp_g_hash_table_get_memsize (pdb->compat_proc_names, 0);
+
+ return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
+ gui_size);
+}
+
+static void
+gimp_pdb_real_register_procedure (GimpPDB *pdb,
+ GimpProcedure *procedure)
+{
+ const gchar *name;
+ GList *list;
+
+ name = gimp_object_get_name (procedure);
+
+ list = g_hash_table_lookup (pdb->procedures, name);
+
+ g_hash_table_replace (pdb->procedures, (gpointer) name,
+ g_list_prepend (list, g_object_ref (procedure)));
+}
+
+static void
+gimp_pdb_real_unregister_procedure (GimpPDB *pdb,
+ GimpProcedure *procedure)
+{
+ const gchar *name;
+ GList *list;
+
+ name = gimp_object_get_name (procedure);
+
+ list = g_hash_table_lookup (pdb->procedures, name);
+
+ if (list)
+ {
+ list = g_list_remove (list, procedure);
+
+ if (list)
+ {
+ name = gimp_object_get_name (list->data);
+ g_hash_table_replace (pdb->procedures, (gpointer) name, list);
+ }
+ else
+ {
+ g_hash_table_remove (pdb->procedures, name);
+ }
+
+ g_object_unref (procedure);
+ }
+}
+
+
+/* public functions */
+
+GimpPDB *
+gimp_pdb_new (Gimp *gimp)
+{
+ GimpPDB *pdb;
+
+ g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
+
+ pdb = g_object_new (GIMP_TYPE_PDB,
+ "name", "pdb",
+ NULL);
+
+ pdb->gimp = gimp;
+
+ return pdb;
+}
+
+void
+gimp_pdb_register_procedure (GimpPDB *pdb,
+ GimpProcedure *procedure)
+{
+ g_return_if_fail (GIMP_IS_PDB (pdb));
+ g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
+
+ if (! procedure->deprecated ||
+ pdb->gimp->pdb_compat_mode != GIMP_PDB_COMPAT_OFF)
+ {
+ g_signal_emit (pdb, gimp_pdb_signals[REGISTER_PROCEDURE], 0,
+ procedure);
+ }
+}
+
+void
+gimp_pdb_unregister_procedure (GimpPDB *pdb,
+ GimpProcedure *procedure)
+{
+ g_return_if_fail (GIMP_IS_PDB (pdb));
+ g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
+
+ g_signal_emit (pdb, gimp_pdb_signals[UNREGISTER_PROCEDURE], 0,
+ procedure);
+}
+
+GimpProcedure *
+gimp_pdb_lookup_procedure (GimpPDB *pdb,
+ const gchar *name)
+{
+ GList *list;
+
+ g_return_val_if_fail (GIMP_IS_PDB (pdb), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ list = g_hash_table_lookup (pdb->procedures, name);
+
+ if (list)
+ return list->data;
+
+ return NULL;
+}
+
+void
+gimp_pdb_register_compat_proc_name (GimpPDB *pdb,
+ const gchar *old_name,
+ const gchar *new_name)
+{
+ g_return_if_fail (GIMP_IS_PDB (pdb));
+ g_return_if_fail (old_name != NULL);
+ g_return_if_fail (new_name != NULL);
+
+ g_hash_table_insert (pdb->compat_proc_names,
+ (gpointer) old_name,
+ (gpointer) new_name);
+}
+
+const gchar *
+gimp_pdb_lookup_compat_proc_name (GimpPDB *pdb,
+ const gchar *old_name)
+{
+ g_return_val_if_fail (GIMP_IS_PDB (pdb), NULL);
+ g_return_val_if_fail (old_name != NULL, NULL);
+
+ return g_hash_table_lookup (pdb->compat_proc_names, old_name);
+}
+
+GimpValueArray *
+gimp_pdb_execute_procedure_by_name_args (GimpPDB *pdb,
+ GimpContext *context,
+ GimpProgress *progress,
+ GError **error,
+ const gchar *name,
+ GimpValueArray *args)
+{
+ GimpValueArray *return_vals = NULL;
+ GList *list;
+
+ g_return_val_if_fail (GIMP_IS_PDB (pdb), NULL);
+ g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
+ g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ list = g_hash_table_lookup (pdb->procedures, name);
+
+ if (list == NULL)
+ {
+ GError *pdb_error = g_error_new (GIMP_PDB_ERROR,
+ GIMP_PDB_ERROR_PROCEDURE_NOT_FOUND,
+ _("Procedure '%s' not found"), name);
+
+ return_vals = gimp_procedure_get_return_values (NULL, FALSE, pdb_error);
+ g_propagate_error (error, pdb_error);
+
+ return return_vals;
+ }
+
+ g_return_val_if_fail (args != NULL, NULL);
+
+ for (; list; list = g_list_next (list))
+ {
+ GimpProcedure *procedure = list->data;
+
+ g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+
+ return_vals = gimp_procedure_execute (procedure,
+ pdb->gimp, context, progress,
+ args, error);
+
+ if (g_value_get_enum (gimp_value_array_index (return_vals, 0)) ==
+ GIMP_PDB_PASS_THROUGH)
+ {
+ /* If the return value is GIMP_PDB_PASS_THROUGH and there is
+ * a next procedure in the list, destroy the return values
+ * and run the next procedure.
+ */
+ if (g_list_next (list))
+ {
+ gimp_value_array_unref (return_vals);
+ g_clear_error (error);
+ }
+ }
+ else
+ {
+ /* No GIMP_PDB_PASS_THROUGH, break out of the list of
+ * procedures and return the current return values.
+ */
+ break;
+ }
+ }
+
+ return return_vals;
+}
+
+GimpValueArray *
+gimp_pdb_execute_procedure_by_name (GimpPDB *pdb,
+ GimpContext *context,
+ GimpProgress *progress,
+ GError **error,
+ const gchar *name,
+ ...)
+{
+ GimpProcedure *procedure;
+ GimpValueArray *args;
+ GimpValueArray *return_vals;
+ va_list va_args;
+ gint i;
+
+ g_return_val_if_fail (GIMP_IS_PDB (pdb), NULL);
+ g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
+ g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ procedure = gimp_pdb_lookup_procedure (pdb, name);
+
+ if (! procedure)
+ {
+ GError *pdb_error = g_error_new (GIMP_PDB_ERROR,
+ GIMP_PDB_ERROR_PROCEDURE_NOT_FOUND,
+ _("Procedure '%s' not found"), name);
+
+ return_vals = gimp_procedure_get_return_values (NULL, FALSE, pdb_error);
+ g_propagate_error (error, pdb_error);
+
+ return return_vals;
+ }
+
+ args = gimp_procedure_get_arguments (procedure);
+
+ va_start (va_args, name);
+
+ for (i = 0; i < procedure->num_args; i++)
+ {
+ GValue *value;
+ GType arg_type;
+ gchar *error_msg = NULL;
+
+ arg_type = va_arg (va_args, GType);
+
+ if (arg_type == G_TYPE_NONE)
+ break;
+
+ value = gimp_value_array_index (args, i);
+
+ if (arg_type != G_VALUE_TYPE (value))
+ {
+ GError *pdb_error;
+ const gchar *expected = g_type_name (G_VALUE_TYPE (value));
+ const gchar *got = g_type_name (arg_type);
+
+ gimp_value_array_unref (args);
+
+ pdb_error = g_error_new (GIMP_PDB_ERROR,
+ GIMP_PDB_ERROR_INVALID_ARGUMENT,
+ _("Procedure '%s' has been called with a "
+ "wrong type for argument #%d. "
+ "Expected %s, got %s."),
+ gimp_object_get_name (procedure),
+ i + 1, expected, got);
+
+ return_vals = gimp_procedure_get_return_values (procedure,
+ FALSE, pdb_error);
+ g_propagate_error (error, pdb_error);
+
+ va_end (va_args);
+
+ return return_vals;
+ }
+
+ G_VALUE_COLLECT (value, va_args, G_VALUE_NOCOPY_CONTENTS, &error_msg);
+
+ if (error_msg)
+ {
+ GError *pdb_error = g_error_new_literal (GIMP_PDB_ERROR,
+ GIMP_PDB_ERROR_INTERNAL_ERROR,
+ error_msg);
+ g_warning ("%s: %s", G_STRFUNC, error_msg);
+ g_free (error_msg);
+
+ gimp_value_array_unref (args);
+
+ return_vals = gimp_procedure_get_return_values (procedure,
+ FALSE, pdb_error);
+ g_propagate_error (error, pdb_error);
+
+ va_end (va_args);
+
+ return return_vals;
+ }
+ }
+
+ va_end (va_args);
+
+ return_vals = gimp_pdb_execute_procedure_by_name_args (pdb, context,
+ progress, error,
+ name, args);
+
+ gimp_value_array_unref (args);
+
+ return return_vals;
+}
+
+/**
+ * gimp_pdb_get_deprecated_procedures:
+ * @pdb:
+ *
+ * Returns: A new #GList with the deprecated procedures. Free with
+ * g_list_free().
+ **/
+GList *
+gimp_pdb_get_deprecated_procedures (GimpPDB *pdb)
+{
+ GList *result = NULL;
+ GList *procs;
+ GList *iter;
+
+ g_return_val_if_fail (GIMP_IS_PDB (pdb), NULL);
+
+ procs = g_hash_table_get_values (pdb->procedures);
+
+ for (iter = procs;
+ iter;
+ iter = g_list_next (iter))
+ {
+ GList *proc_list = iter->data;
+
+ /* Only care about the first procedure in the list */
+ GimpProcedure *procedure = GIMP_PROCEDURE (proc_list->data);
+
+ if (procedure->deprecated)
+ result = g_list_prepend (result, procedure);
+ }
+
+ result = g_list_sort (result, (GCompareFunc) gimp_procedure_name_compare);
+
+ g_list_free (procs);
+
+ return result;
+}
+
+
+/* private functions */
+
+static void
+gimp_pdb_entry_free (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ if (value)
+ g_list_free_full (value, (GDestroyNotify) g_object_unref);
+}
+
+static gint64
+gimp_pdb_entry_get_memsize (GList *procedures,
+ gint64 *gui_size)
+{
+ return gimp_g_list_get_memsize_foreach (procedures,
+ (GimpMemsizeFunc)
+ gimp_object_get_memsize,
+ gui_size);
+}