Skip to content

Commit ff2dfc7

Browse files
authored
Replace fullscreen state polling with appbar notifications (#46507)
Listen for ABN_FULLSCREENAPP instead of polling SHQueryUserNotificationState on a timer. This removes the periodic refresh work and updates the dock's topmost state directly from appbar fullscreen notifications.
1 parent 6007f1a commit ff2dfc7

File tree

3 files changed

+12
-30
lines changed

3 files changed

+12
-30
lines changed

.github/actions/spell-check/allow/code.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ SETAUTOHIDEBAR
334334
WINDOWPOS
335335
WINEVENTPROC
336336
WORKERW
337+
FULLSCREENAPP
337338

338339
# PowerRename metadata pattern abbreviations (used in tests and regex patterns)
339340
DDDD

src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockWindow.xaml.cs

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
using WinRT;
2828
using WinRT.Interop;
2929
using WinUIEx;
30-
using WindowExtensions = Microsoft.CmdPal.UI.Helpers.WindowExtensions;
3130

3231
namespace Microsoft.CmdPal.UI.Dock;
3332

@@ -39,8 +38,6 @@ public sealed partial class DockWindow : WindowEx,
3938
IRecipient<QuitMessage>,
4039
IDisposable
4140
{
42-
private static readonly TimeSpan TopmostStateRefreshInterval = TimeSpan.FromSeconds(1);
43-
4441
#pragma warning disable SA1306 // Field names should begin with lower-case letter
4542
#pragma warning disable SA1310 // Field names should not contain underscore
4643
private readonly uint WM_TASKBAR_RESTART;
@@ -51,13 +48,11 @@ public sealed partial class DockWindow : WindowEx,
5148
private readonly DockWindowViewModel _windowViewModel;
5249
private readonly HiddenOwnerWindowBehavior _hiddenOwnerWindowBehavior = new();
5350

54-
// SHQueryUserNotificationState does not raise change notifications, so we poll lightly.
55-
private readonly DispatcherTimer _topmostStateTimer = new();
56-
5751
private HWND _hwnd = HWND.Null;
5852
private APPBARDATA _appBarData;
5953
private uint _callbackMessageId;
6054
private bool _isWindowTopmost;
55+
private bool _isFullScreenAppOpen;
6156

6257
private DockSettings _settings;
6358
private DockViewModel viewModel;
@@ -97,8 +92,6 @@ public DockWindow()
9792
}
9893

9994
this.Activated += DockWindow_Activated;
100-
_topmostStateTimer.Interval = TopmostStateRefreshInterval;
101-
_topmostStateTimer.Tick += TopmostStateTimer_Tick;
10295

10396
WeakReferenceMessenger.Default.Register<BringToTopMessage>(this);
10497
WeakReferenceMessenger.Default.Register<RequestShowPaletteAtMessage>(this);
@@ -133,6 +126,7 @@ public DockWindow()
133126
_ = PInvoke.SetWindowLong(_hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE, (int)style);
134127

135128
ShowDesktop.AddHook(this);
129+
_isFullScreenAppOpen = WindowHelper.IsWindowFullscreen();
136130
UpdateSettingsOnUiThread();
137131
}
138132

@@ -155,11 +149,6 @@ private void DockWindow_Activated(object sender, WindowActivatedEventArgs args)
155149
UpdateTopmostState();
156150
}
157151

158-
private void TopmostStateTimer_Tick(object? sender, object e)
159-
{
160-
UpdateTopmostState();
161-
}
162-
163152
private HWND GetWindowHandle(Window window)
164153
{
165154
var hwnd = WindowNative.GetWindowHandle(window);
@@ -180,17 +169,6 @@ private void UpdateSettingsOnUiThread()
180169

181170
_dock.UpdateSettings(_settings);
182171

183-
// Only poll for fullscreen changes when AlwaysOnTop is active;
184-
// when disabled the timer is unnecessary work.
185-
if (_settings.AlwaysOnTop)
186-
{
187-
_topmostStateTimer.Start();
188-
}
189-
else
190-
{
191-
_topmostStateTimer.Stop();
192-
}
193-
194172
var side = DockSettingsToViews.GetAppBarEdge(_settings.Side);
195173

196174
if (_appBarData.hWnd != IntPtr.Zero)
@@ -309,7 +287,7 @@ private void DestroyAppBar(HWND hwnd)
309287

310288
private void UpdateTopmostState(bool bringToFront = false)
311289
{
312-
var shouldStayOnTop = _settings.AlwaysOnTop && !WindowHelper.IsWindowFullscreen();
290+
var shouldStayOnTop = _settings.AlwaysOnTop && !_isFullScreenAppOpen;
313291
const SET_WINDOW_POS_FLAGS flags = SET_WINDOW_POS_FLAGS.SWP_NOMOVE | SET_WINDOW_POS_FLAGS.SWP_NOSIZE | SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE;
314292

315293
if (shouldStayOnTop)
@@ -337,7 +315,8 @@ private void UpdateTopmostState(bool bringToFront = false)
337315
return;
338316
}
339317

340-
PInvoke.SetWindowPos(_hwnd, HWND.HWND_NOTOPMOST, 0, 0, 0, 0, flags);
318+
var zOrder = _isFullScreenAppOpen ? HWND.HWND_BOTTOM : HWND.HWND_NOTOPMOST;
319+
PInvoke.SetWindowPos(_hwnd, zOrder, 0, 0, 0, 0, flags);
341320
_isWindowTopmost = false;
342321
}
343322

@@ -566,6 +545,11 @@ private LRESULT CustomWndProc(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam)
566545
{
567546
UpdateWindowPosition();
568547
}
548+
else if (wParam.Value == PInvoke.ABN_FULLSCREENAPP)
549+
{
550+
_isFullScreenAppOpen = lParam != 0;
551+
UpdateTopmostState();
552+
}
569553
}
570554
else if (msg == WM_TASKBAR_RESTART)
571555
{
@@ -676,8 +660,6 @@ private void RequestShowPaletteOnUiThread(Point posDips)
676660

677661
public void Dispose()
678662
{
679-
_topmostStateTimer.Stop();
680-
_topmostStateTimer.Tick -= TopmostStateTimer_Tick;
681663
DisposeAcrylic();
682664
_windowViewModel.Dispose();
683665
}
@@ -688,8 +670,6 @@ private void DockWindow_Closed(object sender, WindowEventArgs args)
688670
var settings = serviceProvider.GetService<SettingsModel>();
689671
settings?.SettingsChanged -= SettingsChangedHandler;
690672
_themeService.ThemeChanged -= ThemeService_ThemeChanged;
691-
_topmostStateTimer.Stop();
692-
_topmostStateTimer.Tick -= TopmostStateTimer_Tick;
693673
DisposeAcrylic();
694674

695675
// Remove our app bar registration

src/modules/cmdpal/Microsoft.CmdPal.UI/NativeMethods.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ ABM_REMOVE
7676
ABM_SETAUTOHIDEBAR
7777
ABS_AUTOHIDE
7878
ABN_POSCHANGED
79+
ABN_FULLSCREENAPP
7980
APPBARDATA
8081
ABE_TOP
8182
ABE_BOTTOM

0 commit comments

Comments
 (0)