ScriptFu: add Scheme language function script-fu-register-regular

Building on prior commits, with a few small fixes to them.

First demonstrable changes towards #12605.

Font map plugin is ported as a test case.

Old-style plugins using script-fu-register still work.
This commit is contained in:
lloyd konneker
2024-09-21 12:03:42 -04:00
committed by Lloyd Konneker
parent d361256977
commit d0a6c4c758
12 changed files with 262 additions and 38 deletions

View File

@ -77,6 +77,8 @@ static pointer script_fu_register_call (scheme *sc,
pointer a);
static pointer script_fu_register_call_filter (scheme *sc,
pointer a);
static pointer script_fu_register_call_regular (scheme *sc,
pointer a);
static pointer script_fu_menu_register_call (scheme *sc,
pointer a);
static pointer script_fu_use_v3_call (scheme *sc,
@ -571,12 +573,14 @@ ts_define_procedure (sc, "load-extension", scm_load_ext);
{
ts_define_procedure (sc, "script-fu-register", script_fu_register_call);
ts_define_procedure (sc, "script-fu-register-filter", script_fu_register_call_filter);
ts_define_procedure (sc, "script-fu-register-regular", script_fu_register_call_regular);
ts_define_procedure (sc, "script-fu-menu-register", script_fu_menu_register_call);
}
else
{
ts_define_procedure (sc, "script-fu-register", script_fu_nil_call);
ts_define_procedure (sc, "script-fu-register-filter", script_fu_nil_call);
ts_define_procedure (sc, "script-fu-register-regular", script_fu_nil_call);
ts_define_procedure (sc, "script-fu-menu-register", script_fu_nil_call);
}
@ -1484,6 +1488,13 @@ script_fu_register_call_filter (scheme *sc,
return script_fu_add_script_filter (sc, a);
}
static pointer
script_fu_register_call_regular (scheme *sc,
pointer a)
{
return script_fu_add_script_regular (sc, a);
}
static pointer
script_fu_menu_register_call (scheme *sc,
pointer a)

View File

@ -142,10 +142,30 @@ sf_dialog_can_be_run (GimpProcedure *procedure,
return TRUE;
}
/* Omit leading "procedure" and "run-mode" properties.
* Caller must free the list.
*/
static GList*
sf_get_suffix_of_config_prop_names (GimpProcedureConfig *config)
{
guint n_specs;
GParamSpec ** pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (config), &n_specs);
GList *property_names = NULL;
for (guint i=2; i<n_specs; i++)
property_names = g_list_append (property_names, (void*) g_param_spec_get_name (pspecs[i]));
g_free (pspecs);
return property_names;
}
/* Create and run a dialog for a procedure.
* Returns true when not canceled.
* Side effects on config.
*
* When should_skip_runmode, the config has a run-mode property
* the dialog does not show.
*
* Procedure may be GimpImageProcedure or ordinary GimpProcedure.
*
* Requires gimp_ui_init already called.
@ -153,7 +173,8 @@ sf_dialog_can_be_run (GimpProcedure *procedure,
static gboolean
sf_dialog_run (GimpProcedure *procedure,
SFScript *script,
GimpProcedureConfig *config)
GimpProcedureConfig *config,
gboolean should_skip_runmode)
{
GimpProcedureDialog *dialog = NULL;
gboolean not_canceled;
@ -178,10 +199,19 @@ sf_dialog_run (GimpProcedure *procedure,
/* Create custom widget where the stock widget is not adequate. */
script_fu_widgets_custom_add (dialog, script);
/* NULL means create widgets for all properties of the procedure
* that we have not already created custom widgets for.
*/
gimp_procedure_dialog_fill_list (dialog, NULL);
/* Create widgets for all properties of the procedure not already created. */
if (should_skip_runmode)
{
GList *property_names = sf_get_suffix_of_config_prop_names (config);
gimp_procedure_dialog_fill_list (dialog, property_names);
g_list_free (property_names);
}
else
{
/* NULL means: all properties. */
gimp_procedure_dialog_fill_list (dialog, NULL);
}
not_canceled = gimp_procedure_dialog_run (dialog);
@ -214,7 +244,7 @@ script_fu_dialog_run_image_proc (
if (! sf_dialog_can_be_run (procedure, script, config))
return gimp_procedure_new_return_values (procedure, GIMP_PDB_EXECUTION_ERROR, NULL);
not_canceled = sf_dialog_run (procedure, script, config);
not_canceled = sf_dialog_run (procedure, script, config, FALSE);
/* Assert config holds validated arg values from a user interaction. */
if (not_canceled)
@ -227,7 +257,7 @@ script_fu_dialog_run_image_proc (
return result;
}
/* Run a dialog for an Procedure, then interpret the script. */
/* Run a dialog for a generic GimpProcedure, then interpret the script. */
GimpValueArray*
script_fu_dialog_run_regular_proc (GimpProcedure *procedure,
SFScript *script,
@ -240,7 +270,8 @@ script_fu_dialog_run_regular_proc (GimpProcedure *procedure,
if (! sf_dialog_can_be_run (procedure, script, config))
return gimp_procedure_new_return_values (procedure, GIMP_PDB_EXECUTION_ERROR, NULL);
not_canceled = sf_dialog_run (procedure, script, config);
not_canceled = sf_dialog_run (procedure, script, config,
TRUE); /* skip run-mode prop of config. */
/* Assert config holds validated arg values from a user interaction. */
if (not_canceled)

View File

@ -119,6 +119,78 @@ script_fu_script_new_from_metadata_args (scheme *sc,
return script;
}
/* Traverse Scheme argument list
* creating a new SFScript with metadata, but empty SFArgs (formal arg specs)
*
* Takes a handle to a pointer into the argument list.
* Advances the pointer past the metadata args.
*
* Returns new SFScript.
*
* For a script declaring using script-fu-register-regular,
* declared without image_type or drawable_arity.
*/
SFScript*
script_fu_script_new_from_metadata_regular (scheme *sc,
pointer *handle)
{
SFScript *script;
const gchar *name;
const gchar *menu_label;
const gchar *blurb;
const gchar *author;
const gchar *copyright;
const gchar *date;
const gchar *image_types;
guint n_args;
/* dereference handle into local pointer. */
pointer a = *handle;
g_debug ("script_fu_script_new_from_metadata_args");
/* Require list_length starting at a is >= 5
* else strange parsing errors at plugin query time.
*/
name = sc->vptr->string_value (sc->vptr->pair_car (a));
a = sc->vptr->pair_cdr (a);
menu_label = sc->vptr->string_value (sc->vptr->pair_car (a));
a = sc->vptr->pair_cdr (a);
blurb = sc->vptr->string_value (sc->vptr->pair_car (a));
a = sc->vptr->pair_cdr (a);
author = sc->vptr->string_value (sc->vptr->pair_car (a));
a = sc->vptr->pair_cdr (a);
/* Copyright is same as author.
* script-fu-register-regular does not require declaring copyright owner
* separately from the author.
*/
copyright = author;
date = sc->vptr->string_value (sc->vptr->pair_car (a));
a = sc->vptr->pair_cdr (a);
/* Image types not used for regular procedures. */
image_types = NULL;
/* Store local, advanced pointer at handle from caller. */
*handle = a;
/* Calculate supplied number of formal arguments of the PDB procedure,
* each takes three actual args from Scheme call.
*/
n_args = sc->vptr->list_length (sc, a) / 3;
/* This allocates empty array of SFArg. Hereafter, script knows its n_args. */
script = script_fu_script_new (name,
menu_label,
blurb,
author,
copyright,
date,
image_types,
n_args);
return script;
}
/* GimpResource
*

View File

@ -23,6 +23,9 @@ pointer script_fu_script_create_formal_args (scheme *sc,
SFScript *script);
SFScript *script_fu_script_new_from_metadata_args (scheme *sc,
pointer *handle);
SFScript *script_fu_script_new_from_metadata_regular
(scheme *sc,
pointer *handle);
pointer script_fu_script_parse_drawable_arity_arg (scheme *sc,
pointer *handle,
SFScript *script);

View File

@ -144,20 +144,23 @@ script_fu_run_image_procedure (GimpProcedure *procedure, /* GimpImageProc
*/
GimpValueArray *
script_fu_run_regular_procedure (GimpProcedure *procedure,
GimpRunMode run_mode,
GimpProcedureConfig *config,
gpointer data)
{
GimpValueArray *result = NULL;
SFScript *script;
GimpRunMode run_mode;
g_debug ("%s", G_STRFUNC);
g_debug ("script_fu_run_regular_procedure");
script = script_fu_find_script (gimp_procedure_get_name (procedure));
if (! script)
return gimp_procedure_new_return_values (procedure, GIMP_PDB_CALLING_ERROR, NULL);
/* Unlike ImageProcedure, run-mode is a prop in the config. */
g_object_get (config, "run-mode", &run_mode, NULL);
ts_set_run_mode (run_mode);
/* Need Gegl. Also inits ui, needed when mode is interactive. */

View File

@ -31,7 +31,6 @@ GimpValueArray *script_fu_run_image_procedure (GimpProcedure *procedure,
gpointer data);
GimpValueArray *script_fu_run_regular_procedure (
GimpProcedure *procedure,
GimpRunMode run_mode,
GimpProcedureConfig *config,
gpointer data);

View File

@ -157,8 +157,7 @@ script_fu_script_create_PDB_procedure (GimpPlugIn *plug_in,
if (script->proc_class == GIMP_TYPE_IMAGE_PROCEDURE)
{
g_debug ("script_fu_script_create_PDB_procedure: %s, plugin type %i, image_proc",
script->name, plug_in_type);
g_debug ("%s: %s, plugin type %i, image_proc", G_STRFUNC, script->name, plug_in_type);
procedure = gimp_image_procedure_new (plug_in, script->name,
plug_in_type,
@ -176,34 +175,67 @@ script_fu_script_create_PDB_procedure (GimpPlugIn *plug_in,
*/
script_fu_script_set_proc_args (procedure, script, 0);
/* The script declared arity, convey to GIMP. */
script_fu_script_set_drawable_sensitivity (procedure, script);
}
else
{
/* Script declares a GimpProcedure.
* Dispatch on which scheme function the script registered with.
*
* v2 had only script-fu-register.
* For compatibility, we still support it,
*/
g_assert (script->proc_class == GIMP_TYPE_PROCEDURE);
g_debug ("script_fu_script_create_PDB_procedure: %s, plugin type %i, ordinary proc",
script->name, plug_in_type);
procedure = gimp_procedure_new (plug_in, script->name,
plug_in_type,
script_fu_run_procedure,
script, NULL);
if (script_fu_script_get_is_old_style (script))
{
g_debug ("%s: %s, plugin type %i, old-style", G_STRFUNC, script->name, plug_in_type);
script_fu_script_set_proc_metadata (procedure, script);
procedure = gimp_procedure_new (plug_in, script->name,
plug_in_type,
script_fu_run_procedure, /* old-style */
script, NULL);
gimp_procedure_add_enum_argument (procedure, "run-mode",
"Run mode", "The run mode",
GIMP_TYPE_RUN_MODE,
GIMP_RUN_INTERACTIVE,
G_PARAM_READWRITE);
script_fu_script_set_proc_metadata (procedure, script);
script_fu_script_set_proc_args (procedure, script, 0);
gimp_procedure_add_enum_argument (procedure, "run-mode",
"Run mode", "The run mode",
GIMP_TYPE_RUN_MODE,
GIMP_RUN_INTERACTIVE,
G_PARAM_READWRITE);
/* !!! Author did not declare drawable arity, it was inferred. */
script_fu_script_set_drawable_sensitivity (procedure, script);
script_fu_script_set_proc_args (procedure, script, 0);
/* !!! Author did not declare drawable arity, it was inferred. */
script_fu_script_set_drawable_sensitivity (procedure, script);
}
else
{
g_debug ("%s: %s, plugin type %i, old-style", G_STRFUNC, script->name, plug_in_type);
procedure = gimp_procedure_new (plug_in, script->name,
plug_in_type,
script_fu_run_regular_procedure, /* new-style */
script, NULL);
script_fu_script_set_proc_metadata (procedure, script);
gimp_procedure_add_enum_argument (procedure, "run-mode",
"Run mode", "The run mode",
GIMP_TYPE_RUN_MODE,
GIMP_RUN_INTERACTIVE,
G_PARAM_READWRITE);
script_fu_script_set_proc_args (procedure, script, 0);
/* The script did not declare arity.
* new-style regular procedure always arity SF_NO_DRAWABLE.
* This conveys to GIMP.
*/
script_fu_script_set_drawable_sensitivity (procedure, script);
}
}
return procedure;
}
@ -458,6 +490,11 @@ script_fu_script_get_command_for_image_proc (SFScript *script,
return g_string_free (s, FALSE);
}
/* The difference between count of config properties and count of script args.
* config will have 2 extra, leading property: "procedure" and "run_mode".
*/
#define SF_ARGS_TO_CONFIG_OFFSET 2
gchar *
script_fu_script_get_command_for_regular_proc (SFScript *script,
GimpProcedureConfig *config)
@ -476,13 +513,12 @@ script_fu_script_get_command_for_regular_proc (SFScript *script,
/* The command has no run mode. */
/* config contains the "other" args
* Iterate over the GimpValueArray.
* Iterate over the GimpValueArray, starting at an offset.
* But script->args should be the same length, and types should match.
*/
pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (config), &n_pspecs);
/* config will have 1 additional property: "procedure". */
for (i = 1; i < n_pspecs; i++)
for (i = SF_ARGS_TO_CONFIG_OFFSET; i < n_pspecs; i++)
{
GParamSpec *pspec = pspecs[i];
GValue value = G_VALUE_INIT;
@ -491,7 +527,8 @@ script_fu_script_get_command_for_regular_proc (SFScript *script,
g_value_init (&value, pspec->value_type);
g_object_get_property (G_OBJECT (config), pspec->name, &value);
script_fu_arg_append_repr_from_gvalue (&script->args[i - 1], s, &value);
script_fu_arg_append_repr_from_gvalue (&script->args[i - SF_ARGS_TO_CONFIG_OFFSET],
s, &value);
g_value_unset (&value);
}
@ -686,3 +723,25 @@ script_fu_script_set_drawable_sensitivity (GimpProcedure *procedure, SFScript *s
g_warning ("Unhandled case for SFDrawableArity");
}
}
/* Set drawable arity of script to NONE, meaning a regular procedure,
* always enabled (sensitive)
*/
void
script_fu_script_set_drawable_arity_none (SFScript *script)
{
script->drawable_arity = SF_NO_DRAWABLE;
}
/* Only settable, never cleared, defaults to false. */
void
script_fu_script_set_is_old_style (SFScript *script)
{
script->is_old_style = TRUE;
}
gboolean
script_fu_script_get_is_old_style (SFScript *script)
{
return script->is_old_style;
}

View File

@ -61,6 +61,9 @@ GimpProcedure * script_fu_script_create_PDB_procedure (GimpPlugIn *plug_
SFScript *script,
GimpPDBProcType plug_in_type);
void script_fu_script_infer_drawable_arity (SFScript *script);
void script_fu_script_infer_drawable_arity (SFScript *script);
void script_fu_script_set_drawable_arity_none (SFScript *script);
void script_fu_script_set_is_old_style (SFScript *script);
gboolean script_fu_script_get_is_old_style (SFScript *script);
#endif /* __SCRIPT_FU_SCRIPT__ */

View File

@ -197,6 +197,8 @@ script_fu_add_script (scheme *sc,
script->proc_class = GIMP_TYPE_PROCEDURE;
script_fu_script_set_is_old_style (script);
script_fu_try_map_menu (script);
script_fu_append_script_to_tree (script);
return sc->NIL;
@ -249,6 +251,45 @@ script_fu_add_script_filter (scheme *sc,
return sc->NIL;
}
/* For a script's call to script-fu-register-regular.
* Traverse Scheme argument list creating a new SFScript
* whose drawable_arity is SF_NO_DRAWABLE
*
* Return NIL or a foreign_error
*/
pointer
script_fu_add_script_regular (scheme *sc,
pointer a)
{
SFScript *script;
pointer args_error; /* a foreign_error or NIL. */
/* Check metadata args args are present.
* Has two less arg than script-fu-register.
* Last metadata arg is "copyright date"
*/
if (sc->vptr->list_length (sc, a) < 5)
return foreign_error (sc, "script-fu-register-filter: Not enough arguments", 0);
/* pass handle i.e. "&a" ("a" of type "pointer" is on the stack) */
script = script_fu_script_new_from_metadata_regular (sc, &a);
script_fu_script_set_drawable_arity_none (script);
/* Parse the args to this function that are formal declarations of
* the args to the PDB procedure being defined.
*/
args_error = script_fu_script_create_formal_args (sc, &a, script);
if (args_error != sc->NIL)
return args_error;
script->proc_class = GIMP_TYPE_PROCEDURE;
script_fu_try_map_menu (script);
script_fu_append_script_to_tree (script);
return sc->NIL;
}
pointer
script_fu_add_menu (scheme *sc,
pointer a)

View File

@ -24,6 +24,8 @@ pointer script_fu_add_script (scheme *sc,
pointer a);
pointer script_fu_add_script_filter (scheme *sc,
pointer a);
pointer script_fu_add_script_regular (scheme *sc,
pointer a);
pointer script_fu_add_menu (scheme *sc,
pointer a);

View File

@ -93,6 +93,8 @@ typedef struct
SFArg *args;
SFDrawableArity drawable_arity;
GType proc_class; /* GimpProcedure or GimpImageProcedure. */
/* is declared using script-fu-register and dialog is old-style. */
gboolean is_old_style;
} SFScript;
/* ScriptFu keeps array of SFArg, it's private arg specs.

View File

@ -163,13 +163,11 @@
)
)
(script-fu-register "script-fu-font-map"
(script-fu-register-regular "script-fu-font-map"
_"Render _Font Map..."
_"Create an image filled with previews of fonts matching a fontname filter"
"Spencer Kimball"
"Spencer Kimball"
"1997"
""
SF-STRING _"_Text" "How quickly daft jumping zebras vex."
SF-TOGGLE _"Use font _name as text" FALSE
SF-TOGGLE _"_Labels" TRUE