Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Windows 10 title bar borders #36429

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/common/ManagedCommon/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ internal static class NativeMethods
[DllImport("user32.dll")]
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)]
public struct INPUT
{
Expand Down Expand Up @@ -100,5 +103,14 @@ internal enum INPUTTYPE : uint
INPUT_KEYBOARD = 1,
INPUT_HARDWARE = 2,
}

[StructLayout(LayoutKind.Sequential)]
internal struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
}
}
12 changes: 12 additions & 0 deletions src/common/ManagedCommon/WindowHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,17 @@ public static void BringToForeground(IntPtr handle)
}
}
}

/// <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/>
/// Has no visible effect on Windows 11.
/// </summary>
public static void ForceTopBorder1PixelInset(IntPtr handle)
{
var margins = new NativeMethods.MARGINS { cxLeftWidth = 0, cxRightWidth = 0, cyBottomHeight = 0, cyTopHeight = 2 };
NativeMethods.DwmExtendFrameIntoClientArea(handle, ref margins);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ double GetHeight(int maxCustomActionCount) =>
};

WindowHelpers.BringToForeground(this.GetWindowHandle());
WindowHelpers.ForceTopBorder1PixelInset(this.GetWindowHandle());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs for DwmExtendFrameIntoClientArea() say that:

This function must be called whenever Desktop Window Manager (DWM) composition is toggled. Handle the WM_DWMCOMPOSITIONCHANGED message for composition change notification.

...however, the docs for WM_DWMCOMPOSITIONCHANGED go on to note that:

As of Windows 8, DWM composition is always enabled, so this message is not sent regardless of video mode changes.

...so I don't think we need to handle this in Window.Activated--just one call at creation time seems to be enough.

}

private void OnActivated(object sender, WindowActivatedEventArgs args)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public MainWindow()
var handle = this.GetWindowHandle();
RegisterWindow(handle);

WindowHelpers.ForceTopBorder1PixelInset(handle);
WindowHelpers.BringToForeground(handle);

MainPage = App.GetService<EnvironmentVariablesMainPage>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;

using ManagedCommon;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
Expand All @@ -22,6 +22,7 @@ public MainWindow(bool isElevated)
SetTitleBar(AppTitleBar);
Activated += MainWindow_Activated;
AppWindow.SetIcon("Assets/FileLocksmith/Icon.ico");
WindowHelpers.ForceTopBorder1PixelInset(this.GetWindowHandle());

var loader = ResourceLoaderInstance.ResourceLoader;
var title = isElevated ? loader.GetString("AppAdminTitle") : loader.GetString("AppTitle");
Expand Down
1 change: 1 addition & 0 deletions src/modules/Hosts/Hosts/HostsXAML/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public MainWindow()

var handle = this.GetWindowHandle();

WindowHelpers.ForceTopBorder1PixelInset(handle);
WindowHelpers.BringToForeground(handle);
Activated += MainWindow_Activated;

Expand Down
3 changes: 2 additions & 1 deletion src/modules/peek/Peek.UI/PeekXAML/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ public MainWindow()
ViewModel = Application.Current.GetService<MainWindowViewModel>();

TitleBarControl.SetTitleBarToWindow(this);
AppWindow.TitleBar.ExtendsContentIntoTitleBar = true;
ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInset(this.GetWindowHandle());
AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall;
AppWindow.SetIcon("Assets/Peek/Icon.ico");

Expand Down
2 changes: 1 addition & 1 deletion src/modules/peek/Peek.UI/PeekXAML/Views/TitleBar.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ private void UpdateTitleBarCustomization(MainWindow mainWindow)
if (AppWindowTitleBar.IsCustomizationSupported())
{
AppWindow appWindow = mainWindow.AppWindow;
appWindow.TitleBar.ExtendsContentIntoTitleBar = true;
mainWindow.ExtendsContentIntoTitleBar = true;
appWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent;
appWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
appWindow.TitleBar.ButtonForegroundColor = ThemeHelpers.GetAppTheme() == AppTheme.Light ? Colors.DarkSlateGray : Colors.White;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ internal MainWindow()
OpenWindowPlacementFile(settingsFolder, windowPlacementFile);

// Update the Win32 looking window with the correct icon (and grab the appWindow handle for later)
IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(this);
Microsoft.UI.WindowId windowId = Win32Interop.GetWindowIdFromWindow(windowHandle);
IntPtr windowHandle = this.GetWindowHandle();
WindowId windowId = Win32Interop.GetWindowIdFromWindow(windowHandle);
appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
appWindow.SetIcon("Assets\\RegistryPreview\\RegistryPreview.ico");

Expand All @@ -49,6 +49,7 @@ internal MainWindow()

// Extend the canvas to include the title bar so the app can support theming
ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInset(windowHandle);
SetTitleBar(titleBar);

// if have settings, update the location of the window
Expand Down
7 changes: 7 additions & 0 deletions src/settings-ui/Settings.UI/SettingsXAML/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ private void OnLaunchedFromRunner(string[] cmdArgs)
// 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.
WindowHelpers.BringToForeground(settingsWindow.GetWindowHandle());

// https://github.com/microsoft/microsoft-ui-xaml/issues/8948 - A window's top border incorrectly
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this note be inline at call sites, or on the function itself?

// renders as black on Windows 10.
WindowHelpers.ForceTopBorder1PixelInset(WindowNative.GetWindowHandle(settingsWindow));
}
else
{
Expand All @@ -255,6 +259,7 @@ private void OnLaunchedFromRunner(string[] cmdArgs)
OobeWindow oobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.Overview);
oobeWindow.Activate();
oobeWindow.ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInset(WindowNative.GetWindowHandle(settingsWindow));
SetOobeWindow(oobeWindow);
}
else if (ShowScoobe)
Expand All @@ -263,6 +268,7 @@ private void OnLaunchedFromRunner(string[] cmdArgs)
OobeWindow scoobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.WhatsNew);
scoobeWindow.Activate();
scoobeWindow.ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInset(WindowNative.GetWindowHandle(settingsWindow));
SetOobeWindow(scoobeWindow);
}
else if (ShowFlyout)
Expand Down Expand Up @@ -310,6 +316,7 @@ protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs ar
// Window is also needed to show MessageDialog
settingsWindow = new MainWindow();
settingsWindow.ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInset(WindowNative.GetWindowHandle(settingsWindow));
settingsWindow.Activate();
settingsWindow.NavigateToSection(StartupPage);
ShowMessageDialog("The application is running in Debug mode.", "DEBUG");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
using System.Collections.ObjectModel;
using System.Globalization;

using global::PowerToys.GPOWrapper;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using WinRT.Interop;

namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
{
Expand Down Expand Up @@ -306,6 +307,7 @@ private void SetTitleBar()
// 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
u.ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInset(WindowNative.GetWindowHandle(u));
u.SetTitleBar(AppTitleBar);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Microsoft.UI.Xaml.Controls;
using Windows.Data.Json;
using Windows.System;
using WinRT.Interop;

namespace Microsoft.PowerToys.Settings.UI.Views
{
Expand Down Expand Up @@ -421,6 +422,7 @@ private void SetTitleBar()
// 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
u.ExtendsContentIntoTitleBar = true;
WindowHelpers.ForceTopBorder1PixelInset(WindowNative.GetWindowHandle(u));
u.SetTitleBar(AppTitleBar);
var loader = ResourceLoaderInstance.ResourceLoader;
AppTitleBarText.Text = App.IsElevated ? loader.GetString("SettingsWindow_AdminTitle") : loader.GetString("SettingsWindow_Title");
Expand Down
Loading