Skip to content

Commit

Permalink
Improve way to respond to accent color change
Browse files Browse the repository at this point in the history
  • Loading branch information
emoacht committed May 9, 2022
1 parent 42f37dd commit 71c8dc6
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 35 deletions.
2 changes: 1 addition & 1 deletion Source/Monitorian.Core/Views/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public MainWindow(AppControllerCore controller)
{
ViewModel.MonitorsView.Refresh();
};
//controller.WindowPainter.ColorChanged += (_, _) =>
//controller.WindowPainter.AccentColorChanged += (_, _) =>
//{
//};

Expand Down
25 changes: 24 additions & 1 deletion Source/ScreenFrame/Helper/ColorExtension.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
Expand All @@ -9,9 +10,31 @@ namespace ScreenFrame.Helper
{
internal static class ColorExtension
{
#region Win32

[DllImport("Dwmapi.dll")]
private static extern int DwmGetColorizationColor(
out uint pcrColorization,
[MarshalAs(UnmanagedType.Bool)] out bool pfOpaqueBlend);

private const int S_OK = 0x0;

#endregion

public static Color GetColorizationColor()
{
if (DwmGetColorizationColor(
out uint pcrColorization,
out _) == S_OK)
{
return FromUInt32(pcrColorization);
}
return default;
}

public static uint ToUInt32(this Color color)
{
var bytes = new[] { color.B, color.G, color.R, color.A }.ToArray();
var bytes = new[] { color.B, color.G, color.R, color.A };
return BitConverter.ToUInt32(bytes, 0);
}

Expand Down
23 changes: 22 additions & 1 deletion Source/ScreenFrame/Helper/Throttle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace ScreenFrame.Helper
/// </summary>
internal class Throttle
{
private static readonly TimeSpan _dueTime = TimeSpan.FromSeconds(1);
private static readonly TimeSpan _dueTime = TimeSpan.FromSeconds(0.2);
private readonly Action _action;

public Throttle(Action action) => this._action = action;
Expand All @@ -29,4 +29,25 @@ public async Task PushAsync()
}
}
}

internal class Throttle<T>
{
private static readonly TimeSpan _dueTime = TimeSpan.FromSeconds(0.2);
private readonly Action<T> _action;

public Throttle(Action<T> action) => this._action = action;

private Task _lastWaitTask;

public async Task PushAsync(T value)
{
var currentWaitTask = Task.Delay(_dueTime);
_lastWaitTask = currentWaitTask;
await currentWaitTask;
if (_lastWaitTask == currentWaitTask)
{
_action?.Invoke(value);
}
}
}
}
101 changes: 69 additions & 32 deletions Source/ScreenFrame/Painter/WindowPainter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ public WindowPainter(IReadOnlyList<string> args)

private ColorTheme _theme;

/// <summary>
/// Whether to respond when the color theme of Windows is changed
/// </summary>
protected bool RespondsThemeChanged { get; set; } = true; // Default

/// <summary>
/// Background texture of window
/// </summary>
Expand Down Expand Up @@ -138,17 +133,15 @@ private void OnSourceInitialized(object sender, EventArgs e)
DisableTransitions(window);
PaintBackground(window);

if (RespondsThemeChanged)
AddHook(window);
AddHook(window);
}

private void OnClosed(object sender, EventArgs e)
{
var oldWindow = (Window)sender;
Remove(oldWindow);

if (RespondsThemeChanged &&
RemoveHook(oldWindow))
if (RemoveHook(oldWindow))
{
var newWindow = _windows.FirstOrDefault(x => x.IsInitialized);
if (newWindow is not null)
Expand Down Expand Up @@ -194,46 +187,53 @@ private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref b
{
switch (msg)
{
case WM_SETTINGCHANGE:
if (string.Equals(Marshal.PtrToStringAuto(lParam), "ImmersiveColorSet"))
{
OnThemeChanged();
}
case WM_SETTINGCHANGE when (Marshal.PtrToStringAuto(lParam) == "ImmersiveColorSet") && RespondsThemeChanged:
OnThemeChanged();
break;

case WM_DWMCOLORIZATIONCOLORCHANGED:
OnColorChanged();
case WM_DWMCOLORIZATIONCOLORCHANGED when RespondsAccentColorChanged:
OnAccentColorChanged(ColorExtension.FromUInt32((uint)wParam));
break;
}
return IntPtr.Zero;
}

private Throttle _themeChange;
private Throttle _colorChange;
private Throttle _applyChangedTheme;
private Throttle<Color> _applyChangedAccentColor;

private async void OnThemeChanged()
{
_themeChange ??= new Throttle(() =>
_applyChangedTheme ??= new Throttle(() =>
{
if (ApplyChangedTheme())
{
ThemeChanged?.Invoke(null, EventArgs.Empty);
}
});
await _themeChange.PushAsync();
await _applyChangedTheme.PushAsync();
}

private async void OnColorChanged()
private async void OnAccentColorChanged(Color color)
{
_colorChange ??= new Throttle(() =>
_applyChangedAccentColor ??= new Throttle<Color>(c =>
{
ColorChanged?.Invoke(null, EventArgs.Empty);
if (ApplyChangedAccentColor(c))
{
AccentColorChanged?.Invoke(null, EventArgs.Empty);
}
});
await _colorChange.PushAsync();
await _applyChangedAccentColor.PushAsync(color);
}

#endregion

#region Theme

/// <summary>
/// Whether to respond when the color theme for Windows is changed
/// </summary>
protected bool RespondsThemeChanged { get; set; } = true; // Default

/// <summary>
/// Occurs when the color theme for Windows is changed.
/// </summary>
Expand Down Expand Up @@ -352,13 +352,6 @@ private void ResetTranslucent()
_translucentBrush = null;
}

/// <summary>
/// Occurs when the accent color for Windows is changed.
/// </summary>
public event EventHandler ColorChanged;

#region Resources

/// <summary>
/// Changes color themes.
/// </summary>
Expand Down Expand Up @@ -397,6 +390,50 @@ protected static void ChangeResources(string oldUriString, string newUriString)

#endregion

#region Accent color

/// <summary>
/// Whether to respond when the accent color for Windows is changed
/// </summary>
protected bool RespondsAccentColorChanged
{
get => _respondsAccentColorChanged;
set
{
_respondsAccentColorChanged = value;
if (_respondsAccentColorChanged)
_accentColor = ColorExtension.GetColorizationColor();
}
}
private bool _respondsAccentColorChanged;

/// <summary>
/// Occurs when the accent color for Windows is changed.
/// </summary>
public event EventHandler AccentColorChanged;

private static Color _accentColor;

private bool ApplyChangedAccentColor(Color accentColor)
{
if (_accentColor == accentColor)
return false;

// Color provided with WM_DWMCOLORIZATIONCOLORCHANGED and by DwmGetColorizationColor
// will not match that provided by UISettings.
ChangeAccentColors();
_accentColor = accentColor;
return true;
}

/// <summary>
/// Changes accent colors.
/// </summary>
protected virtual void ChangeAccentColors()
{ }

#endregion

#region IDisposable

private bool _isDisposed = false;
Expand All @@ -422,7 +459,7 @@ protected virtual void Dispose(bool disposing)
{
RemoveHook();
ThemeChanged = null;
ColorChanged = null;
AccentColorChanged = null;
}

_isDisposed = true;
Expand Down

0 comments on commit 71c8dc6

Please sign in to comment.