Browse Source

Merge pull request #11509 from AvaloniaUI/feature/transparency-hints-list

Make transparency levels a list.
pull/11572/head
Max Katz 3 years ago
committed by GitHub
parent
commit
b10251c531
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      samples/ControlCatalog/MainView.xaml.cs
  2. 2
      samples/IntegrationTestApp/MainWindow.axaml.cs
  3. 168
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  4. 4
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
  5. 22
      src/Avalonia.Controls/ExperimentalAcrylicBorder.cs
  6. 2
      src/Avalonia.Controls/Platform/ITopLevelImpl.cs
  7. 38
      src/Avalonia.Controls/TopLevel.cs
  8. 78
      src/Avalonia.Controls/WindowTransparencyLevel.cs
  9. 4
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  10. 46
      src/Avalonia.Native/WindowImplBase.cs
  11. 81
      src/Avalonia.X11/TransparencyHelper.cs
  12. 8
      src/Avalonia.X11/X11Window.cs
  13. 10
      src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs
  14. 2
      src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs
  15. 4
      src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
  16. 16
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs
  17. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  18. 4
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
  19. 7
      src/Windows/Avalonia.Win32/PlatformConstants.cs
  20. 2
      src/Windows/Avalonia.Win32/TrayIconImpl.cs
  21. 1
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs
  22. 268
      src/Windows/Avalonia.Win32/WindowImpl.cs
  23. 6
      src/iOS/Avalonia.iOS/AvaloniaView.cs
  24. 26
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/WindowTests.cs
  25. 4
      tests/Avalonia.UnitTests/CompositorTestServices.cs

5
samples/ControlCatalog/MainView.xaml.cs

@ -83,9 +83,10 @@ namespace ControlCatalog
if (transparencyLevels.SelectedItem is WindowTransparencyLevel selected)
{
var topLevel = (TopLevel)this.GetVisualRoot()!;
topLevel.TransparencyLevelHint = selected;
topLevel.TransparencyLevelHint = new[] { selected };
if (selected != WindowTransparencyLevel.None)
if (topLevel.ActualTransparencyLevel != WindowTransparencyLevel.None &&
topLevel.ActualTransparencyLevel == selected)
{
var transparentBrush = new ImmutableSolidColorBrush(Colors.White, 0);
var semiTransparentBrush = new ImmutableSolidColorBrush(Colors.Gray, 0.2);

2
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -136,7 +136,7 @@ namespace IntegrationTestApp
Name = "TransparentWindow",
SystemDecorations = SystemDecorations.None,
Background = Brushes.Transparent,
TransparencyLevelHint = WindowTransparencyLevel.Transparent,
TransparencyLevelHint = new[] { WindowTransparencyLevel.Transparent },
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Width = 200,
Height = 200,

168
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.Versioning;
using Android.App;
using Android.Content;
using Android.Graphics;
@ -45,6 +46,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
private readonly AndroidInsetsManager _insetsManager;
private readonly ClipboardImpl _clipboard;
private ViewImpl _view;
private WindowTransparencyLevel _transparencyLevel;
public TopLevelImpl(AvaloniaView avaloniaView, bool placeOnTop = false)
{
@ -68,6 +70,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_nativeControlHost = new AndroidNativeControlHostImpl(avaloniaView);
_storageProvider = new AndroidStorageProvider((Activity)avaloniaView.Context);
_transparencyLevel = WindowTransparencyLevel.None;
_systemNavigationManager = new AndroidSystemNavigationManagerImpl(avaloniaView.Context as IActivityNavigationService);
}
@ -273,7 +276,18 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public Action LostFocus { get; set; }
public Action<WindowTransparencyLevel> TransparencyLevelChanged { get; set; }
public WindowTransparencyLevel TransparencyLevel { get; private set; }
public WindowTransparencyLevel TransparencyLevel
{
get => _transparencyLevel;
private set
{
if (_transparencyLevel != value)
{
_transparencyLevel = value;
TransparencyLevelChanged?.Invoke(value);
}
}
}
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
{
@ -298,91 +312,64 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public double Scaling => RenderScaling;
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevels)
{
if (TransparencyLevel != transparencyLevel)
if (_view.Context is not AvaloniaMainActivity activity)
return;
foreach (var level in transparencyLevels)
{
bool isBelowR = Build.VERSION.SdkInt < BuildVersionCodes.R;
bool isAboveR = Build.VERSION.SdkInt > BuildVersionCodes.R;
if (_view.Context is AvaloniaMainActivity activity)
if (!IsSupported(level))
{
continue;
}
if (level == TransparencyLevel)
{
return;
}
if (level == WindowTransparencyLevel.None)
{
if (OperatingSystem.IsAndroidVersionAtLeast(30))
{
activity.SetTranslucent(false);
}
activity.Window?.SetBackgroundDrawable(new ColorDrawable(Color.White));
}
else if (level == WindowTransparencyLevel.Transparent)
{
if (OperatingSystem.IsAndroidVersionAtLeast(30))
{
activity.SetTranslucent(true);
SetBlurBehind(activity, 0);
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
}
}
else if (level == WindowTransparencyLevel.Blur)
{
switch (transparencyLevel)
if (OperatingSystem.IsAndroidVersionAtLeast(31))
{
case WindowTransparencyLevel.AcrylicBlur:
case WindowTransparencyLevel.ForceAcrylicBlur:
case WindowTransparencyLevel.Mica:
case WindowTransparencyLevel.None:
if (!isBelowR)
{
activity.SetTranslucent(false);
}
if (isAboveR)
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
var attr = activity.Window?.Attributes;
if (attr != null)
{
attr.BlurBehindRadius = 0;
activity.Window.Attributes = attr;
}
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.White));
if(transparencyLevel != WindowTransparencyLevel.None)
{
return;
}
break;
case WindowTransparencyLevel.Transparent:
if (!isBelowR)
{
activity.SetTranslucent(true);
}
if (isAboveR)
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
var attr = activity.Window?.Attributes;
if (attr != null)
{
attr.BlurBehindRadius = 0;
activity.Window.Attributes = attr;
}
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
break;
case WindowTransparencyLevel.Blur:
if (isAboveR)
{
activity.SetTranslucent(true);
activity.Window?.AddFlags(WindowManagerFlags.BlurBehind);
var attr = activity.Window?.Attributes;
if (attr != null)
{
attr.BlurBehindRadius = 120;
activity.Window.Attributes = attr;
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
}
else
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.White));
return;
}
break;
activity.SetTranslucent(true);
SetBlurBehind(activity, 120);
activity.Window?.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
}
TransparencyLevel = transparencyLevel;
}
TransparencyLevel = level;
return;
}
// If we get here, we didn't find a supported level. Use the default of None.
if (OperatingSystem.IsAndroidVersionAtLeast(30))
{
activity.SetTranslucent(false);
}
activity.Window?.SetBackgroundDrawable(new ColorDrawable(Color.White));
}
public virtual object TryGetFeature(Type featureType)
{
if (featureType == typeof(IStorageProvider))
@ -417,6 +404,31 @@ namespace Avalonia.Android.Platform.SkiaPlatform
return null;
}
private static bool IsSupported(WindowTransparencyLevel level)
{
if (level == WindowTransparencyLevel.None)
return true;
if (level == WindowTransparencyLevel.Transparent)
return OperatingSystem.IsAndroidVersionAtLeast(30);
if (level == WindowTransparencyLevel.Blur)
return OperatingSystem.IsAndroidVersionAtLeast(31);
return false;
}
private static void SetBlurBehind(AvaloniaMainActivity activity, int radius)
{
if (radius == 0)
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
else
activity.Window?.AddFlags(WindowManagerFlags.BlurBehind);
if (OperatingSystem.IsAndroidVersionAtLeast(31) && activity.Window?.Attributes is { } attr)
{
attr.BlurBehindRadius = radius;
activity.Window.Attributes = attr;
}
}
}
internal class AvaloniaInputConnection : BaseInputConnection

