diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs index 3e945798d4..2451d26126 100644 --- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs +++ b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs @@ -219,7 +219,10 @@ namespace Avalonia.Gtk3.Interop public delegate void gtk_widget_queue_draw_area(GtkWidget widget, int x, int y, int width, int height); [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] - public delegate void gtk_widget_add_tick_callback(GtkWidget widget, TickCallback callback, IntPtr userData, IntPtr destroy); + public delegate uint gtk_widget_add_tick_callback(GtkWidget widget, TickCallback callback, IntPtr userData, IntPtr destroy); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] + public delegate uint gtk_widget_remove_tick_callback(GtkWidget widget, uint id); [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] public delegate GtkImContext gtk_im_multicontext_new(); @@ -256,6 +259,9 @@ namespace Avalonia.Gtk3.Interop [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] public delegate void gtk_window_unmaximize(GtkWindow window); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] + public delegate void gtk_window_close(GtkWindow window); [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] public delegate void gtk_window_set_geometry_hints(GtkWindow window, IntPtr geometry_widget, ref GdkGeometry geometry, GdkWindowHints geom_mask); @@ -434,6 +440,7 @@ namespace Avalonia.Gtk3.Interop public static D.gdk_window_invalidate_rect GdkWindowInvalidateRect; public static D.gtk_widget_queue_draw_area GtkWidgetQueueDrawArea; public static D.gtk_widget_add_tick_callback GtkWidgetAddTickCallback; + public static D.gtk_widget_remove_tick_callback GtkWidgetRemoveTickCallback; public static D.gtk_widget_activate GtkWidgetActivate; public static D.gtk_clipboard_get_for_display GtkClipboardGetForDisplay; public static D.gtk_clipboard_request_text GtkClipboardRequestText; @@ -456,6 +463,7 @@ namespace Avalonia.Gtk3.Interop public static D.gtk_window_deiconify GtkWindowDeiconify; public static D.gtk_window_maximize GtkWindowMaximize; public static D.gtk_window_unmaximize GtkWindowUnmaximize; + public static D.gtk_window_close GtkWindowClose; public static D.gdk_window_begin_move_drag GdkWindowBeginMoveDrag; public static D.gdk_window_begin_resize_drag GdkWindowBeginResizeDrag; public static D.gdk_event_request_motions GdkEventRequestMotions; diff --git a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs index c41a136bce..5aac4466b2 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs @@ -33,11 +33,11 @@ namespace Avalonia.Gtk3 private readonly AutoResetEvent _canSetNextOperation = new AutoResetEvent(true); internal IntPtr? GdkWindowHandle; private bool _overrideRedirect; + private uint? _tickCallback; public WindowBaseImpl(GtkWindow gtkWidget) { GtkWidget = gtkWidget; - Disposables.Add(gtkWidget); _framebuffer = new FramebufferManager(this); _imContext = Native.GtkImMulticontextNew(); Disposables.Add(_imContext); @@ -62,7 +62,7 @@ namespace Avalonia.Gtk3 { Native.GtkWidgetSetDoubleBuffered(gtkWidget, false); _gcHandle = GCHandle.Alloc(this); - Native.GtkWidgetAddTickCallback(GtkWidget, PinnedStaticCallback, GCHandle.ToIntPtr(_gcHandle), IntPtr.Zero); + _tickCallback = Native.GtkWidgetAddTickCallback(GtkWidget, PinnedStaticCallback, GCHandle.ToIntPtr(_gcHandle), IntPtr.Zero); } } @@ -103,7 +103,7 @@ namespace Avalonia.Gtk3 private bool OnDestroy(IntPtr gtkwidget, IntPtr userdata) { - Dispose(); + DoDispose(true); return false; } @@ -297,14 +297,28 @@ namespace Avalonia.Gtk3 } - public void Dispose() + public void Dispose() => DoDispose(false); + + void DoDispose(bool fromDestroy) { + if (_tickCallback.HasValue) + { + if (!GtkWidget.IsClosed) + Native.GtkWidgetRemoveTickCallback(GtkWidget, _tickCallback.Value); + _tickCallback = null; + } + //We are calling it here, since signal handler will be detached if (!GtkWidget.IsClosed) Closed?.Invoke(); foreach(var d in Disposables.AsEnumerable().Reverse()) d.Dispose(); Disposables.Clear(); + + if (!fromDestroy && !GtkWidget.IsClosed) + Native.GtkWindowClose(GtkWidget); + GtkWidget.Dispose(); + if (_gcHandle.IsAllocated) { _gcHandle.Free();