Skip to content

Commit

Permalink
beautify & fix Windows11 acrylic
Browse files Browse the repository at this point in the history
  • Loading branch information
lingrottin committed Oct 2, 2023
1 parent 88b57ba commit becfe3e
Show file tree
Hide file tree
Showing 10 changed files with 498 additions and 42 deletions.
1 change: 0 additions & 1 deletion MapTP.App/AboutWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using Walterlv.Windows.Effects;

namespace MapTP.App
{
Expand Down
12 changes: 10 additions & 2 deletions MapTP.App/App.config
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
261 changes: 261 additions & 0 deletions MapTP.App/BlurManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;

namespace MapTP.App
{
internal class BlurManager
{
// Completely from Walterlv

private readonly Window _window;
private bool _isEnabled;
private int _blurColor;

/// <summary>
/// 创建 <see cref="BlurManager"/> 的一个新实例。
/// </summary>
/// <param name="window">要创建模糊特效的窗口实例。</param>
public BlurManager(Window window) => _window = window ?? throw new ArgumentNullException(nameof(window));

/// <summary>
/// 获取或设置此窗口模糊特效是否生效的一个状态。
/// 默认为 false,即不生效。
/// </summary>
[DefaultValue(false)]
public bool IsEnabled
{
get => _isEnabled;
set
{
_isEnabled = value;
OnIsEnabledChanged(value);
}
}

/// <summary>
/// 获取或设置此窗口模糊特效叠加的颜色。
/// </summary>
public Color Color
{
get => Color.FromArgb(
// 取出红色分量。
(byte)((_blurColor & 0x000000ff) >> 0),
// 取出绿色分量。
(byte)((_blurColor & 0x0000ff00) >> 8),
// 取出蓝色分量。
(byte)((_blurColor & 0x00ff0000) >> 16),
// 取出透明分量。
(byte)((_blurColor & 0xff000000) >> 24));
set => _blurColor =
// 组装红色分量。
value.R << 0 |
// 组装绿色分量。
value.G << 8 |
// 组装蓝色分量。
value.B << 16 |
// 组装透明分量。
value.A << 24;
}

private void OnIsEnabledChanged(bool isEnabled)
{
Window window = _window;
var handle = new WindowInteropHelper(window).EnsureHandle();
Composite(handle, isEnabled);
}

private void Composite(IntPtr handle, bool isEnabled)
{
// 操作系统版本判定。
var osVersion = Environment.OSVersion.Version;
var windows10_1809 = new Version(10, 0, 17763);
var windows10 = new Version(10, 0);
var windows11_buildver = 22000;

// 创建 AccentPolicy 对象。
var accent = new AccentPolicy();

// 设置特效。
if (!isEnabled)
{
accent.AccentState = AccentState.ACCENT_DISABLED;
}
else if(Environment.OSVersion.Version.Build >= windows11_buildver)
{
accent.AccentState = AccentState.ACCENT_INVALID_STATE; // disable Acrylic and do nothing
}
else if (osVersion > windows10_1809)
{
// 如果系统在 Windows 10 (1809) 以上,则启用亚克力效果,并组合已设置的叠加颜色和透明度。
// 请参见《在 WPF 程序中应用 Windows 10 真•亚克力效果》
// https://blog.walterlv.com/post/using-acrylic-in-wpf-application.html
accent.AccentState = AccentState.ACCENT_ENABLE_ACRYLICBLURBEHIND;
accent.GradientColor = _blurColor;
}
else if (osVersion > windows10)
{
// 如果系统在 Windows 10 以上,则启用 Windows 10 早期的模糊特效。
// 请参见《在 Windows 10 上为 WPF 窗口添加模糊特效》
// https://blog.walterlv.com/post/win10/2017/10/02/wpf-transparent-blur-in-windows-10.html
accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;
}
else
{
// 暂时不处理其他操作系统:
// - Windows 8/8.1 不支持任何模糊特效
// - Windows Vista/7 支持 Aero 毛玻璃效果
return;
}

// 将托管结构转换为非托管对象。
var accentPolicySize = Marshal.SizeOf(accent);
var accentPtr = Marshal.AllocHGlobal(accentPolicySize);
Marshal.StructureToPtr(accent, accentPtr, false);

// 设置窗口组合特性。
try
{
// 设置模糊特效。
var data = new WindowCompositionAttributeData
{
Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY,
SizeOfData = accentPolicySize,
Data = accentPtr,
};
SetWindowCompositionAttribute(handle, ref data);
}
finally
{
// 释放非托管对象。
Marshal.FreeHGlobal(accentPtr);
}
}

[DllImport("user32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
private static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data);

private enum AccentState
{
/// <summary>
/// 完全禁用 DWM 的叠加特效。
/// </summary>
ACCENT_DISABLED = 0,

/// <summary>
///
/// </summary>
ACCENT_ENABLE_GRADIENT = 1,
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
ACCENT_ENABLE_BLURBEHIND = 3,
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4,
ACCENT_INVALID_STATE = 5,
}

[StructLayout(LayoutKind.Sequential)]
private struct AccentPolicy
{
public AccentState AccentState;
public int AccentFlags;
public int GradientColor;
public int AnimationId;
}

[StructLayout(LayoutKind.Sequential)]
private struct WindowCompositionAttributeData
{
public WindowCompositionAttribute Attribute;
public IntPtr Data;
public int SizeOfData;
}

private enum WindowCompositionAttribute
{
// 省略其他未使用的字段
WCA_ACCENT_POLICY = 19,
// 省略其他未使用的字段
}

/// <summary>
/// 当前操作系统支持的透明模糊特效级别。
/// </summary>
public enum BlurSupportedLevel
{
/// <summary>
///
/// </summary>
NotSupported,
Aero,
Blur,
Acrylic,
}
}

/// <summary>
/// enables Mica for Windows 11 users
/// </summary>
internal class Mica
{
//this is from Difegue/Mica-WPF-Sample
#region Win32
[DllImport("dwmapi.dll")]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, DwmWindowAttribute dwAttribute, ref int pvAttribute, int cbAttribute);

[Flags]
public enum DwmWindowAttribute : uint
{
DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
DWMWA_MICA_EFFECT = 1029,
DWMA_SYSTEMBACKDROP_TYPE=38,
}
#endregion

// Enable Mica on the given HWND.
public static void EnableMica(HwndSource source, bool darkThemeEnabled)
{
int trueValue = 0x01;
int falseValue = 0x00;
int systemBackdropType_Main = 3;

// Set dark mode before applying the material, otherwise you'll get an ugly flash when displaying the window.
if (darkThemeEnabled)
DwmSetWindowAttribute(source.Handle, DwmWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE, ref trueValue, Marshal.SizeOf(typeof(int)));
else
DwmSetWindowAttribute(source.Handle, DwmWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE, ref falseValue, Marshal.SizeOf(typeof(int)));

DwmSetWindowAttribute(source.Handle, DwmWindowAttribute.DWMWA_MICA_EFFECT, ref trueValue, Marshal.SizeOf(typeof(int)));
DwmSetWindowAttribute(source.Handle, DwmWindowAttribute.DWMA_SYSTEMBACKDROP_TYPE, ref systemBackdropType_Main, Marshal.SizeOf(typeof(int)));
}

private HwndSource hwndSource;

private bool _enable;
public bool enable
{
get => _enable;
set
{
_enable = value;
if (enable)
{
EnableMica(hwndSource, false);
}
}
}

public Mica(HwndSource _hwndSource)
{
this.hwndSource = _hwndSource;
}
}
}

2 changes: 0 additions & 2 deletions MapTP.App/CalibrateWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
using System;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using Walterlv.Windows.Effects;

namespace MapTP.App
{
Expand Down
6 changes: 4 additions & 2 deletions MapTP.App/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
xmlns:local="clr-namespace:MapTP.App"
mc:Ignorable="d"
Title="MapTP" Height="500" Width="800"
Background="{x:Null}">
Foreground="{DynamicResource SystemControlPageTextBaseHighBrush}"
WindowStyle="None"
Background="#33aaaaff">
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="0,0,0,1"/>
<WindowChrome x:Name="WindowChrome" GlassFrameThickness="0,0,-1,0"/>
</WindowChrome.WindowChrome>
<Grid>
<Grid.RowDefinitions>
Expand Down
47 changes: 36 additions & 11 deletions MapTP.App/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using System.Windows.Media;
using System.Xml;
using System.Xml.Serialization;
using Walterlv.Windows.Effects;

namespace MapTP.App
{
Expand Down Expand Up @@ -98,9 +97,12 @@ public void ReceiveTouchpadSize(int X, int Y)
{
this.TouchpadSizeX = X;
this.TouchpadSizeY = Y;
TpAreaRect.Width = CalculateRectangle(TouchpadSizeX, TouchpadSizeY);
TpRectGrid.Width = CalculateRectangle(TouchpadSizeX, TouchpadSizeY);
TouchpadSizeTB.Text = $"Touchpad size: {TouchpadSizeX}x{TouchpadSizeY}";
if (TouchpadSizeX != 0 && TouchpadSizeY != 0)
{
TpAreaRect.Width = CalculateRectangle(TouchpadSizeX, TouchpadSizeY);
TpRectGrid.Width = CalculateRectangle(TouchpadSizeX, TouchpadSizeY);
TouchpadSizeTB.Text = $"Touchpad size: {TouchpadSizeX}x{TouchpadSizeY}";
}
return;
}

Expand Down Expand Up @@ -190,19 +192,42 @@ protected override void OnSourceInitialized(EventArgs e)
private void OnLoaded(object sender, RoutedEventArgs e)
{

var WalterlvCompositor = new WindowAccentCompositor(this)

if (!(Environment.OSVersion.Version > new Version(10, 0, 17763)))
{
this.Background = Brushes.White;
}
else if (Environment.OSVersion.Version.Build >= 22000) // Mica
{
Color = Color.FromArgb(0x33, 0x87, 0xce, 0xfa)
};
WalterlvCompositor.IsEnabled = true;

if (!(Environment.OSVersion.Version > new Version(10, 0, 17763)))
// Get PresentationSource
PresentationSource presentationSource = PresentationSource.FromVisual((Visual)sender);

// Subscribe to PresentationSource's ContentRendered event
presentationSource.ContentRendered += (s,ev)=>OnRendered(PresentationSource.FromVisual((Visual)sender) as HwndSource);

}
else
{
this.Background = Brushes.Aqua;
WalterlvCompositor.IsEnabled = false;

var WalterlvCompositor = new BlurManager(this)
{
Color = Color.FromArgb(0x33, 0x87, 0xce, 0xfa)
};
WalterlvCompositor.IsEnabled = true;
}
}

/// <summary>
/// Enable Mica when the window is rendered
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnRendered(HwndSource src)
{
var mica = new Mica(src);
mica.enable = true;
}

/// <summary>
/// This method is for limiting TextBoxes only to accept numbers
Expand Down
Loading

0 comments on commit becfe3e

Please sign in to comment.