mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-09 20:57:22 +02:00
CmdPal: Give FG back to the previous window (#40445)
this is a port of ce15032 onto main, for just the FG change.
When we cloak our window, we want to make sure to _manually_ give FG
back to another window. Because apparently cloaked windows can have FG.
beacause that makes sense 🤦
Closes #39638
supersedes #40431
Co-authored-by: jiripolasek <me@jiripolasek.com>
This commit is contained in:
@@ -209,6 +209,9 @@ public sealed partial class MainWindow : WindowEx,
|
|||||||
{
|
{
|
||||||
var hwnd = new HWND(hwndValue != 0 ? hwndValue : _hwnd);
|
var hwnd = new HWND(hwndValue != 0 ? hwndValue : _hwnd);
|
||||||
|
|
||||||
|
// Make sure our HWND is cloaked before any possible window manipulations
|
||||||
|
Cloak();
|
||||||
|
|
||||||
// Remember, IsIconic == "minimized", which is entirely different state
|
// Remember, IsIconic == "minimized", which is entirely different state
|
||||||
// from "show/hide"
|
// from "show/hide"
|
||||||
// If we're currently minimized, restore us first, before we reveal
|
// If we're currently minimized, restore us first, before we reveal
|
||||||
@@ -222,16 +225,11 @@ public sealed partial class MainWindow : WindowEx,
|
|||||||
var display = GetScreen(hwnd, target);
|
var display = GetScreen(hwnd, target);
|
||||||
PositionCentered(display);
|
PositionCentered(display);
|
||||||
|
|
||||||
|
// Just to be sure, SHOW our hwnd.
|
||||||
PInvoke.ShowWindow(hwnd, SHOW_WINDOW_CMD.SW_SHOW);
|
PInvoke.ShowWindow(hwnd, SHOW_WINDOW_CMD.SW_SHOW);
|
||||||
|
|
||||||
// instead of showing the window, uncloak it from DWM
|
// Once we're done, uncloak to avoid all animations
|
||||||
// This will make it visible to the user, without the animation or frames for
|
Uncloak();
|
||||||
// loading XAML with composition
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
BOOL value = false;
|
|
||||||
PInvoke.DwmSetWindowAttribute(_hwnd, DWMWINDOWATTRIBUTE.DWMWA_CLOAK, &value, (uint)sizeof(BOOL));
|
|
||||||
}
|
|
||||||
|
|
||||||
PInvoke.SetForegroundWindow(hwnd);
|
PInvoke.SetForegroundWindow(hwnd);
|
||||||
PInvoke.SetActiveWindow(hwnd);
|
PInvoke.SetActiveWindow(hwnd);
|
||||||
@@ -290,7 +288,14 @@ public sealed partial class MainWindow : WindowEx,
|
|||||||
ShowHwnd(message.Hwnd, settings.SummonOn);
|
ShowHwnd(message.Hwnd, settings.SummonOn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Receive(HideWindowMessage message) => HideWindow();
|
public void Receive(HideWindowMessage message)
|
||||||
|
{
|
||||||
|
// This might come in off the UI thread. Make sure to hop back.
|
||||||
|
DispatcherQueue.TryEnqueue(() =>
|
||||||
|
{
|
||||||
|
HideWindow();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void Receive(QuitMessage message) =>
|
public void Receive(QuitMessage message) =>
|
||||||
|
|
||||||
@@ -302,11 +307,25 @@ public sealed partial class MainWindow : WindowEx,
|
|||||||
|
|
||||||
private void HideWindow()
|
private void HideWindow()
|
||||||
{
|
{
|
||||||
// Hide our window
|
// Cloak our HWND to avoid all animations.
|
||||||
|
Cloak();
|
||||||
|
|
||||||
// Instead of hiding the window, cloak it from DWM
|
// Then hide our HWND, to make sure that the OS gives the FG / focus back to another app
|
||||||
// This will make it invisible to the user, such that we can show it again
|
// (there's no way for us to guess what the right hwnd might be, only the OS can do it right)
|
||||||
// by uncloaking it, which avoids an unnecessary "flicker in" that XAML does
|
PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||||
|
|
||||||
|
// TRICKY: show our HWND again. This will trick XAML into painting our
|
||||||
|
// HWND again, so that we avoid the "flicker" caused by a WinUI3 app
|
||||||
|
// window being first shown
|
||||||
|
// SW_SHOWNA will prevent us for trying to fight the focus back
|
||||||
|
PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_SHOWNA);
|
||||||
|
|
||||||
|
// Intentionally leave the window cloaked. So our window is "visible",
|
||||||
|
// but also cloaked, so you can't see it.
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cloak()
|
||||||
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
BOOL value = true;
|
BOOL value = true;
|
||||||
@@ -314,6 +333,15 @@ public sealed partial class MainWindow : WindowEx,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Uncloak()
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
BOOL value = false;
|
||||||
|
PInvoke.DwmSetWindowAttribute(_hwnd, DWMWINDOWATTRIBUTE.DWMWA_CLOAK, &value, (uint)sizeof(BOOL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal void MainWindow_Closed(object sender, WindowEventArgs args)
|
internal void MainWindow_Closed(object sender, WindowEventArgs args)
|
||||||
{
|
{
|
||||||
var serviceProvider = App.Current.Services;
|
var serviceProvider = App.Current.Services;
|
||||||
@@ -536,6 +564,7 @@ public sealed partial class MainWindow : WindowEx,
|
|||||||
PowerToysTelemetry.Log.WriteEvent(new CmdPalHotkeySummoned(isRootHotkey));
|
PowerToysTelemetry.Log.WriteEvent(new CmdPalHotkeySummoned(isRootHotkey));
|
||||||
|
|
||||||
var isVisible = this.Visible;
|
var isVisible = this.Visible;
|
||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
// We need to check if our window is cloaked or not. A cloaked window is still
|
// We need to check if our window is cloaked or not. A cloaked window is still
|
||||||
@@ -565,7 +594,9 @@ public sealed partial class MainWindow : WindowEx,
|
|||||||
{
|
{
|
||||||
// ... then manually hide our window. When debugged, we won't get the cool cloaking,
|
// ... then manually hide our window. When debugged, we won't get the cool cloaking,
|
||||||
// but that's the price to pay for having the HWND not light-dismiss while we're debugging.
|
// but that's the price to pay for having the HWND not light-dismiss while we're debugging.
|
||||||
PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
Cloak();
|
||||||
|
this.Hide();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user