4
src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs

@ -93,9 +93,9 @@ namespace Avalonia.Controls.Embedding.Offscreen
public Action? LostFocus { get; set; }
public abstract IMouseDevice MouseDevice { get; }
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { }
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevel) { }
public WindowTransparencyLevel TransparencyLevel { get; private set; }
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
public IPopupImpl? CreatePopup() => null;

22
src/Avalonia.Controls/ExperimentalAcrylicBorder.cs

@ -56,22 +56,12 @@ namespace Avalonia.Controls
{
if (tl.PlatformImpl is null)
return;
switch (x)
{
case WindowTransparencyLevel.Transparent:
case WindowTransparencyLevel.None:
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.TransparentLevel;
break;
case WindowTransparencyLevel.Blur:
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.BlurLevel;
break;
case WindowTransparencyLevel.AcrylicBlur:
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.AcrylicBlurLevel;
break;
}
if (x == WindowTransparencyLevel.Transparent || x == WindowTransparencyLevel.None)
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.TransparentLevel;
else if (x == WindowTransparencyLevel.Blur)
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.BlurLevel;
else if (x == WindowTransparencyLevel.AcrylicBlur)
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.AcrylicBlurLevel;
});
UpdateMaterialSubscription();
}

2
src/Avalonia.Controls/Platform/ITopLevelImpl.cs

@ -117,7 +117,7 @@ namespace Avalonia.Platform
/// <summary>
/// Sets the <see cref="WindowTransparencyLevel"/> hint of the TopLevel.
/// </summary>
void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel);
void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevels);
/// <summary>
/// Gets the current <see cref="WindowTransparencyLevel"/> of the TopLevel.

