[WinUI3]Fix Windows 10 title bar borders (#36429)

* Fix borders for windows in the Settings UI

* Fix HOSTS window

* Fix Advanced Paste

* Fix Environment Variables

* Fix File Locksmith

* Fix Peek, with a caveat

* Fix Registry Preview

* Remove unused imports

* Clean up imports in OobeShellPage

* Move OSVersionHelper from Common.UI up into ManagedCommon
This commit is contained in:
Neil McAlister 2025-01-13 17:13:16 +02:00 коммит произвёл GitHub
Родитель aa9f3bb540
Коммит df48a33bb9
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
23 изменённых файлов: 68 добавлений и 25 удалений

Просмотреть файл

@ -42,6 +42,9 @@ namespace ManagedCommon
[DllImport("user32.dll")] [DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); internal static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
[DllImport("dwmapi")]
internal static extern IntPtr DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct INPUT public struct INPUT
{ {
@ -100,5 +103,14 @@ namespace ManagedCommon
INPUT_KEYBOARD = 1, INPUT_KEYBOARD = 1,
INPUT_HARDWARE = 2, INPUT_HARDWARE = 2,
} }
[StructLayout(LayoutKind.Sequential)]
internal struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
} }
} }

Просмотреть файл

@ -4,10 +4,15 @@
using System; using System;
namespace Common.UI namespace ManagedCommon
{ {
public static class OSVersionHelper public static class OSVersionHelper
{ {
public static bool IsWindows10()
{
return Environment.OSVersion.Version.Major >= 10 && Environment.OSVersion.Version.Minor < 22000;
}
public static bool IsWindows11() public static bool IsWindows11()
{ {
return Environment.OSVersion.Version.Major >= 10 && Environment.OSVersion.Version.Build >= 22000; return Environment.OSVersion.Version.Major >= 10 && Environment.OSVersion.Version.Build >= 22000;

Просмотреть файл

@ -35,5 +35,20 @@ namespace ManagedCommon
} }
} }
} }
/// <summary>
/// Workaround for a WinUI bug on Windows 10 in which a window's top border is always
/// black. Calls <c>DwmExtendFrameIntoClientArea()</c> with a <c>cyTopHeight</c> of 2 to force
/// the window's top border to be visible.<br/><br/>
/// Is a no-op on versions other than Windows 10.
/// </summary>
public static void ForceTopBorder1PixelInsetOnWindows10(IntPtr handle)
{
if (OSVersionHelper.IsWindows10())
{
var margins = new NativeMethods.MARGINS { cxLeftWidth = 0, cxRightWidth = 0, cyBottomHeight = 0, cyTopHeight = 2 };
NativeMethods.DwmExtendFrameIntoClientArea(handle, ref margins);
}
}
} }
} }

Просмотреть файл

@ -82,6 +82,7 @@ namespace AdvancedPaste
}; };
WindowHelpers.BringToForeground(this.GetWindowHandle()); WindowHelpers.BringToForeground(this.GetWindowHandle());
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(this.GetWindowHandle());
} }
private void OnActivated(object sender, WindowActivatedEventArgs args) private void OnActivated(object sender, WindowActivatedEventArgs args)

Просмотреть файл

@ -40,6 +40,7 @@ namespace EnvironmentVariables
var handle = this.GetWindowHandle(); var handle = this.GetWindowHandle();
RegisterWindow(handle); RegisterWindow(handle);
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(handle);
WindowHelpers.BringToForeground(handle); WindowHelpers.BringToForeground(handle);
MainPage = App.GetService<EnvironmentVariablesMainPage>(); MainPage = App.GetService<EnvironmentVariablesMainPage>();

Просмотреть файл

@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System; using System;
using ManagedCommon;
using Microsoft.UI.Windowing; using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Media;
@ -22,6 +22,7 @@ namespace FileLocksmithUI
SetTitleBar(AppTitleBar); SetTitleBar(AppTitleBar);
Activated += MainWindow_Activated; Activated += MainWindow_Activated;
AppWindow.SetIcon("Assets/FileLocksmith/Icon.ico"); AppWindow.SetIcon("Assets/FileLocksmith/Icon.ico");
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(this.GetWindowHandle());
var loader = ResourceLoaderInstance.ResourceLoader; var loader = ResourceLoaderInstance.ResourceLoader;
var title = isElevated ? loader.GetString("AppAdminTitle") : loader.GetString("AppTitle"); var title = isElevated ? loader.GetString("AppAdminTitle") : loader.GetString("AppTitle");

