Updated with upstream update

This commit is contained in:
2023-10-30 15:55:30 -07:00
parent 098531073c
commit 3bbdd873ef
584 changed files with 91827 additions and 70362 deletions

View File

@ -642,18 +642,17 @@ script_fu_marshal_procedure_call (scheme *sc,
gboolean permissive,
gboolean deprecated)
{
PikaProcedure *procedure;
PikaValueArray *args;
PikaValueArray *values = NULL;
gchar *proc_name;
GParamSpec **arg_specs;
gint n_arg_specs;
gint actual_arg_count;
gint consumed_arg_count = 0;
gchar error_str[1024];
gint i;
pointer return_val = sc->NIL;
PikaProcedure *procedure;
PikaProcedureConfig *config;
PikaValueArray *values = NULL;
gchar *proc_name;
GParamSpec **arg_specs;
gint n_arg_specs;
gint actual_arg_count;
gint consumed_arg_count = 0;
gchar error_str[1024];
gint i;
pointer return_val = sc->NIL;
g_debug ("In %s()", G_STRFUNC);
@ -692,6 +691,7 @@ script_fu_marshal_procedure_call (scheme *sc,
return script_error (sc, error_str, 0);
}
config = pika_procedure_create_config (procedure);
arg_specs = pika_procedure_get_arguments (procedure, &n_arg_specs);
actual_arg_count = sc->vptr->list_length (sc, a) - 1;
@ -724,8 +724,6 @@ script_fu_marshal_procedure_call (scheme *sc,
}
/* Marshall the supplied arguments */
args = pika_value_array_new (n_arg_specs);
for (i = 0; i < n_arg_specs; i++)
{
GParamSpec *arg_spec = arg_specs[i];
@ -756,34 +754,98 @@ script_fu_marshal_procedure_call (scheme *sc,
if (G_VALUE_HOLDS_INT (&value))
{
if (! sc->vptr->is_number (sc->vptr->pair_car (a)))
return script_type_error (sc, "numeric", i, proc_name);
{
return script_type_error (sc, "numeric", i, proc_name);
}
else
g_value_set_int (&value,
sc->vptr->ivalue (sc->vptr->pair_car (a)));
{
GParamSpecInt *ispec = G_PARAM_SPEC_INT (arg_spec);
gint v = sc->vptr->ivalue (sc->vptr->pair_car (a));
if (v < ispec->minimum || v > ispec->maximum)
{
gchar error_message[1024];
g_snprintf (error_message, sizeof (error_message),
"Invalid value %d for argument %d: expected value between %d and %d",
v, i, ispec->minimum, ispec->maximum);
return script_error (sc, error_message, 0);
}
g_value_set_int (&value, v);
}
}
else if (G_VALUE_HOLDS_UINT (&value))
{
if (! sc->vptr->is_number (sc->vptr->pair_car (a)))
return script_type_error (sc, "numeric", i, proc_name);
{
return script_type_error (sc, "numeric", i, proc_name);
}
else
g_value_set_uint (&value,
sc->vptr->ivalue (sc->vptr->pair_car (a)));
{
GParamSpecUInt *ispec = G_PARAM_SPEC_UINT (arg_spec);
gint v = sc->vptr->ivalue (sc->vptr->pair_car (a));
if (v < ispec->minimum || v > ispec->maximum)
{
gchar error_message[1024];
g_snprintf (error_message, sizeof (error_message),
"Invalid value %d for argument %d: expected value between %d and %d",
v, i, ispec->minimum, ispec->maximum);
return script_error (sc, error_message, 0);
}
g_value_set_uint (&value, v);
}
}
else if (G_VALUE_HOLDS_UCHAR (&value))
{
if (! sc->vptr->is_number (sc->vptr->pair_car (a)))
return script_type_error (sc, "numeric", i, proc_name);
{
return script_type_error (sc, "numeric", i, proc_name);
}
else
g_value_set_uchar (&value,
sc->vptr->ivalue (sc->vptr->pair_car (a)));
{
GParamSpecUChar *cspec = G_PARAM_SPEC_UCHAR (arg_spec);
gint c = sc->vptr->ivalue (sc->vptr->pair_car (a));
if (c < cspec->minimum || c > cspec->maximum)
{
gchar error_message[1024];
g_snprintf (error_message, sizeof (error_message),
"Invalid value %d for argument %d: expected value between %d and %d",
c, i, cspec->minimum, cspec->maximum);
return script_error (sc, error_message, 0);
}
g_value_set_uchar (&value, c);
}
}
else if (G_VALUE_HOLDS_DOUBLE (&value))
{
if (! sc->vptr->is_number (sc->vptr->pair_car (a)))
return script_type_error (sc, "numeric", i, proc_name);
{
return script_type_error (sc, "numeric", i, proc_name);
}
else
g_value_set_double (&value,
sc->vptr->rvalue (sc->vptr->pair_car (a)));
{
GParamSpecDouble *dspec = G_PARAM_SPEC_DOUBLE (arg_spec);
gdouble d = sc->vptr->rvalue (sc->vptr->pair_car (a));
if (d < dspec->minimum || d > dspec->maximum)
{
gchar error_message[1024];
g_snprintf (error_message, sizeof (error_message),
"Invalid value %f for argument %d: expected value between %f and %f",
d, i, dspec->minimum, dspec->maximum);
return script_error (sc, error_message, 0);
}
g_value_set_double (&value, d);
}
}
else if (G_VALUE_HOLDS_ENUM (&value))
{
@ -850,8 +912,7 @@ script_fu_marshal_procedure_call (scheme *sc,
{
g_printerr (" ");
for (j = 0; j < count; ++j)
g_printerr (" \"%s\"",
args[i].data.d_strv[j]);
g_printerr (" \"%s\"", array[j]);
g_printerr ("\n");
}
}
@ -992,7 +1053,12 @@ script_fu_marshal_procedure_call (scheme *sc,
*/
gint32 *array;
n_elements = PIKA_VALUES_GET_INT (args, i - 1);
if (i == 0)
return script_error (sc, "The first argument cannot be an array", a);
else if (! g_type_is_a (arg_specs[i - 1]->value_type, G_TYPE_INT))
return script_error (sc, "Array arguments must be preceded by an int argument (number of items)", a);
g_object_get (config, arg_specs[i - 1]->name, &n_elements, NULL);
if (n_elements > sc->vptr->vector_length (vector))
return script_length_error_in_vector (sc, i, proc_name, n_elements, vector);
@ -1058,7 +1124,12 @@ script_fu_marshal_procedure_call (scheme *sc,
{
gdouble *array;
n_elements = PIKA_VALUES_GET_INT (args, i - 1);
if (i == 0)
return script_error (sc, "The first argument cannot be an array", a);
else if (! g_type_is_a (arg_specs[i - 1]->value_type, G_TYPE_INT))
return script_error (sc, "Array arguments must be preceded by an int argument (number of items)", a);
g_object_get (config, arg_specs[i - 1]->name, &n_elements, NULL);
if (n_elements > sc->vptr->vector_length (vector))
return script_length_error_in_vector (sc, i, proc_name, n_elements, vector);
@ -1142,7 +1213,12 @@ script_fu_marshal_procedure_call (scheme *sc,
{
PikaRGB *array;
n_elements = PIKA_VALUES_GET_INT (args, i - 1);
if (i == 0)
return script_error (sc, "The first argument cannot be an array", a);
else if (! g_type_is_a (arg_specs[i - 1]->value_type, G_TYPE_INT))
return script_error (sc, "Array arguments must be preceded by an int argument (number of items)", a);
g_object_get (config, arg_specs[i - 1]->name, &n_elements, NULL);
if (n_elements > sc->vptr->vector_length (vector))
return script_length_error_in_vector (sc, i, proc_name, n_elements, vector);
@ -1275,6 +1351,8 @@ script_fu_marshal_procedure_call (scheme *sc,
* ID's are unique across all instances of Resource.
*/
resource = pika_resource_get_by_id (resource_id);
if (resource == NULL)
g_warning ("%s: passing null Resource, invalid ID.", G_STRFUNC);
g_value_set_object (&value, resource);
}
@ -1287,7 +1365,18 @@ script_fu_marshal_procedure_call (scheme *sc,
return implementation_error (sc, error_str, 0);
}
debug_gvalue (&value);
pika_value_array_append (args, &value);
if (g_param_value_validate (arg_spec, &value))
{
gchar error_message[1024];
g_snprintf (error_message, sizeof (error_message),
"Invalid value for argument %d",
i);
g_value_unset (&value);
return script_error (sc, error_message, 0);
}
g_object_set_property (G_OBJECT (config), arg_specs[i]->name, &value);
g_value_unset (&value);
}
@ -1296,9 +1385,9 @@ script_fu_marshal_procedure_call (scheme *sc,
return script_error (sc, "A script cannot refresh scripts", 0);
g_debug ("calling %s", proc_name);
values = pika_pdb_run_procedure_array (pika_get_pdb (),
proc_name, args);
values = pika_procedure_run_config (procedure, config);
g_debug ("done.");
g_clear_object (&config);
/* Check the return status */
if (! values)
@ -1330,7 +1419,6 @@ script_fu_marshal_procedure_call (scheme *sc,
pika_value_array_unref (values);
/* free arguments and values */
pika_value_array_unref (args);
/* The callback is NULL except for script-fu-server. See explanation there. */
if (post_command_callback != NULL)

View File

@ -98,6 +98,7 @@ script_fu_arg_free (SFArg *arg)
switch (arg->type)
{
/* Integer ID's: primitives not needing free. */
case SF_IMAGE:
case SF_DRAWABLE:
case SF_LAYER:
@ -106,6 +107,13 @@ script_fu_arg_free (SFArg *arg)
case SF_DISPLAY:
case SF_COLOR:
case SF_TOGGLE:
case SF_BRUSH:
case SF_FONT:
case SF_GRADIENT:
case SF_PALETTE:
case SF_PATTERN:
break;
case SF_VALUE:
@ -124,36 +132,6 @@ script_fu_arg_free (SFArg *arg)
g_free (arg->value.sfa_file.filename);
break;
/* FUTURE: font..gradient could all use the same code.
* Since the type in the union are all the same: gchar*.
* That is, group these cases with SF_VALUE.
* But this method should go away altogether.
*/
case SF_FONT:
g_free (arg->default_value.sfa_font);
g_free (arg->value.sfa_font);
break;
case SF_PALETTE:
g_free (arg->default_value.sfa_palette);
g_free (arg->value.sfa_palette);
break;
case SF_PATTERN:
g_free (arg->default_value.sfa_pattern);
g_free (arg->value.sfa_pattern);
break;
case SF_GRADIENT:
g_free (arg->default_value.sfa_gradient);
g_free (arg->value.sfa_gradient);
break;
case SF_BRUSH:
g_free (arg->default_value.sfa_brush);
g_free (arg->value.sfa_brush);
break;
case SF_OPTION:
g_slist_free_full (arg->default_value.sfa_option.list,
(GDestroyNotify) g_free);
@ -180,6 +158,13 @@ script_fu_arg_reset (SFArg *arg, gboolean should_reset_ids)
case SF_CHANNEL:
case SF_VECTORS:
case SF_DISPLAY:
case SF_BRUSH:
case SF_FONT:
case SF_GRADIENT:
case SF_PALETTE:
case SF_PATTERN:
if (should_reset_ids)
{
/* !!! Use field name "sfa_image"; all these cases have same type in union.
@ -216,35 +201,6 @@ script_fu_arg_reset (SFArg *arg, gboolean should_reset_ids)
value->sfa_file.filename = g_strdup (default_value->sfa_file.filename);
break;
/* FUTURE: font..gradient could all use the same code.
* Since the type in the union are all the same: gchar*.
* That is, group these cases with SF_VALUE.
*/
case SF_FONT:
g_free (value->sfa_font);
value->sfa_font = g_strdup (default_value->sfa_font);
break;
case SF_PALETTE:
g_free (value->sfa_palette);
value->sfa_palette = g_strdup (default_value->sfa_palette);
break;
case SF_PATTERN:
g_free (value->sfa_pattern);
value->sfa_pattern = g_strdup (default_value->sfa_pattern);
break;
case SF_GRADIENT:
g_free (value->sfa_gradient);
value->sfa_gradient = g_strdup (default_value->sfa_gradient);
break;
case SF_BRUSH:
g_free (value->sfa_brush);
value->sfa_brush = g_strdup (default_value->sfa_brush);
break;
case SF_OPTION:
value->sfa_option.history = default_value->sfa_option.history;
break;
@ -486,6 +442,14 @@ script_fu_arg_append_repr_from_gvalue (SFArg *arg,
case SF_CHANNEL:
case SF_VECTORS:
case SF_DISPLAY:
/* The GValue is a GObject of type inheriting PikaResource, having id prop */
case SF_BRUSH:
case SF_FONT:
case SF_GRADIENT:
case SF_PALETTE:
case SF_PATTERN:
{
GObject *object = g_value_get_object (gvalue);
gint id = -1;
@ -584,25 +548,6 @@ script_fu_arg_append_repr_from_gvalue (SFArg *arg,
}
break;
case SF_FONT:
case SF_PALETTE:
case SF_PATTERN:
case SF_GRADIENT:
case SF_BRUSH:
{
/* The GValue is a GObject of type inheriting PikaResource */
PikaResource *resource;
gchar *name = NULL;
resource = g_value_get_object (gvalue);
if (resource)
name = pika_resource_get_name (resource);
g_string_append_printf (result_string, "\"%s\"", name);
}
break;
case SF_OPTION:
append_int_repr_from_gvalue (result_string, gvalue);
break;
@ -648,6 +593,12 @@ script_fu_arg_append_repr_from_self (SFArg *arg,
case SF_CHANNEL:
case SF_VECTORS:
case SF_DISPLAY:
case SF_BRUSH:
case SF_FONT:
case SF_GRADIENT:
case SF_PALETTE:
case SF_PATTERN:
g_string_append_printf (result_string, "%d", arg_value->sfa_image);
break;
@ -701,26 +652,6 @@ script_fu_arg_append_repr_from_self (SFArg *arg,
}
break;
case SF_FONT:
g_string_append_printf (result_string, "\"%s\"", arg_value->sfa_font);
break;
case SF_PALETTE:
g_string_append_printf (result_string, "\"%s\"", arg_value->sfa_palette);
break;
case SF_PATTERN:
g_string_append_printf (result_string, "\"%s\"", arg_value->sfa_pattern);
break;
case SF_GRADIENT:
g_string_append_printf (result_string, "\"%s\"", arg_value->sfa_gradient);
break;
case SF_BRUSH:
g_string_append_printf (result_string, "\"%s\"", arg_value->sfa_brush);
break;
case SF_OPTION:
g_string_append_printf (result_string, "%d", arg_value->sfa_option.history);
break;
@ -883,6 +814,38 @@ script_fu_arg_generate_name_and_nick (SFArg *arg,
}
/* Init the value of an SFArg that is a resource.
* In case user does not touch a widget.
* Cannot be called at registration time.
* Init to value from context, the same as a widget
* will do when passed a NULL initial resource.
*/
void
script_fu_arg_init_resource (SFArg *arg, GType resource_type)
{
PikaResource *resource;
if (resource_type == PIKA_TYPE_BRUSH)
resource = PIKA_RESOURCE (pika_context_get_brush ());
else if (resource_type == PIKA_TYPE_FONT)
resource = PIKA_RESOURCE (pika_context_get_font ());
else if (resource_type == PIKA_TYPE_GRADIENT)
resource = PIKA_RESOURCE (pika_context_get_gradient ());
else if (resource_type == PIKA_TYPE_PALETTE)
resource = PIKA_RESOURCE (pika_context_get_palette ());
else if (resource_type == PIKA_TYPE_PATTERN)
resource = PIKA_RESOURCE (pika_context_get_pattern ());
else
{
g_warning ("%s: Failed get resource from context", G_STRFUNC);
arg->value.sfa_resource = -1;
return;
}
arg->value.sfa_resource = pika_resource_get_id (resource);
}
/* Set the default of a GParamSpec to a GFile for a path string.
* The GFile is allocated and ownership is transferred to the GParamSpec.
* The GFile is only a name and a so-named file might not exist.

View File

@ -40,4 +40,7 @@ void script_fu_arg_generate_name_and_nick (SFArg *arg,
const gchar **name,
const gchar **nick);
void script_fu_arg_init_resource (SFArg *arg,
GType resource_type);
#endif /* __SCRIPT_FU_ARG__ */

View File

@ -98,20 +98,19 @@ script_fu_run_command (const gchar *command,
* 2) adds actual args image, drawable, etc. for PikaImageProcedure
*/
PikaValueArray *
script_fu_interpret_image_proc (
PikaProcedure *procedure,
SFScript *script,
PikaImage *image,
guint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args)
script_fu_interpret_image_proc (PikaProcedure *procedure,
SFScript *script,
PikaImage *image,
guint n_drawables,
PikaDrawable **drawables,
PikaProcedureConfig *config)
{
gchar *command;
PikaValueArray *result = NULL;
gboolean interpretation_result;
GError *error = NULL;
command = script_fu_script_get_command_for_image_proc (script, image, n_drawables, drawables, args);
command = script_fu_script_get_command_for_image_proc (script, image, n_drawables, drawables, config);
/* Take responsibility for handling errors from the scripts further calls to PDB.
* ScriptFu does not show an error dialog, but forwards errors back to PIKA.

View File

@ -30,6 +30,6 @@ PikaValueArray *script_fu_interpret_image_proc (PikaProcedure *procedure,
PikaImage *image,
guint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args);
PikaProcedureConfig *config);
#endif /* __SCRIPT_FU_COMMAND_H__ */

View File

@ -64,72 +64,37 @@ dump_properties (PikaProcedureConfig *config)
g_free (pspecs);
}
static gint
get_length (PikaProcedureConfig *config)
{
GParamSpec **pspecs;
guint n_pspecs;
pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (config),
&n_pspecs);
g_free (pspecs);
g_debug ("length config: %d", n_pspecs);
return n_pspecs;
}
/* Fill a new (length zero) gva with new gvalues (empty but holding the correct type)
from the config.
*/
static void
fill_gva_from (PikaProcedureConfig *config,
PikaValueArray *gva)
{
GParamSpec **pspecs;
guint n_pspecs;
pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (config),
&n_pspecs);
/* !!! Start at property 1 */
for (guint i = 1; i < n_pspecs; i++)
{
g_debug ("%s %s\n", pspecs[i]->name, G_PARAM_SPEC_TYPE_NAME (pspecs[i]));
/* append empty gvalue */
pika_value_array_append (gva, NULL);
}
g_free (pspecs);
}
static void
dump_objects (PikaProcedureConfig *config)
dump_objects (PikaProcedureConfig *config)
{
/* Check it will return non-null objects. */
PikaValueArray *args;
gint length;
GParamSpec **pspecs;
guint n_pspecs;
/* Need one less gvalue !!! */
args = pika_value_array_new (get_length (config) - 1);
/* The array still has length zero. */
g_debug ("GVA length: %d", pika_value_array_length (args));
pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (config), &n_pspecs);
fill_gva_from (config, args);
pika_procedure_config_get_values (config, args);
if (args == NULL)
/* config will have at least 1 property: "procedure". */
if (n_pspecs == 1)
{
g_debug ("config holds no values");
return;
}
length = pika_value_array_length (args);
for (guint i = 1; i < length; i++)
for (gint i = 1; i < n_pspecs; i++)
{
GValue *gvalue = pika_value_array_index (args, i);
if (G_VALUE_HOLDS_OBJECT (gvalue))
if (g_value_get_object (gvalue) == NULL)
GParamSpec *pspec = pspecs[i];
GValue value = G_VALUE_INIT;
g_value_init (&value, pspec->value_type);
g_object_get_property (G_OBJECT (config), pspec->name, &value);
if (G_VALUE_HOLDS_OBJECT (&value))
if (g_value_get_object (&value) == NULL)
g_debug ("gvalue %d holds NULL object", i);
g_value_unset (&value);
}
g_free (pspecs);
}
#endif
@ -152,18 +117,19 @@ script_fu_dialog_run (PikaProcedure *procedure,
PikaImage *image,
guint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *initial_args)
PikaProcedureConfig *config)
{
PikaValueArray *result = NULL;
PikaProcedureDialog *dialog = NULL;
PikaProcedureConfig *config = NULL;
gboolean not_canceled;
guint n_specs;
if ( (! G_IS_OBJECT (procedure)) || script == NULL)
return pika_procedure_new_return_values (procedure, PIKA_PDB_EXECUTION_ERROR, NULL);
if ( pika_value_array_length (initial_args) < 1)
g_free (g_object_class_list_properties (G_OBJECT_GET_CLASS (config), &n_specs));
if (n_specs < 2)
return pika_procedure_new_return_values (procedure, PIKA_PDB_EXECUTION_ERROR, NULL);
/* We don't prevent concurrent dialogs as in script-fu-interface.c.
@ -179,22 +145,12 @@ script_fu_dialog_run (PikaProcedure *procedure,
/* Script's menu label */
pika_ui_init (script_fu_script_get_title (script));
config = pika_procedure_create_config (procedure);
#if DEBUG_CONFIG_PROPERTIES
dump_properties (config);
g_debug ("Len of initial_args %i", pika_value_array_length (initial_args) );
g_debug ("Len of initial_args %i", n_specs - 1);
dump_objects (config);
#endif
/* Get saved settings (last values) into the config.
* Since run mode is INTERACTIVE, initial_args is moot.
* Instead, last used values or default values populate the config.
*/
pika_procedure_config_begin_run (config, NULL, PIKA_RUN_INTERACTIVE, initial_args);
#if DEBUG_CONFIG_PROPERTIES
dump_objects (config);
#endif
/* Create a dialog having properties (describing arguments of the procedure)
* taken from the config.
*
@ -220,22 +176,15 @@ script_fu_dialog_run (PikaProcedure *procedure,
not_canceled = pika_procedure_dialog_run (dialog);
/* Assert config holds validated arg values from a user interaction. */
#if DEBUG_CONFIG_PROPERTIES
dump_objects (config);
#endif
#if DEBUG_CONFIG_PROPERTIES
dump_objects (config);
#endif
if (not_canceled)
{
PikaValueArray *final_args = pika_value_array_copy (initial_args);
/* Store config's values into final_args. */
pika_procedure_config_get_values (config, final_args);
result = script_fu_interpret_image_proc (procedure, script,
image, n_drawables, drawables,
final_args);
pika_value_array_unref (final_args);
config);
}
else
{
@ -244,13 +193,5 @@ script_fu_dialog_run (PikaProcedure *procedure,
gtk_widget_destroy ((GtkWidget*) dialog);
/* Persist config aka settings for the next run of the plugin.
* Passing the PikaPDBStatus from result[0].
* We must have a matching end_run for the begin_run, regardless of status.
*/
pika_procedure_config_end_run (config, g_value_get_enum (pika_value_array_index (result, 0)));
g_object_unref (config);
return result;
}

View File

@ -30,6 +30,6 @@ PikaValueArray *script_fu_dialog_run (PikaProcedure *procedure,
PikaImage *image,
guint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args);
PikaProcedureConfig *config);
#endif /* __SCRIPT_FU_DIALOG_H__ */

View File

@ -48,6 +48,24 @@
};
/* Called on event: language error in author's script,
* in the Scheme arg spec for a PDB registered argument.
* Returns an error which the caller must return to its caller.
*/
pointer registration_error (scheme *sc,
const gchar *error)
{
gchar error_message[1024];
g_debug ("%s", error);
/* Prefix with name of SF function that discovered error. */
g_snprintf (error_message, sizeof (error_message),
"script-fu-register: %s",
error);
return foreign_error (sc, error_message, 0);
}
/*
* Called on event: language error in the author's script.
* Logs the error and returns a foreign_error.

View File

@ -22,6 +22,9 @@
#ifndef __SCRIPT_FU_ERRORS_H__
#define __SCRIPT_FU_ERRORS_H__
pointer registration_error (scheme *sc,
const gchar *error_message);
pointer script_error (scheme *sc,
const gchar *error_message,
const pointer a);

View File

@ -39,6 +39,7 @@
#include "script-fu-interface.h"
#include "script-fu-scripts.h"
#include "script-fu-script.h"
#include "script-fu-arg.h"
#include "script-fu-intl.h"
@ -91,7 +92,7 @@ static void script_fu_resource_set_handler (gpointer data,
gboolean closing);
static GtkWidget * script_fu_resource_widget (const gchar *title,
gchar **id,
gint32 *model,
GType resource_type);
static void script_fu_flush_events (void);
@ -177,6 +178,8 @@ script_fu_interface (SFScript *script,
static gboolean gtk_initted = FALSE;
g_debug ("%s", G_STRFUNC);
/* Simply return if there is already an interface. This is an
* ugly workaround for the fact that we can not process two
* scripts at a time.
@ -467,35 +470,40 @@ script_fu_interface (SFScript *script,
break;
case SF_FONT:
widget = script_fu_resource_widget (_("Script-Fu Font Selection"),
&arg->value.sfa_font,
script_fu_arg_init_resource (arg, PIKA_TYPE_FONT);
widget = script_fu_resource_widget (label_text,
&arg->value.sfa_resource,
PIKA_TYPE_FONT);
break;
case SF_PALETTE:
widget = script_fu_resource_widget (_("Script-Fu Palette Selection"),
&arg->value.sfa_palette,
script_fu_arg_init_resource (arg, PIKA_TYPE_PALETTE);
widget = script_fu_resource_widget (label_text,
&arg->value.sfa_resource,
PIKA_TYPE_PALETTE);
break;
case SF_PATTERN:
left_align = TRUE;
widget = script_fu_resource_widget (_("Script-Fu Pattern Selection"),
&arg->value.sfa_pattern,
script_fu_arg_init_resource (arg, PIKA_TYPE_PATTERN);
widget = script_fu_resource_widget (label_text,
&arg->value.sfa_resource,
PIKA_TYPE_PATTERN);
break;
case SF_GRADIENT:
left_align = TRUE;
widget = script_fu_resource_widget (_("Script-Fu Gradient Selection"),
&arg->value.sfa_gradient,
script_fu_arg_init_resource (arg, PIKA_TYPE_GRADIENT);
widget = script_fu_resource_widget (label_text,
&arg->value.sfa_resource,
PIKA_TYPE_GRADIENT);
break;
case SF_BRUSH:
left_align = TRUE;
widget = script_fu_resource_widget (_("Script-Fu Brush Selection"),
&arg->value.sfa_brush,
script_fu_arg_init_resource (arg, PIKA_TYPE_BRUSH);
widget = script_fu_resource_widget (label_text,
&arg->value.sfa_resource,
PIKA_TYPE_BRUSH);
break;
@ -596,37 +604,41 @@ script_fu_interface (SFScript *script,
}
/* Return a widget for choosing a resource.
* Generic on type.
* Dispatch on resource type.
* Widget will show initial choice from context.
* Widget will update model if user touches widget.
*/
GtkWidget *
static GtkWidget *
script_fu_resource_widget (const gchar *title,
gchar **id_handle,
gint32 *model,
GType resource_type)
{
GtkWidget *result_widget = NULL;
PikaResource *resource;
resource = pika_resource_get_by_name (resource_type, *id_handle);
g_debug ("%s type: %ld", G_STRFUNC, resource_type);
/* Passing NULL resource sets initial choice to resource from context.
* Passing empty string for outer widget label, since we provide our own.
*/
if (g_type_is_a (resource_type, PIKA_TYPE_FONT))
{
result_widget = pika_font_select_button_new (title, resource);
result_widget = pika_font_chooser_new (title, "", NULL);
}
else if (g_type_is_a (resource_type, PIKA_TYPE_BRUSH))
{
result_widget = pika_brush_select_button_new (title, resource);
result_widget = pika_brush_chooser_new (title, "", NULL);
}
else if (g_type_is_a (resource_type, PIKA_TYPE_GRADIENT))
{
result_widget = pika_gradient_select_button_new (title, resource);
result_widget = pika_gradient_chooser_new (title, "", NULL);
}
else if (g_type_is_a (resource_type, PIKA_TYPE_PALETTE))
{
result_widget = pika_palette_select_button_new (title, resource);
result_widget = pika_palette_chooser_new (title, "", NULL);
}
else if (g_type_is_a (resource_type, PIKA_TYPE_PATTERN))
{
result_widget = pika_pattern_select_button_new (title, resource);
result_widget = pika_pattern_chooser_new (title, "", NULL);
}
else
{
@ -637,11 +649,11 @@ script_fu_resource_widget (const gchar *title,
{
/* All resource widgets emit signal resource-set
* Connect to our handler which will be passed the id_handle,
* the place to store the ID of the new choice of resource.
* the model of the new choice of resource.
*/
g_signal_connect_swapped (result_widget, "resource-set",
G_CALLBACK (script_fu_resource_set_handler),
id_handle);
model); /* data */
}
return result_widget;
@ -650,29 +662,10 @@ script_fu_resource_widget (const gchar *title,
static void
script_fu_interface_quit (SFScript *script)
{
gint i;
g_return_if_fail (script != NULL);
g_return_if_fail (sf_interface != NULL);
g_free (sf_interface->title);
for (i = 0; i < script->n_args; i++)
switch (script->args[i].type)
{
case SF_FONT:
case SF_PALETTE:
case SF_PATTERN:
case SF_GRADIENT:
case SF_BRUSH:
pika_resource_select_button_close_popup
(PIKA_RESOURCE_SELECT_BUTTON (sf_interface->widgets[i]));
break;
default:
break;
}
g_free (sf_interface->widgets);
g_free (sf_interface->last_command);
@ -706,25 +699,21 @@ script_fu_combo_callback (GtkWidget *widget,
}
/* Handle resource-set signal.
* Store id of newly chosen resource in SF local cache of args.
* Store id of newly chosen resource in SF local cache of args,
* at the integer location passed by pointer in "data"
*
* Note the callback is the same for all resource types.
* The callback passes only the resource, and no attributes of the resource,
* except it's ID.
* The callback passes the resource, and no attributes of the resource.
*/
static void
script_fu_resource_set_handler (gpointer data, /* callback "data" */
gpointer resource,
gboolean closing)
{
gchar **id_handle = data;
gint32 *id_pointer = data;
/* Free any existing copy of the id string. */
if (*id_handle)
g_free (*id_handle);
/* We don't own the resource, nor its string. Copy the string. */
*id_handle = g_strdup (pika_resource_get_name (resource));
/* Store integer ID, not pointer to Resource. We bind to integer ID. */
*id_pointer = pika_resource_get_id (resource);
if (closing) script_fu_activate_main_dialog ();
}
@ -794,30 +783,22 @@ script_fu_response (GtkWidget *widget,
script_fu_flush_events ();
}
/* Update model for all widgets that
* don't have callbacks that update the model.
* Only the text and string widgets don't.
*
* The model is the arg.value field.
*/
static void
script_fu_ok (SFScript *script)
script_fu_update_models (SFScript *script)
{
GString *output;
gchar *command;
gint i;
for (i = 0; i < script->n_args; i++)
for (gint i = 0; i < script->n_args; i++)
{
SFArgValue *arg_value = &script->args[i].value;
GtkWidget *widget = sf_interface->widgets[i];
switch (script->args[i].type)
{
case SF_IMAGE:
case SF_DRAWABLE:
case SF_LAYER:
case SF_CHANNEL:
case SF_VECTORS:
case SF_DISPLAY:
case SF_COLOR:
case SF_TOGGLE:
break;
case SF_VALUE:
case SF_STRING:
g_free (arg_value->sfa_value);
@ -843,20 +824,19 @@ script_fu_ok (SFScript *script)
FALSE);
}
break;
case SF_ADJUSTMENT:
case SF_FILENAME:
case SF_DIRNAME:
case SF_FONT:
case SF_PALETTE:
case SF_PATTERN:
case SF_GRADIENT:
case SF_BRUSH:
case SF_OPTION:
case SF_ENUM:
break;
}
}
}
/* Handler for event: OK button clicked. */
static void
script_fu_ok (SFScript *script)
{
GString *output;
gchar *command;
script_fu_update_models (script);
command = script_fu_script_get_command (script);
@ -969,23 +949,16 @@ script_fu_reset (SFScript *script)
value->sfa_file.filename);
break;
/* Reset should get the initial/default value that the plugin author
* declared by name in the SF- declaration.
* Said name is a string stored in the default_value.sfa_font
*
* But this code goes away when ScriptFu uses PikaProcedureDialog.
* Rather than make this temporary code do the correct thing,
* instead simply pass NULL to reset to the value from context.
* It is extremely unlikely that any user depends on or will notice
* this temporaryily slightly changed behavior.
/* Pass NULL to reset to the value from context.
* Since v3, script author cannot specify default resource by name.
*/
case SF_FONT:
case SF_PALETTE:
case SF_PATTERN:
case SF_GRADIENT:
case SF_BRUSH:
pika_resource_select_button_set_resource (PIKA_RESOURCE_SELECT_BUTTON (widget),
NULL);
pika_resource_chooser_set_resource (PIKA_RESOURCE_CHOOSER (widget),
NULL);
break;
case SF_OPTION:

View File

@ -35,6 +35,8 @@
#include "script-fu-types.h"
#include "script-fu-script.h"
#include "script-fu-register.h"
#include "script-fu-errors.h"
/* Methods for a script's call to script-fu-register or script-fu-register-filter.
* Such calls declare a PDB procedure, that ScriptFu will register in the PDB,
@ -119,6 +121,263 @@ script_fu_script_new_from_metadata_args (scheme *sc,
return script;
}
/* Parse a default spec from registration data.
*
* Side effects on arg.
*
* Returns sc->NIL on success.
* Returns pointer to a foreign_error on parsing errors.
*
* A default_spec can be an atom or a list.
* An atom is a single default value.
* A list for SF-COLOR is also a default value.
* In other cases, a list is a default and constraints.
* Some constraints are declared to and enforced by the PDB.
* Some constraints also convey to the widget for the arg.
*
* We check that each list is the correct length,
* so we don't car off the end of the list.
*
* We don't check the types of list elements.
* When they are not the correct type,
* they are *some* scheme object and getting the numeric value
* will return *some* value probably not the intended value,
* but at least not a memory error or crash.
*/
static pointer
script_fu_parse_default_spec (scheme *sc,
pointer default_spec,
SFArg *arg)
{
switch (arg->type)
{
case SF_IMAGE:
case SF_DRAWABLE:
case SF_LAYER:
case SF_CHANNEL:
case SF_VECTORS:
case SF_DISPLAY:
if (!sc->vptr->is_integer (default_spec))
return registration_error (sc, "default IDs must be integers");
arg->default_value.sfa_image =
sc->vptr->ivalue (default_spec);
break;
case SF_COLOR:
if (sc->vptr->is_string (default_spec))
{
if (! pika_rgb_parse_css (&arg->default_value.sfa_color,
sc->vptr->string_value (default_spec),
-1))
return registration_error (sc, "invalid default color name");
pika_rgb_set_alpha (&arg->default_value.sfa_color, 1.0);
}
else if (sc->vptr->is_list (sc, default_spec) &&
sc->vptr->list_length (sc, default_spec) == 3)
{
pointer color_list;
guchar r, g, b;
color_list = default_spec;
r = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)), 0, 255);
color_list = sc->vptr->pair_cdr (color_list);
g = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)), 0, 255);
color_list = sc->vptr->pair_cdr (color_list);
b = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)), 0, 255);
pika_rgb_set_uchar (&arg->default_value.sfa_color, r, g, b);
}
else
{
return registration_error (sc, "color defaults must be a list of 3 integers or a color name");
}
break;
case SF_TOGGLE:
if (!sc->vptr->is_integer (default_spec))
return registration_error (sc, "toggle default must be an integer value");
arg->default_value.sfa_toggle =
(sc->vptr->ivalue (default_spec)) ? TRUE : FALSE;
break;
case SF_VALUE:
if (!sc->vptr->is_string (default_spec))
return registration_error (sc, "value defaults must be strings");
arg->default_value.sfa_value =
g_strdup (sc->vptr->string_value (default_spec));
break;
case SF_STRING:
case SF_TEXT:
if (!sc->vptr->is_string (default_spec))
return registration_error (sc, "string defaults must be strings");
arg->default_value.sfa_value =
g_strdup (sc->vptr->string_value (default_spec));
break;
case SF_ADJUSTMENT:
{
pointer adj_list;
if (!sc->vptr->is_list (sc, default_spec) &&
sc->vptr->list_length (sc, default_spec) != 7)
return registration_error (sc, "adjustment defaults must be a list of 7 elements");
adj_list = default_spec;
arg->default_value.sfa_adjustment.value =
sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
adj_list = sc->vptr->pair_cdr (adj_list);
arg->default_value.sfa_adjustment.lower =
sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
adj_list = sc->vptr->pair_cdr (adj_list);
arg->default_value.sfa_adjustment.upper =
sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
adj_list = sc->vptr->pair_cdr (adj_list);
arg->default_value.sfa_adjustment.step =
sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
adj_list = sc->vptr->pair_cdr (adj_list);
arg->default_value.sfa_adjustment.page =
sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
adj_list = sc->vptr->pair_cdr (adj_list);
arg->default_value.sfa_adjustment.digits =
sc->vptr->ivalue (sc->vptr->pair_car (adj_list));
adj_list = sc->vptr->pair_cdr (adj_list);
arg->default_value.sfa_adjustment.type =
sc->vptr->ivalue (sc->vptr->pair_car (adj_list));
}
break;
case SF_FILENAME:
if (!sc->vptr->is_string (default_spec))
return registration_error (sc, "filename defaults must be strings");
/* fallthrough */
case SF_DIRNAME:
if (!sc->vptr->is_string (default_spec))
return registration_error (sc, "dirname defaults must be strings");
arg->default_value.sfa_file.filename =
g_strdup (sc->vptr->string_value (default_spec));
#ifdef G_OS_WIN32
{
/* Replace POSIX slashes with Win32 backslashes. This
* is just so script-fus can be written with only
* POSIX directory separators.
*/
gchar *filename = arg->default_value.sfa_file.filename;
while (*filename)
{
if (*filename == '/')
*filename = G_DIR_SEPARATOR;
filename++;
}
}
#endif
break;
case SF_FONT:
case SF_PALETTE:
case SF_PATTERN:
case SF_BRUSH:
case SF_GRADIENT:
/* Ignore default_spec given by author, it is just placeholder in script.
* We can't look up resource by name at registration time.
* The ParamSpecResource does not conveniently take a default.
* It makes no sense to set objects for defaults.
* Compare to SF_IMAGE.
* Since v3.
*/
arg->default_value.sfa_resource = -1;
break;
case SF_OPTION:
{
pointer option_list;
if (!sc->vptr->is_list (sc, default_spec) ||
sc->vptr->list_length(sc, default_spec) < 1 )
return registration_error (sc, "option defaults must be a non-empty list");
for (option_list = default_spec;
option_list != sc->NIL;
option_list = sc->vptr->pair_cdr (option_list))
{
pointer option = (sc->vptr->pair_car (option_list));
if (sc->vptr->is_string (option))
arg->default_value.sfa_option.list =
g_slist_append (arg->default_value.sfa_option.list,
g_strdup (sc->vptr->string_value (option)));
else
return registration_error (sc, "options must be strings");
}
}
break;
case SF_ENUM:
{
pointer option_list;
const gchar *val;
gchar *type_name;
GEnumValue *enum_value;
GType enum_type;
if (!sc->vptr->is_list (sc, default_spec))
return registration_error (sc, "enum defaults must be a list");
option_list = default_spec;
if (!sc->vptr->is_string (sc->vptr->pair_car (option_list)))
return registration_error (sc, "first element in enum defaults must be a type-name");
val = sc->vptr->string_value (sc->vptr->pair_car (option_list));
if (g_str_has_prefix (val, "Pika"))
type_name = g_strdup (val);
else
type_name = g_strconcat ("Pika", val, NULL);
enum_type = g_type_from_name (type_name);
if (! G_TYPE_IS_ENUM (enum_type))
{
g_free (type_name);
return registration_error (sc, "first element in enum defaults must be the name of a registered type");
}
arg->default_value.sfa_enum.type_name = type_name;
option_list = sc->vptr->pair_cdr (option_list);
if (!sc->vptr->is_string (sc->vptr->pair_car (option_list)))
return registration_error (sc, "second element in enum defaults must be a string");
enum_value =
g_enum_get_value_by_nick (g_type_class_peek (enum_type),
sc->vptr->string_value (sc->vptr->pair_car (option_list)));
if (enum_value)
arg->default_value.sfa_enum.history = enum_value->value;
}
break;
} /* end switch */
/* success */
return sc->NIL;
}
/* Traverse suffix of Scheme argument list,
* creating SFArgs (formal arg specs) from triplets.
*
@ -145,300 +404,43 @@ script_fu_script_create_formal_args (scheme *sc,
if (a != sc->NIL)
{
if (!sc->vptr->is_integer (sc->vptr->pair_car (a)))
return foreign_error (sc, "script-fu-register: argument types must be integer values", 0);
return registration_error (sc, "argument types must be integers");
arg->type = sc->vptr->ivalue (sc->vptr->pair_car (a));
a = sc->vptr->pair_cdr (a);
}
else
return foreign_error (sc, "script-fu-register: missing type specifier", 0);
return registration_error (sc, "missing type specifier");
if (a != sc->NIL)
{
if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
return foreign_error (sc, "script-fu-register: argument labels must be strings", 0);
return registration_error (sc, "argument labels must be strings");
arg->label = g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
a = sc->vptr->pair_cdr (a);
}
else
return foreign_error (sc, "script-fu-register: missing arguments label", 0);
return registration_error (sc, "missing arguments label");
if (a != sc->NIL)
{
switch (arg->type)
{
case SF_IMAGE:
case SF_DRAWABLE:
case SF_LAYER:
case SF_CHANNEL:
case SF_VECTORS:
case SF_DISPLAY:
if (!sc->vptr->is_integer (sc->vptr->pair_car (a)))
return foreign_error (sc, "script-fu-register: default IDs must be integer values", 0);
/* a is pointing into a sequence, grouped in three.
* (car a) is the third part of three.
* (cdr a) is the rest of the sequence
*/
pointer default_spec =sc->vptr->pair_car (a);
pointer error = script_fu_parse_default_spec (sc, default_spec, arg);
arg->default_value.sfa_image =
sc->vptr->ivalue (sc->vptr->pair_car (a));
break;
case SF_COLOR:
if (sc->vptr->is_string (sc->vptr->pair_car (a)))
{
if (! pika_rgb_parse_css (&arg->default_value.sfa_color,
sc->vptr->string_value (sc->vptr->pair_car (a)),
-1))
return foreign_error (sc, "script-fu-register: invalid default color name", 0);
pika_rgb_set_alpha (&arg->default_value.sfa_color, 1.0);
}
else if (sc->vptr->is_list (sc, sc->vptr->pair_car (a)) &&
sc->vptr->list_length(sc, sc->vptr->pair_car (a)) == 3)
{
pointer color_list;
guchar r, g, b;
color_list = sc->vptr->pair_car (a);
r = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)), 0, 255);
color_list = sc->vptr->pair_cdr (color_list);
g = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)), 0, 255);
color_list = sc->vptr->pair_cdr (color_list);
b = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)), 0, 255);
pika_rgb_set_uchar (&arg->default_value.sfa_color, r, g, b);
}
else
{
return foreign_error (sc, "script-fu-register: color defaults must be a list of 3 integers or a color name", 0);
}
break;
case SF_TOGGLE:
if (!sc->vptr->is_integer (sc->vptr->pair_car (a)))
return foreign_error (sc, "script-fu-register: toggle default must be an integer value", 0);
arg->default_value.sfa_toggle =
(sc->vptr->ivalue (sc->vptr->pair_car (a))) ? TRUE : FALSE;
break;
case SF_VALUE:
if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
return foreign_error (sc, "script-fu-register: value defaults must be string values", 0);
arg->default_value.sfa_value =
g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
break;
case SF_STRING:
case SF_TEXT:
if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
return foreign_error (sc, "script-fu-register: string defaults must be string values", 0);
arg->default_value.sfa_value =
g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
break;
case SF_ADJUSTMENT:
{
pointer adj_list;
if (!sc->vptr->is_list (sc, a))
return foreign_error (sc, "script-fu-register: adjustment defaults must be a list", 0);
adj_list = sc->vptr->pair_car (a);
arg->default_value.sfa_adjustment.value =
sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
adj_list = sc->vptr->pair_cdr (adj_list);
arg->default_value.sfa_adjustment.lower =
sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
adj_list = sc->vptr->pair_cdr (adj_list);
arg->default_value.sfa_adjustment.upper =
sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
adj_list = sc->vptr->pair_cdr (adj_list);
arg->default_value.sfa_adjustment.step =
sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
adj_list = sc->vptr->pair_cdr (adj_list);
arg->default_value.sfa_adjustment.page =
sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
adj_list = sc->vptr->pair_cdr (adj_list);
arg->default_value.sfa_adjustment.digits =
sc->vptr->ivalue (sc->vptr->pair_car (adj_list));
adj_list = sc->vptr->pair_cdr (adj_list);
arg->default_value.sfa_adjustment.type =
sc->vptr->ivalue (sc->vptr->pair_car (adj_list));
}
break;
case SF_FILENAME:
if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
return foreign_error (sc, "script-fu-register: filename defaults must be string values", 0);
/* fallthrough */
case SF_DIRNAME:
if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
return foreign_error (sc, "script-fu-register: dirname defaults must be string values", 0);
arg->default_value.sfa_file.filename =
g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
#ifdef G_OS_WIN32
{
/* Replace POSIX slashes with Win32 backslashes. This
* is just so script-fus can be written with only
* POSIX directory separators.
*/
gchar *filename = arg->default_value.sfa_file.filename;
while (*filename)
{
if (*filename == '/')
*filename = G_DIR_SEPARATOR;
filename++;
}
}
#endif
break;
case SF_FONT:
if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
return foreign_error (sc, "script-fu-register: font defaults must be string values", 0);
arg->default_value.sfa_font =
g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
break;
case SF_PALETTE:
if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
return foreign_error (sc, "script-fu-register: palette defaults must be string values", 0);
arg->default_value.sfa_palette =
g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
break;
case SF_PATTERN:
if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
return foreign_error (sc, "script-fu-register: pattern defaults must be string values", 0);
arg->default_value.sfa_pattern =
g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
break;
case SF_BRUSH:
{
pointer brush_list;
if (!sc->vptr->is_list (sc, a))
return foreign_error (sc, "script-fu-register: brush defaults must be a list", 0);
#ifdef OLD
temporarily, still a list, but use only the name
future: not a list, only a name
brush_list = sc->vptr->pair_car (a);
arg->default_value.sfa_brush.name =
g_strdup (sc->vptr->string_value (sc->vptr->pair_car (brush_list)));
brush_list = sc->vptr->pair_cdr (brush_list);
arg->default_value.sfa_brush.opacity =
sc->vptr->rvalue (sc->vptr->pair_car (brush_list));
brush_list = sc->vptr->pair_cdr (brush_list);
arg->default_value.sfa_brush.spacing =
sc->vptr->ivalue (sc->vptr->pair_car (brush_list));
brush_list = sc->vptr->pair_cdr (brush_list);
arg->default_value.sfa_brush.paint_mode =
sc->vptr->ivalue (sc->vptr->pair_car (brush_list));
#else
brush_list = sc->vptr->pair_car (a);
arg->default_value.sfa_brush =
g_strdup (sc->vptr->string_value (sc->vptr->pair_car (brush_list)));
#endif
}
break;
case SF_GRADIENT:
if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
return foreign_error (sc, "script-fu-register: gradient defaults must be string values", 0);
arg->default_value.sfa_gradient =
g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
break;
case SF_OPTION:
{
pointer option_list;
if (!sc->vptr->is_list (sc, a))
return foreign_error (sc, "script-fu-register: option defaults must be a list", 0);
for (option_list = sc->vptr->pair_car (a);
option_list != sc->NIL;
option_list = sc->vptr->pair_cdr (option_list))
{
arg->default_value.sfa_option.list =
g_slist_append (arg->default_value.sfa_option.list,
g_strdup (sc->vptr->string_value
(sc->vptr->pair_car (option_list))));
}
}
break;
case SF_ENUM:
{
pointer option_list;
const gchar *val;
gchar *type_name;
GEnumValue *enum_value;
GType enum_type;
if (!sc->vptr->is_list (sc, a))
return foreign_error (sc, "script-fu-register: enum defaults must be a list", 0);
option_list = sc->vptr->pair_car (a);
if (!sc->vptr->is_string (sc->vptr->pair_car (option_list)))
return foreign_error (sc, "script-fu-register: first element in enum defaults must be a type-name", 0);
val = sc->vptr->string_value (sc->vptr->pair_car (option_list));
if (g_str_has_prefix (val, "Pika"))
type_name = g_strdup (val);
else
type_name = g_strconcat ("Pika", val, NULL);
enum_type = g_type_from_name (type_name);
if (! G_TYPE_IS_ENUM (enum_type))
{
g_free (type_name);
return foreign_error (sc, "script-fu-register: first element in enum defaults must be the name of a registered type", 0);
}
arg->default_value.sfa_enum.type_name = type_name;
option_list = sc->vptr->pair_cdr (option_list);
if (!sc->vptr->is_string (sc->vptr->pair_car (option_list)))
return foreign_error (sc, "script-fu-register: second element in enum defaults must be a string", 0);
enum_value =
g_enum_get_value_by_nick (g_type_class_peek (enum_type),
sc->vptr->string_value (sc->vptr->pair_car (option_list)));
if (enum_value)
arg->default_value.sfa_enum.history = enum_value->value;
}
break;
}
a = sc->vptr->pair_cdr (a);
if (error != sc->NIL)
return error;
else
/* advance to next group of three in the sequence. */
a = sc->vptr->pair_cdr (a);
}
else
{
return foreign_error (sc, "script-fu-register: missing default argument", 0);
return registration_error (sc, "missing default argument");
}
} /* end for */

