Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

61
app/plug-in/meson.build Normal file
View File

@ -0,0 +1,61 @@
stamp_plug_in_enums = custom_target('stamp-plug-in-enums.h',
input : [
files(
'plug-in-enums.h'
),
],
output: [ 'stamp-plug-in-enums.h', ],
command: [
mkenums_wrap, perl,
meson.project_source_root(), meson.current_source_dir(),
meson.current_build_dir(),
'plug-in-',
'#include <gio/gio.h>\n' +
'#include "libpikabase/pikabase.h"\n',
'#include "pika-intl.h"'
],
build_by_default: true
)
libappplugin_sources = [
'pikaenvirontable.c',
'pikagpparams.c',
'pikainterpreterdb.c',
'pikaplugin-cleanup.c',
'pikaplugin-context.c',
'pikaplugin-message.c',
'pikaplugin-proc.c',
'pikaplugin-progress.c',
'pikaplugin.c',
'pikaplugindebug.c',
'pikaplugindef.c',
'pikapluginerror.c',
'pikapluginmanager-call.c',
'pikapluginmanager-data.c',
'pikapluginmanager-file.c',
'pikapluginmanager-help-domain.c',
'pikapluginmanager-menu-branch.c',
'pikapluginmanager-query.c',
'pikapluginmanager-restore.c',
'pikapluginmanager.c',
'pikapluginprocedure.c',
'pikapluginprocframe.c',
'pikapluginshm.c',
'pikatemporaryprocedure.c',
'plug-in-menu-path.c',
'plug-in-rc.c',
'plug-in-enums.c',
stamp_plug_in_enums,
appcoremarshal[1],
]
libappplugin = static_library('appplug-in',
libappplugin_sources,
include_directories: [ rootInclude, rootAppInclude, ],
c_args: '-DG_LOG_DOMAIN="Pika-Plug-In"',
dependencies: [
cairo, gegl, gdk_pixbuf,
],
)

View File

@ -0,0 +1,522 @@
/* 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
*
* pikaenvirontable.c
* (C) 2002 Manish Singh <yosh@gimp.org>
*
* 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 <string.h>
#include <gio/gio.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "plug-in-types.h"
#include "pikaenvirontable.h"
#include "pika-intl.h"
typedef struct _PikaEnvironValue PikaEnvironValue;
struct _PikaEnvironValue
{
gchar *value;
gchar *separator;
};
static void pika_environ_table_finalize (GObject *object);
static void pika_environ_table_load_env_file (PikaEnvironTable *environ_table,
GFile *file);
static gboolean pika_environ_table_legal_name (gchar *name);
static void pika_environ_table_populate (PikaEnvironTable *environ_table);
static void pika_environ_table_populate_one (const gchar *name,
PikaEnvironValue *val,
GPtrArray *env_array);
static gboolean pika_environ_table_pass_through (PikaEnvironTable *environ_table,
const gchar *name);
static void pika_environ_table_clear_vars (PikaEnvironTable *environ_table);
static void pika_environ_table_clear_internal (PikaEnvironTable *environ_table);
static void pika_environ_table_clear_envp (PikaEnvironTable *environ_table);
static void pika_environ_table_free_value (PikaEnvironValue *val);
G_DEFINE_TYPE (PikaEnvironTable, pika_environ_table, G_TYPE_OBJECT)
#define parent_class pika_environ_table_parent_class
static void
pika_environ_table_class_init (PikaEnvironTableClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = pika_environ_table_finalize;
}
static void
pika_environ_table_init (PikaEnvironTable *environ_table)
{
}
static void
pika_environ_table_finalize (GObject *object)
{
PikaEnvironTable *environ_table = PIKA_ENVIRON_TABLE (object);
pika_environ_table_clear_all (environ_table);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
PikaEnvironTable *
pika_environ_table_new (gboolean verbose)
{
PikaEnvironTable *table = g_object_new (PIKA_TYPE_ENVIRON_TABLE, NULL);
table->verbose = verbose;
return table;
}
static guint
pika_environ_table_str_hash (gconstpointer v)
{
#ifdef G_OS_WIN32
gchar *p = g_ascii_strup ((const gchar *) v, -1);
guint retval = g_str_hash (p);
g_free (p);
return retval;
#else
return g_str_hash (v);
#endif
}
static gboolean
pika_environ_table_str_equal (gconstpointer v1,
gconstpointer v2)
{
#ifdef G_OS_WIN32
gchar *string1 = g_ascii_strup ((const gchar *) v1, -1);
gchar *string2 = g_ascii_strup ((const gchar *) v2, -1);
gboolean retval = g_str_equal (string1, string2);
g_free (string1);
g_free (string2);
return retval;
#else
return g_str_equal (v1, v2);
#endif
}
void
pika_environ_table_load (PikaEnvironTable *environ_table,
GList *path)
{
GList *list;
g_return_if_fail (PIKA_IS_ENVIRON_TABLE (environ_table));
pika_environ_table_clear (environ_table);
environ_table->vars =
g_hash_table_new_full (pika_environ_table_str_hash,
pika_environ_table_str_equal,
g_free,
(GDestroyNotify) pika_environ_table_free_value);
for (list = path; list; list = g_list_next (list))
{
GFile *dir = list->data;
GFileEnumerator *enumerator;
enumerator =
g_file_enumerate_children (dir,
G_FILE_ATTRIBUTE_STANDARD_NAME ","
G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
G_FILE_ATTRIBUTE_STANDARD_TYPE,
G_FILE_QUERY_INFO_NONE,
NULL, NULL);
if (enumerator)
{
GFileInfo *info;
while ((info = g_file_enumerator_next_file (enumerator,
NULL, NULL)))
{
if (! g_file_info_get_is_hidden (info) &&
g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR)
{
GFile *file = g_file_enumerator_get_child (enumerator, info);
pika_environ_table_load_env_file (environ_table, file);
g_object_unref (file);
}
g_object_unref (info);
}
g_object_unref (enumerator);
}
}
}
void
pika_environ_table_add (PikaEnvironTable *environ_table,
const gchar *name,
const gchar *value,
const gchar *separator)
{
PikaEnvironValue *val;
g_return_if_fail (PIKA_IS_ENVIRON_TABLE (environ_table));
pika_environ_table_clear_envp (environ_table);
if (! environ_table->internal)
environ_table->internal =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free,
(GDestroyNotify) pika_environ_table_free_value);
val = g_slice_new (PikaEnvironValue);
val->value = g_strdup (value);
val->separator = g_strdup (separator);
g_hash_table_insert (environ_table->internal, g_strdup (name), val);
}
void
pika_environ_table_remove (PikaEnvironTable *environ_table,
const gchar *name)
{
g_return_if_fail (PIKA_IS_ENVIRON_TABLE (environ_table));
if (! environ_table->internal)
return;
pika_environ_table_clear_envp (environ_table);
g_hash_table_remove (environ_table->internal, name);
if (g_hash_table_size (environ_table->internal) == 0)
pika_environ_table_clear_internal (environ_table);
}
void
pika_environ_table_clear (PikaEnvironTable *environ_table)
{
g_return_if_fail (PIKA_IS_ENVIRON_TABLE (environ_table));
pika_environ_table_clear_envp (environ_table);
pika_environ_table_clear_vars (environ_table);
}
void
pika_environ_table_clear_all (PikaEnvironTable *environ_table)
{
g_return_if_fail (PIKA_IS_ENVIRON_TABLE (environ_table));
pika_environ_table_clear_envp (environ_table);
pika_environ_table_clear_vars (environ_table);
pika_environ_table_clear_internal (environ_table);
}
gchar **
pika_environ_table_get_envp (PikaEnvironTable *environ_table)
{
g_return_val_if_fail (PIKA_IS_ENVIRON_TABLE (environ_table), NULL);
/* Hmm.. should we return a copy here in the future? Not thread safe atm,
* but the rest of it isn't either.
*/
if (! environ_table->envp)
pika_environ_table_populate (environ_table);
return environ_table->envp;
}
/* private */
static void
pika_environ_table_load_env_file (PikaEnvironTable *environ_table,
GFile *file)
{
GInputStream *input;
GDataInputStream *data_input;
gchar *buffer;
gsize buffer_len;
GError *error = NULL;
if (environ_table->verbose)
g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file));
input = G_INPUT_STREAM (g_file_read (file, NULL, &error));
if (! input)
{
g_message (_("Could not open '%s' for reading: %s"),
pika_file_get_utf8_name (file),
error->message);
g_clear_error (&error);
return;
}
data_input = g_data_input_stream_new (input);
g_object_unref (input);
while ((buffer = g_data_input_stream_read_line (data_input, &buffer_len,
NULL, &error)))
{
gchar *name;
gchar *value;
gchar *separator;
gchar *p;
gchar *q;
/* Skip comments */
if (buffer[0] == '#')
{
g_free (buffer);
continue;
}
p = strchr (buffer, '=');
if (! p)
{
g_free (buffer);
continue;
}
*p = '\0';
name = buffer;
value = p + 1;
if (name[0] == '\0')
{
g_message (_("Empty variable name in environment file %s"),
pika_file_get_utf8_name (file));
g_free (buffer);
continue;
}
separator = NULL;
q = strchr (name, ' ');
if (q)
{
*q = '\0';
separator = name;
name = q + 1;
}
if (! pika_environ_table_legal_name (name))
{
g_message (_("Illegal variable name in environment file %s: %s"),
pika_file_get_utf8_name (file), name);
g_free (buffer);
continue;
}
if (! g_hash_table_lookup (environ_table->vars, name))
{
PikaEnvironValue *val = g_slice_new (PikaEnvironValue);
val->value = pika_config_path_expand (value, FALSE, NULL);
val->separator = g_strdup (separator);
g_hash_table_insert (environ_table->vars, g_strdup (name), val);
}
g_free (buffer);
}
if (error)
{
g_message (_("Error reading '%s': %s"),
pika_file_get_utf8_name (file),
error->message);
g_clear_error (&error);
}
g_object_unref (data_input);
}
static gboolean
pika_environ_table_legal_name (gchar *name)
{
gchar *s;
if (! g_ascii_isalpha (*name) && (*name != '_'))
return FALSE;
for (s = name + 1; *s; s++)
if (! g_ascii_isalnum (*s) && (*s != '_'))
return FALSE;
return TRUE;
}
static void
pika_environ_table_populate (PikaEnvironTable *environ_table)
{
gchar **env = g_listenv ();
gchar **var;
GPtrArray *env_array;
var = env;
env_array = g_ptr_array_new ();
while (*var)
{
/* g_listenv() only returns the names of environment variables
* that are correctly specified (name=value) in the environ
* array (Unix) or the process environment string table (Win32).
*/
if (pika_environ_table_pass_through (environ_table, *var))
g_ptr_array_add (env_array, g_strconcat (*var, "=", g_getenv (*var), NULL));
var++;
}
g_strfreev (env);
if (environ_table->vars)
g_hash_table_foreach (environ_table->vars,
(GHFunc) pika_environ_table_populate_one,
env_array);
if (environ_table->internal)
g_hash_table_foreach (environ_table->internal,
(GHFunc) pika_environ_table_populate_one,
env_array);
g_ptr_array_add (env_array, NULL);
environ_table->envp = (gchar **) g_ptr_array_free (env_array, FALSE);
#ifdef ENVP_DEBUG
var = environ_table->envp;
g_print ("PikaEnvironTable:\n");
while (*var)
{
g_print ("%s\n", *var);
var++;
}
#endif /* ENVP_DEBUG */
}
static void
pika_environ_table_populate_one (const gchar *name,
PikaEnvironValue *val,
GPtrArray *env_array)
{
const gchar *old;
gchar *var = NULL;
if (val->separator)
{
old = g_getenv (name);
if (old)
var = g_strconcat (name, "=", val->value, val->separator, old, NULL);
}
if (! var)
var = g_strconcat (name, "=", val->value, NULL);
g_ptr_array_add (env_array, var);
}
static gboolean
pika_environ_table_pass_through (PikaEnvironTable *environ_table,
const gchar *name)
{
gboolean vars, internal;
vars = environ_table->vars &&
g_hash_table_lookup (environ_table->vars, name);
internal = environ_table->internal &&
g_hash_table_lookup (environ_table->internal, name);
return (!vars && !internal);
}
static void
pika_environ_table_clear_vars (PikaEnvironTable *environ_table)
{
if (environ_table->vars)
{
g_hash_table_destroy (environ_table->vars);
environ_table->vars = NULL;
}
}
static void
pika_environ_table_clear_internal (PikaEnvironTable *environ_table)
{
if (environ_table->internal)
{
g_hash_table_destroy (environ_table->internal);
environ_table->internal = NULL;
}
}
static void
pika_environ_table_clear_envp (PikaEnvironTable *environ_table)
{
if (environ_table->envp)
{
g_strfreev (environ_table->envp);
environ_table->envp = NULL;
}
}
static void
pika_environ_table_free_value (PikaEnvironValue *val)
{
g_free (val->value);
g_free (val->separator);
g_slice_free (PikaEnvironValue, val);
}

View File

@ -0,0 +1,76 @@
/* 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
*
* pikaenvirontable.h
* (C) 2002 Manish Singh <yosh@gimp.org>
*
* 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/>.
*/
#ifndef __PIKA_ENVIRON_TABLE_H__
#define __PIKA_ENVIRON_TABLE_H__
#define PIKA_TYPE_ENVIRON_TABLE (pika_environ_table_get_type ())
#define PIKA_ENVIRON_TABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_ENVIRON_TABLE, PikaEnvironTable))
#define PIKA_ENVIRON_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_ENVIRON_TABLE, PikaEnvironTableClass))
#define PIKA_IS_ENVIRON_TABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_ENVIRON_TABLE))
#define PIKA_IS_ENVIRON_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_ENVIRON_TABLE))
#define PIKA_ENVIRON_TABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_ENVIRON_TABLE, PikaEnvironTableClass))
typedef struct _PikaEnvironTableClass PikaEnvironTableClass;
struct _PikaEnvironTable
{
GObject parent_instance;
gboolean verbose;
GHashTable *vars;
GHashTable *internal;
gchar **envp;
};
struct _PikaEnvironTableClass
{
GObjectClass parent_class;
};
GType pika_environ_table_get_type (void) G_GNUC_CONST;
PikaEnvironTable * pika_environ_table_new (gboolean verbose);
void pika_environ_table_load (PikaEnvironTable *environ_table,
GList *path);
void pika_environ_table_add (PikaEnvironTable *environ_table,
const gchar *name,
const gchar *value,
const gchar *separator);
void pika_environ_table_remove (PikaEnvironTable *environ_table,
const gchar *name);
void pika_environ_table_clear (PikaEnvironTable *environ_table);
void pika_environ_table_clear_all (PikaEnvironTable *environ_table);
gchar ** pika_environ_table_get_envp (PikaEnvironTable *environ_table);
#endif /* __PIKA_ENVIRON_TABLE_H__ */

View File

@ -0,0 +1,61 @@
/* 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
*
* pikagpparams.c
* Copyright (C) 2019 Michael Natterer <mitch@gimp.org>
*
* 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 <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "libpikabase/pikaprotocol.h"
#include "plug-in-types.h"
#include "core/pika.h"
#include "core/pikabrush.h"
#include "core/pikadisplay.h"
#include "core/pikagradient.h"
#include "core/pikaimage.h"
#include "core/pikalayer.h"
#include "core/pikalayermask.h"
#include "core/pikapalette.h"
#include "core/pikapattern.h"
#include "core/pikaselection.h"
#include "text/pikafont.h"
#include "core/pikaparamspecs.h"
#include "pdb/pikapdb-utils.h"
#include "vectors/pikavectors.h"
#include "libpika/pikagpparams.h"
/* include the implementation, they are shared between app/ and
* libpika/ but need different headers.
*/
#include "../../libpika/pikagpparams-body.c"

View File

@ -0,0 +1,879 @@
/* 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
*
* pikainterpreterdb.c
* (C) 2005 Manish Singh <yosh@gimp.org>
*
* 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/>.
*/
/*
* The binfmt_misc bits are derived from linux/fs/binfmt_misc.c
* Copyright (C) 1997 Richard Günther
*/
/*
* The sh-bang code is derived from linux/fs/binfmt_script.c
* Copyright (C) 1996 Martin von Löwis
* original #!-checking implemented by tytso.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <gio/gio.h>
#include "libpikabase/pikabase.h"
#include "plug-in-types.h"
#include "pikainterpreterdb.h"
#include "pika-intl.h"
#define BUFSIZE 4096
typedef struct _PikaInterpreterMagic PikaInterpreterMagic;
struct _PikaInterpreterMagic
{
gulong offset;
gchar *magic;
gchar *mask;
guint size;
gchar *program;
};
static void pika_interpreter_db_finalize (GObject *object);
static void pika_interpreter_db_load_interp_file (PikaInterpreterDB *db,
GFile *file);
static void pika_interpreter_db_add_program (PikaInterpreterDB *db,
GFile *file,
gchar *buffer);
static void pika_interpreter_db_add_binfmt_misc (PikaInterpreterDB *db,
GFile *file,
gchar *buffer);
static gboolean pika_interpreter_db_add_extension (GFile *file,
PikaInterpreterDB *db,
gchar **tokens);
static gboolean pika_interpreter_db_add_magic (PikaInterpreterDB *db,
gchar **tokens);
static void pika_interpreter_db_clear_magics (PikaInterpreterDB *db);
static void pika_interpreter_db_resolve_programs (PikaInterpreterDB *db);
G_DEFINE_TYPE (PikaInterpreterDB, pika_interpreter_db, G_TYPE_OBJECT)
#define parent_class pika_interpreter_db_parent_class
static void
pika_interpreter_db_class_init (PikaInterpreterDBClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = pika_interpreter_db_finalize;
}
static void
pika_interpreter_db_init (PikaInterpreterDB *db)
{
}
static void
pika_interpreter_db_finalize (GObject *object)
{
PikaInterpreterDB *db = PIKA_INTERPRETER_DB (object);
pika_interpreter_db_clear (db);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
PikaInterpreterDB *
pika_interpreter_db_new (gboolean verbose)
{
PikaInterpreterDB *db = g_object_new (PIKA_TYPE_INTERPRETER_DB, NULL);
db->verbose = verbose;
return db;
}
void
pika_interpreter_db_load (PikaInterpreterDB *db,
GList *path)
{
GList *list;
g_return_if_fail (PIKA_IS_INTERPRETER_DB (db));
pika_interpreter_db_clear (db);
db->programs = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_free);
db->extensions = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_free);
db->magic_names = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
db->extension_names = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
for (list = path; list; list = g_list_next (list))
{
GFile *dir = list->data;
GFileEnumerator *enumerator;
enumerator =
g_file_enumerate_children (dir,
G_FILE_ATTRIBUTE_STANDARD_NAME ","
G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
G_FILE_ATTRIBUTE_STANDARD_TYPE,
G_FILE_QUERY_INFO_NONE,
NULL, NULL);
if (enumerator)
{
GFileInfo *info;
while ((info = g_file_enumerator_next_file (enumerator,
NULL, NULL)))
{
if (! g_file_info_get_is_hidden (info) &&
g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR)
{
GFile *file = g_file_enumerator_get_child (enumerator, info);
pika_interpreter_db_load_interp_file (db, file);
g_object_unref (file);
}
g_object_unref (info);
}
g_object_unref (enumerator);
}
}
pika_interpreter_db_resolve_programs (db);
}
void
pika_interpreter_db_clear (PikaInterpreterDB *db)
{
g_return_if_fail (PIKA_IS_INTERPRETER_DB (db));
if (db->magic_names)
{
g_hash_table_destroy (db->magic_names);
db->magic_names = NULL;
}
if (db->extension_names)
{
g_hash_table_destroy (db->extension_names);
db->extension_names = NULL;
}
if (db->programs)
{
g_hash_table_destroy (db->programs);
db->programs = NULL;
}
if (db->extensions)
{
g_hash_table_destroy (db->extensions);
db->extensions = NULL;
}
pika_interpreter_db_clear_magics (db);
}
static void
pika_interpreter_db_load_interp_file (PikaInterpreterDB *db,
GFile *file)
{
GInputStream *input;
GDataInputStream *data_input;
gchar *buffer;
gsize buffer_len;
GError *error = NULL;
if (db->verbose)
g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file));
input = G_INPUT_STREAM (g_file_read (file, NULL, &error));
if (! input)
{
g_message (_("Could not open '%s' for reading: %s"),
pika_file_get_utf8_name (file),
error->message);
g_clear_error (&error);
return;
}
data_input = g_data_input_stream_new (input);
g_object_unref (input);
while ((buffer = g_data_input_stream_read_line (data_input, &buffer_len,
NULL, &error)))
{
/* Skip comments */
if (buffer[0] == '#')
{
g_free (buffer);
continue;
}
if (g_ascii_isalnum (buffer[0]) || (buffer[0] == '/'))
{
pika_interpreter_db_add_program (db, file, buffer);
}
else if (! g_ascii_isspace (buffer[0]) && (buffer[0] != '\0'))
{
pika_interpreter_db_add_binfmt_misc (db, file, buffer);
}
g_free (buffer);
}
if (error)
{
g_message (_("Error reading '%s': %s"),
pika_file_get_utf8_name (file),
error->message);
g_clear_error (&error);
}
g_object_unref (data_input);
}
static void
pika_interpreter_db_add_program (PikaInterpreterDB *db,
GFile *file,
gchar *buffer)
{
gchar *name;
gchar *program;
gchar *p;
p = strchr (buffer, '=');
if (! p)
return;
*p = '\0';
name = buffer;
program = p + 1;
g_strchomp (program);
if (! g_file_test (program, G_FILE_TEST_IS_EXECUTABLE))
{
gchar *prog;
prog = g_find_program_in_path (program);
if (! prog || ! g_file_test (prog, G_FILE_TEST_IS_EXECUTABLE))
{
g_message (_("Bad interpreter referenced in interpreter file %s: %s"),
pika_file_get_utf8_name (file),
pika_filename_to_utf8 (program));
if (prog)
g_free (prog);
return;
}
program = prog;
}
else
program = g_strdup (program);
if (! g_hash_table_lookup (db->programs, name))
g_hash_table_insert (db->programs, g_strdup (name), program);
}
static void
pika_interpreter_db_add_binfmt_misc (PikaInterpreterDB *db,
GFile *file,
gchar *buffer)
{
gchar **tokens = NULL;
gchar *name, *type, *program;
gsize count;
gchar del[2];
count = strlen (buffer);
if ((count < 10) || (count > 255))
goto bail;
buffer = g_strndup (buffer, count + 9);
del[0] = *buffer;
del[1] = '\0';
memset (buffer + count, del[0], 8);
tokens = g_strsplit (buffer + 1, del, -1);
g_free (buffer);
name = tokens[0];
type = tokens[1];
program = tokens[5];
if ((name[0] == '\0') || (program[0] == '\0') ||
(type[0] == '\0') || (type[1] != '\0'))
goto bail;
switch (type[0])
{
case 'E':
if (! pika_interpreter_db_add_extension (file, db, tokens))
goto bail;
break;
case 'M':
if (! pika_interpreter_db_add_magic (db, tokens))
goto bail;
break;
default:
goto bail;
}
goto out;
bail:
g_message (_("Bad binary format string in interpreter file %s"),
pika_file_get_utf8_name (file));
out:
g_strfreev (tokens);
}
static gboolean
pika_interpreter_db_add_extension (GFile *file,
PikaInterpreterDB *db,
gchar **tokens)
{
const gchar *name = tokens[0];
const gchar *extension = tokens[3];
const gchar *program = tokens[5];
if (! g_hash_table_lookup (db->extension_names, name))
{
gchar *prog;
if (extension[0] == '\0' || extension[0] == '/')
return FALSE;
if (! g_file_test (program, G_FILE_TEST_IS_EXECUTABLE))
{
prog = g_find_program_in_path (program);
if (! prog || ! g_file_test (prog, G_FILE_TEST_IS_EXECUTABLE))
{
g_message (_("Bad interpreter referenced in interpreter file %s: %s"),
pika_file_get_utf8_name (file),
pika_filename_to_utf8 (program));
if (prog)
g_free (prog);
return FALSE;
}
}
else
prog = g_strdup (program);
g_hash_table_insert (db->extensions, g_strdup (extension), prog);
g_hash_table_insert (db->extension_names, g_strdup (name), prog);
}
return TRUE;
}
static gboolean
scanarg (const gchar *s)
{
gchar c;
while ((c = *s++) != '\0')
{
if (c == '\\' && *s == 'x')
{
s++;
if (! g_ascii_isxdigit (*s++))
return FALSE;
if (! g_ascii_isxdigit (*s++))
return FALSE;
}
}
return TRUE;
}
static guint
unquote (gchar *from)
{
gchar *s = from;
gchar *p = from;
gchar c;
while ((c = *s++) != '\0')
{
if (c == '\\' && *s == 'x')
{
s++;
*p = g_ascii_xdigit_value (*s++) << 4;
*p++ |= g_ascii_xdigit_value (*s++);
continue;
}
*p++ = c;
}
return p - from;
}
static gboolean
pika_interpreter_db_add_magic (PikaInterpreterDB *db,
gchar **tokens)
{
PikaInterpreterMagic *interp_magic;
gchar *name, *num, *magic, *mask, *program;
gulong offset;
guint size;
name = tokens[0];
num = tokens[2];
magic = tokens[3];
mask = tokens[4];
program = tokens[5];
if (! g_hash_table_lookup (db->magic_names, name))
{
if (num[0] != '\0')
{
offset = strtoul (num, &num, 10);
if (num[0] != '\0')
return FALSE;
if (offset > (BUFSIZE / 4))
return FALSE;
}
else
{
offset = 0;
}
if (! scanarg (magic))
return FALSE;
if (! scanarg (mask))
return FALSE;
size = unquote (magic);
if ((size + offset) > (BUFSIZE / 2))
return FALSE;
if (mask[0] == '\0')
mask = NULL;
else if (unquote (mask) != size)
return FALSE;
interp_magic = g_slice_new (PikaInterpreterMagic);
interp_magic->offset = offset;
interp_magic->magic = g_memdup2 (magic, size);
interp_magic->mask = g_memdup2 (mask, size);
interp_magic->size = size;
interp_magic->program = g_strdup (program);
db->magics = g_slist_append (db->magics, interp_magic);
g_hash_table_insert (db->magic_names, g_strdup (name), interp_magic);
}
return TRUE;
}
static void
pika_interpreter_db_clear_magics (PikaInterpreterDB *db)
{
PikaInterpreterMagic *magic;
GSList *list, *last;
list = db->magics;
db->magics = NULL;
while (list)
{
magic = list->data;
g_free (magic->magic);
g_free (magic->mask);
g_free (magic->program);
g_slice_free (PikaInterpreterMagic, magic);
last = list;
list = list->next;
g_slist_free_1 (last);
}
}
#ifdef INTERP_DEBUG
static void
print_kv (gpointer key,
gpointer value,
gpointer user_data)
{
g_print ("%s: %s\n", (gchar *) key, (gchar *) value);
}
static gchar *
quote (gchar *s,
guint size)
{
GString *d;
guint i;
if (s == NULL)
return "(null)";
d = g_string_sized_new (size * 4);
for (i = 0; i < size; i++)
g_string_append_printf (d, "\\x%02x", ((guint) s[i]) & 0xff);
return g_string_free (d, FALSE);
}
#endif
static gboolean
resolve_program (gpointer key,
gpointer value,
gpointer user_data)
{
PikaInterpreterDB *db = user_data;
gchar *program;
program = g_hash_table_lookup (db->programs, value);
if (program != NULL)
{
g_free (value);
value = g_strdup (program);
}
g_hash_table_insert (db->extensions, key, value);
return TRUE;
}
static void
pika_interpreter_db_resolve_programs (PikaInterpreterDB *db)
{
GSList *list;
GHashTable *extensions;
for (list = db->magics; list; list = list->next)
{
PikaInterpreterMagic *magic = list->data;
const gchar *program;
program = g_hash_table_lookup (db->programs, magic->program);
if (program != NULL)
{
g_free (magic->program);
magic->program = g_strdup (program);
}
}
extensions = db->extensions;
db->extensions = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_free);
g_hash_table_foreach_steal (extensions, resolve_program, db);
g_hash_table_destroy (extensions);
#ifdef INTERP_DEBUG
g_print ("Programs:\n");
g_hash_table_foreach (db->programs, print_kv, NULL);
g_print ("\nExtensions:\n");
g_hash_table_foreach (db->extensions, print_kv, NULL);
g_print ("\nMagics:\n");
list = db->magics;
while (list)
{
PikaInterpreterMagic *magic;
magic = list->data;
g_print ("program: %s, offset: %lu, magic: %s, mask: %s\n",
magic->program, magic->offset,
quote (magic->magic, magic->size),
quote (magic->mask, magic->size));
list = list->next;
}
g_print ("\n");
#endif
}
static gchar *
resolve_extension (PikaInterpreterDB *db,
const gchar *program_path)
{
gchar *filename;
gchar *p;
const gchar *program;
filename = g_path_get_basename (program_path);
p = strrchr (filename, '.');
if (! p)
{
g_free (filename);
return NULL;
}
program = g_hash_table_lookup (db->extensions, p + 1);
g_free (filename);
return g_strdup (program);
}
static gchar *
resolve_sh_bang (PikaInterpreterDB *db,
const gchar *program_path,
gchar *buffer,
gssize len,
gchar **interp_arg)
{
gchar *cp;
gchar *name;
gchar *program;
cp = strchr (buffer, '\n');
if (! cp)
cp = buffer + len - 1;
*cp = '\0';
while (cp > buffer)
{
cp--;
if ((*cp == ' ') || (*cp == '\t') || (*cp == '\r'))
*cp = '\0';
else
break;
}
for (cp = buffer + 2; (*cp == ' ') || (*cp == '\t'); cp++);
if (*cp == '\0')
return NULL;
name = cp;
for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
/* nothing */ ;
while ((*cp == ' ') || (*cp == '\t'))
*cp++ = '\0';
if (*cp)
{
if (strcmp ("/usr/bin/env", name) == 0)
{
program = g_hash_table_lookup (db->programs, cp);
if (program)
{
/* Shift program name and arguments to the right, if and
* only if we recorded a specific interpreter for such
* script. Otherwise let `env` tool do its job.
*/
name = cp;
for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
;
while ((*cp == ' ') || (*cp == '\t'))
*cp++ = '\0';
}
}
if (*cp)
*interp_arg = g_strdup (cp);
}
program = g_hash_table_lookup (db->programs, name);
if (! program)
program = name;
return g_strdup (program);
}
static gchar *
resolve_magic (PikaInterpreterDB *db,
const gchar *program_path,
gchar *buffer)
{
GSList *list;
PikaInterpreterMagic *magic;
gchar *s;
guint i;
list = db->magics;
while (list)
{
magic = list->data;
s = buffer + magic->offset;
if (magic->mask)
{
for (i = 0; i < magic->size; i++)
if ((*s++ ^ magic->magic[i]) & magic->mask[i])
break;
}
else
{
for (i = 0; i < magic->size; i++)
if ((*s++ ^ magic->magic[i]))
break;
}
if (i == magic->size)
return g_strdup (magic->program);
list = list->next;
}
return NULL;
}
gchar *
pika_interpreter_db_resolve (PikaInterpreterDB *db,
const gchar *program_path,
gchar **interp_arg)
{
GFile *file;
GInputStream *input;
gchar *program = NULL;
g_return_val_if_fail (PIKA_IS_INTERPRETER_DB (db), NULL);
g_return_val_if_fail (program_path != NULL, NULL);
g_return_val_if_fail (interp_arg != NULL, NULL);
*interp_arg = NULL;
file = g_file_new_for_path (program_path);
input = G_INPUT_STREAM (g_file_read (file, NULL, NULL));
g_object_unref (file);
if (input)
{
gsize bytes_read;
gchar buffer[BUFSIZE];
memset (buffer, 0, sizeof (buffer));
g_input_stream_read_all (input, buffer,
sizeof (buffer) - 1, /* leave one nul at the end */
&bytes_read, NULL, NULL);
g_object_unref (input);
if (bytes_read)
{
if (bytes_read > 3 && buffer[0] == '#' && buffer[1] == '!')
program = resolve_sh_bang (db, program_path, buffer, bytes_read, interp_arg);
if (! program)
program = resolve_magic (db, program_path, buffer);
}
}
if (! program)
program = resolve_extension (db, program_path);
return program;
}
static void
collect_extensions (const gchar *ext,
const gchar *program G_GNUC_UNUSED,
GString *str)
{
if (str->len)
g_string_append_c (str, G_SEARCHPATH_SEPARATOR);
g_string_append_c (str, '.');
g_string_append (str, ext);
}
/**
* pika_interpreter_db_get_extensions:
* @db:
*
* Returns: a newly allocated string with all registered file
* extensions separated by %G_SEARCHPATH_SEPARATOR;
* or %NULL if no extensions are registered
**/
gchar *
pika_interpreter_db_get_extensions (PikaInterpreterDB *db)
{
GString *str;
g_return_val_if_fail (PIKA_IS_INTERPRETER_DB (db), NULL);
if (g_hash_table_size (db->extensions) == 0)
return NULL;
str = g_string_new (NULL);
g_hash_table_foreach (db->extensions, (GHFunc) collect_extensions, str);
return g_string_free (str, FALSE);
}