38
src/Avalonia.Controls/TopLevel.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using Avalonia.Reactive;
@ -22,6 +23,7 @@ using Avalonia.Utilities;
using Avalonia.Input.Platform;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Metadata;
using Avalonia.Rendering.Composition;
namespace Avalonia.Controls
@ -65,8 +67,8 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="TransparencyLevelHint"/> property.
/// </summary>
public static readonly StyledProperty<WindowTransparencyLevel> TransparencyLevelHintProperty =
AvaloniaProperty.Register<TopLevel, WindowTransparencyLevel>(nameof(TransparencyLevelHint), WindowTransparencyLevel.None);
public static readonly StyledProperty<IReadOnlyList<WindowTransparencyLevel>> TransparencyLevelHintProperty =
AvaloniaProperty.Register<TopLevel, IReadOnlyList<WindowTransparencyLevel>>(nameof(TransparencyLevelHint), Array.Empty<WindowTransparencyLevel>());
/// <summary>
/// Defines the <see cref="ActualTransparencyLevel"/> property.
@ -173,7 +175,7 @@ namespace Avalonia.Controls
PlatformImpl = impl ?? throw new InvalidOperationException(
"Could not create window implementation: maybe no windowing subsystem was initialized?");
_actualTransparencyLevel = PlatformImpl.TransparencyLevel;
_actualTransparencyLevel = PlatformImpl.TransparencyLevel;
dependencyResolver ??= AvaloniaLocator.Current;
@ -311,8 +313,11 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets the <see cref="WindowTransparencyLevel"/> that the TopLevel should use when possible.
/// Accepts multiple values which are applied in a fallback order.
/// For instance, with "Mica, Blur" Mica will be applied only on platforms where it is possible,
/// and Blur will be used on the rest of them. Default value is an empty array or "None".
/// </summary>
public WindowTransparencyLevel TransparencyLevelHint
public IReadOnlyList<WindowTransparencyLevel> TransparencyLevelHint
{
get { return GetValue(TransparencyLevelHintProperty); }
set { SetValue(TransparencyLevelHintProperty, value); }
@ -536,8 +541,8 @@ namespace Avalonia.Controls
{
if (PlatformImpl != null)
{
PlatformImpl.SetTransparencyLevelHint(change.GetNewValue<WindowTransparencyLevel>());
HandleTransparencyLevelChanged(PlatformImpl.TransparencyLevel);
PlatformImpl.SetTransparencyLevelHint(
change.GetNewValue<IReadOnlyList<WindowTransparencyLevel>>() ?? Array.Empty<WindowTransparencyLevel>());
}
}
else if (change.Property == ActualThemeVariantProperty)
@ -632,27 +637,11 @@ namespace Avalonia.Controls
ScalingChanged?.Invoke(this, EventArgs.Empty);
}
private static bool TransparencyLevelsMatch (WindowTransparencyLevel requested, WindowTransparencyLevel received)
{
if(requested == received)
{
return true;
}
else if(requested >= WindowTransparencyLevel.Blur && received >= WindowTransparencyLevel.Blur)
{
return true;
}
return false;
}
private void HandleTransparencyLevelChanged(WindowTransparencyLevel transparencyLevel)
{
if(_transparencyFallbackBorder != null)
if (_transparencyFallbackBorder != null)
{
if(transparencyLevel == WindowTransparencyLevel.None ||
TransparencyLevelHint == WindowTransparencyLevel.None ||
!TransparencyLevelsMatch(TransparencyLevelHint, transparencyLevel))
if (transparencyLevel == WindowTransparencyLevel.None)
{
_transparencyFallbackBorder.Background = TransparencyBackgroundFallback;
}
@ -682,7 +671,6 @@ namespace Avalonia.Controls
return;
_transparencyFallbackBorder = e.NameScope.Find<Border>("PART_TransparencyFallback");
HandleTransparencyLevelChanged(PlatformImpl.TransparencyLevel);
}

78
src/Avalonia.Controls/WindowTransparencyLevel.cs

@ -1,35 +1,51 @@
namespace Avalonia.Controls
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Avalonia.Controls;
public readonly record struct WindowTransparencyLevel
{
public enum WindowTransparencyLevel
private readonly string _value;
private WindowTransparencyLevel(string value)
{
/// <summary>
/// The window background is Black where nothing is drawn in the window.
/// </summary>
None,
/// <summary>
/// The window background is Transparent where nothing is drawn in the window.
/// </summary>
Transparent,
/// <summary>
/// The window background is a blur-behind where nothing is drawn in the window.
/// </summary>
Blur,
/// <summary>
/// The window background is a blur-behind with a high blur radius. This level may fallback to Blur.
/// </summary>
AcrylicBlur,
/// <summary>
/// Force acrylic on some incompatible versions of Windows 10.
/// </summary>
ForceAcrylicBlur,
/// <summary>
/// The window background is based on desktop wallpaper tint with a blur. This will only work on Windows 11
/// </summary>
Mica
_value = value;
}
/// <summary>
/// The window background is Black where nothing is drawn in the window.
/// </summary>
public static WindowTransparencyLevel None { get; } = new(nameof(None));
/// <summary>
/// The window background is Transparent where nothing is drawn in the window.
/// </summary>
public static WindowTransparencyLevel Transparent { get; } = new(nameof(Transparent));
/// <summary>
/// The window background is a blur-behind where nothing is drawn in the window.
/// </summary>
public static WindowTransparencyLevel Blur { get; } = new(nameof(Blur));
/// <summary>
/// The window background is a blur-behind with a high blur radius. This level may fallback to Blur.
/// </summary>
public static WindowTransparencyLevel AcrylicBlur { get; } = new(nameof(AcrylicBlur));
/// <summary>
/// The window background is based on desktop wallpaper tint with a blur. This will only work on Windows 11
/// </summary>
public static WindowTransparencyLevel Mica { get; } = new(nameof(Mica));
public override string ToString()
{
return _value;
}
}
public class WindowTransparencyLevelCollection : ReadOnlyCollection<WindowTransparencyLevel>
{
public WindowTransparencyLevelCollection(IList<WindowTransparencyLevel> list) : base(list)
{
}
}

4
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@ -177,13 +177,13 @@ namespace Avalonia.DesignerSupport.Remote
public Action GotInputWhenDisabled { get; set; }
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { }
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevel) { }
public void SetWindowManagerAddShadowHint(bool enabled)
{
}
public WindowTransparencyLevel TransparencyLevel { get; private set; }
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
public bool IsClientAreaExtendedToDecorations { get; }

