Browse Source

Merge pull request #2716 from AvaloniaUI/v0.8-pre

V0.8 pre
v0.8 0.8.1
Nikita Tsukanov 7 years ago
committed by GitHub
parent
commit
146d51c992
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      azure-pipelines.yml
  2. 2
      build/SharedVersion.props
  3. 8
      nukebuild/Build.cs
  4. 1
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  5. 5
      samples/ControlCatalog.NetCore/Program.cs
  6. 2
      src/Avalonia.Native/Avalonia.Native.csproj
  7. 18
      src/Avalonia.OpenGL/AngleOptions.cs
  8. 71
      src/Avalonia.OpenGL/EglDisplay.cs
  9. 33
      src/Avalonia.OpenGL/EglGlPlatformSurface.cs
  10. 26
      src/Avalonia.OpenGL/EglInterface.cs
  11. 18
      src/Avalonia.OpenGL/GlInterface.cs
  12. 7
      src/Avalonia.OpenGL/IGlPlatformSurfaceRenderTarget.cs
  13. 5
      src/Avalonia.Visuals/Platform/IRenderTarget.cs
  14. 5
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  15. 14
      src/Avalonia.Visuals/Rendering/ManagedDeferredRendererLock.cs
  16. 32
      src/Avalonia.Visuals/Rendering/UiThreadRenderTimer.cs
  17. 13
      src/Avalonia.X11/Glx/GlxDisplay.cs
  18. 10
      src/Avalonia.X11/X11KeyTransform.cs
  19. 8
      src/Avalonia.X11/X11Platform.cs
  20. 15
      src/Avalonia.X11/X11Window.cs
  21. 2
      src/Skia/Avalonia.Skia/GlRenderTarget.cs
  22. 28
      src/Windows/Avalonia.Win32/WindowImpl.cs

5
azure-pipelines.yml

@ -32,7 +32,7 @@ jobs:
- job: macOS
pool:
vmImage: 'xcode9-macos10.13'
vmImage: 'macOS-10.14'
steps:
- task: DotNetCoreInstaller@0
inputs:
@ -49,7 +49,7 @@ jobs:
inputs:
actions: 'build'
scheme: ''
sdk: 'macosx10.13'
sdk: 'macosx10.14'
configuration: 'Release'
xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace'
xcodeVersion: 'default' # Options: 8, 9, default, specifyPath
@ -134,3 +134,4 @@ jobs:
pathToPublish: '$(Build.SourcesDirectory)/artifacts/zip'
artifactName: 'Samples'
condition: succeeded()

2
build/SharedVersion.props

@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Product>Avalonia</Product>
<Version>0.8.0</Version>
<Version>0.8.1</Version>
<Copyright>Copyright 2018 &#169; The AvaloniaUI Project</Copyright>
<PackageLicenseUrl>https://github.com/AvaloniaUI/Avalonia/blob/master/licence.md</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/AvaloniaUI/Avalonia/</PackageProjectUrl>

8
nukebuild/Build.cs

