Skip to content

Commit 69a0a77

Browse files
committed
Add CI, icon, GitVersion, Azure Trusted Signing
- GitHub Actions build.yml: tag-triggered releases for x64 + ARM64 - GitVersion.yml: ContinuousDelivery, v-prefix tags, MajorMinorPatch - Azure Trusted Signing with hanselman/WindowsEdgeLight profile - App icon: window-to-desktop with green arrow and + indicator - PublishSingleFile + IncludeNativeLibrariesForSelfExtract in csproj - Fix Shift+Click: post COM calls to UI thread (RPC_E_CANTCALLOUT fix) Matches BabySmash/WindowsEdgeLight CI patterns exactly.
1 parent 79510d6 commit 69a0a77

File tree

6 files changed

+183
-7
lines changed

6 files changed

+183
-7
lines changed

.github/workflows/build.yml

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
name: Build Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: write
11+
12+
jobs:
13+
build:
14+
runs-on: windows-latest
15+
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v6
19+
with:
20+
fetch-depth: 0
21+
22+
- name: Setup .NET
23+
uses: actions/setup-dotnet@v5
24+
with:
25+
dotnet-version: '8.0.x'
26+
27+
- name: Restore dependencies
28+
run: dotnet restore src/MaximizeToVirtualDesktop/MaximizeToVirtualDesktop.csproj
29+
30+
- name: Install GitVersion
31+
uses: gittools/actions/gitversion/setup@v4
32+
with:
33+
versionSpec: '6.4.x'
34+
35+
- name: GitVersion
36+
uses: gittools/actions/gitversion/execute@v4
37+
id: gitversion
38+
39+
- name: Set version environment variables
40+
shell: pwsh
41+
run: |
42+
$version = '${{ steps.gitversion.outputs.semVer }}'
43+
$fullVersion = '${{ steps.gitversion.outputs.fullSemVer }}'
44+
$assemblyVersion = "${{ steps.gitversion.outputs.major }}.${{ steps.gitversion.outputs.minor }}.${{ steps.gitversion.outputs.patch }}.0"
45+
46+
Write-Host "SemVer: $version"
47+
Write-Host "FullSemVer: $fullVersion"
48+
Write-Host "AssemblyVersion: $assemblyVersion"
49+
50+
echo "VERSION=$version" >> $env:GITHUB_ENV
51+
echo "FULLVERSION=$fullVersion" >> $env:GITHUB_ENV
52+
echo "ASSEMBLY_VERSION=$assemblyVersion" >> $env:GITHUB_ENV
53+
54+
- name: Publish x64
55+
run: |
56+
dotnet publish src/MaximizeToVirtualDesktop/MaximizeToVirtualDesktop.csproj `
57+
-c Release `
58+
-r win-x64 `
59+
/p:DebugType=None `
60+
/p:DebugSymbols=false `
61+
/p:Version=$env:VERSION `
62+
/p:AssemblyVersion=$env:ASSEMBLY_VERSION `
63+
/p:FileVersion=$env:ASSEMBLY_VERSION `
64+
/p:AssemblyInformationalVersion=$env:FULLVERSION `
65+
--self-contained
66+
67+
- name: Publish ARM64
68+
run: |
69+
dotnet publish src/MaximizeToVirtualDesktop/MaximizeToVirtualDesktop.csproj `
70+
-c Release `
71+
-r win-arm64 `
72+
/p:DebugType=None `
73+
/p:DebugSymbols=false `
74+
/p:Version=$env:VERSION `
75+
/p:AssemblyVersion=$env:ASSEMBLY_VERSION `
76+
/p:FileVersion=$env:ASSEMBLY_VERSION `
77+
/p:AssemblyInformationalVersion=$env:FULLVERSION `
78+
--self-contained
79+
80+
- name: Azure Login
81+
uses: azure/login@v2
82+
with:
83+
creds: '{"clientId":"${{ secrets.AZURE_CLIENT_ID }}","clientSecret":"${{ secrets.AZURE_CLIENT_SECRET }}","subscriptionId":"${{ secrets.AZURE_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZURE_TENANT_ID }}"}'
84+
85+
- name: Sign executables with Trusted Signing
86+
uses: azure/trusted-signing-action@v1
87+
with:
88+
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
89+
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
90+
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
91+
endpoint: https://wus2.codesigning.azure.net/
92+
trusted-signing-account-name: hanselman
93+
certificate-profile-name: WindowsEdgeLight
94+
files-folder: ${{ github.workspace }}\src\MaximizeToVirtualDesktop\bin\Release\net8.0-windows
95+
files-folder-filter: exe
96+
files-folder-recurse: true
97+
file-digest: SHA256
98+
timestamp-rfc3161: http://timestamp.acs.microsoft.com
99+
timestamp-digest: SHA256
100+
101+
- name: Prepare artifacts
102+
shell: pwsh
103+
run: |
104+
New-Item -ItemType Directory -Path artifacts -Force
105+
$version = $env:VERSION
106+
107+
New-Item -ItemType Directory -Path "temp-x64" -Force
108+
Copy-Item "src/MaximizeToVirtualDesktop/bin/Release/net8.0-windows/win-x64/publish/MaximizeToVirtualDesktop.exe" -Destination "temp-x64/"
109+
Copy-Item "README.md" -Destination "temp-x64/"
110+
Compress-Archive -Path "temp-x64/*" -DestinationPath "artifacts/MaximizeToVirtualDesktop-v$version-win-x64.zip"
111+
112+
New-Item -ItemType Directory -Path "temp-arm64" -Force
113+
Copy-Item "src/MaximizeToVirtualDesktop/bin/Release/net8.0-windows/win-arm64/publish/MaximizeToVirtualDesktop.exe" -Destination "temp-arm64/"
114+
Copy-Item "README.md" -Destination "temp-arm64/"
115+
Compress-Archive -Path "temp-arm64/*" -DestinationPath "artifacts/MaximizeToVirtualDesktop-v$version-win-arm64.zip"
116+
117+
Remove-Item "temp-x64" -Recurse -Force
118+
Remove-Item "temp-arm64" -Recurse -Force
119+
120+
- name: Upload artifacts
121+
uses: actions/upload-artifact@v6
122+
with:
123+
name: MaximizeToVirtualDesktop-Release
124+
path: artifacts/*.zip
125+
126+
- name: Create Release
127+
if: startsWith(github.ref, 'refs/tags/')
128+
uses: softprops/action-gh-release@v2
129+
with:
130+
files: artifacts/*.zip
131+
generate_release_notes: true
132+
body: |
133+
## MaximizeToVirtualDesktop ${{ github.ref_name }}
134+
135+
macOS green-button behavior for Windows 11 — maximize any window to its own virtual desktop.
136+
137+
### 📦 Downloads
138+
139+
| File | Platform |
140+
|------|----------|
141+
| `MaximizeToVirtualDesktop-${{ github.ref_name }}-win-x64.zip` | Intel/AMD 64-bit Windows |
142+
| `MaximizeToVirtualDesktop-${{ github.ref_name }}-win-arm64.zip` | ARM64 Windows (Surface Pro X, etc.) |
143+
144+
**Self-contained** — extract and run, no .NET installation required.
145+
146+
### ⌨️ Usage
147+
- `Ctrl+Alt+Shift+X` — toggle maximize to virtual desktop
148+
- `Shift+Click` maximize button — same effect
149+
- System tray icon for Restore All / Exit
150+
151+
---
152+
append_body: true
153+
env:
154+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

GitVersion.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
mode: ContinuousDelivery
2+
tag-prefix: 'v'
3+
4+
assembly-versioning-scheme: MajorMinorPatch
5+
6+
branches:
7+
main:
8+
regex: ^(master|main)$
9+
label: ''
10+
increment: Patch
11+
12+
ignore:
13+
sha: []

src/MaximizeToVirtualDesktop/MaximizeButtonHook.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@ namespace MaximizeToVirtualDesktop;
1111
internal sealed class MaximizeButtonHook : IDisposable
1212
{
1313
private readonly FullScreenManager _manager;
14+
private readonly Control _syncControl;
1415
private IntPtr _hookHandle;
1516
private bool _disposed;
1617

1718
// Must be stored as a field to prevent GC collection
1819
private readonly NativeMethods.LowLevelHookProc _hookProc;
1920

20-
public MaximizeButtonHook(FullScreenManager manager)
21+
public MaximizeButtonHook(FullScreenManager manager, Control syncControl)
2122
{
2223
_manager = manager;
24+
_syncControl = syncControl;
2325
_hookProc = HookCallback;
2426
}
2527

@@ -55,15 +57,19 @@ private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
5557

5658
if (hwnd != IntPtr.Zero && IsClickOnMaximizeButton(hwnd, hookStruct.pt))
5759
{
58-
Trace.WriteLine($"MaximizeButtonHook: Shift+Click on maximize button of {hwnd}");
59-
6060
// Find the top-level window (the click target might be a child)
6161
var topLevel = GetTopLevelWindow(hwnd);
6262
if (topLevel != IntPtr.Zero)
6363
{
64-
_manager.Toggle(topLevel);
64+
Trace.WriteLine($"MaximizeButtonHook: Shift+Click on maximize button of {topLevel}");
65+
66+
// Post to UI thread — COM calls cannot be made inside an input-synchronous hook
67+
if (!_syncControl.IsDisposed && _syncControl.IsHandleCreated)
68+
{
69+
_syncControl.BeginInvoke(() => _manager.Toggle(topLevel));
70+
}
6571

66-
// Suppress the click — return non-zero to prevent it reaching the window
72+
// Suppress the click
6773
return (IntPtr)1;
6874
}
6975
}

src/MaximizeToVirtualDesktop/MaximizeToVirtualDesktop.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
<AssemblyName>MaximizeToVirtualDesktop</AssemblyName>
1111
<RootNamespace>MaximizeToVirtualDesktop</RootNamespace>
1212
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
13+
<PublishSingleFile>true</PublishSingleFile>
14+
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
15+
<ApplicationIcon>app.ico</ApplicationIcon>
1316
</PropertyGroup>
1417

1518
</Project>

src/MaximizeToVirtualDesktop/TrayApplication.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ public TrayApplication()
3434
_tracker = new FullScreenTracker();
3535
_manager = new FullScreenManager(_vds, _tracker);
3636
_monitor = new WindowMonitor(_manager, _tracker, this);
37-
_mouseHook = new MaximizeButtonHook(_manager);
37+
_mouseHook = new MaximizeButtonHook(_manager, this);
3838

3939
// System tray icon
4040
_trayIcon = new NotifyIcon
4141
{
42-
Icon = SystemIcons.Application, // TODO: custom icon
42+
Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath) ?? SystemIcons.Application,
4343
Text = "Maximize to Virtual Desktop",
4444
Visible = true,
4545
ContextMenuStrip = BuildContextMenu()
10.7 KB
Binary file not shown.

0 commit comments

Comments
 (0)