mirror of https://github.com/GNOME/gimp.git
Fix #10044 more natural binding of PDB return values
Allow (script-fu-use-v3) in script, or in SF Console. Definitive description is in script-fu/docs/using-v3-binding.md Makes SF interpret v3 of SF dialect. - marshals single return value from PDB without wrapping in list - marshals boolean return value from PDB as #t #f instead of integers - marshals boolean to PDB from #t and #f or TRUE and FALSE - marshals void return from PDB as () instead of (#t), but that is moot. The version of SF dialect is distinct from the version of the PDB API. Dialect v3 is opt-in: the initial dialect of all SF tools remains v2. Commit also allows #t,#f for defaults of SF-TOGGLE instead of TRUE, FALSE but that is an independent enhancement (but closely related.) Affects interpreter state of the current process. Not an attribute per se of a plugin. While in this state, a plugin should not call PDB procedures which are themselves v2 script plugins, or a few utility scripts in script-fu-util.scm, but that is rarely needed. Does not remove symbols TRUE and FALSE from dialect. A script can also call (script-fu-use-v2) to revert. That is also discouraged but useful e.g. for testing.
This commit is contained in:
parent
d4af93b256
commit
98bf051e7a
|
@ -0,0 +1,282 @@
|
|||
# The version 3 dialect of the ScriptFu language
|
||||
|
||||
## About
|
||||
|
||||
This describes a new dialect of ScriptFu,
|
||||
used when a script calls: (script-fu-use-v3).
|
||||
The new dialect is more like Scheme and makes scripts shorter.
|
||||
The dialect only affects calls to the PDB.
|
||||
|
||||
The audience is script authors and other developers.
|
||||
|
||||
This describes the new dialect and how to port old scripts to the new dialect.
|
||||
|
||||
|
||||
## Quick Start
|
||||
|
||||
A script that calls:
|
||||
```
|
||||
(script-fu-use-v3)
|
||||
```
|
||||
binds to certain PDB calls differently:
|
||||
|
||||
1. PDB procedures that return single values return just that single value,
|
||||
*not wrapped in a list.*
|
||||
Formerly, every PDB call returned a list (possibly nesting more lists.)
|
||||
|
||||
2. You can use #t and #f as arguments to PDB calls taking a boolean.
|
||||
|
||||
3. PDB calls returning a boolean return #t or #f, not TRUE or FALSE (1 or 0.)
|
||||
|
||||
## Script-Fu Console
|
||||
|
||||
The Script-Fu Console always starts in the v2 dialect.
|
||||
|
||||
You can call *script-fu-use-v3* in the console.
|
||||
Then, the console interprets the v3 dialect.
|
||||
It continues to interpret the v3 dialect in that session,
|
||||
until you call *script-fu-use-v2.*
|
||||
|
||||
## Where to call *script-fu-use-v3* in scripts
|
||||
|
||||
Call *script-fu-use-v3* early.
|
||||
This sets the dialect version for the remaining interpretation of the script.
|
||||
Call *script-fu-use-v3* at the beginning of the run function.
|
||||
|
||||
!!! Do not call *script-fu-use-v3* at the top level of a script.
|
||||
This has no effect, since it is only executed in the query phase.
|
||||
The interpreter starts at the run function during the run phase.
|
||||
|
||||
*The interpreter always starts interpreting each script in the v2 dialect.
|
||||
This is true even for extension-script-fu, the long-running interpreter.*
|
||||
There is no need to call *script-fu-use-v2* before returning from a script,
|
||||
to ensure that the next script is interpreted in v2 dialect.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
(define (script-fu-testv3 img drawables )
|
||||
(script-fu-use-v3) ; <<<
|
||||
(let* (
|
||||
...
|
||||
```
|
||||
### Technically speaking
|
||||
|
||||
The dialect version has "execution scope" versus "lexical scope."
|
||||
Setting the dialect version is effective even for
|
||||
other functions defined in the same script but lexically
|
||||
outside the function where the dialect is set.
|
||||
|
||||
|
||||
## Don't call v2 scripts from v3 scripts
|
||||
|
||||
When using the v3 dialect,
|
||||
you can't call plugin scripts or other library scripts that depend on the v2 dialect.
|
||||
And vice versa.
|
||||
(When a script calls a PDB procedure that is a script,
|
||||
a new interpreter process is *NOT* started.)
|
||||
|
||||
For example, a new plugin script should not call the PDB procedure
|
||||
script-fu-add-bevel because it is implemented in ScriptFu Scheme
|
||||
and for example has:
|
||||
|
||||
```
|
||||
(width (car (gimp-drawable-get-width pic-layer)))
|
||||
```
|
||||
which is v2 dialect and would throw an error such as:
|
||||
```
|
||||
Error: car requires a pair.
|
||||
```
|
||||
|
||||
*It is rare that a script calls another plugin script.*
|
||||
A script usually calls the PDB,
|
||||
but rarely calls a plugin script of the PDB.
|
||||
|
||||
There are very few, obscure library scripts that call the PDB using v2 dialect.
|
||||
These are in scripts/script-fu-util.scm.
|
||||
|
||||
## Pure Scheme is unaffected
|
||||
|
||||
The dialect only affects calls the to PDB.
|
||||
|
||||
This means you can usually call most library scripts when using v3,
|
||||
since most library scripts are pure Scheme,
|
||||
that is, with no calls to the GIMP PDB.
|
||||
|
||||
## TRUE and FALSE
|
||||
|
||||
TRUE and FALSE are still in v3 dialect and are still numbers 1 and 0.
|
||||
But we recommend not using them.
|
||||
|
||||
You can still pass them as arguments to PDB calls taking a boolean,
|
||||
and they are still converted to the C notion of boolean truth.
|
||||
|
||||
FALSE which is 0 is truthy in Scheme!!!
|
||||
It converts to the C notion of false only in a call the the PDB.
|
||||
In the ScriptFu Console:
|
||||
```
|
||||
>(equal? FALSE #t)
|
||||
#t
|
||||
```
|
||||
|
||||
TRUE and FALSE symbols may become obsolete in the future.
|
||||
|
||||
## Plans for the future
|
||||
|
||||
This dialect is shorter and more natural for Scheme programmers.
|
||||
|
||||
The long-term goal is for the v3 dialect to be the only dialect of ScriptFu.
|
||||
For the short term, for backward compatibility,
|
||||
the default dialect of ScriptFu is the v2 dialect.
|
||||
|
||||
You should write any new scripts in the v3 dialect,
|
||||
and call *script-fu-use-v3*.
|
||||
|
||||
You should plan on porting existing scripts to the v3 dialect,
|
||||
since eventually ScriptFu might not support v2 dialect.
|
||||
|
||||
## Example conversions from v2 to v3
|
||||
|
||||
### A call to a PDB procedure returning a single value
|
||||
|
||||
```
|
||||
(set! (width (car (gimp-drawable-get-width pic-layer))))
|
||||
```
|
||||
*must* become
|
||||
```
|
||||
(set! (width (gimp-drawable-get-width pic-layer)))
|
||||
```
|
||||
The PDB call returns a single integer,
|
||||
so no *car* is needed.
|
||||
|
||||
### A call to a PDB procedure returning boolean
|
||||
```
|
||||
(if (= (gimp-image-is-rgb image) TRUE) ...
|
||||
```
|
||||
*must* become:
|
||||
```
|
||||
(if (gimp-image-is-rgb image) ...
|
||||
```
|
||||
The PDB procedure returns a boolean,
|
||||
which is bound to #t or #f,
|
||||
the usual symbols for Scheme truth.
|
||||
|
||||
### A call to a PDB procedure taking a boolean
|
||||
|
||||
```
|
||||
(gimp-context-set-antialias TRUE)
|
||||
```
|
||||
*should* become
|
||||
```
|
||||
(gimp-context-set-antialias #t)
|
||||
```
|
||||
This doesn't *require* conversion because TRUE is 1 and is truthy in Scheme.
|
||||
|
||||
!!! But FALSE is 0 and 0 is truthy in Scheme
|
||||
```
|
||||
(gimp-context-set-antialias FALSE)
|
||||
```
|
||||
This *should* be converted, for clarity, but doesn't *require* conversion.
|
||||
For now, ScriptFu still binds Scheme 0 to C 0.
|
||||
So it still does what the script intends.
|
||||
|
||||
### A call to a PDB procedure returning a list
|
||||
|
||||
```
|
||||
(set! brushes (car (gimp-brushes-get-list)))
|
||||
```
|
||||
*must* become:
|
||||
```
|
||||
(set! brushes (gimp-brushes-get-list))
|
||||
```
|
||||
Formerly, the PDB procedure returned a list wrapped in a list,
|
||||
i.e. ((...))
|
||||
In the v3 dialect, it returns just a list, i.e. (...)
|
||||
which is a single value, a single container.
|
||||
|
||||
### A call to a PDB procedure returning a list, getting the first element
|
||||
|
||||
```
|
||||
(set! first-brush (caar (gimp-brushes-get-list)))
|
||||
```
|
||||
Gets the first brush in GIMP.
|
||||
This *must* become:
|
||||
```
|
||||
(set! first-brush (car (gimp-brushes-get-list)))
|
||||
```
|
||||
The call to *caar* is consecutive calls to *car*,
|
||||
and you must eliminate the first call to *car*.
|
||||
|
||||
|
||||
## Knowing what constructs need conversion
|
||||
|
||||
You *should* (but are not required to)
|
||||
eliminate all uses of symbols TRUE and FALSE from a script
|
||||
using v3 dialect.
|
||||
|
||||
You should eliminate many, *but not all*, uses of the *car* function wrapping a call to the PDB,
|
||||
where the PDB procedure returns a single value.
|
||||
There are several hundred such PDB procedures in the PDB.
|
||||
Examine the signature of a PDB procedure using the PDB Browser.
|
||||
|
||||
For example, gimp-brush-get-angle:
|
||||
```
|
||||
Return Values
|
||||
angle gdouble ....
|
||||
Additional Information
|
||||
```
|
||||
This returns a single value so no need to use car.
|
||||
|
||||
For example, gimp-brushes-get-list:
|
||||
```
|
||||
Return Values
|
||||
brush-list GStrv
|
||||
Additional Information
|
||||
```
|
||||
This also returns a single value.
|
||||
The single value is a list i.e. container.
|
||||
In the v2 dialect, this returned a list wrapped in a list,
|
||||
for example (("foo" "bar")).
|
||||
|
||||
See "Example conversions from v2 to v3"
|
||||
|
||||
### Does not require changes to calls to PDB procedures returning void
|
||||
|
||||
You should not need to change scripts on calls to PDB procedures returning C void because a script should not be examining the result.
|
||||
|
||||
Some scripts might examine the result of a call to a void PDB procedure, thinking that (#t) is the success of the call,
|
||||
but that is a misconception and should be fixed.
|
||||
|
||||
Calls to PDB procedures that return C void return (#t) in v2 and the empty list (), sometimes called nil, in v3 dialect.
|
||||
|
||||
## Details of the implementation
|
||||
|
||||
There are new functions in the dialect:
|
||||
```
|
||||
script-fu-use-v3
|
||||
script-fu-use-v2
|
||||
```
|
||||
These functions have side-effects on the state of the interpreter.
|
||||
They always return the empty list ().
|
||||
|
||||
The effect is immediate.
|
||||
The interpreter interprets a dialect from then on,
|
||||
until the script returns,
|
||||
or until the script changes the dialect again.
|
||||
|
||||
A call to *script-fu-use-v3* sets a flag in the state of the interpreter.
|
||||
When the flag is set, the interpreter binds arguments to PDB calls slightly differently, as described.
|
||||
Binding of args to PDB calls is done at run time.
|
||||
|
||||
Similarly, a call to *script-fu-use-v2* clears the flag
|
||||
and restores the interpreter state to binding using the v2 dialect.
|
||||
|
||||
When in the v3 state,
|
||||
any PDB call constructs using v2 binding will yield errors,
|
||||
and vice versa.
|
||||
|
||||
Note that the difference in interpretation is only in binding, but both to and from the PDB:
|
||||
|
||||
1. Single return values *from* the PDB are not wrapped in lists.
|
||||
2. Boolean return values *from* the PDB are bound to #t and #f.
|
||||
3. Boolean values *to* the PDB can be #t and #f.
|
|
@ -21,6 +21,7 @@ libscriptfu_sources = [
|
|||
'script-fu-dialog.c',
|
||||
'script-fu-run-func.c',
|
||||
'script-fu-command.c',
|
||||
'script-fu-version.c',
|
||||
'script-fu-widgets-custom.c',
|
||||
'script-fu-color.c',
|
||||
'script-fu-resource.c',
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libgimp/gimp.h"
|
||||
#include "tinyscheme/scheme-private.h"
|
||||
#include "script-fu-errors.h"
|
||||
#include "script-fu-version.h"
|
||||
#include "scheme-marshal.h"
|
||||
#include "scheme-marshal-return.h"
|
||||
|
||||
|
@ -164,8 +165,11 @@ marshal_PDB_return (scheme *sc,
|
|||
*
|
||||
* Returns a scheme "pointer" type referencing the scheme return value.
|
||||
*
|
||||
* The return value is a list.
|
||||
* FUTURE: value is either a single value or a list.
|
||||
* The return value depends on the SF dialect in use (script-fu-use-v3)
|
||||
* v2: return value is a list.
|
||||
* v3: value is either a single value for PDB procs returning solitary value,
|
||||
* or an empty list for void PDB procs,
|
||||
* or a list for PDB procs returning many values.
|
||||
*
|
||||
* Same error return as marshal_returned_PDB_values.
|
||||
*/
|
||||
|
@ -193,22 +197,36 @@ marshal_PDB_return_by_arity (scheme *sc,
|
|||
if (return_arity == 0)
|
||||
{
|
||||
/* PDB procedure returns void.
|
||||
* Every scheme function must return a value.
|
||||
* Return (#t)
|
||||
* FUTURE: return just sc->T, no reason to wrap it.
|
||||
* result = sc->T;
|
||||
* But every scheme function must return a value.
|
||||
* What we return is moot: a caller should not use result of a void PDB procedure.
|
||||
* This result is NOT an error status.
|
||||
*/
|
||||
g_debug ("void PDB proc returns (#t)");
|
||||
if (is_interpret_v3_dialect ())
|
||||
{
|
||||
/* Marshal to `() satisfying (null? ) predicate.
|
||||
* Note is truthy in Scheme, satisfies (if )
|
||||
*/
|
||||
result = sc->NIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* v2 void PDB proc return marshals to (#t) */
|
||||
result = sc->vptr->cons (sc, sc->T, sc->NIL);
|
||||
}
|
||||
}
|
||||
else if (return_arity == 1)
|
||||
{
|
||||
/* Unary result.
|
||||
* Return a list wrapping the result.
|
||||
* FUTURE: return just unwrapped result (which can itself be a list.)
|
||||
* i.e. just call marshal_returned_PDB_value (singular)
|
||||
*/
|
||||
if (is_interpret_v3_dialect ())
|
||||
{
|
||||
/* Marshal to single value not wrapped in list. */
|
||||
/* The value is second in the GVA, beyond the PDB status value. */
|
||||
result = marshal_returned_PDB_value (sc, gimp_value_array_index (values, 1), 2, &marshalling_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* v2 marshal to list of many values. */
|
||||
result = marshal_returned_PDB_values (sc, values, &marshalling_error);
|
||||
}
|
||||
if (marshalling_error != NULL)
|
||||
{
|
||||
/* Propagate error. */
|
||||
|
@ -217,9 +235,7 @@ marshal_PDB_return_by_arity (scheme *sc,
|
|||
}
|
||||
else /* >1 */
|
||||
{
|
||||
/* Many result values.
|
||||
* Return a list wrapping the results. Similar to Python tuple return.
|
||||
*/
|
||||
/* Marshal to a list wrapping the results. Similar to Python tuple return.*/
|
||||
result = marshal_returned_PDB_values (sc, values, &marshalling_error);
|
||||
if (marshalling_error != NULL)
|
||||
{
|
||||
|
@ -229,11 +245,8 @@ marshal_PDB_return_by_arity (scheme *sc,
|
|||
}
|
||||
g_assert ( (result == NULL && *error != NULL)
|
||||
|| (result != NULL && *error == NULL));
|
||||
/* result is: (#t) or sc->NIL i.e. empty list or a non-empty list. */
|
||||
/* FUTURE result is: #t or an atom or a vector
|
||||
* or empty list or a non-empty list.
|
||||
* A non-empty list is either a single result that itself is a list
|
||||
* or a list wrapping a multiple result.
|
||||
/* result is Scheme pointer to a Scheme data structure
|
||||
* that depends on the dialect being interpreted (script-fu-use-v3)
|
||||
*/
|
||||
return result;
|
||||
}
|
||||
|
@ -252,12 +265,8 @@ marshal_PDB_return_by_arity (scheme *sc,
|
|||
* The list can be non-homogenous (elements of different scheme types.)
|
||||
*
|
||||
* The returned list may be empty or have only a single element.
|
||||
* FUTURE:
|
||||
* When a PDB procedure returns a single value (which can be a container)
|
||||
* do not wrap it in a list.
|
||||
* It will be an error to call this function
|
||||
* for PDB procedures that return a single value or return void.
|
||||
* IOW, for PDB procedures of return arity < 2.
|
||||
* In particular, when v2 dialect is in use, and the called PDB procedure
|
||||
* returns a solitary value.
|
||||
*/
|
||||
static pointer
|
||||
marshal_returned_PDB_values (scheme *sc,
|
||||
|
@ -343,8 +352,9 @@ marshal_returned_PDB_values (scheme *sc,
|
|||
* Currently, does not return atoms of scheme type byte or char
|
||||
* (no PDB procedure returns those types.)
|
||||
*
|
||||
* !!! Returns a scheme number (0 or 1) for C type boolean.
|
||||
* FUTURE: return atoms #f and #t.
|
||||
* !!! For C type boolean, returned scheme type depends on dialect version:
|
||||
* - v2 returns a scheme integer (0 or 1)
|
||||
* - v3 returns atom #f or #t.
|
||||
*/
|
||||
static pointer
|
||||
marshal_returned_PDB_value (scheme *sc,
|
||||
|
@ -438,8 +448,17 @@ marshal_returned_PDB_value (scheme *sc,
|
|||
else if (G_VALUE_HOLDS_BOOLEAN (value))
|
||||
{
|
||||
gboolean v = g_value_get_boolean (value);
|
||||
if (is_interpret_v3_dialect ())
|
||||
{
|
||||
/* Marshal to Scheme #t and #f */
|
||||
result = v ? sc->T : sc->F;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* v2 marshal to integer 0 or 1, same as TRUE FALSE symbols. C idiom */
|
||||
result = sc->vptr->mk_integer (sc, v);
|
||||
}
|
||||
}
|
||||
else if (G_VALUE_HOLDS_STRING (value))
|
||||
{
|
||||
const gchar *v = g_value_get_string (value);
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "script-fu-scripts.h"
|
||||
#include "script-fu-errors.h"
|
||||
#include "script-fu-compat.h"
|
||||
#include "script-fu-version.h"
|
||||
|
||||
#include "scheme-wrapper.h"
|
||||
#include "scheme-marshal.h"
|
||||
|
@ -78,6 +79,10 @@ static pointer script_fu_register_call_filter (scheme *sc,
|
|||
pointer a);
|
||||
static pointer script_fu_menu_register_call (scheme *sc,
|
||||
pointer a);
|
||||
static pointer script_fu_use_v3_call (scheme *sc,
|
||||
pointer a);
|
||||
static pointer script_fu_use_v2_call (scheme *sc,
|
||||
pointer a);
|
||||
static pointer script_fu_quit_call (scheme *sc,
|
||||
pointer a);
|
||||
static pointer script_fu_nil_call (scheme *sc,
|
||||
|
@ -553,6 +558,7 @@ ts_init_procedures (scheme *sc,
|
|||
ts_define_procedure (sc, "load-extension", scm_load_ext);
|
||||
#endif
|
||||
|
||||
/* Define special functions used in scripts. */
|
||||
if (register_scripts)
|
||||
{
|
||||
ts_define_procedure (sc, "script-fu-register", script_fu_register_call);
|
||||
|
@ -566,18 +572,25 @@ ts_define_procedure (sc, "load-extension", scm_load_ext);
|
|||
ts_define_procedure (sc, "script-fu-menu-register", script_fu_nil_call);
|
||||
}
|
||||
|
||||
ts_define_procedure (sc, "script-fu-use-v3", script_fu_use_v3_call);
|
||||
ts_define_procedure (sc, "script-fu-use-v2", script_fu_use_v2_call);
|
||||
ts_define_procedure (sc, "script-fu-quit", script_fu_quit_call);
|
||||
|
||||
/* Define wrapper functions, not used in scripts.
|
||||
* FUTURE: eliminate all but one, deprecated and permissive is obsolete.
|
||||
*/
|
||||
ts_define_procedure (sc, "gimp-proc-db-call", script_fu_marshal_procedure_call_strict);
|
||||
ts_define_procedure (sc, "-gimp-proc-db-call", script_fu_marshal_procedure_call_permissive);
|
||||
ts_define_procedure (sc, "--gimp-proc-db-call", script_fu_marshal_procedure_call_deprecated);
|
||||
|
||||
/* Define each PDB procedure as a scheme func.
|
||||
* Each call passes through one of the wrapper funcs.
|
||||
*/
|
||||
proc_list = gimp_pdb_query_procedures (gimp_get_pdb (),
|
||||
".*", ".*", ".*", ".*",
|
||||
".*", ".*", ".*", ".*");
|
||||
num_procs = proc_list ? g_strv_length (proc_list) : 0;
|
||||
|
||||
/* Register each procedure as a scheme func */
|
||||
for (i = 0; i < num_procs; i++)
|
||||
{
|
||||
gchar *buff;
|
||||
|
@ -854,12 +867,35 @@ script_fu_marshal_procedure_call (scheme *sc,
|
|||
}
|
||||
else if (G_VALUE_HOLDS_BOOLEAN (&value))
|
||||
{
|
||||
if (! sc->vptr->is_number (sc->vptr->pair_car (a)))
|
||||
return script_type_error (sc, "numeric", i, proc_name);
|
||||
else
|
||||
if (sc->vptr->is_number (sc->vptr->pair_car (a)))
|
||||
{
|
||||
/* Bind according to C idiom: 0 is false, other numeric values true.
|
||||
* This is not strict Scheme: 0 is truthy in Scheme.
|
||||
* This lets FALSE still work, where FALSE is a deprecated symbol for 0.
|
||||
*/
|
||||
g_value_set_boolean (&value,
|
||||
sc->vptr->ivalue (sc->vptr->pair_car (a)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_interpret_v3_dialect ())
|
||||
{
|
||||
/* Use Scheme semantics: anything but #f is true.
|
||||
* This allows Scheme expressions yielding any Scheme type.
|
||||
*/
|
||||
/* is_false is not exported from scheme.c (but should be.)
|
||||
* This is the same code: compare Scheme pointers.
|
||||
*/
|
||||
gboolean truth_value = ! (sc->vptr->pair_car (a) == sc->F);
|
||||
g_value_set_boolean (&value, truth_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* v2 */
|
||||
return script_type_error (sc, "numeric", i, proc_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (G_VALUE_HOLDS_STRING (&value))
|
||||
{
|
||||
if (! sc->vptr->is_string (sc->vptr->pair_car (a)))
|
||||
|
@ -1509,6 +1545,22 @@ script_fu_menu_register_call (scheme *sc,
|
|||
return script_fu_add_menu (sc, a);
|
||||
}
|
||||
|
||||
static pointer
|
||||
script_fu_use_v3_call (scheme *sc,
|
||||
pointer a)
|
||||
{
|
||||
begin_interpret_v3_dialect ();
|
||||
return sc->NIL;
|
||||
}
|
||||
|
||||
static pointer
|
||||
script_fu_use_v2_call (scheme *sc,
|
||||
pointer a)
|
||||
{
|
||||
begin_interpret_v2_dialect ();
|
||||
return sc->NIL;
|
||||
}
|
||||
|
||||
static pointer
|
||||
script_fu_quit_call (scheme *sc,
|
||||
pointer a)
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "script-fu-types.h"
|
||||
#include "script-fu-arg.h"
|
||||
#include "script-fu-utils.h"
|
||||
#include "script-fu-version.h"
|
||||
|
||||
|
||||
/*
|
||||
|
@ -497,8 +498,12 @@ script_fu_arg_append_repr_from_gvalue (SFArg *arg,
|
|||
break;
|
||||
|
||||
case SF_TOGGLE:
|
||||
g_string_append_printf (result_string, (g_value_get_boolean (gvalue) ?
|
||||
"TRUE" : "FALSE"));
|
||||
if (is_interpret_v3_dialect ())
|
||||
{
|
||||
g_string_append (result_string, (g_value_get_boolean (gvalue) ? "#t" : "#f"));
|
||||
}
|
||||
else
|
||||
g_string_append (result_string, (g_value_get_boolean (gvalue) ? "TRUE" : "FALSE"));
|
||||
break;
|
||||
|
||||
case SF_VALUE:
|
||||
|
@ -634,6 +639,9 @@ script_fu_arg_append_repr_from_self (SFArg *arg,
|
|||
break;
|
||||
|
||||
case SF_TOGGLE:
|
||||
if (is_interpret_v3_dialect ())
|
||||
g_string_append (result_string, arg_value->sfa_toggle ? "#t" : "#f");
|
||||
else
|
||||
g_string_append (result_string, arg_value->sfa_toggle ? "TRUE" : "FALSE");
|
||||
break;
|
||||
|
||||
|
|
|
@ -194,11 +194,26 @@ script_fu_parse_default_spec (scheme *sc,
|
|||
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;
|
||||
/* Accept scheme boolean or int.
|
||||
* This does not vary by language version, and makes language v2 more lenient.
|
||||
*/
|
||||
/* Note storing internally as a C int, which the widget wants.
|
||||
* Elsewhere we marshal back to a Scheme data.
|
||||
*
|
||||
* Note that is_false is not exported from scheme.c, we compare Scheme pointers.
|
||||
*
|
||||
* The default value is from evaluating a Scheme expression.
|
||||
* More in keeping with Scheme, should convert any value other than #f to C truth.
|
||||
* Instead, convert only literal #t to C truth.
|
||||
*/
|
||||
if (sc->vptr->is_integer (default_spec))
|
||||
arg->default_value.sfa_toggle = (sc->vptr->ivalue (default_spec)) ? TRUE : FALSE;
|
||||
else if (default_spec == sc->T)
|
||||
arg->default_value.sfa_toggle = 1;
|
||||
else if (default_spec == sc->F)
|
||||
arg->default_value.sfa_toggle = 0;
|
||||
else
|
||||
return registration_error (sc, "toggle default must yield an integer, #t, or #f");
|
||||
break;
|
||||
|
||||
case SF_VALUE:
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "script-fu-script.h"
|
||||
#include "script-fu-scripts.h" /* script_fu_find_script */
|
||||
#include "script-fu-command.h"
|
||||
#include "script-fu-version.h"
|
||||
|
||||
#include "script-fu-run-func.h"
|
||||
|
||||
|
@ -42,6 +43,11 @@
|
|||
* These return the result of interpretation,
|
||||
* in a GimpValueArray whose only element is a status.
|
||||
* !!! ScriptFu does not let authors define procedures that return values.
|
||||
*
|
||||
* A prior script may have called (script-fu-use-v3) to opt in to interpret v3 dialect.
|
||||
* When this is long-running extension-script-fu process,
|
||||
* ensure initial dialect is v2, the default.
|
||||
* FUTURE: default is v3 and script must opt in to v2 dialect.
|
||||
*/
|
||||
|
||||
/* run_func for a GimpImageProcedure
|
||||
|
@ -73,6 +79,8 @@ script_fu_run_image_procedure (GimpProcedure *procedure, /* GimpImageProc
|
|||
|
||||
ts_set_run_mode (run_mode);
|
||||
|
||||
begin_interpret_default_dialect ();
|
||||
|
||||
switch (run_mode)
|
||||
{
|
||||
case GIMP_RUN_INTERACTIVE:
|
||||
|
@ -154,6 +162,8 @@ script_fu_run_procedure (GimpProcedure *procedure,
|
|||
|
||||
ts_set_run_mode (run_mode);
|
||||
|
||||
begin_interpret_default_dialect ();
|
||||
|
||||
switch (run_mode)
|
||||
{
|
||||
case GIMP_RUN_INTERACTIVE:
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
* 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 <libgimp/gimp.h>
|
||||
|
||||
/* Flag indicating version 3 binding to the PDB.
|
||||
* while marshalling return values from PDB:
|
||||
* - not wrap solitary values in list
|
||||
* - bind c boolean to scheme truth values
|
||||
*
|
||||
* Set by a script calling (script-fu-use-v3).
|
||||
* Cleared by a script calling (script-fu-use-v2).
|
||||
*
|
||||
* Initial, default state of all ScriptFu tools is interpret v2 dialect.
|
||||
*
|
||||
* New-style scripts call (script-fu-use-v3) at top level.
|
||||
* Ends with process termination of the interpreter.
|
||||
*
|
||||
* Old-style scripts call in run function, but this is discouraged.
|
||||
* Ends after extension-script-fu finishes interpretation of current command.
|
||||
*
|
||||
* Affects interpretation for the duration of the current interpreter process.
|
||||
* !!! All script interpreted subsequently in the current process,
|
||||
* especially in called PDB procedures that are themselves scripts,
|
||||
* must use v3 binding to PDB.
|
||||
* Note most old script plugins in the PDB use v2 that is affected by this flag.
|
||||
* Note a very few routines in script-fu-util.scm call the PDB using v2 binding.
|
||||
* So a script should not call them while this flag is set.
|
||||
*/
|
||||
static gboolean language_version_is_3 = FALSE;
|
||||
|
||||
void
|
||||
begin_interpret_v3_dialect (void)
|
||||
{
|
||||
language_version_is_3 = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
begin_interpret_v2_dialect (void)
|
||||
{
|
||||
language_version_is_3 = FALSE;
|
||||
}
|
||||
|
||||
/* the default dialect is v2 */
|
||||
void
|
||||
begin_interpret_default_dialect (void)
|
||||
{
|
||||
/* the default dialect is v2 */
|
||||
begin_interpret_v2_dialect ();
|
||||
}
|
||||
|
||||
gboolean
|
||||
is_interpret_v3_dialect (void)
|
||||
{
|
||||
return language_version_is_3;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
/* GIMP - The GNU Image Manipulation Program
|
||||
* 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_VERSION_H__
|
||||
#define __SCRIPT_FU_VERSION_H__
|
||||
|
||||
void begin_interpret_v3_dialect (void);
|
||||
void begin_interpret_v2_dialect (void);
|
||||
void begin_interpret_default_dialect (void);
|
||||
gboolean is_interpret_v3_dialect (void);
|
||||
|
||||
#endif /* __SCRIPT_FU_VERSION__ */
|
|
@ -53,6 +53,7 @@ if not stable
|
|||
scripts += [
|
||||
'contactsheet.scm',
|
||||
'test-sphere.scm',
|
||||
'test-v3.scm',
|
||||
]
|
||||
endif
|
||||
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
; See also test-sphere.scm, for GIMP 2, from which this is derived
|
||||
; Diffs marked with ; v3 >>>
|
||||
|
||||
; Also modified to use script-fu-use-v3
|
||||
; I.E. binding of boolean and binding of PDB returns is changed.
|
||||
; TRUE => #t in many places
|
||||
; (car (...)) => (...) in many places
|
||||
|
||||
|
||||
; v3 >>> signature of GimpImageProcedure
|
||||
; drawables is a vector
|
||||
|
@ -37,12 +42,13 @@
|
|||
unused-layer
|
||||
unused-channel
|
||||
unused-drawable)
|
||||
(script-fu-use-v3)
|
||||
(let* (
|
||||
(width (* radius 3.75))
|
||||
(height (* radius 2.5))
|
||||
(img (car (gimp-image-new width height RGB)))
|
||||
(drawable (car (gimp-layer-new img width height RGB-IMAGE
|
||||
"Sphere Layer" 100 LAYER-MODE-NORMAL)))
|
||||
(img (gimp-image-new width height RGB)) ; v3 >>> elide car
|
||||
(drawable (gimp-layer-new img width height RGB-IMAGE
|
||||
"Sphere Layer" 100 LAYER-MODE-NORMAL))
|
||||
(radians (/ (* light *pi*) 180))
|
||||
(cx (/ width 2))
|
||||
(cy (/ height 2))
|
||||
|
@ -73,7 +79,8 @@
|
|||
(if (and
|
||||
(or (and (>= light 45) (<= light 75))
|
||||
(and (<= light 135) (>= light 105)))
|
||||
(= shadow TRUE))
|
||||
; v3 >>> conditional doesn't need (= shadow TRUE)
|
||||
shadow )
|
||||
(let ((shadow-w (* (* radius 2.5) (cos (+ *pi* radians))))
|
||||
(shadow-h (* radius 0.5))
|
||||
(shadow-x cx)
|
||||
|
@ -82,21 +89,21 @@
|
|||
(begin (set! shadow-x (+ cx shadow-w))
|
||||
(set! shadow-w (- shadow-w))))
|
||||
|
||||
(gimp-context-set-feather TRUE)
|
||||
(gimp-context-set-feather #t)
|
||||
(gimp-context-set-feather-radius 7.5 7.5)
|
||||
(gimp-image-select-ellipse img CHANNEL-OP-REPLACE shadow-x shadow-y shadow-w shadow-h)
|
||||
(gimp-context-set-pattern pattern)
|
||||
(gimp-drawable-edit-fill drawable FILL-PATTERN)))
|
||||
|
||||
(gimp-context-set-feather FALSE)
|
||||
(gimp-context-set-feather #f) ; v3 >>> FALSE => #f
|
||||
(gimp-image-select-ellipse img CHANNEL-OP-REPLACE (- cx radius) (- cy radius)
|
||||
(* 2 radius) (* 2 radius))
|
||||
|
||||
(gimp-context-set-gradient-fg-bg-rgb)
|
||||
(gimp-drawable-edit-gradient-fill drawable
|
||||
GRADIENT-RADIAL offset
|
||||
FALSE 1 1
|
||||
TRUE
|
||||
#f 1 1 ; v3 >>> and also supersampling enum starts at 1 now
|
||||
#t
|
||||
light-x light-y
|
||||
light-end-x light-end-y)
|
||||
|
||||
|
@ -108,20 +115,21 @@
|
|||
(gimp-context-set-gradient-reverse gradient-reverse)
|
||||
(gimp-drawable-edit-gradient-fill drawable
|
||||
GRADIENT-LINEAR offset
|
||||
FALSE 1 1
|
||||
TRUE
|
||||
#f 1 1
|
||||
#t
|
||||
10 10
|
||||
30 60)
|
||||
|
||||
(gimp-selection-none img)
|
||||
|
||||
(gimp-context-set-foreground '(0 0 0))
|
||||
(gimp-floating-sel-anchor (car (gimp-text-font img drawable
|
||||
(gimp-floating-sel-anchor (gimp-text-font
|
||||
img drawable
|
||||
x-position y-position
|
||||
multi-text
|
||||
0 TRUE
|
||||
0 #t
|
||||
size
|
||||
font)))
|
||||
font))
|
||||
|
||||
(if (= orientation 1)
|
||||
(gimp-image-rotate img ROTATE-DEGREES90))
|
||||
|
@ -147,7 +155,7 @@
|
|||
SF-ONE-OR-MORE-DRAWABLE ; v3 >>> additional argument
|
||||
SF-ADJUSTMENT "Radius (in pixels)" (list 100 1 5000 1 10 0 SF-SPINNER)
|
||||
SF-ADJUSTMENT "Lighting (degrees)" (list 45 0 360 1 10 1 SF-SLIDER)
|
||||
SF-TOGGLE "Shadow" TRUE
|
||||
SF-TOGGLE "Shadow" #t ; v3 >>>
|
||||
SF-COLOR "Background color" "white"
|
||||
SF-COLOR "Sphere color" "red"
|
||||
; v3 >>> only declare name of default brush
|
||||
|
@ -156,7 +164,7 @@
|
|||
SF-TEXT "Multi-line text" "Hello,\nWorld!"
|
||||
SF-PATTERN "Pattern" "Maple Leaves"
|
||||
SF-GRADIENT "Gradient" "Deep Sea"
|
||||
SF-TOGGLE "Gradient reverse" FALSE
|
||||
SF-TOGGLE "Gradient reverse" #f ; v3 >>>
|
||||
SF-FONT "Font" "Agate"
|
||||
SF-ADJUSTMENT "Font size (pixels)" '(50 1 1000 1 10 0 1)
|
||||
SF-PALETTE "Palette" "Default"
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
; Old style script testing v3 binding of return values from PDB
|
||||
|
||||
; Modified from clothify.scm
|
||||
; 1. Calls (script-fu-use-v3) very early
|
||||
; 2. Uses v3 binding for PDB returns, i.e. elides many (car ()) from original
|
||||
|
||||
; Expect:
|
||||
; this works
|
||||
; after this plugin is invoked, all other /scripts still work, when invoked by menu item
|
||||
|
||||
; !!! You can't do this at top level, it affects all scripts in extension-script-fu
|
||||
; (script-fu-use-v3)
|
||||
|
||||
(define (script-fu-testv3 timg tdrawable bx by azimuth elevation depth)
|
||||
(script-fu-use-v3)
|
||||
(let* (
|
||||
(width (gimp-drawable-get-width tdrawable))
|
||||
(height (gimp-drawable-get-height tdrawable))
|
||||
(img (gimp-image-new width height RGB))
|
||||
; (layer-two (gimp-layer-new img width height RGB-IMAGE "Y Dots" 100 LAYER-MODE-MULTIPLY))
|
||||
(layer-one (gimp-layer-new img width height RGB-IMAGE "X Dots" 100 LAYER-MODE-NORMAL))
|
||||
(layer-two 0)
|
||||
(bump-layer 0)
|
||||
)
|
||||
|
||||
(gimp-context-push)
|
||||
(gimp-context-set-defaults)
|
||||
|
||||
(gimp-image-undo-disable img)
|
||||
|
||||
(gimp-image-insert-layer img layer-one 0 0)
|
||||
|
||||
(gimp-context-set-background '(255 255 255))
|
||||
(gimp-drawable-edit-fill layer-one FILL-BACKGROUND)
|
||||
|
||||
(plug-in-noisify RUN-NONINTERACTIVE img layer-one FALSE 0.7 0.7 0.7 0.7)
|
||||
|
||||
(set! layer-two (gimp-layer-copy layer-one 0))
|
||||
(gimp-layer-set-mode layer-two LAYER-MODE-MULTIPLY)
|
||||
(gimp-image-insert-layer img layer-two 0 0)
|
||||
|
||||
(plug-in-gauss-rle RUN-NONINTERACTIVE img layer-one bx TRUE FALSE)
|
||||
(plug-in-gauss-rle RUN-NONINTERACTIVE img layer-two by FALSE TRUE)
|
||||
(gimp-image-flatten img)
|
||||
; Note the inner call returns (<numeric length> <vector>)
|
||||
; We still need cadr even in v3 language
|
||||
(set! bump-layer (aref (cadr (gimp-image-get-selected-layers img)) 0))
|
||||
|
||||
(plug-in-c-astretch RUN-NONINTERACTIVE img bump-layer)
|
||||
(plug-in-noisify RUN-NONINTERACTIVE img bump-layer FALSE 0.2 0.2 0.2 0.2)
|
||||
|
||||
(plug-in-bump-map RUN-NONINTERACTIVE img tdrawable bump-layer azimuth elevation depth 0 0 0 0 FALSE FALSE 0)
|
||||
(gimp-image-delete img)
|
||||
(gimp-displays-flush)
|
||||
|
||||
(gimp-context-pop)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
(script-fu-register "script-fu-testv3"
|
||||
_"Test script-fu-use-v3..."
|
||||
_"Test use of script-fu-use-v3 in old scripts"
|
||||
"lloyd konneker"
|
||||
""
|
||||
"2023"
|
||||
"RGB* GRAY*"
|
||||
SF-IMAGE "Input image" 0
|
||||
SF-DRAWABLE "Input drawable" 0
|
||||
SF-ADJUSTMENT _"Blur X" '(9 3 100 1 10 0 1)
|
||||
SF-ADJUSTMENT _"Blur Y" '(9 3 100 1 10 0 1)
|
||||
SF-ADJUSTMENT _"Azimuth" '(135 0 360 1 10 1 0)
|
||||
SF-ADJUSTMENT _"Elevation" '(45 0 90 1 10 1 0)
|
||||
SF-ADJUSTMENT _"Depth" '(3 1 50 1 10 0 1)
|
||||
)
|
||||
|
||||
(script-fu-menu-register "script-fu-testv3"
|
||||
"<Image>/Filters/Development/Script-Fu/Test")
|
Loading…
Reference in New Issue