Browse Source

Properly notify the TopLevel before destroying render targets

pull/10951/head
Nikita Tsukanov 4 years ago
parent
commit
9aec3e348b
  1. 14
      src/Avalonia.Controls/TopLevel.cs
  2. 19
      src/Avalonia.X11/X11Window.cs
  3. 15
      src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
  4. 11
      src/Windows/Avalonia.Win32/WindowImpl.cs

14
src/Avalonia.Controls/TopLevel.cs

@ -527,6 +527,13 @@ namespace Avalonia.Controls
/// </summary>
protected virtual void HandleClosed()
{
Renderer.SceneInvalidated -= SceneInvalidated;
// We need to wait for the renderer to complete any in-flight operations
Renderer.Dispose();
// The PlatformImpl is completely invalid at this point
PlatformImpl = null;
if (_globalStyles is object)
{
_globalStyles.GlobalStylesAdded -= ((IStyleHost)this).StylesAdded;
@ -536,10 +543,7 @@ namespace Avalonia.Controls
{
_applicationThemeHost.ActualThemeVariantChanged -= GlobalActualThemeVariantChanged;
}
Renderer.SceneInvalidated -= SceneInvalidated;
Renderer.Dispose();
_layoutDiagnosticBridge?.Dispose();
_layoutDiagnosticBridge = null;
@ -547,8 +551,6 @@ namespace Avalonia.Controls
_pointerOverPreProcessorSubscription?.Dispose();
_backGestureSubscription?.Dispose();
PlatformImpl = null;
var logicalArgs = new LogicalTreeAttachmentEventArgs(this, this, null);
((ILogical)this).NotifyDetachedFromLogicalTree(logicalArgs);

19
src/Avalonia.X11/X11Window.cs

@ -48,6 +48,7 @@ namespace Avalonia.X11
private readonly X11NativeControlHost _nativeControlHost;
private PixelPoint? _position;
private PixelSize _realSize;
private bool _cleaningUp;
private IntPtr _handle;
private IntPtr _xic;
private IntPtr _renderHandle;
@ -522,7 +523,7 @@ namespace Avalonia.X11
else if (ev.type == XEventName.DestroyNotify
&& ev.DestroyWindowEvent.window == _handle)
{
Cleanup();
Cleanup(true);
}
else if (ev.type == XEventName.ClientMessage)
{
@ -816,7 +817,7 @@ namespace Avalonia.X11
public void Dispose()
{
Cleanup();
Cleanup(false);
}
public virtual object? TryGetFeature(Type featureType)
@ -849,8 +850,17 @@ namespace Avalonia.X11
return null;
}
private void Cleanup()
private void Cleanup(bool fromDestroyNotification)
{
// Prevent reentrancy
if(_cleaningUp)
return;
_cleaningUp = true;
// Before doing anything else notify the TopLevel that ITopLevelImpl is no longer valid
if (_handle != IntPtr.Zero)
Closed?.Invoke();
if (_rawEventGrouper != null)
{
_rawEventGrouper.Dispose();
@ -891,7 +901,8 @@ namespace Avalonia.X11
Closed?.Invoke();
_mouse.Dispose();
_touch.Dispose();
XDestroyWindow(_x11.Display, handle);
if (!fromDestroyNotification)
XDestroyWindow(_x11.Display, handle);
}
if (_useRenderWindow && _renderHandle != IntPtr.Zero)

15
src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs

@ -85,6 +85,9 @@ namespace Avalonia.Win32
case WindowsMessage.WM_DESTROY:
{
// The first and foremost thing to do - notify the TopLevel
Closed?.Invoke();
if (UiaCoreTypesApi.IsNetComInteropAvailable)
{
UiaCoreProviderApi.UiaReturnRawElementProvider(_hwnd, IntPtr.Zero, IntPtr.Zero, null);
@ -95,6 +98,18 @@ namespace Avalonia.Win32
{
Imm32InputMethod.Current.ClearLanguageAndWindow();
}
// Cleanup render targets
(_gl as IDisposable)?.Dispose();
if (_dropTarget != null)
{
OleContext.Current?.UnregisterDragDrop(Handle);
_dropTarget.Dispose();
_dropTarget = null;
}
_framebuffer.Dispose();
//Window doesn't exist anymore
_hwnd = IntPtr.Zero;

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

@ -624,15 +624,6 @@ namespace Avalonia.Win32
public void Dispose()
{
(_gl as IDisposable)?.Dispose();
if (_dropTarget != null)
{
OleContext.Current?.UnregisterDragDrop(Handle);
_dropTarget.Dispose();
_dropTarget = null;
}
if (_hwnd != IntPtr.Zero)
{
// Detect if we are being closed programmatically - this would mean that WM_CLOSE was not called
@ -645,8 +636,6 @@ namespace Avalonia.Win32
DestroyWindow(_hwnd);
_hwnd = IntPtr.Zero;
}
_framebuffer.Dispose();
}
public void Invalidate(Rect rect)

Loading…
Cancel
Save