View File

@ -0,0 +1,74 @@
/* 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
*
* pikainterpreterdb.h
* (C) 2005 Manish Singh <yosh@gimp.org>
*
* 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/>.
*/
#ifndef __PIKA_INTERPRETER_DB_H__
#define __PIKA_INTERPRETER_DB_H__
#define PIKA_TYPE_INTERPRETER_DB (pika_interpreter_db_get_type ())
#define PIKA_INTERPRETER_DB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_INTERPRETER_DB, PikaInterpreterDB))
#define PIKA_INTERPRETER_DB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_INTERPRETER_DB, PikaInterpreterDBClass))
#define PIKA_IS_INTERPRETER_DB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_INTERPRETER_DB))
#define PIKA_IS_INTERPRETER_DB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_INTERPRETER_DB))
#define PIKA_INTERPRETER_DB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_INTERPRETER_DB, PikaInterpreterDBClass))
typedef struct _PikaInterpreterDBClass PikaInterpreterDBClass;
struct _PikaInterpreterDB
{
GObject parent_instance;
gboolean verbose;
GHashTable *programs;
GSList *magics;
GHashTable *magic_names;
GHashTable *extensions;
GHashTable *extension_names;
};
struct _PikaInterpreterDBClass
{
GObjectClass parent_class;
};
GType pika_interpreter_db_get_type (void) G_GNUC_CONST;
PikaInterpreterDB * pika_interpreter_db_new (gboolean verbose);
void pika_interpreter_db_load (PikaInterpreterDB *db,
GList *path);
void pika_interpreter_db_clear (PikaInterpreterDB *db);
gchar * pika_interpreter_db_resolve (PikaInterpreterDB *db,
const gchar *program_path,
gchar **interp_arg);
gchar * pika_interpreter_db_get_extensions (PikaInterpreterDB *db);
#endif /* __PIKA_INTERPRETER_DB_H__ */

View File

@ -0,0 +1,582 @@
/* 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
*
* pikaplugin-cleanup.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "plug-in-types.h"
#include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikadrawable.h"
#include "core/pikadrawable-shadow.h"
#include "core/pikaimage.h"
#include "core/pikaimage-undo.h"
#include "core/pikaundostack.h"
#include "pikaplugin.h"
#include "pikaplugin-cleanup.h"
#include "pikapluginmanager.h"
#include "pikapluginprocedure.h"
#include "pika-log.h"
typedef struct _PikaPlugInCleanupImage PikaPlugInCleanupImage;
struct _PikaPlugInCleanupImage
{
PikaImage *image;
gint image_id;
gint undo_group_count;
gint layers_freeze_count;
gint channels_freeze_count;
gint vectors_freeze_count;
};
typedef struct _PikaPlugInCleanupItem PikaPlugInCleanupItem;
struct _PikaPlugInCleanupItem
{
PikaItem *item;
gint item_id;
gboolean shadow_buffer;
};
/* local function prototypes */
static PikaPlugInCleanupImage *
pika_plug_in_cleanup_image_new (PikaPlugInProcFrame *proc_frame,
PikaImage *image);
static void pika_plug_in_cleanup_image_free (PikaPlugInProcFrame *proc_frame,
PikaPlugInCleanupImage *cleanup);
static gboolean
pika_plug_in_cleanup_image_is_clean (PikaPlugInCleanupImage *cleanup);
static PikaPlugInCleanupImage *
pika_plug_in_cleanup_image_get (PikaPlugInProcFrame *proc_frame,
PikaImage *image);
static void pika_plug_in_cleanup_image (PikaPlugInProcFrame *proc_frame,
PikaPlugInCleanupImage *cleanup);
static PikaPlugInCleanupItem *
pika_plug_in_cleanup_item_new (PikaPlugInProcFrame *proc_frame,
PikaItem *item);
static void pika_plug_in_cleanup_item_free (PikaPlugInProcFrame *proc_frame,
PikaPlugInCleanupItem *cleanup);
static gboolean
pika_plug_in_cleanup_item_is_clean (PikaPlugInCleanupItem *cleanup);
static PikaPlugInCleanupItem *
pika_plug_in_cleanup_item_get (PikaPlugInProcFrame *proc_frame,
PikaItem *item);
static void pika_plug_in_cleanup_item (PikaPlugInProcFrame *proc_frame,
PikaPlugInCleanupItem *cleanup);
/* public functions */
gboolean
pika_plug_in_cleanup_undo_group_start (PikaPlugIn *plug_in,
PikaImage *image)
{
PikaPlugInProcFrame *proc_frame;
PikaPlugInCleanupImage *cleanup;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
cleanup = pika_plug_in_cleanup_image_get (proc_frame, image);
if (! cleanup)
cleanup = pika_plug_in_cleanup_image_new (proc_frame, image);
cleanup->undo_group_count++;
return TRUE;
}
gboolean
pika_plug_in_cleanup_undo_group_end (PikaPlugIn *plug_in,
PikaImage *image)
{
PikaPlugInProcFrame *proc_frame;
PikaPlugInCleanupImage *cleanup;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
cleanup = pika_plug_in_cleanup_image_get (proc_frame, image);
if (! cleanup)
return FALSE;
if (cleanup->undo_group_count > 0)
{
cleanup->undo_group_count--;
if (pika_plug_in_cleanup_image_is_clean (cleanup))
pika_plug_in_cleanup_image_free (proc_frame, cleanup);
return TRUE;
}
return FALSE;
}
gboolean
pika_plug_in_cleanup_layers_freeze (PikaPlugIn *plug_in,
PikaImage *image)
{
PikaPlugInProcFrame *proc_frame;
PikaPlugInCleanupImage *cleanup;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
cleanup = pika_plug_in_cleanup_image_get (proc_frame, image);
if (! cleanup)
cleanup = pika_plug_in_cleanup_image_new (proc_frame, image);
cleanup->layers_freeze_count++;
return TRUE;
}
gboolean
pika_plug_in_cleanup_layers_thaw (PikaPlugIn *plug_in,
PikaImage *image)
{
PikaPlugInProcFrame *proc_frame;
PikaPlugInCleanupImage *cleanup;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
cleanup = pika_plug_in_cleanup_image_get (proc_frame, image);
if (! cleanup)
return FALSE;
if (cleanup->layers_freeze_count > 0)
{
cleanup->layers_freeze_count--;
if (pika_plug_in_cleanup_image_is_clean (cleanup))
pika_plug_in_cleanup_image_free (proc_frame, cleanup);
return TRUE;
}
return FALSE;
}
gboolean
pika_plug_in_cleanup_channels_freeze (PikaPlugIn *plug_in,
PikaImage *image)
{
PikaPlugInProcFrame *proc_frame;
PikaPlugInCleanupImage *cleanup;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
cleanup = pika_plug_in_cleanup_image_get (proc_frame, image);
if (! cleanup)
cleanup = pika_plug_in_cleanup_image_new (proc_frame, image);
cleanup->channels_freeze_count++;
return TRUE;
}
gboolean
pika_plug_in_cleanup_channels_thaw (PikaPlugIn *plug_in,
PikaImage *image)
{
PikaPlugInProcFrame *proc_frame;
PikaPlugInCleanupImage *cleanup;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
cleanup = pika_plug_in_cleanup_image_get (proc_frame, image);
if (! cleanup)
return FALSE;
if (cleanup->channels_freeze_count > 0)
{
cleanup->channels_freeze_count--;
if (pika_plug_in_cleanup_image_is_clean (cleanup))
pika_plug_in_cleanup_image_free (proc_frame, cleanup);
return TRUE;
}
return FALSE;
}
gboolean
pika_plug_in_cleanup_vectors_freeze (PikaPlugIn *plug_in,
PikaImage *image)
{
PikaPlugInProcFrame *proc_frame;
PikaPlugInCleanupImage *cleanup;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
cleanup = pika_plug_in_cleanup_image_get (proc_frame, image);
if (! cleanup)
cleanup = pika_plug_in_cleanup_image_new (proc_frame, image);
cleanup->vectors_freeze_count++;
return TRUE;
}
gboolean
pika_plug_in_cleanup_vectors_thaw (PikaPlugIn *plug_in,
PikaImage *image)
{
PikaPlugInProcFrame *proc_frame;
PikaPlugInCleanupImage *cleanup;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
cleanup = pika_plug_in_cleanup_image_get (proc_frame, image);
if (! cleanup)
return FALSE;
if (cleanup->vectors_freeze_count > 0)
{
cleanup->vectors_freeze_count--;
if (pika_plug_in_cleanup_image_is_clean (cleanup))
pika_plug_in_cleanup_image_free (proc_frame, cleanup);
return TRUE;
}
return FALSE;
}
gboolean
pika_plug_in_cleanup_add_shadow (PikaPlugIn *plug_in,
PikaDrawable *drawable)
{
PikaPlugInProcFrame *proc_frame;
PikaPlugInCleanupItem *cleanup;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (PIKA_IS_DRAWABLE (drawable), FALSE);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
cleanup = pika_plug_in_cleanup_item_get (proc_frame, PIKA_ITEM (drawable));
if (! cleanup)
cleanup = pika_plug_in_cleanup_item_new (proc_frame, PIKA_ITEM (drawable));
cleanup->shadow_buffer = TRUE;
return TRUE;
}
gboolean
pika_plug_in_cleanup_remove_shadow (PikaPlugIn *plug_in,
PikaDrawable *drawable)
{
PikaPlugInProcFrame *proc_frame;
PikaPlugInCleanupItem *cleanup;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (PIKA_IS_DRAWABLE (drawable), FALSE);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
cleanup = pika_plug_in_cleanup_item_get (proc_frame, PIKA_ITEM (drawable));
if (! cleanup)
return FALSE;
if (cleanup->shadow_buffer)
{
cleanup->shadow_buffer = FALSE;
if (pika_plug_in_cleanup_item_is_clean (cleanup))
pika_plug_in_cleanup_item_free (proc_frame, cleanup);
return TRUE;
}
return FALSE;
}
void
pika_plug_in_cleanup (PikaPlugIn *plug_in,
PikaPlugInProcFrame *proc_frame)
{
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
g_return_if_fail (proc_frame != NULL);
while (proc_frame->image_cleanups)
{
PikaPlugInCleanupImage *cleanup = proc_frame->image_cleanups->data;
if (pika_image_get_by_id (plug_in->manager->pika,
cleanup->image_id) == cleanup->image)
{
pika_plug_in_cleanup_image (proc_frame, cleanup);
}
pika_plug_in_cleanup_image_free (proc_frame, cleanup);
}
while (proc_frame->item_cleanups)
{
PikaPlugInCleanupItem *cleanup = proc_frame->item_cleanups->data;
if (pika_item_get_by_id (plug_in->manager->pika,
cleanup->item_id) == cleanup->item)
{
pika_plug_in_cleanup_item (proc_frame, cleanup);
}
pika_plug_in_cleanup_item_free (proc_frame, cleanup);
}
}
/* private functions */
static PikaPlugInCleanupImage *
pika_plug_in_cleanup_image_new (PikaPlugInProcFrame *proc_frame,
PikaImage *image)
{
PikaPlugInCleanupImage *cleanup = g_slice_new0 (PikaPlugInCleanupImage);
cleanup->image = image;
cleanup->image_id = pika_image_get_id (image);
proc_frame->image_cleanups = g_list_prepend (proc_frame->image_cleanups,
cleanup);
return cleanup;
}
static void
pika_plug_in_cleanup_image_free (PikaPlugInProcFrame *proc_frame,
PikaPlugInCleanupImage *cleanup)
{
proc_frame->image_cleanups = g_list_remove (proc_frame->image_cleanups,
cleanup);
g_slice_free (PikaPlugInCleanupImage, cleanup);
}
static gboolean
pika_plug_in_cleanup_image_is_clean (PikaPlugInCleanupImage *cleanup)
{
if (cleanup->undo_group_count > 0)
return FALSE;
if (cleanup->layers_freeze_count > 0)
return FALSE;
if (cleanup->channels_freeze_count > 0)
return FALSE;
if (cleanup->vectors_freeze_count > 0)
return FALSE;
return TRUE;
}
static PikaPlugInCleanupImage *
pika_plug_in_cleanup_image_get (PikaPlugInProcFrame *proc_frame,
PikaImage *image)
{
GList *list;
for (list = proc_frame->image_cleanups; list; list = g_list_next (list))
{
PikaPlugInCleanupImage *cleanup = list->data;
if (cleanup->image == image)
return cleanup;
}
return NULL;
}
static void
pika_plug_in_cleanup_image (PikaPlugInProcFrame *proc_frame,
PikaPlugInCleanupImage *cleanup)
{
PikaImage *image = cleanup->image;
PikaContainer *container;
if (cleanup->undo_group_count > 0)
{
g_message ("Plug-in '%s' left image undo in inconsistent state, "
"closing open undo groups.",
pika_procedure_get_label (proc_frame->procedure));
while (cleanup->undo_group_count--)
if (! pika_image_undo_group_end (image))
break;
}
container = pika_image_get_layers (image);
if (cleanup->layers_freeze_count > 0)
{
g_message ("Plug-in '%s' left image's layers frozen, "
"thawing layers.",
pika_procedure_get_label (proc_frame->procedure));
while (cleanup->layers_freeze_count-- > 0 &&
pika_container_frozen (container))
{
pika_container_thaw (container);
}
}
container = pika_image_get_channels (image);
if (cleanup->channels_freeze_count > 0)
{
g_message ("Plug-in '%s' left image's channels frozen, "
"thawing channels.",
pika_procedure_get_label (proc_frame->procedure));
while (cleanup->channels_freeze_count-- > 0 &&
pika_container_frozen (container))
{
pika_container_thaw (container);
}
}
container = pika_image_get_vectors (image);
if (cleanup->vectors_freeze_count > 0)
{
g_message ("Plug-in '%s' left image's vectors frozen, "
"thawing vectors.",
pika_procedure_get_label (proc_frame->procedure));
while (cleanup->vectors_freeze_count > 0 &&
pika_container_frozen (container))
{
pika_container_thaw (container);
}
}
}
static PikaPlugInCleanupItem *
pika_plug_in_cleanup_item_new (PikaPlugInProcFrame *proc_frame,
PikaItem *item)
{
PikaPlugInCleanupItem *cleanup = g_slice_new0 (PikaPlugInCleanupItem);
cleanup->item = item;
cleanup->item_id = pika_item_get_id (item);
proc_frame->item_cleanups = g_list_prepend (proc_frame->item_cleanups,
cleanup);
return cleanup;
}
static void
pika_plug_in_cleanup_item_free (PikaPlugInProcFrame *proc_frame,
PikaPlugInCleanupItem *cleanup)
{
proc_frame->item_cleanups = g_list_remove (proc_frame->item_cleanups,
cleanup);
g_slice_free (PikaPlugInCleanupItem, cleanup);
}
static gboolean
pika_plug_in_cleanup_item_is_clean (PikaPlugInCleanupItem *cleanup)
{
if (cleanup->shadow_buffer)
return FALSE;
return TRUE;
}
static PikaPlugInCleanupItem *
pika_plug_in_cleanup_item_get (PikaPlugInProcFrame *proc_frame,
PikaItem *item)
{
GList *list;
for (list = proc_frame->item_cleanups; list; list = g_list_next (list))
{
PikaPlugInCleanupItem *cleanup = list->data;
if (cleanup->item == item)
return cleanup;
}
return NULL;
}
static void
pika_plug_in_cleanup_item (PikaPlugInProcFrame *proc_frame,
PikaPlugInCleanupItem *cleanup)
{
PikaItem *item = cleanup->item;
if (cleanup->shadow_buffer)
{
PIKA_LOG (SHADOW_TILES,
"Freeing shadow buffer of drawable '%s' on behalf of '%s'.",
pika_object_get_name (item),
pika_procedure_get_label (proc_frame->procedure));
pika_drawable_free_shadow_buffer (PIKA_DRAWABLE (item));
cleanup->shadow_buffer = FALSE;
}
}

View File

@ -0,0 +1,57 @@
/* 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
*
* pikaplugin-cleanup.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_CLEANUP_H__
#define __PIKA_PLUG_IN_CLEANUP_H__
gboolean pika_plug_in_cleanup_undo_group_start (PikaPlugIn *plug_in,
PikaImage *image);
gboolean pika_plug_in_cleanup_undo_group_end (PikaPlugIn *plug_in,
PikaImage *image);
gboolean pika_plug_in_cleanup_layers_freeze (PikaPlugIn *plug_in,
PikaImage *image);
gboolean pika_plug_in_cleanup_layers_thaw (PikaPlugIn *plug_in,
PikaImage *image);
gboolean pika_plug_in_cleanup_channels_freeze (PikaPlugIn *plug_in,
PikaImage *image);
gboolean pika_plug_in_cleanup_channels_thaw (PikaPlugIn *plug_in,
PikaImage *image);
gboolean pika_plug_in_cleanup_vectors_freeze (PikaPlugIn *plug_in,
PikaImage *image);
gboolean pika_plug_in_cleanup_vectors_thaw (PikaPlugIn *plug_in,
PikaImage *image);
gboolean pika_plug_in_cleanup_add_shadow (PikaPlugIn *plug_in,
PikaDrawable *drawable);
gboolean pika_plug_in_cleanup_remove_shadow (PikaPlugIn *plug_in,
PikaDrawable *drawable);
void pika_plug_in_cleanup (PikaPlugIn *plug_in,
PikaPlugInProcFrame *proc_frame);
#endif /* __PIKA_PLUG_IN_CLEANUP_H__ */

View File

@ -0,0 +1,85 @@
/* 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
*
* pikaplugin-context.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "plug-in-types.h"
#include "core/pika.h"
#include "pdb/pikapdbcontext.h"
#include "pikaplugin.h"
#include "pikaplugin-context.h"
#include "pikapluginmanager.h"
gboolean
pika_plug_in_context_push (PikaPlugIn *plug_in)
{
PikaPlugInProcFrame *proc_frame;
PikaContext *parent;
PikaContext *context;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
if (proc_frame->context_stack)
parent = proc_frame->context_stack->data;
else
parent = proc_frame->main_context;
context = pika_pdb_context_new (plug_in->manager->pika, parent, FALSE);
proc_frame->context_stack = g_list_prepend (proc_frame->context_stack,
context);
return TRUE;
}
gboolean
pika_plug_in_context_pop (PikaPlugIn *plug_in)
{
PikaPlugInProcFrame *proc_frame;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
if (proc_frame->context_stack)
{
PikaContext *context = proc_frame->context_stack->data;
proc_frame->context_stack = g_list_remove (proc_frame->context_stack,
context);
g_object_unref (context);
return TRUE;
}
return FALSE;
}

View File

@ -0,0 +1,32 @@
/* 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
*
* pikaplugin-context.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_CONTEXT_H__
#define __PIKA_PLUG_IN_CONTEXT_H__
gboolean pika_plug_in_context_push (PikaPlugIn *plug_in);
gboolean pika_plug_in_context_pop (PikaPlugIn *plug_in);
#endif /* __PIKA_PLUG_IN_CONTEXT_H__ */

View File

