diff --git a/src/Gtk/Avalonia.Gtk3/Interop/GObject.cs b/src/Gtk/Avalonia.Gtk3/Interop/GObject.cs index 9b5ee758b9..9cd9c5cd8b 100644 --- a/src/Gtk/Avalonia.Gtk3/Interop/GObject.cs +++ b/src/Gtk/Avalonia.Gtk3/Interop/GObject.cs @@ -33,5 +33,20 @@ namespace Avalonia.Gtk3.Interop { } + + class GtkWidget : GObject + { + + } + + class GtkWindow : GtkWidget + { + + } + + class GtkImContext : GObject + { + + } } diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs index b325b46285..4112bf3f91 100644 --- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs +++ b/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; diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Signal.cs b/src/Gtk/Avalonia.Gtk3/Interop/Signal.cs index b2ccdcf408..abbcab9e21 100644 --- a/src/Gtk/Avalonia.Gtk3/Interop/Signal.cs +++ b/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(IntPtr obj, string name, T handler) + public static IDisposable Connect(GObject obj, string name, T handler) { var handle = GCHandle.Alloc(handler); var ptr = Marshal.GetFunctionPointerForDelegate((Delegate)(object)handler); diff --git a/src/Gtk/Avalonia.Gtk3/PopupImpl.cs b/src/Gtk/Avalonia.Gtk3/PopupImpl.cs index 4cc01c625f..3f76960e8f 100644 --- a/src/Gtk/Avalonia.Gtk3/PopupImpl.cs +++ b/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; diff --git a/src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs b/src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs index e532a05915..0a8ae49906 100644 --- a/src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs +++ b/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 Disposables = new List(); 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(_imContext, "commit", OnCommit)); Connect("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("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 Input { get; set; } public Action 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); diff --git a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs index 25b0bd8dd3..d1a689b75f 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs +++ b/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);