Browse Source

Proper closing/disposing handling

pull/875/head
Nikita Tsukanov 9 years ago
parent
commit
2561901fd1
  1. 15
      src/Gtk/Avalonia.Gtk3/Interop/GObject.cs
  2. 54
      src/Gtk/Avalonia.Gtk3/Interop/Native.cs
  3. 8
      src/Gtk/Avalonia.Gtk3/Interop/Signal.cs
  4. 4
      src/Gtk/Avalonia.Gtk3/PopupImpl.cs
  5. 29
      src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs
  6. 13
      src/Gtk/Avalonia.Gtk3/WindowImpl.cs

15
src/Gtk/Avalonia.Gtk3/Interop/GObject.cs

@ -33,5 +33,20 @@ namespace Avalonia.Gtk3.Interop
{
}
class GtkWidget : GObject
{
}
class GtkWindow : GtkWidget
{
}
class GtkImContext : GObject
{
}
}

54
src/Gtk/Avalonia.Gtk3/Interop/Native.cs

@ -27,32 +27,35 @@ namespace Avalonia.Gtk3.Interop
public delegate void gtk_main_iteration();
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate IntPtr gtk_window_new(GtkWindowType windowType);
public delegate GtkWindow gtk_window_new(GtkWindowType windowType);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate IntPtr gtk_init(int argc, IntPtr argv);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_present(IntPtr gtkWindow);
public delegate void gtk_window_present(GtkWindow gtkWindow);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_widget_hide(IntPtr gtkWidget);
public delegate void gtk_widget_hide(GtkWidget gtkWidget);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_set_icon(IntPtr window, Pixbuf pixbuf);
public delegate void gtk_window_set_icon(GtkWindow window, Pixbuf pixbuf);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_set_modal(GtkWindow window, bool modal);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] //No manual import
public delegate IntPtr gdk_get_native_handle(IntPtr gdkWindow);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate IntPtr gtk_widget_get_window(IntPtr gtkWidget);
public delegate IntPtr gtk_widget_get_window(GtkWidget gtkWidget);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate IntPtr gtk_widget_get_screen(IntPtr gtkWidget);
public delegate IntPtr gtk_widget_get_screen(GtkWidget gtkWidget);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate IntPtr gtk_widget_set_double_buffered(IntPtr gtkWidget, bool value);
public delegate IntPtr gtk_widget_set_double_buffered(GtkWidget gtkWidget, bool value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate IntPtr gtk_widget_set_events(IntPtr gtkWidget, uint flags);
public delegate IntPtr gtk_widget_set_events(GtkWidget gtkWidget, uint flags);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
@ -70,27 +73,27 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_widget_realize(IntPtr gtkWidget);
public delegate void gtk_widget_realize(GtkWidget gtkWidget);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_set_title(IntPtr gtkWindow, Utf8Buffer title);
public delegate void gtk_window_set_title(GtkWindow gtkWindow, Utf8Buffer title);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_set_decorated(IntPtr gtkWindow, bool decorated);
public delegate void gtk_window_set_decorated(GtkWindow gtkWindow, bool decorated);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_get_size(IntPtr gtkWindow, out int width, out int height);
public delegate void gtk_window_get_size(GtkWindow gtkWindow, out int width, out int height);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_resize(IntPtr gtkWindow, int width, int height);
public delegate void gtk_window_resize(GtkWindow gtkWindow, int width, int height);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_widget_set_size_request(IntPtr gtkWindow, int width, int height);
public delegate void gtk_widget_set_size_request(GtkWidget widget, int width, int height);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_set_default_size(IntPtr gtkWindow, int width, int height);
public delegate void gtk_window_set_default_size(GtkWindow gtkWindow, int width, int height);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_get_position(IntPtr gtkWindow, out int x, out int y);
public delegate void gtk_window_get_position(GtkWindow gtkWindow, out int x, out int y);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_move(IntPtr gtkWindow, int x, int y);
public delegate void gtk_window_move(GtkWindow gtkWindow, int x, int y);
@ -120,19 +123,19 @@ namespace Avalonia.Gtk3.Interop
public delegate void cairo_paint(IntPtr context);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_widget_queue_draw_area(IntPtr gtkWindow, int x, int y, int width, int height);
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 IntPtr gtk_im_multicontext_new();
public delegate GtkImContext gtk_im_multicontext_new();
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate IntPtr gtk_im_context_set_client_window(IntPtr context, IntPtr window);
public delegate IntPtr gtk_im_context_set_client_window(GtkImContext context, IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate bool gtk_im_context_filter_keypress(IntPtr context, IntPtr ev);
public delegate bool gtk_im_context_filter_keypress(GtkImContext context, IntPtr ev);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_widget_activate(IntPtr widget);
public delegate void gtk_widget_activate(GtkWidget widget);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate IntPtr gdk_screen_get_root_window(IntPtr screen);
@ -140,7 +143,7 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate IntPtr gdk_window_get_pointer(IntPtr raw, out int x, out int y, out int mask);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate void gtk_window_set_geometry_hints(IntPtr window, IntPtr geometry_widget, ref GdkGeometry geometry, GdkWindowHints geom_mask);
public delegate void gtk_window_set_geometry_hints(GtkWindow window, IntPtr geometry_widget, ref GdkGeometry geometry, GdkWindowHints geom_mask);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate void gdk_window_invalidate_rect(IntPtr window, ref GdkRectangle rect, bool invalidate_children);
@ -178,9 +181,9 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)]
public delegate void g_object_unref(IntPtr instance);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)]
public delegate ulong g_signal_connect_object(IntPtr instance, Utf8Buffer signal, IntPtr handler, IntPtr userData, int flags);
public delegate ulong g_signal_connect_object(GObject instance, Utf8Buffer signal, IntPtr handler, IntPtr userData, int flags);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)]
public delegate ulong g_signal_handler_disconnect(IntPtr instance, ulong connectionId);
public delegate ulong g_signal_handler_disconnect(GObject instance, ulong connectionId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Glib)]
public delegate ulong g_timeout_add(uint interval, timeout_callback callback, IntPtr data);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Glib)]
@ -214,6 +217,7 @@ namespace Avalonia.Gtk3.Interop
public static D.gtk_main_iteration GtkMainIteration;
public static D.gtk_window_new GtkWindowNew;
public static D.gtk_window_set_icon GtkWindowSetIcon;
public static D.gtk_window_set_modal GtkWindowSetModal;
public static D.gtk_init GtkInit;
public static D.gtk_window_present GtkWindowPresent;
public static D.gtk_widget_hide GtkWidgetHide;

