Skip to content

Commit

Permalink
Fixed slow window drag on arcylic windows. Closes #349
Browse files Browse the repository at this point in the history
  • Loading branch information
GoldenTao committed Feb 26, 2021
1 parent 1623c44 commit f369482
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 9 deletions.
72 changes: 68 additions & 4 deletions EarTrumpet/UI/Themes/AcrylicBrush.cs
@@ -1,5 +1,9 @@
using EarTrumpet.Interop.Helpers;
using EarTrumpet.Extensions;
using EarTrumpet.Interop.Helpers;
using System;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Threading;

namespace EarTrumpet.UI.Themes
{
Expand All @@ -9,11 +13,32 @@ class AcrylicBrush
public static void SetBackground(DependencyObject obj, string value) => obj.SetValue(BackgroundProperty, value);
public static readonly DependencyProperty BackgroundProperty =
DependencyProperty.RegisterAttached("Background", typeof(string), typeof(AcrylicBrush), new PropertyMetadata("", BackgroundChanged));

public static bool GetIsSuppressed(DependencyObject obj) => (bool)obj.GetValue(IsSuppressedProperty);
public static void SetIsSuppressed(DependencyObject obj, bool value) => obj.SetValue(IsSuppressedProperty, value);
public static readonly DependencyProperty IsSuppressedProperty =
DependencyProperty.RegisterAttached("IsSuppressed", typeof(bool), typeof(AcrylicBrush), new PropertyMetadata(false));

private static void BackgroundChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
var window = (Window)dependencyObject;
var suppressAryclicTimer = new DispatcherTimer();

window.Closed += (_, __) => window = null;
window.SourceInitialized += (_, __) => ApplyAcrylicToWindow(window, (string)e.NewValue);
window.LocationChanged += (_, __) => SuppressAryclic(window, suppressAryclicTimer);
window.SizeChanged += (_, __) => SuppressAryclic(window, suppressAryclicTimer);

suppressAryclicTimer.Interval = TimeSpan.FromMilliseconds(200);
suppressAryclicTimer.Tick += (_, __) =>
{
suppressAryclicTimer.Stop();
if (window != null)
{
SetIsSuppressed(window, false);
UpdateWindowAcrylic(window);
}
};

Manager.Current.ThemeChanged += () =>
{
Expand All @@ -24,11 +49,50 @@ private static void BackgroundChanged(DependencyObject dependencyObject, Depende
};
}

private static void SuppressAryclic(Window window, DispatcherTimer timer)
{
if (window != null && (HwndSource)PresentationSource.FromVisual(window) != null)
{
if (!timer.IsEnabled)
{
SetIsSuppressed(window, true);

// This works to prevent flicker:
window.InvalidateVisual();
window.UpdateLayout();
Dispatcher.CurrentDispatcher.InvokeAsync(() => {
if (window != null)
{
UpdateWindowAcrylic(window);
}
}, DispatcherPriority.Render);
}
timer.Stop();
timer.Start();
}
}

private static void ApplyAcrylicToWindow(Window window, string refValue)
{
AccentPolicyLibrary.EnableAcrylic(window,
Manager.Current.ResolveRef(window, refValue),
Interop.User32.AccentFlags.DrawAllBorders);
if (window != null)
{
AccentPolicyLibrary.EnableAcrylic(window,
Manager.Current.ResolveRef(window, refValue),
Interop.User32.AccentFlags.DrawAllBorders);
}
}

private static void UpdateWindowAcrylic(Window window)
{
var suppressed = GetIsSuppressed(window);
if (suppressed)
{
AccentPolicyLibrary.DisableAcrylic(window);
}
else
{
ApplyAcrylicToWindow(window, GetBackground(window));
}
}
}
}
35 changes: 35 additions & 0 deletions EarTrumpet/UI/Views/FullWindow.xaml
Expand Up @@ -32,6 +32,41 @@
</Window.Resources>
<Grid>
<Border Name="AcrylicBackgroundActive" Theme:Brush.Background="AcrylicBackground" />
<Border Name="AcrylicBackgroundWhileDragging">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="Theme:Brush.Background" Value="AcrylicBackgroundFallback" />
<Setter Property="Opacity" Value="0" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=WindowRoot, Path=(Theme:AcrylicBrush.IsSuppressed)}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="IsSuppressed_Enter_AnimationsOn">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="0"
To="1"
Duration="00:00:00" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard Name="IsSuppressed_Exit_AnimationsOn">
<Storyboard>
<DoubleAnimationUsingKeyFrames BeginTime="0:0:0"
Storyboard.TargetProperty="Opacity"
Duration="0:00:00.25">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1" />
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="1" />
<EasingDoubleKeyFrame KeyTime="0:0:0.25" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
<Border Name="AcrylicBackgroundInactive">
<Border.Style>
<Style TargetType="{x:Type Border}">
Expand Down
43 changes: 39 additions & 4 deletions EarTrumpet/UI/Views/SettingsWindow.xaml
Expand Up @@ -140,10 +140,10 @@
<TextBlock VerticalAlignment="Center"
Style="{StaticResource BodyText}"
Text="© File-New-Project" />
<CheckBox Margin="12,24,12,-6"
HorizontalAlignment="Left"
Content="{x:Static resx:Resources.PrivacyCheckboxText}"
IsChecked="{Binding IsTelemetryEnabled, Mode=TwoWay}" />
<CheckBox Margin="12,24,12,-6"
HorizontalAlignment="Left"
Content="{x:Static resx:Resources.PrivacyCheckboxText}"
IsChecked="{Binding IsTelemetryEnabled, Mode=TwoWay}" />
<TextBlock Style="{StaticResource HyperlinkBlock}">
<Hyperlink Command="{Binding OpenPrivacyPolicyCommand}">
<Run Text="{x:Static resx:Resources.PrivacyPolicyText}" />
Expand Down Expand Up @@ -419,6 +419,41 @@
</Grid.ColumnDefinitions>