@ -0,0 +1,933 @@
/* 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
*
* pikaplugin-message.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "libpikabase/pikaprotocol.h"
#include "libpikabase/pikawire.h"
#include "libpika/pikagpparams.h"
#include "plug-in-types.h"
#include "gegl/pika-babl.h"
#include "gegl/pika-gegl-tile-compat.h"
#include "core/pika.h"
#include "core/pikadrawable.h"
#include "core/pikadrawable-shadow.h"
#include "pdb/pika-pdb-compat.h"
#include "pdb/pikapdb.h"
#include "pdb/pikapdberror.h"
#include "pikaplugin.h"
#include "pikaplugin-cleanup.h"
#include "pikaplugin-message.h"
#include "pikapluginmanager.h"
#include "pikaplugindef.h"
#include "pikapluginshm.h"
#include "pikatemporaryprocedure.h"
#include "pika-intl.h"
/* local function prototypes */
static void pika_plug_in_handle_quit (PikaPlugIn *plug_in);
static void pika_plug_in_handle_tile_request (PikaPlugIn *plug_in,
GPTileReq *request);
static void pika_plug_in_handle_tile_put (PikaPlugIn *plug_in,
GPTileReq *request);
static void pika_plug_in_handle_tile_get (PikaPlugIn *plug_in,
GPTileReq *request);
static void pika_plug_in_handle_proc_run (PikaPlugIn *plug_in,
GPProcRun *proc_run);
static void pika_plug_in_handle_proc_return (PikaPlugIn *plug_in,
GPProcReturn *proc_return);
static void pika_plug_in_handle_temp_proc_return (PikaPlugIn *plug_in,
GPProcReturn *proc_return);
static void pika_plug_in_handle_proc_install (PikaPlugIn *plug_in,
GPProcInstall *proc_install);
static void pika_plug_in_handle_proc_uninstall (PikaPlugIn *plug_in,
GPProcUninstall *proc_uninstall);
static void pika_plug_in_handle_extension_ack (PikaPlugIn *plug_in);
static void pika_plug_in_handle_has_init (PikaPlugIn *plug_in);
/* public functions */
void
pika_plug_in_handle_message (PikaPlugIn *plug_in,
PikaWireMessage *msg)
{
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
g_return_if_fail (plug_in->open == TRUE);
g_return_if_fail (msg != NULL);
switch (msg->type)
{
case GP_QUIT:
pika_plug_in_handle_quit (plug_in);
break;
case GP_CONFIG:
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"sent a CONFIG message. This should not happen.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file));
pika_plug_in_close (plug_in, TRUE);
break;
case GP_TILE_REQ:
pika_plug_in_handle_tile_request (plug_in, msg->data);
break;
case GP_TILE_ACK:
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"sent a TILE_ACK message. This should not happen.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file));
pika_plug_in_close (plug_in, TRUE);
break;
case GP_TILE_DATA:
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"sent a TILE_DATA message. This should not happen.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file));
pika_plug_in_close (plug_in, TRUE);
break;
case GP_PROC_RUN:
pika_plug_in_handle_proc_run (plug_in, msg->data);
break;
case GP_PROC_RETURN:
pika_plug_in_handle_proc_return (plug_in, msg->data);
break;
case GP_TEMP_PROC_RUN:
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"sent a TEMP_PROC_RUN message. This should not happen.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file));
pika_plug_in_close (plug_in, TRUE);
break;
case GP_TEMP_PROC_RETURN:
pika_plug_in_handle_temp_proc_return (plug_in, msg->data);
break;
case GP_PROC_INSTALL:
pika_plug_in_handle_proc_install (plug_in, msg->data);
break;
case GP_PROC_UNINSTALL:
pika_plug_in_handle_proc_uninstall (plug_in, msg->data);
break;
case GP_EXTENSION_ACK:
pika_plug_in_handle_extension_ack (plug_in);
break;
case GP_HAS_INIT:
pika_plug_in_handle_has_init (plug_in);
break;
}
}
/* private functions */
static void
pika_plug_in_handle_quit (PikaPlugIn *plug_in)
{
pika_plug_in_close (plug_in, FALSE);
}
static void
pika_plug_in_handle_tile_request (PikaPlugIn *plug_in,
GPTileReq *request)
{
g_return_if_fail (request != NULL);
if (request->drawable_id == -1)
pika_plug_in_handle_tile_put (plug_in, request);
else
pika_plug_in_handle_tile_get (plug_in, request);
}
static void
pika_plug_in_handle_tile_put (PikaPlugIn *plug_in,
GPTileReq *request)
{
GPTileData tile_data;
GPTileData *tile_info;
PikaWireMessage msg;
PikaDrawable *drawable;
GeglBuffer *buffer;
const Babl *format;
GeglRectangle tile_rect;
tile_data.drawable_id = -1;
tile_data.tile_num = 0;
tile_data.shadow = 0;
tile_data.bpp = 0;
tile_data.width = 0;
tile_data.height = 0;
tile_data.use_shm = (plug_in->manager->shm != NULL);
tile_data.data = NULL;
if (! gp_tile_data_write (plug_in->my_write, &tile_data, plug_in))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"%s: ERROR", G_STRFUNC);
pika_plug_in_close (plug_in, TRUE);
return;
}
if (! pika_wire_read_msg (plug_in->my_read, &msg, plug_in))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"%s: ERROR", G_STRFUNC);
pika_plug_in_close (plug_in, TRUE);
return;
}
if (msg.type != GP_TILE_DATA)
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"expected tile data and received: %d", msg.type);
pika_plug_in_close (plug_in, TRUE);
return;
}
tile_info = msg.data;
drawable = (PikaDrawable *) pika_item_get_by_id (plug_in->manager->pika,
tile_info->drawable_id);
if (! PIKA_IS_DRAWABLE (drawable))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"tried writing to invalid drawable %d (killing)",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
tile_info->drawable_id);
pika_plug_in_close (plug_in, TRUE);
return;
}
else if (pika_item_is_removed (PIKA_ITEM (drawable)))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"tried writing to drawable %d which was removed "
"from the image (killing)",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
tile_info->drawable_id);
pika_plug_in_close (plug_in, TRUE);
return;
}
if (tile_info->shadow)
{
/* don't check whether the drawable is a group or locked here,
* the plugin will get a proper error message when it tries to
* merge the shadow tiles, which is much better than just
* killing it.
*/
buffer = pika_drawable_get_shadow_buffer (drawable);
pika_plug_in_cleanup_add_shadow (plug_in, drawable);
}
else
{
if (pika_item_is_content_locked (PIKA_ITEM (drawable), NULL))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"tried writing to a locked drawable %d (killing)",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
tile_info->drawable_id);
pika_plug_in_close (plug_in, TRUE);
return;
}
else if (pika_viewable_get_children (PIKA_VIEWABLE (drawable)))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"tried writing to a group layer %d (killing)",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
tile_info->drawable_id);
pika_plug_in_close (plug_in, TRUE);
return;
}
buffer = pika_drawable_get_buffer (drawable);
}
if (! pika_gegl_buffer_get_tile_rect (buffer,
PIKA_PLUG_IN_TILE_WIDTH,
PIKA_PLUG_IN_TILE_HEIGHT,
tile_info->tile_num,
&tile_rect))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"requested invalid tile #%d for writing (killing)",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
tile_info->tile_num);
pika_plug_in_close (plug_in, TRUE);
return;
}
format = gegl_buffer_get_format (buffer);
if (tile_data.use_shm)
{
gegl_buffer_set (buffer, &tile_rect, 0, format,
pika_plug_in_shm_get_addr (plug_in->manager->shm),
GEGL_AUTO_ROWSTRIDE);
}
else
{
gegl_buffer_set (buffer, &tile_rect, 0, format,
tile_info->data,
GEGL_AUTO_ROWSTRIDE);
}
pika_wire_destroy (&msg);
if (! gp_tile_ack_write (plug_in->my_write, plug_in))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"%s: ERROR", G_STRFUNC);
pika_plug_in_close (plug_in, TRUE);
return;
}
}
static void
pika_plug_in_handle_tile_get (PikaPlugIn *plug_in,
GPTileReq *request)
{
GPTileData tile_data;
PikaWireMessage msg;
PikaDrawable *drawable;
GeglBuffer *buffer;
const Babl *format;
GeglRectangle tile_rect;
gint tile_size;
drawable = (PikaDrawable *) pika_item_get_by_id (plug_in->manager->pika,
request->drawable_id);
if (! PIKA_IS_DRAWABLE (drawable))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"tried reading from invalid drawable %d (killing)",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
request->drawable_id);
pika_plug_in_close (plug_in, TRUE);
return;
}
else if (pika_item_is_removed (PIKA_ITEM (drawable)))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"tried reading from drawable %d which was removed "
"from the image (killing)",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
request->drawable_id);
pika_plug_in_close (plug_in, TRUE);
return;
}
if (request->shadow)
{
buffer = pika_drawable_get_shadow_buffer (drawable);
pika_plug_in_cleanup_add_shadow (plug_in, drawable);
}
else
{
buffer = pika_drawable_get_buffer (drawable);
}
if (! pika_gegl_buffer_get_tile_rect (buffer,
PIKA_PLUG_IN_TILE_WIDTH,
PIKA_PLUG_IN_TILE_HEIGHT,
request->tile_num,
&tile_rect))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"requested invalid tile #%d for reading (killing)",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
request->tile_num);
pika_plug_in_close (plug_in, TRUE);
return;
}
format = gegl_buffer_get_format (buffer);
tile_size = (babl_format_get_bytes_per_pixel (format) *
tile_rect.width * tile_rect.height);
tile_data.drawable_id = request->drawable_id;
tile_data.tile_num = request->tile_num;
tile_data.shadow = request->shadow;
tile_data.bpp = babl_format_get_bytes_per_pixel (format);
tile_data.width = tile_rect.width;
tile_data.height = tile_rect.height;
tile_data.use_shm = (plug_in->manager->shm != NULL);
if (tile_data.use_shm)
{
gegl_buffer_get (buffer, &tile_rect, 1.0, format,
pika_plug_in_shm_get_addr (plug_in->manager->shm),
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
}
else
{
tile_data.data = g_malloc (tile_size);
gegl_buffer_get (buffer, &tile_rect, 1.0, format,
tile_data.data,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
}
if (! gp_tile_data_write (plug_in->my_write, &tile_data, plug_in))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"%s: ERROR", G_STRFUNC);
pika_plug_in_close (plug_in, TRUE);
return;
}
if (! pika_wire_read_msg (plug_in->my_read, &msg, plug_in))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"%s: ERROR", G_STRFUNC);
pika_plug_in_close (plug_in, TRUE);
return;
}
if (msg.type != GP_TILE_ACK)
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"expected tile ack and received: %d", msg.type);
pika_plug_in_close (plug_in, TRUE);
return;
}
pika_wire_destroy (&msg);
}
static void
pika_plug_in_handle_proc_error (PikaPlugIn *plug_in,
PikaPlugInProcFrame *proc_frame,
const gchar *name,
const GError *error)
{
switch (proc_frame->error_handler)
{
case PIKA_PDB_ERROR_HANDLER_INTERNAL:
if (error->domain == PIKA_PDB_ERROR)
{
pika_message (plug_in->manager->pika,
G_OBJECT (proc_frame->progress),
PIKA_MESSAGE_ERROR,
_("Calling error for procedure '%s':\n"
"%s"),
name, error->message);
}
else
{
pika_message (plug_in->manager->pika,
G_OBJECT (proc_frame->progress),
PIKA_MESSAGE_ERROR,
_("Execution error for procedure '%s':\n"
"%s"),
name, error->message);
}
break;
case PIKA_PDB_ERROR_HANDLER_PLUGIN:
/* the plug-in is responsible for handling this error */
break;
}
}
static void
pika_plug_in_handle_proc_run (PikaPlugIn *plug_in,
GPProcRun *proc_run)
{
PikaPlugInProcFrame *proc_frame;
gchar *canonical;
const gchar *proc_name = NULL;
PikaProcedure *procedure;
PikaValueArray *args = NULL;
PikaValueArray *return_vals = NULL;
GError *error = NULL;
g_return_if_fail (proc_run != NULL);
g_return_if_fail (proc_run->name != NULL);
canonical = pika_canonicalize_identifier (proc_run->name);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
procedure = pika_pdb_lookup_procedure (plug_in->manager->pika->pdb,
canonical);
if (! procedure)
{
proc_name = pika_pdb_lookup_compat_proc_name (plug_in->manager->pika->pdb,
canonical);
if (proc_name)
{
procedure = pika_pdb_lookup_procedure (plug_in->manager->pika->pdb,
proc_name);
if (plug_in->manager->pika->pdb_compat_mode == PIKA_PDB_COMPAT_WARN)
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_WARNING,
"Plug-in \"%s\"\n(%s)\n"
"called deprecated procedure '%s'.\n"
"It should call '%s' instead!",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
canonical, proc_name);
}
}
}
else if (procedure->deprecated)
{
if (plug_in->manager->pika->pdb_compat_mode == PIKA_PDB_COMPAT_WARN)
{
if (! strcmp (procedure->deprecated, "NONE"))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_WARNING,
"Plug-in \"%s\"\n(%s)\n"
"called deprecated procedure '%s'.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
canonical);
}
else
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_WARNING,
"WARNING: Plug-in \"%s\"\n(%s)\n"
"called deprecated procedure '%s'.\n"
"It should call '%s' instead!",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
canonical, procedure->deprecated);
}
}
}
if (! proc_name)
proc_name = canonical;
args = _pika_gp_params_to_value_array (plug_in->manager->pika,
procedure ? procedure->args : NULL,
procedure ? procedure->num_args : 0,
proc_run->params,
proc_run->n_params,
FALSE);
/* Execute the procedure even if pika_pdb_lookup_procedure()
* returned NULL, pika_pdb_execute_procedure_by_name_args() will
* return appropriate error return_vals.
*/
pika_plug_in_manager_plug_in_push (plug_in->manager, plug_in);
return_vals = pika_pdb_execute_procedure_by_name_args (plug_in->manager->pika->pdb,
proc_frame->context_stack ?
proc_frame->context_stack->data :
proc_frame->main_context,
proc_frame->progress,
&error,
proc_name,
args);
pika_plug_in_manager_plug_in_pop (plug_in->manager);
pika_value_array_unref (args);
if (error)
{
pika_plug_in_handle_proc_error (plug_in, proc_frame,
canonical, error);
g_error_free (error);
}
g_free (canonical);
/* Don't bother to send the return value if executing the procedure
* closed the plug-in (e.g. if the procedure is pika-quit)
*/
if (plug_in->open)
{
GPProcReturn proc_return;
/* Return the name we got called with, *not* proc_name or canonical,
* since proc_name may have been remapped by pika->procedural_compat_ht
* and canonical may be different too.
*/
proc_return.name = proc_run->name;
proc_return.n_params = pika_value_array_length (return_vals);
proc_return.params = _pika_value_array_to_gp_params (return_vals, FALSE);
if (! gp_proc_return_write (plug_in->my_write, &proc_return, plug_in))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"%s: ERROR", G_STRFUNC);
pika_plug_in_close (plug_in, TRUE);
}
_pika_gp_params_free (proc_return.params, proc_return.n_params, FALSE);
}
pika_value_array_unref (return_vals);
}
static void
pika_plug_in_handle_proc_return (PikaPlugIn *plug_in,
GPProcReturn *proc_return)
{
PikaPlugInProcFrame *proc_frame = &plug_in->main_proc_frame;
g_return_if_fail (proc_return != NULL);
proc_frame->return_vals =
_pika_gp_params_to_value_array (plug_in->manager->pika,
proc_frame->procedure->values,
proc_frame->procedure->num_values,
proc_return->params,
proc_return->n_params,
TRUE);
if (proc_frame->main_loop)
{
g_main_loop_quit (proc_frame->main_loop);
}
else
{
/* the plug-in is run asynchronously, so display its error
* messages here because nobody else will do it
*/
pika_plug_in_procedure_handle_return_values (PIKA_PLUG_IN_PROCEDURE (proc_frame->procedure),
plug_in->manager->pika,
proc_frame->progress,
proc_frame->return_vals);
}
pika_plug_in_close (plug_in, FALSE);
}
static void
pika_plug_in_handle_temp_proc_return (PikaPlugIn *plug_in,
GPProcReturn *proc_return)
{
g_return_if_fail (proc_return != NULL);
if (plug_in->temp_proc_frames)
{
PikaPlugInProcFrame *proc_frame = plug_in->temp_proc_frames->data;
proc_frame->return_vals =
_pika_gp_params_to_value_array (plug_in->manager->pika,
proc_frame->procedure->values,
proc_frame->procedure->num_values,
proc_return->params,
proc_return->n_params,
TRUE);
pika_plug_in_main_loop_quit (plug_in);
pika_plug_in_proc_frame_pop (plug_in);
}
else
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"sent a TEMP_PROC_RETURN message while not running "
"a temporary procedure. This should not happen.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file));
pika_plug_in_close (plug_in, TRUE);
}
}
static void
pika_plug_in_handle_proc_install (PikaPlugIn *plug_in,
GPProcInstall *proc_install)
{
PikaPlugInProcedure *proc = NULL;
PikaProcedure *procedure = NULL;
gboolean null_name = FALSE;
gboolean valid_utf8 = TRUE;
gint i;
g_return_if_fail (proc_install != NULL);
g_return_if_fail (proc_install->name != NULL);
if (! pika_is_canonical_identifier (proc_install->name))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"attempted to install procedure \"%s\" with a "
"non-canonical name.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_install->name);
return;
}
/* Sanity check for array arguments */
for (i = 1; i < proc_install->n_params; i++)
{
GPParamDef *param_def = &proc_install->params[i];
GPParamDef *prev_param_def = &proc_install->params[i - 1];
if ((! strcmp (param_def->type_name, "PikaParamInt32Array") ||
! strcmp (param_def->type_name, "PikaParamIntFloatArray") ||
! strcmp (param_def->type_name, "PikaParamIntColorArray"))
&&
strcmp (prev_param_def->type_name, "GParamInt"))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"attempted to install procedure \"%s\" "
"which fails to comply with the array parameter "
"passing standard. Argument %d is noncompliant.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_install->name, i);
return;
}
}
/* Sanity check strings for UTF-8 validity */
#define VALIDATE(str) ((str) == NULL || g_utf8_validate ((str), -1, NULL))
for (i = 0; i < proc_install->n_params && valid_utf8 && ! null_name; i++)
{
if (! proc_install->params[i].name)
{
null_name = TRUE;
}
else if (! (VALIDATE (proc_install->params[i].name) &&
VALIDATE (proc_install->params[i].nick) &&
VALIDATE (proc_install->params[i].blurb)))
{
valid_utf8 = FALSE;
}
}
for (i = 0; i < proc_install->n_return_vals && valid_utf8 && !null_name; i++)
{
if (! proc_install->return_vals[i].name)
{
null_name = TRUE;
}
else if (! (VALIDATE (proc_install->return_vals[i].name) &&
VALIDATE (proc_install->return_vals[i].nick) &&
VALIDATE (proc_install->return_vals[i].blurb)))
{
valid_utf8 = FALSE;
}
}
#undef VALIDATE
if (null_name)
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"attempted to install procedure \"%s\" with a "
"NULL parameter name.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_install->name);
return;
}
if (! valid_utf8)
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"attempted to install procedure \"%s\" with "
"invalid UTF-8 strings.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_install->name);
return;
}
/* Create the procedure object */
switch (proc_install->type)
{
case PIKA_PDB_PROC_TYPE_PLUGIN:
case PIKA_PDB_PROC_TYPE_EXTENSION:
procedure = pika_plug_in_procedure_new (proc_install->type,
plug_in->file);
break;
case PIKA_PDB_PROC_TYPE_TEMPORARY:
procedure = pika_temporary_procedure_new (plug_in);
break;
}
proc = PIKA_PLUG_IN_PROCEDURE (procedure);
proc->mtime = time (NULL);
proc->installed_during_init = (plug_in->call_mode == PIKA_PLUG_IN_CALL_INIT);
pika_object_set_name (PIKA_OBJECT (procedure), proc_install->name);
for (i = 0; i < proc_install->n_params; i++)
{
GParamSpec *pspec =
_pika_gp_param_def_to_param_spec (&proc_install->params[i]);
if (pspec)
pika_procedure_add_argument (procedure, pspec);
}
for (i = 0; i < proc_install->n_return_vals; i++)
{
GParamSpec *pspec =
_pika_gp_param_def_to_param_spec (&proc_install->return_vals[i]);
if (pspec)
pika_procedure_add_return_value (procedure, pspec);
}
/* Install the procedure */
switch (proc_install->type)
{
case PIKA_PDB_PROC_TYPE_PLUGIN:
case PIKA_PDB_PROC_TYPE_EXTENSION:
pika_plug_in_def_add_procedure (plug_in->plug_in_def, proc);
break;
case PIKA_PDB_PROC_TYPE_TEMPORARY:
pika_plug_in_add_temp_proc (plug_in, PIKA_TEMPORARY_PROCEDURE (proc));
break;
}
g_object_unref (proc);
}
static void
pika_plug_in_handle_proc_uninstall (PikaPlugIn *plug_in,
GPProcUninstall *proc_uninstall)
{
PikaPlugInProcedure *proc;
g_return_if_fail (proc_uninstall != NULL);
g_return_if_fail (proc_uninstall->name != NULL);
if (! pika_is_canonical_identifier (proc_uninstall->name))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"attempted to uninstall procedure \"%s\" with a "
"non-canonical name.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_uninstall->name);
return;
}
proc = pika_plug_in_procedure_find (plug_in->temp_procedures,
proc_uninstall->name);
if (proc)
pika_plug_in_remove_temp_proc (plug_in, PIKA_TEMPORARY_PROCEDURE (proc));
}
static void
pika_plug_in_handle_extension_ack (PikaPlugIn *plug_in)
{
if (plug_in->ext_main_loop)
{
g_main_loop_quit (plug_in->ext_main_loop);
}
else
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"sent an EXTENSION_ACK message while not being started "
"as an extension. This should not happen.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file));
pika_plug_in_close (plug_in, TRUE);
}
}
static void
pika_plug_in_handle_has_init (PikaPlugIn *plug_in)
{
if (plug_in->call_mode == PIKA_PLUG_IN_CALL_QUERY)
{
pika_plug_in_def_set_has_init (plug_in->plug_in_def, TRUE);
}
else
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Plug-in \"%s\"\n(%s)\n\n"
"sent an HAS_INIT message while not in query(). "
"This should not happen.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file));
pika_plug_in_close (plug_in, TRUE);
}
}

View File

@ -0,0 +1,32 @@
/* 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
*
* pikaplugin-message.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_MESSAGE_H__
#define __PIKA_PLUG_IN_MESSAGE_H__
void pika_plug_in_handle_message (PikaPlugIn *plug_in,
PikaWireMessage *msg);
#endif /* __PIKA_PLUG_IN_MESSAGE_H__ */

View File

@ -0,0 +1,676 @@
/* 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
*
* pikaplugin-proc.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "plug-in-types.h"
#include "core/pikaparamspecs.h"
#include "pdb/pikapdberror.h"
#include "pikaplugin.h"
#include "pikaplugin-proc.h"
#include "pikaplugindef.h"
#include "pikapluginmanager.h"
#include "pikapluginmanager-file.h"
#include "pikapluginprocedure.h"
#include "pika-intl.h"
/* local function prototypes */
static PikaPlugInProcedure * pika_plug_in_proc_find (PikaPlugIn *plug_in,
const gchar *proc_name);
/* public functions */
gboolean
pika_plug_in_set_proc_image_types (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *image_types,
GError **error)
{
PikaPlugInProcedure *proc;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register images types "
"for procedure \"%s\".\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
pika_plug_in_procedure_set_image_types (proc, image_types);
return TRUE;
}
gboolean
pika_plug_in_set_proc_sensitivity_mask (PikaPlugIn *plug_in,
const gchar *proc_name,
gint sensitivity_mask,
GError **error)
{
PikaPlugInProcedure *proc;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register the sensitivity mask \"%x\" "
"for procedure \"%s\".\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
sensitivity_mask, proc_name);
return FALSE;
}
pika_plug_in_procedure_set_sensitivity_mask (proc, sensitivity_mask);
return TRUE;
}
gboolean
pika_plug_in_set_proc_menu_label (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *menu_label,
GError **error)
{
PikaPlugInProcedure *proc;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
g_return_val_if_fail (menu_label != NULL && strlen (menu_label), FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register the menu label \"%s\" "
"for procedure \"%s\".\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
menu_label, proc_name);
return FALSE;
}
return pika_plug_in_procedure_set_menu_label (proc, menu_label, error);
}
gboolean
pika_plug_in_add_proc_menu_path (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *menu_path,
GError **error)
{
PikaPlugInProcedure *proc;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
g_return_val_if_fail (menu_path != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register the menu item \"%s\" "
"for procedure \"%s\".\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
menu_path, proc_name);
return FALSE;
}
return pika_plug_in_procedure_add_menu_path (proc, menu_path, error);
}
gboolean
pika_plug_in_set_proc_icon (PikaPlugIn *plug_in,
const gchar *proc_name,
PikaIconType type,
const guint8 *data,
gint data_length,
GError **error)
{
PikaPlugInProcedure *proc;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to set the icon "
"for procedure \"%s\".\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
return pika_plug_in_procedure_set_icon (proc, type, data, data_length,
error);
}
gboolean
pika_plug_in_set_proc_help (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *blurb,
const gchar *help,
const gchar *help_id,
GError **error)
{
PikaPlugInProcedure *proc;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register help "
"for procedure \"%s\".\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
pika_procedure_set_help (PIKA_PROCEDURE (proc),
blurb, help, help_id);
return TRUE;
}
gboolean
pika_plug_in_set_proc_attribution (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *authors,
const gchar *copyright,
const gchar *date,
GError **error)
{
PikaPlugInProcedure *proc;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register the attribution "
"for procedure \"%s\".\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
pika_procedure_set_attribution (PIKA_PROCEDURE (proc),
authors, copyright, date);
return TRUE;
}
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);
}
gboolean
pika_plug_in_set_file_proc_load_handler (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *extensions,
const gchar *prefixes,
const gchar *magics,
GError **error)
{
PikaPlugInProcedure *proc;
PikaProcedure *procedure;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register procedure \"%s\" "
"as load handler.\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
procedure = PIKA_PROCEDURE (proc);
if (((procedure->num_args < 2) ||
(procedure->num_values < 1) ||
! PIKA_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) ||
! PIKA_IS_PARAM_SPEC_FILE (procedure->args[1]) ||
(! proc->generic_file_proc &&
! PIKA_IS_PARAM_SPEC_IMAGE (procedure->values[0]))))
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_FAILED,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register procedure \"%s\" "
"as load handler which does not take the standard "
"load procedure arguments: "
"(PikaRunMode, GFile) -> (PikaImage)",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
pika_plug_in_procedure_set_file_proc (proc, extensions, prefixes, magics);
pika_plug_in_manager_add_load_procedure (plug_in->manager, proc);
return TRUE;
}
gboolean
pika_plug_in_set_file_proc_save_handler (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *extensions,
const gchar *prefixes,
GError **error)
{
PikaPlugInProcedure *proc;
PikaProcedure *procedure;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register procedure \"%s\" "
"as save handler.\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
procedure = PIKA_PROCEDURE (proc);
if ((procedure->num_args < 5) ||
! PIKA_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) ||
! PIKA_IS_PARAM_SPEC_IMAGE (procedure->args[1]) ||
! G_IS_PARAM_SPEC_INT (procedure->args[2]) ||
! PIKA_IS_PARAM_SPEC_OBJECT_ARRAY (procedure->args[3]) ||
! PIKA_IS_PARAM_SPEC_FILE (procedure->args[4]))
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_FAILED,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register procedure \"%s\" "
"as save handler which does not take the standard "
"save procedure arguments:\n"
"(PikaRunMode, PikaImage, int [array size], PikaDrawable Array, GFile)",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
pika_plug_in_procedure_set_file_proc (proc, extensions, prefixes, NULL);
pika_plug_in_manager_add_save_procedure (plug_in->manager, proc);
return TRUE;
}
gboolean
pika_plug_in_set_file_proc_priority (PikaPlugIn *plug_in,
const gchar *proc_name,
gint priority,
GError **error)
{
PikaPlugInProcedure *proc;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register the priority "
"for procedure \"%s\".\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
pika_plug_in_procedure_set_priority (proc, priority);
return TRUE;
}
gboolean
pika_plug_in_set_file_proc_mime_types (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *mime_types,
GError **error)
{
PikaPlugInProcedure *proc;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register mime types "
"for procedure \"%s\".\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
pika_plug_in_procedure_set_mime_types (proc, mime_types);
return TRUE;
}
gboolean
pika_plug_in_set_file_proc_handles_remote (PikaPlugIn *plug_in,
const gchar *proc_name,
GError **error)
{
PikaPlugInProcedure *proc;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register 'handles remote' "
"for procedure \"%s\".\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
pika_plug_in_procedure_set_handles_remote (proc);
return TRUE;
}
gboolean
pika_plug_in_set_file_proc_handles_raw (PikaPlugIn *plug_in,
const gchar *proc_name,
GError **error)
{
PikaPlugInProcedure *proc;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register 'handles raw' "
"for procedure \"%s\".\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
pika_plug_in_procedure_set_handles_raw (proc);
return TRUE;
}
gboolean
pika_plug_in_set_file_proc_thumb_loader (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *thumb_proc_name,
GError **error)
{
PikaPlugInProcedure *proc;
PikaPlugInProcedure *thumb_proc;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
g_return_val_if_fail (thumb_proc_name != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
thumb_proc = pika_plug_in_proc_find (plug_in, thumb_proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register a thumbnail loader "
"for procedure \"%s\".\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
if (! thumb_proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register a procedure \"%s\" "
"as thumbnail loader.\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
thumb_proc_name);
return FALSE;
}
pika_plug_in_procedure_set_thumb_loader (proc, thumb_proc_name);
return TRUE;
}
gboolean
pika_plug_in_set_batch_interpreter (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *interpreter_name,
GError **error)
{
PikaPlugInProcedure *proc;
PikaProcedure *procedure;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (proc_name != NULL, FALSE);
proc = pika_plug_in_proc_find (plug_in, proc_name);
if (! proc)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_PROCEDURE_NOT_FOUND,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register procedure \"%s\" "
"as a 'batch interpreter'.\n"
"It has however not installed that procedure. "
"This is not allowed.",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
procedure = PIKA_PROCEDURE (proc);
if (procedure->num_args < 2 ||
! PIKA_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) ||
! G_IS_PARAM_SPEC_STRING (procedure->args[1]))
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_FAILED,
"Plug-in \"%s\"\n(%s)\n"
"attempted to register procedure \"%s\" "
"as a batch interpreter which does not take the standard "
"batch interpreter procedure arguments: "
"(PikaRunMode, gchar *) -> ()",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
proc_name);
return FALSE;
}
pika_plug_in_procedure_set_batch_interpreter (proc, interpreter_name);
pika_plug_in_manager_add_batch_procedure (plug_in->manager, proc);
return TRUE;
}
/* private functions */
static PikaPlugInProcedure *
pika_plug_in_proc_find (PikaPlugIn *plug_in,
const gchar *proc_name)
{
PikaPlugInProcedure *proc = NULL;
if (plug_in->plug_in_def)
proc = pika_plug_in_procedure_find (plug_in->plug_in_def->procedures,
proc_name);
if (! proc)
proc = pika_plug_in_procedure_find (plug_in->temp_procedures, proc_name);
return proc;
}

View File

@ -0,0 +1,98 @@
/* 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
*
* pikaplugin-proc.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_PROC_H__
#define __PIKA_PLUG_IN_PROC_H__
gboolean pika_plug_in_set_proc_image_types (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *image_types,
GError **error);
gboolean pika_plug_in_set_proc_sensitivity_mask (PikaPlugIn *plug_in,
const gchar *proc_name,
gint sensitivity_mask,
GError **error);
gboolean pika_plug_in_set_proc_menu_label (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *menu_label,
GError **error);
gboolean pika_plug_in_add_proc_menu_path (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *menu_path,
GError **error);
gboolean pika_plug_in_set_proc_icon (PikaPlugIn *plug_in,
const gchar *proc_name,
PikaIconType type,
const guint8 *data,
gint data_length,
GError **error);
gboolean pika_plug_in_set_proc_help (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *blurb,
const gchar *help,
const gchar *help_id,
GError **error);
gboolean pika_plug_in_set_proc_attribution (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *authors,
const gchar *copyright,
const gchar *date,
GError **error);
gboolean pika_plug_in_set_file_proc_load_handler (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *extensions,
const gchar *prefixes,
const gchar *magics,
GError **error);
gboolean pika_plug_in_set_file_proc_save_handler (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *extensions,
const gchar *prefixes,
GError **error);
gboolean pika_plug_in_set_file_proc_priority (PikaPlugIn *plug_in,
const gchar *proc_name,
gint priority,
GError **error);
gboolean pika_plug_in_set_file_proc_mime_types (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *mime_types,
GError **error);
gboolean pika_plug_in_set_file_proc_handles_remote (PikaPlugIn *plug_in,
const gchar *proc_name,
GError **error);
gboolean pika_plug_in_set_file_proc_handles_raw (PikaPlugIn *plug_in,
const gchar *proc_name,
GError **error);
gboolean pika_plug_in_set_file_proc_thumb_loader (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *thumb_proc,
GError **error);
gboolean pika_plug_in_set_batch_interpreter (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *interpreter_name,
GError **error);
#endif /* __PIKA_PLUG_IN_PROC_H__ */

View File

