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

View File

@ -0,0 +1,178 @@
# About script-fu-interpreter
It is PIKA's Scheme interpreter akin to any other language interpreter,
rather than a PIKA extension as is the plugin extension-script-fu.
This interpreter (like all the ScriptFu plugins) embeds a TinyScheme interpreter.
It is an executable program that is passed the name of a .scm file.
The combination defines one or more PDB procedures of type PLUGIN.
Differences from extension-script-fu
====================================
Since pika-script-fu-interpreter and extension-script-fu use the same
embedded interpreter (they both wrap TinyScheme)
there is no difference in the language interpreted.
Any differences are in the larger behavior of plugins.
### PDB Procedure type
Defines PDB procedure(s) of type PLUGIN.
Unlike for the scriptfu extension,
where a .scm file defines PDB procedure(s) of type TEMPORARY
(owned by the PDB procedure of type PLUGIN named extension-script-fu)
### Protocol
Uses protocol to PIKA like other interpreters e.g. Python
(query, create, and run phases.)
The protocol to PIKA is unlike the protocol to the PIKA extension extension-script-fu.
(Note that "extension" has many meanings. It can denote: a protocol,
or "suffix of a filename", or "a resource that extends PIKA."
extension-script-fu is "a resource that extends PIKA" and it also uses
the "extension" protocol,
while pika-script-fu-interpreter is a "a resource that extends PIKA" but uses
the "plugin" protocol.)
### Process lifetimes
Executed many times, for many phases,
unlike extension-script-fu which stays executing and gets a remote procedure call
from PIKA to run a PDB procedure.
### Process concurrency
Each invocation of a plugin is in a separate process.
One plugin process crash does not affect others.
Unlike extension-script-fu, where a crash means the PIKA app must be restarted
to restart extension-script-fu.
### GUI concurrency
Each plugin can have its own GUI visible concurrently
with the GUI of other ScriptFu plugins.
For extension-script-fu, an open dialog
prevents other plugins in /scripts (implemented by extension-script-fu)
from opening a dialog.
Instead extension-script-fu opens such dialogs sequentially.
This difference is not very important,
since most users work sequentially.
Most dialogs for plugins do not do anything substantive
until a user closes the dialog with the OK button.
### Calls between scripts
In extension-script-fu, a call to another PDB procedure
implemented by TEMPORARY procedure owned by extension-script-fu
does not leave the process.
In pika-script-fu-interpreter, a call to another PDB procedure
implemented in another plugin file starts another process.
For other plugins, most calls to another PDB procedure starts another process.
The exception is when one plugin file implements many PDB procedures.
One common case is when one plugin file implements its own TEMPORARY PDB procedures that
exist only for the duration of the plugin's lifetime.
Naming
======
script-fu-interpreter is the informal name.
Source is located in /plug-ins/script-fu/interpreter
Filename of the executable is pika-script-fu-interpreter-3.0.
The name is versioned by a number corresponding to the API
and the major version of PIKA (when script-fu-interpreter was introduced).
We expect plugin authors to be insulated from changes to script-fu-interpreter,
for the duration of the PIKA 3 version.
About .scm scripts for script-fu-interpreter
============================================
The contents of a .scm file queried by script-fu-interpreter
are the same as those handled by extension-script-fu
except for the addition of a shebang:
#!/usr/bin/env pika-script-fu-interpreter-3.0
(define (script-fu-test img drawable)
...
(script-fu-register "script-fu-test"
...
### Query of scripts
As for other interpreters, a plugin script file must have certain attributes
to be queried by PIKA. But a queried file may define many PDB procedures.
A .scm file queried by script-fu-interpreter:
- must have permission to execute.
- must be in a directory names the same as the file's base name (less suffix.)
A directory containing an .scm file queried by script-fu-interpreter
is usually a subdirectory of one of the /plug-ins directories,
unlike for extension-script-fu, where the .scm files are in a /scripts dir.
A plugin directory should contain only one queriable .scm file:
only one file can have the same base name as the directory and
PIKA will query that file.
### Defining many PDB procedures per directory
When PIKA queries, script-fu-interpreter will load *ALL* the .scm files
in the same directory (regardless of shebang or execute permission.)
Any of the .scm files can declare and register a PDB procedure.
Any single .scm file can declare and register many PDB procedures.
Similarly, when PIKA runs a named PDB procedure defined in an .scm file,
script-fu-interpreter will actually load *ALL* the .scm files
in the same directory, but run only the define run function so named.
A plugin directory that contains many .scm files having a shebang
will also work, since only one can be named the same as the parent directory,
and PIKA will only query it,
but find the other .scm files with a shebang.
### Requery of scripts
As with other plugins, PIKA caches plugin definitions between sessions.
PIKA queries plugin files at startup.
PIKA will not requery any plugin files which have not changed since cached.
PIKA will not query a plugin file that is added to the file system
until PIKA is restarted.
(Filters>Development>ScriptFu>Refresh Scripts will not requery script files
handled by pika-script-fu-interpreter, only those handled by extension-script-fu.)
### Errors during query
Most errors occurring during query appear only in the console.
If you are a plugin author, you should start PIKA in a console
so you can see such errors.
A script may be malformed because it does not define
a "run" function having the same name as the PDB procedure name declared
in the call to script-fu-register().
Formerly, such a malformed script was successfully queried but
the script would throw a "undefined variable" error at run time.
Now, such a malformed script is not queried successfully,
but throws a warning to the console:
"Run function not defined, or does not match PDB procedure name:"
Test scripts
============
Small test scripts for pika-script-fu-interpreter
are located in /plug-ins/script-fu/scripts/test
The script ts-helloworld.scm,
formerly installed in /scripts and handled by extension-script-fu,
is now installed in /plug-ins/ts-helloworld/ts-helloworld.scm
and is now handled by pika-script-fu-interpreter.
It appears as "Filters>Development>Script-Fu>Test>Hello World..."

View File

@ -0,0 +1,42 @@
scriptfuInclude = include_directories('..')
executable_name = 'pika-script-fu-interpreter-' + pika_api_version
plugin_sources = [
'script-fu-interpreter.c',
'script-fu-interpreter-plugin.c',
]
if platform_windows
plugin_sources += windows.compile_resources(
plugin_rc,
args: [
'--define', 'ORIGINALFILENAME_STR="@0@"'.format(executable_name+'.exe'),
'--define', 'INTERNALNAME_STR="@0@"' .format(executable_name),
'--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
],
)
endif
# !!! Installs as a usual binary say to /usr/bin, unlike extension-script-fu
# PIKA queries scripts with shebangs, which invokes pika-script-fu-interpreter-3.0.
script_fu_interpreter = executable(executable_name,
plugin_sources,
dependencies: [
libpikaui_dep,
math,
],
c_args: [
'-DG_LOG_DOMAIN="scriptfu"',
],
include_directories: [
scriptfuInclude,
],
link_with : libscriptfu,
install: true,
)

View File

@ -0,0 +1,144 @@
/* 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/>.
*/
/* This file understands how to make a PikaPlugin of the interpreter.
* This is mostly boilerplate for any plugin.
* It understands little about ScriptFu internals,
* hidden by script-fu-interpreter.[ch] and libscriptfu.
*/
#include "config.h"
#include <glib.h>
#include <libpika/pika.h>
#include "libscriptfu/script-fu-intl.h"
#include "script-fu-interpreter.h"
/* ScriptFuInterpreter subclasses PikaPlugIn */
#define SCRIPT_FU_INTERPRETER_TYPE (script_fu_interpreter_get_type ())
G_DECLARE_FINAL_TYPE (ScriptFuInterpreter, script_fu_interpreter, SCRIPT, FU_INTERPRETER, PikaPlugIn)
struct _ScriptFuInterpreter
{
PikaPlugIn parent_instance;
};
static GList * script_fu_interpreter_query_procedures (PikaPlugIn *plug_in);
static PikaProcedure * script_fu_interpreter_create_procedure (PikaPlugIn *plug_in,
const gchar *name);
G_DEFINE_TYPE (ScriptFuInterpreter, script_fu_interpreter, PIKA_TYPE_PLUG_IN)
/* An alias to argv[1], which is the path to the .scm file.
* Each instance of ScriptFuInterpreter is specialized by the script passed in argv[1]
* This var need not belong to the class or to an instance,
* because there will only be one instance of ScriptFuInterpreter per plugin process.
*/
static gchar * path_to_this_script;
/* Connect to Pika. See libpika/pika.c.
*
* Can't use PIKA_MAIN macro, it doesn't omit argv[0].
*
* First arg is app cited in the shebang.
* Second arg is the .scm file containing the shebang.
* Second to last arg is the "phase" e.g. -query or -run
* Last arg is the mode for crash dumps.
* Typical argv:
* pika-script-fu-interpreter-3.0 ~/.config/PIKA/2.99/plug-ins/fu/fu
* -pika 270 12 11 -query 1
*/
int main (int argc, char *argv[])
{
g_debug ("Enter script-fu-interpreter main");
/* Alias path to this plugin's script file. */
path_to_this_script = argv[1];
/* pika_main will create an instance of the class given by the first arg, a GType.
* The class is a subclass of PikaPlugIn (with overridden query and create methods.)
* PIKA will subsequently callback the query or create methods,
* or the run_func of the PDB procedure of the plugin,
* depending on the "phase" arg in argv,
* which is set by the pika plugin manager, which is invoking this interpreter.
*/
/* Omit argv[0] when passing to pika */
pika_main (SCRIPT_FU_INTERPRETER_TYPE, argc-1, &argv[1] );
g_debug ("Exit script-fu-interpreter.");
}
DEFINE_STD_SET_I18N
static void
script_fu_interpreter_class_init (ScriptFuInterpreterClass *klass)
{
PikaPlugInClass *plug_in_class = PIKA_PLUG_IN_CLASS (klass);
plug_in_class->query_procedures = script_fu_interpreter_query_procedures;
plug_in_class->create_procedure = script_fu_interpreter_create_procedure;
plug_in_class->set_i18n = STD_SET_I18N;
}
/* called by the GType system to initialize instance of the class. */
static void
script_fu_interpreter_init (ScriptFuInterpreter *script_fu)
{
/* Nothing to do. */
}
/* Return the names of PDB procedures implemented. A callback from PIKA. */
static GList *
script_fu_interpreter_query_procedures (PikaPlugIn *plug_in)
{
GList *result = NULL;
g_debug ("queried");
result = script_fu_interpreter_list_defined_proc_names (plug_in, path_to_this_script);
if (g_list_length (result) < 1)
g_warning ("No procedures defined in %s", path_to_this_script);
/* Caller is PIKA and it will free the list. */
return result;
}
/* Create and return a PikaPDBProcedure,
* for the named one of the PDB procedures that the script implements.
* A callback from PIKA.
*
* Also set attributes on the procedure, most importantly, menu items (optional.)
* Also create any menus/submenus that the script defines e.g. Filters>My
*/
static PikaProcedure *
script_fu_interpreter_create_procedure (PikaPlugIn *plug_in,
const gchar *proc_name)
{
return script_fu_interpreter_create_proc_at_path (plug_in,
proc_name,
path_to_this_script);
}

View File

@ -0,0 +1,196 @@
/* 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.h>
#include <libpika/pika.h>
#include "libscriptfu/script-fu-lib.h"
#include "script-fu-interpreter.h"
/* Implementation of the outer ScriptFuInterpreter.
* This understands ScriptFu internals
* i.e. uses libscriptfu shared with other ScriptFu plugins e.g. extension-script-fu.
*/
/* We don't need to load (into the interpreter) any .scm files handled by extension-script-fu.
* Namely, the .scm in the PIKA installation /scripts or in the user local /scripts dirs.
*
* During startup, PIKA might call pika-script-fu-interpreter
* to query new files such as /plug-ins/fu/fu.scm.
* This is before extension-script-fu starts.
* But all the .scm files handled by extension-script-fu are type TEMPORARY and not needed
* for a /plug-ins/fu.scm to be queried.
* The only Scheme executed during query are calls to script-fu-register.
* Later, when a /plug-ins/fu.scm is run, it can call temporary PDB procedures
* that extension-script-fu provides.
*
* When we call script_fu_init_embedded_interpreter(),
* the passed paths should include the path to /scripts
* because that is the location of scripts for initialization and compatibility
* (script-fu.init, plug-in-compat.init and script-fu-compat.init,
* which are really scheme files.)
*
* scrip-fu-interpreter always inits embedded interpreter(allow_register=TRUE)
* In the "run" phase, you don't need script-fu-register to be defined, but its harmless.
*/
static GFile *script_fu_get_plugin_parent_path (const gchar *path_to_this_script);
static void script_fu_free_path_list (GList **list);
/* Return a list of PDB procedure names defined in all .scm files in
* the parent dir of the given path, which is a filename of the one being queried.
*
* Each .scm file may contain many calls to script-fu-register, which defines a PDB procedure.
* All .scm files in the parent dir are searched.
*
* This executable is named script-fu-interpreter
* but no PDB procedure is named "script-fu-interpreter".
* Instead, the interpreter registers PDB procs named from name strings
* give in the in script-fu-register() calls in the interpreted scripts.
*
* Caller must free the list.
*/
GList *
script_fu_interpreter_list_defined_proc_names (PikaPlugIn *plug_in,
const gchar *path_to_this_script)
{
GList *name_list = NULL; /* list of strings */
GList *path_list = NULL; /* list of GFile */
/* path_list is /scripts dir etc. from which we will load compat and init scripts.
* second argument TRUE means define script-fu-register into the interpreter.
*/
path_list = script_fu_search_path ();
script_fu_init_embedded_interpreter (path_list, TRUE, PIKA_RUN_NONINTERACTIVE);
script_fu_free_path_list (&path_list);
/* Reuse path_list, now a list of one path, the parent dir of the queried script. */
path_list = g_list_append (path_list,
script_fu_get_plugin_parent_path (path_to_this_script));
name_list = script_fu_find_scripts_list_proc_names (plug_in, path_list);
script_fu_free_path_list (&path_list);
/* Usually name_list is not NULL i.e. not empty.
* But an .scm file that is not an actual PIKA plugin, or broken, may yield empty list.
*/
return name_list;
}
/* Create a PDB proc of type PLUGIN with the given name.
* Unlike extension-script-fu, create proc of type PLUGIN.
*
* We are in "create procedure" phase of call from PIKA.
* Create a PDB procedure that the script-fu-interpreter wraps.
*
* A PikaPDBProcedure has a run function, here script_fu_script_proc()
* of this outer interpreter.
* Sometime after the create, PIKA calls the run func, passing a name aka command.
* In ScriptFu, the same name is used for the PDB proc and the Scheme function
* which is the inner run func defined in the script.
* script_fu_script_proc calls the TinyScheme interpreter to evaluate
* the inner run func in the script.
*/
PikaProcedure *
script_fu_interpreter_create_proc_at_path (PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *path_to_this_script
)
{
PikaProcedure *procedure = NULL;
GList *path_list = NULL; /* list of GFile */
g_debug ("script_fu_interpreter_create_proc_at_path, name: %s", proc_name);
/* Require proc_name is a suitable name for a PDB procedure eg "script-fu-test".
* (Not tested for canonical name "script-fu-<something>")
* Require proc_name is a name that was queried earlier.
* Require the proc_name was defined in some .scm file
* in the same directory as the .scm file passed as argv[0].
* The name of the .scm file eg "/plug-ins/fu/fu.scm"
* can be entirely different from proc_name.
*
* Otherwise, we simply won't find the proc_name defined in any .scm file,
* and will fail gracefully, returning NULL.
*/
path_list = script_fu_search_path ();
path_list = g_list_append (path_list,
script_fu_get_plugin_parent_path (path_to_this_script));
/* path_list are the /scripts dir, for .init and compat.scm, plus the path to this.
* second arg TRUE means define script-fu-register so it is effective.
*/
script_fu_init_embedded_interpreter (path_list, TRUE, PIKA_RUN_NONINTERACTIVE);
/* Reuse path_list, now a list of only the path to this script. */
script_fu_free_path_list (&path_list);
path_list = g_list_append (path_list,
script_fu_get_plugin_parent_path (path_to_this_script));
procedure = script_fu_find_scripts_create_PDB_proc_plugin (plug_in, path_list, proc_name);
script_fu_free_path_list (&path_list);
/* When procedure is not NULL, assert:
* some .scm was evaluated.
* the script defined many PDB procedures locally, i.e. in script-tree
* we created a single PDB procedure (but not put it in the PIKA PDB)
*
* Ensure procedure is-a PikaProcedure or NULL.
* PIKA is the caller and will put non-NULL procedure in the PDB.
*/
return procedure;
}
/* Return GFile of the parent directory of this plugin, whose filename is given.
*
* Caller must free the GFile.
*/
static GFile *
script_fu_get_plugin_parent_path (const gchar *path_to_this_script)
{
GFile *path = NULL;
GFile *parent_path = NULL;
/* A libpika PikaPlugin does not know its path,
* but its path was passed in argv to this interpreter.
* The path is to a file being queried e.g. "~/.config/PIKA/2.99/plug-ins/fu/fu.scm"
*/
g_debug ("path to this plugin %s", path_to_this_script);
path = g_file_new_for_path (path_to_this_script);
parent_path = g_file_get_parent (path);
g_object_unref (path);
return parent_path;
}
/* Free a list of paths at the given handle.
* Ensures that the pointer to the list is NULL, prevents "dangling."
* g_list_free_full alone does not do that.
*/
static void
script_fu_free_path_list (GList **list)
{
/* !!! g_steal_pointer takes a handle. */
g_list_free_full (g_steal_pointer (list), g_object_unref);
}

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 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 __SCRIPT_FU_INTERPRETER_H__
#define __SCRIPT_FU_INTERPRETER_H__
GList *script_fu_interpreter_list_defined_proc_names (
PikaPlugIn *plug_in,
const gchar *path_to_this_plugin);
PikaProcedure *script_fu_interpreter_create_proc_at_path (
PikaPlugIn *plug_in,
const gchar *proc_name,
const gchar *path_to_this_script);
#endif /* __SCRIPT_FU_INTERPRETER_H__ */