@ -122,6 +122,14 @@ partial class Build : NukeBuild
foreach(var fw in frameworks)
{
if (fw.StartsWith("net4")
&& RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
&& Environment.GetEnvironmentVariable("FORCE_LINUX_TESTS") != "1")
{
Information($"Skipping {fw} tests on Linux - https://github.com/mono/mono/issues/13969");
continue;
}
Information("Running for " + fw);
DotNetTest(c =>
{

1
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@ -10,6 +10,7 @@
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
<ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2019013001"/>
</ItemGroup>

5
samples/ControlCatalog.NetCore/Program.cs

@ -3,7 +3,6 @@ using System.Diagnostics;
using System.Linq;
using System.Threading;
using Avalonia;
using Avalonia.Skia;
namespace ControlCatalog.NetCore
{
@ -45,6 +44,10 @@ namespace ControlCatalog.NetCore
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.With(new Win32PlatformOptions
{
AllowEglInitialization = true
})
.UseSkia()
.UseReactiveUI()
.UseDataGrid();

2
src/Avalonia.Native/Avalonia.Native.csproj

@ -7,8 +7,6 @@
<CastXmlPath Condition="Exists('/usr/bin/castxml')">/usr/bin/castxml</CastXmlPath>
<CastXmlPath Condition="Exists('/usr/local/bin/castxml')">/usr/local/bin/castxml</CastXmlPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<!-- This is needed because Rider doesn't see generated files in obj for some reason -->
<SharpGenGeneratedCodeFolder>$(MSBuildThisFileDirectory)/Generated</SharpGenGeneratedCodeFolder>
</PropertyGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release' AND '$([MSBuild]::IsOSPlatform(OSX))' == 'true'">

18
src/Avalonia.OpenGL/AngleOptions.cs

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace Avalonia.OpenGL
{
public class AngleOptions
{
public enum PlatformApi
{
DirectX9,
DirectX11
}
public List<PlatformApi> AllowedPlatformApis = new List<PlatformApi>
{
PlatformApi.DirectX9
};
}
}

71
src/Avalonia.OpenGL/EglDisplay.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Avalonia.Platform.Interop;
using static Avalonia.OpenGL.EglConsts;
@ -13,21 +14,42 @@ namespace Avalonia.OpenGL
private readonly int[] _contextAttributes;
public IntPtr Handle => _display;
private AngleOptions.PlatformApi? _angleApi;
public EglDisplay(EglInterface egl)
{
_egl = egl;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && _egl.GetPlatformDisplayEXT != null)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
foreach (var dapi in new[] {EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE})
if (_egl.GetPlatformDisplayEXT == null)
throw new OpenGlException("eglGetPlatformDisplayEXT is not supported by libegl.dll");
var allowedApis = AvaloniaLocator.Current.GetService<AngleOptions>()?.AllowedPlatformApis
?? new List<AngleOptions.PlatformApi> {AngleOptions.PlatformApi.DirectX9};
foreach (var platformApi in allowedApis)
{
int dapi;
if (platformApi == AngleOptions.PlatformApi.DirectX9)
dapi = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
else if (platformApi == AngleOptions.PlatformApi.DirectX11)
dapi = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
else
continue;
_display = _egl.GetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero, new[]
{
EGL_PLATFORM_ANGLE_TYPE_ANGLE, dapi, EGL_NONE
});
if(_display != IntPtr.Zero)
if (_display != IntPtr.Zero)
{
_angleApi = platformApi;
break;
}
}
if (_display == IntPtr.Zero)
throw new OpenGlException("Unable to create ANGLE display");
}
if (_display == IntPtr.Zero)
@ -64,29 +86,35 @@ namespace Avalonia.OpenGL
if (!_egl.BindApi(cfg.Api))
continue;
var attribs = new[]
foreach(var stencilSize in new[]{8, 1, 0})
foreach (var depthSize in new []{8, 1, 0})
{
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, cfg.RenderableTypeBit,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_STENCIL_SIZE, 8,
EGL_DEPTH_SIZE, 8,
EGL_NONE
};
if (!_egl.ChooseConfig(_display, attribs, out _config, 1, out int numConfigs))
continue;
if (numConfigs == 0)
continue;
_contextAttributes = cfg.Attributes;
Type = cfg.Type;
var attribs = new[]
{
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, cfg.RenderableTypeBit,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_STENCIL_SIZE, stencilSize,
EGL_DEPTH_SIZE, depthSize,
EGL_NONE
};
if (!_egl.ChooseConfig(_display, attribs, out _config, 1, out int numConfigs))
continue;
if (numConfigs == 0)
continue;
_contextAttributes = cfg.Attributes;
Type = cfg.Type;
}
}
if (_contextAttributes == null)
throw new OpenGlException("No suitable EGL config was found");
GlInterface = GlInterface.FromNativeUtf8GetProcAddress(b => _egl.GetProcAddress(b));
}
@ -97,6 +125,7 @@ namespace Avalonia.OpenGL
public GlDisplayType Type { get; }
public GlInterface GlInterface { get; }
public EglInterface EglInterface => _egl;
public IGlContext CreateContext(IGlContext share)
{
var shareCtx = (EglContext)share;

33
src/Avalonia.OpenGL/EglGlPlatformSurface.cs

@ -26,31 +26,44 @@ namespace Avalonia.OpenGL
public IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
{
var glSurface = _display.CreateWindowSurface(_info.Handle);
return new RenderTarget(_context, glSurface, _info);
return new RenderTarget(_display, _context, glSurface, _info);
}
class RenderTarget : IGlPlatformSurfaceRenderTarget
class RenderTarget : IGlPlatformSurfaceRenderTargetWithCorruptionInfo
{
private readonly EglDisplay _display;
private readonly EglContext _context;
private readonly EglSurface _glSurface;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
private PixelSize _initialSize;
public RenderTarget(EglContext context, EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info)
public RenderTarget(EglDisplay display, EglContext context,
EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info)
{
_display = display;
_context = context;
_glSurface = glSurface;
_info = info;
_initialSize = info.Size;
}
public void Dispose() => _glSurface.Dispose();
public bool IsCorrupted => _initialSize != _info.Size;
public IGlPlatformSurfaceRenderingSession BeginDraw()
{
var l = _context.Lock();
try
{
if (IsCorrupted)
throw new RenderTargetCorruptedException();
_context.MakeCurrent(_glSurface);
return new Session(_context, _glSurface, _info, l);
_display.EglInterface.WaitClient();
_display.EglInterface.WaitGL();
_display.EglInterface.WaitNative();
return new Session(_display, _context, _glSurface, _info, l);
}
catch
{
@ -61,15 +74,19 @@ namespace Avalonia.OpenGL
class Session : IGlPlatformSurfaceRenderingSession
{
private readonly IGlContext _context;
private readonly EglContext _context;
private readonly EglSurface _glSurface;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
private readonly EglDisplay _display;
private IDisposable _lock;
public Session(IGlContext context, EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info,
public Session(EglDisplay display, EglContext context,
EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info,
IDisposable @lock)
{
_context = context;
_display = display;
_glSurface = glSurface;
_info = info;
_lock = @lock;
@ -78,7 +95,11 @@ namespace Avalonia.OpenGL
public void Dispose()
{
_context.Display.GlInterface.Flush();
_display.EglInterface.WaitGL();
_glSurface.SwapBuffers();
_display.EglInterface.WaitClient();
_display.EglInterface.WaitGL();
_display.EglInterface.WaitNative();
_context.Display.ClearContext();
_lock.Dispose();
}

26
src/Avalonia.OpenGL/EglInterface.cs

@ -1,4 +1,5 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
@ -91,6 +92,31 @@ namespace Avalonia.OpenGL
[GlEntryPoint("eglGetConfigAttrib")]
public EglGetConfigAttrib GetConfigAttrib { get; }
public delegate bool EglWaitGL();
[GlEntryPoint("eglWaitGL")]
public EglWaitGL WaitGL { get; }
public delegate bool EglWaitClient();
[GlEntryPoint("eglWaitClient")]
public EglWaitGL WaitClient { get; }
public delegate bool EglWaitNative();
[GlEntryPoint("eglWaitNative")]
public EglWaitGL WaitNative { get; }
public delegate IntPtr EglQueryString(IntPtr display, int i);
[GlEntryPoint("eglQueryString")]
public EglQueryString QueryStringNative { get; }
public string QueryString(IntPtr display, int i)
{
var rv = QueryStringNative(display, i);
if (rv == IntPtr.Zero)
return null;
return Marshal.PtrToStringAnsi(rv);
}
// ReSharper restore UnassignedGetOnlyAutoProperty
}
}

18
src/Avalonia.OpenGL/GlInterface.cs

@ -9,12 +9,14 @@ namespace Avalonia.OpenGL
public class GlInterface : GlInterfaceBase
{
public string Version { get; }
public string Vendor { get; }
public string Renderer { get; }
public GlInterface(Func<string, bool, IntPtr> getProcAddress) : base(getProcAddress)
{
var versionPtr = GetString(GlConsts.GL_VERSION);
if (versionPtr != IntPtr.Zero)
Version = Marshal.PtrToStringAnsi(versionPtr);
Version = GetString(GlConsts.GL_VERSION);
Renderer = GetString(GlConsts.GL_RENDERER);
Vendor = GetString(GlConsts.GL_VENDOR);
}
public GlInterface(Func<Utf8Buffer, IntPtr> n) : this(ConvertNative(n))
@ -54,7 +56,15 @@ namespace Avalonia.OpenGL
public delegate IntPtr GlGetString(int v);
[GlEntryPoint("glGetString")]
public GlGetString GetString { get; }
public GlGetString GetStringNative { get; }
public string GetString(int v)
{
var ptr = GetStringNative(v);
if (ptr != IntPtr.Zero)
return Marshal.PtrToStringAnsi(ptr);
return null;
}
public delegate void GlGetIntegerv(int name, out int rv);
[GlEntryPoint("glGetIntegerv")]

7
src/Avalonia.OpenGL/IGlPlatformSurfaceRenderTarget.cs

@ -6,4 +6,9 @@ namespace Avalonia.OpenGL
{
IGlPlatformSurfaceRenderingSession BeginDraw();
}
}
public interface IGlPlatformSurfaceRenderTargetWithCorruptionInfo : IGlPlatformSurfaceRenderTarget
{
bool IsCorrupted { get; }
}
}

5
src/Avalonia.Visuals/Platform/IRenderTarget.cs

@ -23,4 +23,9 @@ namespace Avalonia.Platform
/// </param>
IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer);
}
public interface IRenderTargetWithCorruptionInfo : IRenderTarget
{
bool IsCorrupted { get; }
}
}

5
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -248,6 +248,11 @@ namespace Avalonia.Rendering
{
if (context != null)
return context;
if ((RenderTarget as IRenderTargetWithCorruptionInfo)?.IsCorrupted == true)
{
RenderTarget.Dispose();
RenderTarget = null;
}
if (RenderTarget == null)
RenderTarget = ((IRenderRoot)_root).CreateRenderTarget();
return context = RenderTarget.CreateDrawingContext(this);

14
src/Avalonia.Visuals/Rendering/ManagedDeferredRendererLock.cs

@ -7,11 +7,25 @@ namespace Avalonia.Rendering
public class ManagedDeferredRendererLock : IDeferredRendererLock
{
private readonly object _lock = new object();
/// <summary>
/// Tries to lock the target surface or window
/// </summary>
/// <returns>IDisposable if succeeded to obtain the lock</returns>
public IDisposable TryLock()
{
if (Monitor.TryEnter(_lock))
return Disposable.Create(() => Monitor.Exit(_lock));
return null;
}
/// <summary>
/// Enters a waiting lock, only use from platform code, not from the renderer
/// </summary>
public IDisposable Lock()
{
Monitor.Enter(_lock);
return Disposable.Create(() => Monitor.Exit(_lock));
}
}
}

32
src/Avalonia.Visuals/Rendering/UiThreadRenderTimer.cs

@ -0,0 +1,32 @@
using System;
using System.Diagnostics;
using System.Reactive.Disposables;
using Avalonia.Threading;
namespace Avalonia.Rendering
{
/// <summary>
/// Render timer that ticks on UI thread. Useful for debugging or bootstrapping on new platforms
/// </summary>
public class UiThreadRenderTimer : DefaultRenderTimer
{
public UiThreadRenderTimer(int framesPerSecond) : base(framesPerSecond)
{
}
protected override IDisposable StartCore(Action<TimeSpan> tick)
{
bool cancelled = false;
var st = Stopwatch.StartNew();
DispatcherTimer.Run(() =>
{
if (cancelled)
return false;
tick(st.Elapsed);
return !cancelled;
}, TimeSpan.FromSeconds(1.0 / FramesPerSecond), DispatcherPriority.Render);
return Disposable.Create(() => cancelled = true);
}
}
}

13
src/Avalonia.X11/Glx/GlxDisplay.cs

@ -90,6 +90,19 @@ namespace Avalonia.X11.Glx
GlInterface = new GlInterface(GlxInterface.GlxGetProcAddress);
if (GlInterface.Version == null)
throw new OpenGlException("GL version string is null, aborting");
if (GlInterface.Renderer == null)
throw new OpenGlException("GL renderer string is null, aborting");
if (Environment.GetEnvironmentVariable("AVALONIA_GLX_IGNORE_RENDERER_BLACKLIST") != "1")
{
var blacklist = AvaloniaLocator.Current.GetService<X11PlatformOptions>()
?.GlxRendererBlacklist;
if (blacklist != null)
foreach(var item in blacklist)
if (GlInterface.Renderer.Contains(item))
throw new OpenGlException($"Renderer '{GlInterface.Renderer}' is blacklisted by '{item}'");
}
}
public void ClearContext() => Glx.MakeContextCurrent(_x11.Display,

10
src/Avalonia.X11/X11KeyTransform.cs

@ -221,12 +221,8 @@ namespace Avalonia.X11
//{ X11Key.?, Key.DeadCharProcessed }
};
public static Key ConvertKey(IntPtr key)
{
var ikey = key.ToInt32();
Key result;
return KeyDic.TryGetValue((X11Key)ikey, out result) ? result : Key.None;
}
}
public static Key ConvertKey(X11Key key)
=> KeyDic.TryGetValue(key, out var result) ? result : Key.None;
}
}