@ -0,0 +1,373 @@
/* 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
*
* pikaplugin-progress.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "plug-in-types.h"
#include "core/pika.h"
#include "core/pikadisplay.h"
#include "core/pikaparamspecs.h"
#include "core/pikapdbprogress.h"
#include "core/pikaprogress.h"
#include "pdb/pikapdb.h"
#include "pdb/pikapdberror.h"
#include "pikaplugin.h"
#include "pikaplugin-progress.h"
#include "pikapluginmanager.h"
#include "pikatemporaryprocedure.h"
#include "pika-intl.h"
/* local function prototypes */
static void pika_plug_in_progress_cancel_callback (PikaProgress *progress,
PikaPlugIn *plug_in);
/* public functions */
gint
pika_plug_in_progress_attach (PikaProgress *progress)
{
gint attach_count;
g_return_val_if_fail (PIKA_IS_PROGRESS (progress), 0);
attach_count =
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (progress),
"plug-in-progress-attach-count"));
attach_count++;
g_object_set_data (G_OBJECT (progress), "plug-in-progress-attach-count",
GINT_TO_POINTER (attach_count));
return attach_count;
}
gint
pika_plug_in_progress_detach (PikaProgress *progress)
{
gint attach_count;
g_return_val_if_fail (PIKA_IS_PROGRESS (progress), 0);
attach_count =
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (progress),
"plug-in-progress-attach-count"));
attach_count--;
g_object_set_data (G_OBJECT (progress), "plug-in-progress-attach-count",
GINT_TO_POINTER (attach_count));
return attach_count;
}
void
pika_plug_in_progress_start (PikaPlugIn *plug_in,
const gchar *message,
PikaDisplay *display)
{
PikaPlugInProcFrame *proc_frame;
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
g_return_if_fail (display == NULL || PIKA_IS_DISPLAY (display));
proc_frame = pika_plug_in_get_proc_frame (plug_in);
if (! proc_frame->progress)
{
proc_frame->progress = pika_new_progress (plug_in->manager->pika,
display);
if (proc_frame->progress)
{
proc_frame->progress_created = TRUE;
g_object_ref (proc_frame->progress);
pika_plug_in_progress_attach (proc_frame->progress);
}
}
if (proc_frame->progress)
{
if (! proc_frame->progress_cancel_id)
{
g_object_add_weak_pointer (G_OBJECT (proc_frame->progress),
(gpointer) &proc_frame->progress);
proc_frame->progress_cancel_id =
g_signal_connect (proc_frame->progress, "cancel",
G_CALLBACK (pika_plug_in_progress_cancel_callback),
plug_in);
}
if (pika_progress_is_active (proc_frame->progress))
{
if (message)
pika_progress_set_text_literal (proc_frame->progress, message);
if (pika_progress_get_value (proc_frame->progress) > 0.0)
pika_progress_set_value (proc_frame->progress, 0.0);
}
else
{
pika_progress_start (proc_frame->progress, TRUE,
"%s", message ? message : "");
}
}
}
void
pika_plug_in_progress_end (PikaPlugIn *plug_in,
PikaPlugInProcFrame *proc_frame)
{
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
g_return_if_fail (proc_frame != NULL);
if (proc_frame->progress)
{
if (proc_frame->progress_cancel_id)
{
g_signal_handler_disconnect (proc_frame->progress,
proc_frame->progress_cancel_id);
proc_frame->progress_cancel_id = 0;
g_object_remove_weak_pointer (G_OBJECT (proc_frame->progress),
(gpointer) &proc_frame->progress);
}
if (pika_plug_in_progress_detach (proc_frame->progress) < 1 &&
pika_progress_is_active (proc_frame->progress))
{
pika_progress_end (proc_frame->progress);
}
if (proc_frame->progress_created)
{
pika_free_progress (plug_in->manager->pika, proc_frame->progress);
g_clear_object (&proc_frame->progress);
}
}
}
void
pika_plug_in_progress_set_text (PikaPlugIn *plug_in,
const gchar *message)
{
PikaPlugInProcFrame *proc_frame;
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
proc_frame = pika_plug_in_get_proc_frame (plug_in);
if (proc_frame->progress)
pika_progress_set_text_literal (proc_frame->progress, message);
}
void
pika_plug_in_progress_set_value (PikaPlugIn *plug_in,
gdouble percentage)
{
PikaPlugInProcFrame *proc_frame;
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
proc_frame = pika_plug_in_get_proc_frame (plug_in);
if (! proc_frame->progress ||
! pika_progress_is_active (proc_frame->progress) ||
! proc_frame->progress_cancel_id)
{
pika_plug_in_progress_start (plug_in, NULL, NULL);
}
if (proc_frame->progress && pika_progress_is_active (proc_frame->progress))
pika_progress_set_value (proc_frame->progress, percentage);
}
void
pika_plug_in_progress_pulse (PikaPlugIn *plug_in)
{
PikaPlugInProcFrame *proc_frame;
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
proc_frame = pika_plug_in_get_proc_frame (plug_in);
if (! proc_frame->progress ||
! pika_progress_is_active (proc_frame->progress) ||
! proc_frame->progress_cancel_id)
{
pika_plug_in_progress_start (plug_in, NULL, NULL);
}
if (proc_frame->progress && pika_progress_is_active (proc_frame->progress))
pika_progress_pulse (proc_frame->progress);
}
guint32
pika_plug_in_progress_get_window_id (PikaPlugIn *plug_in)
{
PikaPlugInProcFrame *proc_frame;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), 0);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
if (proc_frame->progress)
return pika_progress_get_window_id (proc_frame->progress);
return 0;
}
gboolean
pika_plug_in_progress_install (PikaPlugIn *plug_in,
const gchar *progress_callback)
{
PikaPlugInProcFrame *proc_frame;
PikaProcedure *procedure;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (progress_callback != NULL, FALSE);
procedure = pika_pdb_lookup_procedure (plug_in->manager->pika->pdb,
progress_callback);
if (! PIKA_IS_TEMPORARY_PROCEDURE (procedure) ||
PIKA_TEMPORARY_PROCEDURE (procedure)->plug_in != plug_in ||
procedure->num_args != 3 ||
! G_IS_PARAM_SPEC_INT (procedure->args[0]) ||
! G_IS_PARAM_SPEC_STRING (procedure->args[1]) ||
! G_IS_PARAM_SPEC_DOUBLE (procedure->args[2]))
{
return FALSE;
}
proc_frame = pika_plug_in_get_proc_frame (plug_in);
if (proc_frame->progress)
{
pika_plug_in_progress_end (plug_in, proc_frame);
g_clear_object (&proc_frame->progress);
}
proc_frame->progress = g_object_new (PIKA_TYPE_PDB_PROGRESS,
"pdb", plug_in->manager->pika->pdb,
"context", proc_frame->main_context,
"callback-name", progress_callback,
NULL);
pika_plug_in_progress_attach (proc_frame->progress);
return TRUE;
}
gboolean
pika_plug_in_progress_uninstall (PikaPlugIn *plug_in,
const gchar *progress_callback)
{
PikaPlugInProcFrame *proc_frame;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (progress_callback != NULL, FALSE);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
if (PIKA_IS_PDB_PROGRESS (proc_frame->progress))
{
pika_plug_in_progress_end (plug_in, proc_frame);
g_clear_object (&proc_frame->progress);
return TRUE;
}
return FALSE;
}
gboolean
pika_plug_in_progress_cancel (PikaPlugIn *plug_in,
const gchar *progress_callback)
{
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (progress_callback != NULL, FALSE);
return FALSE;
}
/* private functions */
static PikaValueArray *
get_cancel_return_values (PikaProcedure *procedure)
{
PikaValueArray *return_vals;
GError *error;
error = g_error_new_literal (PIKA_PDB_ERROR, PIKA_PDB_ERROR_CANCELLED,
_("Cancelled"));
return_vals = pika_procedure_get_return_values (procedure, FALSE, error);
g_error_free (error);
return return_vals;
}
static void
pika_plug_in_progress_cancel_callback (PikaProgress *progress,
PikaPlugIn *plug_in)
{
PikaPlugInProcFrame *proc_frame = &plug_in->main_proc_frame;
GList *list;
if (proc_frame->main_loop)
{
proc_frame->return_vals =
get_cancel_return_values (proc_frame->procedure);
}
for (list = plug_in->temp_proc_frames; list; list = g_list_next (list))
{
proc_frame = list->data;
if (proc_frame->main_loop)
{
proc_frame->return_vals =
get_cancel_return_values (proc_frame->procedure);
}
}
pika_plug_in_close (plug_in, TRUE);
}

View File

@ -0,0 +1,51 @@
/* 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
*
* pikaplugin-progress.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_PROGRESS_H__
#define __PIKA_PLUG_IN_PROGRESS_H__
gint pika_plug_in_progress_attach (PikaProgress *progress);
gint pika_plug_in_progress_detach (PikaProgress *progress);
void pika_plug_in_progress_start (PikaPlugIn *plug_in,
const gchar *message,
PikaDisplay *display);
void pika_plug_in_progress_end (PikaPlugIn *plug_in,
PikaPlugInProcFrame *proc_frame);
void pika_plug_in_progress_set_text (PikaPlugIn *plug_in,
const gchar *message);
void pika_plug_in_progress_set_value (PikaPlugIn *plug_in,
gdouble percentage);
void pika_plug_in_progress_pulse (PikaPlugIn *plug_in);
guint32 pika_plug_in_progress_get_window_id (PikaPlugIn *plug_in);
gboolean pika_plug_in_progress_install (PikaPlugIn *plug_in,
const gchar *progress_callback);
gboolean pika_plug_in_progress_uninstall (PikaPlugIn *plug_in,
const gchar *progress_callback);
gboolean pika_plug_in_progress_cancel (PikaPlugIn *plug_in,
const gchar *progress_callback);
#endif /* __PIKA_PLUG_IN_PROGRESS_H__ */

990
app/plug-in/pikaplugin.c Normal file
View File

@ -0,0 +1,990 @@
/* 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
*
* pikaplugin.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#ifndef _WIN32
#define _GNU_SOURCE
#endif
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
#define STRICT
#include <windows.h>
#include <process.h>
#ifdef G_OS_WIN32
#include <fcntl.h>
#include <io.h>
#ifndef pipe
#define pipe(fds) _pipe(fds, 4096, _O_BINARY)
#endif
#endif
#ifdef G_WITH_CYGWIN
#define O_TEXT 0x0100 /* text file */
#define _O_TEXT 0x0100 /* text file */
#define O_BINARY 0x0200 /* binary file */
#define _O_BINARY 0x0200 /* binary file */
#endif
#endif /* G_OS_WIN32 || G_WITH_CYGWIN */
#include "libpikabase/pikabase.h"
#include "libpikabase/pikaprotocol.h"
#include "libpikabase/pikawire.h"
#include "plug-in-types.h"
#include "core/pika.h"
#include "core/pika-spawn.h"
#include "core/pikaprogress.h"
#include "pdb/pikapdbcontext.h"
#include "pikaenvirontable.h"
#include "pikainterpreterdb.h"
#include "pikaplugin.h"
#include "pikaplugin-message.h"
#include "pikaplugin-progress.h"
#include "pikaplugindebug.h"
#include "pikaplugindef.h"
#include "pikapluginmanager.h"
#include "pikapluginmanager-help-domain.h"
#include "pikatemporaryprocedure.h"
#include "pika-intl.h"
static void pika_plug_in_finalize (GObject *object);
static gboolean pika_plug_in_recv_message (GIOChannel *channel,
GIOCondition cond,
gpointer data);
static gboolean pika_plug_in_write (GIOChannel *channel,
const guint8 *buf,
gulong count,
gpointer data);
static gboolean pika_plug_in_flush (GIOChannel *channel,
gpointer data);
#if defined G_OS_WIN32 && defined WIN32_32BIT_DLL_FOLDER
static void pika_plug_in_set_dll_directory (const gchar *path);
#endif
#ifndef G_OS_WIN32
static void pika_plug_in_close_waitpid (GPid pid,
gint status,
PikaPlugIn *plug_in);
#endif
G_DEFINE_TYPE (PikaPlugIn, pika_plug_in, PIKA_TYPE_OBJECT)
#define parent_class pika_plug_in_parent_class
static void
pika_plug_in_class_init (PikaPlugInClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = pika_plug_in_finalize;
/* initialize the pika protocol library and set the read and
* write handlers.
*/
gp_init ();
pika_wire_set_writer (pika_plug_in_write);
pika_wire_set_flusher (pika_plug_in_flush);
}
static void
pika_plug_in_init (PikaPlugIn *plug_in)
{
plug_in->manager = NULL;
plug_in->file = NULL;
plug_in->call_mode = PIKA_PLUG_IN_CALL_NONE;
plug_in->open = FALSE;
plug_in->hup = FALSE;
plug_in->pid = 0;
plug_in->my_read = NULL;
plug_in->my_write = NULL;
plug_in->his_read = NULL;
plug_in->his_write = NULL;
plug_in->input_id = 0;
plug_in->write_buffer_index = 0;
plug_in->temp_procedures = NULL;
plug_in->ext_main_loop = NULL;
plug_in->temp_proc_frames = NULL;
plug_in->plug_in_def = NULL;
}
static void
pika_plug_in_finalize (GObject *object)
{
PikaPlugIn *plug_in = PIKA_PLUG_IN (object);
g_clear_object (&plug_in->file);
pika_plug_in_proc_frame_dispose (&plug_in->main_proc_frame, plug_in);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
pika_plug_in_recv_message (GIOChannel *channel,
GIOCondition cond,
gpointer data)
{
PikaPlugIn *plug_in = data;
gboolean got_message = FALSE;
#ifdef G_OS_WIN32
/* Workaround for GLib bug #137968: sometimes we are called for no
* reason...
*/
if (cond == 0)
return TRUE;
#endif
if (plug_in->my_read == NULL)
return TRUE;
g_object_ref (plug_in);
if (cond & (G_IO_IN | G_IO_PRI))
{
PikaWireMessage msg;
memset (&msg, 0, sizeof (PikaWireMessage));
if (! pika_wire_read_msg (plug_in->my_read, &msg, plug_in))
{
pika_plug_in_close (plug_in, TRUE);
}
else
{
pika_plug_in_handle_message (plug_in, &msg);
pika_wire_destroy (&msg);
got_message = TRUE;
}
}
if (cond & (G_IO_ERR | G_IO_HUP))
{
if (cond & G_IO_HUP)
plug_in->hup = TRUE;
if (plug_in->open)
pika_plug_in_close (plug_in, TRUE);
}
if (! got_message)
{
PikaPlugInProcFrame *frame = pika_plug_in_get_proc_frame (plug_in);
PikaProgress *progress = frame ? frame->progress : NULL;
pika_message (plug_in->manager->pika, G_OBJECT (progress),
PIKA_MESSAGE_ERROR,
_("Plug-in crashed: \"%s\"\n(%s)\n\n"
"The dying plug-in may have messed up PIKA's internal "
"state. You may want to save your images and restart "
"PIKA to be on the safe side."),
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file));
}
g_object_unref (plug_in);
return TRUE;
}
static gboolean
pika_plug_in_write (GIOChannel *channel,
const guint8 *buf,
gulong count,
gpointer data)
{
PikaPlugIn *plug_in = data;
gulong bytes;
while (count > 0)
{
if ((plug_in->write_buffer_index + count) >= WRITE_BUFFER_SIZE)
{
bytes = WRITE_BUFFER_SIZE - plug_in->write_buffer_index;
memcpy (&plug_in->write_buffer[plug_in->write_buffer_index],
buf, bytes);
plug_in->write_buffer_index += bytes;
if (! pika_wire_flush (channel, plug_in))
return FALSE;
}
else
{
bytes = count;
memcpy (&plug_in->write_buffer[plug_in->write_buffer_index],
buf, bytes);
plug_in->write_buffer_index += bytes;
}
buf += bytes;
count -= bytes;
}
return TRUE;
}
static gboolean
pika_plug_in_flush (GIOChannel *channel,
gpointer data)
{
PikaPlugIn *plug_in = data;
if (plug_in->write_buffer_index > 0)
{
GIOStatus status;
GError *error = NULL;
gint count;
gsize bytes;
count = 0;
while (count != plug_in->write_buffer_index)
{
do
{
bytes = 0;
status = g_io_channel_write_chars (channel,
&plug_in->write_buffer[count],
(plug_in->write_buffer_index - count),
&bytes,
&error);
}
while (status == G_IO_STATUS_AGAIN);
if (status != G_IO_STATUS_NORMAL)
{
if (error)
{
g_warning ("%s: plug_in_flush(): error: %s",
pika_filename_to_utf8 (g_get_prgname ()),
error->message);
g_error_free (error);
}
else
{
g_warning ("%s: plug_in_flush(): error",
pika_filename_to_utf8 (g_get_prgname ()));
}
return FALSE;
}
count += bytes;
}
plug_in->write_buffer_index = 0;
}
return TRUE;
}
#if defined G_OS_WIN32 && defined WIN32_32BIT_DLL_FOLDER
static void
pika_plug_in_set_dll_directory (const gchar *path)
{
LPWSTR w_path;
const gchar *install_dir;
gchar *bin_dir;
LPWSTR w_bin_dir;
DWORD BinaryType;
w_path = NULL;
w_bin_dir = NULL;
install_dir = pika_installation_directory ();
if (path &&
(w_path = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL)) &&
GetBinaryTypeW (w_path, &BinaryType) &&
BinaryType == SCS_32BIT_BINARY)
bin_dir = g_build_filename (install_dir, WIN32_32BIT_DLL_FOLDER, NULL);
else
bin_dir = g_build_filename (install_dir, "bin", NULL);
w_bin_dir = g_utf8_to_utf16 (bin_dir, -1, NULL, NULL, NULL);
if (w_bin_dir)
{
SetDllDirectoryW (w_bin_dir);
g_free (w_bin_dir);
}
g_free (bin_dir);
g_free (w_path);
}
#endif
#ifndef G_OS_WIN32
static void
pika_plug_in_close_waitpid (GPid pid,
gint status,
PikaPlugIn *plug_in)
{
GError *error = NULL;
if (plug_in->manager->pika->be_verbose &&
! g_spawn_check_wait_status (status, &error))
{
g_printerr ("Process for plug-in '%s' terminated with error: %s\n",
pika_object_get_name (plug_in),
error->message);
}
g_clear_error (&error);
g_spawn_close_pid (pid);
}
#endif
/* public functions */
PikaPlugIn *
pika_plug_in_new (PikaPlugInManager *manager,
PikaContext *context,
PikaProgress *progress,
PikaPlugInProcedure *procedure,
GFile *file)
{
PikaPlugIn *plug_in;
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), NULL);
g_return_val_if_fail (PIKA_IS_PDB_CONTEXT (context), NULL);
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), NULL);
g_return_val_if_fail (procedure == NULL ||
PIKA_IS_PLUG_IN_PROCEDURE (procedure), NULL);
g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL);
g_return_val_if_fail ((procedure != NULL || file != NULL) &&
! (procedure != NULL && file != NULL), NULL);
plug_in = g_object_new (PIKA_TYPE_PLUG_IN, NULL);
if (! file)
file = pika_plug_in_procedure_get_file (procedure);
pika_object_take_name (PIKA_OBJECT (plug_in),
g_path_get_basename (pika_file_get_utf8_name (file)));
plug_in->manager = manager;
plug_in->file = g_object_ref (file);
pika_plug_in_proc_frame_init (&plug_in->main_proc_frame,
context, progress, procedure);
return plug_in;
}
gboolean
pika_plug_in_open (PikaPlugIn *plug_in,
PikaPlugInCallMode call_mode,
gboolean synchronous)
{
gchar *progname;
gint my_read[2];
gint my_write[2];
gchar **envp;
const gchar *args[10];
gchar **argv;
gint argc;
gchar protocol_version[8];
gchar *interp, *interp_arg;
gchar *his_read_fd, *his_write_fd;
const gchar *mode;
gchar *stm;
GError *error = NULL;
gboolean debug;
guint debug_flag;
guint spawn_flags;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (plug_in->call_mode == PIKA_PLUG_IN_CALL_NONE, FALSE);
/* Open two pipes. (Bidirectional communication).
*/
if ((pipe (my_read) == -1) || (pipe (my_write) == -1))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Unable to run plug-in \"%s\"\n(%s)\n\npipe() failed: %s",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
g_strerror (errno));
return FALSE;
}
#if defined(G_WITH_CYGWIN)
/* Set to binary mode */
setmode (my_read[0], _O_BINARY);
setmode (my_write[0], _O_BINARY);
setmode (my_read[1], _O_BINARY);
setmode (my_write[1], _O_BINARY);
#endif
/* Prevent the plug-in from inheriting our end of the pipes */
pika_spawn_set_cloexec (my_read[0]);
pika_spawn_set_cloexec (my_write[1]);
#ifdef G_OS_WIN32
plug_in->my_read = g_io_channel_win32_new_fd (my_read[0]);
plug_in->my_write = g_io_channel_win32_new_fd (my_write[1]);
plug_in->his_read = g_io_channel_win32_new_fd (my_write[0]);
plug_in->his_write = g_io_channel_win32_new_fd (my_read[1]);
#else
plug_in->my_read = g_io_channel_unix_new (my_read[0]);
plug_in->my_write = g_io_channel_unix_new (my_write[1]);
plug_in->his_read = g_io_channel_unix_new (my_write[0]);
plug_in->his_write = g_io_channel_unix_new (my_read[1]);
#endif
g_io_channel_set_encoding (plug_in->my_read, NULL, NULL);
g_io_channel_set_encoding (plug_in->my_write, NULL, NULL);
g_io_channel_set_encoding (plug_in->his_read, NULL, NULL);
g_io_channel_set_encoding (plug_in->his_write, NULL, NULL);
g_io_channel_set_buffered (plug_in->my_read, FALSE);
g_io_channel_set_buffered (plug_in->my_write, FALSE);
g_io_channel_set_buffered (plug_in->his_read, FALSE);
g_io_channel_set_buffered (plug_in->his_write, FALSE);
g_io_channel_set_close_on_unref (plug_in->my_read, TRUE);
g_io_channel_set_close_on_unref (plug_in->my_write, TRUE);
g_io_channel_set_close_on_unref (plug_in->his_read, TRUE);
g_io_channel_set_close_on_unref (plug_in->his_write, TRUE);
/* Remember the file descriptors for the pipes.
*/
his_read_fd = g_strdup_printf ("%d",
g_io_channel_unix_get_fd (plug_in->his_read));
his_write_fd = g_strdup_printf ("%d",
g_io_channel_unix_get_fd (plug_in->his_write));
switch (call_mode)
{
case PIKA_PLUG_IN_CALL_QUERY:
mode = "-query";
debug_flag = PIKA_DEBUG_WRAP_QUERY;
break;
case PIKA_PLUG_IN_CALL_INIT:
mode = "-init";
debug_flag = PIKA_DEBUG_WRAP_INIT;
break;
case PIKA_PLUG_IN_CALL_RUN:
mode = "-run";
debug_flag = PIKA_DEBUG_WRAP_RUN;
break;
default:
pika_assert_not_reached ();
}
stm = g_strdup_printf ("%d", plug_in->manager->pika->stack_trace_mode);
progname = g_file_get_path (plug_in->file);
interp = pika_interpreter_db_resolve (plug_in->manager->interpreter_db,
progname, &interp_arg);
argc = 0;
if (interp)
args[argc++] = interp;
if (interp_arg)
args[argc++] = interp_arg;
g_snprintf (protocol_version, sizeof (protocol_version),
"%d", PIKA_PROTOCOL_VERSION);
args[argc++] = progname;
args[argc++] = "-pika";
args[argc++] = protocol_version;
args[argc++] = his_read_fd;
args[argc++] = his_write_fd;
args[argc++] = mode;
args[argc++] = stm;
args[argc++] = NULL;
argv = (gchar **) args;
envp = pika_environ_table_get_envp (plug_in->manager->environ_table);
spawn_flags = (G_SPAWN_LEAVE_DESCRIPTORS_OPEN |
G_SPAWN_DO_NOT_REAP_CHILD |
G_SPAWN_CHILD_INHERITS_STDIN);
debug = FALSE;
if (plug_in->manager->debug)
{
gchar **debug_argv = pika_plug_in_debug_argv (plug_in->manager->debug,
progname,
debug_flag, args);
if (debug_argv)
{
debug = TRUE;
argv = debug_argv;
spawn_flags |= G_SPAWN_SEARCH_PATH;
}
}
/* Fork another process. We'll remember the process id so that we
* can later use it to kill the filter if necessary.
*/
#if defined G_OS_WIN32 && defined WIN32_32BIT_DLL_FOLDER
pika_plug_in_set_dll_directory (argv[0]);
#endif
if (! pika_spawn_async (argv, envp, spawn_flags, &plug_in->pid, &error))
{
pika_message (plug_in->manager->pika, NULL, PIKA_MESSAGE_ERROR,
"Unable to run plug-in \"%s\"\n(%s)\n\n%s",
pika_object_get_name (plug_in),
pika_file_get_utf8_name (plug_in->file),
error->message);
g_clear_error (&error);
goto cleanup;
}
g_clear_pointer (&plug_in->his_read, g_io_channel_unref);
g_clear_pointer (&plug_in->his_write, g_io_channel_unref);
if (! synchronous)
{
GSource *source;
source = g_io_create_watch (plug_in->my_read,
G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP);
g_source_set_callback (source,
(GSourceFunc) pika_plug_in_recv_message, plug_in,
NULL);
g_source_set_can_recurse (source, TRUE);
plug_in->input_id = g_source_attach (source, NULL);
g_source_unref (source);
}
plug_in->open = TRUE;
plug_in->call_mode = call_mode;
pika_plug_in_manager_add_open_plug_in (plug_in->manager, plug_in);
cleanup:
#if defined G_OS_WIN32 && defined WIN32_32BIT_DLL_FOLDER
pika_plug_in_set_dll_directory (NULL);
#endif
if (debug)
g_free (argv);
g_free (his_read_fd);
g_free (his_write_fd);
g_free (stm);
g_free (interp);
g_free (interp_arg);
g_free (progname);
return plug_in->open;
}
void
pika_plug_in_close (PikaPlugIn *plug_in,
gboolean kill_it)
{
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
g_return_if_fail (plug_in->open);
plug_in->open = FALSE;
if (plug_in->pid)
{
#ifndef G_OS_WIN32
gint status;
#endif
/* Ask the filter to exit gracefully,
but not if it is closed because of a broken pipe. */
if (kill_it && ! plug_in->hup)
{
gp_quit_write (plug_in->my_write, plug_in);
/* give the plug-in some time (10 ms) */
g_usleep (10000);
}
/* If necessary, kill the filter. */
#ifndef G_OS_WIN32
if (kill_it)
{
if (plug_in->manager->pika->be_verbose)
g_print ("Terminating plug-in: '%s'\n",
pika_file_get_utf8_name (plug_in->file));
/* If the plug-in opened a process group, kill the group instead
* of only the plug-in, so we kill the plug-in's children too
*/
if (getpgid (0) != getpgid (plug_in->pid))
status = kill (- plug_in->pid, SIGKILL);
else
status = kill (plug_in->pid, SIGKILL);
/* Wait for the process to exit. This will happen
* immediately as it was just killed.
*/
waitpid (plug_in->pid, &status, 0);
}
else
{
/*
* If we don't kill it, it means the plug-in ended normally
* hence its process should just return without problem. And
* this is the case nearly all the time. Yet I had this one
* case where the process would never return (even though the
* plug-in returned with a result and no errors) and a
* waitpid() would block the main process forever.
* Thus use instead a child watch source. My idea was that in
* the rare case when the child process doesn't return, it is
* better to leave a zombie than freeze the core. As it turns
* out, doing this even made the broken process exit (does
* g_child_watch_add_full() do something better than
* waitpid()?).
*/
g_object_ref (plug_in);
g_child_watch_add_full (G_PRIORITY_LOW, plug_in->pid,
(GChildWatchFunc) pika_plug_in_close_waitpid,
plug_in, (GDestroyNotify) g_object_unref);
}
#else /* G_OS_WIN32 */
if (kill_it)
{
/* Trying to avoid TerminateProcess (does mostly work).
* Otherwise some of our needed DLLs may get into an
* unstable state (see Win32 API docs).
*/
DWORD dwExitCode = STILL_ACTIVE;
DWORD dwTries = 10;
while (dwExitCode == STILL_ACTIVE &&
GetExitCodeProcess ((HANDLE) plug_in->pid, &dwExitCode) &&
(dwTries > 0))
{
Sleep (10);
dwTries--;
}
if (dwExitCode == STILL_ACTIVE)
{
if (plug_in->manager->pika->be_verbose)
g_print ("Terminating plug-in: '%s'\n",
pika_file_get_utf8_name (plug_in->file));
TerminateProcess ((HANDLE) plug_in->pid, 0);
}
}
g_spawn_close_pid (plug_in->pid);
#endif /* G_OS_WIN32 */
plug_in->pid = 0;
}
/* Remove the input handler. */
if (plug_in->input_id)
{
g_source_remove (plug_in->input_id);
plug_in->input_id = 0;
}
/* Close the pipes. */
g_clear_pointer (&plug_in->my_read, g_io_channel_unref);
g_clear_pointer (&plug_in->my_write, g_io_channel_unref);
g_clear_pointer (&plug_in->his_read, g_io_channel_unref);
g_clear_pointer (&plug_in->his_write, g_io_channel_unref);
pika_wire_clear_error ();
while (plug_in->temp_proc_frames)
{
PikaPlugInProcFrame *proc_frame = plug_in->temp_proc_frames->data;
#ifdef PIKA_UNSTABLE
g_printerr ("plug-in '%s' aborted before sending its "
"temporary procedure return values\n",
pika_object_get_name (plug_in));
#endif
if (proc_frame->main_loop &&
g_main_loop_is_running (proc_frame->main_loop))
{
g_main_loop_quit (proc_frame->main_loop);
}
/* pop the frame here, because normally this only happens in
* pika_plug_in_handle_temp_proc_return(), which can't
* be called after plug_in_close()
*/
pika_plug_in_proc_frame_pop (plug_in);
}
if (plug_in->main_proc_frame.main_loop &&
g_main_loop_is_running (plug_in->main_proc_frame.main_loop))
{
#ifdef PIKA_UNSTABLE
g_printerr ("plug-in '%s' aborted before sending its "
"procedure return values\n",
pika_object_get_name (plug_in));
#endif
g_main_loop_quit (plug_in->main_proc_frame.main_loop);
}
if (plug_in->ext_main_loop &&
g_main_loop_is_running (plug_in->ext_main_loop))
{
#ifdef PIKA_UNSTABLE
g_printerr ("extension '%s' aborted before sending its "
"extension_ack message\n",
pika_object_get_name (plug_in));
#endif
g_main_loop_quit (plug_in->ext_main_loop);
}
/* Unregister any temporary procedures. */
while (plug_in->temp_procedures)
pika_plug_in_remove_temp_proc (plug_in, plug_in->temp_procedures->data);
pika_plug_in_manager_remove_open_plug_in (plug_in->manager, plug_in);
}
PikaPlugInProcFrame *
pika_plug_in_get_proc_frame (PikaPlugIn *plug_in)
{
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), NULL);
if (plug_in->temp_proc_frames)
return plug_in->temp_proc_frames->data;
else
return &plug_in->main_proc_frame;
}
PikaPlugInProcFrame *
pika_plug_in_proc_frame_push (PikaPlugIn *plug_in,
PikaContext *context,
PikaProgress *progress,
PikaTemporaryProcedure *procedure)
{
PikaPlugInProcFrame *proc_frame;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), NULL);
g_return_val_if_fail (PIKA_IS_PDB_CONTEXT (context), NULL);
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), NULL);
g_return_val_if_fail (PIKA_IS_TEMPORARY_PROCEDURE (procedure), NULL);
proc_frame = pika_plug_in_proc_frame_new (context, progress,
PIKA_PLUG_IN_PROCEDURE (procedure));
plug_in->temp_proc_frames = g_list_prepend (plug_in->temp_proc_frames,
proc_frame);
return proc_frame;
}
void
pika_plug_in_proc_frame_pop (PikaPlugIn *plug_in)
{
PikaPlugInProcFrame *proc_frame;
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
g_return_if_fail (plug_in->temp_proc_frames != NULL);
proc_frame = (PikaPlugInProcFrame *) plug_in->temp_proc_frames->data;
pika_plug_in_proc_frame_unref (proc_frame, plug_in);
plug_in->temp_proc_frames = g_list_remove (plug_in->temp_proc_frames,
proc_frame);
}
void
pika_plug_in_main_loop (PikaPlugIn *plug_in)
{
PikaPlugInProcFrame *proc_frame;
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
g_return_if_fail (plug_in->temp_proc_frames != NULL);
proc_frame = (PikaPlugInProcFrame *) plug_in->temp_proc_frames->data;
g_return_if_fail (proc_frame->main_loop == NULL);
proc_frame->main_loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (proc_frame->main_loop);
g_clear_pointer (&proc_frame->main_loop, g_main_loop_unref);
}
void
pika_plug_in_main_loop_quit (PikaPlugIn *plug_in)
{
PikaPlugInProcFrame *proc_frame;
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
g_return_if_fail (plug_in->temp_proc_frames != NULL);
proc_frame = (PikaPlugInProcFrame *) plug_in->temp_proc_frames->data;
g_return_if_fail (proc_frame->main_loop != NULL);
g_main_loop_quit (proc_frame->main_loop);
}
const gchar *
pika_plug_in_get_undo_desc (PikaPlugIn *plug_in)
{
PikaPlugInProcFrame *proc_frame;
const gchar *undo_desc = NULL;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), NULL);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
if (proc_frame && proc_frame->procedure)
undo_desc = pika_procedure_get_label (proc_frame->procedure);
return undo_desc ? undo_desc : pika_object_get_name (plug_in);
}
void
pika_plug_in_add_temp_proc (PikaPlugIn *plug_in,
PikaTemporaryProcedure *proc)
{
PikaPlugInProcedure *overridden;
const gchar *help_domain;
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
g_return_if_fail (PIKA_IS_TEMPORARY_PROCEDURE (proc));
overridden = pika_plug_in_procedure_find (plug_in->temp_procedures,
pika_object_get_name (proc));
if (overridden)
pika_plug_in_remove_temp_proc (plug_in,
PIKA_TEMPORARY_PROCEDURE (overridden));
help_domain = pika_plug_in_manager_get_help_domain (plug_in->manager,
plug_in->file,
NULL);
pika_plug_in_procedure_set_help_domain (PIKA_PLUG_IN_PROCEDURE (proc),
help_domain);
plug_in->temp_procedures = g_slist_prepend (plug_in->temp_procedures,
g_object_ref (proc));
pika_plug_in_manager_add_temp_proc (plug_in->manager, proc);
}
void
pika_plug_in_remove_temp_proc (PikaPlugIn *plug_in,
PikaTemporaryProcedure *proc)
{
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
g_return_if_fail (PIKA_IS_TEMPORARY_PROCEDURE (proc));
plug_in->temp_procedures = g_slist_remove (plug_in->temp_procedures, proc);
pika_plug_in_manager_remove_temp_proc (plug_in->manager, proc);
g_object_unref (proc);
}
void
pika_plug_in_set_error_handler (PikaPlugIn *plug_in,
PikaPDBErrorHandler handler)
{
PikaPlugInProcFrame *proc_frame;
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
proc_frame = pika_plug_in_get_proc_frame (plug_in);
if (proc_frame)
proc_frame->error_handler = handler;
}
PikaPDBErrorHandler
pika_plug_in_get_error_handler (PikaPlugIn *plug_in)
{
PikaPlugInProcFrame *proc_frame;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in),
PIKA_PDB_ERROR_HANDLER_INTERNAL);
proc_frame = pika_plug_in_get_proc_frame (plug_in);
if (proc_frame)
return proc_frame->error_handler;
return PIKA_PDB_ERROR_HANDLER_INTERNAL;
}

