app, build, plug-ins: Run interpreters conditionally on Windows console

Closes: #12642

Now, we will check at runtime if GIMP is not on a console and
use the corresponding _win.interp file on such case only.
This commit is contained in:
Bruno Lopes 2025-11-09 12:29:10 -03:00
parent 40fcefad9c
commit 0c70a9fe00
No known key found for this signature in database
8 changed files with 111 additions and 30 deletions

View file

@ -38,6 +38,10 @@
#include "libgimpbase/gimpbase.h" #include "libgimpbase/gimpbase.h"
#ifdef G_OS_WIN32
#include <windows.h>
#endif
#include "plug-in-types.h" #include "plug-in-types.h"
#include "gimpinterpreterdb.h" #include "gimpinterpreterdb.h"
@ -121,11 +125,44 @@ gimp_interpreter_db_new (gboolean verbose)
return db; return db;
} }
#ifdef G_OS_WIN32
static gboolean
might_be_console_process (void)
{
/* check for Unix console */
if (g_getenv ("TERM") || g_getenv ("SHELL"))
return TRUE;
/* check for Windows console (taken from gspawn-win32.c) */
gboolean attached_to_self = AttachConsole (GetCurrentProcessId ());
g_return_val_if_fail (! attached_to_self, TRUE);
switch (GetLastError ())
{
case ERROR_ACCESS_DENIED:
return TRUE;
case ERROR_INVALID_HANDLE:
return FALSE;
}
g_return_val_if_reached (FALSE);
}
#endif
void void
gimp_interpreter_db_load (GimpInterpreterDB *db, gimp_interpreter_db_load (GimpInterpreterDB *db,
GList *path) GList *path)
{ {
GList *list; GList *list;
#ifdef G_OS_WIN32
static gboolean console_checked = FALSE;
static gboolean is_console = FALSE;
if (!console_checked)
{
is_console = might_be_console_process ();
console_checked = TRUE;
}
#endif
g_return_if_fail (GIMP_IS_INTERPRETER_DB (db)); g_return_if_fail (GIMP_IS_INTERPRETER_DB (db));
@ -168,8 +205,32 @@ gimp_interpreter_db_load (GimpInterpreterDB *db,
{ {
GFile *file = g_file_enumerator_get_child (enumerator, info); GFile *file = g_file_enumerator_get_child (enumerator, info);
gimp_interpreter_db_load_interp_file (db, file); gchar *basename = g_file_get_basename (file);
#ifndef G_OS_WIN32
/* Unix: always load regular .interp file */
if (! g_strrstr (basename, "_win"))
{
gimp_interpreter_db_load_interp_file (db, file);
}
#else
if (! g_strrstr (basename, "_win"))
{
/* Windows: only load regular .interp file if on console */
if (is_console)
{
gimp_interpreter_db_load_interp_file (db, file);
}
}
else
{
/* Windows: load special _win .interp file if not on console */
if (! is_console)
{
gimp_interpreter_db_load_interp_file (db, file);
}
}
#endif
g_free (basename);
g_object_unref (file); g_object_unref (file);
} }

View file

@ -157,11 +157,10 @@ if (os.getenv("GIMP_UNSTABLE") or not os.getenv("GIMP_RELEASE")) and "32" not in
bundle(GIMP_PREFIX, "lib/girepository-*/*.typelib") bundle(GIMP_PREFIX, "lib/girepository-*/*.typelib")
bundle(MSYSTEM_PREFIX, "bin/libgirepository-*.dll") bundle(MSYSTEM_PREFIX, "bin/libgirepository-*.dll")
#### Python support #### Python support
#####python.exe is needed for plug-ins output in `gimp-console*.exe` #####python.exe is needed for plug-ins error output if `gimp*.exe` is run from console
bundle(MSYSTEM_PREFIX, "bin/python.exe") bundle(MSYSTEM_PREFIX, "bin/python.exe")
if not os.getenv("GIMP_UNSTABLE") and os.getenv("GIMP_RELEASE"): #####pythonw.exe is needed to run plug-ins silently if `gimp*.exe` is run from shortcut
#####pythonw.exe is needed to run plug-ins silently in `gimp*.exe` bundle(MSYSTEM_PREFIX, "bin/pythonw.exe")
bundle(MSYSTEM_PREFIX, "bin/pythonw.exe")
bundle(MSYSTEM_PREFIX, "lib/python*") bundle(MSYSTEM_PREFIX, "lib/python*")
clean(GIMP_DISTRIB, "lib/python*/*.pyc") clean(GIMP_DISTRIB, "lib/python*/*.pyc")
#####Needed for internet connection on python. See: https://gitlab.gnome.org/GNOME/gimp/-/issues/14722 #####Needed for internet connection on python. See: https://gitlab.gnome.org/GNOME/gimp/-/issues/14722

View file

@ -407,7 +407,7 @@ Source: "{#MAIN_BUNDLE}\*.lua"; DestDir: "{app}"; Excludes: "share\gimp\*.lua";
#ifdef PYTHON #ifdef PYTHON
Source: "{#MAIN_BUNDLE}\etc\ssl\*"; DestDir: "{app}\etc\ssl"; Components: {#PY_ARCHS}; Flags: {#COMMON_FLAGS} Source: "{#MAIN_BUNDLE}\etc\ssl\*"; DestDir: "{app}\etc\ssl"; Components: {#PY_ARCHS}; Flags: {#COMMON_FLAGS}
Source: "{#MAIN_BUNDLE}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\environ\py*.env"; DestDir: "{app}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\environ"; Components: {#PY_ARCHS}; Flags: {#COMMON_FLAGS} Source: "{#MAIN_BUNDLE}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\environ\py*.env"; DestDir: "{app}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\environ"; Components: {#PY_ARCHS}; Flags: {#COMMON_FLAGS}
Source: "{#MAIN_BUNDLE}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\interpreters\pygimp.interp"; DestDir: "{app}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\interpreters"; Components: {#PY_ARCHS}; Flags: {#COMMON_FLAGS} Source: "{#MAIN_BUNDLE}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\interpreters\pygimp*.interp"; DestDir: "{app}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\interpreters"; Components: {#PY_ARCHS}; Flags: {#COMMON_FLAGS}
Source: "{#MAIN_BUNDLE}\*.py"; DestDir: "{app}"; Components: {#PY_ARCHS}; Flags: {#COMMON_FLAGS} Source: "{#MAIN_BUNDLE}\*.py"; DestDir: "{app}"; Components: {#PY_ARCHS}; Flags: {#COMMON_FLAGS}
#endif #endif
Source: "{#MAIN_BUNDLE}\share\locale\*"; DestDir: "{app}\share\locale"; Components: loc; Flags: dontcopy {#COMMON_FLAGS} Source: "{#MAIN_BUNDLE}\share\locale\*"; DestDir: "{app}\share\locale"; Components: loc; Flags: dontcopy {#COMMON_FLAGS}
@ -523,6 +523,7 @@ Type: filesandordirs; Name: "{app}\include\gexiv2"
Type: files; Name: "{app}\uninst\uninst.inf" Type: files; Name: "{app}\uninst\uninst.inf"
Type: files; Name: "{app}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\interpreters\lua.interp" Type: files; Name: "{app}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\interpreters\lua.interp"
Type: files; Name: "{app}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\environ\pygimp.env" Type: files; Name: "{app}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\environ\pygimp.env"
Type: files; Name: "{app}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\environ\pygimp_win.env"
;4.3 KEYS TO BE REGISTERED ;4.3 KEYS TO BE REGISTERED
@ -1750,23 +1751,28 @@ begin
begin begin
StatusLabel(CustomMessage('SettingUpPyGimp'),''); StatusLabel(CustomMessage('SettingUpPyGimp'),'');
//python.exe is needed for plug-ins error output if `gimp*.exe` is run from console
InterpFile := ExpandConstant('{app}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\interpreters\pygimp.interp'); InterpFile := ExpandConstant('{app}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\interpreters\pygimp.interp');
DebugMsg('PrepareInterp','Writing interpreter file for gimp-python: ' + InterpFile); DebugMsg('PrepareInterp','Writing interpreter file for gimp-python: ' + InterpFile);
InterpContent := 'python=' + ExpandConstant('{app}\bin\python.exe') + #10 +
#if Defined(GIMP_UNSTABLE) || !Defined(GIMP_RELEASE) 'python3=' + ExpandConstant('{app}\bin\python.exe') + #10 +
//python.exe is prefered in unstable versions because of error output '/usr/bin/python=' + ExpandConstant('{app}\bin\python.exe') + #10 +
#define PYTHON="python.exe" '/usr/bin/python3=' + ExpandConstant('{app}\bin\python.exe') + #10 +
#else
//pythonw.exe is prefered in stable releases because it works silently
#define PYTHON="pythonw.exe"
#endif
InterpContent := 'python=' + ExpandConstant('{app}\bin\{#PYTHON}') + #10 +
'python3=' + ExpandConstant('{app}\bin\{#PYTHON}') + #10 +
'/usr/bin/python=' + ExpandConstant('{app}\bin\{#PYTHON}') + #10 +
'/usr/bin/python3=' + ExpandConstant('{app}\bin\{#PYTHON}') + #10 +
':Python:E::py::python:'#10; ':Python:E::py::python:'#10;
if not SaveStringToUTF8File(InterpFile,InterpContent,False) then
begin
DebugMsg('PrepareInterp','Problem writing the file. [' + InterpContent + ']');
SuppressibleMsgBox(CustomMessage('ErrorUpdatingPython') + ' (2)',mbInformation,mb_ok,IDOK);
end;
//pythonw.exe is needed to run plug-ins silently if `gimp*.exe` is run from shortcut
InterpFile := ExpandConstant('{app}\lib\gimp\{#GIMP_PKGCONFIG_VERSION}\interpreters\pygimp_win.interp');
DebugMsg('PrepareInterp','Writing interpreter file for gimp-python: ' + InterpFile);
InterpContent := 'python=' + ExpandConstant('{app}\bin\pythonw.exe') + #10 +
'python3=' + ExpandConstant('{app}\bin\pythonw.exe') + #10 +
'/usr/bin/python=' + ExpandConstant('{app}\bin\pythonw.exe') + #10 +
'/usr/bin/python3=' + ExpandConstant('{app}\bin\pythonw.exe') + #10 +
':Python:E::py::python:'#10;
if not SaveStringToUTF8File(InterpFile,InterpContent,False) then if not SaveStringToUTF8File(InterpFile,InterpContent,False) then
begin begin
DebugMsg('PrepareInterp','Problem writing the file. [' + InterpContent + ']'); DebugMsg('PrepareInterp','Problem writing the file. [' + InterpContent + ']');

View file

@ -1,3 +1,4 @@
#.interp file read by gimp_interpreter_db_load_interp_file in gimpinterpreterdb.c
install_data('default.interp', install_data('default.interp',
install_dir: gimpplugindir / 'interpreters', install_dir: gimpplugindir / 'interpreters',
) )

View file

@ -1,5 +1,6 @@
subdir('goat-exercises') subdir('goat-exercises')
#.interp file read by gimp_interpreter_db_load_interp_file in gimpinterpreterdb.c
if have_lua and not meson.is_cross_build() and is_variable('lua') and lua.found() and (platform_windows or not relocatable_bundle) if have_lua and not meson.is_cross_build() and is_variable('lua') and lua.found() and (platform_windows or not relocatable_bundle)
lua_config = configuration_data() lua_config = configuration_data()
# For Windows, we set the binary name only. # For Windows, we set the binary name only.

View file

@ -38,17 +38,17 @@ foreach plugin : python_plugins
endforeach endforeach
endforeach endforeach
# Fallback fix to the problem of non-configured interpreters (needed by MSIX) #.interp file read by gimp_interpreter_db_load_interp_file in gimpinterpreterdb.c
if (platform_windows or platform_osx) and not meson.is_cross_build() and python.found() if (platform_windows or platform_osx) and not meson.is_cross_build() and python.found()
python_config = configuration_data() python_config = configuration_data()
if platform_windows if platform_windows
if not stable or not release # python.exe is needed for plug-ins error output if `gimp*.exe` is run from console
#python.exe is prefered in unstable versions because of error output python_config.set('PYTHON_EXE', 'python.exe')
python_config.set('PYTHON_EXE', 'python.exe')
else # pythonw.exe is needed to run plug-ins silently if `gimp*.exe` is run from shortcut
#pythonw.exe is prefered in stable releases because it works silently install_data('pygimp_win.interp',
python_config.set('PYTHON_EXE', 'pythonw.exe') install_dir: gimpplugindir / 'interpreters',
endif )
else else
# A 'python3' symlink is created on macOS. # A 'python3' symlink is created on macOS.
python_config.set('PYTHON_EXE', 'python3') python_config.set('PYTHON_EXE', 'python3')

View file

@ -0,0 +1,5 @@
python=pythonw.exe
python3=pythonw.exe
/usr/bin/python=pythonw.exe
/usr/bin/python3=pythonw.exe
:Python:E::py::python3:

View file

@ -46,7 +46,7 @@ if not meson.is_cross_build()
], ],
) )
# Fallback fix to the problem of non-configured interpreters #.interp file read by gimp_interpreter_db_load_interp_file in gimpinterpreterdb.c
scriptfu_config = configuration_data() scriptfu_config = configuration_data()
scriptfu_config.set('SCRIPTFU_PATH', '') scriptfu_config.set('SCRIPTFU_PATH', '')
configure_file( configure_file(
@ -56,6 +56,14 @@ if not meson.is_cross_build()
install: true, install: true,
install_dir: gimpplugindir / 'interpreters', install_dir: gimpplugindir / 'interpreters',
) )
configure_file(
input : 'gimp-script-fu-interpreter.interp.in',
output: 'gimp-script-fu-interpreter_win.interp',
configuration: scriptfu_config,
install: true,
install_dir: gimpplugindir / 'interpreters',
)
endif endif
# Several components use Gtk # Several components use Gtk