Functions/GenXdev.Windows/Pop-Window.ps1
################################################################################ <# .SYNOPSIS Pops the last active window helper from the stack with optional modifications. .DESCRIPTION Pops a window helper from the stack and optionally applies window transformations. If the stack is empty or contains invalid windows, returns the currently focused window. This function allows you to manipulate windows that were previously saved with Push-Window, applying various positioning, sizing, and visual effects. .PARAMETER Maximize Maximizes the window after popping it from the stack. .PARAMETER Minimize Minimizes the window after popping it from the stack. .PARAMETER Restore Restores the window to its normal state after popping it from the stack. .PARAMETER Hide Hides the window after popping it from the stack. .PARAMETER Show Ensures the window is visible after popping it from the stack. .PARAMETER NoBorders Removes the window borders after popping it from the stack. .PARAMETER AlwaysOnTop Sets the window to always be on top after popping it from the stack. .PARAMETER Opacity Sets the window opacity (0-255) after popping it from the stack. .PARAMETER X Sets the window X position after popping it from the stack. .PARAMETER Y Sets the window Y position after popping it from the stack. .PARAMETER Width Sets the window width after popping it from the stack. .PARAMETER Height Sets the window height after popping it from the stack. .PARAMETER Focus Focuses the window after popping it from the stack. .PARAMETER FadeIn Applies a fade-in effect when showing the window after popping it from the stack. .PARAMETER NoModify Pops the window but doesn't apply any modifications (just returns it). .PARAMETER Left Places window on left half of screen after popping it from the stack. .PARAMETER Right Places window on right half of screen after popping it from the stack. .PARAMETER Top Places window on top half of screen after popping it from the stack. .PARAMETER Bottom Places window on bottom half of screen after popping it from the stack. .PARAMETER Centered Centers window on screen after popping it from the stack. .PARAMETER Fullscreen Fills window to entire screen after popping it from the stack. .PARAMETER Monitor Specifies the monitor to move the window to after popping from the stack: 0 = Primary monitor (default) 1..n = Specific monitor (1-based index) -2 = Secondary monitor (uses $Global:DefaultSecondaryMonitor if defined) .EXAMPLE Pop-Window -Maximize -Focus # Pops the last window from the stack, maximizes it and gives it focus. .EXAMPLE Pop-Window -X 100 -Y 100 -Width 800 -Height 600 -AlwaysOnTop # Pops the last window, positions it at coordinates (100,100), # resizes it to 800x600, and sets it to always stay on top. .EXAMPLE popw -Left -Focus # Pops the last window, positions it on the left half of the screen, # and gives it focus using the alias. .EXAMPLE Pop-Window -Monitor 1 -Maximize # Pops the last window, moves it to the first monitor, and maximizes it. .EXAMPLE Pop-Window -Monitor -2 -Fullscreen # Pops the last window, moves it to the secondary monitor, and makes it fullscreen. #> ################################################################################ function Pop-Window { ############################################################################ [CmdletBinding(DefaultParameterSetName = "Default")] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidGlobalVars", "")] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")] [Alias("popw")] param ( ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $Maximize, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $Minimize, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $Restore, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $Hide, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $Show, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $NoBorders, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $AlwaysOnTop, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [ValidateRange(0, 255)] [byte] $Opacity, ######################################################################## [Parameter( ParameterSetName = "Position", Mandatory = $true )] [int] $X, ######################################################################## [Parameter( ParameterSetName = "Position", Mandatory = $true )] [int] $Y, ######################################################################## [Parameter( ParameterSetName = "Dimensions", Mandatory = $true )] [int] $Width, ######################################################################## [Parameter( ParameterSetName = "Dimensions", Mandatory = $true )] [int] $Height, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $Focus, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $FadeIn, ######################################################################## [Parameter( ParameterSetName = "NoModify" )] [switch] $NoModify, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $Left, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $Right, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $Top, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $Bottom, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $Centered, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [switch] $Fullscreen, ######################################################################## [Parameter( ParameterSetName = "Default" )] [Parameter( ParameterSetName = "Position" )] [Parameter( ParameterSetName = "Dimensions" )] [ValidateNotNull()] [int] $Monitor ) ############################################################################ begin { # Check if the type already exists $typeName = "Win32.Unique2165442User32" $typeExists = $null -ne [System.Type]::GetType($typeName) # define the iswindow function from user32.dll if it doesn't already exist if (-not $typeExists) { Microsoft.PowerShell.Utility\Add-Type -Namespace Win32 -Name Unique2165442User32 ` -MemberDefinition @" [DllImport("user32.dll")] public static extern bool IsWindow(IntPtr hWnd); "@ -Language CSharp } } ############################################################################ process { # helper function to check if a window handle is still valid function IsWindowValid { param ( [Parameter(Mandatory)] [IntPtr] $Handle ) return [Win32.Unique2165442User32]::IsWindow($Handle) } # initialize the popped window variable to null [GenXdev.Helpers.WindowObj] $poppedWindow = $null # Check if window stack exists if (-not $Global:GenXdevWindowStack) { Microsoft.PowerShell.Utility\Write-Verbose "Window stack doesn't exist, initializing" $Global:GenXdevWindowStack = [System.Collections.Concurrent.ConcurrentQueue[GenXdev.Helpers.WindowObj]]::new() } # Log stack status Microsoft.PowerShell.Utility\Write-Verbose "Window stack empty: $($Global:GenXdevWindowStack.IsEmpty)" # try to get a valid window from the stack, discarding invalid handles while ($Global:GenXdevWindowStack -and -not $Global:GenXdevWindowStack.IsEmpty) { # attempt to dequeue a window from the stack $Global:GenXdevWindowStack.TryDequeue([ref]$poppedWindow) | Microsoft.PowerShell.Core\Out-Null # check if window is valid; if so, break the loop if ($poppedWindow -and $poppedWindow.Handle -and (IsWindowValid -Handle $poppedWindow.Handle)) { Microsoft.PowerShell.Utility\Write-Verbose "Found valid window in stack, Handle: $($poppedWindow.Handle), Title: $($poppedWindow.Title)" break } # reset to null if window was invalid Microsoft.PowerShell.Utility\Write-Verbose "Discarded invalid window from stack" $poppedWindow = $null } # if no valid window found, push current window and use that instead if (-not $poppedWindow) { Microsoft.PowerShell.Utility\Write-Verbose "No valid window in stack, getting current window" try { # Get the current foreground window directly $foregroundHandle = GenXdev.Windows\Get-CurrentFocusedWindow if ($foregroundHandle -ne 0) { Microsoft.PowerShell.Utility\Write-Verbose "Got foreground window handle: $foregroundHandle" $poppedWindow = [GenXdev.Helpers.WindowObj]::GetMainWindow($foregroundHandle) Microsoft.PowerShell.Utility\Write-Verbose "Created window object, Title: $($poppedWindow.Title)" } else { Microsoft.PowerShell.Utility\Write-Verbose "Failed to get foreground window, falling back to Push-Window" $null = GenXdev.Windows\Push-Window $Global:GenXdevWindowStack.TryDequeue([ref]$poppedWindow) | Microsoft.PowerShell.Core\Out-Null } } catch { Microsoft.PowerShell.Utility\Write-Verbose "Error getting current window: $_" Microsoft.PowerShell.Utility\Write-Verbose "Falling back to Push-Window" $null = GenXdev.Windows\Push-Window $Global:GenXdevWindowStack.TryDequeue([ref]$poppedWindow) | Microsoft.PowerShell.Core\Out-Null } } # Validate we have a window to work with if (-not $poppedWindow -or -not $poppedWindow.Handle -or -not (IsWindowValid -Handle $poppedWindow.Handle)) { Microsoft.PowerShell.Utility\Write-Error "Failed to get a valid window to manipulate" return } Microsoft.PowerShell.Utility\Write-Verbose "Working with window: $($poppedWindow.Title), Handle: $($poppedWindow.Handle)" # skip modifications if nomodify is specified if ($NoModify) { return $poppedWindow } # move to specified monitor if requested if ($PSBoundParameters.ContainsKey('Monitor')) { # handle special case for secondary monitor (-2) if ($Monitor -eq -2 -and $Global:DefaultSecondaryMonitor -is [int] -and $Global:DefaultSecondaryMonitor -ge 0) { Microsoft.PowerShell.Utility\Write-Verbose ( "Using monitor from `$Global:DefaultSecondaryMonitor: " + "$Global:DefaultSecondaryMonitor" ) $targetMonitor = $Global:DefaultSecondaryMonitor } else { $targetMonitor = $Monitor } Microsoft.PowerShell.Utility\Write-Verbose "Moving window to monitor: $targetMonitor" $null = $poppedWindow.MoveToMonitor($targetMonitor) } # apply show/fade effects if requested if ($Show) { if ($FadeIn) { # apply fade-in effect for smooth appearance $poppedWindow.FadeWindow($true) } else { # show window immediately $null = $poppedWindow.Show() } } # apply window state modifications if ($Maximize) { $null = $poppedWindow.Maximize() } elseif ($Minimize) { $null = $poppedWindow.Minimize() } elseif ($Restore) { $null = $poppedWindow.Restore() } # apply positioning parameters - with enhanced logging # Check if both horizontal and vertical positioning are specified $horizontalPos = $Left -or $Right $verticalPos = $Top -or $Bottom $cornerPositioning = $horizontalPos -and $verticalPos if ($cornerPositioning) { # Handle corner positioning (quarter screen) Microsoft.PowerShell.Utility\Write-Verbose "Positioning window to corner (quarter screen)" if ($Left) { if ($Top) { Microsoft.PowerShell.Utility\Write-Verbose "Positioning to top-left corner" $result = $poppedWindow.PositionTopLeft() Microsoft.PowerShell.Utility\Write-Verbose "PositionTopLeft result: $result" } else { # Bottom Microsoft.PowerShell.Utility\Write-Verbose "Positioning to bottom-left corner" $result = $poppedWindow.PositionBottomLeft() Microsoft.PowerShell.Utility\Write-Verbose "PositionBottomLeft result: $result" } } else { # Right if ($Top) { Microsoft.PowerShell.Utility\Write-Verbose "Positioning to top-right corner" $result = $poppedWindow.PositionTopRight() Microsoft.PowerShell.Utility\Write-Verbose "PositionTopRight result: $result" } else { # Bottom Microsoft.PowerShell.Utility\Write-Verbose "Positioning to bottom-right corner" $result = $poppedWindow.PositionBottomRight() Microsoft.PowerShell.Utility\Write-Verbose "PositionBottomRight result: $result" } } } # Original half-screen positioning logic elseif ($Left) { Microsoft.PowerShell.Utility\Write-Verbose "Positioning window to left half of screen" $result = $poppedWindow.PositionLeft() Microsoft.PowerShell.Utility\Write-Verbose "PositionLeft result: $result" } elseif ($Right) { Microsoft.PowerShell.Utility\Write-Verbose "Positioning window to right half of screen" $result = $poppedWindow.PositionRight() Microsoft.PowerShell.Utility\Write-Verbose "PositionRight result: $result" } elseif ($Top) { Microsoft.PowerShell.Utility\Write-Verbose "Positioning window to top half of screen" $result = $poppedWindow.PositionTop() Microsoft.PowerShell.Utility\Write-Verbose "PositionTop result: $result" } elseif ($Bottom) { Microsoft.PowerShell.Utility\Write-Verbose "Positioning window to bottom half of screen" $result = $poppedWindow.PositionBottom() Microsoft.PowerShell.Utility\Write-Verbose "PositionBottom result: $result" } elseif ($Centered) { Microsoft.PowerShell.Utility\Write-Verbose "Centering window on screen" $result = $poppedWindow.PositionCentered() Microsoft.PowerShell.Utility\Write-Verbose "PositionCentered result: $result" } elseif ($Fullscreen) { Microsoft.PowerShell.Utility\Write-Verbose "Making window fullscreen" $result = $poppedWindow.PositionFullscreen() Microsoft.PowerShell.Utility\Write-Verbose "PositionFullscreen result: $result" } # hide window if requested if ($Hide) { $null = $poppedWindow.Hide() } # apply visual modifications if ($NoBorders) { $poppedWindow.RemoveBorder() } # set always-on-top property if requested if ($AlwaysOnTop) { $poppedWindow.SetAlwaysOnTop($true) } # set opacity if specified if ($PSBoundParameters.ContainsKey('Opacity')) { $poppedWindow.SetOpacity($Opacity) } # apply position changes if requested if ($PSBoundParameters.ContainsKey('X') -and $PSBoundParameters.ContainsKey('Y')) { $null = $poppedWindow.Move($X, $Y) } # apply size changes if requested if ($PSBoundParameters.ContainsKey('Width') -and $PSBoundParameters.ContainsKey('Height')) { $null = $poppedWindow.Resize($Width, $Height) } # focus the window if requested (done last for proper visibility) if ($Focus) { $null = $poppedWindow.SetForeground() } # return the window object for potential further manipulationanipulation return $poppedWindow } ################################################################################################################################ end { } } ####################################################################################################################################################### |