123
app/plug-in/pikaplugin.h Normal file
View File

@ -0,0 +1,123 @@
/* 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
*
* pikaplugin.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_H__
#define __PIKA_PLUG_IN_H__
#include "core/pikaobject.h"
#include "pikapluginprocframe.h"
#define WRITE_BUFFER_SIZE 512
#define PIKA_TYPE_PLUG_IN (pika_plug_in_get_type ())
#define PIKA_PLUG_IN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_PLUG_IN, PikaPlugIn))
#define PIKA_PLUG_IN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_PLUG_IN, PikaPlugInClass))
#define PIKA_IS_PLUG_IN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_PLUG_IN))
#define PIKA_IS_PLUG_IN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_PLUG_IN))
typedef struct _PikaPlugInClass PikaPlugInClass;
struct _PikaPlugIn
{
PikaObject parent_instance;
PikaPlugInManager *manager;
GFile *file; /* Plug-in's full path name */
PikaPlugInCallMode call_mode; /* QUERY, INIT or RUN */
guint open : 1; /* Is the plug-in open? */
guint hup : 1; /* Did we receive a G_IO_HUP */
GPid pid; /* Plug-in's process id */
GIOChannel *my_read; /* App's read and write channels */
GIOChannel *my_write;
GIOChannel *his_read; /* Plug-in's read and write channels */
GIOChannel *his_write;
guint input_id; /* Id of input proc */
gchar write_buffer[WRITE_BUFFER_SIZE]; /* Buffer for writing */
gint write_buffer_index; /* Buffer index */
GSList *temp_procedures; /* Temporary procedures */
GMainLoop *ext_main_loop; /* for waiting for extension_ack */
PikaPlugInProcFrame main_proc_frame;
GList *temp_proc_frames;
PikaPlugInDef *plug_in_def; /* Valid during query() and init() */
};
struct _PikaPlugInClass
{
PikaObjectClass parent_class;
};
GType pika_plug_in_get_type (void) G_GNUC_CONST;
PikaPlugIn * pika_plug_in_new (PikaPlugInManager *manager,
PikaContext *context,
PikaProgress *progress,
PikaPlugInProcedure *procedure,
GFile *file);
gboolean pika_plug_in_open (PikaPlugIn *plug_in,
PikaPlugInCallMode call_mode,
gboolean synchronous);
void pika_plug_in_close (PikaPlugIn *plug_in,
gboolean kill_it);
PikaPlugInProcFrame *
pika_plug_in_get_proc_frame (PikaPlugIn *plug_in);
PikaPlugInProcFrame *
pika_plug_in_proc_frame_push (PikaPlugIn *plug_in,
PikaContext *context,
PikaProgress *progress,
PikaTemporaryProcedure *procedure);
void pika_plug_in_proc_frame_pop (PikaPlugIn *plug_in);
void pika_plug_in_main_loop (PikaPlugIn *plug_in);
void pika_plug_in_main_loop_quit (PikaPlugIn *plug_in);
const gchar * pika_plug_in_get_undo_desc (PikaPlugIn *plug_in);
void pika_plug_in_add_temp_proc (PikaPlugIn *plug_in,
PikaTemporaryProcedure *procedure);
void pika_plug_in_remove_temp_proc (PikaPlugIn *plug_in,
PikaTemporaryProcedure *procedure);
void pika_plug_in_set_error_handler (PikaPlugIn *plug_in,
PikaPDBErrorHandler handler);
PikaPDBErrorHandler
pika_plug_in_get_error_handler (PikaPlugIn *plug_in);
#endif /* __PIKA_PLUG_IN_H__ */

View File

@ -0,0 +1,146 @@
/* 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
*
* pikaplugindebug.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <glib-object.h>
#include "plug-in-types.h"
#include "pikaplugindebug.h"
struct _PikaPlugInDebug
{
gchar *name;
guint flags;
gchar **args;
};
static const GDebugKey pika_debug_wrap_keys[] =
{
{ "query", PIKA_DEBUG_WRAP_QUERY },
{ "init", PIKA_DEBUG_WRAP_INIT },
{ "run", PIKA_DEBUG_WRAP_RUN },
{ "on", PIKA_DEBUG_WRAP_DEFAULT }
};
PikaPlugInDebug *
pika_plug_in_debug_new (void)
{
PikaPlugInDebug *debug;
const gchar *wrap, *wrapper;
gchar *debug_string;
gchar **args;
GError *error = NULL;
wrap = g_getenv ("PIKA_PLUGIN_DEBUG_WRAP");
wrapper = g_getenv ("PIKA_PLUGIN_DEBUG_WRAPPER");
if (!(wrap && wrapper))
return NULL;
if (!g_shell_parse_argv (wrapper, NULL, &args, &error))
{
g_warning ("Unable to parse debug wrapper: \"%s\"\n%s",
wrapper, error->message);
g_error_free (error);
return NULL;
}
debug = g_slice_new (PikaPlugInDebug);
debug->args = args;
debug_string = strchr (wrap, ',');
if (debug_string)
{
debug->name = g_strndup (wrap, debug_string - wrap);
debug->flags = g_parse_debug_string (debug_string + 1,
pika_debug_wrap_keys,
G_N_ELEMENTS (pika_debug_wrap_keys));
}
else
{
debug->name = g_strdup (wrap);
debug->flags = PIKA_DEBUG_WRAP_DEFAULT;
}
return debug;
}
void
pika_plug_in_debug_free (PikaPlugInDebug *debug)
{
g_return_if_fail (debug != NULL);
if (debug->name)
g_free (debug->name);
if (debug->args)
g_strfreev (debug->args);
g_slice_free (PikaPlugInDebug, debug);
}
gchar **
pika_plug_in_debug_argv (PikaPlugInDebug *debug,
const gchar *name,
PikaDebugWrapFlag flag,
const gchar **args)
{
GPtrArray *argv;
gchar **arg;
gchar *basename;
g_return_val_if_fail (debug != NULL, NULL);
g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (args != NULL, NULL);
basename = g_path_get_basename (name);
if (!(debug->flags & flag) || (strcmp (debug->name, basename) != 0))
{
g_free (basename);
return NULL;
}
g_free (basename);
argv = g_ptr_array_sized_new (8);
for (arg = debug->args; *arg != NULL; arg++)
g_ptr_array_add (argv, *arg);
for (arg = (gchar **) args; *arg != NULL; arg++)
g_ptr_array_add (argv, *arg);
g_ptr_array_add (argv, NULL);
return (gchar **) g_ptr_array_free (argv, FALSE);
}

View File

@ -0,0 +1,47 @@
/* 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
*
* pikaplugindebug.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_DEBUG_H__
#define __PIKA_PLUG_IN_DEBUG_H__
typedef enum
{
PIKA_DEBUG_WRAP_QUERY = 1 << 0,
PIKA_DEBUG_WRAP_INIT = 1 << 1,
PIKA_DEBUG_WRAP_RUN = 1 << 2,
PIKA_DEBUG_WRAP_DEFAULT = PIKA_DEBUG_WRAP_RUN
} PikaDebugWrapFlag;
PikaPlugInDebug * pika_plug_in_debug_new (void);
void pika_plug_in_debug_free (PikaPlugInDebug *debug);
gchar ** pika_plug_in_debug_argv (PikaPlugInDebug *debug,
const gchar *name,
PikaDebugWrapFlag flag,
const gchar **args);
#endif /* __PIKA_PLUG_IN_DEBUG_H__ */

207
app/plug-in/pikaplugindef.c Normal file
View File

@ -0,0 +1,207 @@
/* 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
*
* pikaplugindef.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "plug-in-types.h"
#include "core/pika-memsize.h"
#include "pikaplugindef.h"
#include "pikapluginprocedure.h"
static void pika_plug_in_def_finalize (GObject *object);
static gint64 pika_plug_in_def_get_memsize (PikaObject *object,
gint64 *gui_size);
G_DEFINE_TYPE (PikaPlugInDef, pika_plug_in_def, PIKA_TYPE_OBJECT)
#define parent_class pika_plug_in_def_parent_class
static void
pika_plug_in_def_class_init (PikaPlugInDefClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaObjectClass *pika_object_class = PIKA_OBJECT_CLASS (klass);
object_class->finalize = pika_plug_in_def_finalize;
pika_object_class->get_memsize = pika_plug_in_def_get_memsize;
}
static void
pika_plug_in_def_init (PikaPlugInDef *def)
{
}
static void
pika_plug_in_def_finalize (GObject *object)
{
PikaPlugInDef *plug_in_def = PIKA_PLUG_IN_DEF (object);
g_object_unref (plug_in_def->file);
g_free (plug_in_def->help_domain_name);
g_free (plug_in_def->help_domain_uri);
g_slist_free_full (plug_in_def->procedures, (GDestroyNotify) g_object_unref);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gint64
pika_plug_in_def_get_memsize (PikaObject *object,
gint64 *gui_size)
{
PikaPlugInDef *plug_in_def = PIKA_PLUG_IN_DEF (object);
gint64 memsize = 0;
memsize += pika_g_object_get_memsize (G_OBJECT (plug_in_def->file));
memsize += pika_string_get_memsize (plug_in_def->help_domain_name);
memsize += pika_string_get_memsize (plug_in_def->help_domain_uri);
memsize += pika_g_slist_get_memsize (plug_in_def->procedures, 0);
return memsize + PIKA_OBJECT_CLASS (parent_class)->get_memsize (object,
gui_size);
}
/* public functions */
PikaPlugInDef *
pika_plug_in_def_new (GFile *file)
{
PikaPlugInDef *plug_in_def;
g_return_val_if_fail (G_IS_FILE (file), NULL);
plug_in_def = g_object_new (PIKA_TYPE_PLUG_IN_DEF, NULL);
plug_in_def->file = g_object_ref (file);
return plug_in_def;
}
void
pika_plug_in_def_add_procedure (PikaPlugInDef *plug_in_def,
PikaPlugInProcedure *proc)
{
PikaPlugInProcedure *overridden;
g_return_if_fail (PIKA_IS_PLUG_IN_DEF (plug_in_def));
g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc));
overridden = pika_plug_in_procedure_find (plug_in_def->procedures,
pika_object_get_name (proc));
if (overridden)
pika_plug_in_def_remove_procedure (plug_in_def, overridden);
proc->mtime = plug_in_def->mtime;
pika_plug_in_procedure_set_help_domain (proc,
plug_in_def->help_domain_name);
plug_in_def->procedures = g_slist_append (plug_in_def->procedures,
g_object_ref (proc));
}
void
pika_plug_in_def_remove_procedure (PikaPlugInDef *plug_in_def,
PikaPlugInProcedure *proc)
{
g_return_if_fail (PIKA_IS_PLUG_IN_DEF (plug_in_def));
g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc));
plug_in_def->procedures = g_slist_remove (plug_in_def->procedures, proc);
g_object_unref (proc);
}
void
pika_plug_in_def_set_help_domain (PikaPlugInDef *plug_in_def,
const gchar *domain_name,
const gchar *domain_uri)
{
GSList *list;
g_return_if_fail (PIKA_IS_PLUG_IN_DEF (plug_in_def));
if (plug_in_def->help_domain_name)
g_free (plug_in_def->help_domain_name);
plug_in_def->help_domain_name = g_strdup (domain_name);
if (plug_in_def->help_domain_uri)
g_free (plug_in_def->help_domain_uri);
plug_in_def->help_domain_uri = g_strdup (domain_uri);
for (list = plug_in_def->procedures; list; list = g_slist_next (list))
{
PikaPlugInProcedure *procedure = list->data;
pika_plug_in_procedure_set_help_domain (procedure,
plug_in_def->help_domain_name);
}
}
void
pika_plug_in_def_set_mtime (PikaPlugInDef *plug_in_def,
gint64 mtime)
{
GSList *list;
g_return_if_fail (PIKA_IS_PLUG_IN_DEF (plug_in_def));
plug_in_def->mtime = mtime;
for (list = plug_in_def->procedures; list; list = g_slist_next (list))
{
PikaPlugInProcedure *proc = list->data;
proc->mtime = plug_in_def->mtime;
}
}
void
pika_plug_in_def_set_needs_query (PikaPlugInDef *plug_in_def,
gboolean needs_query)
{
g_return_if_fail (PIKA_IS_PLUG_IN_DEF (plug_in_def));
plug_in_def->needs_query = needs_query ? TRUE : FALSE;
}
void
pika_plug_in_def_set_has_init (PikaPlugInDef *plug_in_def,
gboolean has_init)
{
g_return_if_fail (PIKA_IS_PLUG_IN_DEF (plug_in_def));
plug_in_def->has_init = has_init ? TRUE : FALSE;
}

View File

@ -0,0 +1,80 @@
/* 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
*
* pikaplugindef.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_DEF_H__
#define __PIKA_PLUG_IN_DEF_H__
#include "core/pikaobject.h"
#define PIKA_TYPE_PLUG_IN_DEF (pika_plug_in_def_get_type ())
#define PIKA_PLUG_IN_DEF(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_PLUG_IN_DEF, PikaPlugInDef))
#define PIKA_PLUG_IN_DEF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_PLUG_IN_DEF, PikaPlugInDefClass))
#define PIKA_IS_PLUG_IN_DEF(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_PLUG_IN_DEF))
#define PIKA_IS_PLUG_IN_DEF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_PLUG_IN_DEF))
typedef struct _PikaPlugInDefClass PikaPlugInDefClass;
struct _PikaPlugInDef
{
PikaObject parent_instance;
GFile *file;
GSList *procedures;
gchar *help_domain_name;
gchar *help_domain_uri;
gint64 mtime;
gboolean needs_query; /* Does the plug-in need to be queried ? */
gboolean has_init; /* Does the plug-in need to be initialized ? */
};
struct _PikaPlugInDefClass
{
PikaObjectClass parent_class;
};
GType pika_plug_in_def_get_type (void) G_GNUC_CONST;
PikaPlugInDef * pika_plug_in_def_new (GFile *file);
void pika_plug_in_def_add_procedure (PikaPlugInDef *plug_in_def,
PikaPlugInProcedure *proc);
void pika_plug_in_def_remove_procedure (PikaPlugInDef *plug_in_def,
PikaPlugInProcedure *proc);
void pika_plug_in_def_set_help_domain (PikaPlugInDef *plug_in_def,
const gchar *domain_name,
const gchar *domain_uri);
void pika_plug_in_def_set_mtime (PikaPlugInDef *plug_in_def,
gint64 mtime);
void pika_plug_in_def_set_needs_query (PikaPlugInDef *plug_in_def,
gboolean needs_query);
void pika_plug_in_def_set_has_init (PikaPlugInDef *plug_in_def,
gboolean has_init);
#endif /* __PIKA_PLUG_IN_DEF_H__ */

View File

@ -0,0 +1,40 @@
/* 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
*
* 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 <glib-object.h>
#include "pikapluginerror.h"
/**
* pika_plug_in_error_quark:
*
* This function is never called directly. Use PIKA_PLUG_IN_ERROR() instead.
*
* Returns: the #GQuark that defines the PikaPlugIn error domain.
**/
GQuark
pika_plug_in_error_quark (void)
{
return g_quark_from_static_string ("pika-plug-in-error-quark");
}

View File

@ -0,0 +1,39 @@
/* 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
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_ERROR_H__
#define __PIKA_PLUG_IN_ERROR_H__
typedef enum
{
PIKA_PLUG_IN_FAILED, /* generic error condition */
PIKA_PLUG_IN_EXECUTION_FAILED,
PIKA_PLUG_IN_NOT_FOUND
} PikaPlugInErrorCode;
#define PIKA_PLUG_IN_ERROR (pika_plug_in_error_quark ())
GQuark pika_plug_in_error_quark (void) G_GNUC_CONST;
#endif /* __PIKA_PLUG_IN_ERROR_H__ */

View File

@ -0,0 +1,385 @@
/* 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
*
* pikapluginmanager-call.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#ifdef G_OS_WIN32
#include <windows.h>
#endif
#include "libpikabase/pikabase.h"
#include "libpikabase/pikaprotocol.h"
#include "libpikabase/pikawire.h"
#include "libpika/pikagpparams.h"
#include "plug-in-types.h"
#include "config/pikaguiconfig.h"
#include "core/pika.h"
#include "core/pikadisplay.h"
#include "core/pikaprogress.h"
#include "pdb/pikapdbcontext.h"
#include "pikaplugin.h"
#include "pikaplugin-message.h"
#include "pikaplugindef.h"
#include "pikapluginerror.h"
#include "pikapluginmanager.h"
#define __YES_I_NEED_PIKA_PLUG_IN_MANAGER_CALL__
#include "pikapluginmanager-call.h"
#include "pikapluginshm.h"
#include "pikatemporaryprocedure.h"
#include "pika-intl.h"
static void
pika_allow_set_foreground_window (PikaPlugIn *plug_in)
{
#ifdef G_OS_WIN32
AllowSetForegroundWindow (GetProcessId (plug_in->pid));
#endif
}
/* public functions */
void
pika_plug_in_manager_call_query (PikaPlugInManager *manager,
PikaContext *context,
PikaPlugInDef *plug_in_def)
{
PikaPlugIn *plug_in;
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (PIKA_IS_PDB_CONTEXT (context));
g_return_if_fail (PIKA_IS_PLUG_IN_DEF (plug_in_def));
plug_in = pika_plug_in_new (manager, context, NULL,
NULL, plug_in_def->file);
if (plug_in)
{
plug_in->plug_in_def = plug_in_def;
if (pika_plug_in_open (plug_in, PIKA_PLUG_IN_CALL_QUERY, TRUE))
{
while (plug_in->open)
{
PikaWireMessage msg;
if (! pika_wire_read_msg (plug_in->my_read, &msg, plug_in))
{
pika_plug_in_close (plug_in, TRUE);
}
else
{
pika_plug_in_handle_message (plug_in, &msg);
pika_wire_destroy (&msg);
}
}
}
g_object_unref (plug_in);
}
}
void
pika_plug_in_manager_call_init (PikaPlugInManager *manager,
PikaContext *context,
PikaPlugInDef *plug_in_def)
{
PikaPlugIn *plug_in;
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (PIKA_IS_PDB_CONTEXT (context));
g_return_if_fail (PIKA_IS_PLUG_IN_DEF (plug_in_def));
plug_in = pika_plug_in_new (manager, context, NULL,
NULL, plug_in_def->file);
if (plug_in)
{
plug_in->plug_in_def = plug_in_def;
if (pika_plug_in_open (plug_in, PIKA_PLUG_IN_CALL_INIT, TRUE))
{
while (plug_in->open)
{
PikaWireMessage msg;
if (! pika_wire_read_msg (plug_in->my_read, &msg, plug_in))
{
pika_plug_in_close (plug_in, TRUE);
}
else
{
pika_plug_in_handle_message (plug_in, &msg);
pika_wire_destroy (&msg);
}
}
}
g_object_unref (plug_in);
}
}
PikaValueArray *
pika_plug_in_manager_call_run (PikaPlugInManager *manager,
PikaContext *context,
PikaProgress *progress,
PikaPlugInProcedure *procedure,
PikaValueArray *args,
gboolean synchronous,
PikaDisplay *display)
{
PikaValueArray *return_vals = NULL;
PikaPlugIn *plug_in;
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), NULL);
g_return_val_if_fail (PIKA_IS_PDB_CONTEXT (context), NULL);
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), NULL);
g_return_val_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (procedure), NULL);
g_return_val_if_fail (args != NULL, NULL);
g_return_val_if_fail (display == NULL || PIKA_IS_DISPLAY (display), NULL);
plug_in = pika_plug_in_new (manager, context, progress, procedure, NULL);
if (plug_in)
{
PikaCoreConfig *core_config = manager->pika->config;
PikaGeglConfig *gegl_config = PIKA_GEGL_CONFIG (core_config);
PikaDisplayConfig *display_config = PIKA_DISPLAY_CONFIG (core_config);
PikaGuiConfig *gui_config = PIKA_GUI_CONFIG (core_config);
GPConfig config;
GPProcRun proc_run;
gint display_id;
GObject *monitor;
GFile *icon_theme_dir;
if (! pika_plug_in_open (plug_in, PIKA_PLUG_IN_CALL_RUN, FALSE))
{
const gchar *name = pika_object_get_name (plug_in);
GError *error = g_error_new (PIKA_PLUG_IN_ERROR,
PIKA_PLUG_IN_EXECUTION_FAILED,
_("Failed to run plug-in \"%s\""),
name);
g_object_unref (plug_in);
return_vals = pika_procedure_get_return_values (PIKA_PROCEDURE (procedure),
FALSE, error);
g_error_free (error);
return return_vals;
}
if (! display)
display = pika_context_get_display (context);
display_id = display ? pika_display_get_id (display) : -1;
icon_theme_dir = pika_get_icon_theme_dir (manager->pika);
config.tile_width = PIKA_PLUG_IN_TILE_WIDTH;
config.tile_height = PIKA_PLUG_IN_TILE_HEIGHT;
config.shm_id = (manager->shm ?
pika_plug_in_shm_get_id (manager->shm) :
-1);
config.check_size = display_config->transparency_size;
config.check_type = display_config->transparency_type;
config.check_custom_color1 = display_config->transparency_custom_color1;
config.check_custom_color2 = display_config->transparency_custom_color2;
config.show_help_button = (gui_config->use_help &&
gui_config->show_help_button);
config.use_cpu_accel = manager->pika->use_cpu_accel;
config.use_opencl = gegl_config->use_opencl;
config.export_color_profile = core_config->export_color_profile;
config.export_comment = core_config->export_comment;
config.export_exif = core_config->export_metadata_exif;
config.export_xmp = core_config->export_metadata_xmp;
config.export_iptc = core_config->export_metadata_iptc;
config.default_display_id = display_id;
config.app_name = (gchar *) g_get_application_name ();
config.wm_class = (gchar *) pika_get_program_class (manager->pika);
config.display_name = pika_get_display_name (manager->pika,
display_id,
&monitor,
&config.monitor_number);
config.timestamp = pika_get_user_time (manager->pika);
config.icon_theme_dir = (icon_theme_dir ?
g_file_get_path (icon_theme_dir) :
NULL);
config.tile_cache_size = gegl_config->tile_cache_size;
config.swap_path = gegl_config->swap_path;
config.swap_compression = gegl_config->swap_compression;
config.num_processors = gegl_config->num_processors;
proc_run.name = (gchar *) pika_object_get_name (procedure);
proc_run.n_params = pika_value_array_length (args);
proc_run.params = _pika_value_array_to_gp_params (args, FALSE);
if (! gp_config_write (plug_in->my_write, &config, plug_in) ||
! gp_proc_run_write (plug_in->my_write, &proc_run, plug_in) ||
! pika_wire_flush (plug_in->my_write, plug_in))
{
const gchar *name = pika_object_get_name (plug_in);
GError *error = g_error_new (PIKA_PLUG_IN_ERROR,
PIKA_PLUG_IN_EXECUTION_FAILED,
_("Failed to run plug-in \"%s\""),
name);
g_free (config.display_name);
g_free (config.icon_theme_dir);
_pika_gp_params_free (proc_run.params, proc_run.n_params, FALSE);
g_object_unref (plug_in);
return_vals = pika_procedure_get_return_values (PIKA_PROCEDURE (procedure),
FALSE, error);
g_error_free (error);
return return_vals;
}
g_free (config.display_name);
g_free (config.icon_theme_dir);
_pika_gp_params_free (proc_run.params, proc_run.n_params, FALSE);
/* If this is an extension,
* wait for an installation-confirmation message
*/
if (PIKA_PROCEDURE (procedure)->proc_type == PIKA_PDB_PROC_TYPE_EXTENSION)
{
plug_in->ext_main_loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (plug_in->ext_main_loop);
/* main_loop is quit in pika_plug_in_handle_extension_ack() */
g_clear_pointer (&plug_in->ext_main_loop, g_main_loop_unref);
}
/* If this plug-in is requested to run synchronously,
* wait for its return values
*/
if (synchronous)
{
PikaPlugInProcFrame *proc_frame = &plug_in->main_proc_frame;
proc_frame->main_loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (proc_frame->main_loop);
/* main_loop is quit in pika_plug_in_handle_proc_return() */
g_clear_pointer (&proc_frame->main_loop, g_main_loop_unref);
return_vals = pika_plug_in_proc_frame_get_return_values (proc_frame);
}
g_object_unref (plug_in);
}
return return_vals;
}
PikaValueArray *
pika_plug_in_manager_call_run_temp (PikaPlugInManager *manager,
PikaContext *context,
PikaProgress *progress,
PikaTemporaryProcedure *procedure,
PikaValueArray *args)
{
PikaValueArray *return_vals = NULL;
PikaPlugIn *plug_in;
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), NULL);
g_return_val_if_fail (PIKA_IS_PDB_CONTEXT (context), NULL);
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), NULL);
g_return_val_if_fail (PIKA_IS_TEMPORARY_PROCEDURE (procedure), NULL);
g_return_val_if_fail (args != NULL, NULL);
plug_in = procedure->plug_in;
if (plug_in)
{
PikaPlugInProcFrame *proc_frame;
GPProcRun proc_run;
proc_frame = pika_plug_in_proc_frame_push (plug_in, context, progress,
procedure);
proc_run.name = (gchar *) pika_object_get_name (procedure);
proc_run.n_params = pika_value_array_length (args);
proc_run.params = _pika_value_array_to_gp_params (args, FALSE);
if (! gp_temp_proc_run_write (plug_in->my_write, &proc_run, plug_in) ||
! pika_wire_flush (plug_in->my_write, plug_in))
{
const gchar *name = pika_object_get_name (plug_in);
GError *error = g_error_new (PIKA_PLUG_IN_ERROR,
PIKA_PLUG_IN_EXECUTION_FAILED,
_("Failed to run plug-in \"%s\""),
name);
_pika_gp_params_free (proc_run.params, proc_run.n_params, FALSE);
pika_plug_in_proc_frame_pop (plug_in);
return_vals = pika_procedure_get_return_values (PIKA_PROCEDURE (procedure),
FALSE, error);
g_error_free (error);
return return_vals;
}
pika_allow_set_foreground_window (plug_in);
_pika_gp_params_free (proc_run.params, proc_run.n_params, FALSE);
g_object_ref (plug_in);
pika_plug_in_proc_frame_ref (proc_frame);
pika_plug_in_main_loop (plug_in);
/* main_loop is quit and proc_frame is popped in
* pika_plug_in_handle_temp_proc_return()
*/
return_vals = pika_plug_in_proc_frame_get_return_values (proc_frame);
pika_plug_in_proc_frame_unref (proc_frame, plug_in);
g_object_unref (plug_in);
}
return return_vals;
}

View File

