summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rwxr-xr-xmisc/nsis/graphics/install.icobin0 -> 22486 bytes
-rwxr-xr-xmisc/nsis/graphics/readme.txt2
-rwxr-xr-xmisc/nsis/graphics/uninstall.icobin0 -> 22486 bytes
-rwxr-xr-xmisc/nsis/graphics/wizard.bmpbin0 -> 52574 bytes
-rwxr-xr-xmisc/nsis/install.nsh596
-rwxr-xr-xmisc/nsis/install_pages.nsh64
-rwxr-xr-xmisc/nsis/mkunlist.cmd54
-rwxr-xr-xmisc/nsis/qutebrowser.nsi174
-rwxr-xr-xmisc/nsis/uninstall.nsh241
-rwxr-xr-xmisc/nsis/uninstall_pages.nsh32
-rw-r--r--misc/qutebrowser.nsi80
-rwxr-xr-xscripts/dev/build_release.py8
-rwxr-xr-xscripts/dev/update_3rdparty.py37
14 files changed, 1204 insertions, 86 deletions
diff --git a/.gitignore b/.gitignore
index ceafd9946..6074de319 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,5 @@ TODO
/scripts/dev/pylint_checkers/qute_pylint.egg-info
/misc/file_version_info.txt
/doc/extapi/_build
+/misc/nsis/include
+/misc/nsis/plugins
diff --git a/misc/nsis/graphics/install.ico b/misc/nsis/graphics/install.ico
new file mode 100755
index 000000000..8a30f612e
--- /dev/null
+++ b/misc/nsis/graphics/install.ico
Binary files differ
diff --git a/misc/nsis/graphics/readme.txt b/misc/nsis/graphics/readme.txt
new file mode 100755
index 000000000..b99dee86c
--- /dev/null
+++ b/misc/nsis/graphics/readme.txt
@@ -0,0 +1,2 @@
+These are modified versions of 'orange-install.ico', 'orange-uninstall.ico'
+and 'orange.bmp' graphics of the NSIS distribution. \ No newline at end of file
diff --git a/misc/nsis/graphics/uninstall.ico b/misc/nsis/graphics/uninstall.ico
new file mode 100755
index 000000000..94ea5bce3
--- /dev/null
+++ b/misc/nsis/graphics/uninstall.ico
Binary files differ
diff --git a/misc/nsis/graphics/wizard.bmp b/misc/nsis/graphics/wizard.bmp
new file mode 100755
index 000000000..a48c8ee03
--- /dev/null
+++ b/misc/nsis/graphics/wizard.bmp
Binary files differ
diff --git a/misc/nsis/install.nsh b/misc/nsis/install.nsh
new file mode 100755
index 000000000..f3a8042c3
--- /dev/null
+++ b/misc/nsis/install.nsh
@@ -0,0 +1,596 @@
+# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+#
+# This file is part of qutebrowser.
+#
+# qutebrowser 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.
+#
+# qutebrowser 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 qutebrowser. If not, see <http://www.gnu.org/licenses/>.
+
+# NSIS installer header. Uses NsisMultiUser plugin and contains portions of
+# its demo code, copyright 2017 Richard Drizin, Alex Mitev.
+
+; Variables
+var KeepReg
+
+; Languages (first is default language) - must be inserted after all pages
+!insertmacro MUI_LANGUAGE "English"
+!insertmacro MULTIUSER_LANGUAGE_INIT
+
+; Reserve files
+!insertmacro MUI_RESERVEFILE_LANGDLL
+
+; Macros
+!macro UpdateRegStr ROOT_KEY SUBKEY KEY_NAME KEY_VALUE
+ ClearErrors
+ ReadRegStr $R0 ${ROOT_KEY} "${SUBKEY}" "${KEY_NAME}"
+ ${if} ${errors}
+ ${orif} $R0 != "${KEY_VALUE}"
+ WriteRegStr ${ROOT_KEY} "${SUBKEY}" "${KEY_NAME}" "${KEY_VALUE}"
+ ${endif}
+!macroend
+
+!macro UpdateRegDWORD ROOT_KEY SUBKEY KEY_NAME KEY_VALUE
+ ClearErrors
+ ReadRegDWORD $R0 ${ROOT_KEY} "${SUBKEY}" "${KEY_NAME}"
+ ${if} ${errors}
+ ${orif} $R0 != ${KEY_VALUE}
+ WriteRegDWORD ${ROOT_KEY} "${SUBKEY}" "${KEY_NAME}" ${KEY_VALUE}
+ ${endif}
+!macroend
+
+; Push the 32-bit MSI Product Codes on the stack.
+!macro MSI32_STACK
+ Push "${MSI32_010}"
+ Push "${MSI32_011}"
+ Push "${MSI32_012}"
+ Push "${MSI32_013}"
+ Push "${MSI32_014}"
+ Push "${MSI32_020}"
+ Push "${MSI32_021}"
+ Push "${MSI32_030}"
+ Push "${MSI32_040}"
+ Push "${MSI32_041}"
+ Push "${MSI32_050}"
+ Push "${MSI32_051}"
+ Push "${MSI32_060}"
+ Push "${MSI32_061}"
+ Push "${MSI32_062}"
+ Push "${MSI32_070}"
+ Push "${MSI32_080}"
+ Push "${MSI32_081}"
+ Push "${MSI32_082}"
+ Push "${MSI32_084}"
+ Push "${MSI32_090}"
+ Push "${MSI32_091}"
+ Push "${MSI32_100}"
+ Push "${MSI32_101}"
+!macroend
+
+; Push the 64-bit MSI Product Codes on the stack.
+!macro MSI64_STACK
+ Push "${MSI64_010}"
+ Push "${MSI64_011}"
+ Push "${MSI64_012}"
+ Push "${MSI64_013}"
+ Push "${MSI64_014}"
+ Push "${MSI64_020}"
+ Push "${MSI64_021}"
+ Push "${MSI64_030}"
+ Push "${MSI64_040}"
+ Push "${MSI64_041}"
+ Push "${MSI64_050}"
+ Push "${MSI64_051}"
+ Push "${MSI64_060}"
+ Push "${MSI64_061}"
+ Push "${MSI64_062}"
+ Push "${MSI64_070}"
+ Push "${MSI64_080}"
+ Push "${MSI64_081}"
+ Push "${MSI64_082}"
+ Push "${MSI64_084}"
+ Push "${MSI64_090}"
+ Push "${MSI64_091}"
+ Push "${MSI64_100}"
+ Push "${MSI64_101}"
+!macroend
+
+; Check the existence of MSI installations.
+; Must be inserted after MSI32_STACK and MSI64_STACK.
+; Returns the detected code in $R1 or an empty string if none is found.
+!macro CheckMSI
+ ${foreach} $9 ${MSI_COUNT} 1 - 1
+ Pop $R1
+ ReadRegStr $0 HKLM "${REG_UN}\$R1" "DisplayName"
+ ${if} $0 == "${PRODUCT_NAME}"
+ ${exitfor}
+ ${else}
+ StrCpy $R1 ""
+ ${endif}
+ ${next}
+!macroend
+
+; Check the existence of the previous NSIS installations.
+; Returns the uninstaller path in $R0 or an empty string if not found.
+!macro CheckOldNSIS
+ ReadRegStr $R0 HKLM "${REG_UN}\${PRODUCT_NAME}" "QuietUninstallString"
+ ${if} $R0 != ""
+ ReadRegStr $R0 HKLM "${REG_UN}\${PRODUCT_NAME}" "UninstallString"
+ ${if} $R0 != ""
+ ; Remove the quotes from path in $R0
+ System::Call 'Shlwapi::PathUnquoteSpaces(t r10r10)'
+ IfFileExists $R0 +2 0
+ ; Return 0 if the uninstaller is missing.
+ StrCpy $R0 ""
+ ${endif}
+ ${endif}
+!macroend
+
+!macro RemoveOld PRG ARGS
+ ClearErrors
+ ; Using ExecShellWait so the EXE will get the elevation prompt.
+ ExecShellWait "open" "${PRG}" "${ARGS}"
+ ${if} ${errors}
+ MessageBox MB_ICONSTOP \
+ "The uninstaller has failed to complete.$\r$\n\
+ Please restart Windows and try again." \
+ /SD IDOK
+ Abort
+ ${endif}
+!macroend
+
+; Functions
+Function CheckInstallation
+ ; if there's an installed version, uninstall it first (I chose not to start the uninstaller silently, so that user sees what failed)
+ ; if both per-user and per-machine versions are installed, unistall the one that matches $MultiUser.InstallMode
+ StrCpy $0 ""
+ ${if} $HasCurrentModeInstallation = 1
+ StrCpy $0 "$MultiUser.InstallMode"
+ ${else}
+ !if ${MULTIUSER_INSTALLMODE_ALLOW_BOTH_INSTALLATIONS} = 0
+ ${if} $HasPerMachineInstallation = 1
+ StrCpy $0 "AllUsers" ; if there's no per-user installation, but there's per-machine installation, uninstall it
+ ${elseif} $HasPerUserInstallation = 1
+ StrCpy $0 "CurrentUser" ; if there's no per-machine installation, but there's per-user installation, uninstall it
+ ${endif}
+ !endif
+ ${endif}
+
+ ${if} "$0" != ""
+ ${if} $0 == "AllUsers"
+ StrCpy $1 "$PerMachineUninstallString"
+ StrCpy $3 "$PerMachineInstallationFolder"
+ ${else}
+ StrCpy $1 "$PerUserUninstallString"
+ StrCpy $3 "$PerUserInstallationFolder"
+ ${endif}
+ ${if} ${silent}
+ StrCpy $2 "/S"
+ ${else}
+ StrCpy $2 ""
+ ${endif}
+ ${if} $KeepReg = 1
+ StrCpy $4 "/upgrade"
+ ${endif}
+ ${endif}
+FunctionEnd
+
+Function RunUninstaller
+ StrCpy $0 0
+ ; $1 is quoted in registry; the _? param stops the uninstaller from copying
+ ; itself to the temporary directory, which is the only way for ExecWait to work
+ ExecWait '$1 /SS $2 _?=$3' $0 ; $1 is quoted in registry; the _? param stops the uninstaller from copying itself to the temporary directory, which is the only way for ExecWait to work
+FunctionEnd
+
+Function GetDefaultBrowser
+ ReadRegStr $0 HKCU "SOFTWARE\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice" "ProgId"
+ ReadRegStr $1 HKCU "SOFTWARE\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice" "ProgId"
+ ReadRegStr $2 HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.htm\UserChoice" "ProgId"
+ ReadRegStr $3 HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice" "ProgId"
+FunctionEnd
+
+Function SetDefaultBrowser
+ StrCmp $0 "${PRODUCT_NAME}URL" +2 0
+ WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice" \
+ "ProgId" "${PRODUCT_NAME}URL"
+ StrCmp $1 "${PRODUCT_NAME}URL" +2 0
+ WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice" \
+ "ProgId" "${PRODUCT_NAME}URL"
+ StrCmp $2 "${PRODUCT_NAME}HTML" +3 0
+ DeleteRegKey HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.htm\UserChoice"
+ WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.htm\UserChoice" \
+ "ProgId" "${PRODUCT_NAME}HTML"
+ StrCmp $3 "${PRODUCT_NAME}HTML" +3 0
+ DeleteRegKey HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice"
+ WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice" \
+ "ProgId" "${PRODUCT_NAME}HTML"
+FunctionEnd
+
+; Sections
+InstType "Full"
+InstType "Typical"
+InstType "Minimal"
+
+Section "Core Files (required)" SectionCoreFiles
+ SectionIn 1 2 3 RO
+
+ !insertmacro UAC_AsUser_Call Function CheckInstallation ${UAC_SYNCREGISTERS}
+ ${if} "$0" != ""
+ ; Make sure the uninstaller is there before attempting to run it
+ ${if} ${FileExists} "$3\${UNINSTALL_FILENAME}"
+ HideWindow
+ ClearErrors
+ ${if} $0 == "AllUsers"
+ Call RunUninstaller
+ ${else}
+ !insertmacro UAC_AsUser_Call Function RunUninstaller ${UAC_SYNCREGISTERS}
+ ${endif}
+ ${if} ${errors} ; stay in installer
+ SetErrorLevel 2 ; Installation aborted by script
+ BringToFront
+ Abort "Error executing uninstaller."
+ ${else}
+ ${Switch} $0
+ ${Case} 0 ; uninstaller completed successfully - continue with installation
+ BringToFront
+ Sleep 1000 ; wait for cmd.exe (called by the uninstaller) to finish
+ ${Break}
+ ${Case} 1 ; Installation aborted by user (cancel button)
+ ${Case} 2 ; Installation aborted by script
+ SetErrorLevel $0
+ Quit ; uninstaller was started, but completed with errors - Quit installer
+ ${Default} ; all other error codes - uninstaller could not start, elevate, etc. - Abort installer
+ SetErrorLevel $0
+ BringToFront
+ Abort "Error executing uninstaller."
+ ${EndSwitch}
+ ${endif}
+
+ ${if} $IsAdmin = 1
+ !insertmacro DeleteRetryAbort "$3\${UNINSTALL_FILENAME}"
+ RMDir "$3"
+ ${endif}
+ ${endif}
+ ${endif}
+
+ ; Remove any leftovers from the old NSIS installer
+ IfFileExists "$INSTDIR\uninst.exe" 0 +2
+ Delete "$INSTDIR\uninst.exe"
+ ${if} $MultiUser.InstallMode == "AllUsers"
+ SetRegView 32 ; The old NSIS installer writes to 32-bit registry space
+ ReadRegStr $R0 HKLM "${REG_UN}\${PRODUCT_NAME}" "QuietUninstallString"
+ ${if} $R0 != ""
+ DeleteRegKey HKLM "${REG_UN}\${PRODUCT_NAME}"
+ ${endif}
+ SetRegView lastused
+ ${endif}
+
+ SetOutPath $INSTDIR
+ ; Write uninstaller and registry uninstall info as the first step,
+ ; so that the user has the option to run the uninstaller if something goes wrong
+ WriteUninstaller "${UNINSTALL_FILENAME}"
+ ; or this if you're using signing:
+ ; File "${UNINSTALL_FILENAME}"
+ !insertmacro MULTIUSER_RegistryAddInstallInfo ; add registry keys
+ ${if} ${silent} ; MUI doesn't write language in silent mode
+ WriteRegStr "${MUI_LANGDLL_REGISTRY_ROOT}" "${MUI_LANGDLL_REGISTRY_KEY}" \
+ "${MUI_LANGDLL_REGISTRY_VALUENAME}" $LANGUAGE
+ ${endif}
+
+ File /r "${DIST_DIR}\*.*"
+SectionEnd
+
+SectionGroup /e "System Integration" SectionGroupIntegration
+
+Section "Register with Windows" SectionWindowsRegister
+ SectionIn 1 2
+
+ ; No HKCU support for Windows versions earlier than Win8
+ ${if} $MultiUser.InstallMode == "AllUsers"
+ ${orif} ${AtLeastWin8}
+ ;StartMenuInternet
+ StrCpy $0 "$INSTDIR\${PROGEXE}"
+ System::Call 'kernel32::GetLongPathNameW(t r0, t .r1, i ${NSIS_MAX_STRLEN}) i .r2'
+
+ StrCpy $0 "SOFTWARE\Clients\StartMenuInternet\${PRODUCT_NAME}"
+
+ !insertmacro UpdateRegStr SHCTX "$0" "" "${PRODUCT_NAME}"
+
+ !insertmacro UpdateRegStr SHCTX "$0\DefaultIcon" "" "$1,0"
+
+ !insertmacro UpdateRegDWORD SHCTX "$0\InstallInfo" "IconsVisible" 1
+
+ !insertmacro UpdateRegStr SHCTX "$0\shell\open\command" "" "$\"$1$\""
+
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities" "ApplicationDescription" "${COMMENTS}"
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities" "ApplicationIcon" "$1,0"
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities" "ApplicationName" "${PRODUCT_NAME}"
+
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities\FileAssociations" ".htm" "${PRODUCT_NAME}HTML"
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities\FileAssociations" ".html" "${PRODUCT_NAME}HTML"
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities\FileAssociations" ".pdf" "${PRODUCT_NAME}HTML"
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities\FileAssociations" ".shtml" "${PRODUCT_NAME}HTML"
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities\FileAssociations" ".svg" "${PRODUCT_NAME}HTML"
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities\FileAssociations" ".xht" "${PRODUCT_NAME}HTML"
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities\FileAssociations" ".xhtml" "${PRODUCT_NAME}HTML"
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities\FileAssociations" ".webp" "${PRODUCT_NAME}HTML"
+
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities\StartMenu" "StartMenuInternet" "${PRODUCT_NAME}"
+
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities\URLAssociations" "ftp" "${PRODUCT_NAME}URL"
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities\URLAssociations" "http" "${PRODUCT_NAME}URL"
+ !insertmacro UpdateRegStr SHCTX "$0\Capabilities\URLAssociations" "https" "${PRODUCT_NAME}URL"
+
+ ; Register Application
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\RegisteredApplications" "${PRODUCT_NAME}" "$0\Capabilities"
+
+ ; Associate file types
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\.htm\OpenWithProgids" "${PRODUCT_NAME}HTML" ""
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\.html\OpenWithProgids" "${PRODUCT_NAME}HTML" ""
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\.pdf\OpenWithProgids" "${PRODUCT_NAME}HTML" ""
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\.shtml\OpenWithProgids" "${PRODUCT_NAME}HTML" ""
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\.svg\OpenWithProgids" "${PRODUCT_NAME}HTML" ""
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\.xht\OpenWithProgids" "${PRODUCT_NAME}HTML" ""
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\.xhtml\OpenWithProgids" "${PRODUCT_NAME}HTML" ""
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\.webp\OpenWithProgids" "${PRODUCT_NAME}HTML" ""
+
+ ; HTML and URL handlers
+ StrCpy $2 "${PRODUCT_NAME}HTML"
+ StrCpy $3 "${PRODUCT_NAME} HTML Document"
+ WriteRegHandler:
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\$2" "" "$3"
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\$2" "FriendlyTypeName" "$3"
+ !insertmacro UpdateRegDWORD SHCTX "SOFTWARE\Classes\$2" "EditFlags" 0x00000002
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\$2\DefaultIcon" "" "$1,0"
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\$2\shell" "" "open"
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\$2\shell\open\command" "" "$\"$1$\" $\"%1$\""
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\$2\shell\open\ddeexec" "" ""
+ StrCmp $2 "${PRODUCT_NAME}HTML" 0 +4
+ StrCpy $2 "${PRODUCT_NAME}URL"
+ StrCpy $3 "${PRODUCT_NAME} URL"
+ Goto WriteRegHandler
+ !insertmacro UpdateRegStr SHCTX "SOFTWARE\Classes\$2" "URL Protocol" ""
+ ${endif}
+SectionEnd
+
+Section /o "Open Default Browser Settings" SectionDefaultBrowser
+ SectionIn 1
+
+ !insertmacro UAC_AsUser_Call Function GetDefaultBrowser ${UAC_SYNCREGISTERS}
+ ${ifnot} $0 == "${PRODUCT_NAME}URL"
+ ${orifnot} $1 == "${PRODUCT_NAME}URL"
+ ${orifnot} $2 == "${PRODUCT_NAME}HTML"
+ ${orifnot} $3 == "${PRODUCT_NAME}HTML"
+ ${if} ${AtLeastWin10}
+ ExecShell "open" "ms-settings:defaultapps"
+ ${elseif} ${AtLeastWin8}
+ ExecShell "open" "control.exe" "/name Microsoft.DefaultPrograms /page \
+ pageDefaultProgram\pageAdvancedSettings?pszAppName=${PRODUCT_NAME}"
+ ${else}
+ !insertmacro UAC_AsUser_Call Function SetDefaultBrowser ${UAC_SYNCREGISTERS}
+ ${endif}
+ ${endif}
+SectionEnd
+
+SectionGroupEnd
+
+SectionGroup /e "Shortcuts" SectionGroupShortcuts
+
+Section "Dektop Icon" SectionDesktopIcon
+ SectionIn 1 2
+
+ !insertmacro MULTIUSER_GetCurrentUserString $0
+ CreateShortCut "$DESKTOP\${PRODUCT_NAME}$0.lnk" "$INSTDIR\${PROGEXE}"
+SectionEnd
+
+Section "Start Menu Icon" SectionStartMenuIcon
+ SectionIn 1 2
+
+ !insertmacro MULTIUSER_GetCurrentUserString $0
+ CreateShortCut "$STARTMENU\${PRODUCT_NAME}$0.lnk" "$INSTDIR\${PROGEXE}"
+SectionEnd
+
+SectionGroupEnd
+
+Section "-Write Install Info" ; hidden section, write install info as the final step
+ !insertmacro MULTIUSER_RegistryAddInstallSizeInfo
+ !insertmacro MULTIUSER_GetCurrentUserString $0
+ WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "HelpLink" "${HELP_LINK}"
+ WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "URLInfoAbout" "${URL_ABOUT}"
+ WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "URLUpdateInfo" "${URL_UPDATE}"
+ WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "Comments" "${COMMENTS}"
+ WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "Contact" "${CONTACT}"
+
+ ; Add InstallDate String
+ System::Call /NOUNLOAD '*(&i2,&i2,&i2,&i2,&i2,&i2,&i2,&i2) i .r9'
+ System::Call /NOUNLOAD 'kernel32::GetLocalTime(i)i(r9)'
+ System::Call /NOUNLOAD '*$9(&i2,&i2,&i2,&i2,&i2,&i2,&i2,&i2)i(.r1,.r2,.r3,.r4,.r5,.r6,.r7,)'
+ System::Free $9
+ IntCmp $2 9 0 0 +2
+ StrCpy $2 '0$2'
+ IntCmp $4 9 0 0 +2
+ StrCpy $4 '0$4'
+ WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "InstallDate" "$1$2$4"
+
+ ${RefreshShellIcons}
+SectionEnd
+
+; Modern install component descriptions
+!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
+ !insertmacro MUI_DESCRIPTION_TEXT ${SectionCoreFiles} \
+ "Core files required to run ${PRODUCT_NAME}."
+ !insertmacro MUI_DESCRIPTION_TEXT ${SectionGroupIntegration} \
+ "Integrate ${PRODUCT_NAME} with the Operating System."
+ !insertmacro MUI_DESCRIPTION_TEXT ${SectionWindowsRegister} \
+ "Register protocols and file extensions with ${PRODUCT_NAME}."
+ !insertmacro MUI_DESCRIPTION_TEXT ${SectionDefaultBrowser} \
+ "Set ${PRODUCT_NAME} as the default Web browser."
+ !insertmacro MUI_DESCRIPTION_TEXT ${SectionGroupShortcuts} \
+ "Create shortcut icons to run ${PRODUCT_NAME}."
+ !insertmacro MUI_DESCRIPTION_TEXT ${SectionDesktopIcon} \
+ "Create ${PRODUCT_NAME} icon on the Desktop."
+ !insertmacro MUI_DESCRIPTION_TEXT ${SectionStartMenuIcon} \
+ "Create ${PRODUCT_NAME} icon in the Start Menu."
+!insertmacro MUI_FUNCTION_DESCRIPTION_END
+
+; Callbacks
+Function .onInit
+ StrCpy $KeepReg 1
+ !insertmacro CheckPlatform ${PLATFORM}
+ !insertmacro CheckMinWinVer ${MIN_WIN_VER}
+ ${ifnot} ${UAC_IsInnerInstance}
+ !insertmacro CheckSingleInstance "Setup" "Global" "${SETUP_MUTEX}"
+ !insertmacro CheckSingleInstance "Application" "Local" "${APP_MUTEX}"
+ ${endif}
+
+ ; Detect existing setup from previous installers
+ !insertmacro CheckOldNSIS
+ !insertmacro MSI32_STACK
+ !insertmacro CheckMSI
+ ${if} $R1 == ""
+ ${andif} ${RunningX64}
+ SetRegView 64 ; Will be set again by MULTIUSER_INIT
+ !insertmacro MSI64_STACK
+ !insertmacro CheckMSI
+ ${endif}
+ ${if} $R0 != ""
+ ${orif} $R1 != ""
+ MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
+ "An older version of ${PRODUCT_NAME} is already installed.$\r$\n$\r$\n\
+ Click `OK` to remove the previous version and continue,$\r$\n\
+ or `Cancel` to cancel this upgrade." \
+ IDOK +2
+ Abort
+ ${if} $R0 != ""
+ ${GetParent} $R0 $0
+ !insertmacro RemoveOld $R0 "/S _?=$0"
+ ${endif}
+ ${if} $R1 != ""
+ !insertmacro RemoveOld "$SYSDIR\msiexec.exe" "/X$R1 /passive /promptrestart"
+ ${endif}
+ ${endif}
+
+ !insertmacro MULTIUSER_INIT
+
+ ${if} $IsInnerInstance = 0
+ !insertmacro MUI_LANGDLL_DISPLAY
+ ${endif}
+FunctionEnd
+
+Function .onSelChange
+ ${if} ${SectionIsSelected} ${SectionWindowsRegister}
+ StrCpy $KeepReg 1
+ ${else}
+ StrCpy $KeepReg 0
+ ${endif}
+
+ ${if} ${SectionIsSelected} ${SectionDefaultBrowser}
+ !insertmacro SetSectionFlag ${SectionWindowsRegister} ${SF_RO}
+ !insertmacro SelectSection ${SectionWindowsRegister}
+ ${else}
+ !insertmacro ClearSectionFlag ${SectionWindowsRegister} ${SF_RO}
+ ${endif}
+FunctionEnd
+
+Function PageWelcomeLicensePre
+ ${if} $InstallShowPagesBeforeComponents = 0
+ Abort ; don't display the Welcome and License pages for the inner instance
+ ${endif}
+FunctionEnd
+
+Function PageInstallModeChangeMode
+ ; Disable integration for single user install on Win7 and older, as it's not supported
+ ${if} ${AtMostWin7}
+ SectionSetText ${SectionDefaultBrowser} "Set as Default Browser"
+ ${if} $MultiUser.InstallMode == "CurrentUser"
+ SectionSetText ${SectionGroupIntegration} "System Integration (not supported)"
+ IntOP $0 ${SF_RO} & ${SECTION_OFF}
+ SectionSetFlags ${SectionWindowsRegister} $0
+ SectionSetFlags ${SectionDefaultBrowser} $0
+ !insertmacro SetSectionFlag ${SectionGroupIntegration} ${SF_RO}
+ !insertmacro ClearSectionFlag ${SectionGroupIntegration} ${SF_EXPAND}
+ ${else}
+ ; This is necessary because if the installer started under Win7/Vista as Administrator with UAC disabled,
+ ; going back to All users after first selecting Single user, the integration component would still be disabled
+ SectionSetText ${SectionGroupIntegration} "System Integration"
+ !insertmacro ClearSectionFlag ${SectionWindowsRegister} ${SF_RO}
+ !insertmacro ClearSectionFlag ${SectionDefaultBrowser} ${SF_RO}
+ !insertmacro ClearSectionFlag ${SectionGroupIntegration} ${SF_RO}
+ !insertmacro SetSectionFlag ${SectionGroupIntegration} ${SF_EXPAND}
+ !insertmacro SelectSection ${SectionWindowsRegister}
+
+ ; Select 'Default browser' if already set in registry
+ !insertmacro UAC_AsUser_Call Function GetDefaultBrowser ${UAC_SYNCREGISTERS}
+ ${if} $0 == "${PRODUCT_NAME}URL"
+ ${orif} $1 == "${PRODUCT_NAME}URL"
+ ${orif} $2 == "${PRODUCT_NAME}HTML"
+ ${orif} $3 == "${PRODUCT_NAME}HTML"
+ !insertmacro SetSectionFlag ${SectionWindowsRegister} ${SF_RO}
+ !insertmacro SelectSection ${SectionDefaultBrowser}
+ ${else}
+ !insertmacro UnselectSection ${SectionDefaultBrowser}
+ ${endif}
+ ${endif}
+ ${endif}
+FunctionEnd
+
+Function PageComponentsPre
+ GetDlgItem $0 $HWNDPARENT 1
+ SendMessage $0 ${BCM_SETSHIELD} 0 0 ; hide SHIELD (Windows Vista and above)
+FunctionEnd
+
+Function PageDirectoryPre
+ GetDlgItem $1 $HWNDPARENT 1
+ SendMessage $1 ${WM_SETTEXT} 0 "STR:$(^InstallBtn)" ; this is the last page before installing
+ Call MultiUser.CheckPageElevationRequired
+ ${if} $0 = 2
+ SendMessage $1 ${BCM_SETSHIELD} 0 1 ; display SHIELD (Windows Vista and above)
+ ${endif}
+FunctionEnd
+
+Function PageDirectoryShow
+ ${if} $CmdLineDir != ""
+ FindWindow $R1 "#32770" "" $HWNDPARENT
+
+ GetDlgItem $0 $R1 1019 ; Directory edit
+ SendMessage $0 ${EM_SETREADONLY} 1 0 ; read-only is better than disabled, as user can copy contents
+
+ GetDlgItem $0 $R1 1001 ; Browse button
+ EnableWindow $0 0
+ ${endif}
+FunctionEnd
+
+Function PageInstFilesPre
+ GetDlgItem $0 $HWNDPARENT 1
+ SendMessage $0 ${BCM_SETSHIELD} 0 0 ; hide SHIELD (Windows Vista and above)
+FunctionEnd
+
+Function PageFinishRun
+ ; the installer might exit too soon before the application starts and it loses
+ ; the right to be the foreground window and starts in the background
+ ; however, if there's no active window when the application starts, it will
+ ; become the active window, so we hide the installer
+ HideWindow
+ ; the installer will show itself again quickly before closing (w/o Taskbar button), we move it offscreen
+ !define SWP_NOSIZE 0x0001
+ !define SWP_NOZORDER 0x0004
+ System::Call "User32::SetWindowPos(i, i, i, i, i, i, i) b \
+ ($HWNDPARENT, 0, -1000, -1000, 0, 0, ${SWP_NOZORDER}|${SWP_NOSIZE})"
+
+ !insertmacro UAC_AsUser_ExecShell "open" "$INSTDIR\${PROGEXE}" "" "$INSTDIR" ""
+FunctionEnd
+
+Function .onInstFailed
+ MessageBox MB_ICONSTOP \
+ "${PRODUCT_NAME} ${VERSION} could not be fully installed.$\r$\n\
+ Please, restart Windows and run the setup program again." \
+ /SD IDOK
+FunctionEnd
diff --git a/misc/nsis/install_pages.nsh b/misc/nsis/install_pages.nsh
new file mode 100755
index 000000000..9ba6863cc
--- /dev/null
+++ b/misc/nsis/install_pages.nsh
@@ -0,0 +1,64 @@
+# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+#
+# This file is part of qutebrowser.
+#
+# qutebrowser 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.
+#
+# qutebrowser 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 qutebrowser. If not, see <http://www.gnu.org/licenses/>.
+
+# NSIS pages header. Uses NsisMultiUser plugin and contains portions of
+# its demo code, copyright 2017 Richard Drizin, Alex Mitev.
+
+
+; NsisMultiUser optional defines
+!define MULTIUSER_INSTALLMODE_ALLOW_BOTH_INSTALLATIONS 0
+!define MULTIUSER_INSTALLMODE_ALLOW_ELEVATION 1
+!define MULTIUSER_INSTALLMODE_ALLOW_ELEVATION_IF_SILENT 0
+!define MULTIUSER_INSTALLMODE_DEFAULT_ALLUSERS 1
+!if ${PLATFORM} == "win64"
+ !define MULTIUSER_INSTALLMODE_64_BIT 1
+!endif
+!define MULTIUSER_INSTALLMODE_DISPLAYNAME "${PRODUCT_NAME} ${VERSION} (${ARCH})"
+
+; Interface Settings
+!define MUI_ABORTWARNING ; Show a confirmation when cancelling the installation
+!define MUI_LANGDLL_ALLLANGUAGES ; Show all languages, despite user's codepage
+
+; Remember the installer language
+!define MUI_LANGDLL_REGISTRY_ROOT "SHCTX"
+!define MUI_LANGDLL_REGISTRY_KEY "${SETTINGS_REG_KEY}"
+!define MUI_LANGDLL_REGISTRY_VALUENAME "Language"
+
+; Pages
+!define MUI_PAGE_CUSTOMFUNCTION_PRE PageWelcomeLicensePre
+!insertmacro MUI_PAGE_WELCOME
+
+!define MUI_PAGE_CUSTOMFUNCTION_PRE PageWelcomeLicensePre
+!insertmacro MUI_PAGE_LICENSE "${LICENSE_FILE}"
+
+!define MULTIUSER_INSTALLMODE_CHANGE_MODE_FUNCTION PageInstallModeChangeMode
+!insertmacro MULTIUSER_PAGE_INSTALLMODE
+
+!define MUI_COMPONENTSPAGE_SMALLDESC
+!define MUI_PAGE_CUSTOMFUNCTION_PRE PageComponentsPre
+!insertmacro MUI_PAGE_COMPONENTS
+
+!define MUI_PAGE_CUSTOMFUNCTION_PRE PageDirectoryPre
+!define MUI_PAGE_CUSTOMFUNCTION_SHOW PageDirectoryShow
+!insertmacro MUI_PAGE_DIRECTORY
+
+!define MUI_PAGE_CUSTOMFUNCTION_SHOW PageInstFilesPre
+!insertmacro MUI_PAGE_INSTFILES
+
+!define MUI_FINISHPAGE_RUN
+!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
+!insertmacro MUI_PAGE_FINISH
diff --git a/misc/nsis/mkunlist.cmd b/misc/nsis/mkunlist.cmd
new file mode 100755
index 000000000..8ebb6d708
--- /dev/null
+++ b/misc/nsis/mkunlist.cmd
@@ -0,0 +1,54 @@
+@echo off
+
+rem This is called from qutebrowser NSIS script at compile time.
+rem It enumerates the files/directories of the release and generates an nsh
+rem file with the commands to remove them.
+
+rem Usage: mkunlist <release_dir> <nsh_file>
+
+setlocal EnableDelayedExpansion
+
+if [%2]==[] exit 1
+
+rem The full path of the release
+set "DIST=%~f1"
+rem The generated nsh file
+set "ULIST=%~2"
+rem Temporary file to keep the directories list
+set "DLIST=%TEMP%\%~n2%RANDOM%.tmp"
+
+if not exist "%DIST%" exit 2
+
+if exist "%ULIST%" del "%ULIST%" || exit 3
+if exist "%DLIST%" del "%DLIST%" || exit 3
+
+rem Add release files deletion commands
+for /r "%DIST%" %%i in (*) do call:AddToNSH f "%%i" "%ULIST%"
+
+rem '*' doesn't catch hidden files and there are a couple of files starting with
+rem a '.', which will appear as hidden if mapped from a linux file system.
+for /f "tokens=*" %%i in ('dir "%DIST%" /a:h-d /b /s') do call:AddToNSH f "%%i" "%ULIST%"
+
+rem Add to the temporary file the directories removal commands
+for /r "%DIST%" %%i in (.) do call:AddToNSH d "%%i" "%DLIST%"
+
+rem Reverse dir-list items (so each child will get deleted first)
+rem and append them to the nsh.
+sort /r "%DLIST%" >> "%ULIST%"
+del "%DLIST%"
+goto:eof
+
+rem AddToNSH <f|d> <name> <out_file>
+:AddToNSH
+rem Strip quotes from file/dir name
+set "FN=%~2"
+rem Strip leading path
+set "FN=!FN:%DIST%=!"
+rem If the name contains a '$', escape it by adding another '$'
+set "FN=!FN:$=$$!"
+rem Writing to out_file. EnableDelayedExpansion is weird with '!'
+if %1==f (
+ (echo:^^!insertmacro DeleteRetryAbort "$INSTDIR!FN!") >> %3
+) else (
+ (echo:RMDir "$INSTDIR!FN!") >> %3
+)
diff --git a/misc/nsis/qutebrowser.nsi b/misc/nsis/qutebrowser.nsi
new file mode 100755
index 000000000..d9b8fbf8d
--- /dev/null
+++ b/misc/nsis/qutebrowser.nsi
@@ -0,0 +1,174 @@
+# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+#
+# This file is part of qutebrowser.
+#
+# qutebrowser 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.
+#
+# qutebrowser 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 qutebrowser. If not, see <http://www.gnu.org/licenses/>.
+
+# NSIS installer script. Uses NsisMultiUser plugin and contains portions of
+# its demo code, copyright 2017 Richard Drizin, Alex Mitev.
+
+# Includes modified graphics from the NSIS distribution.
+
+# Requires:
+# - NsisMultiUser plugin https://github.com/Drizin/NsisMultiUser
+# - UAC plugin https://nsis.sourceforge.net/UAC_plug-in
+# - StdUtils plugin https://nsis.sourceforge.io/StdUtils_plug-in
+
+
+; Installer Attributes
+Unicode true
+XPStyle on
+ManifestSupportedOS all
+SetDatablockOptimize on
+SetCompressor /SOLID /FINAL lzma
+SetCompressorDictSize 32
+CRCCheck on
+AllowSkipFiles off
+SetOverwrite on
+ShowInstDetails hide
+ShowUninstDetails hide
+
+!addplugindir /x86-unicode ".\plugins\x86-unicode"
+!addincludedir ".\include"
+
+!include MUI2.nsh
+!include NsisMultiUser.nsh
+!include StdUtils.nsh
+
+; Installer defines
+!define PRODUCT_NAME "qutebrowser" ; name of the application as displayed to the user
+!define PROGEXE "qutebrowser.exe" ; main application filename
+!define COMPANY_NAME "qutebrowser.org" ; company, used for registry tree hierarchy
+!define COPYRIGHT "© 2014-2018 Florian Bruhin (The Compiler)"
+!define TM "qutebrowser is free software under the GNU General Public License"
+!define URL_ABOUT "https://qutebrowser.org/"
+!define URL_UPDATE "https://qutebrowser.org/doc/install.html"
+!define HELP_LINK "https://qutebrowser.org/doc/help/"
+!define CONTACT "mail@qutebrowser.org"
+!define COMMENTS "A keyboard-driven, vim-like browser based on PyQt5."
+!define LANGID "1033" ; U.S. English
+!define MIN_WIN_VER "XP"
+!define SETUP_MUTEX "${PRODUCT_NAME} Setup Mutex" ; do not change this between program versions!
+!define APP_MUTEX "${PRODUCT_NAME} App Mutex" ; do not change this between program versions!
+!define REG_UN "Software\Microsoft\Windows\CurrentVersion\Uninstall"
+!define SETTINGS_REG_KEY "${REG_UN}\${PRODUCT_NAME}"
+!define CONFIG_DIR "$APPDATA\${PRODUCT_NAME}"
+!define CACHE_DIR "$LOCALAPPDATA\${PRODUCT_NAME}"
+!define LICENSE_FILE ".\..\..\LICENSE"
+!define MUI_ICON ".\graphics\install.ico"
+!define MUI_UNICON ".\graphics\uninstall.ico"
+!define MUI_WELCOMEFINISHPAGE_BITMAP ".\graphics\wizard.bmp"
+; The old MSI installers had a different Product Code on every release by mistake
+!define MSI_COUNT 24
+!define MSI32_010 "{50691080-E51F-4F1A-AEEA-ACA8C64DB98B}"
+!define MSI32_011 "{B6FE0FC1-3754-4FF6-A5E5-A305B1EDC8CB}"
+!define MSI32_012 "{B1341894-8D82-40C6-B0D0-A5ECEFB997BE}"
+!define MSI32_013 "{22EEF3C7-4D72-4F7E-B35B-1F2A22B5E64A}"
+!define MSI32_014 "{29C7D770-EBFE-465A-8354-C6A4EA3D8BAF}"
+!define MSI32_020 "{061B339B-ABBC-4D89-BE0D-A843FEA48DA7}"
+!define MSI32_021 "{0228BB7C-8D7C-4763-A1C6-AAE0B1902AF9}"
+!define MSI32_030 "{F514C234-DB31-4158-9D96-53412B431F81}"
+!define MSI32_040 "{895E71DC-41D6-4FC3-A0F8-2EC5FE19ACB8}"
+!define MSI32_041 "{66F9576D-0DB5-475D-9C25-E0511580C897}"
+!define MSI32_050 "{EDB54F4D-7A00-47AE-9808-E59FF5E79136}"
+!define MSI32_051 "{EEF03487-BC9F-4EA4-A5A1-E9CF5F9E1FB6}"
+!define MSI32_060 "{F9FECA24-95DA-4E46-83E3-A805E5B1CE06}"
+!define MSI32_061 "{F1A0F4B9-CCA3-4B07-8ADB-16BC81530440}"
+!define MSI32_062 "{43F5E4C5-FF96-4676-B027-5AD63D3871AB}"
+!define MSI32_070 "{558FF39C-CA5F-4E2A-87D2-90963FCBC424}"
+!define MSI32_080 "{9DF540E2-4F8C-46A4-A27F-43BD0558CC42}"
+!define MSI32_081 "{EA0FB6B1-83AF-4F16-8B89-645B587D90FD}"
+!define MSI32_082 "{F849A0B2-301C-435D-9CC0-9651938FCA6F}"
+!define MSI32_084 "{9331D947-AC86-4542-A755-A833429C6E69}"
+!define MSI32_090 "{AD967987-7777-4095-A03A-3F2EE8968D9E}"
+!define MSI32_091 "{87F05B8A-2238-4D86-82BB-EC8B4CE97E78}"
+!define MSI32_100 "{07B85A0B-D025-4B4B-B46D-BC9B02912835}"
+!define MSI32_101 "{9F05D9E4-D049-445E-A489-A7DC0256C774}"
+!define MSI64_010 "{A8191862-28A7-4BB0-9532-49AD5CFFFE66}"
+!define MSI64_011 "{1C476CC1-A171-48B7-A883-0F00F4D301D3}"
+!define MSI64_012 "{ADA727AC-9DDD-4F03-93B7-BAFE950757BE}"
+!define MSI64_013 "{64949BFF-287A-4C16-A5F3-84A38A6703F1}"
+!define MSI64_014 "{63F22761-D886-4FDD-93F4-7543265E9FF7}"
+!define MSI64_020 "{80BE09C6-347F-4121-98D3-1E4363C3CE6B}"
+!define MSI64_021 "{2D86F472-DD52-40A1-8FE0-90550D674554}"
+!define MSI64_030 "{53DED10D-C609-406F-959E-C1B52A518561}"
+!define MSI64_040 "{B9535FDF-7A9E-4AED-BA1E-BEE5FFCBC311}"
+!define MSI64_041 "{DAE1309A-FE7D-46E5-B488-B437CC509DF9}"
+!define MSI64_050 "{DC9ECE64-F8E5-4BCB-BCFF-BE4ADCEF2655}"
+!define MSI64_051 "{26AED286-23BD-49FF-BD9C-7C0DC4467BD7}"
+!define MSI64_060 "{3035744D-2390-4D5E-ACAD-905E72B9EBEC}"
+!define MSI64_061 "{0223F48F-93A8-4985-BCFF-328E5A9D97D5}"
+!define MSI64_062 "{95835A82-A9C2-4924-87DF-E03D910E3400}"
+!define MSI64_070 "{61D1AC75-7ECD-45FF-B42B-454C056DB178}"
+!define MSI64_080 "{92D1C65C-1338-4B11-B515-6BD5B1FF92D9}"
+!define MSI64_081 "{AF7AC009-FB82-48F6-9439-6E46AEB60DBF}"
+!define MSI64_082 "{CC316D68-5742-4C2B-98EC-4ADF06A19B84}"
+!define MSI64_084 "{633F41F9-FE9B-42D1-9CC4-718CBD01EE11}"
+!define MSI64_090 "{5E3E7404-D6D7-4FF1-846A-F9BBFE2F841A}"
+!define MSI64_091 "{3190D3F6-7B24-47DC-88E7-99280905FACF}"
+!define MSI64_100 "{7AA6530C-3812-4DC5-9A30-E762BBDDF55E}"
+!define MSI64_101 "{B0104B85-8229-49FB-8606-275A90ACC024}"
+
+; Set PLATFORM - default x64
+!ifdef X86
+ !define PLATFORM "Win32"
+ !define ARCH "x86"
+ !define SUFFIX "win32"
+!else
+ !define PLATFORM "Win64"
+ !define ARCH "x64"
+ !define SUFFIX "amd64"
+!endif
+
+; If not defined, get VERSION from PROGEXE. Set DIST_DIR accordingly.
+!ifndef VERSION
+ !define /ifndef DIST_DIR ".\..\..\dist\${PRODUCT_NAME}-${ARCH}"
+ !getdllversion "${DIST_DIR}\${PROGEXE}" expv_
+ !define VERSION "${expv_1}.${expv_2}.${expv_3}"
+!else
+ !define /ifndef DIST_DIR ".\..\..\dist\${PRODUCT_NAME}-${VERSION}-${ARCH}"
+!endif
+
+; Pack the exe header with upx if UPX is defined.
+!ifdef UPX
+ !packhdr "$%TEMP%\exehead.tmp" '"upx" "--ultra-brute" "$%TEMP%\exehead.tmp"'
+!endif
+
+; Version Information
+VIFileVersion "${VERSION}.0"
+VIProductVersion "${VERSION}.0"
+VIAddVersionKey /LANG=${LANGID} "Comments" "Built with NSIS ${NSIS_VERSION}"
+VIAddVersionKey /LANG=${LANGID} "CompanyName" "${COMPANY_NAME}"
+VIAddVersionKey /LANG=${LANGID} "FileVersion" "${VERSION}"
+VIAddVersionKey /LANG=${LANGID} "InternalName" "${PRODUCT_NAME}-${VERSION}-${SUFFIX}"
+VIAddVersionKey /LANG=${LANGID} "LegalTrademarks" "${TM}"
+VIAddVersionKey /LANG=${LANGID} "LegalCopyright" "${COPYRIGHT}"
+VIAddVersionKey /LANG=${LANGID} "FileDescription" "${PRODUCT_NAME} ${ARCH} Setup"
+VIAddVersionKey /LANG=${LANGID} "OriginalFilename" "${PRODUCT_NAME}-${VERSION}-${SUFFIX}.exe"
+VIAddVersionKey /LANG=${LANGID} "ProductName" "${PRODUCT_NAME}"
+VIAddVersionKey /LANG=${LANGID} "ProductVersion" "${VERSION}"
+
+; Final Attributes
+Name "${PRODUCT_NAME}"
+BrandingText "${PRODUCT_NAME} v${VERSION} Installer (${ARCH})"
+OutFile "${DIST_DIR}\..\${PRODUCT_NAME}-${VERSION}-${SUFFIX}.exe"
+
+; installer/uninstaller pages and actions
+!include "Utils.nsh"
+!include "install_pages.nsh"
+; remove next line if you're using signing after the uninstaller is extracted from the initially compiled setup
+!include "uninstall_pages.nsh"
+!include "install.nsh"
+; remove next line if you're using signing after the uninstaller is extracted from the initially compiled setup
+!include "uninstall.nsh"
diff --git a/misc/nsis/uninstall.nsh b/misc/nsis/uninstall.nsh
new file mode 100755
index 000000000..caaddd848
--- /dev/null
+++ b/misc/nsis/uninstall.nsh
@@ -0,0 +1,241 @@
+# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+#
+# This file is part of qutebrowser.
+#
+# qutebrowser 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.
+#
+# qutebrowser 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 qutebrowser. If not, see <http://www.gnu.org/licenses/>.
+
+# NSIS uninstaller header. Uses NsisMultiUser plugin and contains portions of
+# its demo code, copyright 2017 Richard Drizin, Alex Mitev.
+
+
+; Variables
+Var SemiSilentMode ; installer started uninstaller in semi-silent mode using /SS parameter
+Var RunningFromInstaller ; installer started uninstaller using /uninstall parameter
+Var RunningAsUser ; uninstaller restarted itself using the user of the running shell
+Var UserName
+
+!insertmacro DeleteRetryAbortFunc "un."
+!insertmacro CheckSingleInstanceFunc "un."
+
+Function un.GetUserName
+ System::Call "advapi32::GetUserName(t .r0, *i ${NSIS_MAX_STRLEN} r1) i.r2"
+FunctionEnd
+
+Function un.GetConfigDir
+ SetShellVarContext current
+ StrCpy $0 ${CONFIG_DIR}
+ SetShellVarContext all
+FunctionEnd
+
+Function un.GetCacheDir
+ SetShellVarContext current
+ StrCpy $0 ${CACHE_DIR}
+ SetShellVarContext all
+FunctionEnd
+
+Section "un.Program Files" SectionUninstallProgram
+ SectionIn RO
+
+ ; Call shell script to generate an uninstall-list nsh file
+ !tempfile UNLIST
+ !ifdef NSIS_WIN32_MAKENSIS
+ !execute 'cmd.exe /c .\mkunlist.cmd "${DIST_DIR}" "${UNLIST}"'
+ !else
+ !error "POSIX script for uninstall list generation is not yet available."
+ !endif
+
+ ; Try to delete the EXE as the first step - if it's in use, don't remove anything else
+ !insertmacro DeleteRetryAbort "$INSTDIR\${PROGEXE}"
+
+ ; Clean up "Dektop Icon"
+ !insertmacro MULTIUSER_GetCurrentUserString $0
+ !insertmacro DeleteRetryAbort "$DESKTOP\${PRODUCT_NAME}$0.lnk"
+
+ ; Clean up "Start Menu Icon"
+ !insertmacro MULTIUSER_GetCurrentUserString $0
+ !insertmacro DeleteRetryAbort "$STARTMENU\${PRODUCT_NAME}$0.lnk"
+
+ ; Clean up Windows Registry
+ ${if} $KeepReg = 0
+ ${if} $MultiUser.InstallMode == "AllUsers"
+ ${orif} ${AtLeastWin8}
+ DeleteRegValue SHCTX "SOFTWARE\RegisteredApplications" "${PRODUCT_NAME}"
+ DeleteRegKey SHCTX "SOFTWARE\Clients\StartMenuInternet\${PRODUCT_NAME}"
+ DeleteRegKey SHCTX "SOFTWARE\Classes\${PRODUCT_NAME}HTML"
+ DeleteRegKey SHCTX "SOFTWARE\Classes\${PRODUCT_NAME}URL"
+ DeleteRegValue SHCTX "SOFTWARE\Classes\.htm\OpenWithProgids" "${PRODUCT_NAME}HTML"
+ DeleteRegValue SHCTX "SOFTWARE\Classes\.html\OpenWithProgids" "${PRODUCT_NAME}HTML"
+ DeleteRegValue SHCTX "SOFTWARE\Classes\.pdf\OpenWithProgids" "${PRODUCT_NAME}HTML"
+ DeleteRegValue SHCTX "SOFTWARE\Classes\.shtml\OpenWithProgids" "${PRODUCT_NAME}HTML"
+ DeleteRegValue SHCTX "SOFTWARE\Classes\.svg\OpenWithProgids" "${PRODUCT_NAME}HTML"
+ DeleteRegValue SHCTX "SOFTWARE\Classes\.xht\OpenWithProgids" "${PRODUCT_NAME}HTML"
+ DeleteRegValue SHCTX "SOFTWARE\Classes\.xhtml\OpenWithProgids" "${PRODUCT_NAME}HTML"
+ DeleteRegValue SHCTX "SOFTWARE\Classes\.webp\OpenWithProgids" "${PRODUCT_NAME}HTML"
+ ${endif}
+ ${endif}
+
+ ; Include and then delete the uninstall nsh file
+ !include "${UNLIST}"
+ !delfile "${UNLIST}"
+SectionEnd
+
+SectionGroup /e "un.$UserName's Files" SectionGroupRemoveUserFiles
+
+Section /o "!un.Program Settings" SectionRemoveSettings
+ ; this section is executed only explicitly and shouldn't be placed in SectionUninstallProgram
+ ${if} $MultiUser.InstallMode == "CurrentUser"
+ !insertmacro UAC_AsUser_GetGlobal $0 ${CONFIG_DIR}
+ ${else}
+ !insertmacro UAC_AsUser_Call Function un.GetConfigDir ${UAC_SYNCREGISTERS}
+ ${endif}
+ RMDIR /r "$0\data"
+ RMDIR /r "$0\config"
+ RMDIR "$0"
+SectionEnd
+
+Section /o "un.Program Cache" SectionRemoveCache
+ ; this section is executed only explicitly and shouldn't be placed in SectionUninstallProgram
+ ${if} $MultiUser.InstallMode == "CurrentUser"
+ !insertmacro UAC_AsUser_GetGlobal $0 ${CACHE_DIR}
+ ${else}
+ !insertmacro UAC_AsUser_Call Function un.GetCacheDir ${UAC_SYNCREGISTERS}
+ ${endif}
+ RMDIR /r "$0\cache"
+ RMDIR "$0"
+SectionEnd
+
+SectionGroupEnd
+
+Section "-Uninstall" ; hidden section, must always be the last one!
+ ; we cannot use DeleteRetryAbort here - when using the _? parameter the
+ ; uninstaller cannot delete itself and Delete fails, which is OK
+ Delete "$INSTDIR\${UNINSTALL_FILENAME}"
+ ; remove the directory only if it is empty - the user might have saved some files in it
+ RMDir "$INSTDIR"
+
+ ; Remove the uninstaller from registry as the very last step
+ ; if something goes wrong, let the user run it again
+ !insertmacro MULTIUSER_RegistryRemoveInstallInfo ; Remove registry keys
+
+ ${RefreshShellIcons}
+
+ ; If the uninstaller still exists, use cmd.exe on exit to remove it (along with $INSTDIR if it's empty)
+ ${if} ${FileExists} "$INSTDIR\${UNINSTALL_FILENAME}"
+ Exec '"$SYSDIR\cmd.exe" /c (del /f /q "$INSTDIR\${UNINSTALL_FILENAME}") & (rmdir "$INSTDIR")'
+ ${endif}
+SectionEnd
+
+; Modern install component descriptions
+!insertmacro MUI_UNFUNCTION_DESCRIPTION_BEGIN
+ !insertmacro MUI_DESCRIPTION_TEXT ${SectionGroupRemoveUserFiles} \
+ "Remove quterbowser files of user $UserName."
+ !insertmacro MUI_DESCRIPTION_TEXT ${SectionUninstallProgram} \
+ "Remove ${PRODUCT_NAME} application files."
+ !insertmacro MUI_DESCRIPTION_TEXT ${SectionRemoveSettings} \
+ "Remove ${PRODUCT_NAME} user files \
+ (configuration, bookmarks, history, sessions, scripts, cookies, etc.)."
+ !insertmacro MUI_DESCRIPTION_TEXT ${SectionRemoveCache} \
+ "Remove ${PRODUCT_NAME} cache files."
+!insertmacro MUI_UNFUNCTION_DESCRIPTION_END
+
+; Callbacks
+Function un.onInit
+ !insertmacro UAC_AsUser_Call Function un.GetUserName ${UAC_SYNCREGISTERS}
+ StrCpy $UserName $0
+
+ ${GetParameters} $R0
+
+ ${GetOptions} $R0 "/user" $R1
+ ${ifnot} ${errors}
+ StrCpy $RunningAsUser 1
+ ${else}
+ StrCpy $RunningAsUser 0
+ ${endif}
+
+ ${GetOptions} $R0 "/uninstall" $R1
+ ${ifnot} ${errors}
+ StrCpy $RunningFromInstaller 1
+ ${else}
+ StrCpy $RunningFromInstaller 0
+ ${endif}
+
+ ${GetOptions} $R0 "/upgrade" $R1
+ ${ifnot} ${errors}
+ StrCpy $KeepReg 1
+ ${else}
+ StrCpy $KeepReg 0
+ ${endif}
+
+ ${GetOptions} $R0 "/SS" $R1
+ ${ifnot} ${errors}
+ StrCpy $SemiSilentMode 1
+ StrCpy $RunningFromInstaller 1
+ ; auto close (if no errors) if we are called from the installer
+ ; if there are errors, will be automatically set to false
+ SetAutoClose true
+ ${else}
+ StrCpy $SemiSilentMode 0
+ ${endif}
+
+ ; Windows stars the uninstallers elevated when called from 'Cotrol Panel' or
+ ; from 'Apps & features' (where it elevates even for per user installations).
+ ; This causes the uninstaller to run for the account used for elevation, which
+ ; may be different than the user doing the uninstall. As a workaround, the
+ ; uninstaller is restarted using the non-elevated user.
+ ${ifnot} ${UAC_IsInnerInstance}
+ ${andif} $RunningFromInstaller = 0
+ ${if} ${UAC_IsAdmin}
+ ${andif} $RunningAsUser = 0
+ ${StdUtils.ExecShellAsUser} $0 "$INSTDIR\${UNINSTALL_FILENAME}" "open" "/user $R0"
+ Quit
+ ${endif}
+ !insertmacro CheckSingleInstance "Setup" "Global" "${SETUP_MUTEX}"
+ !insertmacro CheckSingleInstance "Application" "Local" "${APP_MUTEX}"
+ ${endif}
+
+ !insertmacro MULTIUSER_UNINIT
+
+ !insertmacro MUI_UNGETLANGUAGE
+FunctionEnd
+
+Function un.PageInstallModeChangeMode
+FunctionEnd
+
+Function un.PageComponentsPre
+ ${if} $SemiSilentMode = 1
+ ; if user is installing, no use to remove program settings anyway
+ ; (should be compatible with all versions)
+ Abort
+ ${endif}
+FunctionEnd
+
+Function un.PageComponentsShow
+ ; Show/hide the Back button
+ GetDlgItem $0 $HWNDPARENT 3
+ ShowWindow $0 $UninstallShowBackButton
+FunctionEnd
+
+Function un.onUninstFailed
+ ${if} $SemiSilentMode = 0
+ MessageBox MB_ICONSTOP \
+ "${PRODUCT_NAME} ${VERSION} could not be fully uninstalled.$\r$\n\
+ Please restart Windows and run the uninstaller again." \
+ /SD IDOK
+ ${else}
+ MessageBox MB_ICONSTOP \
+ "${PRODUCT_NAME} could not be fully installed.$\r$\n\
+ Please, restart Windows and run the setup program again." \
+ /SD IDOK
+ ${endif}
+FunctionEnd
diff --git a/misc/nsis/uninstall_pages.nsh b/misc/nsis/uninstall_pages.nsh
new file mode 100755
index 000000000..8ad203ebb
--- /dev/null
+++ b/misc/nsis/uninstall_pages.nsh
@@ -0,0 +1,32 @@
+# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+#
+# This file is part of qutebrowser.
+#
+# qutebrowser 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.
+#
+# qutebrowser 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 qutebrowser. If not, see <http://www.gnu.org/licenses/>.
+
+# NSIS pages header. Uses NsisMultiUser plugin and contains portions of
+# its demo code, copyright 2017 Richard Drizin, Alex Mitev.
+
+
+; Pages
+!define MUI_UNABORTWARNING ; Show a confirmation when cancelling the installation
+
+!define MULTIUSER_INSTALLMODE_CHANGE_MODE_FUNCTION un.PageInstallModeChangeMode
+!insertmacro MULTIUSER_UNPAGE_INSTALLMODE
+
+!define MUI_PAGE_CUSTOMFUNCTION_PRE un.PageComponentsPre
+!define MUI_PAGE_CUSTOMFUNCTION_SHOW un.PageComponentsShow
+!insertmacro MUI_UNPAGE_COMPONENTS
+
+!insertmacro MUI_UNPAGE_INSTFILES
diff --git a/misc/qutebrowser.nsi b/misc/qutebrowser.nsi
deleted file mode 100644
index 76f459a78..000000000
--- a/misc/qutebrowser.nsi
+++ /dev/null
@@ -1,80 +0,0 @@
-Name "qutebrowser"
-
-Unicode true
-RequestExecutionLevel admin
-SetCompressor /solid lzma
-
-!ifdef X64
- OutFile "..\dist\qutebrowser-${VERSION}-amd64.exe"
- InstallDir "$ProgramFiles64\qutebrowser"
-!else
- OutFile "..\dist\qutebrowser-${VERSION}-win32.exe"
- InstallDir "$ProgramFiles\qutebrowser"
-!endif
-
-;Default installation folder
-
-!include "MUI2.nsh"
-;!include "MultiUser.nsh"
-
-!define MUI_ABORTWARNING
-;!define MULTIUSER_MUI
-;!define MULTIUSER_INSTALLMODE_COMMANDLINE
-!define MUI_ICON "../icons/qutebrowser.ico"
-!define MUI_UNICON "../icons/qutebrowser.ico"
-
-!insertmacro MUI_PAGE_LICENSE "..\LICENSE"
-!insertmacro MUI_PAGE_DIRECTORY
-!insertmacro MUI_PAGE_INSTFILES
-!insertmacro MUI_UNPAGE_CONFIRM
-!insertmacro MUI_UNPAGE_INSTFILES
-
-!insertmacro MUI_LANGUAGE "English"
-
-; depends on admin status
-;SetShellVarContext current
-
-
-Section "Install"
-
- ; Uninstall old versions
- ExecWait 'MsiExec.exe /quiet /qn /norestart /X{633F41F9-FE9B-42D1-9CC4-718CBD01EE11}'
- ExecWait 'MsiExec.exe /quiet /qn /norestart /X{9331D947-AC86-4542-A755-A833429C6E69}'
- IfFileExists "$INSTDIR\uninst.exe" 0 +2
- ExecWait "$INSTDIR\uninst.exe /S _?=$INSTDIR"
- CreateDirectory "$INSTDIR"
-
- SetOutPath "$INSTDIR"
-
- !ifdef X64
- file /r "..\dist\qutebrowser-${VERSION}-x64\*.*"
- !else
- file /r "..\dist\qutebrowser-${VERSION}-x86\*.*"
- !endif
-
- SetShellVarContext all
- CreateShortCut "$SMPROGRAMS\qutebrowser.lnk" "$INSTDIR\qutebrowser.exe"
-
- ;Create uninstaller
- WriteUninstaller "$INSTDIR\uninst.exe"
-
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qutebrowser" "DisplayName" "qutebrowser"
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qutebrowser" "UninstallString" '"$INSTDIR\uninst.exe"'
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qutebrowser" "QuietUninstallString" '"$INSTDIR\uninst.exe" /S'
-
-SectionEnd
-
-;--------------------------------
-;Uninstaller Section
-
-Section "Uninstall"
-
- SetShellVarContext all
- Delete "$SMPROGRAMS\qutebrowser.lnk"
-
- RMDir /r "$INSTDIR\*.*"
- RMDir "$INSTDIR"
-
- DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qutebrowser"
-
-SectionEnd
diff --git a/scripts/dev/build_release.py b/scripts/dev/build_release.py
index 2ff683b0b..0f1b49619 100755
--- a/scripts/dev/build_release.py
+++ b/scripts/dev/build_release.py
@@ -202,7 +202,7 @@ def build_mac():
def build_windows():
"""Build windows executables/setups."""
utils.print_title("Updating 3rdparty content")
- update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)
+ update_3rdparty.run(nsis=True, ace=False, pdfjs=True, fancy_dmg=False)
utils.print_title("Building Windows binaries")
parts = str(sys.version_info.major), str(sys.version_info.minor)
@@ -256,11 +256,11 @@ def build_windows():
utils.print_title("Building installers")
subprocess.run(['makensis.exe',
'/DVERSION={}'.format(qutebrowser.__version__),
- 'misc/qutebrowser.nsi'], check=True)
+ 'misc/nsis/qutebrowser.nsi'], check=True)
subprocess.run(['makensis.exe',
- '/DX64',
+ '/DX86',
'/DVERSION={}'.format(qutebrowser.__version__),
- 'misc/qutebrowser.nsi'], check=True)
+ 'misc/nsis/qutebrowser.nsi'], check=True)
name_32 = 'qutebrowser-{}-win32.exe'.format(qutebrowser.__version__)
name_64 = 'qutebrowser-{}-amd64.exe'.format(qutebrowser.__version__)
diff --git a/scripts/dev/update_3rdparty.py b/scripts/dev/update_3rdparty.py
index 3a777765e..e7226ec18 100755
--- a/scripts/dev/update_3rdparty.py
+++ b/scripts/dev/update_3rdparty.py
@@ -35,6 +35,35 @@ from scripts import dictcli
from qutebrowser.config import configdata
+def download_nsis_plugins():
+ """Download the plugins required by the NSIS script"""
+ github_url = 'https://raw.githubusercontent.com/Drizin/NsisMultiUser'
+ git_commit = 'master'
+ nsh_files = ('Include/NsisMultiUser.nsh', 'Include/NsisMultiUserLang.nsh',
+ 'Include/UAC.nsh', 'Include/StdUtils.nsh',
+ 'Demos/Common/Utils.nsh')
+ dll_files = ('Plugins/x86-unicode/UAC.dll',
+ 'Plugins/x86-unicode/StdUtils.dll')
+ include_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+ '..', '..', 'misc', 'nsis',
+ 'include')
+ plugins_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+ '..', '..', 'misc', 'nsis',
+ 'plugins', 'x86-unicode')
+ os.makedirs(include_dir, exist_ok=True)
+ os.makedirs(plugins_dir, exist_ok=True)
+ print("=> Downloading NSIS plugins")
+ for nsh_file in nsh_files:
+ target_path = os.path.join(include_dir, os.path.basename(nsh_file))
+ urllib.request.urlretrieve('{}/{}/{}'.format(github_url, git_commit,
+ nsh_file), target_path)
+ for dll_file in dll_files:
+ target_path = os.path.join(plugins_dir, os.path.basename(dll_file))
+ urllib.request.urlretrieve('{}/{}/{}'.format(github_url, git_commit,
+ dll_file), target_path)
+ urllib.request.urlcleanup()
+
+
def get_latest_pdfjs_url():
"""Get the URL of the latest pdf.js prebuilt package.
@@ -129,9 +158,11 @@ def test_dicts():
print('ERROR: {}'.format(response.status))
-def run(ace=False, pdfjs=True, fancy_dmg=False, pdfjs_version=None,
+def run(nsis=False, ace=False, pdfjs=True, fancy_dmg=False, pdfjs_version=None,
dicts=False):
"""Update components based on the given arguments."""
+ if nsis:
+ download_nsis_plugins()
if pdfjs:
update_pdfjs(pdfjs_version)
if ace:
@@ -144,6 +175,8 @@ def run(ace=False, pdfjs=True, fancy_dmg=False, pdfjs_version=None,
def main():
parser = argparse.ArgumentParser()
+ parser.add_argument('--nsis', '-n', help='Download NSIS plugins.',
+ required=False, action='store_true')
parser.add_argument(
'--pdfjs', '-p',
help='Specify pdfjs version. If not given, '
@@ -157,7 +190,7 @@ def main():
'can be reached at the remote repository.',
required=False, action='store_true')
args = parser.parse_args()
- run(ace=True, pdfjs=True, fancy_dmg=args.fancy_dmg,
+ run(nsis=False, ace=True, pdfjs=True, fancy_dmg=args.fancy_dmg,
pdfjs_version=args.pdfjs, dicts=args.dicts)