46
src/Avalonia.Native/WindowImplBase.cs

@ -65,6 +65,7 @@ namespace Avalonia.Native
private NativeControlHostImpl _nativeControlHost;
private IStorageProvider _storageProvider;
private PlatformBehaviorInhibition _platformBehaviorInhibition;
private WindowTransparencyLevel _transparencyLevel = WindowTransparencyLevel.None;
internal WindowBaseImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts,
AvaloniaNativeGlPlatformGraphics glFeature)
@ -479,26 +480,47 @@ namespace Avalonia.Native
_native?.BeginDragAndDropOperation(effects, point, clipboard, callback, sourceHandle);
}
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevels)
{
if (TransparencyLevel != transparencyLevel)
foreach (var level in transparencyLevels)
{
if (transparencyLevel > WindowTransparencyLevel.Transparent)
transparencyLevel = WindowTransparencyLevel.AcrylicBlur;
AvnWindowTransparencyMode? mode = null;
TransparencyLevel = transparencyLevel;
if (level == WindowTransparencyLevel.None)
mode = AvnWindowTransparencyMode.Opaque;
if (level == WindowTransparencyLevel.Transparent)
mode = AvnWindowTransparencyMode.Transparent;
else if (level == WindowTransparencyLevel.AcrylicBlur)
mode = AvnWindowTransparencyMode.Blur;
_native.SetTransparencyMode(transparencyLevel == WindowTransparencyLevel.None
? AvnWindowTransparencyMode.Opaque
: transparencyLevel == WindowTransparencyLevel.Transparent
? AvnWindowTransparencyMode.Transparent
: AvnWindowTransparencyMode.Blur);
if (mode.HasValue && level != TransparencyLevel)
{
_native?.SetTransparencyMode(mode.Value);
TransparencyLevel = level;
return;
}
}
TransparencyLevelChanged?.Invoke(TransparencyLevel);
// If we get here, we didn't find a supported level. Use the default of None.
if (TransparencyLevel != WindowTransparencyLevel.None)
{
_native?.SetTransparencyMode(AvnWindowTransparencyMode.Opaque);
TransparencyLevel = WindowTransparencyLevel.None;
}
}
public WindowTransparencyLevel TransparencyLevel { get; private set; } = WindowTransparencyLevel.None;
public WindowTransparencyLevel TransparencyLevel
{
get => _transparencyLevel;
private set
{
if (_transparencyLevel != value)
{
_transparencyLevel = value;
TransparencyLevelChanged?.Invoke(value);
}
}
}
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
{

81
src/Avalonia.X11/TransparencyHelper.cs

@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using Avalonia.Controls;
#nullable enable
namespace Avalonia.X11
{
internal class TransparencyHelper : IDisposable, X11Globals.IGlobalsSubscriber
@ -9,11 +12,23 @@ namespace Avalonia.X11
private readonly IntPtr _window;
private readonly X11Globals _globals;
private WindowTransparencyLevel _currentLevel;
private WindowTransparencyLevel _requestedLevel;
private IReadOnlyList<WindowTransparencyLevel>? _requestedLevels;
private bool _blurAtomsAreSet;
public Action<WindowTransparencyLevel> TransparencyLevelChanged { get; set; }
public WindowTransparencyLevel CurrentLevel => _currentLevel;
public Action<WindowTransparencyLevel>? TransparencyLevelChanged { get; set; }
public WindowTransparencyLevel CurrentLevel
{
get => _currentLevel;
set
{
if (_currentLevel != value)
{
_currentLevel = value;
TransparencyLevelChanged?.Invoke(value);
}
}
}
public TransparencyHelper(X11Info x11, IntPtr window, X11Globals globals)
{
@ -23,25 +38,53 @@ namespace Avalonia.X11
_globals.AddSubscriber(this);
}
public void SetTransparencyRequest(WindowTransparencyLevel level)
public void SetTransparencyRequest(IReadOnlyList<WindowTransparencyLevel> levels)
{
_requestedLevels = levels;
foreach (var level in levels)
{
if (!IsSupported(level))
continue;
SetBlur(level == WindowTransparencyLevel.Blur);
CurrentLevel = level;
return;
}
// If we get here, we didn't find a supported level. Use the defualt of Transparent or
// None, depending on whether composition is enabled.
SetBlur(false);
CurrentLevel = _globals.IsCompositionEnabled ?
WindowTransparencyLevel.Transparent :
WindowTransparencyLevel.None;
}
private bool IsSupported(WindowTransparencyLevel level)
{
_requestedLevel = level;
UpdateTransparency();
// None is suppported when composition is disabled.
if (level == WindowTransparencyLevel.None)
return !_globals.IsCompositionEnabled;
// Transparent is suppported when composition is enabled.
if (level == WindowTransparencyLevel.Transparent)
return _globals.IsCompositionEnabled;
// Blur is supported when composition is enabled and KWin is used.
if (level == WindowTransparencyLevel.Blur)
return _globals.IsCompositionEnabled && _globals.WmName == "KWin";
return false;
}
private void UpdateTransparency()
{
var newLevel = UpdateAtomsAndGetTransparency();
if (newLevel != _currentLevel)
{
_currentLevel = newLevel;
TransparencyLevelChanged?.Invoke(newLevel);
}
SetTransparencyRequest(_requestedLevels ?? Array.Empty<WindowTransparencyLevel>());
}
private WindowTransparencyLevel UpdateAtomsAndGetTransparency()
private void SetBlur(bool blur)
{
if (_requestedLevel >= WindowTransparencyLevel.Blur)
if (blur)
{
if (!_blurAtomsAreSet)
{
@ -59,15 +102,7 @@ namespace Avalonia.X11
_blurAtomsAreSet = false;
}
}
if (!_globals.IsCompositionEnabled)
return WindowTransparencyLevel.None;
if (_requestedLevel >= WindowTransparencyLevel.Blur && CanBlur)
return WindowTransparencyLevel.Blur;
return WindowTransparencyLevel.Transparent;
}
private bool CanBlur => _globals.WmName == "KWin" && _globals.IsCompositionEnabled;
public void Dispose()
{

8
src/Avalonia.X11/X11Window.cs

@ -196,7 +196,7 @@ namespace Avalonia.X11
_rawEventGrouper = new RawEventGrouper(DispatchInput, platform.EventGrouperDispatchQueue);
_transparencyHelper = new TransparencyHelper(_x11, _handle, platform.Globals);
_transparencyHelper.SetTransparencyRequest(WindowTransparencyLevel.None);
_transparencyHelper.SetTransparencyRequest(Array.Empty<WindowTransparencyLevel>());
CreateIC();
@ -1306,8 +1306,10 @@ namespace Avalonia.X11
public IPopupPositioner? PopupPositioner { get; }
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) =>
_transparencyHelper?.SetTransparencyRequest(transparencyLevel);
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevels)
{
_transparencyHelper?.SetTransparencyRequest(transparencyLevels);
}
public void SetWindowManagerAddShadowHint(bool enabled)
{

10
src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs

@ -39,7 +39,6 @@ namespace Avalonia.Browser
{
Surfaces = Enumerable.Empty<object>();
_avaloniaView = avaloniaView;
TransparencyLevel = WindowTransparencyLevel.None;
AcrylicCompensationLevels = new AcrylicPlatformCompensationLevels(1, 1, 1);
_touchDevice = new TouchDevice();
_penDevice = new PenDevice();
@ -218,13 +217,8 @@ namespace Avalonia.Browser
return null;
}
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevel)
{
if (transparencyLevel == WindowTransparencyLevel.None
|| transparencyLevel == WindowTransparencyLevel.Transparent)
{
TransparencyLevel = transparencyLevel;
}
}
public Size ClientSize => _clientSize;
@ -244,7 +238,7 @@ namespace Avalonia.Browser
public IMouseDevice MouseDevice { get; } = new MouseDevice();
public IKeyboardDevice KeyboardDevice { get; } = BrowserWindowingPlatform.Keyboard;
public WindowTransparencyLevel TransparencyLevel { get; private set; }
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
{
// not in the standard, but we potentially can use "apple-mobile-web-app-status-bar-style" for iOS and "theme-color" for android.

2
src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs

@ -336,7 +336,7 @@ namespace Avalonia.Headless
}
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevel)
{
}