@ -0,0 +1,63 @@
/* 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
*
* pikapluginmanager-call.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_MANAGER_CALL_H__
#define __PIKA_PLUG_IN_MANAGER_CALL_H__
#ifndef __YES_I_NEED_PIKA_PLUG_IN_MANAGER_CALL__
#error Do not use pika_plug_in_manager_call_run*(), use pika_procedure_execute*() instead.
#endif
/* Call the plug-in's query() function
*/
void pika_plug_in_manager_call_query (PikaPlugInManager *manager,
PikaContext *context,
PikaPlugInDef *plug_in_def);
/* Call the plug-in's init() function
*/
void pika_plug_in_manager_call_init (PikaPlugInManager *manager,
PikaContext *context,
PikaPlugInDef *plug_in_def);
/* Run a plug-in as if it were a procedure database procedure
*/
PikaValueArray * pika_plug_in_manager_call_run (PikaPlugInManager *manager,
PikaContext *context,
PikaProgress *progress,
PikaPlugInProcedure *procedure,
PikaValueArray *args,
gboolean synchronous,
PikaDisplay *display);
/* Run a temp plug-in proc as if it were a procedure database procedure
*/
PikaValueArray * pika_plug_in_manager_call_run_temp (PikaPlugInManager *manager,
PikaContext *context,
PikaProgress *progress,
PikaTemporaryProcedure *procedure,
PikaValueArray *args);
#endif /* __PIKA_PLUG_IN_MANAGER_CALL_H__ */

View File

@ -0,0 +1,137 @@
/* 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
*
* pikapluginmanager-data.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gio/gio.h>
#include "plug-in-types.h"
#include "pikapluginmanager.h"
#include "pikapluginmanager-data.h"
typedef struct _PikaPlugInData PikaPlugInData;
struct _PikaPlugInData
{
gchar *identifier;
gint32 bytes;
guint8 *data;
};
/* public functions */
void
pika_plug_in_manager_data_free (PikaPlugInManager *manager)
{
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
if (manager->data_list)
{
GList *list;
for (list = manager->data_list;
list;
list = g_list_next (list))
{
PikaPlugInData *data = list->data;
g_free (data->identifier);
g_free (data->data);
g_slice_free (PikaPlugInData, data);
}
g_list_free (manager->data_list);
manager->data_list = NULL;
}
}
void
pika_plug_in_manager_set_data (PikaPlugInManager *manager,
const gchar *identifier,
gint32 bytes,
const guint8 *data)
{
PikaPlugInData *plug_in_data;
GList *list;
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (identifier != NULL);
g_return_if_fail (bytes > 0);
g_return_if_fail (data != NULL);
for (list = manager->data_list; list; list = g_list_next (list))
{
plug_in_data = list->data;
if (! strcmp (plug_in_data->identifier, identifier))
break;
}
/* If there isn't already data with the specified identifier, create one */
if (list == NULL)
{
plug_in_data = g_slice_new0 (PikaPlugInData);
plug_in_data->identifier = g_strdup (identifier);
manager->data_list = g_list_prepend (manager->data_list, plug_in_data);
}
else
{
g_free (plug_in_data->data);
}
plug_in_data->bytes = bytes;
plug_in_data->data = g_memdup2 (data, bytes);
}
const guint8 *
pika_plug_in_manager_get_data (PikaPlugInManager *manager,
const gchar *identifier,
gint32 *bytes)
{
GList *list;
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), NULL);
g_return_val_if_fail (identifier != NULL, NULL);
g_return_val_if_fail (bytes != NULL, NULL);
*bytes = 0;
for (list = manager->data_list; list; list = g_list_next (list))
{
PikaPlugInData *plug_in_data = list->data;
if (! strcmp (plug_in_data->identifier, identifier))
{
*bytes = plug_in_data->bytes;
return plug_in_data->data;
}
}
return NULL;
}

View File

@ -0,0 +1,39 @@
/* 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
*
* pikapluginmanager-data.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_MANAGER_DATA_H__
#define __PIKA_PLUG_IN_MANAGER_DATA_H__
void pika_plug_in_manager_data_free (PikaPlugInManager *manager);
void pika_plug_in_manager_set_data (PikaPlugInManager *manager,
const gchar *identifier,
gint32 bytes,
const guint8 *data);
const guint8 * pika_plug_in_manager_get_data (PikaPlugInManager *manager,
const gchar *identifier,
gint32 *bytes);
#endif /* __PIKA_PLUG_IN_MANAGER_DATA_H__ */

View File

@ -0,0 +1,908 @@
/* 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
*
* pikapluginmanager-file.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <errno.h>
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "plug-in-types.h"
#include "core/pika.h"
#include "core/pika-utils.h"
#include "pikaplugin.h"
#include "pikaplugindef.h"
#include "pikapluginmanager.h"
#include "pikapluginmanager-file.h"
#include "pikapluginprocedure.h"
#include "pika-log.h"
#include "pika-intl.h"
#ifdef G_OS_WIN32
#include <stdlib.h>
#endif
typedef enum
{
/* positive values indicate the length of a matching magic */
FILE_MATCH_NONE = 0,
FILE_MATCH_SIZE = -1
} FileMatchType;
/* local function prototypes */
static gboolean file_proc_in_group (PikaPlugInProcedure *file_proc,
PikaFileProcedureGroup group);
static PikaPlugInProcedure * file_proc_find (GSList *procs,
GFile *file,
GError **error);
static PikaPlugInProcedure * file_proc_find_by_prefix (GSList *procs,
GFile *file,
gboolean skip_magic);
static PikaPlugInProcedure * file_proc_find_by_extension (GSList *procs,
GFile *file,
gboolean skip_magic);
static PikaPlugInProcedure * file_proc_find_by_mime_type (GSList *procs,
const gchar *mime_type);
static PikaPlugInProcedure * file_proc_find_by_name (GSList *procs,
GFile *file,
gboolean skip_magic);
static void file_convert_string (const gchar *instr,
gchar *outmem,
gint maxmem,
gint *nmem);
static FileMatchType file_check_single_magic (const gchar *offset,
const gchar *type,
const gchar *value,
const guchar *file_head,
gint headsize,
GFile *file,
GInputStream *input);
static FileMatchType file_check_magic_list (GSList *magics_list,
const guchar *head,
gint headsize,
GFile *file,
GInputStream *input);
/* public functions */
void
pika_plug_in_manager_add_load_procedure (PikaPlugInManager *manager,
PikaPlugInProcedure *proc)
{
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc));
if (! g_slist_find (manager->load_procs, proc))
manager->load_procs = g_slist_prepend (manager->load_procs, proc);
}
void
pika_plug_in_manager_add_save_procedure (PikaPlugInManager *manager,
PikaPlugInProcedure *proc)
{
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc));
if (file_proc_in_group (proc, PIKA_FILE_PROCEDURE_GROUP_SAVE))
{
if (! g_slist_find (manager->save_procs, proc))
manager->save_procs = g_slist_prepend (manager->save_procs, proc);
}
if (file_proc_in_group (proc, PIKA_FILE_PROCEDURE_GROUP_EXPORT))
{
if (! g_slist_find (manager->export_procs, proc))
manager->export_procs = g_slist_prepend (manager->export_procs, proc);
}
}
GSList *
pika_plug_in_manager_get_file_procedures (PikaPlugInManager *manager,
PikaFileProcedureGroup group)
{
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), NULL);
switch (group)
{
case PIKA_FILE_PROCEDURE_GROUP_NONE:
return NULL;
case PIKA_FILE_PROCEDURE_GROUP_OPEN:
return manager->display_load_procs;
case PIKA_FILE_PROCEDURE_GROUP_SAVE:
return manager->display_save_procs;
case PIKA_FILE_PROCEDURE_GROUP_EXPORT:
return manager->display_export_procs;
default:
g_return_val_if_reached (NULL);
}
}
PikaPlugInProcedure *
pika_plug_in_manager_file_procedure_find (PikaPlugInManager *manager,
PikaFileProcedureGroup group,
GFile *file,
GError **error)
{
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), NULL);
g_return_val_if_fail (G_IS_FILE (file), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
switch (group)
{
case PIKA_FILE_PROCEDURE_GROUP_OPEN:
return file_proc_find (manager->load_procs, file, error);
case PIKA_FILE_PROCEDURE_GROUP_SAVE:
return file_proc_find (manager->save_procs, file, error);
case PIKA_FILE_PROCEDURE_GROUP_EXPORT:
return file_proc_find (manager->export_procs, file, error);
default:
g_return_val_if_reached (NULL);
}
}
PikaPlugInProcedure *
pika_plug_in_manager_file_procedure_find_by_prefix (PikaPlugInManager *manager,
PikaFileProcedureGroup group,
GFile *file)
{
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), NULL);
g_return_val_if_fail (G_IS_FILE (file), NULL);
switch (group)
{
case PIKA_FILE_PROCEDURE_GROUP_OPEN:
return file_proc_find_by_prefix (manager->load_procs, file, FALSE);
case PIKA_FILE_PROCEDURE_GROUP_SAVE:
return file_proc_find_by_prefix (manager->save_procs, file, FALSE);
case PIKA_FILE_PROCEDURE_GROUP_EXPORT:
return file_proc_find_by_prefix (manager->export_procs, file, FALSE);
default:
g_return_val_if_reached (NULL);
}
}
PikaPlugInProcedure *
pika_plug_in_manager_file_procedure_find_by_extension (PikaPlugInManager *manager,
PikaFileProcedureGroup group,
GFile *file)
{
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), NULL);
g_return_val_if_fail (G_IS_FILE (file), NULL);
switch (group)
{
case PIKA_FILE_PROCEDURE_GROUP_OPEN:
return file_proc_find_by_extension (manager->load_procs, file, FALSE);
case PIKA_FILE_PROCEDURE_GROUP_SAVE:
return file_proc_find_by_extension (manager->save_procs, file, FALSE);
case PIKA_FILE_PROCEDURE_GROUP_EXPORT:
return file_proc_find_by_extension (manager->export_procs, file, FALSE);
default:
g_return_val_if_reached (NULL);
}
}
PikaPlugInProcedure *
pika_plug_in_manager_file_procedure_find_by_mime_type (PikaPlugInManager *manager,
PikaFileProcedureGroup group,
const gchar *mime_type)
{
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), NULL);
g_return_val_if_fail (mime_type != NULL, NULL);
switch (group)
{
case PIKA_FILE_PROCEDURE_GROUP_OPEN:
return file_proc_find_by_mime_type (manager->load_procs, mime_type);
case PIKA_FILE_PROCEDURE_GROUP_SAVE:
return file_proc_find_by_mime_type (manager->save_procs, mime_type);
case PIKA_FILE_PROCEDURE_GROUP_EXPORT:
return file_proc_find_by_mime_type (manager->export_procs, mime_type);
default:
g_return_val_if_reached (NULL);
}
}
/* private functions */
static gboolean
file_proc_in_group (PikaPlugInProcedure *file_proc,
PikaFileProcedureGroup group)
{
const gchar *name = pika_object_get_name (file_proc);
gboolean is_xcf_save = FALSE;
gboolean is_filter = FALSE;
is_xcf_save = (strcmp (name, "pika-xcf-save") == 0);
is_filter = (strcmp (name, "file-gz-save") == 0 ||
strcmp (name, "file-bz2-save") == 0 ||
strcmp (name, "file-xz-save") == 0);
switch (group)
{
case PIKA_FILE_PROCEDURE_GROUP_NONE:
return FALSE;
case PIKA_FILE_PROCEDURE_GROUP_SAVE:
/* Only .xcf shall pass */
return is_xcf_save || is_filter;
case PIKA_FILE_PROCEDURE_GROUP_EXPORT:
/* Anything but .xcf shall pass */
return ! is_xcf_save;
case PIKA_FILE_PROCEDURE_GROUP_OPEN:
/* No filter applied for Open */
return TRUE;
default:
case PIKA_FILE_PROCEDURE_GROUP_ANY:
return TRUE;
}
}
static PikaPlugInProcedure *
file_proc_find (GSList *procs,
GFile *file,
GError **error)
{
PikaPlugInProcedure *file_proc;
PikaPlugInProcedure *size_matched_proc = NULL;
gint size_match_count = 0;
g_return_val_if_fail (procs != NULL, NULL);
g_return_val_if_fail (G_IS_FILE (file), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
/* First, check magicless prefixes/suffixes */
file_proc = file_proc_find_by_name (procs, file, TRUE);
if (file_proc)
return file_proc;
/* Then look for magics, but not on remote files */
if (g_file_is_native (file))
{
GSList *list;
GInputStream *input = NULL;
gboolean opened = FALSE;
gsize head_size = 0;
guchar head[256];
FileMatchType best_match_val = FILE_MATCH_NONE;
PikaPlugInProcedure *best_file_proc = NULL;
for (list = procs; list; list = g_slist_next (list))
{
file_proc = list->data;
if (file_proc->magics_list)
{
if (G_UNLIKELY (! opened))
{
input = G_INPUT_STREAM (g_file_read (file, NULL, error));
if (input)
{
g_input_stream_read_all (input,
head, sizeof (head),
&head_size, NULL, error);
if (head_size < 4)
{
g_object_unref (input);
input = NULL;
}
else
{
GDataInputStream *data_input;
data_input = g_data_input_stream_new (input);
g_object_unref (input);
input = G_INPUT_STREAM (data_input);
}
}
opened = TRUE;
}
if (head_size >= 4)
{
FileMatchType match_val;
match_val = file_check_magic_list (file_proc->magics_list,
head, head_size,
file, input);
if (match_val == FILE_MATCH_SIZE)
{
/* Use it only if no other magic matches */
size_match_count++;
size_matched_proc = file_proc;
}
else if (match_val != FILE_MATCH_NONE)
{
PIKA_LOG (MAGIC_MATCH,
"magic match %d on %s\n",
match_val,
pika_object_get_name (file_proc));
if (match_val > best_match_val)
{
best_match_val = match_val;
best_file_proc = file_proc;
}
}
}
}
}
if (input)
g_object_unref (input);
if (best_file_proc)
{
PIKA_LOG (MAGIC_MATCH,
"best magic match on %s\n",
pika_object_get_name (best_file_proc));
return best_file_proc;
}
}
if (size_match_count == 1)
return size_matched_proc;
/* As a last resort, try matching by name, not skipping magic procs */
file_proc = file_proc_find_by_name (procs, file, FALSE);
if (file_proc)
{
/* we found a procedure, clear error that might have been set */
g_clear_error (error);
}
else
{
/* set an error message unless one was already set */
if (error && *error == NULL)
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unknown file type"));
}
return file_proc;
}
static PikaPlugInProcedure *
file_proc_find_by_mime_type (GSList *procs,
const gchar *mime_type)
{
GSList *list;
g_return_val_if_fail (mime_type != NULL, NULL);
for (list = procs; list; list = g_slist_next (list))
{
PikaPlugInProcedure *proc = list->data;
GSList *mime;
for (mime = proc->mime_types_list; mime; mime = g_slist_next (mime))
{
if (! strcmp (mime_type, mime->data))
return proc;
}
}
return NULL;
}
static PikaPlugInProcedure *
file_proc_find_by_prefix (GSList *procs,
GFile *file,
gboolean skip_magic)
{
gchar *uri = g_file_get_uri (file);
GSList *p;
for (p = procs; p; p = g_slist_next (p))
{
PikaPlugInProcedure *proc = p->data;
GSList *prefixes;
if (skip_magic && proc->magics_list)
continue;
for (prefixes = proc->prefixes_list;
prefixes;
prefixes = g_slist_next (prefixes))
{
if (g_str_has_prefix (uri, prefixes->data))
{
g_free (uri);
return proc;
}
}
}
g_free (uri);
return NULL;
}
static PikaPlugInProcedure *
file_proc_find_by_extension (GSList *procs,
GFile *file,
gboolean skip_magic)
{
gchar *ext = pika_file_get_extension (file);
if (ext)
{
GSList *p;
for (p = procs; p; p = g_slist_next (p))
{
PikaPlugInProcedure *proc = p->data;
if (skip_magic && proc->magics_list)
continue;
if (g_slist_find_custom (proc->extensions_list,
ext + 1,
(GCompareFunc) g_ascii_strcasecmp))
{
g_free (ext);
return proc;
}
}
g_free (ext);
}
return NULL;
}
static PikaPlugInProcedure *
file_proc_find_by_name (GSList *procs,
GFile *file,
gboolean skip_magic)
{
PikaPlugInProcedure *proc;
proc = file_proc_find_by_prefix (procs, file, skip_magic);
if (! proc)
proc = file_proc_find_by_extension (procs, file, skip_magic);
return proc;
}
static void
file_convert_string (const gchar *instr,
gchar *outmem,
gint maxmem,
gint *nmem)
{
/* Convert a string in C-notation to array of char */
const guchar *uin = (const guchar *) instr;
guchar *uout = (guchar *) outmem;
guchar tmp[5], *tmpptr;
guint k;
while ((*uin != '\0') && ((((gchar *) uout) - outmem) < maxmem))
{
if (*uin != '\\') /* Not an escaped character ? */
{
*(uout++) = *(uin++);
continue;
}
if (*(++uin) == '\0')
{
*(uout++) = '\\';
break;
}
switch (*uin)
{
case '0': case '1': case '2': case '3': /* octal */
for (tmpptr = tmp; (tmpptr - tmp) <= 3;)
{
*(tmpptr++) = *(uin++);
if ( (*uin == '\0') || (!g_ascii_isdigit (*uin))
|| (*uin == '8') || (*uin == '9'))
break;
}
*tmpptr = '\0';
sscanf ((gchar *) tmp, "%o", &k);
*(uout++) = k;
break;
case 'a': *(uout++) = '\a'; uin++; break;
case 'b': *(uout++) = '\b'; uin++; break;
case 't': *(uout++) = '\t'; uin++; break;
case 'n': *(uout++) = '\n'; uin++; break;
case 'v': *(uout++) = '\v'; uin++; break;
case 'f': *(uout++) = '\f'; uin++; break;
case 'r': *(uout++) = '\r'; uin++; break;
default : *(uout++) = *(uin++); break;
}
}
*nmem = ((gchar *) uout) - outmem;
}
static FileMatchType
file_check_single_magic (const gchar *offset,
const gchar *type,
const gchar *value,
const guchar *file_head,
gint headsize,
GFile *file,
GInputStream *input)
{
FileMatchType found = FILE_MATCH_NONE;
glong offs;
gulong num_testval;
gulong num_operator_val;
gint numbytes, k;
const gchar *num_operator_ptr;
gchar num_operator;
/* Check offset */
if (sscanf (offset, "%ld", &offs) != 1)
return FILE_MATCH_NONE;
/* Check type of test */
num_operator_ptr = NULL;
num_operator = '\0';
if (g_str_has_prefix (type, "byte"))
{
numbytes = 1;
num_operator_ptr = type + strlen ("byte");
}
else if (g_str_has_prefix (type, "short"))
{
numbytes = 2;
num_operator_ptr = type + strlen ("short");
}
else if (g_str_has_prefix (type, "long"))
{
numbytes = 4;
num_operator_ptr = type + strlen ("long");
}
else if (g_str_has_prefix (type, "size"))
{
numbytes = 5;
}
else if (strcmp (type, "string") == 0)
{
numbytes = 0;
}
else
{
return FILE_MATCH_NONE;
}
/* Check numerical operator value if present */
if (num_operator_ptr && (*num_operator_ptr == '&'))
{
if (g_ascii_isdigit (num_operator_ptr[1]))
{
if (num_operator_ptr[1] != '0') /* decimal */
sscanf (num_operator_ptr+1, "%lu", &num_operator_val);
else if (num_operator_ptr[2] == 'x') /* hexadecimal */
sscanf (num_operator_ptr+3, "%lx", &num_operator_val);
else /* octal */
sscanf (num_operator_ptr+2, "%lo", &num_operator_val);
num_operator = *num_operator_ptr;
}
}
if (numbytes > 0)
{
/* Numerical test */
gchar num_test = '=';
gulong fileval = 0;
/* Check test value */
if ((value[0] == '>') || (value[0] == '<'))
{
num_test = value[0];
value++;
}
errno = 0;
num_testval = strtol (value, NULL, 0);
if (errno != 0)
return FILE_MATCH_NONE;
if (numbytes == 5)
{
/* Check for file size */
GFileInfo *info = g_file_query_info (file,
G_FILE_ATTRIBUTE_STANDARD_SIZE,
G_FILE_QUERY_INFO_NONE,
NULL, NULL);
if (! info)
return FILE_MATCH_NONE;
fileval = g_file_info_get_size (info);
g_object_unref (info);
}
else if (offs >= 0 &&
(offs + numbytes <= headsize))
{
/* We have it in memory */
for (k = 0; k < numbytes; k++)
fileval = (fileval << 8) | (glong) file_head[offs + k];
}
else
{
/* Read it from file */
if (! g_seekable_seek (G_SEEKABLE (input), offs,
(offs >= 0) ? G_SEEK_SET : G_SEEK_END,
NULL, NULL))
return FILE_MATCH_NONE;
for (k = 0; k < numbytes; k++)
{
guchar byte;
GError *error = NULL;
byte = g_data_input_stream_read_byte (G_DATA_INPUT_STREAM (input),
NULL, &error);
if (error)
{
g_clear_error (&error);
return FILE_MATCH_NONE;
}
fileval = (fileval << 8) | byte;
}
}
if (num_operator == '&')
fileval &= num_operator_val;
if (num_test == '<')
{
if (fileval < num_testval)
found = numbytes;
}
else if (num_test == '>')
{
if (fileval > num_testval)
found = numbytes;
}
else
{
if (fileval == num_testval)
found = numbytes;
}
if (found && (numbytes == 5))
found = FILE_MATCH_SIZE;
}
else if (numbytes == 0)
{
/* String test */
gchar mem_testval[256];
file_convert_string (value,
mem_testval, sizeof (mem_testval),
&numbytes);
if (numbytes <= 0)
return FILE_MATCH_NONE;
if (offs >= 0 &&
(offs + numbytes <= headsize))
{
/* We have it in memory */
if (memcmp (mem_testval, file_head + offs, numbytes) == 0)
found = numbytes;
}
else
{
/* Read it from file */
if (! g_seekable_seek (G_SEEKABLE (input), offs,
(offs >= 0) ? G_SEEK_SET : G_SEEK_END,
NULL, NULL))
return FILE_MATCH_NONE;
for (k = 0; k < numbytes; k++)
{
guchar byte;
GError *error = NULL;
byte = g_data_input_stream_read_byte (G_DATA_INPUT_STREAM (input),
NULL, &error);
if (error)
{
g_clear_error (&error);
return FILE_MATCH_NONE;
}
if (byte != mem_testval[k])
return FILE_MATCH_NONE;
}
found = numbytes;
}
}
return found;
}
static FileMatchType
file_check_magic_list (GSList *magics_list,
const guchar *head,
gint headsize,
GFile *file,
GInputStream *input)
{
gboolean and = FALSE;
gboolean found = FALSE;
FileMatchType best_match_val = FILE_MATCH_NONE;
FileMatchType match_val = FILE_MATCH_NONE;
for (; magics_list; magics_list = magics_list->next)
{
const gchar *offset;
const gchar *type;
const gchar *value;
FileMatchType single_match_val = FILE_MATCH_NONE;
if ((offset = magics_list->data) == NULL) return FILE_MATCH_NONE;
if ((magics_list = magics_list->next) == NULL) return FILE_MATCH_NONE;
if ((type = magics_list->data) == NULL) return FILE_MATCH_NONE;
if ((magics_list = magics_list->next) == NULL) return FILE_MATCH_NONE;
if ((value = magics_list->data) == NULL) return FILE_MATCH_NONE;
single_match_val = file_check_single_magic (offset, type, value,
head, headsize,
file, input);
if (and)
found = found && (single_match_val != FILE_MATCH_NONE);
else
found = (single_match_val != FILE_MATCH_NONE);
if (found)
{
if (match_val == FILE_MATCH_NONE)
{
/* if we have no match yet, this is it in any case */
match_val = single_match_val;
}
else if (single_match_val != FILE_MATCH_NONE)
{
/* else if we have a match on this one, combine it with the
* existing return value
*/
if (single_match_val == FILE_MATCH_SIZE)
{
/* if we already have a magic match, simply increase
* that by one to indicate "better match", not perfect
* but better than losing the additional size match
* entirely
*/
if (match_val != FILE_MATCH_SIZE)
match_val += 1;
}
else
{
/* if we already have a magic match, simply add to its
* length; otherwise if we already have a size match,
* combine it with this match, see comment above
*/
if (match_val != FILE_MATCH_SIZE)
match_val += single_match_val;
else
match_val = single_match_val + 1;
}
}
}
else
{
match_val = FILE_MATCH_NONE;
}
and = (strchr (offset, '&') != NULL);
if (! and)
{
/* when done with this 'and' list, update best_match_val */
if (best_match_val == FILE_MATCH_NONE)
{
/* if we have no best match yet, this is it */
best_match_val = match_val;
}
else if (match_val != FILE_MATCH_NONE)
{
/* otherwise if this was a match, update the best match, note
* that by using MAX we will not overwrite a magic match
* with a size match
*/
best_match_val = MAX (best_match_val, match_val);
}
match_val = FILE_MATCH_NONE;
}
}
return best_match_val;
}

View File

@ -0,0 +1,55 @@
/* 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
*
* pikapluginmanager-file.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_MANAGER_FILE_H__
#define __PIKA_PLUG_IN_MANAGER_FILE_H__
void pika_plug_in_manager_add_load_procedure (PikaPlugInManager *manager,
PikaPlugInProcedure *proc);
void pika_plug_in_manager_add_save_procedure (PikaPlugInManager *manager,
PikaPlugInProcedure *proc);
GSList * pika_plug_in_manager_get_file_procedures (PikaPlugInManager *manager,
PikaFileProcedureGroup group);
PikaPlugInProcedure *
pika_plug_in_manager_file_procedure_find (PikaPlugInManager *manager,
PikaFileProcedureGroup group,
GFile *file,
GError **error);
PikaPlugInProcedure *
pika_plug_in_manager_file_procedure_find_by_prefix (PikaPlugInManager *manager,
PikaFileProcedureGroup group,
GFile *file);
PikaPlugInProcedure *
pika_plug_in_manager_file_procedure_find_by_extension (PikaPlugInManager *manager,
PikaFileProcedureGroup group,
GFile *file);
PikaPlugInProcedure *
pika_plug_in_manager_file_procedure_find_by_mime_type (PikaPlugInManager *manager,
PikaFileProcedureGroup group,
const gchar *mime_type);
#endif /* __PIKA_PLUG_IN_MANAGER_FILE_H__ */

View File

@ -0,0 +1,164 @@
/* 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
*
* pikapluginmanager-help-domain.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gio/gio.h>
#include "plug-in-types.h"
#include "pikapluginmanager.h"
#include "pikapluginmanager-help-domain.h"
typedef struct _PikaPlugInHelpDomain PikaPlugInHelpDomain;
struct _PikaPlugInHelpDomain
{
GFile *file;
gchar *domain_name;
gchar *domain_uri;
};
void
pika_plug_in_manager_help_domain_exit (PikaPlugInManager *manager)
{
GSList *list;
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
for (list = manager->help_domains; list; list = list->next)
{
PikaPlugInHelpDomain *domain = list->data;
g_object_unref (domain->file);
g_free (domain->domain_name);
g_free (domain->domain_uri);
g_slice_free (PikaPlugInHelpDomain, domain);
}
g_slist_free (manager->help_domains);
manager->help_domains = NULL;
}
void
pika_plug_in_manager_add_help_domain (PikaPlugInManager *manager,
GFile *file,
const gchar *domain_name,
const gchar *domain_uri)
{
PikaPlugInHelpDomain *domain;
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (G_IS_FILE (file));
g_return_if_fail (domain_name != NULL);
domain = g_slice_new (PikaPlugInHelpDomain);
domain->file = g_object_ref (file);
domain->domain_name = g_strdup (domain_name);
domain->domain_uri = g_strdup (domain_uri);
manager->help_domains = g_slist_prepend (manager->help_domains, domain);
#ifdef VERBOSE
g_print ("added help domain \"%s\" for base uri \"%s\"\n",
domain->domain_name ? domain->domain_name : "(null)",
domain->domain_uri ? domain->domain_uri : "(null)");
#endif
}
const gchar *
pika_plug_in_manager_get_help_domain (PikaPlugInManager *manager,
GFile *file,
const gchar **domain_uri)
{
GSList *list;
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), NULL);
g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL);
if (domain_uri)
*domain_uri = NULL;
/* A NULL prog_name is PIKA itself, return the default domain */
if (! file)
return NULL;
for (list = manager->help_domains; list; list = list->next)
{
PikaPlugInHelpDomain *domain = list->data;
if (domain && domain->file &&
g_file_equal (domain->file, file))
{
if (domain_uri && domain->domain_uri)
*domain_uri = domain->domain_uri;
return domain->domain_name;
}
}
return NULL;
}
gint
pika_plug_in_manager_get_help_domains (PikaPlugInManager *manager,
gchar ***help_domains,
gchar ***help_uris)
{
gint n_domains;
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), 0);
g_return_val_if_fail (help_domains != NULL, 0);
g_return_val_if_fail (help_uris != NULL, 0);
n_domains = g_slist_length (manager->help_domains);
if (n_domains > 0)
{
GSList *list;
gint i;
*help_domains = g_new0 (gchar *, n_domains + 1);
*help_uris = g_new0 (gchar *, n_domains + 1);
for (list = manager->help_domains, i = 0; list; list = list->next, i++)
{
PikaPlugInHelpDomain *domain = list->data;
(*help_domains)[i] = g_strdup (domain->domain_name);
(*help_uris)[i] = g_strdup (domain->domain_uri);
}
}
else
{
*help_domains = NULL;
*help_uris = NULL;
}
return n_domains;
}

View File

