diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs index a8016e2f0c..65c73b101a 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs @@ -1,4 +1,3 @@ -using System; using Avalonia.Controls; using Avalonia.Platform; @@ -16,4 +15,4 @@ namespace Avalonia.Web.Blazor UseWindowingSubsystem(BlazorWindowingPlatform.Register); } } -} \ No newline at end of file +} diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs index f6547fb108..ec3d665597 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs @@ -20,7 +20,7 @@ namespace Avalonia.Web.Blazor private SKHtmlCanvasInterop _interop = null!; private SizeWatcherInterop _sizeWatcher = null!; private DpiWatcherInterop _dpiWatcher = null!; - private SKHtmlCanvasInterop.GLInfo _jsGlInfo = null!; + private SKHtmlCanvasInterop.GLInfo? _jsGlInfo = null!; private InputHelperInterop _inputHelper = null!; private ElementReference _htmlCanvas; private ElementReference _inputElement; @@ -33,7 +33,7 @@ namespace Avalonia.Web.Blazor private bool _initialised; - [Inject] IJSRuntime Js { get; set; } = null!; + [Inject] private IJSRuntime Js { get; set; } = null!; public AvaloniaView() { diff --git a/src/Web/Avalonia.Web.Blazor/BlazorRuntimePlatform.cs b/src/Web/Avalonia.Web.Blazor/BlazorRuntimePlatform.cs index ecff76c5ea..9a5bf6b151 100644 --- a/src/Web/Avalonia.Web.Blazor/BlazorRuntimePlatform.cs +++ b/src/Web/Avalonia.Web.Blazor/BlazorRuntimePlatform.cs @@ -4,9 +4,10 @@ using Avalonia.Shared.PlatformSupport; namespace Avalonia.Web.Blazor { - class BlazorRuntimePlatform : IRuntimePlatform + internal class BlazorRuntimePlatform : IRuntimePlatform { - public static IRuntimePlatform Instance = new BlazorRuntimePlatform(); + public static readonly IRuntimePlatform Instance = new BlazorRuntimePlatform(); + public IDisposable StartSystemTimer(TimeSpan interval, Action tick) { return new Timer(_ => tick(), null, interval, interval); @@ -25,24 +26,24 @@ namespace Avalonia.Web.Blazor }; } - class BasicBlob : IUnmanagedBlob + private class BasicBlob : IUnmanagedBlob { - private IntPtr _data; public BasicBlob(int size) { - _data = Marshal.AllocHGlobal(size); + Address = Marshal.AllocHGlobal(size); Size = size; } public void Dispose() { - if (_data != IntPtr.Zero) - Marshal.FreeHGlobal(_data); - _data = IntPtr.Zero; + if (Address != IntPtr.Zero) + Marshal.FreeHGlobal(Address); + Address = IntPtr.Zero; } - public IntPtr Address => _data; + public IntPtr Address { get; private set; } + public int Size { get; } - public bool IsDisposed => _data == IntPtr.Zero; + public bool IsDisposed => Address == IntPtr.Zero; } public IUnmanagedBlob AllocBlob(int size) diff --git a/src/Web/Avalonia.Web.Blazor/BlazorSingleViewLifetime.cs b/src/Web/Avalonia.Web.Blazor/BlazorSingleViewLifetime.cs index 7eb5939011..85ac57c746 100644 --- a/src/Web/Avalonia.Web.Blazor/BlazorSingleViewLifetime.cs +++ b/src/Web/Avalonia.Web.Blazor/BlazorSingleViewLifetime.cs @@ -6,7 +6,7 @@ namespace Avalonia.Web.Blazor { public class BlazorSingleViewLifetime : ISingleViewApplicationLifetime { - public Control MainView { get; set; } + public Control? MainView { get; set; } } public static class WebAppBuilder diff --git a/src/Web/Avalonia.Web.Blazor/BlazorSkiaGpu.cs b/src/Web/Avalonia.Web.Blazor/BlazorSkiaGpu.cs index fe6873cba6..6fa7bf0bde 100644 --- a/src/Web/Avalonia.Web.Blazor/BlazorSkiaGpu.cs +++ b/src/Web/Avalonia.Web.Blazor/BlazorSkiaGpu.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using Avalonia.Skia; namespace Avalonia.Web.Blazor @@ -18,7 +17,7 @@ namespace Avalonia.Web.Blazor return null; } - public ISkiaSurface TryCreateSurface(PixelSize size, ISkiaGpuRenderSession session) + public ISkiaSurface? TryCreateSurface(PixelSize size, ISkiaGpuRenderSession session) { return null; } diff --git a/src/Web/Avalonia.Web.Blazor/BlazorSkiaSurface.cs b/src/Web/Avalonia.Web.Blazor/BlazorSkiaSurface.cs index 7631967493..512309cfe3 100644 --- a/src/Web/Avalonia.Web.Blazor/BlazorSkiaSurface.cs +++ b/src/Web/Avalonia.Web.Blazor/BlazorSkiaSurface.cs @@ -5,6 +5,16 @@ namespace Avalonia.Web.Blazor { internal class BlazorSkiaSurface { + public BlazorSkiaSurface(GRContext context, SKHtmlCanvasInterop.GLInfo glInfo, SKColorType colorType, PixelSize size, double scaling, GRSurfaceOrigin origin) + { + Context = context; + GlInfo = glInfo; + ColorType = colorType; + Size = size; + Scaling = scaling; + Origin = origin; + } + public SKColorType ColorType { get; set; } public PixelSize Size { get; set; } diff --git a/src/Web/Avalonia.Web.Blazor/CustomFontManagerImpl.cs b/src/Web/Avalonia.Web.Blazor/CustomFontManagerImpl.cs index dba49b1c50..01837bbcd4 100644 --- a/src/Web/Avalonia.Web.Blazor/CustomFontManagerImpl.cs +++ b/src/Web/Avalonia.Web.Blazor/CustomFontManagerImpl.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; -using System.Globalization; -using System.Linq; +using System.Globalization; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Skia; @@ -34,8 +32,6 @@ namespace Avalonia.Web.Blazor return _customTypefaces.Select(x => x.FontFamily.Name); } - private readonly string[] _bcp47 = { CultureInfo.CurrentCulture.ThreeLetterISOLanguageName, CultureInfo.CurrentCulture.TwoLetterISOLanguageName }; - public bool TryMatchCharacter(int codepoint, FontStyle fontStyle, FontWeight fontWeight, FontFamily fontFamily, CultureInfo culture, out Typeface typeface) { diff --git a/src/Web/Avalonia.Web.Blazor/ExampleJsInterop.cs b/src/Web/Avalonia.Web.Blazor/ExampleJsInterop.cs deleted file mode 100644 index 4136afc843..0000000000 --- a/src/Web/Avalonia.Web.Blazor/ExampleJsInterop.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Microsoft.JSInterop; - -namespace Avalonia.Web.Blazor -{ - // This class provides an example of how JavaScript functionality can be wrapped - // in a .NET class for easy consumption. The associated JavaScript module is - // loaded on demand when first needed. - // - // This class can be registered as scoped DI service and then injected into Blazor - // components for use. - - public class ExampleJsInterop : IAsyncDisposable - { - private readonly Lazy> moduleTask; - - public ExampleJsInterop(IJSRuntime jsRuntime) - { - moduleTask = new(() => jsRuntime.InvokeAsync( - "import", "./_content//exampleJsInterop.js").AsTask()); - } - - public async ValueTask Prompt(string message) - { - var module = await moduleTask.Value; - return await module.InvokeAsync("showPrompt", message); - } - - public async ValueTask DisposeAsync() - { - if (moduleTask.IsValueCreated) - { - var module = await moduleTask.Value; - await module.DisposeAsync(); - } - } - } -} \ No newline at end of file diff --git a/src/Web/Avalonia.Web.Blazor/Keycodes.cs b/src/Web/Avalonia.Web.Blazor/Keycodes.cs index 00e7a4b7fa..ea30f0a9f0 100644 --- a/src/Web/Avalonia.Web.Blazor/Keycodes.cs +++ b/src/Web/Avalonia.Web.Blazor/Keycodes.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using Avalonia.Input; namespace Avalonia.Web.Blazor diff --git a/src/Web/Avalonia.Web.Blazor/ManualTriggerRenderTimer.cs b/src/Web/Avalonia.Web.Blazor/ManualTriggerRenderTimer.cs index 03e79d6423..1a06d47744 100644 --- a/src/Web/Avalonia.Web.Blazor/ManualTriggerRenderTimer.cs +++ b/src/Web/Avalonia.Web.Blazor/ManualTriggerRenderTimer.cs @@ -1,4 +1,3 @@ -using System; using System.Diagnostics; using Avalonia.Rendering; @@ -6,12 +5,12 @@ namespace Avalonia.Web.Blazor { public class ManualTriggerRenderTimer : IRenderTimer { - private static readonly Stopwatch _sw = Stopwatch.StartNew(); + private static readonly Stopwatch s_sw = Stopwatch.StartNew(); - public static ManualTriggerRenderTimer Instance { get; } = new ManualTriggerRenderTimer(); + public static ManualTriggerRenderTimer Instance { get; } = new(); - public void RaiseTick() => Tick?.Invoke(_sw.Elapsed); + public void RaiseTick() => Tick?.Invoke(s_sw.Elapsed); - public event Action Tick; + public event Action? Tick; } -} \ No newline at end of file +} diff --git a/src/Web/Avalonia.Web.Blazor/RazorViewTopLevelImpl.cs b/src/Web/Avalonia.Web.Blazor/RazorViewTopLevelImpl.cs index 04afe150b6..8cd4d7b111 100644 --- a/src/Web/Avalonia.Web.Blazor/RazorViewTopLevelImpl.cs +++ b/src/Web/Avalonia.Web.Blazor/RazorViewTopLevelImpl.cs @@ -9,6 +9,8 @@ using Avalonia.Rendering; using Avalonia.Web.Blazor.Interop; using SkiaSharp; +#nullable enable + namespace Avalonia.Web.Blazor { internal class RazorViewTopLevelImpl : ITopLevelImplWithTextInputMethod @@ -16,13 +18,15 @@ namespace Avalonia.Web.Blazor private Size _clientSize; private BlazorSkiaSurface? _currentSurface; private IInputRoot? _inputRoot; - private Stopwatch _sw = Stopwatch.StartNew(); + private readonly Stopwatch _sw = Stopwatch.StartNew(); private readonly ITextInputMethodImpl _textInputMethod; private readonly TouchDevice _touchDevice; public RazorViewTopLevelImpl(ITextInputMethodImpl textInputMethod) { _textInputMethod = textInputMethod; + TransparencyLevel = WindowTransparencyLevel.None; + AcrylicCompensationLevels = new AcrylicPlatformCompensationLevels(1, 1, 1); _touchDevice = new TouchDevice(); } @@ -31,15 +35,8 @@ namespace Avalonia.Web.Blazor internal void SetSurface(GRContext context, SKHtmlCanvasInterop.GLInfo glInfo, SKColorType colorType, PixelSize size, double scaling) { - _currentSurface = new BlazorSkiaSurface - { - Context = context, - GlInfo = glInfo, - ColorType = colorType, - Size = size, - Scaling = scaling, - Origin = GRSurfaceOrigin.BottomLeft - }; + _currentSurface = + new BlazorSkiaSurface(context, glInfo, colorType, size, scaling, GRSurfaceOrigin.BottomLeft); } public void SetClientSize(SKSize size, double dpi) @@ -63,7 +60,7 @@ namespace Avalonia.Web.Blazor { if (_inputRoot is { }) { - Input.Invoke(new RawTouchEventArgs(_touchDevice, Timestamp, _inputRoot, type, p, modifiers, touchPointId)); + Input?.Invoke(new RawTouchEventArgs(_touchDevice, Timestamp, _inputRoot, type, p, modifiers, touchPointId)); } } @@ -102,8 +99,6 @@ namespace Avalonia.Web.Blazor } } - - public void Dispose() { @@ -136,7 +131,7 @@ namespace Avalonia.Web.Blazor } - public IPopupImpl CreatePopup() + public IPopupImpl? CreatePopup() { return null; } @@ -150,17 +145,15 @@ namespace Avalonia.Web.Blazor public Size? FrameSize => null; public double RenderScaling => 1; - public IEnumerable Surfaces => new[] { _currentSurface }; - - internal BlazorSkiaSurface Surface => _currentSurface; + public IEnumerable Surfaces => new object[] { _currentSurface! }; - public Action Input { get; set; } - public Action Paint { get; set; } - public Action Resized { get; set; } - public Action ScalingChanged { get; set; } - public Action TransparencyLevelChanged { get; set; } - public Action Closed { get; set; } - public Action LostFocus { get; set; } + public Action? Input { get; set; } + public Action? Paint { get; set; } + public Action? Resized { get; set; } + public Action? ScalingChanged { get; set; } + public Action? TransparencyLevelChanged { get; set; } + public Action? Closed { get; set; } + public Action? LostFocus { get; set; } public IMouseDevice MouseDevice { get; } = new MouseDevice(); public IKeyboardDevice KeyboardDevice { get; } = BlazorWindowingPlatform.Keyboard; diff --git a/src/Web/Avalonia.Web.Blazor/WinStubs.cs b/src/Web/Avalonia.Web.Blazor/WinStubs.cs index 5b38484d48..13d83a9ee3 100644 --- a/src/Web/Avalonia.Web.Blazor/WinStubs.cs +++ b/src/Web/Avalonia.Web.Blazor/WinStubs.cs @@ -1,17 +1,14 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.Platform; using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.Platform; +#nullable enable + namespace Avalonia.Web.Blazor { - class ClipboardStub : IClipboard + internal class ClipboardStub : IClipboard { public Task GetTextAsync() => Task.FromResult(""); @@ -23,10 +20,10 @@ namespace Avalonia.Web.Blazor public Task GetFormatsAsync() => Task.FromResult(Array.Empty()); - public Task GetDataAsync(string format) => Task.FromResult(null); + public Task GetDataAsync(string format) => Task.FromResult(new ()); } - class CursorStub : ICursorImpl + internal class CursorStub : ICursorImpl { public void Dispose() { @@ -34,7 +31,7 @@ namespace Avalonia.Web.Blazor } } - class CursorFactoryStub : ICursorFactory + internal class CursorFactoryStub : ICursorFactory { public ICursorImpl CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot) { @@ -47,9 +44,9 @@ namespace Avalonia.Web.Blazor } } - class IconLoaderStub : IPlatformIconLoader + internal class IconLoaderStub : IPlatformIconLoader { - class IconStub : IWindowIconImpl + private class IconStub : IWindowIconImpl { public void Save(Stream outputStream) { @@ -64,20 +61,20 @@ namespace Avalonia.Web.Blazor public IWindowIconImpl LoadIcon(IBitmapImpl bitmap) => new IconStub(); } - class SystemDialogsStub : ISystemDialogImpl + internal class SystemDialogsStub : ISystemDialogImpl { - public Task ShowFileDialogAsync(FileDialog dialog, Window parent) => - Task.FromResult((string[])null); + public Task ShowFileDialogAsync(FileDialog dialog, Window parent) => + Task.FromResult((string[]?)null); - public Task ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent) => - Task.FromResult((string)null); + public Task ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent) => + Task.FromResult((string?)null); } - class ScreenStub : IScreenImpl + internal class ScreenStub : IScreenImpl { public int ScreenCount => 1; public IReadOnlyList AllScreens { get; } = - new Screen[] { new Screen(96, new PixelRect(0, 0, 4000, 4000), new PixelRect(0, 0, 4000, 4000), true) }; + new[] { new Screen(96, new PixelRect(0, 0, 4000, 4000), new PixelRect(0, 0, 4000, 4000), true) }; } -} \ No newline at end of file +} diff --git a/src/Web/Avalonia.Web.Blazor/WindowingPlatform.cs b/src/Web/Avalonia.Web.Blazor/WindowingPlatform.cs index c6a64360a1..a3f2de5b61 100644 --- a/src/Web/Avalonia.Web.Blazor/WindowingPlatform.cs +++ b/src/Web/Avalonia.Web.Blazor/WindowingPlatform.cs @@ -5,15 +5,14 @@ using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Threading; +#nullable enable + namespace Avalonia.Web.Blazor { public class BlazorWindowingPlatform : IWindowingPlatform, IPlatformSettings, IPlatformThreadingInterface { - private static object _uiLock = new object(); - private static object _syncRootLock = new object(); - private bool _signaled = false; - private static int _uiThreadId = -1; - private static int _lockNesting = 0; + private bool _signaled; + private static int s_uiThreadId = -1; public IWindowImpl CreateWindow() => throw new NotSupportedException(); @@ -22,7 +21,7 @@ namespace Avalonia.Web.Blazor throw new NotImplementedException(); } - public ITrayIconImpl CreateTrayIcon() + public ITrayIconImpl? CreateTrayIcon() { return null; } @@ -61,36 +60,29 @@ namespace Avalonia.Web.Blazor return AvaloniaLocator.Current.GetService() .StartSystemTimer(interval, () => { - using (Lock()) - { - Dispatcher.UIThread.RunJobs(priority); - tick(); - } + Dispatcher.UIThread.RunJobs(priority); + tick(); }); } public void Signal(DispatcherPriority priority) { - lock (_syncRootLock) - { - if (_signaled) - return; - _signaled = true; - IDisposable disp = null; - disp = AvaloniaLocator.Current.GetService() - .StartSystemTimer(TimeSpan.FromMilliseconds(1), - () => - { - lock (_syncRootLock) - { - _signaled = false; - disp.Dispose(); - } - - using (Lock()) - Signaled?.Invoke(null); - }); - } + if (_signaled) + return; + + _signaled = true; + + IDisposable? disp = null; + + disp = AvaloniaLocator.Current.GetService() + .StartSystemTimer(TimeSpan.FromMilliseconds(1), + () => + { + _signaled = false; + disp?.Dispose(); + + Signaled?.Invoke(null); + }); } public bool CurrentThreadIsLoopThread @@ -101,33 +93,8 @@ namespace Avalonia.Web.Blazor } } - public event Action Signaled; - - class LockDisposable : IDisposable - { - public void Dispose() - { - lock (_syncRootLock) - { - _lockNesting--; - if (_lockNesting == 0) - _uiThreadId = -1; - } - - Monitor.Exit(_uiLock); - } - } - - public static IDisposable Lock() - { - Monitor.Enter(_uiLock); - lock (_syncRootLock) - { - _lockNesting++; - _uiThreadId = Thread.CurrentThread.ManagedThreadId; - } + public event Action? Signaled; - return new LockDisposable(); - } + } }