gimp/build/windows/installer/base_gimp3264.iss

1693 lines
60 KiB
Plaintext

;.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,
; ;
;Copyright (c) 2002-2010 Jernej Simončič ;
; ;
;This software is provided 'as-is', without any express or implied ;
;warranty. In no event will the authors be held liable for any damages ;
;arising from the use of this software. ;
; ;
;Permission is granted to anyone to use this software for any purpose, ;
;including commercial applications, and to alter it and redistribute it ;
;freely, subject to the following restrictions: ;
; ;
; 1. The origin of this software must not be misrepresented; you must ;
; not claim that you wrote the original software. If you use this ;
; software in a product, an acknowledgment in the product ;
; documentation would be appreciated but is not required. ;
; ;
; 2. Altered source versions must be plainly marked as such, and must ;
; not be misrepresented as being the original software. ;
; ;
; 3. This notice may not be removed or altered from any source ;
; distribution. ;
;.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.;
;
;Install script for GIMP and GTK+
;requires Inno Setup 6
;
;See base_directories.isi
;
;Changelog:
;
;2012-05-05
;- check for SSE support
;- remove obsolete 2.6 plugins when installing over 2.6.12 combined installer
;
;2011-12-18
;- display a picture on the first install screen
;- add a development version warning back
;- clean gegl's DLLs on install as some files have changed names
;
;2011-08-30
;- only uninstall previous GIMP version when installing over existing installation
; TODO: offer the option to uninstall 32bit version when installing on x64 system
;- install 32bit plugins to same directory as 64bit plugins on x64 installs to
; avoid problems when upgrading
;
;2010-07-08
;- clean up entire Python subdirectory (since the .pyc files are generated when
; scripts are run)
;- use crHand instead of crHandPoint for the billboard URL
;
;2010-07-02
;- add libraries for compatibility with old 32-bit plug-ins as a component
;- remove a few unused RTF ready-memo related things
;- uninst.inf is now processed as the first step of uninstall, as otherwise the
; uninstaller could leave behind empty directories
;
;2010-06-29
;- fix SuppressibleMsgBox calls to use proper button ID for default button
;- simplify the wizard - skip Welcome page, and make the Next button from
; InfoBefore/License page invoke install immediately (custom install is still
; possible by clicking the Customize button)
;
;2010-05-15
;- rewrote script mostly from scratch
;- combine 32 and 64bit GIMP versions to a single installer
; - install enough 32bit support files even with 64bit version to allow running 32bit
; plug-ins on 64bit version (used by Python scriptin support [as there's no 64-bit
; PyGTK+ on Windows available yet] and TWAIN plug-in, which only works in 32-bit
; version)
;- Python with PyGTK is included in the installer now
;- install GIMP to new directory by default ({pf}\GIMP 2 instead of {pf}\GIMP-2.0)
;- uninstall previous GIMP versions as the first step of install (both 32 and 64-bit)
; - require reboot if installing to directory from which GIMP was just uninstalled,
; and this directory wasn't removed by the uninstaller; the installer will continue
; automatically after reboot
;- fixed a long standing bug where "Open with GIMP" menu entries would be left after
; uninstalling
;
#pragma option -e+
; Optional Build-time params: DEBUG_SYMBOLS, LUA, PYTHON, NOCOMPRESSION, NOFILES
; Optional Run-time params: /configoverride= /disablecheckupdate=false|true /debugresume=0|1 /resumeinstall=0|1|2
#define X86 1
#define X64 2
#define ARM64 3
#define GIMP_DIR32 GIMP_DIR + "\" + DIR32
#define GIMP_DIR64 GIMP_DIR + "\" + DIR64
#define GIMP_DIRA64 GIMP_DIR + "\" + DIR64
#define DDIR32 DIR32
#define DDIR64 DIR64
#define DDIRA64 DIRA64
#define DEPS_DIR32 DEPS_DIR + "\" + DDIR32
#define DEPS_DIR64 DEPS_DIR + "\" + DDIR64
#define DEPS_DIRA64 DEPS_DIR + "\" + DDIRA64
#define MAJOR=Copy(GIMP_VERSION,1,Pos(".",GIMP_VERSION)-1)
#define MINOR=Copy(GIMP_VERSION,Pos(".",GIMP_VERSION)+1)
#expr MINOR=Copy(MINOR,1,Pos(".",MINOR)-1)
#if Int(MINOR) % 2 == 1
#define GIMP_UNSTABLE="-dev"
#endif
[Setup]
MissingMessagesWarning=no
NotRecognizedMessagesWarning=no
#define ASSETS_DIR BUILD_DIR + "\build\windows\installer"
;INSTALLER AND APP INFO
AppName=GIMP
#if Defined(GIMP_UNSTABLE) && GIMP_UNSTABLE != ""
;Inno installer identifier: https://github.com/jrsoftware/issrc/pull/461
SetupMutex=GIMP-{#GIMP_APP_VERSION}
;Inno installer (default) install location
DefaultDirName={autopf}\GIMP {#GIMP_APP_VERSION}
;Inno uninstaller identifier
AppID=GIMP-{#GIMP_APP_VERSION}
#else
SetupMutex=GIMP-{#MAJOR}
DefaultDirName={autopf}\GIMP {#MAJOR}
AppID=GIMP-{#MAJOR}
#endif
#if !defined(REVISION) || REVISION == "0"
;Inno installer file version
VersionInfoVersion={#GIMP_VERSION}
;Inno installer product version and ImmersiveControlPanel 'DisplayVersion'
AppVersion={#GIMP_VERSION}.0
;ImmersiveControlPanel 'DisplayName'
AppVerName=GIMP {#GIMP_VERSION}
#else
VersionInfoVersion={#GIMP_VERSION}.{#REVISION}
AppVersion={#GIMP_VERSION}.{#REVISION}
AppVerName=GIMP {#GIMP_VERSION}.{#REVISION}
#endif
;ImmersiveControlPanel 'Publisher'
AppPublisher=The GIMP Team
;ControlPanel 'URLInfoAbout'
AppPublisherURL=https://www.gimp.org/
;ControlPanel 'HelpLink'
AppSupportURL=https://www.gimp.org/docs/
#if Defined(GIMP_UNSTABLE) && GIMP_UNSTABLE != ""
;ControlPanel 'URLUpdateInfo'
AppUpdatesURL=https://www.gimp.org/downloads/devel/
#else
AppUpdatesURL=https://www.gimp.org/downloads/
#endif
;INSTALLER PAGES
PrivilegesRequiredOverridesAllowed=dialog
ShowLanguageDialog=auto
DisableWelcomePage=no
InfoBeforeFile=gpl+python.rtf
DisableDirPage=auto
FlatComponentsList=yes
DisableProgramGroupPage=yes
;AllowNoIcons=true
ChangesAssociations=true
ChangesEnvironment=yes
AlwaysShowDirOnReadyPage=yes
WizardStyle=modern
WizardSizePercent=100
WizardResizable=no
WizardSmallImageFile={#ASSETS_DIR}\gimp.scale-100.bmp,{#ASSETS_DIR}\gimp.scale-125.bmp,{#ASSETS_DIR}\gimp.scale-150.bmp,{#ASSETS_DIR}\gimp.scale-175.bmp,{#ASSETS_DIR}\gimp.scale-200.bmp,{#ASSETS_DIR}\gimp.scale-225.bmp,{#ASSETS_DIR}\gimp.scale-250.bmp
WizardImageFile={#ASSETS_DIR}\install-end.scale-100.bmp,{#ASSETS_DIR}\install-end.scale-125.bmp,{#ASSETS_DIR}\install-end.scale-150.bmp,{#ASSETS_DIR}\install-end.scale-175.bmp,{#ASSETS_DIR}\install-end.scale-200.bmp,{#ASSETS_DIR}\install-end.scale-225.bmp,{#ASSETS_DIR}\install-end.scale-250.bmp
WizardImageStretch=yes
;INSTALLER .EXE FILE
SetupIconFile={#ASSETS_DIR}\setup.ico
ArchitecturesInstallIn64BitMode=x64 arm64
MinVersion=10.0
#if Defined(GIMP_UNSTABLE) && GIMP_UNSTABLE != ""
LZMANumBlockThreads=4
LZMABlockSize=76800
#endif
#ifdef NOCOMPRESSION
;UseSetupLdr=no
OutputDir={#GIMP_DIR}\unc
Compression=none
;InternalCompressLevel=0
DiskSpanning=yes
DiskSliceSize=max
#else
OutputDir={#GIMP_DIR}
Compression=lzma2/ultra64
InternalCompressLevel=ultra
SolidCompression=yes
LZMAUseSeparateProcess=yes
LZMANumFastBytes=273
; Increasing dictionary size may improve compression ratio at the
; expense of memory requirement. We run into "Out of memory" error in
; the CI.
;LZMADictionarySize=524288
;SignTool=Default
;SignedUninstaller=yes
;SignedUninstallerDir=_Uninst
#endif //NOCOMPRESSION
#if !defined(REVISION) || REVISION == "0"
OutputBaseFileName=gimp-{#GIMP_VERSION}-setup
#else
OutputBaseFileName=gimp-{#GIMP_VERSION}.{#REVISION}-setup
#endif
OutputManifestFile=inno.log
;UNINSTALLER
;ImmersiveControlPanel 'DisplayIcon'
UninstallDisplayIcon={app}\bin\gimp-{#GIMP_APP_VERSION}.exe
UninstallFilesDir={app}\uninst
[LangOptions]
;Win32 Vista design (despite the name it is still used in Win32 Win 11 apps)
DialogFontName=Segoe UI
DialogFontSize=9
WelcomeFontName=Segoe UI
WelcomeFontSize=12
[Languages]
Name: "en"; MessagesFile: "compiler:Default.isl,{#ASSETS_DIR}\lang\en.setup.isl"
#include ASSETS_DIR + "\base_po-msg.list"
[Types]
;Name: normal; Description: "{cm:TypeTypical}"
Name: full; Description: "{cm:TypeFull}"
Name: compact; Description: "{cm:TypeCompact}"
Name: custom; Description: "{cm:TypeCustom}"; Flags: iscustom
[Components]
;Required components (minimal install)
Name: gimp32; Description: "{cm:ComponentsGimp,{#GIMP_VERSION}}"; Types: full compact custom; Flags: fixed; Check: Check3264('32')
Name: gimp64; Description: "{cm:ComponentsGimp,{#GIMP_VERSION}}"; Types: full compact custom; Flags: fixed; Check: Check3264('x64')
Name: gimpARM64; Description: "{cm:ComponentsGimp,{#GIMP_VERSION}}"; Types: full compact custom; Flags: fixed; Check: Check3264('arm64')
Name: deps32; Description: "{cm:ComponentsDeps}"; Types: full compact custom; Flags: fixed; Check: Check3264('32')
Name: deps64; Description: "{cm:ComponentsDeps}"; Types: full compact custom; Flags: fixed; Check: Check3264('x64')
Name: depsARM64; Description: "{cm:ComponentsDeps}"; Types: full compact custom; Flags: fixed; Check: Check3264('arm64')
;Optional components (complete install)
#ifdef DEBUG_SYMBOLS
Name: debug32; Description: "{cm:ComponentsDebug}"; Types: full custom; Flags: disablenouninstallwarning; Check: Check3264('32')
Name: debug64; Description: "{cm:ComponentsDebug}"; Types: full custom; Flags: disablenouninstallwarning; Check: Check3264('x64')
Name: debugARM64; Description: "{cm:ComponentsDebug}"; Types: full custom; Flags: disablenouninstallwarning; Check: Check3264('arm64')
#endif
;Ghostscript
Name: gs32; Description: "{cm:ComponentsGhostscript}"; Types: full custom; Check: Check3264('32')
Name: gs64; Description: "{cm:ComponentsGhostscript}"; Types: full custom; Check: Check3264('x64')
Name: gsARM64; Description: "{cm:ComponentsGhostscript}"; Types: full custom; Check: Check3264('arm64')
#ifdef LUA
Name: lua32; Description: "{cm:ComponentsLua}"; Types: full custom; Check: Check3264('32')
Name: lua64; Description: "{cm:ComponentsLua}"; Types: full custom; Check: Check3264('x64')
Name: luaARM64; Description: "{cm:ComponentsLua}"; Types: full custom; Check: Check3264('arm64')
#endif
#ifdef PYTHON
Name: py32; Description: "{cm:ComponentsPython}"; Types: full custom; Check: Check3264('32')
Name: py64; Description: "{cm:ComponentsPython}"; Types: full custom; Check: Check3264('x64')
Name: pyARM64; Description: "{cm:ComponentsPython}"; Types: full custom; Check: Check3264('arm64')
#endif
;Locales
Name: loc; Description: "{cm:ComponentsTranslations}"; Types: full custom
#include ASSETS_DIR + "\base_po-cmp.list"
;MyPaint Brushes
Name: mypaint; Description: "{cm:ComponentsMyPaint}"; Types: full custom
;32-bit TWAIN support
Name: gimp32on64; Description: "{cm:ComponentsGimp32}"; Types: full custom; Flags: checkablealone; Check: Check3264('64')
[Tasks]
Name: desktopicon; Description: "{cm:AdditionalIconsDesktop}"; GroupDescription: "{cm:AdditionalIcons}"
[Icons]
Name: "{autoprograms}\GIMP {#GIMP_VERSION}"; Filename: "{app}\bin\gimp-{#GIMP_APP_VERSION}.exe"; WorkingDir: "%USERPROFILE%"; Comment: "GIMP {#GIMP_VERSION}"
Name: "{autodesktop}\GIMP {#GIMP_VERSION}"; Filename: "{app}\bin\gimp-{#GIMP_APP_VERSION}.exe"; WorkingDir: "%USERPROFILE%"; Comment: "GIMP {#GIMP_VERSION}"; Tasks: desktopicon
[Run]
Filename: "{app}\bin\gimp-{#GIMP_APP_VERSION}.exe"; Description: "{cm:LaunchGimp}"; Flags: unchecked postinstall nowait skipifsilent
[Files]
;setup files
Source: "{#ASSETS_DIR}\install-end.scale-100.bmp"; Flags: dontcopy
Source: "{#ASSETS_DIR}\installsplash.bmp"; Flags: dontcopy
Source: "{#ASSETS_DIR}\installsplash_small.bmp"; Flags: dontcopy
#ifndef NOFILES
#define COMMON_FLAGS="recursesubdirs restartreplace uninsrestartdelete ignoreversion"
;Required arch-neutral components (compact install)
#define GIMP_ARCHS="gimp32 or gimp64 or gimpARM64"
#define OPTIONAL_EXT="*.debug,*.lua,*.py"
Source: "{#GIMP_DIR32}\etc\gimp\*"; DestDir: "{app}\etc\gimp"; Components: {#GIMP_ARCHS}; Flags: {#COMMON_FLAGS}
Source: "{#GIMP_DIR32}\lib\gimp\{#GIMP_API_VERSION}\environ\default.env"; DestDir: "{app}\lib\gimp\{#GIMP_API_VERSION}\environ"; Components: {#GIMP_ARCHS}; Flags: {#COMMON_FLAGS}
Source: "{#GIMP_DIR32}\lib\gimp\{#GIMP_API_VERSION}\interpreters\gimp-script-fu-interpreter.interp"; DestDir: "{app}\lib\gimp\{#GIMP_API_VERSION}\interpreters"; Components: {#GIMP_ARCHS}; Flags: {#COMMON_FLAGS}
Source: "{#GIMP_DIR32}\lib\gimp\{#GIMP_API_VERSION}\extensions\*"; DestDir: "{app}\lib\gimp\{#GIMP_API_VERSION}\extensions"; Excludes: "*.dll,*.exe,{#OPTIONAL_EXT}"; Components: {#GIMP_ARCHS}; Flags: {#COMMON_FLAGS}
Source: "{#GIMP_DIR32}\lib\gimp\{#GIMP_API_VERSION}\plug-ins\*"; DestDir: "{app}\lib\gimp\{#GIMP_API_VERSION}\plug-ins"; Excludes: "*.dll,*.exe,{#OPTIONAL_EXT}"; Components: {#GIMP_ARCHS}; Flags: {#COMMON_FLAGS}
Source: "{#GIMP_DIR32}\share\gimp\*"; DestDir: "{app}\share\gimp"; Excludes: "{#OPTIONAL_EXT}"; Components: {#GIMP_ARCHS}; Flags: {#COMMON_FLAGS} createallsubdirs
Source: "{#GIMP_DIR32}\share\icons\hicolor\*"; DestDir: "{app}\share\icons\hicolor"; Components: {#GIMP_ARCHS}; Flags: {#COMMON_FLAGS}
Source: "{#GIMP_DIR32}\share\metainfo\*"; DestDir: "{app}\share\metainfo"; Components: {#GIMP_ARCHS}; Flags: {#COMMON_FLAGS}
#define DEPS_ARCHS="deps32 or deps64 or depsARM64"
Source: "{#DEPS_DIR32}\etc\*"; DestDir: "{app}\etc"; Excludes: "gimp"; Components: {#DEPS_ARCHS}; Flags: {#COMMON_FLAGS}
Source: "{#DEPS_DIR32}\share\*"; DestDir: "{app}\share"; Excludes: "gimp,icons\hicolor,metainfo,locale\*,mypaint-data"; Components: {#DEPS_ARCHS}; Flags: {#COMMON_FLAGS} createallsubdirs
;Optional arch-neutral components (full install)
#ifdef LUA
Source: "{#GIMP_DIR32}\lib\gimp\{#GIMP_API_VERSION}\interpreters\lua.interp"; DestDir: "{app}\lib\gimp\{#GIMP_API_VERSION}\interpreters"; Components: (lua32 or lua64 or luaARM64); Flags: {#COMMON_FLAGS}
Source: "{#GIMP_DIR32}\*.lua"; DestDir: "{app}"; Components: (lua32 or lua64 or luaARM64); Flags: {#COMMON_FLAGS}
#endif
#ifdef PYTHON
Source: "{#GIMP_DIR32}\lib\gimp\{#GIMP_API_VERSION}\environ\py*.env"; DestDir: "{app}\lib\gimp\{#GIMP_API_VERSION}\environ"; Components: (py32 or py64 or pyARM64); Flags: {#COMMON_FLAGS}
Source: "{#GIMP_DIR32}\lib\gimp\{#GIMP_API_VERSION}\interpreters\pygimp.interp"; DestDir: "{app}\lib\gimp\{#GIMP_API_VERSION}\interpreters"; Components: (py32 or py64 or pyARM64); Flags: {#COMMON_FLAGS}
Source: "{#GIMP_DIR32}\*.py"; DestDir: "{app}"; Components: (py32 or py64 or pyARM64); Flags: {#COMMON_FLAGS}
#endif
Source: "{#GIMP_DIR32}\share\locale\*"; DestDir: "{app}\share\locale"; Components: loc; Flags: dontcopy {#COMMON_FLAGS}
#include ASSETS_DIR + "\base_po-files.list"
Source: "{#DEPS_DIR32}\share\mypaint-data\*"; DestDir: "{app}\share\mypaint-data"; Components: mypaint; Flags: {#COMMON_FLAGS}
;files arch specific
;i686
#define PLATFORM X86
#include "base_executables.isi"
;special case, since 64bit version doesn't work, and is excluded in base_executables.isi
Source: "{#GIMP_DIR32}\lib\gimp\{#GIMP_API_VERSION}\plug-ins\twain.exe"; DestDir: "{app}\lib\gimp\{#GIMP_API_VERSION}\plug-ins"; Components: gimp32; Flags: {#COMMON_FLAGS}
;x86_64
#define PLATFORM X64
#include "base_executables.isi"
;AArch64
#define PLATFORM ARM64
#include "base_executables.isi"
;32-on-64bit
#include "base_twain32on64.isi"
;prefer 32bit twain plugin over 64bit because 64bit twain drivers are rare
Source: "{#GIMP_DIR32}\lib\gimp\{#GIMP_API_VERSION}\plug-ins\twain\twain.exe"; DestDir: "{app}\lib\gimp\{#GIMP_API_VERSION}\plug-ins\twain"; Components: gimp32on64; Flags: {#COMMON_FLAGS}
;upgrade zlib1.dll in System32 if it's present there to avoid breaking plugins
;sharedfile flag will ensure that the upgraded file is left behind on uninstall to avoid breaking other programs that use the file
Source: "{#DEPS_DIR32}\bin\zlib1.dll"; DestDir: "{sys}"; Components: {#GIMP_ARCHS}; Flags: restartreplace sharedfile 32bit uninsrestartdelete comparetimestamp; Check: BadSysDLL('zlib1.dll',32)
Source: "{#DEPS_DIR64}\bin\zlib1.dll"; DestDir: "{sys}"; Components: gimp64; Flags: restartreplace sharedfile uninsrestartdelete comparetimestamp; Check: BadSysDLL('zlib1.dll',64)
;allow specific configuration files to be overridden by files in a specific directory
#define FindHandle
#sub ProcessConfigFile
#define FileName FindGetFileName(FindHandle)
Source: "{code:GetExternalConfDir}\{#FileName}"; DestDir: "{app}\{#ConfigDir}"; Flags: external restartreplace; Check: CheckExternalConf('{#FileName}')
#if BaseDir != GIMP_DIR32
Source: "{code:GetExternalConfDir}\{#FileName}"; DestDir: "{app}\32\{#ConfigDir}"; Components: gimp32on64; Flags: external restartreplace; Check: CheckExternalConf('{#FileName}')
#endif
#endsub
#define FindResult
#sub ProcessConfigDir
#emit ';; ' + ConfigDir
#emit ';; ' + BaseDir
#for {FindHandle = FindResult = FindFirst(AddBackslash(BaseDir) + AddBackSlash(ConfigDir) + "*", 0); \
FindResult; FindResult = FindNext(FindHandle)} ProcessConfigFile
#if FindHandle
#expr FindClose(FindHandle)
#endif
#endsub
#define public BaseDir GIMP_DIR32
#define public ConfigDir "etc\gimp\" + GIMP_API_VERSION
#expr ProcessConfigDir
#define public ConfigDir "etc\fonts"
#expr ProcessConfigDir
#endif //NOFILES
;We need at least an empty folder to avoid GIMP*_LOCALEDIR warnings
[Dirs]
Name: "{app}\32\share\locale"; Components: gimp32on64; Flags: uninsalwaysuninstall
[InstallDelete]
Type: files; Name: "{app}\bin\gimp-?.?.exe"
Type: files; Name: "{app}\bin\gimp-?.??.exe"
Type: files; Name: "{app}\bin\gimp-console-?.?.exe"
Type: files; Name: "{app}\bin\gimp-console-?.??.exe"
;old ghostscript
Type: filesandordirs; Name: "{app}\share\ghostscript\*"
;<2.99.14 plug-ins and modules
Type: files; Name: "{app}\lib\gimp\2.99\plug-ins\py-slice\py-slice.py"
Type: files; Name: "{app}\lib\gimp\2.99\plug-ins\benchmark-foreground-extract\benchmark-foreground-extract.py"
;Some typo in meson which we used for GIMP 2.99.12 installer.
Type: files; Name: "{app}\lib\gimp\2.99\modules\libcontroller-dx-input.dll"
;old icons
#ifndef GIMP_UNSTABLE
Type: files; Name: "{autoprograms}\GIMP {#MAJOR}.lnk"
Type: files; Name: "{autodesktop}\GIMP {#MAJOR}.lnk"
#endif
;get previous GIMP icon name from uninstall name in Registry
#if Defined(GIMP_UNSTABLE) && GIMP_UNSTABLE != ""
Type: files; Name: "{autoprograms}\GIMP {reg:HKA\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\GIMP-{#GIMP_APP_VERSION}_is1,DisplayVersion|GIMP {#GIMP_APP_VERSION}}.lnk"; Check: CheckRegValueExists('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\GIMP-{#GIMP_APP_VERSION}_is1','DisplayVersion')
Type: files; Name: "{autodesktop}\GIMP {reg:HKA\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\GIMP-{#GIMP_APP_VERSION}_is1,DisplayVersion|GIMP {#GIMP_APP_VERSION}}.lnk"; Check: CheckRegValueExists('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\GIMP-{#GIMP_APP_VERSION}_is1','DisplayVersion')
#else
Type: files; Name: "{autoprograms}\GIMP {reg:HKA\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\GIMP-{#MAJOR}_is1,DisplayVersion|GIMP {#MAJOR}}.lnk"; Check: CheckRegValueExists('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\GIMP-{#MAJOR}_is1','DisplayVersion')
Type: files; Name: "{autodesktop}\GIMP {reg:HKA\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\GIMP-{#MAJOR}_is1,DisplayVersion|GIMP {#MAJOR}}.lnk"; Check: CheckRegValueExists('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\GIMP-{#MAJOR}_is1','DisplayVersion')
#endif
;remove old babl and gegl plugins
Type: filesandordirs; Name: "{app}\lib\babl-0.1"
Type: filesandordirs; Name: "{app}\lib\gegl-0.4"
[Registry]
;Shell "Open with"
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#GIMP_APP_VERSION}.exe"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#GIMP_APP_VERSION}.exe"; ValueType: string; ValueName: "FriendlyAppName"; ValueData: "GIMP"
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#GIMP_APP_VERSION}.exe\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\bin\gimp-{#GIMP_APP_VERSION}.exe,1"
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#GIMP_APP_VERSION}.exe\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\bin\gimp-{#GIMP_APP_VERSION}.exe"" ""%1"""
Root: HKA; Subkey: "Software\GIMP {#GIMP_APP_VERSION}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\GIMP {#GIMP_APP_VERSION}\Capabilities"; ValueType: string; ValueName: "ApplicationName"; ValueData: "GIMP"
Root: HKA; Subkey: "Software\GIMP {#GIMP_APP_VERSION}\Capabilities"; ValueType: string; ValueName: "ApplicationIcon"; ValueData: "{app}\bin\gimp-{#GIMP_APP_VERSION}.exe,0"
Root: HKA; Subkey: "Software\GIMP {#GIMP_APP_VERSION}\Capabilities"; ValueType: string; ValueName: "ApplicationDescription"; ValueData: "GIMP is a free raster graphics editor used for image retouching and editing, free-form drawing, converting between different image formats, and more specialized tasks."
Root: HKA; Subkey: "Software\RegisteredApplications"; ValueType: string; ValueName: "GIMP {#GIMP_APP_VERSION}"; ValueData: "Software\GIMP {#GIMP_APP_VERSION}\Capabilities"; Flags: uninsdeletevalue
;Associations
#pragma option -e-
#define protected
#define Line=0
#define FileLine
#sub ProcessAssociation
#if !defined(Finished)
#if Copy(FileLine,1,1)=="#" || FileLine==""
//skip comments and empty lines
#else
#pragma message "Processing data_associations.list: " + FileLine
Root: HKA; Subkey: "Software\Classes\.{#FileLine}\OpenWithProgids"; ValueType: string; ValueName: "GIMP{#MAJOR}.{#FileLine}"; ValueData: ""; Flags: uninsdeletevalue
Root: HKA; Subkey: "Software\Classes\GIMP{#MAJOR}.{#FileLine}"; ValueType: string; ValueName: ""; ValueData: "GIMP {#GIMP_VERSION} {#UpperCase(FileLine)}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\Classes\GIMP{#MAJOR}.{#FileLine}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\bin\gimp-{#GIMP_APP_VERSION}.exe,1"
Root: HKA; Subkey: "Software\Classes\GIMP{#MAJOR}.{#FileLine}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\bin\gimp-{#GIMP_APP_VERSION}.exe"" ""%1"""
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#GIMP_APP_VERSION}.exe\SupportedTypes"; ValueType: string; ValueName: ".{#FileLine}"; ValueData: ""
Root: HKA; Subkey: "Software\GIMP {#GIMP_APP_VERSION}\Capabilities\FileAssociations"; ValueType: string; ValueName: ".{#FileLine}"; ValueData: "GIMP{#MAJOR}.{#FileLine}"
#endif
#endif
#endsub
#define FileHandle
#for {FileHandle = FileOpen(AddBackslash(SourcePath)+"data_associations.list"); \
FileHandle && !FileEof(FileHandle); FileLine = FileRead(FileHandle)} \
ProcessAssociation
#if FileHandle
#expr FileClose(FileHandle)
#endif
;special case for .ico files
Root: HKA; Subkey: "Software\Classes\.ico\OpenWithProgids"; ValueType: string; ValueName: "GIMP{#MAJOR}.ico"; ValueData: ""; Flags: uninsdeletevalue
Root: HKA; Subkey: "Software\Classes\GIMP{#MAJOR}.ico"; ValueType: string; ValueName: ""; ValueData: "GIMP {#GIMP_VERSION}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\Classes\GIMP{#MAJOR}.ico\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "%1"
Root: HKA; Subkey: "Software\Classes\GIMP{#MAJOR}.ico\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\bin\gimp-{#GIMP_APP_VERSION}.exe"" ""%1"""
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#GIMP_APP_VERSION}.exe\SupportedTypes"; ValueType: string; ValueName: ".ico"; ValueData: ""
Root: HKA; Subkey: "Software\GIMP {#GIMP_APP_VERSION}\Capabilities\FileAssociations"; ValueType: string; ValueName: ".ico"; ValueData: "GIMP{#MAJOR}.{#FileLine}"
[UninstallDelete]
Type: files; Name: "{app}\uninst\uninst.inf"
Type: files; Name: "{app}\lib\gimp\{#GIMP_API_VERSION}\interpreters\lua.interp"
Type: files; Name: "{app}\lib\gimp\{#GIMP_API_VERSION}\environ\pygimp.env"
[Code]
//GENERAL VARS AND UTILS
const
CP_ACP = 0;
CP_UTF8 = 65001;
COLOR_HOTLIGHT = 26;
var
//pgSimple: TWizardPage;
InstallMode: (imNone, imSimple, imCustom, imRebootContinue);
ConfigOverride: (coUndefined, coOverride, coDontOverride);
Force32bitInstall: Boolean;
function WideCharToMultiByte(CodePage: Cardinal; dwFlags: DWORD; lpWideCharStr: String; cchWideCharStr: Integer;
lpMultiByteStr: PAnsiChar; cbMultiByte: Integer; lpDefaultChar: Integer;
lpUsedDefaultChar: Integer): Integer; external 'WideCharToMultiByte@Kernel32 stdcall';
function MultiByteToWideChar(CodePage: Cardinal; dwFlags: DWORD; lpMultiByteStr: PAnsiChar; cbMultiByte: Integer;
lpWideCharStr: String; cchWideChar: Integer): Integer;
external 'MultiByteToWideChar@Kernel32 stdcall';
function GetLastError(): DWORD; external 'GetLastError@Kernel32 stdcall';
function GetSysColor(nIndex: Integer): DWORD; external 'GetSysColor@user32.dll stdcall';
function GetButtonWidth(const Texts: TArrayOfString; const Minimum: Integer): Integer;
var MeasureLabel: TNewStaticText;
i: Integer;
begin
MeasureLabel := TNewStaticText.Create(WizardForm);
with MeasureLabel do
begin
Parent := WizardForm;
Left := 0;
Top := 0;
AutoSize := True;
end;
Result := Minimum;
for i := 0 to GetArrayLength(Texts) - 1 do
begin
MeasureLabel.Caption := Texts[i];
if (MeasureLabel.Width + ScaleX(16)) > Result then
Result := (MeasureLabel.Width + ScaleX(16));
end;
MeasureLabel.Free;
end;
#include "util_general.isi"
#include "util_MessageWithURL.isi"
//0. PRELIMINARY SETUP CODE
//SSE instructions
const
PF_XMMI_INSTRUCTIONS_AVAILABLE = 6;
function IsProcessorFeaturePresent(ProcessorFeature: DWORD): LongBool; external 'IsProcessorFeaturePresent@kernel32 stdcall';
//Existing 32-bit
procedure Check32bitOverride;
var i: Integer;
old: String;
begin
Force32bitInstall := False;
old := LowerCase(GetPreviousData('32bitMode',''));
if old = 'true' then //ignore command line if previous install is already present
Force32bitInstall := True
else if old = 'false' then
Force32bitInstall := False
else
for i := 0 to ParamCount do //not a bug (in script anyway) - ParamCount returns the index of last ParamStr element, not the actual count
if ParamStr(i) = '/32' then
begin
Force32bitInstall := True;
break;
end;
DebugMsg('Check32bitOverride',BoolToStr(Force32bitInstall) + '[' + old + ']');
end;
procedure RegisterPreviousData(PreviousDataKey: Integer);
begin
if Is64BitInstallMode() then
SetPreviousData(PreviousDataKey,'32BitMode',BoolToStr(Force32bitInstall));
end;
//Resume after reboot (if needed)
function RestartSetupAfterReboot(): Boolean; forward;
//Screen bit depth
function GetDC(hWnd: Integer): Integer; external 'GetDC@User32 stdcall';
function ReleaseDC(hWnd, hDC: Integer): Integer; external 'ReleaseDC@User32 stdcall';
function GetDeviceCaps(hDC, nIndex: Integer): Integer; external 'GetDeviceCaps@GDI32 stdcall';
const
BITSPIXEL = 12;
PLANES = 14;
function BPPTooLowWarning(): Boolean;
var hDC, bpp, pl: Integer;
Message,Buttons: TArrayOfString;
begin
hDC := GetDC(0);
pl := GetDeviceCaps(hDC, PLANES);
bpp := GetDeviceCaps(hDC, BITSPIXEL);
ReleaseDC(0,hDC);
bpp := pl * bpp;
if bpp < 32 then
begin
SetArrayLength(Message,1);
SetArrayLength(Buttons,2);
Message[0] := CustomMessage('Require32BPP');
Buttons[0] := CustomMessage('Require32BPPContinue');
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;
end;
function InitializeSetup(): Boolean;
#if (Defined(GIMP_UNSTABLE) && GIMP_UNSTABLE != "") || Defined(DEVEL_WARNING)
var Message,Buttons: TArrayOfString;
#endif
begin
ConfigOverride := coUndefined;
if not IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) then
begin
SuppressibleMsgBox(CustomMessage('SSERequired'), mbCriticalError, MB_OK, 0);
Result := false;
exit;
end;
Check32bitOverride;
Result := RestartSetupAfterReboot(); //resume install after reboot - skip all setting pages, and install directly
if Result then
Result := BPPTooLowWarning();
if not Result then //no need to do anything else
exit;
//Unstable version warning
#if (Defined(GIMP_UNSTABLE) && GIMP_UNSTABLE != "") || Defined(DEVEL_WARNING)
Explode(Message, CustomMessage('DevelopmentWarning'), #13#10);
SetArrayLength(Buttons,2);
Buttons[0] := CustomMessage('DevelopmentButtonContinue');
Buttons[1] := CustomMessage('DevelopmentButtonExit');
if (not WizardSilent) and
(MessageWithURL(Message, CustomMessage('DevelopmentWarningTitle'), Buttons, mbError, 2, 2) = 2) then
begin
Result := False;
Exit;
end;
#endif
try
ExtractTemporaryFile('install-end.scale-100.bmp');
ExtractTemporaryFile('installsplash.bmp');
ExtractTemporaryFile('installsplash_small.bmp');
except
DebugMsg('InitializeSetup','Error extracting temporary file: ' + GetExceptionMessage);
MsgBox(CustomMessage('ErrorExtractingTemp') + #13#13 + GetExceptionMessage,mbError,MB_OK);
Result := False;
exit;
end;
//if InstallMode <> imRebootContinue then
// SuppressibleMsgBox(CustomMessage('UninstallWarning'),mbError,MB_OK,IDOK);
end;
//1. WELCOME: add splash image with buttons in non-default positions
var
WelcomeBitmapBottom: TBitmapImage;
btnInstall, btnCustomize: TNewButton;
procedure UpdateWizardImages();
var NewBitmap1,NewBitmap2: TFileStream;
begin
WelcomeBitmapBottom := TBitmapImage.Create(WizardForm);
with WelcomeBitmapBottom do
begin
Left := 0;
Top := 0;
Parent := WizardForm;
Width := WizardForm.ClientWidth;
Height := WizardForm.ClientHeight;
Stretch := True;
end;
DebugMsg('UpdateWizardImages','Height: ' + IntToStr(WizardForm.WizardBitmapImage.Height));
if WizardForm.WizardBitmapImage.Height < 386 then //use smaller image when not using Large Fonts
begin
try
NewBitmap1 := TFileStream.Create(ExpandConstant('{tmp}\installsplash_small.bmp'),fmOpenRead);
WizardForm.WizardBitmapImage.Bitmap.LoadFromStream(NewBitmap1);
WelcomeBitmapBottom.Bitmap := WizardForm.WizardBitmapImage.Bitmap;
try
NewBitmap2 := TFileStream.Create(ExpandConstant('{tmp}\install-end.scale-100.bmp'),fmOpenRead);
WizardForm.WizardBitmapImage2.Bitmap.LoadFromStream(NewBitmap2);
except
DebugMsg('UpdateWizardImages','Error loading image: ' + GetExceptionMessage);
finally
if NewBitmap2 <> nil then
NewBitmap2.Free;
end;
except
DebugMsg('UpdateWizardImages','Error loading image: ' + GetExceptionMessage);
finally
if NewBitmap1 <> nil then
NewBitmap1.Free;
end;
end
else
begin
try
NewBitmap1 := TFileStream.Create(ExpandConstant('{tmp}\installsplash.bmp'),fmOpenRead);
WizardForm.WizardBitmapImage.Bitmap.LoadFromStream(NewBitmap1);
WelcomeBitmapBottom.Bitmap := WizardForm.WizardBitmapImage.Bitmap;
except
DebugMsg('UpdateWizardImages','Error loading image: ' + GetExceptionMessage);
finally
if NewBitmap1 <> nil then
NewBitmap1.Free;
end;
end;
WizardForm.WizardBitmapImage.Width := WizardForm.ClientWidth;
WizardForm.WizardBitmapImage.Height := WizardForm.ClientHeight;
end;
procedure PrepareWelcomePage();
begin
if not WizardSilent then
begin
WizardForm.NextButton.Visible := False;
btnInstall.Visible := True;
btnInstall.TabOrder := 1;
btnCustomize.Visible := True;
WizardForm.Bevel.Visible := False;
WizardForm.WelcomeLabel1.Visible := False;
WizardForm.WelcomeLabel2.Visible := False;
WelcomeBitmapBottom.Visible := True;
end;
end;
procedure CleanUpCustomWelcome();
begin
WizardForm.NextButton.Visible := True;
btnInstall.Visible := False;
btnCustomize.Visible := False;
WizardForm.Bevel.Visible := True;
WelcomeBitmapBottom.Visible := False;
end;
procedure InstallOnClick(Sender: TObject);
begin
DebugMsg('Install mode','Simple');
InstallMode := imSimple;
CleanUpCustomWelcome();
WizardForm.NextButton.OnClick(TNewButton(Sender).Parent);
end;
procedure CustomizeOnClick(Sender: TObject);
begin
DebugMsg('Install mode','Custom');
InstallMode := imCustom;
CleanUpCustomWelcome();
WizardForm.NextButton.OnClick(TNewButton(Sender).Parent);
end;
procedure InitCustomPages();
var i,ButtonWidth: Integer;
ButtonText: TArrayOfString;
MeasureLabel: TNewStaticText;
//lblInfo: TNewStaticText;
begin
DebugMsg('InitCustomPages','wpLicense');
btnInstall := TNewButton.Create(WizardForm);
with btnInstall do
begin
Parent := WizardForm;
Width := WizardForm.NextButton.Width;
Height := WizardForm.NextButton.Height;
Left := WizardForm.NextButton.Left;
Top := WizardForm.NextButton.Top;
Caption := CustomMessage('Install');
Default := True;
Visible := False;
OnClick := @InstallOnClick;
end;
//used to measure text width
MeasureLabel := TNewStaticText.Create(WizardForm);
with MeasureLabel do
begin
Parent := WizardForm;
Left := 0;
Top := 0;
AutoSize := True;
Caption := CustomMessage('Customize');
end;
btnCustomize := TNewButton.Create(WizardForm);
with btnCustomize do
begin
Parent := WizardForm;
Width := WizardForm.NextButton.Width;
if Width < (MeasureLabel.Width + ScaleX(8)) then
Width := MeasureLabel.Width + ScaleX(8);
Height := WizardForm.NextButton.Height;
Left := WizardForm.ClientWidth - (WizardForm.CancelButton.Left + WizardForm.CancelButton.Width);
//Left := WizardForm.BackButton.Left;
Top := WizardForm.NextButton.Top;
Visible := False;
Caption := CustomMessage('Customize');
OnClick := @CustomizeOnClick;
end;
MeasureLabel.Free;
end;
//2. LICENSE
procedure InfoBeforeLikeLicense();
begin
WizardForm.InfoBeforeClickLabel.Visible := False;
WizardForm.InfoBeforeMemo.Height := WizardForm.InfoBeforeMemo.Height + WizardForm.InfoBeforeMemo.Top - WizardForm.InfoBeforeClickLabel.Top;
WizardForm.InfoBeforeMemo.Top := WizardForm.InfoBeforeClickLabel.Top;
end;
//3. INSTALL DIR (no customizations)
//4. COMPONENTS: Add panel with description on click, to the right of the list
var
lblComponentDescription: TNewStaticText;
procedure ComponentsListOnClick(pSender: TObject); forward;
procedure SelectComponentsFaceLift();
var pnlDescription: TPanel;
lblDescription: TNewStaticText;
begin
DebugMsg('SelectComponentsFaceLift','');
if WizardForm.ComponentsList.Width = WizardForm.SelectComponentsPage.Width then
WizardForm.ComponentsList.Width := Round(WizardForm.ComponentsList.Width * 0.6)
else
exit;
DebugMsg('SelectComponentsFaceLift','2');
WizardForm.ComponentsList.OnClick := @ComponentsListOnClick;
lblDescription := TNewStaticText.Create(WizardForm.ComponentsList.Parent)
with lblDescription do
begin
Left := WizardForm.ComponentsList.Left + WizardForm.ComponentsList.Width + ScaleX(16);
Top := WizardForm.ComponentsList.Top;
AutoSize := True;
Caption := CustomMessage('ComponentsDescription');
end;
pnlDescription := TPanel.Create(WizardForm.ComponentsList.Parent);
with pnlDescription do
begin
Parent := WizardForm.ComponentsList.Parent;
Left := WizardForm.ComponentsList.Left + WizardForm.ComponentsList.Width + ScaleX(8);
Width := WizardForm.TypesCombo.Width - WizardForm.ComponentsList.Width - ScaleX(8);
ParentColor := True;
BevelOuter := bvLowered;
BevelInner := bvRaised;
Top := WizardForm.ComponentsList.Top + Round(lblDescription.Height * 0.4);
Height := WizardForm.ComponentsList.Height - Round(lblDescription.Height * 0.4);
end;
lblDescription.Parent := WizardForm.ComponentsList.Parent; //place lblDescription above pnlDescription
lblComponentDescription := TNewStaticText.Create(pnlDescription);
with lblComponentDescription do
begin
Parent := pnlDescription;
Left := ScaleX(8);
WordWrap := True;
AutoSize := False;
Width := Parent.Width - ScaleX(16);
Height := Parent.Height - ScaleY(20);
Top := ScaleY(12);
end;
end;
procedure ComponentsListOnClick(pSender: TObject);
var i,j: Integer;
Components: TArrayOfString;
ComponentDesc: String;
begin
DebugMsg('ComponentsListOnClick','');
Components := ['Gimp','Deps','Debug', 'Ghostscript','Lua','Python','Translations','MyPaint','Gimp32'];
ComponentDesc := '';
for i := 0 to TNewCheckListBox(pSender).Items.Count - 1 do
if TNewCheckListBox(pSender).Selected[i] then
begin
for j := 0 to Length(Components) - 1 do
begin
if TNewCheckListBox(pSender).Items.Strings[i] = CustomMessage('Components' + Components[j]) then
ComponentDesc := CustomMessage('Components' + Components[j] + 'Description');
end;
if ComponentDesc <> '' then
break;
end;
lblComponentDescription.Caption := ComponentDesc;
end;
//5. TAKS (no customizations)
//6. READY: Add formatting support to text box on ready page
var
ReadyMemoRichText: String;
procedure ReadyFaceLift();
var rtfNewReadyMemo: TRichEditViewer;
begin
DebugMsg('ReadyFaceLift','');
WizardForm.ReadyMemo.Visible := False;
rtfNewReadyMemo := TRichEditViewer.Create(WizardForm.ReadyMemo.Parent);
with rtfNewReadyMemo do
begin
Parent := WizardForm.ReadyMemo.Parent;
Scrollbars := ssVertical;
Color := WizardForm.Color;
BevelKind := bkFlat;
BorderStyle := bsNone;
UseRichEdit := True;
RTFText := ReadyMemoRichText;
ReadOnly := True;
Left := WizardForm.ReadyMemo.Left;
Top := WizardForm.ReadyMemo.Top;
Width := WizardForm.ReadyMemo.Width;
Height := WizardForm.ReadyMemo.Height;
Visible := True;
end;
end;
function CopyW(const S: String; const Start, Len: Integer): String; //work-around for unicode-related bug in Copy
begin
Result := Copy(S, Start, Len);
end;
function Unicode2RTF(const pIn: String): String; //convert to RTF-compatible unicode
var i: Integer;
c: SmallInt;
begin
Result := '';
for i := 1 to Length(pIn) do
if Ord(pIn[i]) <= 127 then
begin
Result := Result + pIn[i];
end else
begin
c := Ord(pIn[i]); //code points above 7FFF must be expressed as negative numbers
Result := Result + '\u' + IntToStr(c) + '?';
end;
end;
const
RTFPara = '\par ';
function ParseReadyMemoText(pSpaces,pText: String): String;
var sTemp: String;
begin
sTemp := CopyW(pText,Pos(#10,pText)+1,Length(pText));
sTemp := Replace('{','\{',sTemp);
sTemp := Replace('\','\\',sTemp);
sTemp := Replace(#13#10,RTFpara,sTemp);
sTemp := Replace(pSpaces,'',sTemp);
sTemp := '\b ' + CopyW(pText,1,Pos(#13,pText)-1) + '\par\sb0' +
'\li284\b0 ' + sTemp + '\par \pard';
Result := Unicode2RTF(sTemp);
end;
const
RTFHeader = '{\rtf1\deff0{\fonttbl{\f0\fswiss\fprq2\fcharset0 Segoe UI;}{\f1\fnil\fcharset2 Segoe UI Symbol;}}\viewkind4\uc1\fs18';
//RTFBullet = '{\pntext\f1\''B7\tab}';
function UpdateReadyMemo(pSpace, pNewLine, pMemoUserInfo, pMemoDirInfo, pMemoTypeInfo, pMemoComponentsInfo, pMemoGroupInfo, pMemoTasksInfo: String): String;
var sText: String;
bShowAssoc: Boolean;
i,j: Integer;
begin
DebugMsg('UpdateReadyMemo','');
(* Prepare the text for new Ready Memo *)
sText := RTFHeader;
if pMemoDirInfo <> '' then
sText := sText + ParseReadyMemoText(pSpace,pMemoDirInfo) + '\sb100';
sText := sText + ParseReadyMemoText(pSpace,pMemoTypeInfo);
sText := sText + '\sb100' + ParseReadyMemoText(pSpace,pMemoComponentsInfo);
If pMemoTasksInfo<>'' then
sText := sText + '\sb100' + ParseReadyMemoText(pSpace,pMemoTasksInfo);
ReadyMemoRichText := Copy(sText,1,Length(sText)-6) + '}';
Result := 'If you see this, something went wrong';
end;
//7.1 BEFORE INSTALL
//Unistall old version of GIMP (only if needed)
const
UNINSTALL_MAX_WAIT_TIME = 10000;
UNINSTALL_CHECK_TIME = 250;
type
TRemoveOldGIMPResult = (rogContinue, rogRestartRequired, rogUninstallFailed, rogCantUninstall);
procedure DoUninstall(const UninstStr, InstallDir: String; const pInfoLabel: TNewStaticText; var oResult: TRemoveOldGIMPResult);
var InResult: TRemoveOldGIMPResult;
ResultCode, i: Integer;
begin
InResult := oResult;
DebugMsg('DoUninstall','Uninstall string: ' + UninstStr);
//when installing to same directory, assume that restart is required by default ...
if LowerCase(RemoveBackslashUnlessRoot(InstallDir)) = LowerCase(RemoveBackslashUnlessRoot(ExpandConstant('{app}'))) then
oResult := rogRestartRequired
else
oResult := InResult;
pInfoLabel.Caption := InstallDir;
if not Exec('>',UninstStr,'',SW_SHOW,ewWaitUntilTerminated,ResultCode) then
begin
DebugMsg('DoUninstall','Exec('+UninstStr+') failed: ' + IntToStr(ResultCode));
if not DirExists(InstallDir) then //old install directory doesn't exist, assume it was deleted, and Registry info is orphaned
begin
DebugMsg('DoUninstall','Install directory doesn'#39't exist: ' + InstallDir + ', resuming install');
oResult := InResult
end else
begin
oResult := rogUninstallFailed;
end;
exit;
end;
DebugMsg('DoUninstall','Exec succeeded, uninstaller result: ' + IntToStr(ResultCode));
//... unless the complete installation directory was removed on uninstall
i := 0;
while i < (UNINSTALL_MAX_WAIT_TIME / UNINSTALL_CHECK_TIME) do
begin
if not DirExists(ExpandConstant('{app}')) then
begin
DebugMsg('DoUninstall','Existing GIMP directory removed, restoring previous restart requirement');
oResult := InResult; //restore previous result
break;
end;
DebugMsg('DoUninstall','Waiting for ' + ExpandConstant('{app}') + ' to disappear [' + IntToStr(i) + ']');
Sleep(UNINSTALL_CHECK_TIME); //it may take a few seconds for the uninstaller to remove the directory after it's exited
Inc(i);
end;
end;
function RemoveOldGIMPVersions(): TRemoveOldGIMPResult;
var lblInfo1,lblInfo2: TNewStaticText;
RootKey: Integer;
OldPath, UninstallString, WhichStr: String;
begin
Result := rogContinue;
lblInfo1 := TNewStaticText.Create(WizardForm.PreparingPage);
with lblInfo1 do
begin
Parent := WizardForm.PreparingPage;
Left := 0;
Top := 0;
AutoSize := True;
WordWrap := True;
Width := WizardForm.PreparingPage.ClientWidth;
Caption := CustomMessage('RemovingOldVersion');
end;
lblInfo2 := TNewStaticText.Create(WizardForm.PreparingPage);
with lblInfo2 do
begin
Parent := WizardForm.PreparingPage;
Left := 0;
AutoSize := True;
WordWrap := True;
Width := WizardForm.PreparingPage.ClientWidth;
Top := lblInfo1.Height + ScaleY(8);
end;
if ExpandConstant('{param:debugresume|0}') = '1' then
Result := rogRestartRequired; //for testing
if Is64BitInstallMode() then
RootKey := HKLM32
else
RootKey := HKLM;
if RegValueExists(RootKey,'Software\Microsoft\Windows\CurrentVersion\Uninstall\WinGimp-2.0_is1',
'Inno Setup: App Path') then
begin
if RegQueryStringValue(RootKey,'Software\Microsoft\Windows\CurrentVersion\Uninstall\WinGimp-2.0_is1',
'Inno Setup: App Path',OldPath) then
begin
DebugMsg('RemoveOldGIMPVersions','Found legacy GIMP install, removing');
if RegValueExists(RootKey,'Software\Microsoft\Windows\CurrentVersion\Uninstall\WinGimp-2.0_is1',
'QuietUninstallString') then
WhichStr := 'QuietUninstallString'
else if RegValueExists(RootKey,'Software\Microsoft\Windows\CurrentVersion\Uninstall\WinGimp-2.0_is1',
'UninstallString') then
WhichStr := 'UninstallString'
else
begin
Result := rogCantUninstall;
exit;
end;
if not RegQueryStringValue(RootKey,'Software\Microsoft\Windows\CurrentVersion\Uninstall\WinGimp-2.0_is1',
WhichStr,UninstallString) then
begin
Result := rogCantUninstall;
exit;
end;
if WhichStr = 'UninstallString' then
UninstallString := UninstallString + ' /SILENT';
UninstallString := UninstallString + ' /NORESTART';
DoUninstall(UninstallString, OldPath, lblInfo2, Result);
end;
end;
lblInfo1.Free;
lblInfo2.Free;
end;
procedure CreateRunOnceEntry; forward;
function PrepareToInstall(var pNeedsRestart: Boolean): String;
var ChecksumBefore, ChecksumAfter: String;
RemoveResult: TRemoveOldGIMPResult;
begin
ChecksumBefore := MakePendingFileRenameOperationsChecksum;
RemoveResult := RemoveOldGIMPVersions;
if RemoveResult = rogRestartRequired then //old version was uninstalled, but something was left behind, so to be safe a reboot
begin //is enforced - this can only happen when reusing install directory
DebugMsg('PrepareToInstall','RemoveOldGIMPVersions requires restart');
ChecksumAfter := MakePendingFileRenameOperationsChecksum;
if (ChecksumBefore <> ChecksumAfter) or (ExpandConstant('{param:debugresume|0}') = '1') then
begin //this check is most likely redundant, since the uninstaller will be added to pending rename operations
CreateRunOnceEntry;
pNeedsRestart := True;
Result := CustomMessage('RebootRequiredFirst');
end;
end else
if RemoveResult = rogContinue then
begin
DebugMsg('PrepareToInstall','RemoveOldGIMPVersions finished successfully');
Result := ''; //old version was uninstalled successfully, nothing was left behind, so install can continue immediately
end else
if RemoveResult = rogUninstallFailed then
begin
DebugMsg('PrepareToInstall','RemoveOldGIMPVersions failed to uninstall old GIMP version');
Result := FmtMessage(CustomMessage('RemovingOldVersionFailed'),['{#GIMP_VERSION}',ExpandConstant('{app}')]);
end else
if RemoveResult = rogCantUninstall then
begin
DebugMsg('PrepareToInstall','RemoveOldGIMPVersions failed to uninstall old GIMP version [1]');
Result := FmtMessage(CustomMessage('RemovingOldVersionCantUninstall'),['{#GIMP_VERSION}',ExpandConstant('{app}')]);
end else
begin
DebugMsg('PrepareToInstall','Internal error 11');
Result := FmtMessage(CustomMessage('InternalError'),['11']); //should never happen
end;
end;
//remove .debug files from previous installs
//there's no built-in way in Inno to recursively delete files with wildcard+extension
procedure RemoveDebugFilesFromDir(pDir: String; var pDirectories: TArrayOfString);
var FindRec: TFindRec;
begin
DebugMsg('RemoveDebugFilesFromDir', pDir);
WizardForm.FilenameLabel.Caption := pDir;
if FindFirst(AddBackSlash(pDir) + '*', FindRec) then
begin
try
repeat
if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then
begin
if (Length(FindRec.Name) > 6) and (LowerCase(Copy(FindRec.Name, Length(FindRec.Name) - 5, 6)) = '.debug') then
begin
DebugMsg('RemoveDebugFilesFromDir', '> ' + FindRec.Name);
DeleteFile(AddBackSlash(pDir) + FindRec.Name);
end;
end else
begin
if (FindRec.Name <> '.') and (FindRec.Name <> '..') then
begin
SetArrayLength(pDirectories, GetArrayLength(pDirectories) + 1);
pDirectories[GetArrayLength(pDirectories) - 1] := AddBackSlash(pDir) + FindRec.Name;
end;
end;
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;
procedure RemoveDebugFiles();
var Directories: TArrayOfString;
Index: Integer;
begin
SetArrayLength(Directories, 1);
Directories[0] := ExpandConstant('{app}');
Index := 0;
WizardForm.StatusLabel.Caption := CustomMessage('RemovingOldFiles');
repeat
RemoveDebugFilesFromDir(Directories[Index], Directories);
Inc(Index);
until Index = GetArrayLength(Directories);
end;
procedure AssociationsCleanUp(); forward;
//Check if icon exists in registry
function CheckRegValueExists(const SubKeyName, ValueName: String): Boolean;
begin
Result := RegValueExists(HKEY_AUTO, SubKeyName, ValueName);
DebugMsg('CheckRegValueExists',SubKeyName + ', ' + ValueName + ': ' + BoolToStr(Result));
end;
//Legacy arch check
function Check3264(const pWhich: String): Boolean;
begin
if pWhich = '64' then //x64 or arm64
Result := Is64BitInstallMode() and (not Force32bitInstall)
else if pWhich = '32' then
Result := (not Is64BitInstallMode()) or Force32bitInstall
else if pWhich = 'x64' then
Result := Is64BitInstallMode() and IsX64 and (not Force32bitInstall)
else if pWhich = 'arm64' then
Result := Is64BitInstallMode() and IsARM64 and (not Force32bitInstall)
else
RaiseException('Unknown check');
end;
//some programs improperly install libraries to the System32 directory, which then causes problems with plugins
//this function checks if such file exists in System32, and lets setup update the file when it exists
function BadSysDLL(const pFile: String; const pPlatform: Integer): Boolean;
var OldRedir: Boolean;
begin
Result := False;
if pPlatform = 64 then
begin
if Is64BitInstallMode() then //only check when installing in 64bit mode
begin
OldRedir := EnableFsRedirection(False);
DebugMsg('BadSysDLL','64: ' + ExpandConstant('{sys}\' + pFile));
Result := FileExists(ExpandConstant('{sys}\' + pFile));
EnableFsRedirection(OldRedir);
end;
end
else if pPlatform = 32 then
begin
if Is64BitInstallMode() then //check 32bit system directory on x64 windows
begin
DebugMsg('BadSysDLL','32on64: ' + ExpandConstant('{syswow64}\' + pFile));
Result := FileExists(ExpandConstant('{syswow64}\' + pFile));
end
else
begin
DebugMsg('BadSysDLL','32: ' + ExpandConstant('{sys}\' + pFile));
Result := FileExists(ExpandConstant('{sys}\' + pFile));
end;
end
else
begin
RaiseException('Unsupported platform');
end;
DebugMsg('BadSysDLL','Result: ' + BoolToStr(Result));
end;
//Override some 'etc' configs (if requested)
const
CONFIG_OVERRIDE_PARAM = 'configoverride';
function DoConfigOverride: Boolean;
var i: Integer;
begin
if ConfigOverride = coUndefined then
begin
DebugMsg('DoConfigOverride', 'First call');
Result := False;
ConfigOverride := coDontOverride;
for i := 0 to ParamCount() do //use ParamCount/ParamStr to allow specifying /configoverride without any parameters
if LowerCase(Copy(ParamStr(i),1,15)) = '/' + CONFIG_OVERRIDE_PARAM then
begin
Result := True;
ConfigOverride := coOverride;
break;
end;
end
else if ConfigOverride = coOverride then
Result := True
else
Result := False;
DebugMsg('DoConfigOverride', BoolToStr(Result));
end;
function GetExternalConfDir(Unused: String): String;
begin
if ExpandConstant('{param:' + CONFIG_OVERRIDE_PARAM + '|<>}') = '<>' then
Result := ExpandConstant('{src}\')
else
Result := ExpandConstant('{param:' + CONFIG_OVERRIDE_PARAM + '|<>}\');
DebugMsg('GetExternalConfDir', Result);
end;
function CheckExternalConf(const pFile: String): Boolean;
begin
if not DoConfigOverride then //no config override
Result := False
else
begin
if FileExists(GetExternalConfDir('') + pFile) then //config file override only applies when that file exists
Result := True
else
Result := False;
end;
DebugMsg('CheckExternalConf', pFile + ': ' + BoolToStr(Result));
end;
//7.2 INSTALL: show GIMP text (aka billboard) above progress bar
#if Defined(GIMP_UNSTABLE) && GIMP_UNSTABLE != ""
const
GIMP_URL = 'https://gimp.org/downloads/devel/';
#else
const
GIMP_URL = 'https://gimp.org/downloads/';
#endif
procedure lblURL_OnClick(Sender: TObject);
var ErrorCode: Integer;
begin
ShellExecAsOriginalUser('',GIMP_URL,'','',SW_SHOW,ewNoWait,ErrorCode);
end;
function MeasureLabel(const pText: String): Integer; //WordWrap + AutoSize works better with TNewStaticText than with TLabel,
var lblMeasure: TNewStaticText; //abuse this
begin
lblMeasure := TNewStaticText.Create(WizardForm.InstallingPage);
with lblMeasure do
begin
Parent := WizardForm.InstallingPage;
AutoSize := True;
WordWrap := True;
Width := Parent.ClientWidth;
Caption := pText;
Result := Height;
end;
lblMeasure.Free;
end;
procedure InstallingFaceLift();
var lblMessage1,lblURL,lblMessage2: TLabel; //TNewStaticText doesn't support alignment
begin
with WizardForm.ProgressGauge do
begin
Height := ScaleY(21);
Top := WizardForm.InstallingPage.ClientHeight - Top - Height;
WizardForm.StatusLabel.Top := Top - WizardForm.FilenameLabel.Height - ScaleY(4);
WizardForm.FilenameLabel.Top := Top + Height + ScaleY(4);
end;
lblMessage1 := TLabel.Create(WizardForm.InstallingPage);
with lblMessage1 do
begin
Parent := WizardForm.InstallingPage;
Alignment := taCenter;
WordWrap := True;
AutoSize := False;
Width := WizardForm.InstallingPage.ClientWidth;
Height := MeasureLabel(CustomMessage('Billboard1'));
Caption := CustomMessage('Billboard1');
end;
lblURL := TLabel.Create(WizardForm.InstallingPage);
with lblURL do
begin
Parent := WizardForm.InstallingPage;
AutoSize := True;
WordWrap := False;
Font.Color := GetSysColor(COLOR_HOTLIGHT);
Font.Style := [fsUnderline];
Font.Size := 12;
Cursor := crHand;
OnClick := @lblURL_OnClick;
Caption := GIMP_URL;
Left := Integer(WizardForm.InstallingPage.ClientWidth / 2 - Width / 2);
end;
lblMessage2 := TLabel.Create(WizardForm.InstallingPage);
with lblMessage2 do
begin
Parent := WizardForm.InstallingPage;
Alignment := taCenter;
WordWrap := True;
AutoSize := False;
Width := WizardForm.InstallingPage.ClientWidth;
Height := MeasureLabel(CustomMessage('Billboard2'));
Caption := CustomMessage('Billboard2');
end;
lblMessage1.Top := Integer(WizardForm.StatusLabel.Top / 2 -
(lblMessage1.Height + ScaleY(4) + lblURL.Height + ScaleY(4) + lblMessage2.Height) / 2);
lblURL.Top := lblMessage1.Top + lblMessage1.Height + ScaleY(4);
lblMessage2.Top := lblURL.Top + lblURL.Height + ScaleY(4);
end;
//7.3 AFTER INSTALL
//Create .interp files
procedure PrepareInterp();
var InterpFile,InterpContent,LuaBin: String;
begin
#ifdef PYTHON
if IsComponentSelected('py32') or IsComponentSelected('py64') or IsComponentSelected('pyARM64') then
begin
StatusLabel(CustomMessage('SettingUpPyGimp'),'');
InterpFile := ExpandConstant('{app}\lib\gimp\{#GIMP_API_VERSION}\interpreters\pygimp.interp');
DebugMsg('PrepareInterp','Writing interpreter file for gimp-python: ' + InterpFile);
#ifdef GIMP_UNSTABLE
#define PYTHON="python.exe"
#else
#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;
if not SaveStringToUTF8File(InterpFile,InterpContent,False) then
begin
DebugMsg('PrepareInterp','Problem writing the file. [' + InterpContent + ']');
SuppressibleMsgBox(CustomMessage('ErrorUpdatingPython') + ' (2)',mbInformation,mb_ok,IDOK);
end;
end;
#endif
#ifdef LUA
if IsComponentSelected('lua32') or IsComponentSelected('lua64') or IsComponentSelected('luaARM64') then
begin
InterpFile := ExpandConstant('{app}\lib\gimp\{#GIMP_API_VERSION}\interpreters\lua.interp');
DebugMsg('PrepareInterp','Writing interpreter file for lua: ' + InterpFile);
LuaBin := 'luajit.exe'
InterpContent := 'lua=' + ExpandConstant('{app}\bin\') + LuaBin + #10 +
'luajit=' + ExpandConstant('{app}\bin\') + LuaBin + #10 +
'/usr/bin/luajit=' + ExpandConstant('{app}\bin\') + LuaBin + #10 +
'/usr/bin/lua=' + ExpandConstant('{app}\bin\') + LuaBin + #10 +
':Lua:E::lua::' + LuaBin + ':'#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;
end;
#endif
// !!! use comma for binfmt delimiter and full Windows path in interpreter field of binfmt
begin
InterpFile := ExpandConstant('{app}\lib\gimp\{#GIMP_API_VERSION}\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-{#GIMP_API_VERSION}.exe') + #10 +
'gimp-script-fu-interpreter-{#GIMP_API_VERSION}=' + ExpandConstant('{app}\bin\gimp-script-fu-interpreter-{#GIMP_API_VERSION}.exe') + #10 +
'/usr/bin/gimp-script-fu-interpreter=' + ExpandConstant('{app}\bin\gimp-script-fu-interpreter-{#GIMP_API_VERSION}.exe') + #10 +
',ScriptFu,E,,scm,,' + ExpandConstant('{app}\bin\gimp-script-fu-interpreter-{#GIMP_API_VERSION}.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; //PrepareInterp
//Create .env files
procedure PrepareGimpEnvironment();
var EnvFile,Env: String;
begin
StatusLabel(CustomMessage('SettingUpEnvironment'),'');
//set PATH to be used by plug-ins
EnvFile := ExpandConstant('{app}\lib\gimp\{#GIMP_API_VERSION}\environ\default.env');
DebugMsg('PrepareGimpEnvironment','Setting environment in ' + EnvFile);
Env := #10'PATH=${gimp_installation_dir}\bin';
if IsComponentSelected('gimp32on64') then
begin
Env := Env + ';${gimp_installation_dir}\32\bin' + #10;
end else
begin
Env := Env + #10;
end;
DebugMsg('PrepareGimpEnvironment','Appending ' + Env);
if not SaveStringToUTF8File(EnvFile,Env,True) then
begin
DebugMsg('PrepareGimpEnvironment','Problem appending');
SuppressibleMsgBox(FmtMessage(CustomMessage('ErrorChangingEnviron'),[EnvFile]),mbInformation,mb_ok,IDOK);
end;
// Disable check-update when run with specific option
if ExpandConstant('{param:disablecheckupdate|false}') = 'true' then
begin
EnvFile := ExpandConstant('{app}\share\gimp\{#GIMP_API_VERSION}\gimp-release');
DebugMsg('DisableCheckUpdate','Disabling check-update in ' + EnvFile);
Env := 'check-update=false'
if not SaveStringToUTF8File(EnvFile,Env,True) then
begin
DebugMsg('PrepareGimpEnvironment','Problem appending');
SuppressibleMsgBox(FmtMessage(CustomMessage('ErrorChangingEnviron'),[EnvFile]),mbInformation,mb_ok,IDOK);
end;
end;
end;//PrepareGimpEnvironment
//Unistaller info
procedure SaveToUninstInf(const pText: AnsiString); forward;
procedure SaveToUninstInf(const pText: AnsiString);
var sUnInf: String;
sOldContent: String;
begin
sUnInf := ExpandConstant('{app}\uninst\uninst.inf');
if not FileExists(sUnInf) then //save small header
SaveStringToUTF8File(sUnInf,#$feff+'#Additional uninstall tasks'#13#10+ //#$feff BOM is required for LoadStringsFromFile
'#This file uses UTF-8 encoding'#13#10+
'#'#13#10+
'#Empty lines and lines beginning with # are ignored'#13#10+
'#'#13#10+
'#Add uninstallers for GIMP add-ons that should be removed together with GIMP like this:'#13#10+
'#Run:<description>/<full path to uninstaller>/<parameters for automatic uninstall>'#13#10+
'#'#13#10+
'#The file is parsed in reverse order' + #13#10 +
'' + #13#10 //needs '' in front, otherwise preprocessor complains
,False)
else
begin
LoadStringFromUTF8File(sUnInf,sOldContent);
if Pos(#13#10+pText+#13#10,sOldContent) > 0 then //don't write duplicate lines
exit;
end;
SaveStringToUTF8File(sUnInf,pText+#13#10,True);
end;
#include "util_uninst.isi"
//8. DONE/FINAL PAGE (no customizations)
//INITIALIZE AND ORDER INSTALLER PAGES
procedure InitializeWizard();
begin
UpdateWizardImages();
InitCustomPages();
end;
function ShouldSkipPage(pPageID: Integer): Boolean;
begin
DebugMsg('ShouldSkipPage','ID: '+IntToStr(pPageID));
Result := ((InstallMode = imSimple) or (InstallMode = imRebootContinue)) and (pPageID <> wpFinished);
if Result then
DebugMsg('ShouldSkipPage','Yes')
else
DebugMsg('ShouldSkipPage','No');
end;
procedure CurPageChanged(pCurPageID: Integer);
begin
DebugMsg('CurPageChanged','ID: '+IntToStr(pCurPageID));
case pCurPageID of
wpWelcome:
PrepareWelcomePage();
wpInfoBefore:
InfoBeforeLikeLicense();
wpSelectComponents:
SelectComponentsFaceLift();
wpReady:
ReadyFaceLift();
wpInstalling:
InstallingFaceLift();
end;
end;
procedure CurStepChanged(pCurStep: TSetupStep);
begin
case pCurStep of
ssInstall:
begin
RemoveDebugFiles();
AssociationsCleanup();
end;
ssPostInstall:
begin
PrepareInterp();
PrepareGimpEnvironment();
end;
end;
end;
//Reboot if needed
#include "util_rebootcontinue.isi"
#expr SaveToFile(AddBackslash(SourcePath) + "Preprocessed.iss")