View File

@ -57,17 +57,17 @@
* Since 3.0
*/
PikaValueArray *
script_fu_run_image_procedure ( PikaProcedure *procedure, /* PikaImageProcedure */
PikaRunMode run_mode,
PikaImage *image,
guint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *other_args,
gpointer data)
script_fu_run_image_procedure (PikaProcedure *procedure, /* PikaImageProcedure */
PikaRunMode run_mode,
PikaImage *image,
guint n_drawables,
PikaDrawable **drawables,
PikaProcedureConfig *config,
gpointer data)
{
PikaValueArray *result = NULL;
SFScript *script;
PikaValueArray *result = NULL;
SFScript *script;
g_debug ("script_fu_run_image_procedure");
script = script_fu_find_script (pika_procedure_get_name (procedure));
@ -81,33 +81,36 @@ script_fu_run_image_procedure ( PikaProcedure *procedure, /* PikaImagePr
{
case PIKA_RUN_INTERACTIVE:
{
if (pika_value_array_length (other_args) > 0)
guint n_specs;
g_free (g_object_class_list_properties (G_OBJECT_GET_CLASS (config), &n_specs));
if (n_specs > 1)
{
/* Let user choose "other" args in a dialog, then interpret. Maintain a config. */
result = script_fu_dialog_run (procedure, script, image, n_drawables, drawables, other_args);
result = script_fu_dialog_run (procedure, script, image, n_drawables, drawables, config);
}
else
{
/* No "other" args for user to choose. No config to maintain. */
result = script_fu_interpret_image_proc (procedure, script, image, n_drawables, drawables, other_args);
result = script_fu_interpret_image_proc (procedure, script, image, n_drawables, drawables, config);
}
break;
}
case PIKA_RUN_NONINTERACTIVE:
{
/* A call from another PDB procedure.
* Use the given other_args, without interacting with user.
* Use the given config, without interacting with user.
* Since no user interaction, no config to maintain.
*/
result = script_fu_interpret_image_proc (procedure, script, image, n_drawables, drawables, other_args);
result = script_fu_interpret_image_proc (procedure, script, image, n_drawables, drawables, config);
break;
}
case PIKA_RUN_WITH_LAST_VALS:
{
/* User invoked from a menu "Filter>Run with last values".
* Do not show dialog. other_args are already last values, from a config.
* Do not show dialog. config are already last values.
*/
result = script_fu_interpret_image_proc (procedure, script, image, n_drawables, drawables, other_args);
result = script_fu_interpret_image_proc (procedure, script, image, n_drawables, drawables, config);
break;
}
default:
@ -115,6 +118,7 @@ script_fu_run_image_procedure ( PikaProcedure *procedure, /* PikaImagePr
result = pika_procedure_new_return_values (procedure, PIKA_PDB_CALLING_ERROR, NULL);
}
}
return result;
}
@ -128,14 +132,17 @@ script_fu_run_image_procedure ( PikaProcedure *procedure, /* PikaImagePr
* Since prior to 3.0 but formerly named script_fu_script_proc
*/
PikaValueArray *
script_fu_run_procedure (PikaProcedure *procedure,
const PikaValueArray *args,
gpointer data)
script_fu_run_procedure (PikaProcedure *procedure,
PikaProcedureConfig *config,
gpointer data)
{
PikaPDBStatusType status = PIKA_PDB_SUCCESS;
SFScript *script;
PikaRunMode run_mode;
GError *error = NULL;
PikaPDBStatusType status = PIKA_PDB_SUCCESS;
SFScript *script;
GParamSpec **pspecs;
guint n_pspecs;
gint n_aux_args;
PikaRunMode run_mode;
GError *error = NULL;
script = script_fu_find_script (pika_procedure_get_name (procedure));
@ -144,7 +151,10 @@ script_fu_run_procedure (PikaProcedure *procedure,
PIKA_PDB_CALLING_ERROR,
NULL);
run_mode = PIKA_VALUES_GET_ENUM (args, 0);
pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (config), &n_pspecs);
pika_procedure_get_aux_arguments (procedure, &n_aux_args);
g_object_get (config, "run-mode", &run_mode, NULL);
ts_set_run_mode (run_mode);
@ -155,7 +165,7 @@ script_fu_run_procedure (PikaProcedure *procedure,
gint min_args = 0;
/* First, try to collect the standard script arguments... */
min_args = script_fu_script_collect_standard_args (script, args);
min_args = script_fu_script_collect_standard_args (script, pspecs, n_pspecs, config);
/* ...then acquire the rest of arguments (if any) with a dialog */
if (script->n_args > min_args)
@ -169,15 +179,18 @@ script_fu_run_procedure (PikaProcedure *procedure,
}
case PIKA_RUN_NONINTERACTIVE:
/* Make sure all the arguments are there */
if (pika_value_array_length (args) != (script->n_args + 1))
/* Verify actual args count equals declared arg count.
* Scripts declare args except run_mode (SF hides it.)
* pspecs have run_mode and one extra internal pspec, thus +2.
*/
if (n_pspecs != script->n_args + n_aux_args + 2)
status = PIKA_PDB_CALLING_ERROR;
if (status == PIKA_PDB_SUCCESS)
{
gchar *command;
command = script_fu_script_get_command_from_params (script, args);
command = script_fu_script_get_command_from_params (script, pspecs, n_pspecs, config);
/* run the command through the interpreter */
if (! script_fu_run_command (command, &error))
@ -196,7 +209,7 @@ script_fu_run_procedure (PikaProcedure *procedure,
gchar *command;
/* First, try to collect the standard script arguments */
script_fu_script_collect_standard_args (script, args);
script_fu_script_collect_standard_args (script, pspecs, n_pspecs, config);
command = script_fu_script_get_command (script);

View File

@ -23,7 +23,7 @@
#define __SCRIPT_FU_RUN_FUNC_H__
PikaValueArray *script_fu_run_procedure (PikaProcedure *procedure,
const PikaValueArray *args,
PikaProcedureConfig *config,
gpointer data);
PikaValueArray *script_fu_run_image_procedure (PikaProcedure *procedure,
@ -31,7 +31,7 @@ PikaValueArray *script_fu_run_image_procedure (PikaProcedure *procedure,
PikaImage *image,
guint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args,
PikaProcedureConfig *config,
gpointer data);
#endif /* __SCRIPT_FU_RUN_FUNC__ */

View File

@ -40,7 +40,9 @@
*/
static gboolean script_fu_script_param_init (SFScript *script,
const PikaValueArray *args,
GParamSpec **pspecs,
guint n_pspecs,
PikaProcedureConfig *config,
SFArgType type,
gint n);
static void script_fu_script_set_proc_metadata (
@ -162,12 +164,11 @@ script_fu_script_create_PDB_procedure (PikaPlugIn *plug_in,
g_debug ("script_fu_script_create_PDB_procedure: %s, plugin type %i, image_proc",
script->name, plug_in_type);
procedure = pika_image_procedure_new (
plug_in, script->name,
plug_in_type,
(PikaRunImageFunc) script_fu_run_image_procedure,
script, /* user_data, pointer in extension-script-fu process */
NULL);
procedure = pika_image_procedure_new (plug_in, script->name,
plug_in_type,
(PikaRunImageFunc) script_fu_run_image_procedure,
script, /* user_data, pointer in extension-script-fu process */
NULL);
script_fu_script_set_proc_metadata (procedure, script);
@ -270,23 +271,25 @@ script_fu_script_reset (SFScript *script,
gint
script_fu_script_collect_standard_args (SFScript *script,
const PikaValueArray *args)
GParamSpec **pspecs,
guint n_pspecs,
PikaProcedureConfig *config)
{
gint params_consumed = 0;
g_return_val_if_fail (script != NULL, 0);
/* the first parameter may be a DISPLAY id */
if (script_fu_script_param_init (script,
args, SF_DISPLAY,
if (script_fu_script_param_init (script, pspecs, n_pspecs,
config, SF_DISPLAY,
params_consumed))
{
params_consumed++;
}
/* an IMAGE id may come first or after the DISPLAY id */
if (script_fu_script_param_init (script,
args, SF_IMAGE,
if (script_fu_script_param_init (script, pspecs, n_pspecs,
config, SF_IMAGE,
params_consumed))
{
params_consumed++;
@ -294,17 +297,17 @@ script_fu_script_collect_standard_args (SFScript *script,
/* and may be followed by a DRAWABLE, LAYER, CHANNEL or
* VECTORS id
*/
if (script_fu_script_param_init (script,
args, SF_DRAWABLE,
if (script_fu_script_param_init (script, pspecs, n_pspecs,
config, SF_DRAWABLE,
params_consumed) ||
script_fu_script_param_init (script,
args, SF_LAYER,
script_fu_script_param_init (script, pspecs, n_pspecs,
config, SF_LAYER,
params_consumed) ||
script_fu_script_param_init (script,
args, SF_CHANNEL,
script_fu_script_param_init (script, pspecs, n_pspecs,
config, SF_CHANNEL,
params_consumed) ||
script_fu_script_param_init (script,
args, SF_VECTORS,
script_fu_script_param_init (script, pspecs, n_pspecs,
config, SF_VECTORS,
params_consumed))
{
params_consumed++;
@ -343,7 +346,9 @@ script_fu_script_get_command (SFScript *script)
gchar *
script_fu_script_get_command_from_params (SFScript *script,
const PikaValueArray *args)
GParamSpec **pspecs,
guint n_pspecs,
PikaProcedureConfig *config)
{
GString *s;
gint i;
@ -355,13 +360,18 @@ script_fu_script_get_command_from_params (SFScript *script,
for (i = 0; i < script->n_args; i++)
{
GValue *value = pika_value_array_index (args, i + 1);
GValue value = G_VALUE_INIT;
GParamSpec *pspec = pspecs[i + 1];
g_value_init (&value, pspec->value_type);
g_object_get_property (G_OBJECT (config), pspec->name, &value);
g_string_append_c (s, ' ');
script_fu_arg_append_repr_from_gvalue (&script->args[i],
s,
value);
&value);
g_value_unset (&value);
}
g_string_append_c (s, ')');
@ -399,11 +409,15 @@ script_fu_script_get_command_for_image_proc (SFScript *script,
PikaImage *image,
guint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args)
PikaProcedureConfig *config)
{
GString *s;
GParamSpec **pspecs;
guint n_pspecs;
GString *s;
gint i;
g_return_val_if_fail (script != NULL, NULL);
g_return_val_if_fail (PIKA_IS_PROCEDURE_CONFIG (config), NULL);
s = g_string_new ("(");
g_string_append (s, script->name);
@ -424,20 +438,28 @@ script_fu_script_get_command_for_image_proc (SFScript *script,
*/
script_fu_command_append_drawables (s, n_drawables, drawables);
/* args contains the "other" args
/* config contains the "other" args
* Iterate over the PikaValueArray.
* But script->args should be the same length, and types should match.
*/
for (guint i = 0; i < pika_value_array_length (args); i++)
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++)
{
GValue *value = pika_value_array_index (args, i);
GParamSpec *pspec = pspecs[i];
GValue value = G_VALUE_INIT;
g_string_append_c (s, ' ');
script_fu_arg_append_repr_from_gvalue (&script->args[i],
s,
value);
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);
g_value_unset (&value);
}
g_string_append_c (s, ')');
g_free (pspecs);
return g_string_free (s, FALSE);
}
@ -466,7 +488,9 @@ script_fu_script_infer_drawable_arity (SFScript *script)
static gboolean
script_fu_script_param_init (SFScript *script,
const PikaValueArray *args,
GParamSpec **pspecs,
guint n_pspecs,
PikaProcedureConfig *config,
SFArgType type,
gint n)
{
@ -474,16 +498,20 @@ script_fu_script_param_init (SFScript *script,
if (script->n_args > n &&
arg->type == type &&
pika_value_array_length (args) > n + 1)
/* The first pspec is "procedure", the second is "run-mode". */
n_pspecs > n + 2)
{
GValue *value = pika_value_array_index (args, n + 1);
GValue value = G_VALUE_INIT;
GParamSpec *pspec = pspecs[n + 2];
g_value_init (&value, pspec->value_type);
g_object_get_property (G_OBJECT (config), pspec->name, &value);
switch (type)
{
case SF_IMAGE:
if (PIKA_VALUE_HOLDS_IMAGE (value))
if (PIKA_VALUE_HOLDS_IMAGE (&value))
{
PikaImage *image = g_value_get_object (value);
PikaImage *image = g_value_get_object (&value);
arg->value.sfa_image = pika_image_get_id (image);
return TRUE;
@ -491,9 +519,9 @@ script_fu_script_param_init (SFScript *script,
break;
case SF_DRAWABLE:
if (PIKA_VALUE_HOLDS_DRAWABLE (value))
if (PIKA_VALUE_HOLDS_DRAWABLE (&value))
{
PikaItem *item = g_value_get_object (value);
PikaItem *item = g_value_get_object (&value);
arg->value.sfa_drawable = pika_item_get_id (item);
return TRUE;
@ -501,9 +529,9 @@ script_fu_script_param_init (SFScript *script,
break;
case SF_LAYER:
if (PIKA_VALUE_HOLDS_LAYER (value))
if (PIKA_VALUE_HOLDS_LAYER (&value))
{
PikaItem *item = g_value_get_object (value);
PikaItem *item = g_value_get_object (&value);
arg->value.sfa_layer = pika_item_get_id (item);
return TRUE;
@ -511,9 +539,9 @@ script_fu_script_param_init (SFScript *script,
break;
case SF_CHANNEL:
if (PIKA_VALUE_HOLDS_CHANNEL (value))
if (PIKA_VALUE_HOLDS_CHANNEL (&value))
{
PikaItem *item = g_value_get_object (value);
PikaItem *item = g_value_get_object (&value);
arg->value.sfa_channel = pika_item_get_id (item);
return TRUE;
@ -521,9 +549,9 @@ script_fu_script_param_init (SFScript *script,
break;
case SF_VECTORS:
if (PIKA_VALUE_HOLDS_VECTORS (value))
if (PIKA_VALUE_HOLDS_VECTORS (&value))
{
PikaItem *item = g_value_get_object (value);
PikaItem *item = g_value_get_object (&value);
arg->value.sfa_vectors = pika_item_get_id (item);
return TRUE;
@ -531,9 +559,9 @@ script_fu_script_param_init (SFScript *script,
break;
case SF_DISPLAY:
if (PIKA_VALUE_HOLDS_DISPLAY (value))
if (PIKA_VALUE_HOLDS_DISPLAY (&value))
{
PikaDisplay *display = g_value_get_object (value);
PikaDisplay *display = g_value_get_object (&value);
arg->value.sfa_display = pika_display_get_id (display);
return TRUE;
@ -543,6 +571,7 @@ script_fu_script_param_init (SFScript *script,
default:
break;
}
g_value_unset (&value);
}
return FALSE;

View File

@ -43,17 +43,21 @@ void script_fu_script_reset (SFScript *scrip
gboolean reset_ids);
gint script_fu_script_collect_standard_args (SFScript *script,
const PikaValueArray *args);
GParamSpec **pspecs,
guint n_pspecs,
PikaProcedureConfig *config);
gchar * script_fu_script_get_command (SFScript *script);
gchar * script_fu_script_get_command_from_params (SFScript *script,
const PikaValueArray *args);
GParamSpec **pspecs,
guint n_pspecs,
PikaProcedureConfig *config);
gchar * script_fu_script_get_command_for_image_proc (
SFScript *script,
PikaImage *image,
guint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args);
PikaProcedureConfig *config);
PikaProcedure * script_fu_script_create_PDB_procedure (PikaPlugIn *plug_in,
SFScript *script,

View File

@ -54,6 +54,8 @@ typedef struct
gint history;
} SFEnum;
typedef gint32 SFResourceType;
typedef union
{
gint32 sfa_image;
@ -67,11 +69,7 @@ typedef union
gchar *sfa_value;
SFAdjustment sfa_adjustment;
SFFilename sfa_file;
gchar *sfa_font;
gchar *sfa_gradient;
gchar *sfa_palette;
gchar *sfa_pattern;
gchar *sfa_brush;
SFResourceType sfa_resource;
SFOption sfa_option;
SFEnum sfa_enum;
} SFArgValue;