Просмотреть файл

@ -39,6 +39,7 @@ namespace Hosts
var handle = this.GetWindowHandle(); var handle = this.GetWindowHandle();
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(handle);
WindowHelpers.BringToForeground(handle); WindowHelpers.BringToForeground(handle);
Activated += MainWindow_Activated; Activated += MainWindow_Activated;

Просмотреть файл

@ -5,7 +5,7 @@
using System; using System;
using ColorPicker.Helpers; using ColorPicker.Helpers;
using Common.UI; using ManagedCommon;
using Wpf.Ui.Controls; using Wpf.Ui.Controls;
namespace ColorPicker namespace ColorPicker

Просмотреть файл

@ -7,9 +7,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Common.UI;
using ImageResizer.ViewModels; using ImageResizer.ViewModels;
using ManagedCommon;
using Microsoft.Win32; using Microsoft.Win32;
using Wpf.Ui.Controls; using Wpf.Ui.Controls;

Просмотреть файл

@ -6,6 +6,7 @@ using System;
using System.IO; using System.IO;
using System.Windows; using System.Windows;
using System.Windows.Media; using System.Windows.Media;
using ManagedCommon;
using Microsoft.Win32; using Microsoft.Win32;
using Wox.Infrastructure.Image; using Wox.Infrastructure.Image;
using Wox.Infrastructure.UserSettings; using Wox.Infrastructure.UserSettings;
@ -50,7 +51,7 @@ namespace PowerLauncher.Helper
private void SetSystemTheme(ManagedCommon.Theme theme) private void SetSystemTheme(ManagedCommon.Theme theme)
{ {
_mainWindow.Background = Common.UI.OSVersionHelper.IsWindows11() is false ? SystemColors.WindowBrush : null; _mainWindow.Background = OSVersionHelper.IsWindows11() is false ? SystemColors.WindowBrush : null;
_mainWindow.Resources.MergedDictionaries.Clear(); _mainWindow.Resources.MergedDictionaries.Clear();
_mainWindow.Resources.MergedDictionaries.Add(new ResourceDictionary _mainWindow.Resources.MergedDictionaries.Add(new ResourceDictionary
@ -66,7 +67,7 @@ namespace PowerLauncher.Helper
Source = new Uri(themeString, UriKind.Absolute), Source = new Uri(themeString, UriKind.Absolute),
}; };
_mainWindow.Resources.MergedDictionaries.Add(fluentThemeDictionary); _mainWindow.Resources.MergedDictionaries.Add(fluentThemeDictionary);
if (!Common.UI.OSVersionHelper.IsWindows11()) if (!OSVersionHelper.IsWindows11())
{ {
// Apply background only on Windows 10 // Apply background only on Windows 10
// Windows theme does not work properly for dark and light mode so right now set the background color manual. // Windows theme does not work properly for dark and light mode so right now set the background color manual.
@ -95,7 +96,7 @@ namespace PowerLauncher.Helper
{ {
Source = new Uri(styleThemeString, UriKind.Relative), Source = new Uri(styleThemeString, UriKind.Relative),
}); });
if (Common.UI.OSVersionHelper.IsWindows11()) if (OSVersionHelper.IsWindows11())
{ {
// Apply background only on Windows 11 to keep the same style as WPFUI // Apply background only on Windows 11 to keep the same style as WPFUI
_mainWindow.Background = new SolidColorBrush _mainWindow.Background = new SolidColorBrush

Просмотреть файл

@ -15,6 +15,7 @@ using System.Windows.Interop;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Common.UI; using Common.UI;
using ManagedCommon;
using Microsoft.PowerLauncher.Telemetry; using Microsoft.PowerLauncher.Telemetry;
using Microsoft.PowerToys.Telemetry; using Microsoft.PowerToys.Telemetry;
using PowerLauncher.Helper; using PowerLauncher.Helper;

Просмотреть файл

@ -7,8 +7,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using ManagedCommon;
using Common.UI;
using Microsoft.Win32; using Microsoft.Win32;
using Wox.Plugin.Common.VirtualDesktop.Interop; using Wox.Plugin.Common.VirtualDesktop.Interop;
using Wox.Plugin.Common.Win32; using Wox.Plugin.Common.Win32;

Просмотреть файл

@ -48,7 +48,8 @@ namespace Peek.UI
ViewModel = Application.Current.GetService<MainWindowViewModel>(); ViewModel = Application.Current.GetService<MainWindowViewModel>();
TitleBarControl.SetTitleBarToWindow(this); TitleBarControl.SetTitleBarToWindow(this);
AppWindow.TitleBar.ExtendsContentIntoTitleBar = true; ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(this.GetWindowHandle());
AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall; AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall;
AppWindow.SetIcon("Assets/Peek/Icon.ico"); AppWindow.SetIcon("Assets/Peek/Icon.ico");

Просмотреть файл

@ -231,7 +231,7 @@ namespace Peek.UI.Views
if (AppWindowTitleBar.IsCustomizationSupported()) if (AppWindowTitleBar.IsCustomizationSupported())
{ {
AppWindow appWindow = mainWindow.AppWindow; AppWindow appWindow = mainWindow.AppWindow;
appWindow.TitleBar.ExtendsContentIntoTitleBar = true; mainWindow.ExtendsContentIntoTitleBar = true;
appWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent; appWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent;
appWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent; appWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
appWindow.TitleBar.ButtonForegroundColor = ThemeHelpers.GetAppTheme() == AppTheme.Light ? Colors.DarkSlateGray : Colors.White; appWindow.TitleBar.ButtonForegroundColor = ThemeHelpers.GetAppTheme() == AppTheme.Light ? Colors.DarkSlateGray : Colors.White;

Просмотреть файл

@ -38,8 +38,8 @@ namespace RegistryPreview
OpenWindowPlacementFile(settingsFolder, windowPlacementFile); OpenWindowPlacementFile(settingsFolder, windowPlacementFile);
// Update the Win32 looking window with the correct icon (and grab the appWindow handle for later) // Update the Win32 looking window with the correct icon (and grab the appWindow handle for later)
IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(this); IntPtr windowHandle = this.GetWindowHandle();
Microsoft.UI.WindowId windowId = Win32Interop.GetWindowIdFromWindow(windowHandle); WindowId windowId = Win32Interop.GetWindowIdFromWindow(windowHandle);
appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId); appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
appWindow.SetIcon("Assets\\RegistryPreview\\RegistryPreview.ico"); appWindow.SetIcon("Assets\\RegistryPreview\\RegistryPreview.ico");
@ -49,6 +49,7 @@ namespace RegistryPreview
// Extend the canvas to include the title bar so the app can support theming // Extend the canvas to include the title bar so the app can support theming
ExtendsContentIntoTitleBar = true; ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(windowHandle);
SetTitleBar(titleBar); SetTitleBar(titleBar);
// if have settings, update the location of the window // if have settings, update the location of the window

Просмотреть файл

@ -3,8 +3,7 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Diagnostics; using System.Diagnostics;
using ManagedCommon;
using Common.UI;
namespace Microsoft.PowerToys.Settings.UI.Helpers namespace Microsoft.PowerToys.Settings.UI.Helpers
{ {

Просмотреть файл

@ -241,6 +241,10 @@ namespace Microsoft.PowerToys.Settings.UI
// https://github.com/microsoft/microsoft-ui-xaml/issues/7595 - Activate doesn't bring window to the foreground // https://github.com/microsoft/microsoft-ui-xaml/issues/7595 - Activate doesn't bring window to the foreground
// Need to call SetForegroundWindow to actually gain focus. // Need to call SetForegroundWindow to actually gain focus.
WindowHelpers.BringToForeground(settingsWindow.GetWindowHandle()); WindowHelpers.BringToForeground(settingsWindow.GetWindowHandle());
// https://github.com/microsoft/microsoft-ui-xaml/issues/8948 - A window's top border incorrectly
// renders as black on Windows 10.
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(WindowNative.GetWindowHandle(settingsWindow));
} }
else else
{ {
@ -255,6 +259,7 @@ namespace Microsoft.PowerToys.Settings.UI
OobeWindow oobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.Overview); OobeWindow oobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.Overview);
oobeWindow.Activate(); oobeWindow.Activate();
oobeWindow.ExtendsContentIntoTitleBar = true; oobeWindow.ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(WindowNative.GetWindowHandle(settingsWindow));
SetOobeWindow(oobeWindow); SetOobeWindow(oobeWindow);
} }
else if (ShowScoobe) else if (ShowScoobe)
@ -263,6 +268,7 @@ namespace Microsoft.PowerToys.Settings.UI
OobeWindow scoobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.WhatsNew); OobeWindow scoobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.WhatsNew);
scoobeWindow.Activate(); scoobeWindow.Activate();
scoobeWindow.ExtendsContentIntoTitleBar = true; scoobeWindow.ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(WindowNative.GetWindowHandle(settingsWindow));
SetOobeWindow(scoobeWindow); SetOobeWindow(scoobeWindow);
} }
else if (ShowFlyout) else if (ShowFlyout)
@ -310,6 +316,7 @@ namespace Microsoft.PowerToys.Settings.UI
// Window is also needed to show MessageDialog // Window is also needed to show MessageDialog
settingsWindow = new MainWindow(); settingsWindow = new MainWindow();
settingsWindow.ExtendsContentIntoTitleBar = true; settingsWindow.ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(WindowNative.GetWindowHandle(settingsWindow));
settingsWindow.Activate(); settingsWindow.Activate();
settingsWindow.NavigateToSection(StartupPage); settingsWindow.NavigateToSection(StartupPage);
ShowMessageDialog("The application is running in Debug mode.", "DEBUG"); ShowMessageDialog("The application is running in Debug mode.", "DEBUG");