8
src/Gtk/Avalonia.Gtk3/Interop/Signal.cs

@ -7,15 +7,15 @@ using System.Threading.Tasks;
namespace Avalonia.Gtk3.Interop
{
public class Signal
class Signal
{
class ConnectedSignal : IDisposable
{
private readonly IntPtr _instance;
private readonly GObject _instance;
private GCHandle _handle;
private readonly ulong _id;
public ConnectedSignal(IntPtr instance, GCHandle handle, ulong id)
public ConnectedSignal(GObject instance, GCHandle handle, ulong id)
{
_instance = instance;
_handle = handle;
@ -32,7 +32,7 @@ namespace Avalonia.Gtk3.Interop
}
}
public static IDisposable Connect<T>(IntPtr obj, string name, T handler)
public static IDisposable Connect<T>(GObject obj, string name, T handler)
{
var handle = GCHandle.Alloc(handler);
var ptr = Marshal.GetFunctionPointerForDelegate((Delegate)(object)handler);

4
src/Gtk/Avalonia.Gtk3/PopupImpl.cs

@ -10,7 +10,7 @@ namespace Avalonia.Gtk3
{
class PopupImpl : TopLevelImpl, IPopupImpl
{
static IntPtr CreateWindow()
static GtkWindow CreateWindow()
{
var window = Native.GtkWindowNew(GtkWindowType.Popup);
Native.GtkWindowSetSizeRequest(window, 1, 1);
@ -33,6 +33,8 @@ namespace Avalonia.Gtk3
}
set
{
if(GtkWidget.IsClosed)
return;
Native.GtkWindowSetDefaultSize(GtkWidget, (int)value.Width, (int)value.Height);
base.ClientSize = value;
var size = ClientSize;

29
src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Avalonia.Controls;
@ -13,20 +14,23 @@ namespace Avalonia.Gtk3
{
abstract class TopLevelImpl : ITopLevelImpl, IPlatformHandle
{
protected readonly IntPtr GtkWidget;
protected readonly GtkWindow GtkWidget;
private IInputRoot _inputRoot;
private readonly IntPtr _imContext;
private readonly GtkImContext _imContext;
private readonly FramebufferManager _framebuffer;
protected readonly List<IDisposable> Disposables = new List<IDisposable>();
private Size _lastSize;
private Point _lastPosition;
private uint _lastKbdEvent;
public TopLevelImpl(IntPtr gtkWidget)
public TopLevelImpl(GtkWindow gtkWidget)
{
GtkWidget = gtkWidget;
Disposables.Add(gtkWidget);
_framebuffer = new FramebufferManager(this);
_imContext = Native.GtkImMulticontextNew();
Disposables.Add(_imContext);
Native.GtkWidgetSetEvents(gtkWidget, uint.MaxValue);
Disposables.Add(Signal.Connect<Native.D.signal_commit>(_imContext, "commit", OnCommit));
Connect<Native.D.signal_widget_draw>("draw", OnDraw);
@ -39,6 +43,7 @@ namespace Avalonia.Gtk3
ConnectEvent("window-state-event", OnStateChanged);
ConnectEvent("key-press-event", OnKeyEvent);
ConnectEvent("key-release-event", OnKeyEvent);
Connect<Native.D.signal_generic>("destroy", OnDestroy);
Native.GtkWidgetRealize(gtkWidget);
}
@ -66,6 +71,12 @@ namespace Avalonia.Gtk3
return false;
}
private bool OnDestroy(IntPtr gtkwidget, IntPtr userdata)
{
Closed?.Invoke();
return false;
}
private static InputModifiers GetModifierKeys(GdkModifierType state)
{
var rv = InputModifiers.None;
@ -190,10 +201,10 @@ namespace Avalonia.Gtk3
public void Dispose()
{
foreach(var d in Disposables)
Closed?.Invoke();
foreach(var d in Disposables.AsEnumerable().Reverse())
d.Dispose();
Disposables.Clear();
//TODO
}
public Size MaxClientSize
@ -212,7 +223,7 @@ namespace Avalonia.Gtk3
string IPlatformHandle.HandleDescriptor => "HWND";
public Action Activated { get; set; }
public Action Closed { get; set; } //TODO
public Action Closed { get; set; }
public Action Deactivated { get; set; }
public Action<RawInputEventArgs> Input { get; set; }
public Action<Rect> Paint { get; set; }
@ -224,6 +235,8 @@ namespace Avalonia.Gtk3
public void Invalidate(Rect rect)
{
if(GtkWidget.IsClosed)
return;
Native.GtkWidgetQueueDrawArea(GtkWidget, (int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height);
}
@ -279,12 +292,16 @@ namespace Avalonia.Gtk3
{
get
{
if (GtkWidget.IsClosed)
return new Size();
int w, h;
Native.GtkWindowGetSize(GtkWidget, out w, out h);
return new Size(w, h);
}
set
{
if (GtkWidget.IsClosed)
return;
Native.GtkWindowResize(GtkWidget, (int)value.Width, (int)value.Height);
if (Native.GtkWidgetGetWindow(GtkWidget) == IntPtr.Zero)
Native.GtkWidgetRealize(GtkWidget);

13
src/Gtk/Avalonia.Gtk3/WindowImpl.cs

@ -14,10 +14,19 @@ namespace Avalonia.Gtk3
Native.GtkWindowSetTitle(GtkWidget, t);
}
class EmptyDisposable : IDisposable
{
public void Dispose()
{
}
}
public IDisposable ShowDialog()
{
return null;
//STUB
Native.GtkWindowSetModal(GtkWidget, true);
Show();
return new EmptyDisposable();
}
public void SetSystemDecorations(bool enabled) => Native.GtkWindowSetDecorated(GtkWidget, enabled);

Loading…
Cancel
Save