summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--misc/dist/windows/.gitignore2
-rw-r--r--misc/dist/windows/README.md17
-rw-r--r--misc/dist/windows/godot.iss63
-rw-r--r--misc/dist/windows/modpath.pas219
4 files changed, 301 insertions, 0 deletions
diff --git a/misc/dist/windows/.gitignore b/misc/dist/windows/.gitignore
new file mode 100644
index 0000000000..b615268279
--- /dev/null
+++ b/misc/dist/windows/.gitignore
@@ -0,0 +1,2 @@
+# Ignore both the Godot executable and generated installers.
+*.exe
diff --git a/misc/dist/windows/README.md b/misc/dist/windows/README.md
new file mode 100644
index 0000000000..6df66437a7
--- /dev/null
+++ b/misc/dist/windows/README.md
@@ -0,0 +1,17 @@
+# Windows installer
+
+`godot.iss` is an [Inno Setup](https://jrsoftware.org/isinfo.php) installer file
+that can be used to build a Windows installer. The generated installer is able
+to run without Administrator privileges and can optionally add Godot to the
+user's `PATH` environment variable.
+
+To use Inno Setup on Linux, use [innoextract](https://constexpr.org/innoextract/)
+to extract the Inno Setup installer then run `ISCC.exe` using
+[WINE](https://www.winehq.org/).
+
+## Building
+
+- Place a Godot editor executable in this folder and rename it to `godot.exe`.
+- Run the Inno Setup Compiler (part of the Inno Setup suite) on the `godot.iss` file.
+
+If everything succeeds, an installer will be generated in this folder.
diff --git a/misc/dist/windows/godot.iss b/misc/dist/windows/godot.iss
new file mode 100644
index 0000000000..f7aa8249bc
--- /dev/null
+++ b/misc/dist/windows/godot.iss
@@ -0,0 +1,63 @@
+#define MyAppName "Godot Engine"
+#define MyAppVersion "4.0.dev"
+#define MyAppPublisher "Godot Engine contributors"
+#define MyAppURL "https://godotengine.org/"
+#define MyAppExeName "godot.exe"
+
+[Setup]
+AppId={{60D07AAA-400E-40F5-B073-A796C34D9D78}
+AppName={#MyAppName}
+AppVersion={#MyAppVersion}
+; Don't add "version {version}" to the installed app name in the Add/Remove Programs
+; dialog as it's redundant with the Version field in that same dialog.
+AppVerName={#MyAppName}
+AppPublisher={#MyAppPublisher}
+AppPublisherURL={#MyAppURL}
+AppSupportURL={#MyAppURL}
+AppUpdatesURL={#MyAppURL}
+AppComments=Godot Engine editor
+ChangesEnvironment=yes
+DefaultDirName={localappdata}\Godot
+DefaultGroupName=Godot Engine
+AllowNoIcons=yes
+UninstallDisplayIcon={app}\{#MyAppExeName}
+#ifdef App32Bit
+ OutputBaseFilename=godot-setup-x86
+#else
+ OutputBaseFilename=godot-setup-x86_64
+ ArchitecturesAllowed=x64
+ ArchitecturesInstallIn64BitMode=x64
+#endif
+Compression=lzma
+SolidCompression=yes
+PrivilegesRequired=lowest
+
+[Languages]
+Name: "english"; MessagesFile: "compiler:Default.isl"
+
+[Tasks]
+Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
+Name: "modifypath"; Description: "Add Godot to PATH environment variable"
+
+[Files]
+Source: "{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
+
+[Icons]
+Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
+Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
+
+[Run]
+Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
+
+[Code]
+const
+ ModPathName = 'modifypath';
+ ModPathType = 'user';
+
+function ModPathDir(): TArrayOfString;
+begin
+ setArrayLength(Result, 1)
+ Result[0] := ExpandConstant('{app}');
+end;
+
+#include "modpath.pas"
diff --git a/misc/dist/windows/modpath.pas b/misc/dist/windows/modpath.pas
new file mode 100644
index 0000000000..c55ec60163
--- /dev/null
+++ b/misc/dist/windows/modpath.pas
@@ -0,0 +1,219 @@
+// ----------------------------------------------------------------------------
+//
+// Inno Setup Ver: 5.4.2
+// Script Version: 1.4.2
+// Author: Jared Breland <jbreland@legroom.net>
+// Homepage: http://www.legroom.net/software
+// License: GNU Lesser General Public License (LGPL), version 3
+// http://www.gnu.org/licenses/lgpl.html
+//
+// Script Function:
+// Allow modification of environmental path directly from Inno Setup installers
+//
+// Instructions:
+// Copy modpath.iss to the same directory as your setup script
+//
+// Add this statement to your [Setup] section
+// ChangesEnvironment=true
+//
+// Add this statement to your [Tasks] section
+// You can change the Description or Flags
+// You can change the Name, but it must match the ModPathName setting below
+// Name: modifypath; Description: &Add application directory to your environmental path; Flags: unchecked
+//
+// Add the following to the end of your [Code] section
+// ModPathName defines the name of the task defined above
+// ModPathType defines whether the 'user' or 'system' path will be modified;
+// this will default to user if anything other than system is set
+// setArrayLength must specify the total number of dirs to be added
+// Result[0] contains first directory, Result[1] contains second, etc.
+// const
+// ModPathName = 'modifypath';
+// ModPathType = 'user';
+//
+// function ModPathDir(): TArrayOfString;
+// begin
+// setArrayLength(Result, 1);
+// Result[0] := ExpandConstant('{app}');
+// end;
+// #include "modpath.iss"
+// ----------------------------------------------------------------------------
+
+procedure ModPath();
+var
+ oldpath: String;
+ newpath: String;
+ updatepath: Boolean;
+ pathArr: TArrayOfString;
+ aExecFile: String;
+ aExecArr: TArrayOfString;
+ i, d: Integer;
+ pathdir: TArrayOfString;
+ regroot: Integer;
+ regpath: String;
+
+begin
+ // Get constants from main script and adjust behavior accordingly
+ // ModPathType MUST be 'system' or 'user'; force 'user' if invalid
+ if ModPathType = 'system' then begin
+ regroot := HKEY_LOCAL_MACHINE;
+ regpath := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
+ end else begin
+ regroot := HKEY_CURRENT_USER;
+ regpath := 'Environment';
+ end;
+
+ // Get array of new directories and act on each individually
+ pathdir := ModPathDir();
+ for d := 0 to GetArrayLength(pathdir)-1 do begin
+ updatepath := true;
+
+ // Modify WinNT path
+ if UsingWinNT() = true then begin
+
+ // Get current path, split into an array
+ RegQueryStringValue(regroot, regpath, 'Path', oldpath);
+ oldpath := oldpath + ';';
+ i := 0;
+
+ while (Pos(';', oldpath) > 0) do begin
+ SetArrayLength(pathArr, i+1);
+ pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1);
+ oldpath := Copy(oldpath, Pos(';', oldpath)+1, Length(oldpath));
+ i := i + 1;
+
+ // Check if current directory matches app dir
+ if pathdir[d] = pathArr[i-1] then begin
+ // if uninstalling, remove dir from path
+ if IsUninstaller() = true then begin
+ continue;
+ // if installing, flag that dir already exists in path
+ end else begin
+ updatepath := false;
+ end;
+ end;
+
+ // Add current directory to new path
+ if i = 1 then begin
+ newpath := pathArr[i-1];
+ end else begin
+ newpath := newpath + ';' + pathArr[i-1];
+ end;
+ end;
+
+ // Append app dir to path if not already included
+ if (IsUninstaller() = false) AND (updatepath = true) then
+ newpath := newpath + ';' + pathdir[d];
+
+ // Write new path
+ RegWriteStringValue(regroot, regpath, 'Path', newpath);
+
+ // Modify Win9x path
+ end else begin
+
+ // Convert to shortened dirname
+ pathdir[d] := GetShortName(pathdir[d]);
+
+ // If autoexec.bat exists, check if app dir already exists in path
+ aExecFile := 'C:\AUTOEXEC.BAT';
+ if FileExists(aExecFile) then begin
+ LoadStringsFromFile(aExecFile, aExecArr);
+ for i := 0 to GetArrayLength(aExecArr)-1 do begin
+ if IsUninstaller() = false then begin
+ // If app dir already exists while installing, skip add
+ if (Pos(pathdir[d], aExecArr[i]) > 0) then
+ updatepath := false;
+ break;
+ end else begin
+ // If app dir exists and = what we originally set, then delete at uninstall
+ if aExecArr[i] = 'SET PATH=%PATH%;' + pathdir[d] then
+ aExecArr[i] := '';
+ end;
+ end;
+ end;
+
+ // If app dir not found, or autoexec.bat didn't exist, then (create and) append to current path
+ if (IsUninstaller() = false) AND (updatepath = true) then begin
+ SaveStringToFile(aExecFile, #13#10 + 'SET PATH=%PATH%;' + pathdir[d], True);
+
+ // If uninstalling, write the full autoexec out
+ end else begin
+ SaveStringsToFile(aExecFile, aExecArr, False);
+ end;
+ end;
+ end;
+end;
+
+// Split a string into an array using passed delimeter
+procedure MPExplode(var Dest: TArrayOfString; Text: String; Separator: String);
+var
+ i: Integer;
+begin
+ i := 0;
+ repeat
+ SetArrayLength(Dest, i+1);
+ if Pos(Separator,Text) > 0 then begin
+ Dest[i] := Copy(Text, 1, Pos(Separator, Text)-1);
+ Text := Copy(Text, Pos(Separator,Text) + Length(Separator), Length(Text));
+ i := i + 1;
+ end else begin
+ Dest[i] := Text;
+ Text := '';
+ end;
+ until Length(Text)=0;
+end;
+
+
+procedure CurStepChanged(CurStep: TSetupStep);
+var
+ taskname: String;
+begin
+ taskname := ModPathName;
+ if CurStep = ssPostInstall then
+ if IsTaskSelected(taskname) then
+ ModPath();
+end;
+
+procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
+var
+ aSelectedTasks: TArrayOfString;
+ i: Integer;
+ taskname: String;
+ regpath: String;
+ regstring: String;
+ appid: String;
+begin
+ // only run during actual uninstall
+ if CurUninstallStep = usUninstall then begin
+ // get list of selected tasks saved in registry at install time
+ appid := '{#emit SetupSetting("AppId")}';
+ if appid = '' then appid := '{#emit SetupSetting("AppName")}';
+ regpath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\'+appid+'_is1');
+ RegQueryStringValue(HKLM, regpath, 'Inno Setup: Selected Tasks', regstring);
+ if regstring = '' then RegQueryStringValue(HKCU, regpath, 'Inno Setup: Selected Tasks', regstring);
+
+ // check each task; if matches modpath taskname, trigger patch removal
+ if regstring <> '' then begin
+ taskname := ModPathName;
+ MPExplode(aSelectedTasks, regstring, ',');
+ if GetArrayLength(aSelectedTasks) > 0 then begin
+ for i := 0 to GetArrayLength(aSelectedTasks)-1 do begin
+ if comparetext(aSelectedTasks[i], taskname) = 0 then
+ ModPath();
+ end;
+ end;
+ end;
+ end;
+end;
+
+function NeedRestart(): Boolean;
+var
+ taskname: String;
+begin
+ taskname := ModPathName;
+ if IsTaskSelected(taskname) and not UsingWinNT() then begin
+ Result := True;
+ end else begin
+ Result := False;
+ end;
+end;