private/90-desktop.ps1
|
# --------------------------------------------------------------------- desktop -- function Show-UI4MEUiFileDialog { <# .SYNOPSIS Native open/save/folder dialog. Returns a path (an array with -Multiple) or $null when cancelled. .DESCRIPTION The window stays responsive while the dialog is open; a user close still asks -OnCloseRequest. -Filters: @{ 'Images' = @('png','jpg') }. #> [CmdletBinding()] param([ValidateSet('Open', 'Save', 'Folder')][string]$Kind = 'Open', [string]$Title, [string]$Directory, [string]$FileName, [hashtable]$Filters, [switch]$Multiple) $ctx = Assert-UiBuilder if (-not $ctx.Window) { throw 'File dialogs need a running application.' } $params = @{ Window = $ctx.Window; Kind = @{ Open = 'OpenFiles'; Save = 'SaveFile'; Folder = 'ChooseFolder' }[$Kind] } if ($Title) { $params.Title = $Title } if ($Directory) { $params.Directory = $Directory } if ($FileName) { $params.FileName = $FileName } if ($Kind -eq 'Open') { $params.Multiple = [bool]$Multiple } if ($Filters -and $Kind -ne 'Folder') { $params.Filters = @($Filters.Keys | ForEach-Object { @{ name = [string]$_; extensions = @($Filters[$_]) } }) } $result = Show-UI4MEFileDialog @params $paths = @() if ($null -ne $result -and $result.PSObject.Properties['paths'] -and $null -ne $result.paths) { $paths = @($result.paths) } if ($paths.Count -eq 0) { return $null } if ($Multiple) { return , $paths } return [string]$paths[0] } function Start-UI4MEUiScript { <# .SYNOPSIS Legacy compatibility launcher. Normal usage is `pwsh -File app.ps1`; Invoke-UI4MEApp starts Core itself. .PARAMETER WindowsPowerShell On Windows, run the backend with Windows PowerShell 5.1 (powershell.exe) instead of this PowerShell. #> [CmdletBinding()] param([Parameter(Mandatory)][string]$Path, [string]$Title, [string]$AppId = 'org.ui4me.UserApp', [switch]$WindowsPowerShell, [switch]$NoWait, [switch]$Headless) Import-Module UI4ME.Core -ErrorAction Stop $source = (Resolve-Path -LiteralPath $Path -ErrorAction Stop).Path if ($AppId -notmatch '^[A-Za-z][A-Za-z0-9_.-]*$') { throw 'AppId may contain only ASCII letters, digits, dots, hyphens and underscores' } $appTitle = if ($Title) { $Title } else { [System.IO.Path]::GetFileNameWithoutExtension($source) } if ($WindowsPowerShell -or $PSVersionTable.PSEdition -eq 'Desktop') { if (-not (Test-Path -LiteralPath (Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\powershell.exe'))) { throw 'Windows PowerShell 5.1 is not available' } # Retain a bare process name for compatibility; Core 1.0.1 also # correctly supports absolute Windows PowerShell 5.1 program paths. $program = 'powershell.exe' } else { $program = (Get-Process -Id $PID).Path } if (-not $program) { throw 'Could not resolve the PowerShell executable' } $temp = Join-Path ([System.IO.Path]::GetTempPath()) ('ui4me-ps-' + [guid]::NewGuid().ToString('N')) $null = New-Item -ItemType Directory -Path $temp -Force $manifest = Join-Path $temp 'app.toml' $q = { param($s) '"' + ([string]$s).Replace('\', '\\').Replace('"', '\"') + '"' } $toml = @( '[app]', ('id = ' + (& $q $AppId)), ('name = ' + (& $q $appTitle)), 'version = "2.1.0"', '', '[backend]', ('program = ' + (& $q $program)), ('args = ["-NoLogo", "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", ' + (& $q $source) + ']'), ('cwd = ' + (& $q (Split-Path -Parent $source))), '', '[host]', 'startup_timeout_ms = 30000', 'shutdown_timeout_ms = 5000', 'max_windows = 16', 'instance = "multiple"' ) -join "`n" if ($toml -match '[\x00-\x08\x0b-\x1f]') { throw 'Control characters are not allowed in the manifest values' } [System.IO.File]::WriteAllText($manifest, $toml + "`n", (New-Object System.Text.UTF8Encoding($false))) if ($Headless) { # Test mode: the real host without a desktop window (no native input, focus or dialogs). try { & (Get-UI4MEHostPath) run --headless --app $manifest if ($LASTEXITCODE -ne 0) { throw "UI4ME host exited with code $LASTEXITCODE" } } finally { Remove-Item -LiteralPath $temp -Recurse -Force -ErrorAction SilentlyContinue } return } if ($NoWait) { return (Start-UI4MEHost -Manifest $manifest -NoWait) } try { Start-UI4MEHost -Manifest $manifest } finally { Remove-Item -LiteralPath $temp -Recurse -Force -ErrorAction SilentlyContinue } } |