@ -0,0 +1,47 @@
/* 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
*
* pikapluginmanager-help-domain.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_MANAGER_HELP_DOMAIN_H__
#define __PIKA_PLUG_IN_MANAGER_HELP_DOMAIN_H__
void pika_plug_in_manager_help_domain_exit (PikaPlugInManager *manager);
/* Add a help domain */
void pika_plug_in_manager_add_help_domain (PikaPlugInManager *manager,
GFile *file,
const gchar *domain_name,
const gchar *domain_uri);
/* Retrieve a plug-ins help domain */
const gchar * pika_plug_in_manager_get_help_domain (PikaPlugInManager *manager,
GFile *file,
const gchar **help_uri);
/* Retrieve all help domains */
gint pika_plug_in_manager_get_help_domains (PikaPlugInManager *manager,
gchar ***help_domains,
gchar ***help_uris);
#endif /* __PIKA_PLUG_IN_MANAGER_HELP_DOMAIN_H__ */

View File

@ -0,0 +1,96 @@
/* 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
*
* pikapluginmanager-menu-branch.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gio/gio.h>
#include "plug-in-types.h"
#include "pikapluginmanager.h"
#include "pikapluginmanager-menu-branch.h"
#include "plug-in-menu-path.h"
/* public functions */
void
pika_plug_in_manager_menu_branch_exit (PikaPlugInManager *manager)
{
GSList *list;
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
for (list = manager->menu_branches; list; list = list->next)
{
PikaPlugInMenuBranch *branch = list->data;
g_object_unref (branch->file);
g_free (branch->menu_path);
g_free (branch->menu_label);
g_slice_free (PikaPlugInMenuBranch, branch);
}
g_slist_free (manager->menu_branches);
manager->menu_branches = NULL;
}
void
pika_plug_in_manager_add_menu_branch (PikaPlugInManager *manager,
GFile *file,
const gchar *menu_path,
const gchar *menu_label)
{
PikaPlugInMenuBranch *branch;
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (G_IS_FILE (file));
g_return_if_fail (menu_path != NULL);
g_return_if_fail (menu_label != NULL);
branch = g_slice_new (PikaPlugInMenuBranch);
branch->file = g_object_ref (file);
branch->menu_path = plug_in_menu_path_map (menu_path, menu_label);
branch->menu_label = g_strdup (menu_label);
manager->menu_branches = g_slist_append (manager->menu_branches, branch);
g_signal_emit_by_name (manager, "menu-branch-added",
branch->file,
branch->menu_path,
branch->menu_label);
#ifdef VERBOSE
g_print ("added menu branch \"%s\" at path \"%s\"\n",
branch->menu_label, branch->menu_path);
#endif
}
GSList *
pika_plug_in_manager_get_menu_branches (PikaPlugInManager *manager)
{
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), NULL);
return manager->menu_branches;
}

View File

@ -0,0 +1,46 @@
/* 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
*
* pikapluginmanager-menu-branch.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_MANAGER_MENU_BRANCH_H__
#define __PIKA_PLUG_IN_MANAGER_MENU_BRANCH_H__
struct _PikaPlugInMenuBranch
{
GFile *file;
gchar *menu_path;
gchar *menu_label;
};
void pika_plug_in_manager_menu_branch_exit (PikaPlugInManager *manager);
/* Add a menu branch */
void pika_plug_in_manager_add_menu_branch (PikaPlugInManager *manager,
GFile *file,
const gchar *menu_path,
const gchar *menu_label);
GSList * pika_plug_in_manager_get_menu_branches (PikaPlugInManager *manager);
#endif /* __PIKA_PLUG_IN_MANAGER_MENU_BRANCH_H__ */

View File

@ -0,0 +1,132 @@
/* 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-2003 Spencer Kimball and Peter Mattis
*
* plug-ins-query.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "plug-in-types.h"
#include "pikapluginmanager.h"
#include "pikapluginmanager-query.h"
#include "pikapluginprocedure.h"
static gboolean
match_string (GRegex *regex,
gchar *string)
{
return g_regex_match (regex, string, 0, NULL);
}
gint
pika_plug_in_manager_query (PikaPlugInManager *manager,
const gchar *search_str,
gchar ***procedure_strs,
gchar ***accel_strs,
gchar ***prog_strs,
gint32 **time_ints)
{
gint num_plugins = 0;
GRegex *sregex = NULL;
GSList *matched = NULL;
GSList *list;
gint i;
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), 0);
g_return_val_if_fail (procedure_strs != NULL, 0);
g_return_val_if_fail (accel_strs != NULL, 0);
g_return_val_if_fail (prog_strs != NULL, 0);
g_return_val_if_fail (time_ints != NULL, 0);
*procedure_strs = NULL;
*accel_strs = NULL;
*prog_strs = NULL;
*time_ints = NULL;
if (search_str && ! strlen (search_str))
search_str = NULL;
if (search_str)
{
sregex = g_regex_new (search_str, G_REGEX_CASELESS | G_REGEX_OPTIMIZE, 0,
NULL);
if (! sregex)
return 0;
}
/* count number of plugin entries, then allocate arrays of correct size
* where we can store the strings.
*/
for (list = manager->plug_in_procedures; list; list = g_slist_next (list))
{
PikaPlugInProcedure *proc = list->data;
if (proc->file && proc->menu_paths)
{
gchar *name = proc->menu_label;
name = pika_strip_uline (name);
if (! search_str || match_string (sregex, name))
{
num_plugins++;
matched = g_slist_prepend (matched, proc);
}
g_free (name);
}
}
*procedure_strs = g_new0 (gchar *, num_plugins + 1);
*accel_strs = g_new0 (gchar *, num_plugins + 1);
*prog_strs = g_new0 (gchar *, num_plugins + 1);
*time_ints = g_new (gint, num_plugins);
matched = g_slist_reverse (matched);
for (list = matched, i = 0;
list;
list = g_slist_next (list), i++)
{
PikaPlugInProcedure *proc = list->data;
(*procedure_strs)[i] = g_strdup (pika_object_get_name (proc));
(*accel_strs)[i] = g_strdup ("");
(*prog_strs)[i] = g_file_get_path (proc->file);
(*time_ints)[i] = proc->mtime;
}
g_slist_free (matched);
if (sregex)
g_regex_unref (sregex);
return num_plugins;
}

View File

@ -0,0 +1,36 @@
/* 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
*
* pikapluginmanager-query.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_MANAGER_QUERY_H__
#define __PIKA_PLUG_IN_MANAGER_QUERY_H__
gint pika_plug_in_manager_query (PikaPlugInManager *manager,
const gchar *search_str,
gchar ***procedure_strs,
gchar ***accel_strs,
gchar ***prog_strs,
gint32 **time_ints);
#endif /* __PIKA_PLUG_IN_MANAGER_QUERY_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
/* 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-1997 Spencer Kimball and Peter Mattis
*
* pikapluginmanager-restore.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_MANAGER_RESTORE_H__
#define __PIKA_PLUG_IN_MANAGER_RESTORE_H__
void pika_plug_in_manager_restore (PikaPlugInManager *manager,
PikaContext *context,
PikaInitStatusFunc status_callback);
#endif /* __PIKA_PLUG_IN_MANAGER_RESTORE_H__ */

View File

@ -0,0 +1,447 @@
/* 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-2002 Spencer Kimball, Peter Mattis, and others
*
* pikapluginmanager.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "plug-in-types.h"
#include "config/pikacoreconfig.h"
#include "core/pika.h"
#include "core/pika-filter-history.h"
#include "core/pika-memsize.h"
#include "core/pikamarshal.h"
#include "pdb/pikapdb.h"
#include "pikaenvirontable.h"
#include "pikainterpreterdb.h"
#include "pikaplugin.h"
#include "pikaplugindebug.h"
#include "pikaplugindef.h"
#include "pikapluginmanager.h"
#include "pikapluginmanager-data.h"
#include "pikapluginmanager-help-domain.h"
#include "pikapluginmanager-menu-branch.h"
#include "pikapluginshm.h"
#include "pikatemporaryprocedure.h"
#include "pika-intl.h"
enum
{
PLUG_IN_OPENED,
PLUG_IN_CLOSED,
MENU_BRANCH_ADDED,
LAST_SIGNAL
};
static void pika_plug_in_manager_finalize (GObject *object);
static gint64 pika_plug_in_manager_get_memsize (PikaObject *object,
gint64 *gui_size);
G_DEFINE_TYPE (PikaPlugInManager, pika_plug_in_manager, PIKA_TYPE_OBJECT)
#define parent_class pika_plug_in_manager_parent_class
static guint manager_signals[LAST_SIGNAL] = { 0, };
static void
pika_plug_in_manager_class_init (PikaPlugInManagerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaObjectClass *pika_object_class = PIKA_OBJECT_CLASS (klass);
manager_signals[PLUG_IN_OPENED] =
g_signal_new ("plug-in-opened",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (PikaPlugInManagerClass,
plug_in_opened),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_PLUG_IN);
manager_signals[PLUG_IN_CLOSED] =
g_signal_new ("plug-in-closed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (PikaPlugInManagerClass,
plug_in_closed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_PLUG_IN);
manager_signals[MENU_BRANCH_ADDED] =
g_signal_new ("menu-branch-added",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (PikaPlugInManagerClass,
menu_branch_added),
NULL, NULL,
pika_marshal_VOID__OBJECT_STRING_STRING,
G_TYPE_NONE, 3,
G_TYPE_FILE,
G_TYPE_STRING,
G_TYPE_STRING);
object_class->finalize = pika_plug_in_manager_finalize;
pika_object_class->get_memsize = pika_plug_in_manager_get_memsize;
}
static void
pika_plug_in_manager_init (PikaPlugInManager *manager)
{
}
static void
pika_plug_in_manager_finalize (GObject *object)
{
PikaPlugInManager *manager = PIKA_PLUG_IN_MANAGER (object);
g_clear_pointer (&manager->load_procs, g_slist_free);
g_clear_pointer (&manager->save_procs, g_slist_free);
g_clear_pointer (&manager->export_procs, g_slist_free);
g_clear_pointer (&manager->raw_load_procs, g_slist_free);
g_clear_pointer (&manager->batch_procs, g_slist_free);
g_clear_pointer (&manager->display_load_procs, g_slist_free);
g_clear_pointer (&manager->display_save_procs, g_slist_free);
g_clear_pointer (&manager->display_export_procs, g_slist_free);
g_clear_pointer (&manager->display_raw_load_procs, g_slist_free);
if (manager->plug_in_procedures)
{
g_slist_free_full (manager->plug_in_procedures,
(GDestroyNotify) g_object_unref);
manager->plug_in_procedures = NULL;
}
if (manager->plug_in_defs)
{
g_slist_free_full (manager->plug_in_defs,
(GDestroyNotify) g_object_unref);
manager->plug_in_defs = NULL;
}
g_clear_object (&manager->environ_table);
g_clear_object (&manager->interpreter_db);
g_clear_pointer (&manager->debug, pika_plug_in_debug_free);
pika_plug_in_manager_menu_branch_exit (manager);
pika_plug_in_manager_help_domain_exit (manager);
pika_plug_in_manager_data_free (manager);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gint64
pika_plug_in_manager_get_memsize (PikaObject *object,
gint64 *gui_size)
{
PikaPlugInManager *manager = PIKA_PLUG_IN_MANAGER (object);
gint64 memsize = 0;
memsize += pika_g_slist_get_memsize_foreach (manager->plug_in_defs,
(PikaMemsizeFunc)
pika_object_get_memsize,
gui_size);
memsize += pika_g_slist_get_memsize (manager->plug_in_procedures, 0);
memsize += pika_g_slist_get_memsize (manager->load_procs, 0);
memsize += pika_g_slist_get_memsize (manager->save_procs, 0);
memsize += pika_g_slist_get_memsize (manager->export_procs, 0);
memsize += pika_g_slist_get_memsize (manager->raw_load_procs, 0);
memsize += pika_g_slist_get_memsize (manager->batch_procs, 0);
memsize += pika_g_slist_get_memsize (manager->display_load_procs, 0);
memsize += pika_g_slist_get_memsize (manager->display_save_procs, 0);
memsize += pika_g_slist_get_memsize (manager->display_export_procs, 0);
memsize += pika_g_slist_get_memsize (manager->display_raw_load_procs, 0);
memsize += pika_g_slist_get_memsize (manager->menu_branches, 0 /* FIXME */);
memsize += pika_g_slist_get_memsize (manager->help_domains, 0 /* FIXME */);
memsize += pika_g_slist_get_memsize_foreach (manager->open_plug_ins,
(PikaMemsizeFunc)
pika_object_get_memsize,
gui_size);
memsize += pika_g_slist_get_memsize (manager->plug_in_stack, 0);
memsize += 0; /* FIXME manager->shm */
memsize += /* FIXME */ pika_g_object_get_memsize (G_OBJECT (manager->interpreter_db));
memsize += /* FIXME */ pika_g_object_get_memsize (G_OBJECT (manager->environ_table));
memsize += 0; /* FIXME manager->plug_in_debug */
memsize += pika_g_list_get_memsize (manager->data_list, 0 /* FIXME */);
return memsize + PIKA_OBJECT_CLASS (parent_class)->get_memsize (object,
gui_size);
}
PikaPlugInManager *
pika_plug_in_manager_new (Pika *pika)
{
PikaPlugInManager *manager;
manager = g_object_new (PIKA_TYPE_PLUG_IN_MANAGER, NULL);
manager->pika = pika;
manager->interpreter_db = pika_interpreter_db_new (pika->be_verbose);
manager->environ_table = pika_environ_table_new (pika->be_verbose);
return manager;
}
void
pika_plug_in_manager_initialize (PikaPlugInManager *manager,
PikaInitStatusFunc status_callback)
{
PikaCoreConfig *config;
GList *path;
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (status_callback != NULL);
config = manager->pika->config;
status_callback (NULL, _("Plug-in Interpreters"), 0.8);
path = pika_config_path_expand_to_files (config->interpreter_path, NULL);
pika_interpreter_db_load (manager->interpreter_db, path);
g_list_free_full (path, (GDestroyNotify) g_object_unref);
status_callback (NULL, _("Plug-in Environment"), 0.9);
path = pika_config_path_expand_to_files (config->environ_path, NULL);
pika_environ_table_load (manager->environ_table, path);
g_list_free_full (path, (GDestroyNotify) g_object_unref);
/* allocate a piece of shared memory for use in transporting tiles
* to plug-ins. if we can't allocate a piece of shared memory then
* we'll fall back on sending the data over the pipe.
*/
if (manager->pika->use_shm)
manager->shm = pika_plug_in_shm_new ();
manager->debug = pika_plug_in_debug_new ();
}
void
pika_plug_in_manager_exit (PikaPlugInManager *manager)
{
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
while (manager->open_plug_ins)
pika_plug_in_close (manager->open_plug_ins->data, TRUE);
/* need to detach from shared memory, we can't rely on exit()
* cleaning up behind us (see bug #609026)
*/
if (manager->shm)
{
pika_plug_in_shm_free (manager->shm);
manager->shm = NULL;
}
}
void
pika_plug_in_manager_add_procedure (PikaPlugInManager *manager,
PikaPlugInProcedure *procedure)
{
GSList *list;
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (procedure));
for (list = manager->plug_in_procedures; list; list = list->next)
{
PikaPlugInProcedure *tmp_proc = list->data;
if (strcmp (pika_object_get_name (procedure),
pika_object_get_name (tmp_proc)) == 0)
{
GSList *list2;
list->data = g_object_ref (procedure);
g_printerr ("Removing duplicate PDB procedure '%s' "
"registered by '%s'\n",
pika_object_get_name (tmp_proc),
pika_file_get_utf8_name (tmp_proc->file));
/* search the plugin list to see if any plugins had references to
* the tmp_proc.
*/
for (list2 = manager->plug_in_defs; list2; list2 = list2->next)
{
PikaPlugInDef *plug_in_def = list2->data;
if (g_slist_find (plug_in_def->procedures, tmp_proc))
pika_plug_in_def_remove_procedure (plug_in_def, tmp_proc);
}
/* also remove it from the lists of load, save and export procs */
manager->load_procs = g_slist_remove (manager->load_procs, tmp_proc);
manager->save_procs = g_slist_remove (manager->save_procs, tmp_proc);
manager->export_procs = g_slist_remove (manager->export_procs, tmp_proc);
manager->raw_load_procs = g_slist_remove (manager->raw_load_procs, tmp_proc);
manager->batch_procs = g_slist_remove (manager->batch_procs, tmp_proc);
manager->display_load_procs = g_slist_remove (manager->display_load_procs, tmp_proc);
manager->display_save_procs = g_slist_remove (manager->display_save_procs, tmp_proc);
manager->display_export_procs = g_slist_remove (manager->display_export_procs, tmp_proc);
manager->display_raw_load_procs = g_slist_remove (manager->display_raw_load_procs, tmp_proc);
/* and from the history */
pika_filter_history_remove (manager->pika, PIKA_PROCEDURE (tmp_proc));
g_object_unref (tmp_proc);
return;
}
}
manager->plug_in_procedures = g_slist_prepend (manager->plug_in_procedures,
g_object_ref (procedure));
}
void
pika_plug_in_manager_add_batch_procedure (PikaPlugInManager *manager,
PikaPlugInProcedure *proc)
{
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (proc));
if (! g_slist_find (manager->batch_procs, proc))
manager->batch_procs = g_slist_prepend (manager->batch_procs, proc);
}
GSList *
pika_plug_in_manager_get_batch_procedures (PikaPlugInManager *manager)
{
g_return_val_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager), NULL);
return manager->batch_procs;
}
void
pika_plug_in_manager_add_temp_proc (PikaPlugInManager *manager,
PikaTemporaryProcedure *procedure)
{
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (PIKA_IS_TEMPORARY_PROCEDURE (procedure));
pika_pdb_register_procedure (manager->pika->pdb, PIKA_PROCEDURE (procedure));
manager->plug_in_procedures = g_slist_prepend (manager->plug_in_procedures,
g_object_ref (procedure));
}
void
pika_plug_in_manager_remove_temp_proc (PikaPlugInManager *manager,
PikaTemporaryProcedure *procedure)
{
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (PIKA_IS_TEMPORARY_PROCEDURE (procedure));
manager->plug_in_procedures = g_slist_remove (manager->plug_in_procedures,
procedure);
pika_filter_history_remove (manager->pika,
PIKA_PROCEDURE (procedure));
pika_pdb_unregister_procedure (manager->pika->pdb,
PIKA_PROCEDURE (procedure));
g_object_unref (procedure);
}
void
pika_plug_in_manager_add_open_plug_in (PikaPlugInManager *manager,
PikaPlugIn *plug_in)
{
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
manager->open_plug_ins = g_slist_prepend (manager->open_plug_ins,
g_object_ref (plug_in));
g_signal_emit (manager, manager_signals[PLUG_IN_OPENED], 0,
plug_in);
}
void
pika_plug_in_manager_remove_open_plug_in (PikaPlugInManager *manager,
PikaPlugIn *plug_in)
{
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
manager->open_plug_ins = g_slist_remove (manager->open_plug_ins, plug_in);
g_signal_emit (manager, manager_signals[PLUG_IN_CLOSED], 0,
plug_in);
g_object_unref (plug_in);
}
void
pika_plug_in_manager_plug_in_push (PikaPlugInManager *manager,
PikaPlugIn *plug_in)
{
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
manager->current_plug_in = plug_in;
manager->plug_in_stack = g_slist_prepend (manager->plug_in_stack,
manager->current_plug_in);
}
void
pika_plug_in_manager_plug_in_pop (PikaPlugInManager *manager)
{
g_return_if_fail (PIKA_IS_PLUG_IN_MANAGER (manager));
if (manager->current_plug_in)
manager->plug_in_stack = g_slist_remove (manager->plug_in_stack,
manager->plug_in_stack->data);
if (manager->plug_in_stack)
manager->current_plug_in = manager->plug_in_stack->data;
else
manager->current_plug_in = NULL;
}

View File

@ -0,0 +1,126 @@
/* 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-1997 Spencer Kimball and Peter Mattis
*
* pikapluginmanager.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_MANAGER_H__
#define __PIKA_PLUG_IN_MANAGER_H__
#include "core/pikaobject.h"
#define PIKA_TYPE_PLUG_IN_MANAGER (pika_plug_in_manager_get_type ())
#define PIKA_PLUG_IN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_PLUG_IN_MANAGER, PikaPlugInManager))
#define PIKA_PLUG_IN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_PLUG_IN_MANAGER, PikaPlugInManagerClass))
#define PIKA_IS_PLUG_IN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_PLUG_IN_MANAGER))
#define PIKA_IS_PLUG_IN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_PLUG_IN_MANAGER))
typedef struct _PikaPlugInManagerClass PikaPlugInManagerClass;
struct _PikaPlugInManager
{
PikaObject parent_instance;
Pika *pika;
GSList *plug_in_defs;
gboolean write_pluginrc;
GSList *plug_in_procedures;
GSList *load_procs;
GSList *save_procs;
GSList *export_procs;
GSList *raw_load_procs;
GSList *batch_procs;
GSList *display_load_procs;
GSList *display_save_procs;
GSList *display_export_procs;
GSList *display_raw_load_procs;
GSList *menu_branches;
GSList *help_domains;
PikaPlugIn *current_plug_in;
GSList *open_plug_ins;
GSList *plug_in_stack;
PikaPlugInShm *shm;
PikaInterpreterDB *interpreter_db;
PikaEnvironTable *environ_table;
PikaPlugInDebug *debug;
GList *data_list;
};
struct _PikaPlugInManagerClass
{
PikaObjectClass parent_class;
void (* plug_in_opened) (PikaPlugInManager *manager,
PikaPlugIn *plug_in);
void (* plug_in_closed) (PikaPlugInManager *manager,
PikaPlugIn *plug_in);
void (* menu_branch_added) (PikaPlugInManager *manager,
GFile *file,
const gchar *menu_path,
const gchar *menu_label);
};
GType pika_plug_in_manager_get_type (void) G_GNUC_CONST;
PikaPlugInManager * pika_plug_in_manager_new (Pika *pika);
void pika_plug_in_manager_initialize (PikaPlugInManager *manager,
PikaInitStatusFunc status_callback);
void pika_plug_in_manager_exit (PikaPlugInManager *manager);
/* Register a plug-in. This function is public for file load-save
* handlers, which are organized around the plug-in data structure.
* This could all be done a little better, but oh well. -josh
*/
void pika_plug_in_manager_add_procedure (PikaPlugInManager *manager,
PikaPlugInProcedure *procedure);
void pika_plug_in_manager_add_batch_procedure (PikaPlugInManager *manager,
PikaPlugInProcedure *proc);
GSList * pika_plug_in_manager_get_batch_procedures (PikaPlugInManager *manager);
void pika_plug_in_manager_add_temp_proc (PikaPlugInManager *manager,
PikaTemporaryProcedure *procedure);
void pika_plug_in_manager_remove_temp_proc (PikaPlugInManager *manager,
PikaTemporaryProcedure *procedure);
void pika_plug_in_manager_add_open_plug_in (PikaPlugInManager *manager,
PikaPlugIn *plug_in);
void pika_plug_in_manager_remove_open_plug_in (PikaPlugInManager *manager,
PikaPlugIn *plug_in);
void pika_plug_in_manager_plug_in_push (PikaPlugInManager *manager,
PikaPlugIn *plug_in);
void pika_plug_in_manager_plug_in_pop (PikaPlugInManager *manager);
#endif /* __PIKA_PLUG_IN_MANAGER_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,155 @@
/* 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.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_PROCEDURE_H__
#define __PIKA_PLUG_IN_PROCEDURE_H__
#include "pdb/pikaprocedure.h"
#define PIKA_TYPE_PLUG_IN_PROCEDURE (pika_plug_in_procedure_get_type ())
#define PIKA_PLUG_IN_PROCEDURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_PLUG_IN_PROCEDURE, PikaPlugInProcedure))
#define PIKA_PLUG_IN_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_PLUG_IN_PROCEDURE, PikaPlugInProcedureClass))
#define PIKA_IS_PLUG_IN_PROCEDURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_PLUG_IN_PROCEDURE))
#define PIKA_IS_PLUG_IN_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_PLUG_IN_PROCEDURE))
#define PIKA_PLUG_IN_PROCEDURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_PLUG_IN_PROCEDURE, PikaPlugInProcedureClass))
typedef struct _PikaPlugInProcedureClass PikaPlugInProcedureClass;
struct _PikaPlugInProcedure
{
PikaProcedure parent_instance;
/* common members */
GFile *file;
GQuark help_domain;
gchar *menu_label;
GList *menu_paths;
gchar *help_id_with_domain;
PikaIconType icon_type;
gint icon_data_length;
guint8 *icon_data;
gchar *image_types;
PikaPlugInImageType image_types_val;
gchar *insensitive_reason;
gint sensitivity_mask;
gint64 mtime;
gboolean installed_during_init;
/* file proc specific members */
gboolean file_proc;
gboolean generic_file_proc; /* not returning an image. */
gchar *extensions;
gchar *prefixes;
gchar *magics;
gint priority;
gchar *mime_types;
gboolean handles_remote;
gboolean handles_raw;
gboolean batch_interpreter;
gchar *batch_interpreter_name;
GSList *extensions_list;
GSList *prefixes_list;
GSList *magics_list;
GSList *mime_types_list;
gchar *thumb_loader;
};
struct _PikaPlugInProcedureClass
{
PikaProcedureClass parent_class;
/* virtual functions */
GFile * (* get_file) (PikaPlugInProcedure *procedure);
/* signals */
void (* menu_path_added) (PikaPlugInProcedure *procedure,
const gchar *menu_path);
};
GType pika_plug_in_procedure_get_type (void) G_GNUC_CONST;
PikaProcedure * pika_plug_in_procedure_new (PikaPDBProcType proc_type,
GFile *file);
PikaPlugInProcedure * pika_plug_in_procedure_find (GSList *list,
const gchar *proc_name);
GFile * pika_plug_in_procedure_get_file (PikaPlugInProcedure *proc);
void pika_plug_in_procedure_set_help_domain (PikaPlugInProcedure *proc,
const gchar *help_domain);
const gchar * pika_plug_in_procedure_get_help_domain (PikaPlugInProcedure *proc);
gboolean pika_plug_in_procedure_set_menu_label (PikaPlugInProcedure *proc,
const gchar *menu_label,
GError **error);
gboolean pika_plug_in_procedure_add_menu_path (PikaPlugInProcedure *proc,
const gchar *menu_path,
GError **error);
gboolean pika_plug_in_procedure_set_icon (PikaPlugInProcedure *proc,
PikaIconType type,
const guint8 *data,
gint data_length,
GError **error);
gboolean pika_plug_in_procedure_take_icon (PikaPlugInProcedure *proc,
PikaIconType type,
guint8 *data,
gint data_length,
GError **error);
void pika_plug_in_procedure_set_image_types (PikaPlugInProcedure *proc,
const gchar *image_types);
void pika_plug_in_procedure_set_sensitivity_mask (PikaPlugInProcedure *proc,
gint sensitivity_mask);
void pika_plug_in_procedure_set_file_proc (PikaPlugInProcedure *proc,
const gchar *extensions,
const gchar *prefixes,
const gchar *magics);
void pika_plug_in_procedure_set_generic_file_proc (PikaPlugInProcedure *proc,
gboolean is_generic_file_proc);
void pika_plug_in_procedure_set_priority (PikaPlugInProcedure *proc,
gint priority);
void pika_plug_in_procedure_set_mime_types (PikaPlugInProcedure *proc,
const gchar *mime_ypes);
void pika_plug_in_procedure_set_handles_remote(PikaPlugInProcedure *proc);
void pika_plug_in_procedure_set_handles_raw (PikaPlugInProcedure *proc);
void pika_plug_in_procedure_set_thumb_loader (PikaPlugInProcedure *proc,
const gchar *thumbnailer);
void pika_plug_in_procedure_set_batch_interpreter (PikaPlugInProcedure *proc,
const gchar *name);
void pika_plug_in_procedure_handle_return_values (PikaPlugInProcedure *proc,
Pika *pika,
PikaProgress *progress,
PikaValueArray *return_vals);
#endif /* __PIKA_PLUG_IN_PROCEDURE_H__ */

View File