4
src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs

@ -72,9 +72,9 @@ using Avalonia.Rendering.Composition;
public Size ScaledSize => _outputBackend.PixelSize.ToSize(RenderScaling);
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { }
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevel) { }
public WindowTransparencyLevel TransparencyLevel { get; private set; }
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { }

16
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs

@ -274,6 +274,19 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
}
}
if (type.Equals(types.WindowTransparencyLevel))
{
foreach (var property in types.WindowTransparencyLevel.Properties)
{
if (property.PropertyType == types.WindowTransparencyLevel && property.Name.Equals(text, StringComparison.OrdinalIgnoreCase))
{
result = new XamlStaticOrTargetedReturnMethodCallNode(node, property.Getter, Enumerable.Empty<IXamlAstValueNode>());
return true;
}
}
}
if (type.Equals(types.Uri))
{
var uriText = text.Trim();
@ -385,7 +398,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
result = new AvaloniaXamlIlArrayConstantAstNode(node, elementType.MakeArrayType(1), elementType, nodes);
return true;
}
else if (type == context.Configuration.WellKnownTypes.IListOfT.MakeGenericType(elementType))
else if (type == context.Configuration.WellKnownTypes.IListOfT.MakeGenericType(elementType) ||
type == types.IReadOnlyListOfT.MakeGenericType(elementType))
{
var listType = context.Configuration.WellKnownTypes.IListOfT.MakeGenericType(elementType);
result = new AvaloniaXamlIlArrayConstantAstNode(node, listType, elementType, nodes);

4
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

@ -117,6 +117,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlConstructor UriConstructor { get; }
public IXamlType Style { get; }
public IXamlType ControlTheme { get; }
public IXamlType WindowTransparencyLevel { get; }
public IXamlType IReadOnlyListOfT { get; }
public AvaloniaXamlIlWellKnownTypes(TransformerConfiguration cfg)
{
@ -199,6 +201,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
FontFamily = cfg.TypeSystem.GetType("Avalonia.Media.FontFamily");
FontFamilyConstructorUriName = FontFamily.GetConstructor(new List<IXamlType> { Uri, XamlIlTypes.String });
ThemeVariant = cfg.TypeSystem.GetType("Avalonia.Styling.ThemeVariant");
WindowTransparencyLevel = cfg.TypeSystem.GetType("Avalonia.Controls.WindowTransparencyLevel");
(IXamlType, IXamlConstructor) GetNumericTypeInfo(string name, IXamlType componentType, int componentCount)
{
@ -260,6 +263,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
UriConstructor = Uri.GetConstructor(new List<IXamlType>() { cfg.WellKnownTypes.String, UriKind });
Style = cfg.TypeSystem.GetType("Avalonia.Styling.Style");
ControlTheme = cfg.TypeSystem.GetType("Avalonia.Styling.ControlTheme");
IReadOnlyListOfT = cfg.TypeSystem.GetType("System.Collections.Generic.IReadOnlyList`1");
}
}

4
src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs

@ -241,9 +241,9 @@ namespace Avalonia.Win32.Interop.Wpf
public IPopupImpl CreatePopup() => null;
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { }
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevel) { }
public WindowTransparencyLevel TransparencyLevel { get; private set; }
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { }

7
src/Windows/Avalonia.Win32/PlatformConstants.cs

@ -2,12 +2,13 @@ using System;
namespace Avalonia.Win32
{
public static class PlatformConstants
internal static class PlatformConstants
{
public const string WindowHandleType = "HWND";
public const string CursorHandleType = "HCURSOR";
internal static readonly Version Windows8 = new Version(6, 2);
internal static readonly Version Windows7 = new Version(6, 1);
public static readonly Version Windows10 = new Version(10, 0);
public static readonly Version Windows8 = new Version(6, 2);
public static readonly Version Windows7 = new Version(6, 1);
}
}

2
src/Windows/Avalonia.Win32/TrayIconImpl.cs

@ -147,7 +147,7 @@ namespace Avalonia.Win32
SystemDecorations = SystemDecorations.None,
SizeToContent = SizeToContent.WidthAndHeight,
Background = null,
TransparencyLevelHint = WindowTransparencyLevel.Transparent,
TransparencyLevelHint = new[] { WindowTransparencyLevel.Transparent },
Content = new TrayIconMenuFlyoutPresenter()
{
ItemsSource = menuItems

1
src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs

@ -12,6 +12,7 @@ internal class WinUiCompositionShared : IDisposable
public ICompositionBrush? MicaBrush { get; }
public object SyncRoot { get; } = new();
public static readonly Version MinAcrylicVersion = new(10, 0, 15063);
public static readonly Version MinHostBackdropVersion = new(10, 0, 22000);
public WinUiCompositionShared(ICompositor compositor)

268
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
@ -25,6 +25,7 @@ using Avalonia.Win32.WinRT.Composition;
using Avalonia.Win32.WinRT;
using static Avalonia.Win32.Interop.UnmanagedMethods;
using Avalonia.Input.Platform;
using System.Diagnostics;
namespace Avalonia.Win32
{
@ -98,6 +99,7 @@ namespace Avalonia.Win32
private bool _hiddenWindowIsParent;
private uint _langid;
private bool _ignoreWmChar;
private WindowTransparencyLevel _transparencyLevel;
private const int MaxPointerHistorySize = 512;
private static readonly PooledList<RawPointerPoint> s_intermediatePointsPooledList = new();
@ -182,6 +184,7 @@ namespace Avalonia.Win32
_storageProvider = new Win32StorageProvider(this);
_nativeControlHost = new Win32NativeControlHost(this, _isUsingComposition);
_transparencyLevel = _isUsingComposition ? WindowTransparencyLevel.Transparent : WindowTransparencyLevel.None;
s_instances.Add(this);
}
@ -315,7 +318,18 @@ namespace Avalonia.Win32
}
}
public WindowTransparencyLevel TransparencyLevel { get; private set; }
public WindowTransparencyLevel TransparencyLevel
{
get => _transparencyLevel;
private set
{
if (_transparencyLevel != value)
{
_transparencyLevel = value;
TransparencyLevelChanged?.Invoke(value);
}
}
}
protected IntPtr Hwnd => _hwnd;
@ -346,82 +360,132 @@ namespace Avalonia.Win32
return null;
}
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevels)
{
TransparencyLevel = EnableBlur(transparencyLevel);
}
var windowsVersion = Win32Platform.WindowsVersion;
foreach (var level in transparencyLevels)
{
if (!IsSupported(level, windowsVersion))
continue;
if (level == TransparencyLevel)
return;
if (level == WindowTransparencyLevel.Transparent)
SetTransparencyTransparent(windowsVersion);
else if (level == WindowTransparencyLevel.Blur)
SetTransparencyBlur(windowsVersion);
else if (level == WindowTransparencyLevel.AcrylicBlur)
SetTransparencyAcrylicBlur(windowsVersion);
else if (level == WindowTransparencyLevel.Mica)
SetTransparencyMica(windowsVersion);
TransparencyLevel = level;
return;
}
private WindowTransparencyLevel EnableBlur(WindowTransparencyLevel transparencyLevel)
{
if (Win32Platform.WindowsVersion.Major >= 6)
// If we get here, we didn't find a supported level. Use the defualt of Transparent or
// None, depending on whether composition is enabled.
if (_isUsingComposition)
{
if (DwmIsCompositionEnabled(out var compositionEnabled) != 0 || !compositionEnabled)
{
return WindowTransparencyLevel.None;
}
else if (Win32Platform.WindowsVersion.Major >= 10)
{
return Win10EnableBlur(transparencyLevel);
}
else if (Win32Platform.WindowsVersion.Minor >= 2)
{
return Win8xEnableBlur(transparencyLevel);
}
else
{
return Win7EnableBlur(transparencyLevel);
}
SetTransparencyTransparent(windowsVersion);
TransparencyLevel = WindowTransparencyLevel.Transparent;
}
else
{
return WindowTransparencyLevel.None;
TransparencyLevel = WindowTransparencyLevel.None;
}
}
private WindowTransparencyLevel Win7EnableBlur(WindowTransparencyLevel transparencyLevel)
private bool IsSupported(WindowTransparencyLevel level, Version windowsVersion)
{
if (transparencyLevel == WindowTransparencyLevel.AcrylicBlur)
{
transparencyLevel = WindowTransparencyLevel.Blur;
}
// Only None is suppported when composition is disabled.
if (!_isUsingComposition)
return level == WindowTransparencyLevel.None;
var blurInfo = new DWM_BLURBEHIND(false);
// When composition is enabled, None is not supported because the backing visual always
// has an alpha channel
if (level == WindowTransparencyLevel.None)
return false;
if (transparencyLevel == WindowTransparencyLevel.Blur)
// Transparent only supported on Windows 8+.
if (level == WindowTransparencyLevel.Transparent)
return windowsVersion >= PlatformConstants.Windows8;
// Blur only supported on Windows 8 and lower.
if (level == WindowTransparencyLevel.Blur)
return windowsVersion < PlatformConstants.Windows10;
// Acrylic is supported on Windows >= 10.0.15063.
if (level == WindowTransparencyLevel.AcrylicBlur)
return windowsVersion >= WinUiCompositionShared.MinAcrylicVersion;
// Mica is supported on Windows >= 10.0.22000.
if (level == WindowTransparencyLevel.Mica)
return windowsVersion >= WinUiCompositionShared.MinHostBackdropVersion;
return false;
}
private void SetTransparencyTransparent(Version windowsVersion)
{
// Transparent only supported with composition on Windows 8+.
if (!_isUsingComposition || windowsVersion < PlatformConstants.Windows8)
return;
if (windowsVersion < PlatformConstants.Windows10)
{
blurInfo = new DWM_BLURBEHIND(true);
// Some of the AccentState Enum's values have different meanings on Windows 8.x than on
// Windows 10, hence using ACCENT_ENABLE_BLURBEHIND to disable blurbehind ¯\_(ツ)_/¯.
// Hey, I'm just porting what was here before.
SetAccentState(AccentState.ACCENT_ENABLE_BLURBEHIND);
var blurInfo = new DWM_BLURBEHIND(false);
DwmEnableBlurBehindWindow(_hwnd, ref blurInfo);
}
SetUseHostBackdropBrush(false);
_blurHost?.SetBlur(BlurEffect.None);
}
private void SetTransparencyBlur(Version windowsVersion)
{
// Blur only supported with composition on Windows 8 and lower.
if (!_isUsingComposition || windowsVersion >= PlatformConstants.Windows10)
return;
// Some of the AccentState Enum's values have different meanings on Windows 8.x than on
// Windows 10.
SetAccentState(AccentState.ACCENT_DISABLED);
var blurInfo = new DWM_BLURBEHIND(true);
DwmEnableBlurBehindWindow(_hwnd, ref blurInfo);
}
if (transparencyLevel == WindowTransparencyLevel.Transparent)
{
return WindowTransparencyLevel.None;
}
else
{
return transparencyLevel;
}
private void SetTransparencyAcrylicBlur(Version windowsVersion)
{
// Acrylic blur only supported with composition on Windows >= 10.0.15063.
if (!_isUsingComposition || windowsVersion < WinUiCompositionShared.MinAcrylicVersion)
return;
SetUseHostBackdropBrush(true);
_blurHost?.SetBlur(BlurEffect.Acrylic);
}
private WindowTransparencyLevel Win8xEnableBlur(WindowTransparencyLevel transparencyLevel)
private void SetTransparencyMica(Version windowsVersion)
{
var accent = new AccentPolicy();
var accentStructSize = Marshal.SizeOf<AccentPolicy>();
// Mica only supported with composition on Windows >= 10.0.22000.
if (!_isUsingComposition || windowsVersion < WinUiCompositionShared.MinHostBackdropVersion)
return;
if (transparencyLevel == WindowTransparencyLevel.AcrylicBlur)
{
transparencyLevel = WindowTransparencyLevel.Blur;
}
SetUseHostBackdropBrush(false);
_blurHost?.SetBlur(BlurEffect.Mica);
}
if (transparencyLevel == WindowTransparencyLevel.Transparent)
{
accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;
}
else
{
accent.AccentState = AccentState.ACCENT_DISABLED;
}
private void SetAccentState(AccentState state)
{
var accent = new AccentPolicy();
var accentStructSize = Marshal.SizeOf(accent);
//Some of the AccentState Enum's values have different meanings on Windows 8.x than on Windows 10
accent.AccentState = state;
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
Marshal.StructureToPtr(accent, accentPtr, false);
@ -432,98 +496,18 @@ namespace Avalonia.Win32
data.Data = accentPtr;
SetWindowCompositionAttribute(_hwnd, ref data);
Marshal.FreeHGlobal(accentPtr);
if (transparencyLevel >= WindowTransparencyLevel.Blur)
{
Win7EnableBlur(transparencyLevel);
}
return transparencyLevel;
}
private WindowTransparencyLevel Win10EnableBlur(WindowTransparencyLevel transparencyLevel)
private void SetUseHostBackdropBrush(bool useHostBackdropBrush)
{
if (_isUsingComposition)
{
var effect = transparencyLevel switch
{
WindowTransparencyLevel.Mica => BlurEffect.Mica,
WindowTransparencyLevel.AcrylicBlur => BlurEffect.Acrylic,
WindowTransparencyLevel.Blur => BlurEffect.Acrylic,
_ => BlurEffect.None
};
if (Win32Platform.WindowsVersion >= WinUiCompositionShared.MinHostBackdropVersion)
{
unsafe
{
int pvUseBackdropBrush = effect == BlurEffect.Acrylic ? 1 : 0;
DwmSetWindowAttribute(_hwnd, (int)DwmWindowAttribute.DWMWA_USE_HOSTBACKDROPBRUSH, &pvUseBackdropBrush, sizeof(int));
}
}
if (Win32Platform.WindowsVersion < WinUiCompositionShared.MinHostBackdropVersion && effect == BlurEffect.Mica)
{
effect = BlurEffect.Acrylic;
}
_blurHost?.SetBlur(effect);
if (Win32Platform.WindowsVersion < WinUiCompositionShared.MinHostBackdropVersion)
return;
return transparencyLevel;
}
else
unsafe
{
bool canUseAcrylic = Win32Platform.WindowsVersion.Major > 10 || Win32Platform.WindowsVersion.Build >= 19628;
var accent = new AccentPolicy();
var accentStructSize = Marshal.SizeOf<AccentPolicy>();
if (transparencyLevel == WindowTransparencyLevel.AcrylicBlur && !canUseAcrylic)
{
transparencyLevel = WindowTransparencyLevel.Blur;
}
switch (transparencyLevel)
{
default:
case WindowTransparencyLevel.None:
accent.AccentState = AccentState.ACCENT_DISABLED;
break;
case WindowTransparencyLevel.Transparent:
accent.AccentState = AccentState.ACCENT_ENABLE_TRANSPARENTGRADIENT;
break;
case WindowTransparencyLevel.Blur:
accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;
break;
case WindowTransparencyLevel.AcrylicBlur:
case WindowTransparencyLevel.ForceAcrylicBlur: // hack-force acrylic.
case WindowTransparencyLevel.Mica:
accent.AccentState = AccentState.ACCENT_ENABLE_ACRYLIC;
transparencyLevel = WindowTransparencyLevel.AcrylicBlur;
break;
}
accent.AccentFlags = 2;
accent.GradientColor = 0x01000000;
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
Marshal.StructureToPtr(accent, accentPtr, false);
var data = new WindowCompositionAttributeData();
data.Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY;
data.SizeOfData = accentStructSize;
data.Data = accentPtr;
SetWindowCompositionAttribute(_hwnd, ref data);
Marshal.FreeHGlobal(accentPtr);
return transparencyLevel;
var pvUseBackdropBrush = useHostBackdropBrush ? 1 : 0;
DwmSetWindowAttribute(_hwnd, (int)DwmWindowAttribute.DWMWA_USE_HOSTBACKDROPBRUSH, &pvUseBackdropBrush, sizeof(int));
}
}