8
src/Avalonia.X11/X11Platform.cs

@ -95,6 +95,14 @@ namespace Avalonia
{
public bool UseEGL { get; set; }
public bool UseGpu { get; set; } = true;
public List<string> GlxRendererBlacklist { get; set; } = new List<string>
{
// llvmpipe is a software GL rasterizer. If it's returned by glGetString,
// that usually means that something in the system is horribly misconfigured
// and sometimes attempts to use GLX might cause a segfault
"llvmpipe"
};
public string WmClass { get; set; } = Assembly.GetEntryAssembly()?.GetName()?.Name ?? "AvaloniaApplication";
}
public static class AvaloniaX11PlatformExtensions

15
src/Avalonia.X11/X11Window.cs

@ -419,10 +419,21 @@ namespace Avalonia.X11
return;
var buffer = stackalloc byte[40];
var latinKeysym = XKeycodeToKeysym(_x11.Display, ev.KeyEvent.keycode, 0);
var index = ev.KeyEvent.state.HasFlag(XModifierMask.ShiftMask);
// We need the latin key, since it's mainly used for hotkeys, we use a different API for text anyway
var key = (X11Key)XKeycodeToKeysym(_x11.Display, ev.KeyEvent.keycode, index ? 1 : 0).ToInt32();
// Manually switch the Shift index for the keypad,
// there should be a proper way to do this
if (ev.KeyEvent.state.HasFlag(XModifierMask.Mod2Mask)
&& key > X11Key.Num_Lock && key <= X11Key.KP_9)
key = (X11Key)XKeycodeToKeysym(_x11.Display, ev.KeyEvent.keycode, index ? 0 : 1).ToInt32();
ScheduleInput(new RawKeyEventArgs(_keyboard, (ulong)ev.KeyEvent.time.ToInt64(),
ev.type == XEventName.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
X11KeyTransform.ConvertKey(latinKeysym), TranslateModifiers(ev.KeyEvent.state)), ref ev);
X11KeyTransform.ConvertKey(key), TranslateModifiers(ev.KeyEvent.state)), ref ev);
if (ev.type == XEventName.KeyPress)
{

2
src/Skia/Avalonia.Skia/GlRenderTarget.cs

@ -21,6 +21,8 @@ namespace Avalonia.Skia
public void Dispose() => _surface.Dispose();
public bool IsCorrupted => (_surface as IGlPlatformSurfaceRenderTargetWithCorruptionInfo)?.IsCorrupted == true;
public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
{
var session = _surface.BeginDraw();

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

@ -31,6 +31,7 @@ namespace Avalonia.Win32
private string _className;
private IntPtr _hwnd;
private IInputRoot _owner;
private ManagedDeferredRendererLock _rendererLock = new ManagedDeferredRendererLock();
private bool _trackingMouse;
private bool _decorated = true;
private bool _resizable = true;
@ -148,7 +149,9 @@ namespace Avalonia.Win32
if (customRendererFactory != null)
return customRendererFactory.Create(root, loop);
return Win32Platform.UseDeferredRendering ? (IRenderer)new DeferredRenderer(root, loop) : new ImmediateRenderer(root);
return Win32Platform.UseDeferredRendering ?
(IRenderer)new DeferredRenderer(root, loop, rendererLock: _rendererLock) :
new ImmediateRenderer(root);
}
public void Resize(Size value)
@ -627,18 +630,26 @@ namespace Avalonia.Win32
break;
case UnmanagedMethods.WindowsMessage.WM_PAINT:
UnmanagedMethods.PAINTSTRUCT ps;
if (UnmanagedMethods.BeginPaint(_hwnd, out ps) != IntPtr.Zero)
using (_rendererLock.Lock())
{
var f = Scaling;
var r = ps.rcPaint;
Paint?.Invoke(new Rect(r.left / f, r.top / f, (r.right - r.left) / f, (r.bottom - r.top) / f));
UnmanagedMethods.EndPaint(_hwnd, ref ps);
UnmanagedMethods.PAINTSTRUCT ps;
if (UnmanagedMethods.BeginPaint(_hwnd, out ps) != IntPtr.Zero)
{
var f = Scaling;
var r = ps.rcPaint;
Paint?.Invoke(new Rect(r.left / f, r.top / f, (r.right - r.left) / f,
(r.bottom - r.top) / f));
UnmanagedMethods.EndPaint(_hwnd, ref ps);
}
}
return IntPtr.Zero;
case UnmanagedMethods.WindowsMessage.WM_SIZE:
using (_rendererLock.Lock())
{
// Do nothing here, just block until the pending frame render is completed on the render thread
}
var size = (UnmanagedMethods.SizeCommand)wParam;
if (Resized != null &&
@ -704,7 +715,8 @@ namespace Avalonia.Win32
}
}
return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);
using (_rendererLock.Lock())
return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);
}
static InputModifiers GetMouseModifiers(IntPtr wParam)

Loading…
Cancel
Save