@ -0,0 +1,204 @@
/* 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
*
* pikapluginprocframe.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "plug-in-types.h"
#include "core/pikaprogress.h"
#include "pdb/pikapdbcontext.h"
#include "pdb/pikapdberror.h"
#include "pikaplugin.h"
#include "pikaplugin-cleanup.h"
#include "pikaplugin-progress.h"
#include "pikapluginprocedure.h"
#include "pika-intl.h"
/* public functions */
PikaPlugInProcFrame *
pika_plug_in_proc_frame_new (PikaContext *context,
PikaProgress *progress,
PikaPlugInProcedure *procedure)
{
PikaPlugInProcFrame *proc_frame;
g_return_val_if_fail (PIKA_IS_PDB_CONTEXT (context), NULL);
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), NULL);
g_return_val_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (procedure), NULL);
proc_frame = g_slice_new0 (PikaPlugInProcFrame);
proc_frame->ref_count = 1;
pika_plug_in_proc_frame_init (proc_frame, context, progress, procedure);
return proc_frame;
}
void
pika_plug_in_proc_frame_init (PikaPlugInProcFrame *proc_frame,
PikaContext *context,
PikaProgress *progress,
PikaPlugInProcedure *procedure)
{
g_return_if_fail (proc_frame != NULL);
g_return_if_fail (PIKA_IS_PDB_CONTEXT (context));
g_return_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress));
g_return_if_fail (procedure == NULL ||
PIKA_IS_PLUG_IN_PROCEDURE (procedure));
proc_frame->main_context = g_object_ref (context);
proc_frame->context_stack = NULL;
proc_frame->procedure = procedure ? g_object_ref (PIKA_PROCEDURE (procedure)) : NULL;
proc_frame->main_loop = NULL;
proc_frame->return_vals = NULL;
proc_frame->progress = progress ? g_object_ref (progress) : NULL;
proc_frame->progress_created = FALSE;
proc_frame->progress_cancel_id = 0;
proc_frame->error_handler = PIKA_PDB_ERROR_HANDLER_INTERNAL;
if (progress)
pika_plug_in_progress_attach (progress);
}
void
pika_plug_in_proc_frame_dispose (PikaPlugInProcFrame *proc_frame,
PikaPlugIn *plug_in)
{
g_return_if_fail (proc_frame != NULL);
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
if (proc_frame->progress)
{
pika_plug_in_progress_end (plug_in, proc_frame);
g_clear_object (&proc_frame->progress);
}
if (proc_frame->context_stack)
{
g_list_free_full (proc_frame->context_stack,
(GDestroyNotify) g_object_unref);
proc_frame->context_stack = NULL;
}
g_clear_object (&proc_frame->main_context);
g_clear_pointer (&proc_frame->return_vals, pika_value_array_unref);
g_clear_pointer (&proc_frame->main_loop, g_main_loop_unref);
if (proc_frame->image_cleanups || proc_frame->item_cleanups)
pika_plug_in_cleanup (plug_in, proc_frame);
g_clear_object (&proc_frame->procedure);
}
PikaPlugInProcFrame *
pika_plug_in_proc_frame_ref (PikaPlugInProcFrame *proc_frame)
{
g_return_val_if_fail (proc_frame != NULL, NULL);
proc_frame->ref_count++;
return proc_frame;
}
void
pika_plug_in_proc_frame_unref (PikaPlugInProcFrame *proc_frame,
PikaPlugIn *plug_in)
{
g_return_if_fail (proc_frame != NULL);
g_return_if_fail (PIKA_IS_PLUG_IN (plug_in));
proc_frame->ref_count--;
if (proc_frame->ref_count < 1)
{
pika_plug_in_proc_frame_dispose (proc_frame, plug_in);
g_slice_free (PikaPlugInProcFrame, proc_frame);
}
}
PikaValueArray *
pika_plug_in_proc_frame_get_return_values (PikaPlugInProcFrame *proc_frame)
{
PikaValueArray *return_vals;
g_return_val_if_fail (proc_frame != NULL, NULL);
if (proc_frame->return_vals)
{
if (pika_value_array_length (proc_frame->return_vals) >=
proc_frame->procedure->num_values + 1)
{
return_vals = proc_frame->return_vals;
}
else
{
/* Allocate new return values of the correct size. */
return_vals = pika_procedure_get_return_values (proc_frame->procedure,
TRUE, NULL);
/* Copy all of the arguments we can. */
memcpy (pika_value_array_index (return_vals, 0),
pika_value_array_index (proc_frame->return_vals, 0),
sizeof (GValue) *
pika_value_array_length (proc_frame->return_vals));
/* Free the old arguments. */
memset (pika_value_array_index (proc_frame->return_vals, 0), 0,
sizeof (GValue) *
pika_value_array_length (proc_frame->return_vals));
pika_value_array_unref (proc_frame->return_vals);
}
/* We have consumed any saved values, so clear them. */
proc_frame->return_vals = NULL;
}
else
{
PikaProcedure *procedure = proc_frame->procedure;
GError *error;
error = g_error_new (PIKA_PDB_ERROR, PIKA_PDB_ERROR_INVALID_RETURN_VALUE,
_("Procedure '%s' returned no return values"),
pika_object_get_name (procedure));
return_vals = pika_procedure_get_return_values (procedure, FALSE,
error);
g_error_free (error);
}
return return_vals;
}

View File

@ -0,0 +1,71 @@
/* 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
*
* pikapluginprocframe.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_PROC_FRAME_H__
#define __PIKA_PLUG_IN_PROC_FRAME_H__
struct _PikaPlugInProcFrame
{
gint ref_count;
PikaContext *main_context;
GList *context_stack;
PikaProcedure *procedure;
GMainLoop *main_loop;
PikaValueArray *return_vals;
PikaProgress *progress;
gboolean progress_created;
gulong progress_cancel_id;
PikaPDBErrorHandler error_handler;
/* lists of things to clean up on dispose */
GList *image_cleanups;
GList *item_cleanups;
};
PikaPlugInProcFrame * pika_plug_in_proc_frame_new (PikaContext *context,
PikaProgress *progress,
PikaPlugInProcedure *procedure);
void pika_plug_in_proc_frame_init (PikaPlugInProcFrame *proc_frame,
PikaContext *context,
PikaProgress *progress,
PikaPlugInProcedure *procedure);
void pika_plug_in_proc_frame_dispose (PikaPlugInProcFrame *proc_frame,
PikaPlugIn *plug_in);
PikaPlugInProcFrame * pika_plug_in_proc_frame_ref (PikaPlugInProcFrame *proc_frame);
void pika_plug_in_proc_frame_unref (PikaPlugInProcFrame *proc_frame,
PikaPlugIn *plug_in);
PikaValueArray * pika_plug_in_proc_frame_get_return_values
(PikaPlugInProcFrame *proc_frame);
#endif /* __PIKA_PLUG_IN_PROC_FRAME_H__ */

311
app/plug-in/pikapluginshm.c Normal file
View File

@ -0,0 +1,311 @@
/* 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
*
* pikapluginhsm.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <sys/types.h>
#include <errno.h>
#if defined(USE_SYSV_SHM)
#ifdef HAVE_IPC_H
#include <sys/ipc.h>
#endif
#ifdef HAVE_SHM_H
#include <sys/shm.h>
#endif
#elif defined(USE_POSIX_SHM)
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/mman.h>
#endif /* USE_POSIX_SHM */
#include <gio/gio.h>
#include <gegl.h>
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
#define STRICT
#include <windows.h>
#include <process.h>
#ifdef G_OS_WIN32
#include <fcntl.h>
#include <io.h>
#endif
#define USE_WIN32_SHM 1
#endif /* G_OS_WIN32 || G_WITH_CYGWIN */
#include "plug-in-types.h"
#include "core/pika-utils.h"
#include "pikapluginshm.h"
#include "pika-log.h"
#define TILE_MAP_SIZE (PIKA_PLUG_IN_TILE_WIDTH * PIKA_PLUG_IN_TILE_HEIGHT * 32)
#define ERRMSG_SHM_DISABLE "Disabling shared memory tile transport"
struct _PikaPlugInShm
{
gint shm_id;
guchar *shm_addr;
#if defined(USE_WIN32_SHM)
HANDLE shm_handle;
#endif
};
PikaPlugInShm *
pika_plug_in_shm_new (void)
{
/* allocate a piece of shared memory for use in transporting tiles
* to plug-ins. if we can't allocate a piece of shared memory then
* we'll fall back on sending the data over the pipe.
*/
PikaPlugInShm *shm = g_slice_new0 (PikaPlugInShm);
shm->shm_id = -1;
#if defined(USE_SYSV_SHM)
/* Use SysV shared memory mechanisms for transferring tile data. */
{
shm->shm_id = shmget (IPC_PRIVATE, TILE_MAP_SIZE, IPC_CREAT | 0600);
if (shm->shm_id != -1)
{
shm->shm_addr = (guchar *) shmat (shm->shm_id, NULL, 0);
if (shm->shm_addr == (guchar *) -1)
{
g_printerr ("shmat() failed: %s\n" ERRMSG_SHM_DISABLE,
g_strerror (errno));
shmctl (shm->shm_id, IPC_RMID, NULL);
shm->shm_id = -1;
}
#ifdef IPC_RMID_DEFERRED_RELEASE
if (shm->shm_addr != (guchar *) -1)
shmctl (shm->shm_id, IPC_RMID, NULL);
#endif
}
else
{
g_printerr ("shmget() failed: %s\n" ERRMSG_SHM_DISABLE,
g_strerror (errno));
}
}
#elif defined(USE_WIN32_SHM)
/* Use Win32 shared memory mechanisms for transferring tile data. */
{
gint pid;
gchar fileMapName[MAX_PATH];
wchar_t *w_fileMapName = NULL;
/* Our shared memory id will be our process ID */
pid = GetCurrentProcessId ();
/* From the id, derive the file map name */
g_snprintf (fileMapName, sizeof (fileMapName), "PIKA%d.SHM", pid);
w_fileMapName = g_utf8_to_utf16 (fileMapName, -1, NULL, NULL, NULL);
/* Create the file mapping into paging space */
shm->shm_handle = CreateFileMappingW (INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0,
TILE_MAP_SIZE,
w_fileMapName);
g_free (w_fileMapName);
w_fileMapName = NULL;
if (shm->shm_handle)
{
/* Map the shared memory into our address space for use */
shm->shm_addr = (guchar *) MapViewOfFile (shm->shm_handle,
FILE_MAP_ALL_ACCESS,
0, 0, TILE_MAP_SIZE);
/* Verify that we mapped our view */
if (shm->shm_addr)
{
shm->shm_id = pid;
}
else
{
g_printerr ("MapViewOfFile error: %u... " ERRMSG_SHM_DISABLE,
(unsigned) GetLastError ());
}
}
else
{
g_printerr ("CreateFileMapping error: %u... " ERRMSG_SHM_DISABLE,
(unsigned) GetLastError ());
}
}
#elif defined(USE_POSIX_SHM)
/* Use POSIX shared memory mechanisms for transferring tile data. */
{
gint pid;
gchar shm_handle[32];
gint shm_fd;
/* Our shared memory id will be our process ID */
pid = pika_get_pid ();
/* From the id, derive the file map name */
g_snprintf (shm_handle, sizeof (shm_handle), "/pika-shm-%d", pid);
/* Create the file mapping into paging space */
shm_fd = shm_open (shm_handle, O_RDWR | O_CREAT, 0600);
if (shm_fd != -1)
{
if (ftruncate (shm_fd, TILE_MAP_SIZE) != -1)
{
/* Map the shared memory into our address space for use */
shm->shm_addr = (guchar *) mmap (NULL, TILE_MAP_SIZE,
PROT_READ | PROT_WRITE, MAP_SHARED,
shm_fd, 0);
/* Verify that we mapped our view */
if (shm->shm_addr != MAP_FAILED)
{
shm->shm_id = pid;
}
else
{
g_printerr ("mmap() failed: %s\n" ERRMSG_SHM_DISABLE,
g_strerror (errno));
shm_unlink (shm_handle);
}
}
else
{
g_printerr ("ftruncate() failed: %s\n" ERRMSG_SHM_DISABLE,
g_strerror (errno));
shm_unlink (shm_handle);
}
close (shm_fd);
}
else
{
g_printerr ("shm_open() failed: %s\n" ERRMSG_SHM_DISABLE,
g_strerror (errno));
}
}
#endif
if (shm->shm_id == -1)
{
g_slice_free (PikaPlugInShm, shm);
shm = NULL;
}
else
{
PIKA_LOG (SHM, "attached shared memory segment ID = %d", shm->shm_id);
}
return shm;
}
void
pika_plug_in_shm_free (PikaPlugInShm *shm)
{
g_return_if_fail (shm != NULL);
if (shm->shm_id != -1)
{
#if defined (USE_SYSV_SHM)
shmdt (shm->shm_addr);
#ifndef IPC_RMID_DEFERRED_RELEASE
shmctl (shm->shm_id, IPC_RMID, NULL);
#endif
#elif defined(USE_WIN32_SHM)
if (shm->shm_handle)
CloseHandle (shm->shm_handle);
#elif defined(USE_POSIX_SHM)
gchar shm_handle[32];
munmap (shm->shm_addr, TILE_MAP_SIZE);
g_snprintf (shm_handle, sizeof (shm_handle), "/pika-shm-%d",
shm->shm_id);
shm_unlink (shm_handle);
#endif
PIKA_LOG (SHM, "detached shared memory segment ID = %d", shm->shm_id);
}
g_slice_free (PikaPlugInShm, shm);
}
gint
pika_plug_in_shm_get_id (PikaPlugInShm *shm)
{
g_return_val_if_fail (shm != NULL, -1);
return shm->shm_id;
}
guchar *
pika_plug_in_shm_get_addr (PikaPlugInShm *shm)
{
g_return_val_if_fail (shm != NULL, NULL);
return shm->shm_addr;
}

View File

@ -0,0 +1,35 @@
/* 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
*
* pikapluginshm.h
*
* 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/>.
*/
#ifndef __PIKA_PLUG_IN_SHM_H__
#define __PIKA_PLUG_IN_SHM_H__
PikaPlugInShm * pika_plug_in_shm_new (void);
void pika_plug_in_shm_free (PikaPlugInShm *shm);
gint pika_plug_in_shm_get_id (PikaPlugInShm *shm);
guchar * pika_plug_in_shm_get_addr (PikaPlugInShm *shm);
#endif /* __PIKA_PLUG_IN_SHM_H__ */

View File

@ -0,0 +1,160 @@
/* 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
*
* pikatemporaryprocedure.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "plug-in-types.h"
#include "core/pika.h"
#include "pikaplugin.h"
#define __YES_I_NEED_PIKA_PLUG_IN_MANAGER_CALL__
#include "pikapluginmanager-call.h"
#include "pikatemporaryprocedure.h"
#include "pika-intl.h"
static void pika_temporary_procedure_finalize (GObject *object);
static PikaValueArray * pika_temporary_procedure_execute (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
PikaValueArray *args,
GError **error);
static void pika_temporary_procedure_execute_async (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
PikaValueArray *args,
PikaDisplay *display);
static GFile * pika_temporary_procedure_get_file (PikaPlugInProcedure *procedure);
G_DEFINE_TYPE (PikaTemporaryProcedure, pika_temporary_procedure,
PIKA_TYPE_PLUG_IN_PROCEDURE)
#define parent_class pika_temporary_procedure_parent_class
static void
pika_temporary_procedure_class_init (PikaTemporaryProcedureClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaProcedureClass *proc_class = PIKA_PROCEDURE_CLASS (klass);
PikaPlugInProcedureClass *plug_class = PIKA_PLUG_IN_PROCEDURE_CLASS (klass);
object_class->finalize = pika_temporary_procedure_finalize;
proc_class->execute = pika_temporary_procedure_execute;
proc_class->execute_async = pika_temporary_procedure_execute_async;
plug_class->get_file = pika_temporary_procedure_get_file;
}
static void
pika_temporary_procedure_init (PikaTemporaryProcedure *proc)
{
PIKA_PROCEDURE (proc)->proc_type = PIKA_PDB_PROC_TYPE_TEMPORARY;
}
static void
pika_temporary_procedure_finalize (GObject *object)
{
/* PikaTemporaryProcedure *proc = PIKA_TEMPORARY_PROCEDURE (object); */
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static PikaValueArray *
pika_temporary_procedure_execute (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
PikaValueArray *args,
GError **error)
{
return pika_plug_in_manager_call_run_temp (pika->plug_in_manager,
context, progress,
PIKA_TEMPORARY_PROCEDURE (procedure),
args);
}
static void
pika_temporary_procedure_execute_async (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
PikaValueArray *args,
PikaDisplay *display)
{
PikaTemporaryProcedure *temp_procedure = PIKA_TEMPORARY_PROCEDURE (procedure);
PikaValueArray *return_vals;
return_vals = pika_plug_in_manager_call_run_temp (pika->plug_in_manager,
context, progress,
temp_procedure,
args);
if (return_vals)
{
PikaPlugInProcedure *proc = PIKA_PLUG_IN_PROCEDURE (procedure);
pika_plug_in_procedure_handle_return_values (proc,
pika, progress,
return_vals);
pika_value_array_unref (return_vals);
}
}
static GFile *
pika_temporary_procedure_get_file (PikaPlugInProcedure *procedure)
{
return PIKA_TEMPORARY_PROCEDURE (procedure)->plug_in->file;
}
/* public functions */
PikaProcedure *
pika_temporary_procedure_new (PikaPlugIn *plug_in)
{
PikaTemporaryProcedure *proc;
g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), NULL);
proc = g_object_new (PIKA_TYPE_TEMPORARY_PROCEDURE, NULL);
proc->plug_in = plug_in;
PIKA_PLUG_IN_PROCEDURE (proc)->file = g_file_new_for_path ("none");
return PIKA_PROCEDURE (proc);
}

View File

@ -0,0 +1,59 @@
/* 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
*
* pikatemporaryprocedure.h
*
* 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/>.
*/
#ifndef __PIKA_TEMPORARY_PROCEDURE_H__
#define __PIKA_TEMPORARY_PROCEDURE_H__
#include "pikapluginprocedure.h"
#define PIKA_TYPE_TEMPORARY_PROCEDURE (pika_temporary_procedure_get_type ())
#define PIKA_TEMPORARY_PROCEDURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_TEMPORARY_PROCEDURE, PikaTemporaryProcedure))
#define PIKA_TEMPORARY_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_TEMPORARY_PROCEDURE, PikaTemporaryProcedureClass))
#define PIKA_IS_TEMPORARY_PROCEDURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_TEMPORARY_PROCEDURE))
#define PIKA_IS_TEMPORARY_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_TEMPORARY_PROCEDURE))
#define PIKA_TEMPORARY_PROCEDURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_TEMPORARY_PROCEDURE, PikaTemporaryProcedureClass))
typedef struct _PikaTemporaryProcedureClass PikaTemporaryProcedureClass;
struct _PikaTemporaryProcedure
{
PikaPlugInProcedure parent_instance;
PikaPlugIn *plug_in;
};
struct _PikaTemporaryProcedureClass
{
PikaPlugInProcedureClass parent_class;
};
GType pika_temporary_procedure_get_type (void) G_GNUC_CONST;
PikaProcedure * pika_temporary_procedure_new (PikaPlugIn *plug_in);
#endif /* __PIKA_TEMPORARY_PROCEDURE_H__ */

119
app/plug-in/plug-in-enums.c Normal file
View File

@ -0,0 +1,119 @@
/* Generated data (by pika-mkenums) */
#include "stamp-plug-in-enums.h"
#include "config.h"
#include <gio/gio.h>
#include "libpikabase/pikabase.h"
#include "plug-in-enums.h"
#include "pika-intl.h"
/* enumerations from "plug-in-enums.h" */
GType
pika_plug_in_image_type_get_type (void)
{
static const GFlagsValue values[] =
{
{ PIKA_PLUG_IN_RGB_IMAGE, "PIKA_PLUG_IN_RGB_IMAGE", "rgb-image" },
{ PIKA_PLUG_IN_GRAY_IMAGE, "PIKA_PLUG_IN_GRAY_IMAGE", "gray-image" },
{ PIKA_PLUG_IN_INDEXED_IMAGE, "PIKA_PLUG_IN_INDEXED_IMAGE", "indexed-image" },
{ PIKA_PLUG_IN_RGBA_IMAGE, "PIKA_PLUG_IN_RGBA_IMAGE", "rgba-image" },
{ PIKA_PLUG_IN_GRAYA_IMAGE, "PIKA_PLUG_IN_GRAYA_IMAGE", "graya-image" },
{ PIKA_PLUG_IN_INDEXEDA_IMAGE, "PIKA_PLUG_IN_INDEXEDA_IMAGE", "indexeda-image" },
{ 0, NULL, NULL }
};
static const PikaFlagsDesc descs[] =
{
{ PIKA_PLUG_IN_RGB_IMAGE, "PIKA_PLUG_IN_RGB_IMAGE", NULL },
{ PIKA_PLUG_IN_GRAY_IMAGE, "PIKA_PLUG_IN_GRAY_IMAGE", NULL },
{ PIKA_PLUG_IN_INDEXED_IMAGE, "PIKA_PLUG_IN_INDEXED_IMAGE", NULL },
{ PIKA_PLUG_IN_RGBA_IMAGE, "PIKA_PLUG_IN_RGBA_IMAGE", NULL },
{ PIKA_PLUG_IN_GRAYA_IMAGE, "PIKA_PLUG_IN_GRAYA_IMAGE", NULL },
{ PIKA_PLUG_IN_INDEXEDA_IMAGE, "PIKA_PLUG_IN_INDEXEDA_IMAGE", NULL },
{ 0, NULL, NULL }
};
static GType type = 0;
if (G_UNLIKELY (! type))
{
type = g_flags_register_static ("PikaPlugInImageType", values);
pika_type_set_translation_context (type, "plug-in-image-type");
pika_flags_set_value_descriptions (type, descs);
}
return type;
}
GType
pika_plug_in_call_mode_get_type (void)
{
static const GEnumValue values[] =
{
{ PIKA_PLUG_IN_CALL_NONE, "PIKA_PLUG_IN_CALL_NONE", "none" },
{ PIKA_PLUG_IN_CALL_RUN, "PIKA_PLUG_IN_CALL_RUN", "run" },
{ PIKA_PLUG_IN_CALL_QUERY, "PIKA_PLUG_IN_CALL_QUERY", "query" },
{ PIKA_PLUG_IN_CALL_INIT, "PIKA_PLUG_IN_CALL_INIT", "init" },
{ 0, NULL, NULL }
};
static const PikaEnumDesc descs[] =
{
{ PIKA_PLUG_IN_CALL_NONE, "PIKA_PLUG_IN_CALL_NONE", NULL },
{ PIKA_PLUG_IN_CALL_RUN, "PIKA_PLUG_IN_CALL_RUN", NULL },
{ PIKA_PLUG_IN_CALL_QUERY, "PIKA_PLUG_IN_CALL_QUERY", NULL },
{ PIKA_PLUG_IN_CALL_INIT, "PIKA_PLUG_IN_CALL_INIT", NULL },
{ 0, NULL, NULL }
};
static GType type = 0;
if (G_UNLIKELY (! type))
{
type = g_enum_register_static ("PikaPlugInCallMode", values);
pika_type_set_translation_context (type, "plug-in-call-mode");
pika_enum_set_value_descriptions (type, descs);
}
return type;
}
GType
pika_file_procedure_group_get_type (void)
{
static const GEnumValue values[] =
{
{ PIKA_FILE_PROCEDURE_GROUP_NONE, "PIKA_FILE_PROCEDURE_GROUP_NONE", "none" },
{ PIKA_FILE_PROCEDURE_GROUP_ANY, "PIKA_FILE_PROCEDURE_GROUP_ANY", "any" },
{ PIKA_FILE_PROCEDURE_GROUP_OPEN, "PIKA_FILE_PROCEDURE_GROUP_OPEN", "open" },
{ PIKA_FILE_PROCEDURE_GROUP_SAVE, "PIKA_FILE_PROCEDURE_GROUP_SAVE", "save" },
{ PIKA_FILE_PROCEDURE_GROUP_EXPORT, "PIKA_FILE_PROCEDURE_GROUP_EXPORT", "export" },
{ 0, NULL, NULL }
};
static const PikaEnumDesc descs[] =
{
{ PIKA_FILE_PROCEDURE_GROUP_NONE, "PIKA_FILE_PROCEDURE_GROUP_NONE", NULL },
{ PIKA_FILE_PROCEDURE_GROUP_ANY, "PIKA_FILE_PROCEDURE_GROUP_ANY", NULL },
{ PIKA_FILE_PROCEDURE_GROUP_OPEN, "PIKA_FILE_PROCEDURE_GROUP_OPEN", NULL },
{ PIKA_FILE_PROCEDURE_GROUP_SAVE, "PIKA_FILE_PROCEDURE_GROUP_SAVE", NULL },
{ PIKA_FILE_PROCEDURE_GROUP_EXPORT, "PIKA_FILE_PROCEDURE_GROUP_EXPORT", NULL },
{ 0, NULL, NULL }
};
static GType type = 0;
if (G_UNLIKELY (! type))
{
type = g_enum_register_static ("PikaFileProcedureGroup", values);
pika_type_set_translation_context (type, "file-procedure-group");
pika_enum_set_value_descriptions (type, descs);
}
return type;
}
/* Generated data ends here */

View File

@ -0,0 +1,68 @@
/* 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
*
* 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/>.
*/
#ifndef __PLUG_IN_ENUMS_H__
#define __PLUG_IN_ENUMS_H__
#define PIKA_TYPE_PLUG_IN_IMAGE_TYPE (pika_plug_in_image_type_get_type ())
GType pika_plug_in_image_type_get_type (void) G_GNUC_CONST;
typedef enum
{
PIKA_PLUG_IN_RGB_IMAGE = 1 << 0,
PIKA_PLUG_IN_GRAY_IMAGE = 1 << 1,
PIKA_PLUG_IN_INDEXED_IMAGE = 1 << 2,
PIKA_PLUG_IN_RGBA_IMAGE = 1 << 3,
PIKA_PLUG_IN_GRAYA_IMAGE = 1 << 4,
PIKA_PLUG_IN_INDEXEDA_IMAGE = 1 << 5
} PikaPlugInImageType;
#define PIKA_TYPE_PLUG_CALL_MODE (pika_plug_in_call_mode_get_type ())
GType pika_plug_in_call_mode_get_type (void) G_GNUC_CONST;
typedef enum
{
PIKA_PLUG_IN_CALL_NONE,
PIKA_PLUG_IN_CALL_RUN,
PIKA_PLUG_IN_CALL_QUERY,
PIKA_PLUG_IN_CALL_INIT
} PikaPlugInCallMode;
#define PIKA_TYPE_FILE_PROCEDURE_GROUP (pika_file_procedure_group_get_type ())
GType pika_file_procedure_group_get_type (void) G_GNUC_CONST;
typedef enum
{
PIKA_FILE_PROCEDURE_GROUP_NONE,
PIKA_FILE_PROCEDURE_GROUP_ANY,
PIKA_FILE_PROCEDURE_GROUP_OPEN,
PIKA_FILE_PROCEDURE_GROUP_SAVE,
PIKA_FILE_PROCEDURE_GROUP_EXPORT
} PikaFileProcedureGroup;
#endif /* __PLUG_IN_ENUMS_H__ */

View File

@ -0,0 +1,125 @@
/* 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
*
* plug-in-menu-path.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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gio/gio.h>
#include "libpikabase/pikabase.h"
#include "plug-in-types.h"
#include "plug-in-menu-path.h"
typedef struct _MenuPathMapping MenuPathMapping;
struct _MenuPathMapping
{
const gchar *orig_path;
const gchar *label;
const gchar *mapped_path;
};
static const MenuPathMapping menu_path_mappings[] =
{
{ "<Image>/File/Acquire", NULL, "<Image>/File/Create/Acquire" },
{ "<Image>/File/New", NULL, "<Image>/File/Create" },
{ "<Image>/Image/Mode/Color Profile", NULL, "<Image>/Image/Color Management" },
{ NULL, NULL, NULL }
};
gchar *
plug_in_menu_path_map (const gchar *menu_path,
const gchar *menu_label)
{
const MenuPathMapping *mapping;
gchar *stripped_label = NULL;
g_return_val_if_fail (menu_path != NULL, NULL);
if (menu_label)
stripped_label = pika_strip_uline (menu_label);
for (mapping = menu_path_mappings; mapping->orig_path; mapping++)
{
if (g_str_has_prefix (menu_path, mapping->orig_path))
{
gint orig_len = strlen (mapping->orig_path);
gchar *mapped_path;
/* if the mapping has a label, only map if the passed label
* is identical and the paths' lengths match exactly.
*/
if (mapping->label &&
(! stripped_label ||
strlen (menu_path) != orig_len ||
strcmp (mapping->label, stripped_label)))
{
continue;
}
if (strlen (menu_path) > orig_len)
mapped_path = g_strconcat (mapping->mapped_path,
menu_path + orig_len,
NULL);
else
mapped_path = g_strdup (mapping->mapped_path);
#if PIKA_UNSTABLE
{
gchar *orig;
gchar *mapped;
if (menu_label)
{
orig = g_strdup_printf ("%s/%s", menu_path, stripped_label);
mapped = g_strdup_printf ("%s/%s", mapped_path, stripped_label);
}
else
{
orig = g_strdup (menu_path);
mapped = g_strdup (mapped_path);
}
g_printerr (" mapped '%s' to '%s'\n", orig, mapped);
g_free (orig);
g_free (mapped);
}
#endif
g_free (stripped_label);
return mapped_path;
}
}
g_free (stripped_label);
return g_strdup (menu_path);
}

View File

@ -0,0 +1,32 @@
/* 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
*
* plug-in-menu-path.h
*
* 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/>.
*/
#ifndef __PLUG_IN_MENU_PATH_H__
#define __PLUG_IN_MENU_PATH_H__
gchar * plug_in_menu_path_map (const gchar *menu_path,
const gchar *menu_label);
#endif /* __PLUG_IN_MENU_PATH_H__ */

1333
app/plug-in/plug-in-rc.c Normal file

File diff suppressed because it is too large Load Diff

37
app/plug-in/plug-in-rc.h Normal file
View File

@ -0,0 +1,37 @@
/* 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
*
* plug-in-rc.h
* Copyright (C) 2001 Sven Neumann <sven@gimp.org>
*
* 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/>.
*/
#ifndef __PLUG_IN_RC_H__
#define __PLUG_IN_RC_H__
GSList * plug_in_rc_parse (Pika *pika,
GFile *file,
GError **error);
gboolean plug_in_rc_write (GSList *plug_in_defs,
GFile *file,
GError **error);
#endif /* __PLUG_IN_RC_H__ */

View File

@ -0,0 +1,44 @@
/* 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
*
* 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/>.
*/
#ifndef __PLUG_IN_TYPES_H__
#define __PLUG_IN_TYPES_H__
#include "core/core-types.h"
#include "plug-in/plug-in-enums.h"
#define PIKA_PLUG_IN_TILE_WIDTH 128
#define PIKA_PLUG_IN_TILE_HEIGHT 128
typedef struct _PikaPlugIn PikaPlugIn;
typedef struct _PikaPlugInDebug PikaPlugInDebug;
typedef struct _PikaPlugInDef PikaPlugInDef;
typedef struct _PikaPlugInManager PikaPlugInManager;
typedef struct _PikaPlugInMenuBranch PikaPlugInMenuBranch;
typedef struct _PikaPlugInProcFrame PikaPlugInProcFrame;
typedef struct _PikaPlugInShm PikaPlugInShm;
#endif /* __PLUG_IN_TYPES_H__ */