diff --git a/packages/Avalonia/AvaloniaBuildTasks.targets b/packages/Avalonia/AvaloniaBuildTasks.targets
index 45a7f1aa44..de3830ffea 100644
--- a/packages/Avalonia/AvaloniaBuildTasks.targets
+++ b/packages/Avalonia/AvaloniaBuildTasks.targets
@@ -42,12 +42,24 @@
- $(BuildAvaloniaResourcesDependsOn);AddAvaloniaResources;ResolveReferences
+ $(BuildAvaloniaResourcesDependsOn);AddAvaloniaResources;ResolveReferences;_GenerateAvaloniaResourcesDependencyCache
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Controls/Design.cs b/src/Avalonia.Controls/Design.cs
index 0d05e19e53..07d2918a88 100644
--- a/src/Avalonia.Controls/Design.cs
+++ b/src/Avalonia.Controls/Design.cs
@@ -60,6 +60,19 @@ namespace Avalonia.Controls
return target.GetValue(PreviewWithProperty);
}
+ public static readonly AttachedProperty DesignStyleProperty = AvaloniaProperty
+ .RegisterAttached("DesignStyle", typeof(Design));
+
+ public static void SetDesignStyle(Control control, IStyle value)
+ {
+ control.SetValue(DesignStyleProperty, value);
+ }
+
+ public static IStyle GetDesignStyle(Control control)
+ {
+ return control.GetValue(DesignStyleProperty);
+ }
+
public static void ApplyDesignModeProperties(Control target, Control source)
{
if (source.IsSet(WidthProperty))
@@ -68,6 +81,8 @@ namespace Avalonia.Controls
target.Height = source.GetValue(HeightProperty);
if (source.IsSet(DataContextProperty))
target.DataContext = source.GetValue(DataContextProperty);
+ if (source.IsSet(DesignStyleProperty))
+ target.Styles.Add(source.GetValue(DesignStyleProperty));
}
}
}
diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
index 209feb351c..726d2c596c 100644
--- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
+++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
@@ -303,7 +303,8 @@ namespace Avalonia.Controls.Platform
{
item.Parent.SelectedItem.Close();
SelectItemAndAncestors(item);
- Open(item, false);
+ if (item.HasSubMenu)
+ Open(item, false);
}
else
{
diff --git a/src/Avalonia.Themes.Fluent/Controls/NotificationCard.xaml b/src/Avalonia.Themes.Fluent/Controls/NotificationCard.xaml
index c06b501f82..924d977eb5 100644
--- a/src/Avalonia.Themes.Fluent/Controls/NotificationCard.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/NotificationCard.xaml
@@ -17,7 +17,7 @@
-
+
-
+
-
-
+
+
diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
index 3bd8e05ee2..6c84cfd55c 100644
--- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
+++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
@@ -35,6 +35,8 @@ namespace Avalonia.Rendering
private IRef _currentDraw;
private readonly IDeferredRendererLock _lock;
private readonly object _sceneLock = new object();
+ private readonly object _startStopLock = new object();
+ private readonly object _renderLoopIsRenderingLock = new object();
private readonly Action _updateSceneIfNeededDelegate;
///
@@ -139,6 +141,8 @@ namespace Avalonia.Rendering
}
Stop();
+ // Wait for any in-progress rendering to complete
+ lock(_renderLoopIsRenderingLock){}
DisposeRenderTarget();
}
@@ -233,20 +237,26 @@ namespace Avalonia.Rendering
///
public void Start()
{
- if (!_running && _renderLoop != null)
+ lock (_startStopLock)
{
- _renderLoop.Add(this);
- _running = true;
+ if (!_running && _renderLoop != null)
+ {
+ _renderLoop.Add(this);
+ _running = true;
+ }
}
}
///
public void Stop()
{
- if (_running && _renderLoop != null)
+ lock (_startStopLock)
{
- _renderLoop.Remove(this);
- _running = false;
+ if (_running && _renderLoop != null)
+ {
+ _renderLoop.Remove(this);
+ _running = false;
+ }
}
}
@@ -255,7 +265,16 @@ namespace Avalonia.Rendering
void IRenderLoopTask.Update(TimeSpan time) => UpdateScene();
- void IRenderLoopTask.Render() => Render(false);
+ void IRenderLoopTask.Render()
+ {
+ lock (_renderLoopIsRenderingLock)
+ {
+ lock(_startStopLock)
+ if(!_running)
+ return;
+ Render(false);
+ }
+ }
///
Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush)
diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs
index 149d7fb9b2..f0d2d5ca8a 100644
--- a/src/Avalonia.X11/X11Window.cs
+++ b/src/Avalonia.X11/X11Window.cs
@@ -805,13 +805,14 @@ namespace Avalonia.X11
if (_handle != IntPtr.Zero)
{
- XDestroyWindow(_x11.Display, _handle);
_platform.Windows.Remove(_handle);
_platform.XI2?.OnWindowDestroyed(_handle);
+ var handle = _handle;
_handle = IntPtr.Zero;
Closed?.Invoke();
_mouse.Dispose();
_touch.Dispose();
+ XDestroyWindow(_x11.Display, handle);
}
if (_useRenderWindow && _renderHandle != IntPtr.Zero)
diff --git a/src/Linux/Avalonia.LinuxFramebuffer/LockedFramebuffer.cs b/src/Linux/Avalonia.LinuxFramebuffer/LockedFramebuffer.cs
deleted file mode 100644
index 87c7b64c26..0000000000
--- a/src/Linux/Avalonia.LinuxFramebuffer/LockedFramebuffer.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using Avalonia.Platform;
-
-namespace Avalonia.LinuxFramebuffer
-{
- unsafe class LockedFramebuffer : ILockedFramebuffer
- {
- private readonly int _fb;
- private readonly fb_fix_screeninfo _fixedInfo;
- private fb_var_screeninfo _varInfo;
- private readonly IntPtr _address;
-
- public LockedFramebuffer(int fb, fb_fix_screeninfo fixedInfo, fb_var_screeninfo varInfo, IntPtr address, Vector dpi)
- {
- _fb = fb;
- _fixedInfo = fixedInfo;
- _varInfo = varInfo;
- _address = address;
- Dpi = dpi;
- //Use double buffering to avoid flicker
- Address = Marshal.AllocHGlobal(RowBytes * Size.Height);
- }
-
-
- void VSync()
- {
- NativeUnsafeMethods.ioctl(_fb, FbIoCtl.FBIO_WAITFORVSYNC, null);
- }
-
- public void Dispose()
- {
- VSync();
- NativeUnsafeMethods.memcpy(_address, Address, new IntPtr(RowBytes * Size.Height));
-
- Marshal.FreeHGlobal(Address);
- Address = IntPtr.Zero;
- }
-
- public IntPtr Address { get; private set; }
- public PixelSize Size => new PixelSize((int)_varInfo.xres, (int) _varInfo.yres);
- public int RowBytes => (int) _fixedInfo.line_length;
- public Vector Dpi { get; }
- public PixelFormat Format => _varInfo.bits_per_pixel == 16 ? PixelFormat.Rgb565 : _varInfo.blue.offset == 16 ? PixelFormat.Rgba8888 : PixelFormat.Bgra8888;
- }
-}
diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Output/FbDevBackBuffer.cs b/src/Linux/Avalonia.LinuxFramebuffer/Output/FbDevBackBuffer.cs
new file mode 100644
index 0000000000..7afad13bb6
--- /dev/null
+++ b/src/Linux/Avalonia.LinuxFramebuffer/Output/FbDevBackBuffer.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Avalonia.Platform;
+
+namespace Avalonia.LinuxFramebuffer.Output
+{
+ internal unsafe class FbDevBackBuffer : IDisposable
+ {
+ private readonly int _fb;
+ private readonly fb_fix_screeninfo _fixedInfo;
+ private readonly fb_var_screeninfo _varInfo;
+ private readonly IntPtr _targetAddress;
+ private readonly object _lock = new object();
+
+ public FbDevBackBuffer(int fb, fb_fix_screeninfo fixedInfo, fb_var_screeninfo varInfo, IntPtr targetAddress)
+ {
+ _fb = fb;
+ _fixedInfo = fixedInfo;
+ _varInfo = varInfo;
+ _targetAddress = targetAddress;
+ Address = Marshal.AllocHGlobal(RowBytes * Size.Height);
+ }
+
+
+ public void Dispose()
+ {
+ if (Address != IntPtr.Zero)
+ {
+ Marshal.FreeHGlobal(Address);
+ Address = IntPtr.Zero;
+ }
+ }
+
+ public ILockedFramebuffer Lock(Vector dpi)
+ {
+ Monitor.Enter(_lock);
+ try
+ {
+ return new LockedFramebuffer(Address,
+ new PixelSize((int)_varInfo.xres, (int)_varInfo.yres),
+ (int)_fixedInfo.line_length, dpi,
+ _varInfo.bits_per_pixel == 16 ? PixelFormat.Rgb565
+ : _varInfo.blue.offset == 16 ? PixelFormat.Rgba8888
+ : PixelFormat.Bgra8888,
+ () =>
+ {
+ try
+ {
+ NativeUnsafeMethods.ioctl(_fb, FbIoCtl.FBIO_WAITFORVSYNC, null);
+ NativeUnsafeMethods.memcpy(_targetAddress, Address, new IntPtr(RowBytes * Size.Height));
+ }
+ finally
+ {
+ Monitor.Exit(_lock);
+ }
+ });
+ }
+ catch
+ {
+ Monitor.Exit(_lock);
+ throw;
+ }
+ }
+
+ public IntPtr Address { get; private set; }
+ public PixelSize Size => new PixelSize((int)_varInfo.xres, (int) _varInfo.yres);
+ public int RowBytes => (int) _fixedInfo.line_length;
+ }
+}
diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Output/FbdevOutput.cs b/src/Linux/Avalonia.LinuxFramebuffer/Output/FbdevOutput.cs
index 61f00b2795..f3f9a12ac8 100644
--- a/src/Linux/Avalonia.LinuxFramebuffer/Output/FbdevOutput.cs
+++ b/src/Linux/Avalonia.LinuxFramebuffer/Output/FbdevOutput.cs
@@ -14,6 +14,7 @@ namespace Avalonia.LinuxFramebuffer
private fb_var_screeninfo _varInfo;
private IntPtr _mappedLength;
private IntPtr _mappedAddress;
+ private FbDevBackBuffer _backBuffer;
public double Scaling { get; set; }
///
@@ -146,7 +147,9 @@ namespace Avalonia.LinuxFramebuffer
{
if (_fd <= 0)
throw new ObjectDisposedException("LinuxFramebuffer");
- return new LockedFramebuffer(_fd, _fixedInfo, _varInfo, _mappedAddress, new Vector(96, 96) * Scaling);
+ return (_backBuffer ??=
+ new FbDevBackBuffer(_fd, _fixedInfo, _varInfo, _mappedAddress))
+ .Lock(new Vector(96, 96) * Scaling);
}
@@ -165,6 +168,8 @@ namespace Avalonia.LinuxFramebuffer
public void Dispose()
{
+ _backBuffer?.Dispose();
+ _backBuffer = null;
ReleaseUnmanagedResources();
GC.SuppressFinalize(this);
}
diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
index ad409810b8..6a6bcc5715 100644
--- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
+++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
@@ -808,6 +808,31 @@ namespace Avalonia.Win32.Interop
MNC_SELECT = 3
}
+ public enum SysCommands
+ {
+ SC_SIZE = 0xF000,
+ SC_MOVE = 0xF010,
+ SC_MINIMIZE = 0xF020,
+ SC_MAXIMIZE = 0xF030,
+ SC_NEXTWINDOW = 0xF040,
+ SC_PREVWINDOW = 0xF050,
+ SC_CLOSE = 0xF060,
+ SC_VSCROLL = 0xF070,
+ SC_HSCROLL = 0xF080,
+ SC_MOUSEMENU = 0xF090,
+ SC_KEYMENU = 0xF100,
+ SC_ARRANGE = 0xF110,
+ SC_RESTORE = 0xF120,
+ SC_TASKLIST = 0xF130,
+ SC_SCREENSAVE = 0xF140,
+ SC_HOTKEY = 0xF150,
+ SC_DEFAULT = 0xF160,
+ SC_MONITORPOWER = 0xF170,
+ SC_CONTEXTHELP = 0xF180,
+ SC_SEPARATOR = 0xF00F,
+ SCF_ISSECURE = 0x00000001,
+ }
+
[StructLayout(LayoutKind.Sequential)]
public struct RGBQUAD
{
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
index d163b3d068..f7ed2f215f 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
@@ -123,6 +123,12 @@ namespace Avalonia.Win32
break;
}
+ case WindowsMessage.WM_SYSCOMMAND:
+ // Disable system handling of Alt/F10 menu keys.
+ if ((SysCommands)wParam == SysCommands.SC_KEYMENU && HighWord(ToInt32(lParam)) <= 0)
+ return IntPtr.Zero;
+ break;
+
case WindowsMessage.WM_MENUCHAR:
{
// mute the system beep