Просмотреть файл

@ -6,12 +6,13 @@ using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Globalization; using System.Globalization;
using global::PowerToys.GPOWrapper; using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.OOBE.Enums; using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using WinRT.Interop;
namespace Microsoft.PowerToys.Settings.UI.OOBE.Views namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
{ {
@ -306,6 +307,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
// A custom title bar is required for full window theme and Mica support. // A custom title bar is required for full window theme and Mica support.
// https://docs.microsoft.com/windows/apps/develop/title-bar?tabs=winui3#full-customization // https://docs.microsoft.com/windows/apps/develop/title-bar?tabs=winui3#full-customization
u.ExtendsContentIntoTitleBar = true; u.ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(WindowNative.GetWindowHandle(u));
u.SetTitleBar(AppTitleBar); u.SetTitleBar(AppTitleBar);
} }
} }

Просмотреть файл

@ -14,6 +14,7 @@ using Microsoft.UI.Xaml.Automation.Peers;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Windows.Data.Json; using Windows.Data.Json;
using Windows.System; using Windows.System;
using WinRT.Interop;
namespace Microsoft.PowerToys.Settings.UI.Views namespace Microsoft.PowerToys.Settings.UI.Views
{ {
@ -421,6 +422,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
// A custom title bar is required for full window theme and Mica support. // A custom title bar is required for full window theme and Mica support.
// https://docs.microsoft.com/windows/apps/develop/title-bar?tabs=winui3#full-customization // https://docs.microsoft.com/windows/apps/develop/title-bar?tabs=winui3#full-customization
u.ExtendsContentIntoTitleBar = true; u.ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(WindowNative.GetWindowHandle(u));
u.SetTitleBar(AppTitleBar); u.SetTitleBar(AppTitleBar);
var loader = ResourceLoaderInstance.ResourceLoader; var loader = ResourceLoaderInstance.ResourceLoader;
AppTitleBarText.Text = App.IsElevated ? loader.GetString("SettingsWindow_AdminTitle") : loader.GetString("SettingsWindow_Title"); AppTitleBarText.Text = App.IsElevated ? loader.GetString("SettingsWindow_AdminTitle") : loader.GetString("SettingsWindow_Title");

Просмотреть файл

@ -6,9 +6,8 @@ using System;
using System.Globalization; using System.Globalization;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text.Json; using System.Text.Json;
using Common.UI;
using global::PowerToys.GPOWrapper; using global::PowerToys.GPOWrapper;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers; using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces; using Microsoft.PowerToys.Settings.UI.Library.Interfaces;

Просмотреть файл

@ -4,9 +4,8 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Common.UI;
using global::PowerToys.GPOWrapper; using global::PowerToys.GPOWrapper;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers; using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces; using Microsoft.PowerToys.Settings.UI.Library.Interfaces;

Просмотреть файл

@ -10,8 +10,6 @@ using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using Common.UI;
using global::PowerToys.GPOWrapper; using global::PowerToys.GPOWrapper;
using ManagedCommon; using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Helpers;

Просмотреть файл

@ -9,9 +9,8 @@ using System.Globalization;
using System.Linq; using System.Linq;
using System.Text.Json; using System.Text.Json;
using System.Timers; using System.Timers;
using Common.UI;
using global::PowerToys.GPOWrapper; using global::PowerToys.GPOWrapper;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers; using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces; using Microsoft.PowerToys.Settings.UI.Library.Interfaces;