Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ No version number is assigned to this update.
- Added a dedicated maximized Chrome/Edge app window using its own browser profile.
- Closing the dedicated Parroty app window now automatically stops the hidden
Flask backend, matching `stop.bat` behavior without affecting normal browser windows.
- Corrected that shutdown detection to monitor the exact native Parroty window
handle rather than waiting for the Chromium process, which may remain alive
after its app window is closed.
- Added desktop-shortcut creation using the Parroty icon.
- Corrected hidden-launch template/static resolution.
- Kept narration workers GPU-enabled when the app window is hidden or inactive.
Expand Down
45 changes: 42 additions & 3 deletions parroty_window.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ public static class ParrotyNativeWindow {

[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern bool IsWindow(IntPtr hWnd);
}
"@
} catch {}
Expand Down Expand Up @@ -137,6 +140,41 @@ public static class ParrotyNativeWindow {
return $InitialProcess
}

function Wait-ParrotyWindowClose {
param(
[IntPtr]$WindowHandle,
[System.Diagnostics.Process]$WindowProcess,
[scriptblock]$WindowExists = $null,
[int]$PollMilliseconds = 250
)

# Chrome and Edge may keep their process alive after an app-mode window is
# closed. Watch the exact native window handle instead of waiting for the
# Chromium process to exit.
if ($WindowHandle -ne [IntPtr]::Zero) {
if (-not $WindowExists) {
$WindowExists = {
param([IntPtr]$Handle)
[ParrotyNativeWindow]::IsWindow($Handle)
}
}

while ($true) {
$windowStillExists = $false
try {
$windowStillExists = [bool](& $WindowExists $WindowHandle)
} catch {}

if (-not $windowStillExists) { break }
Start-Sleep -Milliseconds ([Math]::Max(10, $PollMilliseconds))
}
return
}

# Last-resort fallback if Chromium never exposed a usable native handle.
try { $WindowProcess.WaitForExit() } catch {}
}

$browser = Find-Browser
if (-not $browser) {
# A normal browser tab cannot be reliably monitored for its close event, so
Expand Down Expand Up @@ -174,10 +212,11 @@ if (-not $process) {
}

$windowProcess = Maximize-ParrotyWindow -InitialProcess $process -BrowserPath $browser -LaunchTime $launchTime
$windowHandle = [IntPtr]$windowProcess.MainWindowHandle
Set-Content -LiteralPath (Join-Path $Root ".parroty.browser.pid") -Value $windowProcess.Id

# Wait for the dedicated Parroty app window—not the user's normal browser—to be
# closed with X. Closing it is treated the same as running stop.bat.
try { $windowProcess.WaitForExit() } catch {}
# Watch the actual Parroty app window. Closing it with X is treated the same as
# running stop.bat, even if Chromium keeps its process alive in the background.
Wait-ParrotyWindowClose -WindowHandle $windowHandle -WindowProcess $windowProcess
Remove-Item -LiteralPath (Join-Path $Root ".parroty.browser.pid") -Force -ErrorAction SilentlyContinue
Stop-ParrotyBackend -ProcessIds $backendPids