/* 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 * * pikapluginprocedure.c * * 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 #include #include #include "libpikabase/pikabase.h" #include "plug-in-types.h" #include "gegl/pika-babl-compat.h" #include "core/pika.h" #include "core/pika-memsize.h" #include "core/pikadrawable.h" #include "core/pikaimage.h" #include "core/pikaparamspecs.h" #include "file/file-utils.h" #define __YES_I_NEED_PIKA_PLUG_IN_MANAGER_CALL__ #include "pikapluginmanager-call.h" #include "pikapluginerror.h" #include "pikapluginprocedure.h" #include "plug-in-menu-path.h" #include "pika-intl.h" enum { MENU_PATH_ADDED, LAST_SIGNAL }; static void pika_plug_in_procedure_finalize (GObject *object); static gint64 pika_plug_in_procedure_get_memsize (PikaObject *object, gint64 *gui_size); static gchar * pika_plug_in_procedure_get_description (PikaViewable *viewable, gchar **tooltip); static const gchar * pika_plug_in_procedure_get_label (PikaProcedure *procedure); static const gchar * pika_plug_in_procedure_get_menu_label (PikaProcedure *procedure); static const gchar * pika_plug_in_procedure_get_blurb (PikaProcedure *procedure); static const gchar * pika_plug_in_procedure_get_help_id(PikaProcedure *procedure); static gboolean pika_plug_in_procedure_get_sensitive (PikaProcedure *procedure, PikaObject *object, const gchar **reason); static PikaValueArray * pika_plug_in_procedure_execute (PikaProcedure *procedure, Pika *pika, PikaContext *context, PikaProgress *progress, PikaValueArray *args, GError **error); static void pika_plug_in_procedure_execute_async (PikaProcedure *procedure, Pika *pika, PikaContext *context, PikaProgress *progress, PikaValueArray *args, PikaDisplay *display); static GFile * pika_plug_in_procedure_real_get_file (PikaPlugInProcedure *procedure); static gboolean pika_plug_in_procedure_validate_args (PikaPlugInProcedure *proc, Pika *pika, PikaValueArray *args, GError **error); G_DEFINE_TYPE (PikaPlugInProcedure, pika_plug_in_procedure, PIKA_TYPE_PROCEDURE) #define parent_class pika_plug_in_procedure_parent_class static guint pika_plug_in_procedure_signals[LAST_SIGNAL] = { 0 }; static void pika_plug_in_procedure_class_init (PikaPlugInProcedureClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); PikaObjectClass *pika_object_class = PIKA_OBJECT_CLASS (klass); PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass); PikaProcedureClass *proc_class = PIKA_PROCEDURE_CLASS (klass); pika_plug_in_procedure_signals[MENU_PATH_ADDED] = g_signal_new ("menu-path-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (PikaPlugInProcedureClass, menu_path_added), NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING); object_class->finalize = pika_plug_in_procedure_finalize; pika_object_class->get_memsize = pika_plug_in_procedure_get_memsize; viewable_class->default_icon_name = "system-run"; viewable_class->get_description = pika_plug_in_procedure_get_description; proc_class->get_label = pika_plug_in_procedure_get_label; proc_class->get_menu_label = pika_plug_in_procedure_get_menu_label; proc_class->get_blurb = pika_plug_in_procedure_get_blurb; proc_class->get_help_id = pika_plug_in_procedure_get_help_id; proc_class->get_sensitive = pika_plug_in_procedure_get_sensitive; proc_class->execute = pika_plug_in_procedure_execute; proc_class->execute_async = pika_plug_in_procedure_execute_async; klass->get_file = pika_plug_in_procedure_real_get_file; klass->menu_path_added = NULL; } static void pika_plug_in_procedure_init (PikaPlugInProcedure *proc) { PIKA_PROCEDURE (proc)->proc_type = PIKA_PDB_PROC_TYPE_PLUGIN; proc->icon_data_length = -1; } static void pika_plug_in_procedure_finalize (GObject *object) { PikaPlugInProcedure *proc = PIKA_PLUG_IN_PROCEDURE (object); g_object_unref (proc->file); g_free (proc->menu_label); g_list_free_full (proc->menu_paths, (GDestroyNotify) g_free); g_free (proc->help_id_with_domain); g_free (proc->icon_data); g_free (proc->image_types); g_free (proc->insensitive_reason); g_free (proc->extensions); g_free (proc->prefixes); g_free (proc->magics); g_free (proc->mime_types); g_slist_free_full (proc->extensions_list, (GDestroyNotify) g_free); g_slist_free_full (proc->prefixes_list, (GDestroyNotify) g_free); g_slist_free_full (proc->magics_list, (GDestroyNotify) g_free); g_slist_free_full (proc->mime_types_list, (GDestroyNotify) g_free); g_free (proc->thumb_loader); g_free (proc->batch_interpreter_name); G_OBJECT_CLASS (parent_class)->finalize (object); } static gint64 pika_plug_in_procedure_get_memsize (PikaObject *object, gint64 *gui_size) { PikaPlugInProcedure *proc = PIKA_PLUG_IN_PROCEDURE (object); gint64 memsize = 0; GList *list; GSList *slist; memsize += pika_g_object_get_memsize (G_OBJECT (proc->file)); memsize += pika_string_get_memsize (proc->menu_label); for (list = proc->menu_paths; list; list = g_list_next (list)) memsize += sizeof (GList) + pika_string_get_memsize (list->data); switch (proc->icon_type) { case PIKA_ICON_TYPE_ICON_NAME: case PIKA_ICON_TYPE_IMAGE_FILE: memsize += pika_string_get_memsize ((const gchar *) proc->icon_data); break; case PIKA_ICON_TYPE_PIXBUF: memsize += proc->icon_data_length; break; } memsize += pika_string_get_memsize (proc->extensions); memsize += pika_string_get_memsize (proc->prefixes); memsize += pika_string_get_memsize (proc->magics); memsize += pika_string_get_memsize (proc->mime_types); memsize += pika_string_get_memsize (proc->thumb_loader); memsize += pika_string_get_memsize (proc->batch_interpreter_name); for (slist = proc->extensions_list; slist; slist = g_slist_next (slist)) memsize += sizeof (GSList) + pika_string_get_memsize (slist->data); for (slist = proc->prefixes_list; slist; slist = g_slist_next (slist)) memsize += sizeof (GSList) + pika_string_get_memsize (slist->data); for (slist = proc->magics_list; slist; slist = g_slist_next (slist)) memsize += sizeof (GSList) + pika_string_get_memsize (slist->data); for (slist = proc->mime_types_list; slist; slist = g_slist_next (slist)) memsize += sizeof (GSList) + pika_string_get_memsize (slist->data); return memsize + PIKA_OBJECT_CLASS (parent_class)->get_memsize (object, gui_size); } static gchar * pika_plug_in_procedure_get_description (PikaViewable *viewable, gchar **tooltip) { PikaProcedure *procedure = PIKA_PROCEDURE (viewable); if (tooltip) *tooltip = g_strdup (pika_procedure_get_blurb (procedure)); return g_strdup (pika_procedure_get_label (procedure)); } static const gchar * pika_plug_in_procedure_get_label (PikaProcedure *procedure) { PikaPlugInProcedure *proc = PIKA_PLUG_IN_PROCEDURE (procedure); if (! proc->menu_label) return NULL; return PIKA_PROCEDURE_CLASS (parent_class)->get_label (procedure); } static const gchar * pika_plug_in_procedure_get_menu_label (PikaProcedure *procedure) { PikaPlugInProcedure *proc = PIKA_PLUG_IN_PROCEDURE (procedure); if (proc->menu_label) return proc->menu_label; return PIKA_PROCEDURE_CLASS (parent_class)->get_menu_label (procedure); } static const gchar * pika_plug_in_procedure_get_blurb (PikaProcedure *procedure) { if (procedure->blurb) return procedure->blurb; return NULL; } static const gchar * pika_plug_in_procedure_get_help_id (PikaProcedure *procedure) { PikaPlugInProcedure *proc = PIKA_PLUG_IN_PROCEDURE (procedure); const gchar *domain; const gchar *help_id; if (proc->help_id_with_domain) return proc->help_id_with_domain; domain = pika_plug_in_procedure_get_help_domain (proc); if (procedure->help_id) help_id = procedure->help_id; else help_id = pika_object_get_name (procedure); if (domain) proc->help_id_with_domain = g_strconcat (domain, "?", help_id, NULL); else proc->help_id_with_domain = g_strdup (help_id); return proc->help_id_with_domain; } static gboolean pika_plug_in_procedure_get_sensitive (PikaProcedure *procedure, PikaObject *object, const gchar **reason) { PikaPlugInProcedure *proc = PIKA_PLUG_IN_PROCEDURE (procedure); PikaImage *image; GList *drawables = NULL; PikaImageType image_type = -1; gboolean sensitive = FALSE; g_return_val_if_fail (object == NULL || PIKA_IS_IMAGE (object), FALSE); image = PIKA_IMAGE (object); if (image) drawables = pika_image_get_selected_drawables (image); if (drawables) { const Babl *format = pika_drawable_get_format (drawables->data); image_type = pika_babl_format_get_image_type (format); } switch (image_type) { case PIKA_RGB_IMAGE: sensitive = proc->image_types_val & PIKA_PLUG_IN_RGB_IMAGE; break; case PIKA_RGBA_IMAGE: sensitive = proc->image_types_val & PIKA_PLUG_IN_RGBA_IMAGE; break; case PIKA_GRAY_IMAGE: sensitive = proc->image_types_val & PIKA_PLUG_IN_GRAY_IMAGE; break; case PIKA_GRAYA_IMAGE: sensitive = proc->image_types_val & PIKA_PLUG_IN_GRAYA_IMAGE; break; case PIKA_INDEXED_IMAGE: sensitive = proc->image_types_val & PIKA_PLUG_IN_INDEXED_IMAGE; break; case PIKA_INDEXEDA_IMAGE: sensitive = proc->image_types_val & PIKA_PLUG_IN_INDEXEDA_IMAGE; break; default: break; } if (! image && (proc->sensitivity_mask & PIKA_PROCEDURE_SENSITIVE_NO_IMAGE) != 0) sensitive = TRUE; else if (g_list_length (drawables) == 1 && proc->sensitivity_mask != 0 && (proc->sensitivity_mask & PIKA_PROCEDURE_SENSITIVE_DRAWABLE) == 0) sensitive = FALSE; else if (g_list_length (drawables) == 0 && (proc->sensitivity_mask & PIKA_PROCEDURE_SENSITIVE_NO_DRAWABLES) == 0) sensitive = FALSE; else if (g_list_length (drawables) > 1 && (proc->sensitivity_mask & PIKA_PROCEDURE_SENSITIVE_DRAWABLES) == 0) sensitive = FALSE; g_list_free (drawables); if (! sensitive) *reason = proc->insensitive_reason; return sensitive ? TRUE : FALSE; } static PikaValueArray * pika_plug_in_procedure_execute (PikaProcedure *procedure, Pika *pika, PikaContext *context, PikaProgress *progress, PikaValueArray *args, GError **error) { PikaPlugInProcedure *plug_in_procedure = PIKA_PLUG_IN_PROCEDURE (procedure); GError *pdb_error = NULL; if (! pika_plug_in_procedure_validate_args (plug_in_procedure, pika, args, &pdb_error)) { PikaValueArray *return_vals; return_vals = pika_procedure_get_return_values (procedure, FALSE, pdb_error); g_propagate_error (error, pdb_error); return return_vals; } if (procedure->proc_type == PIKA_PDB_PROC_TYPE_INTERNAL) return PIKA_PROCEDURE_CLASS (parent_class)->execute (procedure, pika, context, progress, args, error); return pika_plug_in_manager_call_run (pika->plug_in_manager, context, progress, PIKA_PLUG_IN_PROCEDURE (procedure), args, TRUE, NULL); } static void pika_plug_in_procedure_execute_async (PikaProcedure *procedure, Pika *pika, PikaContext *context, PikaProgress *progress, PikaValueArray *args, PikaDisplay *display) { PikaPlugInProcedure *plug_in_procedure = PIKA_PLUG_IN_PROCEDURE (procedure); GError *error = NULL; if (pika_plug_in_procedure_validate_args (plug_in_procedure, pika, args, &error)) { PikaValueArray *return_vals; return_vals = pika_plug_in_manager_call_run (pika->plug_in_manager, context, progress, plug_in_procedure, args, FALSE, display); if (return_vals) { pika_plug_in_procedure_handle_return_values (plug_in_procedure, pika, progress, return_vals); pika_value_array_unref (return_vals); } } else { pika_message_literal (pika, G_OBJECT (progress), PIKA_MESSAGE_ERROR, error->message); g_error_free (error); } } static GFile * pika_plug_in_procedure_real_get_file (PikaPlugInProcedure *procedure) { return procedure->file; } static inline gboolean PIKA_IS_PARAM_SPEC_RUN_MODE (GParamSpec *pspec) { return (G_IS_PARAM_SPEC_ENUM (pspec) && pspec->value_type == PIKA_TYPE_RUN_MODE); } static inline gboolean PIKA_IS_PARAM_SPEC_FILE (GParamSpec *pspec) { return (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type == G_TYPE_FILE); } static gboolean pika_plug_in_procedure_validate_args (PikaPlugInProcedure *proc, Pika *pika, PikaValueArray *args, GError **error) { #if 0 PikaProcedure *procedure = PIKA_PROCEDURE (proc); GValue *uri_value = NULL; if (! proc->file_proc) return TRUE; /* make sure that the passed strings are actually URIs, not just a * file path (bug 758685) */ if ((procedure->num_args >= 3) && (procedure->num_values >= 1) && PIKA_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) && PIKA_IS_PARAM_SPEC_FILE (procedure->args[1]) && PIKA_IS_PARAM_SPEC_IMAGE (procedure->values[0])) { uri_value = pika_value_array_index (args, 1); } else if ((procedure->num_args >= 5) && PIKA_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) && PIKA_IS_PARAM_SPEC_IMAGE (procedure->args[1]) && PIKA_IS_PARAM_SPEC_DRAWABLE (procedure->args[2]) && PIKA_IS_PARAM_SPEC_FILE (procedure->args[3])) { uri_value = pika_value_array_index (args, 3); } if (uri_value) { GFile *file; file = file_utils_filename_to_file (pika, g_value_get_string (uri_value), error); if (! file) return FALSE; g_value_take_string (uri_value, g_file_get_uri (file)); g_object_unref (file); } #endif return TRUE; } /* public functions */ PikaProcedure * pika_plug_in_procedure_new (PikaPDBProcType proc_type, GFile *file) { PikaPlugInProcedure *proc; g_return_val_if_fail (proc_type == PIKA_PDB_PROC_TYPE_PLUGIN || proc_type == PIKA_PDB_PROC_TYPE_EXTENSION, NULL); g_return_val_if_fail (G_IS_FILE (file), NULL); proc = g_object_new (PIKA_TYPE_PLUG_IN_PROCEDURE, NULL); proc->file = g_object_ref (file); PIKA_PROCEDURE (proc)->proc_type = proc_type; return PIKA_PROCEDURE (proc); } PikaPlugInProcedure * pika_plug_in_procedure_find (GSList *list, const gchar *proc_name) { GSList *l; for (l = list; l; l = g_slist_next (l)) { PikaObject *object = l->data; if (! strcmp (proc_name, pika_object_get_name (object))) return PIKA_PLUG_IN_PROCEDURE (object); } return NULL; } GFile * pika_plug_in_procedure_get_file (PikaPlugInProcedure *proc) { g_return_val_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc), NULL); return PIKA_PLUG_IN_PROCEDURE_GET_CLASS (proc)->get_file (proc); } void pika_plug_in_procedure_set_help_domain (PikaPlugInProcedure *proc, const gchar *help_domain) { g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc)); proc->help_domain = help_domain ? g_quark_from_string (help_domain) : 0; } const gchar * pika_plug_in_procedure_get_help_domain (PikaPlugInProcedure *proc) { g_return_val_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc), NULL); return g_quark_to_string (proc->help_domain); } gboolean pika_plug_in_procedure_set_menu_label (PikaPlugInProcedure *proc, const gchar *menu_label, GError **error) { g_return_val_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc), FALSE); g_return_val_if_fail (menu_label != NULL && strlen (menu_label), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (menu_label[0] == '<') { gchar *basename = g_path_get_basename (pika_file_get_utf8_name (proc->file)); g_set_error (error, PIKA_PLUG_IN_ERROR, PIKA_PLUG_IN_FAILED, "Plug-in \"%s\"\n(%s)\n\n" "attempted to install procedure \"%s\" with a full " "menu path \"%s\" as menu label, this is not supported " "any longer.", basename, pika_file_get_utf8_name (proc->file), pika_object_get_name (proc), menu_label); g_free (basename); return FALSE; } g_clear_pointer (&PIKA_PROCEDURE (proc)->label, g_free); g_free (proc->menu_label); proc->menu_label = g_strdup (menu_label); return TRUE; } gboolean pika_plug_in_procedure_add_menu_path (PikaPlugInProcedure *proc, const gchar *menu_path, GError **error) { PikaProcedure *procedure; gchar *basename = NULL; const gchar *required = NULL; gchar *p; gchar *mapped_path; g_return_val_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc), FALSE); g_return_val_if_fail (menu_path != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); procedure = PIKA_PROCEDURE (proc); if (! proc->menu_label) { basename = g_path_get_basename (pika_file_get_utf8_name (proc->file)); g_set_error (error, PIKA_PLUG_IN_ERROR, PIKA_PLUG_IN_FAILED, "Plug-in \"%s\"\n(%s)\n" "attempted to register the procedure \"%s\" " "in the menu \"%s\", but the procedure has no label. " "This is not allowed.", basename, pika_file_get_utf8_name (proc->file), pika_object_get_name (proc), menu_path); g_free (basename); return FALSE; } p = strchr (menu_path, '>'); if (p == NULL || (*(++p) && *p != '/')) { basename = g_path_get_basename (pika_file_get_utf8_name (proc->file)); g_set_error (error, PIKA_PLUG_IN_ERROR, PIKA_PLUG_IN_FAILED, "Plug-in \"%s\"\n(%s)\n" "attempted to install procedure \"%s\"\n" "in the invalid menu location \"%s\".\n" "The menu path must look like either \"\" " "or \"/path/to/item\".", basename, pika_file_get_utf8_name (proc->file), pika_object_get_name (proc), menu_path); goto failure; } if (g_str_has_prefix (menu_path, "")) { if ((procedure->num_args < 1) || ! PIKA_IS_PARAM_SPEC_RUN_MODE (procedure->args[0])) { required = "PikaRunMode"; goto failure; } } else if (g_str_has_prefix (menu_path, "")) { if ((procedure->num_args < 3) || ! PIKA_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) || ! PIKA_IS_PARAM_SPEC_IMAGE (procedure->args[1]) || ! (G_TYPE_FROM_INSTANCE (procedure->args[2]) == PIKA_TYPE_PARAM_LAYER || G_TYPE_FROM_INSTANCE (procedure->args[2]) == PIKA_TYPE_PARAM_DRAWABLE)) { required = "PikaRunMode, PikaImage, (PikaLayer | PikaDrawable)"; goto failure; } } else if (g_str_has_prefix (menu_path, "")) { if ((procedure->num_args < 3) || ! PIKA_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) || ! PIKA_IS_PARAM_SPEC_IMAGE (procedure->args[1]) || ! (G_TYPE_FROM_INSTANCE (procedure->args[2]) == PIKA_TYPE_PARAM_CHANNEL || G_TYPE_FROM_INSTANCE (procedure->args[2]) == PIKA_TYPE_PARAM_DRAWABLE)) { required = "PikaRunMode, PikaImage, (PikaChannel | PikaDrawable)"; goto failure; } } else if (g_str_has_prefix (menu_path, "")) { if ((procedure->num_args < 3) || ! PIKA_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) || ! PIKA_IS_PARAM_SPEC_IMAGE (procedure->args[1]) || ! PIKA_IS_PARAM_SPEC_VECTORS (procedure->args[2])) { required = "PikaRunMode, PikaImage, PikaVectors"; goto failure; } } else if (g_str_has_prefix (menu_path, "")) { if ((procedure->num_args < 2) || ! PIKA_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) || ! PIKA_IS_PARAM_SPEC_IMAGE (procedure->args[1])) { required = "PikaRunMode, PikaImage"; goto failure; } } else if (g_str_has_prefix (menu_path, "") || g_str_has_prefix (menu_path, "") || g_str_has_prefix (menu_path, "") || g_str_has_prefix (menu_path, "") || g_str_has_prefix (menu_path, "") || g_str_has_prefix (menu_path, "") || g_str_has_prefix (menu_path, "") || g_str_has_prefix (menu_path, "") || g_str_has_prefix (menu_path, "")) { if ((procedure->num_args < 1) || ! PIKA_IS_PARAM_SPEC_RUN_MODE (procedure->args[0])) { required = "PikaRunMode"; goto failure; } } else { basename = g_path_get_basename (pika_file_get_utf8_name (proc->file)); g_set_error (error, PIKA_PLUG_IN_ERROR, PIKA_PLUG_IN_FAILED, "Plug-in \"%s\"\n(%s)\n" "attempted to install procedure \"%s\" " "in the invalid menu location \"%s\".\n" "Use either \"\", " "\"\", \"\", \"\", " "\"\", \"\", \"\", " "\"\", \"\", \"\", " "\"\", \"\", \"\" " "or \"\".", basename, pika_file_get_utf8_name (proc->file), pika_object_get_name (proc), menu_path); goto failure; } g_free (basename); mapped_path = plug_in_menu_path_map (menu_path, NULL); proc->menu_paths = g_list_append (proc->menu_paths, mapped_path); g_signal_emit (proc, pika_plug_in_procedure_signals[MENU_PATH_ADDED], 0, mapped_path); return TRUE; failure: if (required) { gchar *prefix = g_strdup (menu_path); p = strchr (prefix, '>') + 1; *p = '\0'; basename = g_path_get_basename (pika_file_get_utf8_name (proc->file)); g_set_error (error, PIKA_PLUG_IN_ERROR, PIKA_PLUG_IN_FAILED, "Plug-in \"%s\"\n(%s)\n\n" "attempted to install %s procedure \"%s\" " "which does not take the standard %s plug-in's " "arguments: (%s).", basename, pika_file_get_utf8_name (proc->file), prefix, pika_object_get_name (proc), prefix, required); g_free (prefix); } g_free (basename); return FALSE; } gboolean pika_plug_in_procedure_set_icon (PikaPlugInProcedure *proc, PikaIconType icon_type, const guint8 *icon_data, gint icon_data_length, GError **error) { return pika_plug_in_procedure_take_icon (proc, icon_type, g_memdup2 (icon_data, icon_data_length), icon_data_length, error); } gboolean pika_plug_in_procedure_take_icon (PikaPlugInProcedure *proc, PikaIconType icon_type, guint8 *icon_data, gint icon_data_length, GError **error) { const gchar *icon_name = NULL; GdkPixbuf *icon_pixbuf = NULL; gboolean success = TRUE; g_return_val_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (proc->icon_data) { g_free (proc->icon_data); proc->icon_data_length = -1; proc->icon_data = NULL; } proc->icon_type = icon_type; switch (proc->icon_type) { GdkPixbufLoader *loader; case PIKA_ICON_TYPE_ICON_NAME: proc->icon_data_length = -1; proc->icon_data = icon_data; icon_name = (const gchar *) proc->icon_data; break; case PIKA_ICON_TYPE_PIXBUF: proc->icon_data_length = icon_data_length; proc->icon_data = icon_data; loader = gdk_pixbuf_loader_new (); if (! gdk_pixbuf_loader_write (loader, proc->icon_data, proc->icon_data_length, error)) { gdk_pixbuf_loader_close (loader, NULL); success = FALSE; } else if (! gdk_pixbuf_loader_close (loader, error)) { success = FALSE; } if (success) { icon_pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); if (icon_pixbuf) g_object_ref (icon_pixbuf); } g_object_unref (loader); break; case PIKA_ICON_TYPE_IMAGE_FILE: proc->icon_data_length = -1; proc->icon_data = icon_data; icon_pixbuf = gdk_pixbuf_new_from_file ((gchar *) proc->icon_data, error); if (! icon_pixbuf) success = FALSE; break; } pika_viewable_set_icon_name (PIKA_VIEWABLE (proc), icon_name); g_object_set (proc, "icon-pixbuf", icon_pixbuf, NULL); if (icon_pixbuf) g_object_unref (icon_pixbuf); return success; } static PikaPlugInImageType image_types_parse (const gchar *name, const gchar *image_types) { const gchar *type_spec = image_types; PikaPlugInImageType types = 0; /* If the plug_in registers with image_type == NULL or "", return 0 * By doing so it won't be touched by plug_in_set_menu_sensitivity() */ if (! image_types) return types; while (*image_types) { while (*image_types && ((*image_types == ' ') || (*image_types == '\t') || (*image_types == ','))) image_types++; if (*image_types) { if (g_str_has_prefix (image_types, "RGBA")) { types |= PIKA_PLUG_IN_RGBA_IMAGE; image_types += strlen ("RGBA"); } else if (g_str_has_prefix (image_types, "RGB*")) { types |= PIKA_PLUG_IN_RGB_IMAGE | PIKA_PLUG_IN_RGBA_IMAGE; image_types += strlen ("RGB*"); } else if (g_str_has_prefix (image_types, "RGB")) { types |= PIKA_PLUG_IN_RGB_IMAGE; image_types += strlen ("RGB"); } else if (g_str_has_prefix (image_types, "GRAYA")) { types |= PIKA_PLUG_IN_GRAYA_IMAGE; image_types += strlen ("GRAYA"); } else if (g_str_has_prefix (image_types, "GRAY*")) { types |= PIKA_PLUG_IN_GRAY_IMAGE | PIKA_PLUG_IN_GRAYA_IMAGE; image_types += strlen ("GRAY*"); } else if (g_str_has_prefix (image_types, "GRAY")) { types |= PIKA_PLUG_IN_GRAY_IMAGE; image_types += strlen ("GRAY"); } else if (g_str_has_prefix (image_types, "INDEXEDA")) { types |= PIKA_PLUG_IN_INDEXEDA_IMAGE; image_types += strlen ("INDEXEDA"); } else if (g_str_has_prefix (image_types, "INDEXED*")) { types |= PIKA_PLUG_IN_INDEXED_IMAGE | PIKA_PLUG_IN_INDEXEDA_IMAGE; image_types += strlen ("INDEXED*"); } else if (g_str_has_prefix (image_types, "INDEXED")) { types |= PIKA_PLUG_IN_INDEXED_IMAGE; image_types += strlen ("INDEXED"); } else if (g_str_has_prefix (image_types, "*")) { types |= (PIKA_PLUG_IN_RGB_IMAGE | PIKA_PLUG_IN_RGBA_IMAGE | PIKA_PLUG_IN_GRAY_IMAGE | PIKA_PLUG_IN_GRAYA_IMAGE | PIKA_PLUG_IN_INDEXED_IMAGE | PIKA_PLUG_IN_INDEXEDA_IMAGE); image_types += strlen ("*"); } else { g_printerr ("%s: image-type contains unrecognizable parts:" "'%s'\n", name, type_spec); /* skip to next token */ while (*image_types && *image_types != ' ' && *image_types != '\t' && *image_types != ',') { image_types++; } } } } return types; } void pika_plug_in_procedure_set_image_types (PikaPlugInProcedure *proc, const gchar *image_types) { GList *types = NULL; g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc)); if (proc->image_types) g_free (proc->image_types); proc->image_types = g_strdup (image_types); proc->image_types_val = image_types_parse (pika_object_get_name (proc), proc->image_types); g_clear_pointer (&proc->insensitive_reason, g_free); if (proc->image_types_val & (PIKA_PLUG_IN_RGB_IMAGE | PIKA_PLUG_IN_RGBA_IMAGE)) { if ((proc->image_types_val & PIKA_PLUG_IN_RGB_IMAGE) && (proc->image_types_val & PIKA_PLUG_IN_RGBA_IMAGE)) { types = g_list_prepend (types, _("RGB")); } else if (proc->image_types_val & PIKA_PLUG_IN_RGB_IMAGE) { types = g_list_prepend (types, _("RGB without alpha")); } else { types = g_list_prepend (types, _("RGB with alpha")); } } if (proc->image_types_val & (PIKA_PLUG_IN_GRAY_IMAGE | PIKA_PLUG_IN_GRAYA_IMAGE)) { if ((proc->image_types_val & PIKA_PLUG_IN_GRAY_IMAGE) && (proc->image_types_val & PIKA_PLUG_IN_GRAYA_IMAGE)) { types = g_list_prepend (types, _("Grayscale")); } else if (proc->image_types_val & PIKA_PLUG_IN_GRAY_IMAGE) { types = g_list_prepend (types, _("Grayscale without alpha")); } else { types = g_list_prepend (types, _("Grayscale with alpha")); } } if (proc->image_types_val & (PIKA_PLUG_IN_INDEXED_IMAGE | PIKA_PLUG_IN_INDEXEDA_IMAGE)) { if ((proc->image_types_val & PIKA_PLUG_IN_INDEXED_IMAGE) && (proc->image_types_val & PIKA_PLUG_IN_INDEXEDA_IMAGE)) { types = g_list_prepend (types, _("Indexed")); } else if (proc->image_types_val & PIKA_PLUG_IN_INDEXED_IMAGE) { types = g_list_prepend (types, _("Indexed without alpha")); } else { types = g_list_prepend (types, _("Indexed with alpha")); } } if (types) { GString *string; GList *list; types = g_list_reverse (types); string = g_string_new (_("This plug-in only works on the " "following layer types:")); g_string_append (string, " "); for (list = types; list; list = g_list_next (list)) { g_string_append (string, list->data); if (list->next) g_string_append (string, ", "); else g_string_append (string, "."); } g_list_free (types); proc->insensitive_reason = g_string_free (string, FALSE); } } void pika_plug_in_procedure_set_sensitivity_mask (PikaPlugInProcedure *proc, gint sensitivity_mask) { g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc)); proc->sensitivity_mask = sensitivity_mask; } static GSList * extensions_parse (gchar *extensions) { GSList *list = NULL; /* extensions can be NULL. Avoid calling strtok if it is. */ if (extensions) { gchar *extension; gchar *next_token; /* work on a copy */ extensions = g_strdup (extensions); next_token = extensions; extension = strtok (next_token, " \t,"); while (extension) { list = g_slist_prepend (list, g_strdup (extension)); extension = strtok (NULL, " \t,"); } g_free (extensions); } return g_slist_reverse (list); } void pika_plug_in_procedure_set_file_proc (PikaPlugInProcedure *proc, const gchar *extensions, const gchar *prefixes, const gchar *magics) { GSList *list; g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc)); proc->file_proc = TRUE; /* extensions */ if (proc->extensions != extensions) { if (proc->extensions) g_free (proc->extensions); proc->extensions = g_strdup (extensions); } if (proc->extensions_list) g_slist_free_full (proc->extensions_list, (GDestroyNotify) g_free); proc->extensions_list = extensions_parse (proc->extensions); /* prefixes */ if (proc->prefixes != prefixes) { if (proc->prefixes) g_free (proc->prefixes); proc->prefixes = g_strdup (prefixes); } if (proc->prefixes_list) g_slist_free_full (proc->prefixes_list, (GDestroyNotify) g_free); proc->prefixes_list = extensions_parse (proc->prefixes); /* don't allow "file:" to be registered as prefix */ for (list = proc->prefixes_list; list; list = g_slist_next (list)) { const gchar *prefix = list->data; if (prefix && strcmp (prefix, "file:") == 0) { g_free (list->data); proc->prefixes_list = g_slist_delete_link (proc->prefixes_list, list); break; } } /* magics */ if (proc->magics != magics) { if (proc->magics) g_free (proc->magics); proc->magics = g_strdup (magics); } if (proc->magics_list) g_slist_free_full (proc->magics_list, (GDestroyNotify) g_free); proc->magics_list = extensions_parse (proc->magics); } void pika_plug_in_procedure_set_generic_file_proc (PikaPlugInProcedure *proc, gboolean is_generic_file_proc) { proc->generic_file_proc = is_generic_file_proc; } void pika_plug_in_procedure_set_priority (PikaPlugInProcedure *proc, gint priority) { g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc)); proc->priority = priority; } void pika_plug_in_procedure_set_mime_types (PikaPlugInProcedure *proc, const gchar *mime_types) { g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc)); if (proc->mime_types != mime_types) { if (proc->mime_types) g_free (proc->mime_types); proc->mime_types = g_strdup (mime_types); } if (proc->mime_types_list) g_slist_free_full (proc->mime_types_list, (GDestroyNotify) g_free); proc->mime_types_list = extensions_parse (proc->mime_types); } void pika_plug_in_procedure_set_handles_remote (PikaPlugInProcedure *proc) { g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc)); proc->handles_remote = TRUE; } void pika_plug_in_procedure_set_handles_raw (PikaPlugInProcedure *proc) { g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc)); proc->handles_raw = TRUE; } void pika_plug_in_procedure_set_thumb_loader (PikaPlugInProcedure *proc, const gchar *thumb_loader) { g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc)); if (proc->thumb_loader) g_free (proc->thumb_loader); proc->thumb_loader = g_strdup (thumb_loader); } void pika_plug_in_procedure_set_batch_interpreter (PikaPlugInProcedure *proc, const gchar *name) { g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc)); g_return_if_fail (name != NULL); if (proc->batch_interpreter_name) g_free (proc->batch_interpreter_name); proc->batch_interpreter = TRUE; proc->batch_interpreter_name = g_strdup (name); } void pika_plug_in_procedure_handle_return_values (PikaPlugInProcedure *proc, Pika *pika, PikaProgress *progress, PikaValueArray *return_vals) { g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc)); g_return_if_fail (return_vals != NULL); if (pika_value_array_length (return_vals) == 0 || G_VALUE_TYPE (pika_value_array_index (return_vals, 0)) != PIKA_TYPE_PDB_STATUS_TYPE) { return; } switch (g_value_get_enum (pika_value_array_index (return_vals, 0))) { case PIKA_PDB_SUCCESS: break; case PIKA_PDB_CALLING_ERROR: if (pika_value_array_length (return_vals) > 1 && G_VALUE_HOLDS_STRING (pika_value_array_index (return_vals, 1))) { pika_message (pika, G_OBJECT (progress), PIKA_MESSAGE_ERROR, _("Calling error for '%s':\n" "%s"), pika_procedure_get_label (PIKA_PROCEDURE (proc)), g_value_get_string (pika_value_array_index (return_vals, 1))); } break; case PIKA_PDB_EXECUTION_ERROR: if (pika_value_array_length (return_vals) > 1 && G_VALUE_HOLDS_STRING (pika_value_array_index (return_vals, 1))) { pika_message (pika, G_OBJECT (progress), PIKA_MESSAGE_ERROR, _("Execution error for '%s':\n" "%s"), pika_procedure_get_label (PIKA_PROCEDURE (proc)), g_value_get_string (pika_value_array_index (return_vals, 1))); } break; } }