ScriptFu: Add script-fu-interpreter akin to other interpreters
Why: 1) users can install .scm scripts to plug-ins dir 2) Crashing scripts do not crash extension-script-fu Scripts (.scm files) have a shebang and are executable and in a same-named subdir of plugin dir. Interpreter/scripts create PDB procs of type PLUGIN unlike extension-script-fu which creates PDB procs of type TEMPORARY, owned by extension-script-fu. Unlike other interpreters, the interpreter is-a plugin outright, not by virtue of the script subclassing GimpPlugin and using GI. More details in /plug-ins/script-fu/interpreter/README
This commit is contained in:
parent
a0ba969450
commit
d5a83429b4
35 changed files with 1473 additions and 74 deletions
|
|
@ -25,7 +25,7 @@
|
|||
;Install script for GIMP and GTK+
|
||||
;requires Inno Setup 6
|
||||
;
|
||||
;See directories.isi
|
||||
;See directories.isi
|
||||
;
|
||||
;Changelog:
|
||||
;
|
||||
|
|
@ -751,7 +751,7 @@ begin
|
|||
begin
|
||||
|
||||
DebugMsg('DoConfigOverride', 'First call');
|
||||
|
||||
|
||||
Result := False;
|
||||
ConfigOverride := coDontOverride;
|
||||
|
||||
|
|
@ -819,7 +819,7 @@ begin
|
|||
'/usr/bin/python=' + ExpandConstant('{app}\bin\{#PYTHON}') + #10 +
|
||||
'/usr/bin/python3=' + ExpandConstant('{app}\bin\{#PYTHON}') + #10 +
|
||||
':Python:E::py::python:'#10;
|
||||
|
||||
|
||||
if not SaveStringToUTF8File(InterpFile,InterpContent,False) then
|
||||
begin
|
||||
DebugMsg('PrepareInterp','Problem writing the file. [' + InterpContent + ']');
|
||||
|
|
@ -840,7 +840,7 @@ begin
|
|||
'/usr/bin/luajit=' + ExpandConstant('{app}\bin\luajit.exe') + #10 +
|
||||
'/usr/bin/lua=' + ExpandConstant('{app}\bin\luajit.exe') + #10 +
|
||||
':Lua:E::lua::luajit:'#10;
|
||||
|
||||
|
||||
if not SaveStringToUTF8File(InterpFile,InterpContent,False) then
|
||||
begin
|
||||
DebugMsg('PrepareInterp','Problem writing the file. [' + InterpContent + ']');
|
||||
|
|
@ -848,13 +848,32 @@ begin
|
|||
end;
|
||||
end;
|
||||
#endif
|
||||
|
||||
// not optional
|
||||
// !!! use comma for binfmt delimiter and full Windows path in interpreter field of binfmt
|
||||
begin
|
||||
InterpFile := ExpandConstant('{app}\lib\gimp\{#DIR_VER}\interpreters\gimp-script-fu-interpreter.interp');
|
||||
DebugMsg('PrepareInterp','Writing interpreter file for gimp-script-fu-interpreter: ' + InterpFile);
|
||||
|
||||
InterpContent := 'gimp-script-fu-interpreter=' + ExpandConstant('{app}\bin\gimp-script-fu-interpreter-3.0.exe') + #10 +
|
||||
'gimp-script-fu-interpreter-3.0=' + ExpandConstant('{app}\bin\gimp-script-fu-interpreter-3.0.exe') + #10 +
|
||||
'/usr/bin/gimp-script-fu-interpreter=' + ExpandConstant('{app}\bin\gimp-script-fu-interpreter-3.0.exe') + #10 +
|
||||
',ScriptFu,E,,scm,,' + ExpandConstant('{app}\bin\gimp-script-fu-interpreter-3.0.exe') + ','#10;
|
||||
|
||||
if not SaveStringToUTF8File(InterpFile,InterpContent,False) then
|
||||
begin
|
||||
DebugMsg('PrepareInterp','Problem writing the file. [' + InterpContent + ']');
|
||||
SuppressibleMsgBox(CustomMessage('ErrorUpdatingScriptFu') + ' (2)',mbInformation,mb_ok,IDOK);
|
||||
end;
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
|
||||
procedure PrepareGimpEnvironment();
|
||||
var EnvFile,Env: String;
|
||||
begin
|
||||
|
||||
|
||||
StatusLabel(CustomMessage('SettingUpEnvironment'),'');
|
||||
|
||||
//set PATH to be used by plug-ins
|
||||
|
|
@ -862,7 +881,7 @@ begin
|
|||
DebugMsg('PrepareGimpEnvironment','Setting environment in ' + EnvFile);
|
||||
|
||||
Env := #10'PATH=${gimp_installation_dir}\bin';
|
||||
|
||||
|
||||
if IsComponentSelected('gimp32on64') then
|
||||
begin
|
||||
|
||||
|
|
@ -941,7 +960,7 @@ procedure CustomizeOnClick(Sender: TObject);
|
|||
begin
|
||||
DebugMsg('Install mode','Custom');
|
||||
InstallMode := imCustom;
|
||||
|
||||
|
||||
CleanUpCustomWelcome();
|
||||
|
||||
WizardForm.NextButton.OnClick(TNewButton(Sender).Parent);
|
||||
|
|
@ -1044,9 +1063,9 @@ begin
|
|||
else
|
||||
exit;
|
||||
DebugMsg('SelectComponentsFaceLift','2');
|
||||
|
||||
|
||||
WizardForm.ComponentsList.OnClick := @ComponentsListOnClick;
|
||||
|
||||
|
||||
lblDescription := TNewStaticText.Create(WizardForm.ComponentsList.Parent)
|
||||
with lblDescription do
|
||||
begin
|
||||
|
|
@ -1055,7 +1074,7 @@ begin
|
|||
AutoSize := True;
|
||||
Caption := CustomMessage('ComponentsDescription');
|
||||
end;
|
||||
|
||||
|
||||
pnlDescription := TPanel.Create(WizardForm.ComponentsList.Parent);
|
||||
with pnlDescription do
|
||||
begin
|
||||
|
|
@ -1069,7 +1088,7 @@ begin
|
|||
end;
|
||||
|
||||
lblDescription.Parent := WizardForm.ComponentsList.Parent; //place lblDescription above pnlDescription
|
||||
|
||||
|
||||
lblComponentDescription := TNewStaticText.Create(pnlDescription);
|
||||
with lblComponentDescription do
|
||||
begin
|
||||
|
|
@ -1081,7 +1100,7 @@ begin
|
|||
Height := Parent.Height - ScaleY(20);
|
||||
Top := ScaleY(12);
|
||||
end;
|
||||
|
||||
|
||||
end;
|
||||
|
||||
|
||||
|
|
@ -1090,7 +1109,7 @@ var rtfNewReadyMemo: TRichEditViewer;
|
|||
begin
|
||||
DebugMsg('ReadyFaceLift','');
|
||||
WizardForm.ReadyMemo.Visible := False;
|
||||
|
||||
|
||||
rtfNewReadyMemo := TRichEditViewer.Create(WizardForm.ReadyMemo.Parent);
|
||||
with rtfNewReadyMemo do
|
||||
begin
|
||||
|
|
@ -1214,7 +1233,7 @@ begin
|
|||
|
||||
Components := ['Gimp','Deps','Debug','Translations','MyPaint','Python','Ghostscript','Lua','Gimp32'];
|
||||
ComponentDesc := '';
|
||||
|
||||
|
||||
for i := 0 to TNewCheckListBox(pSender).Items.Count - 1 do
|
||||
if TNewCheckListBox(pSender).Selected[i] then
|
||||
begin
|
||||
|
|
@ -1277,7 +1296,7 @@ var sText: String;
|
|||
begin
|
||||
DebugMsg('UpdateReadyMemo','');
|
||||
(* Prepare the text for new Ready Memo *)
|
||||
|
||||
|
||||
sText := RTFHeader;
|
||||
if pMemoDirInfo <> '' then
|
||||
sText := sText + ParseReadyMemoText(pSpace,pMemoDirInfo) + '\sb100';
|
||||
|
|
@ -1286,7 +1305,7 @@ begin
|
|||
|
||||
If pMemoTasksInfo<>'' then
|
||||
sText := sText + '\sb100' + ParseReadyMemoText(pSpace,pMemoTasksInfo);
|
||||
|
||||
|
||||
ReadyMemoRichText := Copy(sText,1,Length(sText)-6) + '}';
|
||||
|
||||
Result := 'If you see this, something went wrong';
|
||||
|
|
@ -1299,7 +1318,7 @@ var NewBitmap1,NewBitmap2: TFileStream;
|
|||
begin
|
||||
WelcomeBitmapBottom := TBitmapImage.Create(WizardForm);
|
||||
with WelcomeBitmapBottom do
|
||||
begin
|
||||
begin
|
||||
Left := 0;
|
||||
Top := 0;
|
||||
Parent := WizardForm;
|
||||
|
|
@ -1309,7 +1328,7 @@ begin
|
|||
end;
|
||||
|
||||
DebugMsg('UpdateWizardImages','Height: ' + IntToStr(WizardForm.WizardBitmapImage.Height));
|
||||
|
||||
|
||||
if WizardForm.WizardBitmapImage.Height < 386 then //use smaller image when not using Large Fonts
|
||||
begin
|
||||
try
|
||||
|
|
@ -1375,7 +1394,7 @@ begin
|
|||
DebugMsg('DoUninstall','Install directory doesn'#39't exist: ' + InstallDir + ', resuming install');
|
||||
oResult := InResult
|
||||
end else
|
||||
begin
|
||||
begin
|
||||
oResult := rogUninstallFailed;
|
||||
end;
|
||||
|
||||
|
|
@ -1472,7 +1491,7 @@ begin
|
|||
UninstallString := UninstallString + ' /NORESTART';
|
||||
|
||||
DoUninstall(UninstallString, OldPath, lblInfo2, Result);
|
||||
|
||||
|
||||
end;
|
||||
|
||||
end;
|
||||
|
|
@ -1509,7 +1528,7 @@ begin
|
|||
end;
|
||||
|
||||
|
||||
procedure CurPageChanged(pCurPageID: Integer);
|
||||
procedure CurPageChanged(pCurPageID: Integer);
|
||||
begin
|
||||
DebugMsg('CurPageChanged','ID: '+IntToStr(pCurPageID));
|
||||
case pCurPageID of
|
||||
|
|
@ -1678,15 +1697,15 @@ begin
|
|||
SetArrayLength(Buttons,2);
|
||||
Message[0] := CustomMessage('Require32BPP');
|
||||
Buttons[0] := CustomMessage('Require32BPPContinue');
|
||||
Buttons[1] := CustomMessage('Require32BPPExit');
|
||||
if (not WizardSilent) and
|
||||
Buttons[1] := CustomMessage('Require32BPPExit');
|
||||
if (not WizardSilent) and
|
||||
(MessageWithURL(Message, CustomMessage('Require32BPPTitle'), Buttons, mbError, 2, 2) = 2) then
|
||||
Result := False
|
||||
else
|
||||
Result := True;
|
||||
end
|
||||
else
|
||||
Result := True;
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
|
||||
|
|
@ -1733,7 +1752,7 @@ begin
|
|||
Result := RestartSetupAfterReboot(); //resume install after reboot - skip all setting pages, and install directly
|
||||
|
||||
if Result then
|
||||
Result := BPPTooLowWarning();
|
||||
Result := BPPTooLowWarning();
|
||||
|
||||
if not Result then //no need to do anything else
|
||||
exit;
|
||||
|
|
@ -1743,7 +1762,7 @@ begin
|
|||
SetArrayLength(Buttons,2);
|
||||
Buttons[0] := CustomMessage('DevelopmentButtonContinue');
|
||||
Buttons[1] := CustomMessage('DevelopmentButtonExit');
|
||||
if (not WizardSilent) and
|
||||
if (not WizardSilent) and
|
||||
(MessageWithURL(Message, CustomMessage('DevelopmentWarningTitle'), Buttons, mbError, 2, 2) = 2) then
|
||||
begin
|
||||
Result := False;
|
||||
|
|
@ -1810,4 +1829,3 @@ end;
|
|||
#include "uninst.isi"
|
||||
|
||||
#expr SaveToFile(AddBackslash(SourcePath) + "Preprocessed.iss")
|
||||
|
||||
|
|
|
|||
|
|
@ -3106,6 +3106,7 @@ plug-ins/script-fu/libscriptfu/Makefile
|
|||
plug-ins/script-fu/libscriptfu/ftx/Makefile
|
||||
plug-ins/script-fu/libscriptfu/tinyscheme/Makefile
|
||||
plug-ins/script-fu/server/Makefile
|
||||
plug-ins/script-fu/interpreter/Makefile
|
||||
plug-ins/script-fu/scripts/Makefile
|
||||
plug-ins/script-fu/scripts/images/Makefile
|
||||
plug-ins/selection-to-path/Makefile
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ AM_LDFLAGS = \
|
|||
$(framework_cocoa) \
|
||||
$(xnone)
|
||||
|
||||
SUBDIRS = libscriptfu scripts server
|
||||
SUBDIRS = libscriptfu scripts server interpreter
|
||||
|
||||
# Each plugin must be installed in a dir of the same name as the executable
|
||||
script_fudir = $(gimpplugindir)/plug-ins/script-fu
|
||||
|
|
|
|||
6
plug-ins/script-fu/interpreter/.gitignore
vendored
Normal file
6
plug-ins/script-fu/interpreter/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/Makefile.in
|
||||
/Makefile
|
||||
/.deps
|
||||
/_libs
|
||||
/.libs
|
||||
/script-fu-interpreter.exe
|
||||
102
plug-ins/script-fu/interpreter/Makefile.am
Normal file
102
plug-ins/script-fu/interpreter/Makefile.am
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
# derived from app/Makefile.am, another installed binary
|
||||
|
||||
if PLATFORM_OSX
|
||||
xobjective_c = "-xobjective-c"
|
||||
xobjective_cxx = "-xobjective-c++"
|
||||
xnone = "-xnone"
|
||||
framework_cocoa = -framework Cocoa
|
||||
endif
|
||||
|
||||
if OS_WIN32
|
||||
win32_ldflags = -mwindows -Wl,--tsaware $(WIN32_LARGE_ADDRESS_AWARE)
|
||||
|
||||
if HAVE_EXCHNDL
|
||||
exchndl = -lexchndl
|
||||
endif
|
||||
|
||||
else
|
||||
libm = -lm
|
||||
endif
|
||||
|
||||
if ENABLE_RELOCATABLE_RESOURCES
|
||||
munix = -Wl,-rpath '-Wl,$$ORIGIN/../lib'
|
||||
endif
|
||||
|
||||
if HAVE_WINDRES
|
||||
include $(top_srcdir)/build/windows/gimprc-plug-ins.rule
|
||||
script_fu_interpreter_RC = script-fu-interpreter.rc.o
|
||||
endif
|
||||
|
||||
libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
|
||||
libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
|
||||
libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
|
||||
libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
|
||||
libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
|
||||
libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la
|
||||
libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la $(libm)
|
||||
|
||||
# link to libscriptfu
|
||||
libgimp_scriptfu = $(top_builddir)/plug-ins/script-fu/libscriptfu/libgimp-scriptfu-$(GIMP_API_VERSION).la
|
||||
|
||||
# include srcdir parent to find libscriptfu include files
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
$(GTK_CFLAGS) \
|
||||
$(GEGL_CFLAGS) \
|
||||
-I$(includedir) \
|
||||
-I$(srcdir)/.. \
|
||||
-DG_LOG_DOMAIN=\"scriptfu\"
|
||||
|
||||
AM_CFLAGS = \
|
||||
$(xobjective_c)
|
||||
|
||||
AM_CXXFLAGS = \
|
||||
$(xobjective_cxx)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
$(munix) \
|
||||
$(win32_ldflags) \
|
||||
$(framework_cocoa) \
|
||||
$(xnone)
|
||||
|
||||
# interpreter is-a plugin but is-a bin_PROGRAM
|
||||
# i.e. installs to usual place of executables e.g. /usr/bin so shebangs find it.
|
||||
bin_PROGRAMS = gimp-script-fu-interpreter-@GIMP_API_VERSION@
|
||||
|
||||
gimp_script_fu_interpreter_@GIMP_API_VERSION@_SOURCES = \
|
||||
script-fu-interpreter.c \
|
||||
script-fu-interpreter.h \
|
||||
script-fu-interpreter-plugin.c
|
||||
|
||||
# link with libgimp-scriptfu
|
||||
# link with the usual gimp suspects
|
||||
|
||||
gimp_script_fu_interpreter_@GIMP_API_VERSION@_LDADD = \
|
||||
$(libgimp_scriptfu) \
|
||||
$(libgimpmath) \
|
||||
$(libgimp) \
|
||||
$(libgimpbase) \
|
||||
$(libgimpui) \
|
||||
$(libgimpwidgets) \
|
||||
$(libgimpconfig) \
|
||||
$(libgimpcolor) \
|
||||
$(GTK_LIBS) \
|
||||
$(GTK_MAC_INTEGRATION_LIBS) \
|
||||
$(RT_LIBS) \
|
||||
$(INTLLIBS) \
|
||||
$(exchndl) \
|
||||
$(script_fu_interpreter_RC)
|
||||
|
||||
install-exec-hook:
|
||||
if DEFAULT_BINARY
|
||||
cd $(DESTDIR)$(bindir) \
|
||||
&& rm -f gimp-script-fu-interpreter$(EXEEXT) \
|
||||
&& $(LN_S) gimp-script-fu-interpreter-$(GIMP_APP_VERSION)$(EXEEXT) gimp-script-fu-interpreter$(EXEEXT)
|
||||
endif
|
||||
|
||||
uninstall-local:
|
||||
if DEFAULT_BINARY
|
||||
rm -f $(DESTDIR)$(bindir)/gimp-script-fu-interpreter$(EXEEXT)
|
||||
endif
|
||||
178
plug-ins/script-fu/interpreter/README
Normal file
178
plug-ins/script-fu/interpreter/README
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
# About script-fu-interpreter
|
||||
|
||||
It is GIMP's Scheme interpreter akin to any other language interpreter,
|
||||
rather than a GIMP extension as is the plugin extension-script-fu.
|
||||
This interpreter (like all the ScriptFu plugins) embeds a TinyScheme interpreter.
|
||||
|
||||
It is an executable program that is passed the name of a .scm file.
|
||||
The combination defines one or more PDB procedures of type PLUGIN.
|
||||
|
||||
Differences from extension-script-fu
|
||||
====================================
|
||||
|
||||
Since gimp-script-fu-interpreter and extension-script-fu use the same
|
||||
embedded interpreter (they both wrap TinyScheme)
|
||||
there is no difference in the language interpreted.
|
||||
Any differences are in the larger behavior of plugins.
|
||||
|
||||
### PDB Procedure type
|
||||
|
||||
Defines PDB procedure(s) of type PLUGIN.
|
||||
Unlike for the scriptfu extension,
|
||||
where a .scm file defines PDB procedure(s) of type TEMPORARY
|
||||
(owned by the PDB procedure of type PLUGIN named extension-script-fu)
|
||||
|
||||
### Protocol
|
||||
|
||||
Uses protocol to GIMP like other interpreters e.g. Python
|
||||
(query, create, and run phases.)
|
||||
The protocol to GIMP is unlike the protocol to the GIMP extension extension-script-fu.
|
||||
|
||||
(Note that "extension" has many meanings. It can denote: a protocol,
|
||||
or "suffix of a filename", or "a resource that extends GIMP."
|
||||
extension-script-fu is "a resource that extends GIMP" and it also uses
|
||||
the "extension" protocol,
|
||||
while gimp-script-fu-interpreter is a "a resource that extends GIMP" but uses
|
||||
the "plugin" protocol.)
|
||||
|
||||
### Process lifetimes
|
||||
|
||||
Executed many times, for many phases,
|
||||
unlike extension-script-fu which stays executing and gets a remote procedure call
|
||||
from GIMP to run a PDB procedure.
|
||||
|
||||
### Process concurrency
|
||||
|
||||
Each invocation of a plugin is in a separate process.
|
||||
One plugin process crash does not affect others.
|
||||
Unlike extension-script-fu, where a crash means the GIMP app must be restarted
|
||||
to restart extension-script-fu.
|
||||
|
||||
### GUI concurrency
|
||||
|
||||
Each plugin can have its own GUI visible concurrently
|
||||
with the GUI of other ScriptFu plugins.
|
||||
|
||||
For extension-script-fu, an open dialog
|
||||
prevents other plugins in /scripts (implemented by extension-script-fu)
|
||||
from opening a dialog.
|
||||
Instead extension-script-fu opens such dialogs sequentially.
|
||||
|
||||
This difference is not very important,
|
||||
since most users work sequentially.
|
||||
Most dialogs for plugins do not do anything substantive
|
||||
until a user closes the dialog with the OK button.
|
||||
|
||||
### Calls between scripts
|
||||
|
||||
In extension-script-fu, a call to another PDB procedure
|
||||
implemented by TEMPORARY procedure owned by extension-script-fu
|
||||
does not leave the process.
|
||||
|
||||
In gimp-script-fu-interpreter, a call to another PDB procedure
|
||||
implemented in another plugin file starts another process.
|
||||
|
||||
For other plugins, most calls to another PDB procedure starts another process.
|
||||
The exception is when one plugin file implements many PDB procedures.
|
||||
One common case is when one plugin file implements its own TEMPORARY PDB procedures that
|
||||
exist only for the duration of the plugin's lifetime.
|
||||
|
||||
Naming
|
||||
======
|
||||
|
||||
script-fu-interpreter is the informal name.
|
||||
|
||||
Source is located in /plug-ins/script-fu/interpreter
|
||||
|
||||
Filename of the executable is gimp-script-fu-interpreter-3.0.
|
||||
The name is versioned by a number corresponding to the API
|
||||
and the major version of GIMP (when script-fu-interpreter was introduced).
|
||||
We expect plugin authors to be insulated from changes to script-fu-interpreter,
|
||||
for the duration of the GIMP 3 version.
|
||||
|
||||
|
||||
About .scm scripts for script-fu-interpreter
|
||||
============================================
|
||||
|
||||
The contents of a .scm file queried by script-fu-interpreter
|
||||
are the same as those handled by extension-script-fu
|
||||
except for the addition of a shebang:
|
||||
|
||||
#!/usr/bin/env gimp-script-fu-interpreter-3.0
|
||||
(define (script-fu-test img drawable)
|
||||
...
|
||||
(script-fu-register "script-fu-test"
|
||||
...
|
||||
|
||||
### Query of scripts
|
||||
|
||||
As for other interpreters, a plugin script file must have certain attributes
|
||||
to be queried by GIMP. But a queried file may define many PDB procedures.
|
||||
|
||||
A .scm file queried by script-fu-interpreter:
|
||||
|
||||
- must have permission to execute.
|
||||
- must be in a directory names the same as the file's base name (less suffix.)
|
||||
|
||||
A directory containing an .scm file queried by script-fu-interpreter
|
||||
is usually a subdirectory of one of the /plug-ins directories,
|
||||
unlike for extension-script-fu, where the .scm files are in a /scripts dir.
|
||||
|
||||
A plugin directory should contain only one queriable .scm file:
|
||||
only one file can have the same base name as the directory and
|
||||
GIMP will query that file.
|
||||
|
||||
### Defining many PDB procedures per directory
|
||||
|
||||
When GIMP queries, script-fu-interpreter will load *ALL* the .scm files
|
||||
in the same directory (regardless of shebang or execute permission.)
|
||||
Any of the .scm files can declare and register a PDB procedure.
|
||||
Any single .scm file can declare and register many PDB procedures.
|
||||
|
||||
Similarly, when GIMP runs a named PDB procedure defined in an .scm file,
|
||||
script-fu-interpreter will actually load *ALL* the .scm files
|
||||
in the same directory, but run only the define run function so named.
|
||||
|
||||
A plugin directory that contains many .scm files having a shebang
|
||||
will also work, since only one can be named the same as the parent directory,
|
||||
and GIMP will only query it,
|
||||
but find the other .scm files with a shebang.
|
||||
|
||||
### Requery of scripts
|
||||
|
||||
As with other plugins, GIMP caches plugin definitions between sessions.
|
||||
GIMP queries plugin files at startup.
|
||||
GIMP will not requery any plugin files which have not changed since cached.
|
||||
GIMP will not query a plugin file that is added to the file system
|
||||
until GIMP is restarted.
|
||||
(Filters>Development>ScriptFu>Refresh Scripts will not requery script files
|
||||
handled by gimp-script-fu-interpreter, only those handled by extension-script-fu.)
|
||||
|
||||
### Errors during query
|
||||
|
||||
Most errors occurring during query appear only in the console.
|
||||
If you are a plugin author, you should start GIMP in a console
|
||||
so you can see such errors.
|
||||
|
||||
A script may be malformed because it does not define
|
||||
a "run" function having the same name as the PDB procedure name declared
|
||||
in the call to script-fu-register().
|
||||
Formerly, such a malformed script was successfully queried but
|
||||
the script would throw a "undefined variable" error at run time.
|
||||
Now, such a malformed script is not queried successfully,
|
||||
but throws a warning to the console:
|
||||
"Run function not defined, or does not match PDB procedure name:"
|
||||
|
||||
|
||||
|
||||
Test scripts
|
||||
============
|
||||
|
||||
Small test scripts for gimp-script-fu-interpreter
|
||||
are located in /plug-ins/script-fu/scripts/test
|
||||
|
||||
The script ts-helloworld.scm,
|
||||
formerly installed in /scripts and handled by extension-script-fu,
|
||||
is now installed in /plug-ins/ts-helloworld/ts-helloworld.scm
|
||||
and is now handled by gimp-script-fu-interpreter.
|
||||
It appears as "Filters>Development>Script-Fu>Test>Hello World..."
|
||||
42
plug-ins/script-fu/interpreter/meson.build
Normal file
42
plug-ins/script-fu/interpreter/meson.build
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
scriptfuInclude = include_directories('..')
|
||||
|
||||
executable_name = 'gimp-script-fu-interpreter-' + gimp_api_version
|
||||
|
||||
plugin_sources = [
|
||||
'script-fu-interpreter.c',
|
||||
'script-fu-interpreter-plugin.c',
|
||||
]
|
||||
|
||||
if platform_windows
|
||||
plugin_sources += windows.compile_resources(
|
||||
plugin_rc,
|
||||
args: [
|
||||
'--define', 'ORIGINALFILENAME_STR="@0@"'.format(executable_name+'.exe'),
|
||||
'--define', 'INTERNALNAME_STR="@0@"' .format(executable_name),
|
||||
'--define', 'TOP_SRCDIR="@0@"' .format(meson.source_root()),
|
||||
],
|
||||
include_directories: [
|
||||
rootInclude, appInclude,
|
||||
],
|
||||
)
|
||||
endif
|
||||
|
||||
# !!! Installs as a usual binary say to /usr/bin, unlike extension-script-fu
|
||||
# GIMP queries scripts with shebangs, which invokes gimp-script-fu-interpreter-3.0.
|
||||
|
||||
executable(executable_name,
|
||||
plugin_sources,
|
||||
dependencies: [
|
||||
libgimpui_dep,
|
||||
math,
|
||||
],
|
||||
c_args: [
|
||||
'-DG_LOG_DOMAIN="scriptfu"',
|
||||
],
|
||||
include_directories: [
|
||||
scriptfuInclude,
|
||||
],
|
||||
link_with : libscriptfu,
|
||||
install: true,
|
||||
)
|
||||
140
plug-ins/script-fu/interpreter/script-fu-interpreter-plugin.c
Normal file
140
plug-ins/script-fu/interpreter/script-fu-interpreter-plugin.c
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/* 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/>.
|
||||
*/
|
||||
|
||||
/* This file understands how to make a GimpPlugin of the interpreter.
|
||||
* This is mostly boilerplate for any plugin.
|
||||
* It understands little about ScriptFu internals,
|
||||
* hidden by script-fu-interpreter.[ch] and libscriptfu.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <glib.h>
|
||||
#include <libgimp/gimp.h>
|
||||
|
||||
#include "libscriptfu/script-fu-intl.h"
|
||||
|
||||
#include "script-fu-interpreter.h"
|
||||
|
||||
|
||||
/* ScriptFuInterpreter subclasses GimpPlugIn */
|
||||
|
||||
#define SCRIPT_FU_INTERPRETER_TYPE (script_fu_interpreter_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (ScriptFuInterpreter, script_fu_interpreter, SCRIPT, FU_INTERPRETER, GimpPlugIn)
|
||||
|
||||
struct _ScriptFuInterpreter
|
||||
{
|
||||
GimpPlugIn parent_instance;
|
||||
};
|
||||
|
||||
static GList * script_fu_interpreter_query_procedures (GimpPlugIn *plug_in);
|
||||
static GimpProcedure * script_fu_interpreter_create_procedure (GimpPlugIn *plug_in,
|
||||
const gchar *name);
|
||||
|
||||
G_DEFINE_TYPE (ScriptFuInterpreter, script_fu_interpreter, GIMP_TYPE_PLUG_IN)
|
||||
|
||||
/* An alias to argv[1], which is the path to the .scm file.
|
||||
* Each instance of ScriptFuInterpreter is specialized by the script passed in argv[1]
|
||||
* This var need not belong to the class or to an instance,
|
||||
* because there will only be one instance of ScriptFuInterpreter per plugin process.
|
||||
*/
|
||||
static gchar * path_to_this_script;
|
||||
|
||||
/* Connect to Gimp. See libgimp/gimp.c.
|
||||
*
|
||||
* Can't use GIMP_MAIN macro, it doesn't omit argv[0].
|
||||
*
|
||||
* First arg is app cited in the shebang.
|
||||
* Second arg is the .scm file containing the shebang.
|
||||
* Second to last arg is the "phase" e.g. -query or -run
|
||||
* Last arg is the mode for crash dumps.
|
||||
* Typical argv:
|
||||
* gimp-script-fu-interpreter-3.0 ~/.config/GIMP/2.99/plug-ins/fu/fu
|
||||
* -gimp 270 12 11 -query 1
|
||||
*/
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
g_debug ("Enter script-fu-interpreter main");
|
||||
|
||||
/* Alias path to this plugin's script file. */
|
||||
path_to_this_script = argv[1];
|
||||
|
||||
/* gimp_main will create an instance of the class given by the first arg, a GType.
|
||||
* The class is a subclass of GimpPlugIn (with overridden query and create methods.)
|
||||
* GIMP will subsequently callback the query or create methods,
|
||||
* or the run_func of the PDB procedure of the plugin,
|
||||
* depending on the "phase" arg in argv,
|
||||
* which is set by the gimp plugin manager, which is invoking this interpreter.
|
||||
*/
|
||||
/* Omit argv[0] when passing to gimp */
|
||||
gimp_main (SCRIPT_FU_INTERPRETER_TYPE, argc-1, &argv[1] );
|
||||
|
||||
g_debug ("Exit script-fu-interpreter.");
|
||||
}
|
||||
|
||||
DEFINE_STD_SET_I18N
|
||||
|
||||
static void
|
||||
script_fu_interpreter_class_init (ScriptFuInterpreterClass *klass)
|
||||
{
|
||||
GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
|
||||
|
||||
plug_in_class->query_procedures = script_fu_interpreter_query_procedures;
|
||||
plug_in_class->create_procedure = script_fu_interpreter_create_procedure;
|
||||
plug_in_class->set_i18n = STD_SET_I18N;
|
||||
}
|
||||
|
||||
|
||||
/* called by the GType system to initialize instance of the class. */
|
||||
static void
|
||||
script_fu_interpreter_init (ScriptFuInterpreter *script_fu)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
|
||||
/* Return the names of PDB procedures implemented. A callback from GIMP. */
|
||||
static GList *
|
||||
script_fu_interpreter_query_procedures (GimpPlugIn *plug_in)
|
||||
{
|
||||
GList *result = NULL;
|
||||
|
||||
g_debug ("queried");
|
||||
|
||||
result = script_fu_interpreter_list_defined_proc_names (plug_in, path_to_this_script);
|
||||
if (g_list_length (result) < 1)
|
||||
g_warning ("No procedures defined in %s", path_to_this_script);
|
||||
|
||||
/* Caller is GIMP and it will free the list. */
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Create and return a GimpPDBProcedure,
|
||||
* for the named one of the PDB procedures that the script implements.
|
||||
* A callback from GIMP.
|
||||
*
|
||||
* Also set attributes on the procedure, most importantly, menu items (optional.)
|
||||
* Also create any menus/submenus that the script defines e.g. Filters>My
|
||||
*/
|
||||
static GimpProcedure *
|
||||
script_fu_interpreter_create_procedure (GimpPlugIn *plug_in,
|
||||
const gchar *proc_name)
|
||||
{
|
||||
return script_fu_interpreter_create_proc_at_path (plug_in,
|
||||
proc_name,
|
||||
path_to_this_script);
|
||||
}
|
||||
192
plug-ins/script-fu/interpreter/script-fu-interpreter.c
Normal file
192
plug-ins/script-fu/interpreter/script-fu-interpreter.c
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
/* 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 <glib.h>
|
||||
#include <libgimp/gimp.h>
|
||||
|
||||
#include "libscriptfu/script-fu-lib.h"
|
||||
|
||||
#include "script-fu-interpreter.h"
|
||||
|
||||
/* Implementation of the outer ScriptFuInterpreter.
|
||||
* This understands ScriptFu internals
|
||||
* i.e. uses libscriptfu shared with other ScriptFu plugins e.g. extension-script-fu.
|
||||
*/
|
||||
|
||||
/* We don't need to load (into the interpreter) any .scm files handled by extension-script-fu.
|
||||
* Namely, the .scm in the GIMP installation /scripts or in the user local /scripts dirs.
|
||||
*
|
||||
* During startup, GIMP might call gimp-script-fu-interpreter
|
||||
* to query new files such as /plug-ins/fu/fu.scm.
|
||||
* This is before extension-script-fu starts.
|
||||
* But all the .scm files handled by extension-script-fu are type TEMPORARY and not needed
|
||||
* for a /plug-ins/fu.scm to be queried.
|
||||
* The only Scheme executed during query are calls to script-fu-register.
|
||||
* Later, when a /plug-ins/fu.scm is run, it can call temporary PDB procedures
|
||||
* that extension-script-fu provides.
|
||||
*
|
||||
* When we call script_fu_init_embedded_interpreter(),
|
||||
* the passed paths should include the path to /scripts
|
||||
* because that is the location of scripts for initialization and compatibility
|
||||
* (script-fu.init, plug-in-compat.init and script-fu-compat.init,
|
||||
* which are really scheme files.)
|
||||
*
|
||||
* scrip-fu-interpreter always inits embedded interpreter(allow_register=TRUE)
|
||||
* In the "run" phase, you don't need script-fu-register to be defined, but its harmless.
|
||||
*/
|
||||
|
||||
static GFile *script_fu_get_plugin_parent_path (const gchar *path_to_this_script);
|
||||
static void script_fu_free_path_list (GList **list);
|
||||
|
||||
|
||||
/* Return a list of PDB procedure names defined in all .scm files in
|
||||
* the parent dir of the given path, which is a filename of the one being queried.
|
||||
*
|
||||
* Each .scm file may contain many calls to script-fu-register, which defines a PDB procedure.
|
||||
* All .scm files in the parent dir are searched.
|
||||
*
|
||||
* This executable is named script-fu-interpreter
|
||||
* but no PDB procedure is named "script-fu-interpreter".
|
||||
* Instead, the interpreter registers PDB procs named from name strings
|
||||
* give in the in script-fu-register() calls in the interpreted scripts.
|
||||
*
|
||||
* Caller must free the list.
|
||||
*/
|
||||
GList *
|
||||
script_fu_interpreter_list_defined_proc_names (GimpPlugIn *plug_in,
|
||||
const gchar *path_to_this_script)
|
||||
{
|
||||
GList *name_list = NULL; /* list of strings */
|
||||
GList *path_list = NULL; /* list of GFile */
|
||||
|
||||
/* path_list is /scripts dir etc. from which we will load compat and init scripts.
|
||||
* second argument TRUE means define script-fu-register into the interpreter.
|
||||
*/
|
||||
path_list = script_fu_search_path ();
|
||||
script_fu_init_embedded_interpreter (path_list, TRUE, GIMP_RUN_NONINTERACTIVE);
|
||||
script_fu_free_path_list (&path_list);
|
||||
|
||||
/* Reuse path_list, now a list of one path, the parent dir of the queried script. */
|
||||
path_list = g_list_append (path_list,
|
||||
script_fu_get_plugin_parent_path (path_to_this_script));
|
||||
name_list = script_fu_find_scripts_list_proc_names (plug_in, path_list);
|
||||
script_fu_free_path_list (&path_list);
|
||||
|
||||
/* Usually name_list is not NULL i.e. not empty.
|
||||
* But an .scm file that is not an actual GIMP plugin, or broken, may yield empty list.
|
||||
*/
|
||||
return name_list;
|
||||
}
|
||||
|
||||
|
||||
/* Create a PDB proc of type PLUGIN with the given name.
|
||||
* Unlike extension-script-fu, create proc of type PLUGIN.
|
||||
*
|
||||
* We are in "create procedure" phase of call from GIMP.
|
||||
* Create a PDB procedure that the script-fu-interpreter wraps.
|
||||
*
|
||||
* A GimpPDBProcedure has a run function, here script_fu_script_proc()
|
||||
* of this outer interpreter.
|
||||
* Sometime after the create, GIMP calls the run func, passing a name aka command.
|
||||
* In ScriptFu, the same name is used for the PDB proc and the Scheme function
|
||||
* which is the inner run func defined in the script.
|
||||
* script_fu_script_proc calls the TinyScheme interpreter to evaluate
|
||||
* the inner run func in the script.
|
||||
*/
|
||||
GimpProcedure *
|
||||
script_fu_interpreter_create_proc_at_path (GimpPlugIn *plug_in,
|
||||
const gchar *proc_name,
|
||||
const gchar *path_to_this_script
|
||||
)
|
||||
{
|
||||
GimpProcedure *procedure = NULL;
|
||||
GList *path_list = NULL; /* list of GFile */
|
||||
|
||||
g_debug ("script_fu_interpreter_create_proc_at_path, name: %s", proc_name);
|
||||
|
||||
/* Require proc_name is a suitable name for a PDB procedure eg "script-fu-test".
|
||||
* (Not tested for canonical name "script-fu-<something>")
|
||||
* Require proc_name is a name that was queried earlier.
|
||||
* Require the proc_name was defined in some .scm file
|
||||
* in the same directory as the .scm file passed as argv[0].
|
||||
* The name of the .scm file eg "/plug-ins/fu/fu.scm"
|
||||
* can be entirely different from proc_name.
|
||||
*
|
||||
* Otherwise, we simply won't find the proc_name defined in any .scm file,
|
||||
* and will fail gracefully, returning NULL.
|
||||
*/
|
||||
|
||||
path_list = script_fu_search_path ();
|
||||
path_list = g_list_append (path_list,
|
||||
script_fu_get_plugin_parent_path (path_to_this_script));
|
||||
/* path_list are the /scripts dir, for .init and compat.scm, plus the path to this.
|
||||
* second arg TRUE means define script-fu-register so it is effective.
|
||||
*/
|
||||
script_fu_init_embedded_interpreter (path_list, TRUE, GIMP_RUN_NONINTERACTIVE);
|
||||
|
||||
/* Reuse path_list, now a list of only the path to this script. */
|
||||
script_fu_free_path_list (&path_list);
|
||||
path_list = g_list_append (path_list,
|
||||
script_fu_get_plugin_parent_path (path_to_this_script));
|
||||
|
||||
procedure = script_fu_find_scripts_create_PDB_proc_plugin (plug_in, path_list, proc_name);
|
||||
script_fu_free_path_list (&path_list);
|
||||
|
||||
/* When procedure is not NULL, assert:
|
||||
* some .scm was evaluated.
|
||||
* the script defined many PDB procedures locally, i.e. in script-tree
|
||||
* we created a single PDB procedure (but not put it in the GIMP PDB)
|
||||
*
|
||||
* Ensure procedure is-a GimpProcedure or NULL.
|
||||
* GIMP is the caller and will put non-NULL procedure in the PDB.
|
||||
*/
|
||||
return procedure;
|
||||
}
|
||||
|
||||
|
||||
/* Return GFile of the parent directory of this plugin, whose filename is given.
|
||||
*
|
||||
* Caller must free the GFile.
|
||||
*/
|
||||
static GFile *
|
||||
script_fu_get_plugin_parent_path (const gchar *path_to_this_script)
|
||||
{
|
||||
GFile *path = NULL;
|
||||
GFile *parent_path = NULL;
|
||||
|
||||
/* A libgimp GimpPlugin does not know its path,
|
||||
* but its path was passed in argv to this interpreter.
|
||||
* The path is to a file being queried e.g. "~/.config/GIMP/2.99/plug-ins/fu/fu.scm"
|
||||
*/
|
||||
g_debug ("path to this plugin %s", path_to_this_script);
|
||||
path = g_file_new_for_path (path_to_this_script);
|
||||
parent_path = g_file_get_parent (path);
|
||||
g_object_unref (path);
|
||||
return parent_path;
|
||||
}
|
||||
|
||||
/* Free a list of paths at the given handle.
|
||||
* Ensures that the pointer to the list is NULL, prevents "dangling."
|
||||
* g_list_free_full alone does not do that.
|
||||
*/
|
||||
static void
|
||||
script_fu_free_path_list (GList **list)
|
||||
{
|
||||
/* !!! g_steal_pointer takes a handle. */
|
||||
g_list_free_full (g_steal_pointer (list), g_object_unref);
|
||||
}
|
||||
29
plug-ins/script-fu/interpreter/script-fu-interpreter.h
Normal file
29
plug-ins/script-fu/interpreter/script-fu-interpreter.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* 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_INTERPRETER_H__
|
||||
#define __SCRIPT_FU_INTERPRETER_H__
|
||||
|
||||
GList *script_fu_interpreter_list_defined_proc_names (
|
||||
GimpPlugIn *plug_in,
|
||||
const gchar *path_to_this_plugin);
|
||||
GimpProcedure *script_fu_interpreter_create_proc_at_path (
|
||||
GimpPlugIn *plug_in,
|
||||
const gchar *proc_name,
|
||||
const gchar *path_to_this_script);
|
||||
|
||||
#endif /* __SCRIPT_FU_INTERPRETER_H__ */
|
||||
|
|
@ -119,7 +119,9 @@ libgimp_scriptfu_@GIMP_API_VERSION@_la_SOURCES = \
|
|||
scheme-wrapper.c \
|
||||
scheme-wrapper.h \
|
||||
script-fu-lib.c \
|
||||
script-fu-lib.h
|
||||
script-fu-lib.h \
|
||||
script-fu-proc-factory.h \
|
||||
script-fu-proc-factory.c
|
||||
|
||||
EXTRA_libgimp_scriptfu_@GIMP_API_VERSION@_la_DEPENDENCIES = $(scriptfu_def)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ libscriptfu_sources = [
|
|||
'script-fu-errors.c',
|
||||
'script-fu-compat.c',
|
||||
'script-fu-lib.c',
|
||||
'script-fu-proc-factory.c',
|
||||
]
|
||||
|
||||
# !! just "library(...)" which means shared versus static depends on configuration of project.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <libgimp/gimp.h>
|
||||
/* FIXME script-fu-types.h refers to GtkAdjustment. */
|
||||
/* FIXME We only need gimpui because script-fu-types.h refers to GtkAdjustment. */
|
||||
#include <libgimp/gimpui.h>
|
||||
|
||||
#include "script-fu-lib.h"
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
#include "scheme-wrapper.h" /* tinyscheme_init etc, */
|
||||
#include "script-fu-scripts.h" /* script_fu_find_scripts */
|
||||
#include "script-fu-interface.h" /* script_fu_interface_is_active */
|
||||
#include "script-fu-proc-factory.h"
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -67,13 +68,43 @@ script_fu_find_and_register_scripts ( GimpPlugIn *plugin,
|
|||
script_fu_find_scripts (plugin, paths);
|
||||
}
|
||||
|
||||
/*
|
||||
* Init the embedded interpreter.
|
||||
*
|
||||
* allow_register:
|
||||
* TRUE: allow loaded scripts to register PDB procedures.
|
||||
* The scheme functions script-fu-register and script-fu-menu-register are
|
||||
* defined to do something.
|
||||
* FALSE: The scheme functions script-fu-register and script-fu-menu-register are
|
||||
* defined but do nothing.
|
||||
*
|
||||
* Note that the embedded interpreter always defines scheme functions
|
||||
* for all PDB procedures already existing when the interpreter starts
|
||||
* (currently bound at startup, but its possible to lazy bind.)
|
||||
* allow_register doesn't affect that.
|
||||
*/
|
||||
void
|
||||
script_fu_init_embedded_interpreter ( GList *paths,
|
||||
gboolean allow_register,
|
||||
GimpRunMode run_mode)
|
||||
{
|
||||
g_debug ("script_fu_init_embedded_interpreter");
|
||||
tinyscheme_init (paths, allow_register);
|
||||
ts_set_run_mode (run_mode);
|
||||
/*
|
||||
* Ensure the embedded interpreter is running
|
||||
* and has loaded its internal Scheme scripts
|
||||
* and has defined existing PDB procs as Scheme foreign functions
|
||||
* (is ready to interpret PDB-like function calls in scheme scripts.)
|
||||
*
|
||||
* scripts/...init and scripts/...compat.scm are loaded
|
||||
* iff paths includes the "/scripts" dir.
|
||||
*
|
||||
* The .scm file(s) for plugins are loaded
|
||||
* iff paths includes their parent directory (e.g. /scripts)
|
||||
* Loaded does not imply yet registered in the PDB
|
||||
* (yet, they soon might be for some phases of the plugin.)
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -155,7 +186,6 @@ script_fu_search_path (void)
|
|||
GList *path = NULL;
|
||||
|
||||
path_str = gimp_gimprc_query ("script-fu-path");
|
||||
|
||||
if (path_str)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
|
@ -170,6 +200,23 @@ script_fu_search_path (void)
|
|||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
GimpProcedure *
|
||||
script_fu_find_scripts_create_PDB_proc_plugin (GimpPlugIn *plug_in,
|
||||
GList *paths,
|
||||
const gchar *name)
|
||||
{
|
||||
/* Delegate to factory. */
|
||||
return script_fu_proc_factory_make_PLUGIN (plug_in, paths, name);
|
||||
}
|
||||
|
||||
GList *
|
||||
script_fu_find_scripts_list_proc_names (GimpPlugIn *plug_in,
|
||||
GList *paths)
|
||||
{
|
||||
/* Delegate to factory. */
|
||||
return script_fu_proc_factory_list_names (plug_in, paths);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,4 +42,10 @@ void script_fu_run_read_eval_print_loop (void);
|
|||
void script_fu_register_quit_callback (void (*func) (void));
|
||||
void script_fu_register_post_command_callback (void (*func) (void));
|
||||
|
||||
GimpProcedure *script_fu_find_scripts_create_PDB_proc_plugin (GimpPlugIn *plug_in,
|
||||
GList *paths,
|
||||
const gchar *name);
|
||||
GList *script_fu_find_scripts_list_proc_names (GimpPlugIn *plug_in,
|
||||
GList *paths);
|
||||
|
||||
#endif /* __SCRIPT_FU_LIB_H__ */
|
||||
|
|
|
|||
205
plug-ins/script-fu/libscriptfu/script-fu-proc-factory.c
Normal file
205
plug-ins/script-fu/libscriptfu/script-fu-proc-factory.c
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/* 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 <glib.h>
|
||||
#include <libgimp/gimp.h>
|
||||
#include <libgimp/gimpui.h>
|
||||
|
||||
#include "tinyscheme/scheme-private.h"
|
||||
#include "script-fu-types.h"
|
||||
#include "script-fu-scripts.h"
|
||||
#include "script-fu-script.h"
|
||||
|
||||
#include "script-fu-proc-factory.h"
|
||||
|
||||
/* Local functions */
|
||||
static void script_fu_add_menu_to_procedure (GimpProcedure *procedure,
|
||||
SFScript *script);
|
||||
|
||||
|
||||
/* Methods to register PDB procs. A factory makes objects, here PDB procedures.
|
||||
*
|
||||
* Used by the outer script-fu-interpreter
|
||||
*
|
||||
* This is in libscriptfu to hide the SFScript type from outer plugins.
|
||||
* These methods use instances of type SFScript as specs for procedures.
|
||||
*
|
||||
* FUTURE: migrate code.
|
||||
* There are two flavors of factory-like code: for PDBProcType TEMPORARY and PLUGIN.
|
||||
* extension-script-fu outer plugin only makes TEMPORARY
|
||||
* script-fu-interpreter outer plugin only makes PLUGIN type
|
||||
* This source file supports only script-fu-interpreter.
|
||||
* script_fu_find_scripts() in script-fu-scripts.c is also a factory-like method,
|
||||
* and could be extracted to a separate source file.
|
||||
* Maybe more code sharing between the two flavors.
|
||||
*/
|
||||
|
||||
|
||||
/* Create and return a single PDB procedure of type PLUGIN,
|
||||
* for the given proc name, by reading the script file in the given paths.
|
||||
* Also add a menu for the procedure.
|
||||
*
|
||||
* PDB proc of type PLUGIN has permanent lifetime, unlike type TEMPORARY.
|
||||
*
|
||||
* The list of paths is usually just one directory, a subdir of /plug-ins.
|
||||
* The directory may contain many .scm files.
|
||||
* The plugin manager only queries one .scm file,
|
||||
* having the same name as its parent dir and and having execute permission.
|
||||
* But here we read all the .scm files in the directory.
|
||||
* Each .scm file may register (and define run func for) many PDB procedures.
|
||||
*
|
||||
* Here, one name is passed, and though we load all the .scm files,
|
||||
* we only create a PDB procedure for the passed name.
|
||||
*/
|
||||
GimpProcedure *
|
||||
script_fu_proc_factory_make_PLUGIN (GimpPlugIn *plug_in,
|
||||
GList *paths,
|
||||
const gchar *proc_name)
|
||||
{
|
||||
SFScript * script = NULL;
|
||||
GimpProcedure * procedure = NULL;
|
||||
|
||||
/* Reads all .scm files at paths, even though only one is pertinent.
|
||||
* The returned script_tree is also in the state of the interpreter,
|
||||
* we don't need the result here.
|
||||
*/
|
||||
(void) script_fu_find_scripts_into_tree (plug_in, paths);
|
||||
|
||||
/* Get the pertinent script from the tree. */
|
||||
script = script_fu_find_script (proc_name);
|
||||
|
||||
if (script)
|
||||
{
|
||||
procedure = script_fu_script_create_PDB_procedure (
|
||||
plug_in,
|
||||
script,
|
||||
script_fu_script_proc, /* run_func */
|
||||
GIMP_PDB_PROC_TYPE_PLUGIN);
|
||||
script_fu_add_menu_to_procedure (procedure, script);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Failed to find script: %s.", proc_name);
|
||||
}
|
||||
return procedure;
|
||||
}
|
||||
|
||||
/* Traverse the list of scripts, for each defined name of a PDB proc,
|
||||
* add it list whose handle is given.
|
||||
*
|
||||
* Order is not important. Could just as well prepend.
|
||||
*
|
||||
* This is a GTraverseFunction
|
||||
*/
|
||||
static gboolean
|
||||
script_fu_append_script_names (gpointer *foo G_GNUC_UNUSED,
|
||||
GList *scripts,
|
||||
GList **name_list)
|
||||
{
|
||||
for (GList * list = scripts; list; list = g_list_next (list))
|
||||
{
|
||||
SFScript *script = list->data;
|
||||
|
||||
if ( !script_fu_is_defined (script->name))
|
||||
{
|
||||
g_warning ("Run function not defined, or does not match PDB procedure name: %s",
|
||||
script->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Must assign result from g_list_append back to name_list */
|
||||
*name_list = g_list_append ( (GList *) *name_list, g_strdup (script->name));
|
||||
}
|
||||
return FALSE; /* We traversed all. */
|
||||
}
|
||||
|
||||
/* Load script texts (.scm files) in the given paths.
|
||||
* Iterate over all loaded scripts to get the PDB proc names they define.
|
||||
* Return a list of the names.
|
||||
*/
|
||||
GList *
|
||||
script_fu_proc_factory_list_names (GimpPlugIn *plug_in,
|
||||
GList *paths)
|
||||
{
|
||||
GList * result_list = NULL;
|
||||
GTree * script_tree = NULL;
|
||||
|
||||
/* Load (eval) all .scm files in all dirs in paths. */
|
||||
script_tree = script_fu_find_scripts_into_tree (plug_in, paths);
|
||||
|
||||
/* Iterate over the tree, adding each script name to result list */
|
||||
g_tree_foreach (script_tree,
|
||||
(GTraverseFunc) script_fu_append_script_names,
|
||||
&result_list);
|
||||
|
||||
return result_list;
|
||||
}
|
||||
|
||||
/* From scriptfu's internal data, add any menu to given procedure in the PDB.
|
||||
* Requires that a script was just eval'ed so that scriptfu's list of menus
|
||||
* declared in a script is valid.
|
||||
* Requires the proc exists in PDB.
|
||||
*
|
||||
* Not ensure the PDB proc has a menu, when no menu was defined in the script.
|
||||
*
|
||||
* Derived from script_fu_install_menu, but that is specific to TEMPORARY procs.
|
||||
* Also, unlike script_fu_install_menu, we don't nuke the menu list as we proceed.
|
||||
*
|
||||
* For each "create" of a procedure, the gimp-script-fu-interpreter is started anew,
|
||||
* and a new script_menu_list is derived from the .scm file.
|
||||
* We don't traverse the menu list more than once per session, which soon exits.
|
||||
*/
|
||||
static void
|
||||
script_fu_add_menu_to_procedure (GimpProcedure *procedure,
|
||||
SFScript *script)
|
||||
{
|
||||
GList *menu_list;
|
||||
gboolean did_add_menu = FALSE;
|
||||
|
||||
menu_list = script_fu_get_menu_list ();
|
||||
/* menu_list might be NULL: for loop will have no iterations. */
|
||||
|
||||
/* Each .scm file can declare many menu paths.
|
||||
* Traverse the list to find the menu path defined for the procedure.
|
||||
* Each SFMenu points to the procedure (SFScript) it belongs to.
|
||||
*/
|
||||
for (GList * traverser = menu_list; traverser; traverser = g_list_next (traverser))
|
||||
{
|
||||
SFMenu *menu = traverser->data;
|
||||
if (menu->script == script)
|
||||
{
|
||||
g_debug ("Add menu: %s", menu->menu_path);
|
||||
gimp_procedure_add_menu_path (procedure, menu->menu_path);
|
||||
did_add_menu = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Some procedures don't have menu path.
|
||||
* It is normal, but not common, to define procs of type PLUGIN that don't appear in the menus.
|
||||
* No part of GIMP defaults a menu path for procedures.
|
||||
* A menu label without a menu path is probably a mistake by the script author.
|
||||
*/
|
||||
if ( ! did_add_menu )
|
||||
{
|
||||
/* Unusual for a .scm file to have no menu paths, but not an error. */
|
||||
g_debug ("No menu paths! Does the procedure name in script-fu-menu-register match?");
|
||||
/* FUTURE if the script defines a menu *label*, declare an error. */
|
||||
}
|
||||
/* script_menu_list is a reference we do not need to free. */
|
||||
}
|
||||
27
plug-ins/script-fu/libscriptfu/script-fu-proc-factory.h
Normal file
27
plug-ins/script-fu/libscriptfu/script-fu-proc-factory.h
Normal file
|
|
@ -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_PDB_PROC_FACTORY_H__
|
||||
#define __SCRIPT_FU_PDB_PROC_FACTORY_H__
|
||||
|
||||
GimpProcedure *script_fu_proc_factory_make_PLUGIN (GimpPlugIn *plug_in,
|
||||
GList *paths,
|
||||
const gchar *name);
|
||||
GList *script_fu_proc_factory_list_names (GimpPlugIn *plug_in,
|
||||
GList *paths);
|
||||
|
||||
#endif /* __SCRIPT_FU_PDB_PROC_FACTORY__ */
|
||||
|
|
@ -43,6 +43,8 @@ static gboolean script_fu_script_param_init (SFScript *script,
|
|||
gint n);
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Function definitions
|
||||
*/
|
||||
|
|
@ -165,26 +167,59 @@ script_fu_script_free (SFScript *script)
|
|||
g_slice_free (SFScript, script);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* From the script, create a temporary PDB procedure,
|
||||
* and install it as owned by the scriptfu extension PDB proc.
|
||||
*/
|
||||
void
|
||||
script_fu_script_install_proc (GimpPlugIn *plug_in,
|
||||
SFScript *script,
|
||||
GimpRunFunc run_func)
|
||||
{
|
||||
GimpProcedure *procedure;
|
||||
const gchar *menu_label = NULL;
|
||||
gint arg_count[SF_DISPLAY] = { 0, };
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
|
||||
g_return_if_fail (script != NULL);
|
||||
g_return_if_fail (run_func != NULL);
|
||||
|
||||
procedure = script_fu_script_create_PDB_procedure (plug_in,
|
||||
script,
|
||||
run_func,
|
||||
GIMP_PDB_PROC_TYPE_TEMPORARY);
|
||||
|
||||
gimp_plug_in_add_temp_procedure (plug_in, procedure);
|
||||
g_object_unref (procedure);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create and return a GimpProcedure.
|
||||
* Caller typically either:
|
||||
* install it owned by self as TEMPORARY type procedure
|
||||
* OR return it as the result of a create_procedure callback from GIMP (PLUGIN type procedure.)
|
||||
*
|
||||
* Caller must unref the procedure.
|
||||
*/
|
||||
GimpProcedure *
|
||||
script_fu_script_create_PDB_procedure (GimpPlugIn *plug_in,
|
||||
SFScript *script,
|
||||
GimpRunFunc run_func,
|
||||
GimpPDBProcType plug_in_type)
|
||||
{
|
||||
GimpProcedure *procedure;
|
||||
const gchar *menu_label = NULL;
|
||||
gint arg_count[SF_DISPLAY] = { 0, };
|
||||
gint i;
|
||||
|
||||
g_debug ("script_fu_script_create_PDB_procedure: %s of type %i", script->name, plug_in_type);
|
||||
|
||||
/* Allow scripts with no menus */
|
||||
if (strncmp (script->menu_label, "<None>", 6) != 0)
|
||||
menu_label = script->menu_label;
|
||||
|
||||
procedure = gimp_procedure_new (plug_in, script->name,
|
||||
GIMP_PDB_PROC_TYPE_TEMPORARY,
|
||||
plug_in_type,
|
||||
run_func, script, NULL);
|
||||
|
||||
gimp_procedure_set_image_types (procedure, script->image_types);
|
||||
|
|
@ -509,8 +544,7 @@ script_fu_script_install_proc (GimpPlugIn *plug_in,
|
|||
gimp_procedure_add_argument (procedure, pspec);
|
||||
}
|
||||
|
||||
gimp_plug_in_add_temp_procedure (plug_in, procedure);
|
||||
g_object_unref (procedure);
|
||||
return procedure;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -46,5 +46,11 @@ gchar * script_fu_script_get_command (SFScript *scrip
|
|||
gchar * script_fu_script_get_command_from_params (SFScript *script,
|
||||
const GimpValueArray *args);
|
||||
|
||||
GimpProcedure * script_fu_script_create_PDB_procedure (GimpPlugIn *plug_in,
|
||||
SFScript *script,
|
||||
GimpRunFunc run_func,
|
||||
GimpPDBProcType plug_in_type);
|
||||
|
||||
|
||||
|
||||
#endif /* __SCRIPT_FU_SCRIPT__ */
|
||||
|
|
|
|||
|
|
@ -43,13 +43,6 @@
|
|||
#include "script-fu-intl.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SFScript *script;
|
||||
gchar *menu_path;
|
||||
} SFMenu;
|
||||
|
||||
|
||||
/*
|
||||
* Local Functions
|
||||
*/
|
||||
|
|
@ -65,11 +58,6 @@ static void script_fu_install_menu (SFMenu *menu);
|
|||
static gboolean script_fu_remove_script (gpointer foo,
|
||||
GList *scripts,
|
||||
gpointer data);
|
||||
static GimpValueArray * script_fu_script_proc (GimpProcedure *procedure,
|
||||
const GimpValueArray *args,
|
||||
gpointer data);
|
||||
|
||||
static SFScript * script_fu_find_script (const gchar *name);
|
||||
|
||||
static gchar * script_fu_menu_map (const gchar *menu_path);
|
||||
static gint script_fu_menu_compare (gconstpointer a,
|
||||
|
|
@ -88,13 +76,25 @@ static GList *script_menu_list = NULL;
|
|||
* Function definitions
|
||||
*/
|
||||
|
||||
void
|
||||
script_fu_find_scripts (GimpPlugIn *plug_in,
|
||||
GList *path)
|
||||
/* Traverse list of paths, finding .scm files.
|
||||
* Load and eval any found script texts.
|
||||
* Script texts will call Scheme functions script-fu-register()
|
||||
* and script-fu-menu-register(),
|
||||
* which insert a SFScript record into script_tree,
|
||||
* and insert a SFMenu record into script_menu_list.
|
||||
* These are side effects on the state of the outer (SF) interpreter.
|
||||
*
|
||||
* Return the tree of scripts, as well as keeping a local pointer to the tree.
|
||||
* The other result (script_menu_list) is not returned, see script_fu_get_menu_list().
|
||||
*
|
||||
* Caller should free script_tree and script_menu_list,
|
||||
* This should only be called once.
|
||||
*/
|
||||
GTree *
|
||||
script_fu_find_scripts_into_tree ( GimpPlugIn *plug_in,
|
||||
GList *paths)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
/* Make sure to clear any existing scripts */
|
||||
/* Clear any existing scripts */
|
||||
if (script_tree != NULL)
|
||||
{
|
||||
g_tree_foreach (script_tree,
|
||||
|
|
@ -103,16 +103,46 @@ script_fu_find_scripts (GimpPlugIn *plug_in,
|
|||
g_tree_destroy (script_tree);
|
||||
}
|
||||
|
||||
if (! path)
|
||||
return;
|
||||
|
||||
script_tree = g_tree_new ((GCompareFunc) g_utf8_collate);
|
||||
|
||||
for (list = path; list; list = g_list_next (list))
|
||||
if (paths)
|
||||
{
|
||||
script_fu_load_directory (list->data);
|
||||
GList *list;
|
||||
|
||||
for (list = paths; list; list = g_list_next (list))
|
||||
{
|
||||
script_fu_load_directory (list->data);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Assert result is not NULL, but may be an empty tree.
|
||||
* When paths is NULL, or no scripts found at paths.
|
||||
*/
|
||||
|
||||
g_debug ("script_fu_find_scripts_into_tree found %i scripts", g_tree_nnodes (script_tree));
|
||||
return script_tree;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return list of SFMenu for recently loaded scripts.
|
||||
* List is non-empty only after a call to script_fu_find_scripts_into_tree().
|
||||
*/
|
||||
GList *
|
||||
script_fu_get_menu_list (void)
|
||||
{
|
||||
return script_menu_list;
|
||||
}
|
||||
|
||||
/* Find scripts, create and install TEMPORARY PDB procedures,
|
||||
* owned by self PDB procedure (e.g. extension-script-fu.)
|
||||
*/
|
||||
void
|
||||
script_fu_find_scripts (GimpPlugIn *plug_in,
|
||||
GList *path)
|
||||
{
|
||||
script_fu_find_scripts_into_tree (plug_in, path);
|
||||
|
||||
/* Now that all scripts are read in and sorted, tell gimp about them */
|
||||
g_tree_foreach (script_tree,
|
||||
(GTraverseFunc) script_fu_install_script,
|
||||
|
|
@ -571,12 +601,13 @@ script_fu_run_command (const gchar *command,
|
|||
GString *output;
|
||||
gboolean success = FALSE;
|
||||
|
||||
g_debug ("script_fu_run_command: %s", command);
|
||||
output = g_string_new (NULL);
|
||||
ts_register_output_func (ts_gstring_output_func, output);
|
||||
|
||||
if (ts_interpret_string (command))
|
||||
{
|
||||
g_set_error (error, 0, 0, "%s", output->str);
|
||||
g_set_error (error, GIMP_PLUG_IN_ERROR, 0, "%s", output->str);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -593,6 +624,8 @@ script_fu_load_directory (GFile *directory)
|
|||
{
|
||||
GFileEnumerator *enumerator;
|
||||
|
||||
g_debug ("Load dir: %s", g_file_get_parse_name (directory));
|
||||
|
||||
enumerator = g_file_enumerate_children (directory,
|
||||
G_FILE_ATTRIBUTE_STANDARD_NAME ","
|
||||
G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
|
||||
|
|
@ -665,8 +698,10 @@ script_fu_load_script (GFile *file)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following function is a GTraverseFunction.
|
||||
/* This is-a GTraverseFunction.
|
||||
*
|
||||
* Traverse. For each, install TEMPORARY PDB proc.
|
||||
* Returning FALSE means entire list was traversed.
|
||||
*/
|
||||
static gboolean
|
||||
script_fu_install_script (gpointer foo G_GNUC_UNUSED,
|
||||
|
|
@ -680,8 +715,12 @@ script_fu_install_script (gpointer foo G_GNUC_UNUSED,
|
|||
{
|
||||
SFScript *script = list->data;
|
||||
|
||||
script_fu_script_install_proc (plug_in, script,
|
||||
script_fu_script_proc);
|
||||
const gchar* name = script->name;
|
||||
if (script_fu_is_defined (name))
|
||||
script_fu_script_install_proc (plug_in, script,
|
||||
script_fu_script_proc);
|
||||
else
|
||||
g_warning ("Run function not defined, or does not match PDB procedure name: %s", name);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
|
@ -690,13 +729,14 @@ script_fu_install_script (gpointer foo G_GNUC_UNUSED,
|
|||
static void
|
||||
script_fu_install_menu (SFMenu *menu)
|
||||
{
|
||||
GimpPlugIn *plug_in = gimp_get_plug_in ();
|
||||
GimpProcedure *procedure;
|
||||
GimpPlugIn *plug_in = gimp_get_plug_in ();
|
||||
GimpProcedure *procedure = NULL;
|
||||
|
||||
procedure = gimp_plug_in_get_temp_procedure (plug_in,
|
||||
menu->script->name);
|
||||
|
||||
gimp_procedure_add_menu_path (procedure, menu->menu_path);
|
||||
if (procedure)
|
||||
gimp_procedure_add_menu_path (procedure, menu->menu_path);
|
||||
|
||||
g_free (menu->menu_path);
|
||||
g_slice_free (SFMenu, menu);
|
||||
|
|
@ -726,7 +766,15 @@ script_fu_remove_script (gpointer foo G_GNUC_UNUSED,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static GimpValueArray *
|
||||
/* This is the outer "run func" for this plugin.
|
||||
* When called, the name of the inner run func (code in Scheme language)
|
||||
* is the first element of the value array.
|
||||
* Form a command (text in Scheme language) that is a call to the the inner run func,
|
||||
* evaluate it, and return the result, marshalled into a GimpValueArray.
|
||||
*
|
||||
* In the name 'script_fu_script_proc', 'proc' is a verb meaning 'process the script'
|
||||
*/
|
||||
GimpValueArray *
|
||||
script_fu_script_proc (GimpProcedure *procedure,
|
||||
const GimpValueArray *args,
|
||||
gpointer data)
|
||||
|
|
@ -841,7 +889,7 @@ script_fu_lookup_script (gpointer *foo G_GNUC_UNUSED,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static SFScript *
|
||||
SFScript *
|
||||
script_fu_find_script (const gchar *name)
|
||||
{
|
||||
gconstpointer script = name;
|
||||
|
|
@ -916,3 +964,43 @@ script_fu_menu_compare (gconstpointer a,
|
|||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Is name a defined symbol in the interpreter state?
|
||||
* (Defined in any script already loaded.)
|
||||
* Where "symbol" has the usual lisp meaning: a unique name associated with
|
||||
* a variable or function.
|
||||
*
|
||||
* The most common use is
|
||||
* test the name of a PDB proc, which in ScriptFu must match
|
||||
* a defined function that is the inner run function.
|
||||
* I.E. check for typos by author of script.
|
||||
* Used during query, to preflight so that we don't install a PDB proc
|
||||
* that won't run later (during the run phase)
|
||||
* giving "undefined symbol" for extension-script-fu.
|
||||
* Note that if instead we create a PDB proc having no defined run func,
|
||||
* script-fu-interpreter would load and define a same-named scheme function
|
||||
* that calls the PDB, and can enter an infinite loop.
|
||||
*/
|
||||
gboolean
|
||||
script_fu_is_defined (const gchar * name)
|
||||
{
|
||||
gchar *scheme_text;
|
||||
GError *error = NULL;
|
||||
gboolean result;
|
||||
|
||||
/* text to be interpreted is a call to an internal scheme function. */
|
||||
scheme_text = g_strdup_printf (" (symbol? %s ) ", name);
|
||||
|
||||
/* Use script_fu_run_command, it correctly handles the string yielded.
|
||||
* But we don't need the string yielded.
|
||||
* If defined, string yielded is "#t", else is "Undefined symbol" or "#f"
|
||||
*/
|
||||
result = script_fu_run_command (scheme_text, &error);
|
||||
if (!result)
|
||||
{
|
||||
g_debug ("script_fu_is_defined returns false");
|
||||
/* error contains string yielded by interpretation. */
|
||||
g_error_free (error);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,5 +26,13 @@ pointer script_fu_add_script (scheme *sc,
|
|||
pointer script_fu_add_menu (scheme *sc,
|
||||
pointer a);
|
||||
|
||||
GTree * script_fu_find_scripts_into_tree (GimpPlugIn *plug_in,
|
||||
GList *path);
|
||||
SFScript * script_fu_find_script (const gchar *name);
|
||||
GList * script_fu_get_menu_list (void);
|
||||
GimpValueArray * script_fu_script_proc (GimpProcedure *procedure,
|
||||
const GimpValueArray *args,
|
||||
gpointer data);
|
||||
gboolean script_fu_is_defined (const gchar *name);
|
||||
|
||||
#endif /* __SCRIPT_FU_SCRIPTS__ */
|
||||
|
|
|
|||
|
|
@ -103,5 +103,10 @@ typedef struct
|
|||
SFArg *args;
|
||||
} SFScript;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SFScript *script; // script which defined this menu path and label
|
||||
gchar *menu_path;
|
||||
} SFMenu;
|
||||
|
||||
#endif /* __SCRIPT_FU_TYPES__ */
|
||||
|
|
|
|||
|
|
@ -13,3 +13,5 @@ EXPORTS
|
|||
script_fu_register_quit_callback
|
||||
script_fu_register_post_command_callback
|
||||
script_fu_search_path
|
||||
script_fu_find_scripts_create_PDB_proc_plugin
|
||||
script_fu_find_scripts_list_proc_names
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
subdir('libscriptfu')
|
||||
subdir('scripts')
|
||||
subdir('server')
|
||||
subdir('interpreter')
|
||||
|
||||
|
||||
executable_name = 'script-fu'
|
||||
|
|
|
|||
|
|
@ -59,9 +59,17 @@ scripts = \
|
|||
|
||||
test_scripts = \
|
||||
contactsheet.scm \
|
||||
test-sphere.scm \
|
||||
test-sphere.scm
|
||||
|
||||
# scripts interpreted by gimp-script-fu-interpreter
|
||||
# Each installs to a subdir of /plug-ins
|
||||
# Each should have a shebang and execute permission
|
||||
independent_scripts = \
|
||||
ts-helloworld.scm
|
||||
|
||||
ts_helloworlddir = $(gimpplugindir)/plug-ins/ts-helloworld
|
||||
ts_helloworld_SCRIPTS = ts-helloworld.scm
|
||||
|
||||
|
||||
scriptdata_DATA = $(scripts)
|
||||
|
||||
|
|
@ -69,4 +77,4 @@ if GIMP_UNSTABLE
|
|||
scriptdata_DATA += $(test_scripts)
|
||||
endif
|
||||
|
||||
EXTRA_DIST = $(scripts) $(test_scripts)
|
||||
EXTRA_DIST = $(scripts) $(test_scripts) $(independent_scripts)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
subdir('images')
|
||||
|
||||
# scripts interpreted by extension-script-fu, installed to /scripts
|
||||
scripts = [
|
||||
'add-bevel.scm',
|
||||
'addborder.scm',
|
||||
|
|
@ -58,7 +59,6 @@ if not stable
|
|||
scripts += [
|
||||
'contactsheet.scm',
|
||||
'test-sphere.scm',
|
||||
'ts-helloworld.scm',
|
||||
]
|
||||
endif
|
||||
|
||||
|
|
@ -66,3 +66,22 @@ install_data(
|
|||
scripts,
|
||||
install_dir: gimpdatadir / 'scripts',
|
||||
)
|
||||
|
||||
# scripts interpreted by gimp-script-fu-interpreter
|
||||
# Each installed in subdirectory of /plug-in
|
||||
# Each have a shebang and executable permission.
|
||||
# Like other interpreted plugins.
|
||||
# Lacking a shebang, a .interp file is needed to associate .scm suffix
|
||||
|
||||
scripts_independent = [
|
||||
{ 'name': 'ts-helloworld' },
|
||||
]
|
||||
|
||||
foreach plugin : scripts_independent
|
||||
name = plugin.get('name')
|
||||
srcs = plugin.get('srcs', name + '.scm')
|
||||
|
||||
install_data(srcs,
|
||||
install_dir: gimpplugindir / 'plug-ins' / name,
|
||||
install_mode: 'rwxr-xr-x')
|
||||
endforeach
|
||||
|
|
|
|||
5
plug-ins/script-fu/scripts/test/README
Normal file
5
plug-ins/script-fu/scripts/test/README
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Scripts to test script-fu-interpreter.
|
||||
|
||||
Not usually installed.
|
||||
|
||||
To use, copy the test<x> dirs into /plugins and ensure the .scm files have execute permission.
|
||||
31
plug-ins/script-fu/scripts/test/test0/test0.scm
Normal file
31
plug-ins/script-fu/scripts/test/test0/test0.scm
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env gimp-script-fu-interpreter-3.0
|
||||
|
||||
; Basic test of a .scm file interpreted by script-fu-interpreter
|
||||
;
|
||||
; Setup: copy this file w/ executable permission, and its parent dir to /plug-ins
|
||||
; Example: to ~/.gimp-2.99/plug-ins/test0/test0.scm
|
||||
; (That is custom to one user.)
|
||||
|
||||
; Expect "Test>Test SF interpreter 0" in the menus
|
||||
; Expect when chosen, message on GIMP message bar.
|
||||
|
||||
; Also, remove the execute permission.
|
||||
; Then expect not appear in GIMP menus (not queried.)
|
||||
|
||||
; Also, make the name different from its parent dir.
|
||||
; Then expect not appear in GIMP menus (not queried.)
|
||||
|
||||
(define (script-fu-test0)
|
||||
(gimp-message "Hello script-fu-test0")
|
||||
)
|
||||
|
||||
(script-fu-register "script-fu-test0"
|
||||
"Test SF interpreter 0"
|
||||
_"Just gives a message from Gimp"
|
||||
"lkk"
|
||||
"lkk"
|
||||
"2022"
|
||||
"" ; all image types
|
||||
)
|
||||
|
||||
(script-fu-menu-register "script-fu-test0" "<Image>/Test")
|
||||
43
plug-ins/script-fu/scripts/test/test1/test1.scm
Normal file
43
plug-ins/script-fu/scripts/test/test1/test1.scm
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env gimp-script-fu-interpreter-3.0
|
||||
|
||||
; Basic test that a second .scm file is also queried.
|
||||
; Expect "Test>Test SF interpreter 1" in the menus
|
||||
; Expect when chosen, message on GIMP message bar.
|
||||
|
||||
; Also tests that one .scm file can define two PDB procedures
|
||||
; File is queried once, yielding two names.
|
||||
; Two separate procedures created.
|
||||
|
||||
|
||||
(define (script-fu-test1)
|
||||
(gimp-message "Hello script-fu-test1")
|
||||
)
|
||||
|
||||
(script-fu-register "script-fu-test1"
|
||||
"Test SF interpreter 01"
|
||||
_"Just gives a message from Gimp"
|
||||
"lkk"
|
||||
"lkk"
|
||||
"2022"
|
||||
"" ; all image types
|
||||
)
|
||||
|
||||
(script-fu-menu-register "script-fu-test1" "<Image>/Test")
|
||||
|
||||
|
||||
|
||||
|
||||
(define (script-fu-test2)
|
||||
(gimp-message "Hello script-fu-test2")
|
||||
)
|
||||
|
||||
(script-fu-register "script-fu-test2"
|
||||
"Test SF interpreter 02"
|
||||
_"Just gives a message from Gimp"
|
||||
"lkk"
|
||||
"lkk"
|
||||
"2022"
|
||||
"" ; all image types
|
||||
)
|
||||
|
||||
(script-fu-menu-register "script-fu-test2" "<Image>/Test")
|
||||
31
plug-ins/script-fu/scripts/test/test1/test3.scm
Normal file
31
plug-ins/script-fu/scripts/test/test1/test3.scm
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
; !!! No shebang here
|
||||
|
||||
; Test a second .scm file in the same directory as a queried .scm.
|
||||
; The second .scm file need not be executable.
|
||||
; The second .scm file need not have a shebang.
|
||||
; The gimp-script-fu-interpreter will nevertheless load the second .scm
|
||||
; while it is querying the first, executable .scm in the dir.
|
||||
; The plugin manager queries the first executable,
|
||||
; and gimp-script-fu-interpreter loads (and returns defined names in)
|
||||
; the second during the query of the first.
|
||||
|
||||
; Expect "Test>Test SF interpreter 3" in the menus
|
||||
; Expect when chosen, message on GIMP message bar.
|
||||
|
||||
; plug-ins/test1/test1.scm is executable
|
||||
; plug-ins/test1/test3.scm is NOT executable
|
||||
|
||||
(define (script-fu-test3)
|
||||
(gimp-message "Hello script-fu-test3")
|
||||
)
|
||||
|
||||
(script-fu-register "script-fu-test3"
|
||||
"Test SF interpreter 3"
|
||||
_"Just gives a message from Gimp"
|
||||
"lkk"
|
||||
"lkk"
|
||||
"2022"
|
||||
"" ; all image types
|
||||
)
|
||||
|
||||
(script-fu-menu-register "script-fu-test3" "<Image>/Test")
|
||||
25
plug-ins/script-fu/scripts/test/test4/test4.scm
Normal file
25
plug-ins/script-fu/scripts/test/test4/test4.scm
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env gimp-script-fu-interpreter-3.0
|
||||
|
||||
; Test a .scm file that does not call script-fu-menu-register
|
||||
; The menu will NOT default.
|
||||
; Expect "Test SF interpreter 4" to NOT EXIST in any menu
|
||||
; Expect the PDB proc "script-fu-test4" does appear in the PDB Brower
|
||||
|
||||
; Two test cases:
|
||||
; Alongside an executable script: plug-ins/test4/test4.scm NOT executable
|
||||
; Executable, in its own directory: plug-ins/test1/test4.scm is executable
|
||||
|
||||
(define (script-fu-test4)
|
||||
(gimp-message "Hello script-fu-test4")
|
||||
)
|
||||
|
||||
(script-fu-register "script-fu-test4"
|
||||
"Test SF interpreter 4"
|
||||
_"Just gives a message from Gimp"
|
||||
"lkk"
|
||||
"lkk"
|
||||
"2022"
|
||||
"" ; all image types
|
||||
)
|
||||
|
||||
; !!! No call to script-fu-menu-register
|
||||
16
plug-ins/script-fu/scripts/test/test5/test5.scm
Normal file
16
plug-ins/script-fu/scripts/test/test5/test5.scm
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env gimp-script-fu-interpreter
|
||||
|
||||
; Test a .scm file with an invalid shebang
|
||||
; Note "-3.0" missing above.
|
||||
|
||||
; The test depends on platform and env and .interp
|
||||
; Must not be a file system link from gimp-script-fu-interpreter to gimp-script-fu-interpreter-3.0
|
||||
; Must not be a .interp file having "gimp-script-fu-interpreter=gimp-script-fu-interpreter-3.0"
|
||||
|
||||
; Expect in the console: "/usr/bin/env: 'script-fu-interpreter': No such file or directory"
|
||||
|
||||
(define (script-fu-test5)
|
||||
(gimp-message "Hello script-fu-test5")
|
||||
)
|
||||
|
||||
; !!! No call to script-fu-menu-register
|
||||
12
plug-ins/script-fu/scripts/test/test6/test6.scm
Normal file
12
plug-ins/script-fu/scripts/test/test6/test6.scm
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env gimp-script-fu-interpreter-3.0
|
||||
|
||||
; Test a .scm file that does not register any procedure
|
||||
|
||||
; Expect in the console:
|
||||
; "(test6.scm:164): scriptfu-WARNING **: 10:06:07.966: No procedures defined in /work/.home/.config/GIMP/2.99/plug-ins/test6/test6.scm"
|
||||
|
||||
(define (script-fu-test6)
|
||||
(gimp-message "Hello script-fu-test6")
|
||||
)
|
||||
|
||||
; !!! No call to script-fu-register
|
||||
28
plug-ins/script-fu/scripts/test/test7/test7.scm
Normal file
28
plug-ins/script-fu/scripts/test/test7/test7.scm
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env gimp-script-fu-interpreter-3.0
|
||||
|
||||
; Test non-canonical name for PDB procedure
|
||||
; gimp-script-fu-interpreter does not enforce canonical name.
|
||||
; Other parts of GIMP (PDB) does not enforce canonical name
|
||||
; for PDB procedures defined by .scm scripts.
|
||||
|
||||
; Canonical means starts with "script-fu-"
|
||||
; Here the name doesn't, its just "test7"
|
||||
|
||||
; Expect "Test>Test SF interpreter 7" in the menus
|
||||
; Expect when chosen, message on GIMP message bar.
|
||||
|
||||
|
||||
(define (test7)
|
||||
(gimp-message "Hello test7")
|
||||
)
|
||||
|
||||
(script-fu-register "test7"
|
||||
"Test SF interpreter 7"
|
||||
_"Just gives a message from Gimp"
|
||||
"lkk"
|
||||
"lkk"
|
||||
"2022"
|
||||
"" ; all image types
|
||||
)
|
||||
|
||||
(script-fu-menu-register "test7" "<Image>/Test")
|
||||
39
plug-ins/script-fu/scripts/test/test8/test8.scm
Normal file
39
plug-ins/script-fu/scripts/test/test8/test8.scm
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env gimp-script-fu-interpreter-3.0
|
||||
|
||||
; Test mismatch between name of defined run function and name for PDB procedure
|
||||
; Not a high priority: a rare syntax error in a plugin text.
|
||||
; If authors follow a template, they won't make this mistake.
|
||||
|
||||
; The names must match exactly.
|
||||
; Here, "mismatch" the name of the defined run function
|
||||
; does not match "script-fu-test8" the name of the PDB proc.
|
||||
|
||||
; Expect a warning in the text console as the plugin text is queried:
|
||||
; script-fu: WARNING: Run function not defined, or does not match PDB procedure name: script-fu-test8.
|
||||
; Expect the PDB procedure to not exist
|
||||
|
||||
; If we don't detect this syntax error:
|
||||
; A PDB procedure is created.
|
||||
; When invoked from Test>Test SF interpreter 8"
|
||||
; the interpreter enters an infinite loop.
|
||||
; There is no harm to the GIMP app, but the interpreter process can only be killed.
|
||||
; During the run phase, the "(define foo)"
|
||||
; should re-define an existing definition in the interpreter state.
|
||||
; Instead, since the name is mismatched,
|
||||
; the foo function remains defined to be a call to the PDB procedure named foo.
|
||||
; So script-fu-script-proc instead calls the PDB again, an infinite loop.
|
||||
|
||||
(define (mismatch)
|
||||
(gimp-message "mismatch")
|
||||
)
|
||||
|
||||
(script-fu-register "script-fu-test8"
|
||||
"Test SF interpreter 8"
|
||||
_"Just gives a message from Gimp"
|
||||
"lkk"
|
||||
"lkk"
|
||||
"2022"
|
||||
"" ; all image types
|
||||
)
|
||||
|
||||
(script-fu-menu-register "script-fu-test8" "<Image>/Test")
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
#!/usr/bin/env gimp-script-fu-interpreter-3.0
|
||||
|
||||
; "Hello, World" Test v1.00 February 29, 2004
|
||||
; by Kevin Cozens <kcozens@interlog.com>
|
||||
;
|
||||
|
|
|
|||
Loading…
Reference in a new issue