<Border Name="AcrylicBackgroundActive" Theme:Brush.Background="AcrylicBackground" />
<Border Name="AcrylicBackgroundWhileDragging">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="Theme:Brush.Background" Value="AcrylicBackgroundFallback" />
<Setter Property="Opacity" Value="0" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=WindowRoot, Path=(Theme:AcrylicBrush.IsSuppressed)}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="IsSuppressed_Enter_AnimationsOn">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="0"
To="1"
Duration="00:00:00" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard Name="IsSuppressed_Exit_AnimationsOn">
<Storyboard>
<DoubleAnimationUsingKeyFrames BeginTime="0:0:0"
Storyboard.TargetProperty="Opacity"
Duration="0:00:00.25">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1" />
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="1" />
<EasingDoubleKeyFrame KeyTime="0:0:0.25" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
<Border Name="AcrylicBackgroundInactive">
<Border.Style>
<Style TargetType="{x:Type Border}">
Expand Down
1 change: 0 additions & 1 deletion README.md
Expand Up @@ -43,7 +43,6 @@ Install EarTrumpet from the [Microsoft Store](https://www.microsoft.com/en-us/p/
## Known issues
- SoundCloud audio cannot be adjusted ([#178](https://github.com/File-New-Project/EarTrumpet/issues/178))
- Error: Windows cannot find "[...] EarTrumpet.exe". Make sure you typed the name correctly, and then try again ([#274](https://github.com/File-New-Project/EarTrumpet/issues/274))
- EarTrumpet windows move slowly on Windows 10 19H1+ ([#349](https://github.com/File-New-Project/EarTrumpet/issues/349))

## Credits
- David Golden ([@GoldenTao](https://www.twitter.com/GoldenTao))
Expand Down

0 comments on commit f369482

Please sign in to comment.