diff --git a/.github/workflows/build_win.yml b/.github/workflows/build_win.yml index 391a13c5..904d7482 100644 --- a/.github/workflows/build_win.yml +++ b/.github/workflows/build_win.yml @@ -19,7 +19,7 @@ jobs: - name: Checkout Source uses: actions/checkout@v4 - - name: Download Artifacts + - name: Download Assets uses: actions/download-artifact@v4 with: name: nw-assets diff --git a/.github/workflows/build_win_launcher.yml b/.github/workflows/build_win_launcher.yml new file mode 100644 index 00000000..901f8a0d --- /dev/null +++ b/.github/workflows/build_win_launcher.yml @@ -0,0 +1,45 @@ +name: BuildWindowsLauncher + +on: workflow_dispatch + +jobs: + buildLauncherWin64: + runs-on: windows-latest + steps: + - name: Checkout Source + uses: actions/checkout@v4 + + - name: Build Launcher + id: build + run: | + Set-Location setup\windows + .\make.ps1 + + - name: Upload Unsigned Artifacts + id: upload-unsigned-artifact + uses: actions/upload-artifact@v4 + with: + name: launcher + path: setup/windows/novelWriter.exe + if-no-files-found: error + retention-days: 14 + + - name: Submit Signing Request + uses: signpath/github-action-submit-signing-request@v1 + with: + api-token: "${{ secrets.SIGNPATH_API_TOKEN }}" + organization-id: "0471e52c-66fa-4e9a-bfb9-36167095ca3f" + project-slug: "novelWriter" + signing-policy-slug: "release-signing" + artifact-configuration-slug: "launcher" + github-artifact-id: "${{ steps.upload-unsigned-artifact.outputs.artifact-id }}" + wait-for-completion: true + output-artifact-directory: "." + + - name: Upload Signed Artifacts + uses: actions/upload-artifact@v4 + with: + name: launcher-signed + path: novelWriter.exe + if-no-files-found: error + retention-days: 14 diff --git a/.gitignore b/.gitignore index 90e51a5d..fd69c45f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ setup.iss /novelwriter.desktop /novelWriter.pyw /setup/macos/Info.plist +/setup/windows/build .venv # Translations diff --git a/setup/win_setup_embed.iss b/setup/win_setup_embed.iss index f4c55ac9..e1d15de7 100644 --- a/setup/win_setup_embed.iss +++ b/setup/win_setup_embed.iss @@ -5,7 +5,6 @@ #define nwAppVersion "%%version%%" #define nwAppPublisher "novelWriter" #define nwAppURL "https://novelWriter.io" -#define nwAppExeName "novelWriter.pyw" [Setup] AppId={{459A75D0-951F-4932-9809-6002EC8E733E} @@ -50,15 +49,15 @@ Type: filesandordirs; Name: "{app}\novelwriter\*" Source: "{#nwAppDir}\novelWriter\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs [Icons] -Name: "{autoprograms}\{#nwAppName}"; Filename: "{app}\pythonw.exe"; Parameters: "{#nwAppExeName}"; IconFilename: "{app}\novelwriter.ico" -Name: "{autodesktop}\{#nwAppName}"; Filename: "{app}\pythonw.exe"; Parameters: "{#nwAppExeName}"; IconFilename: "{app}\novelwriter.ico"; Tasks: desktopicon; +Name: "{autoprograms}\{#nwAppName}"; Filename: "{app}\novelWriter.exe"; IconFilename: "{app}\novelWriter.ico" +Name: "{autodesktop}\{#nwAppName}"; Filename: "{app}\novelWriter.exe"; IconFilename: "{app}\novelWriter.ico"; Tasks: desktopicon; [Run] -Filename: "{app}\pythonw.exe"; Parameters: "{#nwAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(nwAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent +Filename: "{app}\novelWriter.exe"; Description: "{cm:LaunchProgram,{#StringChange(nwAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent [Registry] Root: HKA; Subkey: "Software\Classes\.nwx\OpenWithProgids"; ValueType: string; ValueName: "novelWriterProject.nwx"; ValueData: ""; Flags: uninsdeletevalue Root: HKA; Subkey: "Software\Classes\novelWriterProject.nwx"; ValueType: string; ValueName: ""; ValueData: "novelWriter Project File"; Flags: uninsdeletekey Root: HKA; Subkey: "Software\Classes\novelWriterProject.nwx\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\novelwriter\assets\icons\x-novelwriter-project.ico" -Root: HKA; Subkey: "Software\Classes\novelWriterProject.nwx\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\pythonw.exe"" ""{app}\{#nwAppExeName}"" ""%1""" -Root: HKA; Subkey: "Software\Classes\Applications\{#nwAppExeName}\SupportedTypes"; ValueType: string; ValueName: ".nwx"; ValueData: ""; Flags: uninsdeletekey +Root: HKA; Subkey: "Software\Classes\novelWriterProject.nwx\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\novelWriter.exe"" ""%1""" +Root: HKA; Subkey: "Software\Classes\Applications\novelWriter.exe\SupportedTypes"; ValueType: string; ValueName: ".nwx"; ValueData: ""; Flags: uninsdeletekey diff --git a/setup/windows/CMakeLists.txt b/setup/windows/CMakeLists.txt new file mode 100644 index 00000000..4f1ec280 --- /dev/null +++ b/setup/windows/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.14) + +project(novelWriter LANGUAGES CXX) + +add_executable(novelWriter main.cpp launcher.rc) diff --git a/setup/windows/launcher.rc b/setup/windows/launcher.rc new file mode 100644 index 00000000..d8ad36e2 --- /dev/null +++ b/setup/windows/launcher.rc @@ -0,0 +1,22 @@ +IDI_ICON1 ICON DISCARDABLE "novelwriter.ico" +1 VERSIONINFO +FILEVERSION 1,0,0,0 +PRODUCTVERSION 1,0,0,0 +FILEOS 0x4 +FILETYPE 0x1 +{ + BLOCK "StringFileInfo" { + BLOCK "040904b0" { + VALUE "CompanyName", "Veronica Berglyd Olsen\0" + VALUE "FileDescription", "novelWriter Launcher\0" + VALUE "FileVersion", "1.0.0.0\0" + VALUE "LegalCopyright", "© 2025 Veronica Berglyd Olsen\0" + VALUE "OriginalFilename", "novelWriter.exe\0" + VALUE "ProductName", "novelWriter\0" + VALUE "ProductVersion", "1.0.0.0\0" + } + } + BLOCK "VarFileInfo" { + VALUE "Translation", 0x0809, 1200 + } +} diff --git a/setup/windows/main.cpp b/setup/windows/main.cpp new file mode 100644 index 00000000..052f57c6 --- /dev/null +++ b/setup/windows/main.cpp @@ -0,0 +1,51 @@ +/* +** novelWriter - Windows Launcher +** ============================== +** +** This file is a part of novelWriter +** Copyright (C) 2025 Veronica Berglyd Olsen and novelWriter contributors +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, but +** WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +#include +#include +#include +#include + +void _tmain( int argc, TCHAR *argv[] ) { + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + + TCHAR fileName[MAX_PATH]; + auto pathlen = GetModuleFileName(NULL, fileName, MAX_PATH); + fileName[pathlen - 15] = 0; + SetCurrentDirectory(fileName); + std::cout << "WorkDir: " << fileName << std::endl; + + TCHAR cmd[MAX_PATH] = "pythonw.exe novelWriter.pyw"; + if (argc > 1) { + _tcscat_s(cmd, TEXT(" ")); + _tcscat_s(cmd, argv[1]); + } + std::cout << "Command: " << cmd << std::endl; + + CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + + return; +} diff --git a/setup/windows/make.ps1 b/setup/windows/make.ps1 new file mode 100644 index 00000000..2056ce63 --- /dev/null +++ b/setup/windows/make.ps1 @@ -0,0 +1,11 @@ +if (Test-Path .\build) { + Remove-Item .\build -Recurse +} +New-Item -Path . -Name build -ItemType Directory +Set-Location .\build + +cmake -S .. -B . +cmake --build . --config Release + +Set-Location .. +Copy-Item .\build\Release\novelWriter.exe . -Force diff --git a/setup/windows/novelWriter.exe b/setup/windows/novelWriter.exe new file mode 100644 index 00000000..5026cddb Binary files /dev/null and b/setup/windows/novelWriter.exe differ diff --git a/setup/windows/novelWriter.ico b/setup/windows/novelWriter.ico new file mode 100644 index 00000000..54301ffe Binary files /dev/null and b/setup/windows/novelWriter.ico differ diff --git a/utils/build_windows.py b/utils/build_windows.py index c6401dfd..1a94632a 100644 --- a/utils/build_windows.py +++ b/utils/build_windows.py @@ -44,8 +44,9 @@ def prepareCode(outDir: Path) -> None: ROOT_DIR / "CREDITS.md", ROOT_DIR / "LICENSE.md", ROOT_DIR / "requirements.txt", - SETUP_DIR / "icons" / "novelwriter.ico", SETUP_DIR / "iss_license.txt", + SETUP_DIR / "windows" / "novelWriter.ico", + SETUP_DIR / "windows" / "novelWriter.exe", ] for item in files: @@ -203,7 +204,7 @@ def main(args: argparse.Namespace) -> None: outDir.mkdir() libDir.mkdir() - copySourceCode(outDir) + prepareCode(outDir) embedPython(bldDir, outDir) installRequirements(libDir) removeRedundantQt(libDir)