From 15113cce752083081333a1358c93498b3d2de8e3 Mon Sep 17 00:00:00 2001 From: Mgg sk Date: Thu, 12 Dec 2024 20:22:24 +0100 Subject: [PATCH 1/8] Improved the Backdrop sample --- WinUIGallery/Common/Win32.cs | 21 +- .../ControlPages/SystemBackdropsPage.xaml | 51 +++-- .../ControlPages/SystemBackdropsPage.xaml.cs | 46 +++-- .../SystemBackdropsSample1.txt | 61 +++--- .../SystemBackdropsSample2.txt | 61 +++--- .../SystemBackdropsSample3.txt | 11 +- .../SystemBackdropsSample4.txt | 9 +- WinUIGallery/DataModel/ControlInfoData.json | 21 +- WinUIGallery/Helper/WindowHelper.cs | 27 ++- .../SampleBuiltInSystemBackdropsWindow.xaml | 22 +-- ...SampleBuiltInSystemBackdropsWindow.xaml.cs | 70 ++++--- .../SampleSystemBackdropsWindow.xaml | 22 +-- .../SampleSystemBackdropsWindow.xaml.cs | 180 ++++++++++-------- 13 files changed, 355 insertions(+), 247 deletions(-) diff --git a/WinUIGallery/Common/Win32.cs b/WinUIGallery/Common/Win32.cs index 526ab63a5..81e406ba4 100644 --- a/WinUIGallery/Common/Win32.cs +++ b/WinUIGallery/Common/Win32.cs @@ -39,6 +39,9 @@ internal static class Win32 [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam); + [DllImport("DwmApi.dll")] + public static extern int DwmSetWindowAttribute(nint hWnd, DwmWindowAttribute attribute, ref int value, int size); + public static int SetWindowKeyHook(HookProc hookProc) { @@ -57,11 +60,12 @@ public static bool IsKeyDownHook(IntPtr lWord) public const int WA_INACTIVE = 0x00; public const int WH_KEYBOARD = 2; public const int WM_KEYDOWN = 0x0104; - public const int WM_SETICON = 0x0080; + public const int ICON_SMALL = 0; public const int ICON_BIG = 1; + internal delegate IntPtr WinProc(IntPtr hWnd, WindowMessage Msg, IntPtr wParam, IntPtr lParam); public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam); @@ -75,5 +79,20 @@ internal enum WindowMessage : int { WM_GETMINMAXINFO = 0x0024, } + + internal enum DwmWindowAttribute : int + { + DWMWA_USE_IMMERSIVE_DARK_MODE = 20, //Dark mode + DWMWA_SYSTEMBACKDROP_TYPE = 38 //Title bar backdrop + } + + internal enum DwmSystemBackdropType : int + { + DWMSBT_AUTO = 0, //Default + DWMSBT_NONE = 1, //None + DWMSBT_MAINWINDOW = 2, //Mica + DWMSBT_TRANSIENTWINDOW = 3, //Acrylic thin + DWMSBT_TABBEDWINDOW = 4, //Mica Alt + } } } diff --git a/WinUIGallery/ControlPages/SystemBackdropsPage.xaml b/WinUIGallery/ControlPages/SystemBackdropsPage.xaml index d95b7bc01..6119526c8 100644 --- a/WinUIGallery/ControlPages/SystemBackdropsPage.xaml +++ b/WinUIGallery/ControlPages/SystemBackdropsPage.xaml @@ -19,25 +19,40 @@ mc:Ignorable="d"> - Backdrop types: + -// Option 1 - implement Mica with Xaml. +// Option 1 - Implement Mica with Xaml. <Window.SystemBackdrop> <MicaBackdrop /> </Window.SystemBackdrop> + +//Option 1.5 Implement Mica Alt with Xaml. +<Window.SystemBackdrop> + <MicaBackdrop Kind="BaseAlt" /> +</Window.SystemBackdrop> - - - - - + + + Inheritance: Object -> DependencyObject -> SystemBackdrop + + Mica is an opaque, dynamic material that incorporates theme and desktop wallpaper to paint the background of windows. + You can apply Mica as your application backdrop to create a visual hierarchy, aiding productivity, by increasing clarity about which window is in focus. + Mica is specifically designed for app performance as it only samples the desktop wallpaper once to create its visualization. + Mica is available for Windows 11 build 22000 or later. + + Mica Alt is a variant of Mica, with stronger tinting of the user's desktop background color. + You can apply Mica Alt as your app's backdrop to provide a deeper visual hierarchy than Mica, especially when creating an app with a tabbed title bar. + Mica Alt is available for Windows 11 build 22000 or later. + + + - @@ -47,7 +62,21 @@ </Window.SystemBackdrop> - + + + Inheritance: Object -> DependencyObject -> SystemBackdrop + + Acrylic is a semi-transparent material that replicates the effect of frosted glass. + It's used only for transient, light-dismiss surfaces such as flyouts and context menus. + + + + + + Backdrop controllers: + + Create Window with customizable Desktop Acrylic - diff --git a/WinUIGallery/ControlPages/SystemBackdropsPage.xaml.cs b/WinUIGallery/ControlPages/SystemBackdropsPage.xaml.cs index 4c66fe210..440417e17 100644 --- a/WinUIGallery/ControlPages/SystemBackdropsPage.xaml.cs +++ b/WinUIGallery/ControlPages/SystemBackdropsPage.xaml.cs @@ -7,13 +7,9 @@ // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. // //********************************************************* -using WinUIGallery.Helper; -using System; -using Microsoft.UI; -using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Media; +using WinUIGallery.SamplePages; namespace WinUIGallery.ControlPages { @@ -21,34 +17,46 @@ public sealed partial class SystemBackdropsPage : Page { public SystemBackdropsPage() { - this.InitializeComponent(); + InitializeComponent(); } private void createBuiltInMicaWindow_Click(object sender, RoutedEventArgs e) { - var newWindow = new WinUIGallery.SamplePages.SampleBuiltInSystemBackdropsWindow(); - newWindow.Activate(); + var micaWindow = new SampleBuiltInSystemBackdropsWindow(); + micaWindow.AllowedBackdrops = [SampleBuiltInSystemBackdropsWindow.BackdropType.None, + SampleBuiltInSystemBackdropsWindow.BackdropType.Mica, + SampleBuiltInSystemBackdropsWindow.BackdropType.MicaAlt]; + micaWindow.SetBackdrop(SampleBuiltInSystemBackdropsWindow.BackdropType.Mica); + micaWindow.Activate(); } - private void createCustomMicaWindow_Click(object sender, RoutedEventArgs e) + private void createBuiltInAcrylicWindow_Click(object sender, RoutedEventArgs e) { - var newWindow = new WinUIGallery.SamplePages.SampleSystemBackdropsWindow(); - newWindow.SetBackdrop(WinUIGallery.SamplePages.SampleSystemBackdropsWindow.BackdropType.Mica); - newWindow.Activate(); + var acrylicWindow = new SampleBuiltInSystemBackdropsWindow(); + acrylicWindow.AllowedBackdrops = [SampleBuiltInSystemBackdropsWindow.BackdropType.None, + SampleBuiltInSystemBackdropsWindow.BackdropType.Acrylic]; + acrylicWindow.SetBackdrop(SampleBuiltInSystemBackdropsWindow.BackdropType.Acrylic); + acrylicWindow.Activate(); } - private void createBuiltInAcrylicWindow_Click(object sender, RoutedEventArgs e) + private void createCustomMicaWindow_Click(object sender, RoutedEventArgs e) { - var newWindow = new WinUIGallery.SamplePages.SampleSystemBackdropsWindow(); - newWindow.SetBackdrop(WinUIGallery.SamplePages.SampleSystemBackdropsWindow.BackdropType.DesktopAcrylicBase); - newWindow.Activate(); + var micaWindow = new SampleSystemBackdropsWindow(); + micaWindow.AllowedBackdrops = [SampleSystemBackdropsWindow.BackdropType.None, + SampleSystemBackdropsWindow.BackdropType.Mica, + SampleSystemBackdropsWindow.BackdropType.MicaAlt]; + micaWindow.SetBackdrop(SampleSystemBackdropsWindow.BackdropType.Mica); + micaWindow.Activate(); } private void createCustomDesktopAcrylicWindow_Click(object sender, RoutedEventArgs e) { - var newWindow = new WinUIGallery.SamplePages.SampleSystemBackdropsWindow(); - newWindow.SetBackdrop(WinUIGallery.SamplePages.SampleSystemBackdropsWindow.BackdropType.DesktopAcrylicBase); - newWindow.Activate(); + var acrylicWindow = new SampleSystemBackdropsWindow(); + acrylicWindow.AllowedBackdrops = [SampleSystemBackdropsWindow.BackdropType.None, + SampleSystemBackdropsWindow.BackdropType.Acrylic, + SampleSystemBackdropsWindow.BackdropType.AcrylicThin]; + acrylicWindow.SetBackdrop(SampleSystemBackdropsWindow.BackdropType.Acrylic); + acrylicWindow.Activate(); } } } diff --git a/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample1.txt b/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample1.txt index 5606bd3b5..f9f4aa60c 100644 --- a/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample1.txt +++ b/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample1.txt @@ -1,35 +1,35 @@ -using System.Runtime.InteropServices; // For DllImport -using WinRT; // required to support Window.As() +using System.Runtime.InteropServices; +using WinRT; +using Microsoft.UI.Composition; +using Microsoft.UI.Composition.SystemBackdrops; -WindowsSystemDispatcherQueueHelper m_wsdqHelper; // See separate sample below for implementation -Microsoft.UI.Composition.SystemBackdrops.MicaController m_micaController; -Microsoft.UI.Composition.SystemBackdrops.SystemBackdropConfiguration m_configurationSource; +WindowsSystemDispatcherQueueHelper wsdqHelper; // See the helper class sample for the implementation +MicaController micaController; +SystemBackdropConfiguration configurationSource; bool TrySetMicaBackdrop(bool useMicaAlt) { - if (Microsoft.UI.Composition.SystemBackdrops.MicaController.IsSupported()) + if (MicaController.IsSupported()) { - m_wsdqHelper = new WindowsSystemDispatcherQueueHelper(); - m_wsdqHelper.EnsureWindowsSystemDispatcherQueueController(); + wsdqHelper = new WindowsSystemDispatcherQueueHelper(); + wsdqHelper.EnsureWindowsSystemDispatcherQueueController(); // Hooking up the policy object - m_configurationSource = new Microsoft.UI.Composition.SystemBackdrops.SystemBackdropConfiguration(); - this.Activated += Window_Activated; - this.Closed += Window_Closed; - ((FrameworkElement)this.Content).ActualThemeChanged += Window_ThemeChanged; + configurationSource = new SystemBackdropConfiguration(); + Activated += Window_Activated; + Closed += Window_Closed; + ((FrameworkElement)Content).ActualThemeChanged += Window_ThemeChanged; // Initial configuration state. - m_configurationSource.IsInputActive = true; + configurationSource.IsInputActive = true; SetConfigurationSourceTheme(); - m_micaController = new Microsoft.UI.Composition.SystemBackdrops.MicaController(); - - m_micaController.Kind = useMicaAlt ? Microsoft.UI.Composition.SystemBackdrops.MicaKind.BaseAlt : Microsoft.UI.Composition.SystemBackdrops.MicaKind.Base; + micaController = new MicaController(); + micaController.Kind = useMicaAlt ? MicaKind.BaseAlt : MicaKind.Base; // Enable the system backdrop. - // Note: Be sure to have "using WinRT;" to support the Window.As<...>() call. - m_micaController.AddSystemBackdropTarget(this.As()); - m_micaController.SetSystemBackdropConfiguration(m_configurationSource); + micaController.AddSystemBackdropTarget(this.As()); + micaController.SetSystemBackdropConfiguration(configurationSource); return true; // Succeeded. } @@ -38,25 +38,24 @@ bool TrySetMicaBackdrop(bool useMicaAlt) private void Window_Activated(object sender, WindowActivatedEventArgs args) { - m_configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated; + configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated; } private void Window_Closed(object sender, WindowEventArgs args) { - // Make sure any Mica/Acrylic controller is disposed so it doesn't try to - // use this closed window. - if (m_micaController != null) + // Make sure any Mica/Acrylic controller is disposed + if (micaController != null) { - m_micaController.Dispose(); - m_micaController = null; + micaController.Dispose(); + micaController = null; } this.Activated -= Window_Activated; - m_configurationSource = null; + configurationSource = null; } private void Window_ThemeChanged(FrameworkElement sender, object args) { - if (m_configurationSource != null) + if (configurationSource != null) { SetConfigurationSourceTheme(); } @@ -64,10 +63,10 @@ private void Window_ThemeChanged(FrameworkElement sender, object args) private void SetConfigurationSourceTheme() { - switch (((FrameworkElement)this.Content).ActualTheme) + switch (((FrameworkElement)Content).ActualTheme) { - case ElementTheme.Dark: m_configurationSource.Theme = Microsoft.UI.Composition.SystemBackdrops.SystemBackdropTheme.Dark; break; - case ElementTheme.Light: m_configurationSource.Theme = Microsoft.UI.Composition.SystemBackdrops.SystemBackdropTheme.Light; break; - case ElementTheme.Default: m_configurationSource.Theme = Microsoft.UI.Composition.SystemBackdrops.SystemBackdropTheme.Default; break; + case ElementTheme.Dark: configurationSource.Theme = SystemBackdropTheme.Dark; break; + case ElementTheme.Light: configurationSource.Theme = SystemBackdropTheme.Light; break; + case ElementTheme.Default: configurationSource.Theme = SystemBackdropTheme.Default; break; } } diff --git a/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample2.txt b/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample2.txt index f47c55ac2..34622844e 100644 --- a/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample2.txt +++ b/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample2.txt @@ -1,35 +1,35 @@ -using System.Runtime.InteropServices; // For DllImport -using WinRT; // required to support Window.As() +using System.Runtime.InteropServices; +using WinRT; +using Microsoft.UI.Composition; +using Microsoft.UI.Composition.SystemBackdrops; -WindowsSystemDispatcherQueueHelper m_wsdqHelper; // See separate sample below for implementation -Microsoft.UI.Composition.SystemBackdrops.DesktopAcrylicController m_acrylicController; -Microsoft.UI.Composition.SystemBackdrops.SystemBackdropConfiguration m_configurationSource; +WindowsSystemDispatcherQueueHelper wsdqHelper; // See the helper class sample for the implementation +SystemBackdrops.DesktopAcrylicController acrylicController; +SystemBackdrops.SystemBackdropConfiguration configurationSource; bool TrySetAcrylicBackdrop(bool useAcrylicThin) { - if (Microsoft.UI.Composition.SystemBackdrops.DesktopAcrylicController.IsSupported()) + if (DesktopAcrylicController.IsSupported()) { - m_wsdqHelper = new WindowsSystemDispatcherQueueHelper(); - m_wsdqHelper.EnsureWindowsSystemDispatcherQueueController(); + wsdqHelper = new WindowsSystemDispatcherQueueHelper(); + wsdqHelper.EnsureWindowsSystemDispatcherQueueController(); // Hooking up the policy object - m_configurationSource = new Microsoft.UI.Composition.SystemBackdrops.SystemBackdropConfiguration(); - this.Activated += Window_Activated; - this.Closed += Window_Closed; - ((FrameworkElement)this.Content).ActualThemeChanged += Window_ThemeChanged; + configurationSource = new SystemBackdropConfiguration(); + Activated += Window_Activated; + Closed += Window_Closed; + ((FrameworkElement)Content).ActualThemeChanged += Window_ThemeChanged; // Initial configuration state. - m_configurationSource.IsInputActive = true; + configurationSource.IsInputActive = true; SetConfigurationSourceTheme(); - m_acrylicController = new Microsoft.UI.Composition.SystemBackdrops.DesktopAcrylicController(); - - m_acrylicController.Kind = useAcrylicThin ? Microsoft.UI.Composition.SystemBackdrops.DesktopAcrylicKind.Thin : Microsoft.UI.Composition.SystemBackdrops.DesktopAcrylicKind.Base; + acrylicController = new DesktopAcrylicController(); + acrylicController.Kind = useAcrylicThin ? DesktopAcrylicKind.Thin : DesktopAcrylicKind.Base; // Enable the system backdrop. - // Note: Be sure to have "using WinRT;" to support the Window.As<...>() call. - m_acrylicController.AddSystemBackdropTarget(this.As()); - m_acrylicController.SetSystemBackdropConfiguration(m_configurationSource); + acrylicController.AddSystemBackdropTarget(As()); + acrylicController.SetSystemBackdropConfiguration(configurationSource); return true; // Succeeded. } @@ -38,25 +38,24 @@ bool TrySetAcrylicBackdrop(bool useAcrylicThin) private void Window_Activated(object sender, WindowActivatedEventArgs args) { - m_configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated; + configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated; } private void Window_Closed(object sender, WindowEventArgs args) { - // Make sure any Mica/Acrylic controller is disposed so it doesn't try to - // use this closed window. - if (m_acrylicController != null) + // Make sure any Mica/Acrylic controller is disposed + if (acrylicController != null) { - m_acrylicController.Dispose(); - m_acrylicController = null; + acrylicController.Dispose(); + acrylicController = null; } - this.Activated -= Window_Activated; - m_configurationSource = null; + Activated -= Window_Activated; + configurationSource = null; } private void Window_ThemeChanged(FrameworkElement sender, object args) { - if (m_configurationSource != null) + if (configurationSource != null) { SetConfigurationSourceTheme(); } @@ -66,8 +65,8 @@ private void SetConfigurationSourceTheme() { switch (((FrameworkElement)this.Content).ActualTheme) { - case ElementTheme.Dark: m_configurationSource.Theme = Microsoft.UI.Composition.SystemBackdrops.SystemBackdropTheme.Dark; break; - case ElementTheme.Light: m_configurationSource.Theme = Microsoft.UI.Composition.SystemBackdrops.SystemBackdropTheme.Light; break; - case ElementTheme.Default: m_configurationSource.Theme = Microsoft.UI.Composition.SystemBackdrops.SystemBackdropTheme.Default; break; + case ElementTheme.Dark: configurationSource.Theme = SystemBackdropTheme.Dark; break; + case ElementTheme.Light: configurationSource.Theme = SystemBackdropTheme.Light; break; + case ElementTheme.Default: configurationSource.Theme = SystemBackdropTheme.Default; break; } } diff --git a/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample3.txt b/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample3.txt index ccfa98a90..3df5c0539 100644 --- a/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample3.txt +++ b/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample3.txt @@ -1,12 +1,11 @@ -// Option 2 - Implement Mica with codebehind. -// Allows for toggling backdrops as shown in sample. +// Option 2 - Implement Mica with c#. bool TrySetMicaBackdrop(bool useMicaAlt) { - if (Microsoft.UI.Composition.SystemBackdrops.MicaController.IsSupported()) + if (SystemBackdrops.MicaController.IsSupported()) { - Microsoft.UI.Xaml.Media.MicaBackdrop micaBackdrop = new Microsoft.UI.Xaml.Media.MicaBackdrop(); - micaBackdrop.Kind = useMicaAlt ? Microsoft.UI.Composition.SystemBackdrops.MicaKind.BaseAlt : Microsoft.UI.Composition.SystemBackdrops.MicaKind.Base; - this.SystemBackdrop = micaBackdrop; + MicaBackdrop micaBackdrop = new MicaBackdrop(); + micaBackdrop.Kind = useMicaAlt ? MicaKind.BaseAlt : MicaKind.Base; + SystemBackdrop = micaBackdrop; return true; // Succeeded. } diff --git a/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample4.txt b/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample4.txt index 2b1d40d9b..a27ac9ced 100644 --- a/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample4.txt +++ b/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample4.txt @@ -1,11 +1,10 @@ -// Option 2 - Implement Acrylic with codebehind. -// Allows for toggling backdrops as shown in sample. +// Option 2 - Implement Acrylic with c#. bool TrySetDesktopAcrylicBackdrop() { - if (Microsoft.UI.Composition.SystemBackdrops.DesktopAcrylicController.IsSupported()) + if (DesktopAcrylicController.IsSupported()) { - Microsoft.UI.Xaml.Media.DesktopAcrylicBackdrop DesktopAcrylicBackdrop = new Microsoft.UI.Xaml.Media.DesktopAcrylicBackdrop(); - this.SystemBackdrop = DesktopAcrylicBackdrop; + DesktopAcrylicBackdrop DesktopAcrylicBackdrop = new DesktopAcrylicBackdrop(); + SystemBackdrop = DesktopAcrylicBackdrop; return true; // Succeeded. } diff --git a/WinUIGallery/DataModel/ControlInfoData.json b/WinUIGallery/DataModel/ControlInfoData.json index 0e347fcd3..b9abb6ad9 100644 --- a/WinUIGallery/DataModel/ControlInfoData.json +++ b/WinUIGallery/DataModel/ControlInfoData.json @@ -2900,14 +2900,31 @@ }, { "UniqueId": "SystemBackdrops", - "Title": "System Backdrops (Mica/Acrylic)", + "Title": "SystemBackdrop", "ApiNamespace": "Microsoft.UI.Composition.SystemBackdrops", "Subtitle": "System backdrops, like Mica and Acrylic, for the window.", "ImagePath": "ms-appx:///Assets/ControlImages/Acrylic.png", - "Description": "System backdrops are used to provide a different background for a Window other than the default white or black (depending on Light or Dark theme). Mica and Desktop Acrylic are the current supported backdrops. There are two options for applying a backdrop: first, to use built-in Mica/Acrylic types, which have no customization and are simple to apply. The second is to create a customizable backdrop, which requires more code.", + "Description": "System backdrops provide a transparency effect for the window background. Mica and Acrylic are the current supported backdrops. There are two options for applying a backdrop: the backdrop types (little customization, but easy to use) and the backdrop controllers (more customization, but harder to use)", "Content": "

Look at the SampleSystemBackdropsWindow.xaml.cs file in Visual Studio to see the full code for applying a backdrop.

", "SourcePath": "/Materials", + "IsUpdated": true, + "BaseClasses": [ + "Object", + "DependencyObject" + ], "Docs": [ + { + "Title": "SystemBackdrop - API", + "Uri": "https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.systembackdrop?view=windows-app-sdk-1.6" + }, + { + "Title": "MicaBackdrop - API", + "Uri": "https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.micabackdrop?view=windows-app-sdk-1.6" + }, + { + "Title": "DesktopAcrylicBackdrop - API", + "Uri": "https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.desktopacrylicbackdrop?view=windows-app-sdk-1.6" + }, { "Title": "MicaController - API", "Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.composition.systembackdrops.micacontroller" diff --git a/WinUIGallery/Helper/WindowHelper.cs b/WinUIGallery/Helper/WindowHelper.cs index 7b1a51ff1..46ec8a6a2 100644 --- a/WinUIGallery/Helper/WindowHelper.cs +++ b/WinUIGallery/Helper/WindowHelper.cs @@ -9,6 +9,7 @@ //********************************************************* using Microsoft.UI; +using Microsoft.UI.Composition.SystemBackdrops; using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media; @@ -16,7 +17,9 @@ using System.Collections.Generic; using System.Threading.Tasks; using Windows.Storage; +using WinRT; using WinRT.Interop; +using static WinUIGallery.Win32; namespace WinUIGallery.Helper { @@ -25,7 +28,7 @@ namespace WinUIGallery.Helper // of all active Windows. The app code must call WindowHelper.CreateWindow // rather than "new Window" so we can keep track of all the relevant // windows. In the future, we would like to support this in platform APIs. - public class WindowHelper + public static class WindowHelper { static public Window CreateWindow() { @@ -99,5 +102,27 @@ static public StorageFolder GetAppLocalFolder() } return localFolder; } + + public static void SetTitleBarBackdrop(this Window window, SystemBackdrop backdrop) + { + var backdropType = DwmSystemBackdropType.DWMSBT_AUTO; + + if (backdrop is MicaBackdrop micaBackdrop) + backdropType = micaBackdrop.Kind == MicaKind.Base ? DwmSystemBackdropType.DWMSBT_MAINWINDOW : DwmSystemBackdropType.DWMSBT_TABBEDWINDOW; + else if (backdrop is DesktopAcrylicBackdrop) + backdropType = DwmSystemBackdropType.DWMSBT_TRANSIENTWINDOW; + else if (backdrop is null) + backdropType = DwmSystemBackdropType.DWMSBT_NONE; + + var backdropTypeInt = ((int)backdropType); + int hResult = DwmSetWindowAttribute(WindowNative.GetWindowHandle(window), DwmWindowAttribute.DWMWA_SYSTEMBACKDROP_TYPE, ref backdropTypeInt, sizeof(DwmSystemBackdropType)); + ExceptionHelpers.ThrowExceptionForHR(hResult); + } + + public static void SetTitleBarTheme(this Window window) + { + int darkMode = ((FrameworkElement)window.Content).ActualTheme == ElementTheme.Dark ? 1 : 0; + DwmSetWindowAttribute(WindowNative.GetWindowHandle(window), DwmWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE, ref darkMode, sizeof(int)); + } } } diff --git a/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml b/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml index 78817cdf2..9e0d8a265 100644 --- a/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml +++ b/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml @@ -4,29 +4,23 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d"> + mc:Ignorable="d" + Title="SystemBackdrop sample window"> - - - - - - - - + - - @@ -84,9 +86,16 @@
- Helpers: + + + + + + - +
diff --git a/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsTitleBarBackdrops.txt b/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsTitleBarBackdrops.txt new file mode 100644 index 000000000..d85ccbbcd --- /dev/null +++ b/WinUIGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsTitleBarBackdrops.txt @@ -0,0 +1,35 @@ +internal enum DwmSystemBackdropType : int +{ + DWMSBT_AUTO = 0, //Default + DWMSBT_NONE = 1, //None + DWMSBT_MAINWINDOW = 2, //Mica + DWMSBT_TRANSIENTWINDOW = 3, //Acrylic thin + DWMSBT_TABBEDWINDOW = 4, //Mica Alt +} + + +internal enum DwmWindowAttribute : int +{ + DWMWA_SYSTEMBACKDROP_TYPE = 38 //Title bar backdrop +} + + +[DllImport("DwmApi.dll")] +public static extern int DwmSetWindowAttribute(nint hWnd, DwmWindowAttribute attribute, ref int value, int size); + + +public static void SetTitleBarBackdrop(this Window window, SystemBackdrop backdrop) +{ + var backdropType = DwmSystemBackdropType.DWMSBT_AUTO; + + if (backdrop is MicaBackdrop micaBackdrop) + backdropType = micaBackdrop.Kind == MicaKind.Base ? DwmSystemBackdropType.DWMSBT_MAINWINDOW : DwmSystemBackdropType.DWMSBT_TABBEDWINDOW; + else if (backdrop is DesktopAcrylicBackdrop) + backdropType = DwmSystemBackdropType.DWMSBT_TRANSIENTWINDOW; + else if (backdrop is null) + backdropType = DwmSystemBackdropType.DWMSBT_NONE; + + var backdropTypeInt = ((int)backdropType); + int hResult = DwmSetWindowAttribute(WindowNative.GetWindowHandle(window), DwmWindowAttribute.DWMWA_SYSTEMBACKDROP_TYPE, ref backdropTypeInt, sizeof(DwmSystemBackdropType)); + ExceptionHelpers.ThrowExceptionForHR(hResult); +} \ No newline at end of file diff --git a/WinUIGallery/Helper/Win32WindowHelper.cs b/WinUIGallery/Helper/Win32WindowHelper.cs index 79e5d2778..03b6f6cb4 100644 --- a/WinUIGallery/Helper/Win32WindowHelper.cs +++ b/WinUIGallery/Helper/Win32WindowHelper.cs @@ -1,6 +1,10 @@ using System; using System.Runtime.InteropServices; +using Microsoft.UI.Composition.SystemBackdrops; using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Media; +using WinRT.Interop; +using WinRT; using static WinUIGallery.Win32; namespace WinUIGallery.Helper @@ -85,4 +89,30 @@ private struct MINMAXINFO public POINT ptMaxTrackSize; } } + + public static class Win32HelperExtensions + { + public static void SetTitleBarBackdrop(this Window window, SystemBackdrop backdrop) + { + var backdropType = DwmSystemBackdropType.DWMSBT_AUTO; + + if (backdrop is MicaBackdrop micaBackdrop) + backdropType = micaBackdrop.Kind == MicaKind.Base ? DwmSystemBackdropType.DWMSBT_MAINWINDOW : DwmSystemBackdropType.DWMSBT_TABBEDWINDOW; + else if (backdrop is DesktopAcrylicBackdrop) + backdropType = DwmSystemBackdropType.DWMSBT_TRANSIENTWINDOW; + else if (backdrop is null) + backdropType = DwmSystemBackdropType.DWMSBT_NONE; + + var backdropTypeInt = (int)backdropType; + int hResult = DwmSetWindowAttribute(WindowNative.GetWindowHandle(window), DwmWindowAttribute.DWMWA_SYSTEMBACKDROP_TYPE, ref backdropTypeInt, sizeof(DwmSystemBackdropType)); + ExceptionHelpers.ThrowExceptionForHR(hResult); + } + + public static void SetTitleBarTheme(this Window window, ElementTheme theme = ElementTheme.Default) + { + int darkMode = (theme == ElementTheme.Default ? ((FrameworkElement)window.Content).ActualTheme : theme) == ElementTheme.Dark ? 1 : 0; + int hResult = DwmSetWindowAttribute(WindowNative.GetWindowHandle(window), DwmWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE, ref darkMode, sizeof(int)); + ExceptionHelpers.ThrowExceptionForHR(hResult); + } + } } diff --git a/WinUIGallery/Helper/WindowHelper.cs b/WinUIGallery/Helper/WindowHelper.cs index 46ec8a6a2..b7c2d6aa2 100644 --- a/WinUIGallery/Helper/WindowHelper.cs +++ b/WinUIGallery/Helper/WindowHelper.cs @@ -19,7 +19,6 @@ using Windows.Storage; using WinRT; using WinRT.Interop; -using static WinUIGallery.Win32; namespace WinUIGallery.Helper { @@ -102,27 +101,5 @@ static public StorageFolder GetAppLocalFolder() } return localFolder; } - - public static void SetTitleBarBackdrop(this Window window, SystemBackdrop backdrop) - { - var backdropType = DwmSystemBackdropType.DWMSBT_AUTO; - - if (backdrop is MicaBackdrop micaBackdrop) - backdropType = micaBackdrop.Kind == MicaKind.Base ? DwmSystemBackdropType.DWMSBT_MAINWINDOW : DwmSystemBackdropType.DWMSBT_TABBEDWINDOW; - else if (backdrop is DesktopAcrylicBackdrop) - backdropType = DwmSystemBackdropType.DWMSBT_TRANSIENTWINDOW; - else if (backdrop is null) - backdropType = DwmSystemBackdropType.DWMSBT_NONE; - - var backdropTypeInt = ((int)backdropType); - int hResult = DwmSetWindowAttribute(WindowNative.GetWindowHandle(window), DwmWindowAttribute.DWMWA_SYSTEMBACKDROP_TYPE, ref backdropTypeInt, sizeof(DwmSystemBackdropType)); - ExceptionHelpers.ThrowExceptionForHR(hResult); - } - - public static void SetTitleBarTheme(this Window window) - { - int darkMode = ((FrameworkElement)window.Content).ActualTheme == ElementTheme.Dark ? 1 : 0; - DwmSetWindowAttribute(WindowNative.GetWindowHandle(window), DwmWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE, ref darkMode, sizeof(int)); - } } } diff --git a/WinUIGallery/Helper/WindowsSystemDispatcherQueueHelper.cs b/WinUIGallery/Helper/WindowsSystemDispatcherQueueHelper.cs new file mode 100644 index 000000000..081f8e8cc --- /dev/null +++ b/WinUIGallery/Helper/WindowsSystemDispatcherQueueHelper.cs @@ -0,0 +1,45 @@ +using System; +using System.Runtime.InteropServices; +using Windows.System; + +namespace WinUIGallery.Helper +{ + class WindowsSystemDispatcherQueueHelper + { + [StructLayout(LayoutKind.Sequential)] + struct DispatcherQueueOptions + { + internal int dwSize; + internal int threadType; + internal int apartmentType; + } + + [DllImport("CoreMessaging.dll")] + private static unsafe extern int CreateDispatcherQueueController(DispatcherQueueOptions options, IntPtr* instance); + + IntPtr m_dispatcherQueueController = IntPtr.Zero; + public void EnsureWindowsSystemDispatcherQueueController() + { + if (DispatcherQueue.GetForCurrentThread() != null) + { + // one already exists, so we'll just use it. + return; + } + + if (m_dispatcherQueueController == IntPtr.Zero) + { + DispatcherQueueOptions options; + options.dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions)); + options.threadType = 2; // DQTYPE_THREAD_CURRENT + options.apartmentType = 2; // DQTAT_COM_STA + + unsafe + { + IntPtr dispatcherQueueController; + CreateDispatcherQueueController(options, &dispatcherQueueController); + m_dispatcherQueueController = dispatcherQueueController; + } + } + } + } +} diff --git a/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml b/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml index 9e0d8a265..02ee18727 100644 --- a/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml +++ b/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml @@ -22,5 +22,13 @@ Click="ChangeBackdropButton_Click" Content="Change Backdrop" /> + + + + + diff --git a/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml.cs b/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml.cs index 7ffb02bf4..3d6fe6931 100644 --- a/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml.cs +++ b/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml.cs @@ -1,6 +1,7 @@ using System.Linq; using Microsoft.UI.Composition.SystemBackdrops; using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media; using WinUIGallery.Helper; @@ -18,6 +19,7 @@ public SampleBuiltInSystemBackdropsWindow() ((FrameworkElement)Content).RequestedTheme = ThemeHelper.RootTheme; this.SetTitleBarTheme(); SetBackdrop(BackdropType.Mica); + ThemeComboBox.SelectedIndex = 0; } public enum BackdropType @@ -133,5 +135,16 @@ void ChangeBackdropButton_Click(object sender, RoutedEventArgs e) SetBackdrop(newType); } + + private void ThemeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + ((FrameworkElement)Content).RequestedTheme = ThemeComboBox.SelectedIndex switch + { + 1 => ElementTheme.Light, + 2 => ElementTheme.Dark, + _ => ElementTheme.Default + }; + this.SetTitleBarTheme(); + } } } diff --git a/WinUIGallery/SamplePages/SampleSystemBackdropsWindow.xaml b/WinUIGallery/SamplePages/SampleSystemBackdropsWindow.xaml index 8626f288d..b4d14328a 100644 --- a/WinUIGallery/SamplePages/SampleSystemBackdropsWindow.xaml +++ b/WinUIGallery/SamplePages/SampleSystemBackdropsWindow.xaml @@ -7,20 +7,32 @@ mc:Ignorable="d" Title="SystemBackdrop sample window"> - + - + - - + + + Inheritance: Object + + Manages rendering and system policy for the mica material. + + + - - + + + Inheritance: Object + + Manages rendering and system policy for the background acrylic material. + + + Helpers: - + Date: Sat, 21 Dec 2024 00:07:16 +0100 Subject: [PATCH 4/8] custom title bar setting and more descriptions --- .../ControlPages/SystemBackdropsPage.xaml | 18 +++++---- .../SampleBuiltInSystemBackdropsWindow.xaml | 25 ++++++------ ...SampleBuiltInSystemBackdropsWindow.xaml.cs | 31 +++++++++++++++ .../SampleSystemBackdropsWindow.xaml | 1 + .../SampleSystemBackdropsWindow.xaml.cs | 38 +++++++++++++++++++ 5 files changed, 95 insertions(+), 18 deletions(-) diff --git a/WinUIGallery/ControlPages/SystemBackdropsPage.xaml b/WinUIGallery/ControlPages/SystemBackdropsPage.xaml index 704f63259..7828eea20 100644 --- a/WinUIGallery/ControlPages/SystemBackdropsPage.xaml +++ b/WinUIGallery/ControlPages/SystemBackdropsPage.xaml @@ -64,11 +64,13 @@ - + Inheritance: Object -> DependencyObject -> SystemBackdrop - Acrylic is a semi-transparent material that replicates the effect of frosted glass. - It's used only for transient, light-dismiss surfaces such as flyouts and context menus. + Acrylic is a semi-transparent material that replicates the effect of frosted glass. It's used only for transient, light-dismiss surfaces such as flyouts and context menus. + Acrylic's most noticeable characteristic is its transparency. There are two acrylic blend types that change what's visible through the material: + Background acrylic reveals the desktop wallpaper and other windows that are behind the currently active app, adding depth between application windows while celebrating the user's personalization preferences. + In-app acrylic adds a sense of depth within the app frame, providing both focus and hierarchy. (Inplemented with a AcrilicBrush in Xaml) @@ -79,10 +81,11 @@ - + Inheritance: Object - Manages rendering and system policy for the mica material. + Manages rendering and system policy for the mica material. The MicaController class provides a very customizable way to apply the Mica material to a app. + This is a list of properties that can be modified: FallbackColor, Kind (Can also be set using the MicaBackdrop class), LuminosityOpacity, State, TintColor and the TintOpacity. @@ -91,10 +94,11 @@ - + Inheritance: Object - Manages rendering and system policy for the background acrylic material. + Manages rendering and system policy for the background acrylic material. Acrylic has the same level of customization as Mica, but the type (Base / Thin) can't be changed using the DesktopAcrylicBackdrop class. + If you wan't to use Acrylic Thin in your app you have to use the DesktopAcrylicController class. There are 2 types of Acrylic: Base and Thin. The DesktopAcrylicBackdrop class uses a version of the Base type with less dimming. diff --git a/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml b/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml index 02ee18727..e6fee42cb 100644 --- a/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml +++ b/WinUIGallery/SamplePages/SampleBuiltInSystemBackdropsWindow.xaml @@ -7,28 +7,31 @@ mc:Ignorable="d" Title="SystemBackdrop sample window"> - + - + - -