/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * pikaimageprocedure.c * Copyright (C) 2019 Michael Natterer * * 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 . */ #include "config.h" #include "pika.h" #include "libpikabase/pikawire.h" /* FIXME kill this include */ #include "pikaimageprocedure.h" #include "pikaplugin-private.h" #include "pikaprocedureconfig-private.h" /** * PikaImageProcedure: * * A [class@Procedure] subclass that makes it easier to write standard plug-in * procedures that operate on drawables. * * It automatically adds the standard * * ( [enum@RunMode], [class@Image], [class@Drawable] ) * * arguments of an image procedure. It is possible to add additional * arguments. * * When invoked via [method@Procedure.run], it unpacks these standard * arguments and calls @run_func which is a [callback@RunImageFunc]. The * "args" [struct@ValueArray] of [callback@RunImageFunc] only contains * additionally added arguments. */ struct _PikaImageProcedurePrivate { PikaRunImageFunc run_func; gpointer run_data; GDestroyNotify run_data_destroy; }; static void pika_image_procedure_constructed (GObject *object); static void pika_image_procedure_finalize (GObject *object); static PikaValueArray * pika_image_procedure_run (PikaProcedure *procedure, const PikaValueArray *args); static PikaProcedureConfig * pika_image_procedure_create_config (PikaProcedure *procedure, GParamSpec **args, gint n_args); static gboolean pika_image_procedure_set_sensitivity (PikaProcedure *procedure, gint sensitivity_mask); G_DEFINE_TYPE_WITH_PRIVATE (PikaImageProcedure, pika_image_procedure, PIKA_TYPE_PROCEDURE) #define parent_class pika_image_procedure_parent_class static void pika_image_procedure_class_init (PikaImageProcedureClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); PikaProcedureClass *procedure_class = PIKA_PROCEDURE_CLASS (klass); object_class->constructed = pika_image_procedure_constructed; object_class->finalize = pika_image_procedure_finalize; procedure_class->run = pika_image_procedure_run; procedure_class->create_config = pika_image_procedure_create_config; procedure_class->set_sensitivity = pika_image_procedure_set_sensitivity; } static void pika_image_procedure_init (PikaImageProcedure *procedure) { procedure->priv = pika_image_procedure_get_instance_private (procedure); } static void pika_image_procedure_constructed (GObject *object) { PikaProcedure *procedure = PIKA_PROCEDURE (object); G_OBJECT_CLASS (parent_class)->constructed (object); PIKA_PROC_ARG_ENUM (procedure, "run-mode", "Run mode", "The run mode", PIKA_TYPE_RUN_MODE, PIKA_RUN_NONINTERACTIVE, G_PARAM_READWRITE); PIKA_PROC_ARG_IMAGE (procedure, "image", "Image", "The input image", FALSE, G_PARAM_READWRITE); PIKA_PROC_ARG_INT (procedure, "num-drawables", "Number of drawables", "Number of input drawables", 0, G_MAXINT, 1, G_PARAM_READWRITE); PIKA_PROC_ARG_OBJECT_ARRAY (procedure, "drawables", "Drawables", "The input drawables", PIKA_TYPE_DRAWABLE, G_PARAM_READWRITE | PIKA_PARAM_NO_VALIDATE); } static void pika_image_procedure_finalize (GObject *object) { PikaImageProcedure *procedure = PIKA_IMAGE_PROCEDURE (object); if (procedure->priv->run_data_destroy) procedure->priv->run_data_destroy (procedure->priv->run_data); G_OBJECT_CLASS (parent_class)->finalize (object); } #define ARG_OFFSET 4 static PikaValueArray * pika_image_procedure_run (PikaProcedure *procedure, const PikaValueArray *args) { PikaPlugIn *plug_in; PikaImageProcedure *image_proc = PIKA_IMAGE_PROCEDURE (procedure); PikaPDBStatusType status = PIKA_PDB_EXECUTION_ERROR; PikaProcedureConfig *config; PikaValueArray *remaining; PikaValueArray *return_values; PikaRunMode run_mode; PikaImage *image; PikaDrawable **drawables; gint n_drawables; gint i; run_mode = PIKA_VALUES_GET_ENUM (args, 0); image = PIKA_VALUES_GET_IMAGE (args, 1); n_drawables = PIKA_VALUES_GET_INT (args, 2); drawables = PIKA_VALUES_GET_OBJECT_ARRAY (args, 3); remaining = pika_value_array_new (pika_value_array_length (args) - ARG_OFFSET); for (i = ARG_OFFSET; i < pika_value_array_length (args); i++) { GValue *value = pika_value_array_index (args, i); pika_value_array_append (remaining, value); } config = pika_procedure_create_config (procedure); _pika_procedure_config_begin_run (config, image, run_mode, remaining); return_values = image_proc->priv->run_func (procedure, run_mode, image, n_drawables, drawables, config, image_proc->priv->run_data); if (return_values != NULL && pika_value_array_length (return_values) > 0 && G_VALUE_HOLDS_ENUM (pika_value_array_index (return_values, 0))) status = PIKA_VALUES_GET_ENUM (return_values, 0); _pika_procedure_config_end_run (config, status); /* This is debug printing to help plug-in developers figure out best * practices. */ plug_in = pika_procedure_get_plug_in (procedure); if (G_OBJECT (config)->ref_count > 1 && _pika_plug_in_manage_memory_manually (plug_in)) g_printerr ("%s: ERROR: the PikaProcedureConfig object was refed " "by plug-in, it MUST NOT do that!\n", G_STRFUNC); g_object_unref (config); pika_value_array_unref (remaining); return return_values; } static PikaProcedureConfig * pika_image_procedure_create_config (PikaProcedure *procedure, GParamSpec **args, gint n_args) { if (n_args > ARG_OFFSET) { args += ARG_OFFSET; n_args -= ARG_OFFSET; } else { args = NULL; n_args = 0; } return PIKA_PROCEDURE_CLASS (parent_class)->create_config (procedure, args, n_args); } static gboolean pika_image_procedure_set_sensitivity (PikaProcedure *procedure, gint sensitivity_mask) { GParamSpec *pspec; g_return_val_if_fail (PIKA_IS_IMAGE_PROCEDURE (procedure), FALSE); pspec = pika_procedure_find_argument (procedure, "image"); g_return_val_if_fail (pspec, FALSE); if (sensitivity_mask & PIKA_PROCEDURE_SENSITIVE_NO_IMAGE) pspec->flags |= PIKA_PARAM_NO_VALIDATE; else pspec->flags &= ~PIKA_PARAM_NO_VALIDATE; return TRUE; } /* public functions */ /** * pika_image_procedure_new: * @plug_in: a #PikaPlugIn. * @name: the new procedure's name. * @proc_type: the new procedure's #PikaPDBProcType. * @run_func: (closure run_data): the run function for the new procedure. * @run_data: user data passed to @run_func. * @run_data_destroy: (destroy run_data) (nullable): free function for @run_data, or %NULL. * * Creates a new image procedure named @name which will call @run_func * when invoked. * * See [ctor@Procedure.new] for information about @proc_type. * * Returns: (transfer full): a new #PikaProcedure. * * Since: 3.0 **/ PikaProcedure * pika_image_procedure_new (PikaPlugIn *plug_in, const gchar *name, PikaPDBProcType proc_type, PikaRunImageFunc run_func, gpointer run_data, GDestroyNotify run_data_destroy) { PikaImageProcedure *procedure; g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), NULL); g_return_val_if_fail (pika_is_canonical_identifier (name), NULL); g_return_val_if_fail (proc_type != PIKA_PDB_PROC_TYPE_INTERNAL, NULL); g_return_val_if_fail (proc_type != PIKA_PDB_PROC_TYPE_EXTENSION, NULL); g_return_val_if_fail (run_func != NULL, NULL); procedure = g_object_new (PIKA_TYPE_IMAGE_PROCEDURE, "plug-in", plug_in, "name", name, "procedure-type", proc_type, NULL); procedure->priv->run_func = run_func; procedure->priv->run_data = run_data; procedure->priv->run_data_destroy = run_data_destroy; return PIKA_PROCEDURE (procedure); }