6
src/iOS/Avalonia.iOS/AvaloniaView.cs

@ -137,7 +137,7 @@ namespace Avalonia.iOS
return null;
}
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevel)
{
// No-op
}
@ -157,8 +157,8 @@ namespace Avalonia.iOS
// legacy no-op
public IMouseDevice MouseDevice { get; } = new MouseDevice();
public WindowTransparencyLevel TransparencyLevel { get; }
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
{
// TODO adjust status bar depending on full screen mode.

26
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/WindowTests.cs

@ -0,0 +1,26 @@
using Avalonia.Controls;
using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Markup.Xaml.UnitTests.Xaml
{
public class WindowTests : XamlTestBase
{
[Fact]
public void Can_Specify_TransparencyLevelHint()
{
using var app = UnitTestApplication.Start(TestServices.MockWindowingPlatform);
var xaml = @"<Window xmlns='https://github.com/avaloniaui' TransparencyLevelHint='Blur,Transparent,None'/>";
var target = AvaloniaRuntimeXamlLoader.Parse<Window>(xaml);
Assert.Equal(
new[]
{
WindowTransparencyLevel.Blur,
WindowTransparencyLevel.Transparent,
WindowTransparencyLevel.None,
}, target.TransparencyLevelHint);
}
}
}

4
tests/Avalonia.UnitTests/CompositorTestServices.cs

@ -186,11 +186,11 @@ public class CompositorTestServices : IDisposable
public IMouseDevice MouseDevice { get; } = new MouseDevice();
public IPopupImpl CreatePopup() => throw new NotImplementedException();
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevel)
{
}
public WindowTransparencyLevel TransparencyLevel { get; }
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
{

Loading…
Cancel
Save