From 04359041d7aef90f20ef87dc7f5a6acaa400ad9d Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 26 Jan 2017 03:42:54 +0300 Subject: [PATCH] Implemented click support --- src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj | 6 ++ src/Gtk/Avalonia.Gtk3/Interop/Native.cs | 96 +++++++++++++++++++++ src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs | 97 +++++++++++++++++++--- src/Gtk/Avalonia.Gtk3/WindowImpl.cs | 11 --- 4 files changed, 189 insertions(+), 21 deletions(-) diff --git a/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj b/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj index df5a712c18..ab52c8f9c4 100644 --- a/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj +++ b/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj @@ -25,6 +25,7 @@ DEBUG;TRACE prompt 4 + true pdbonly @@ -33,6 +34,7 @@ TRACE prompt 4 + true @@ -65,6 +67,10 @@ {62024B2D-53EB-4638-B26B-85EEAA54866E} Avalonia.Input + + {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} + Avalonia.Interactivity + {EB582467-6ABB-43A1-B052-E981BA910E3A} Avalonia.SceneGraph diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs index 2a5abfe603..3ee8871b40 100644 --- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs +++ b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs @@ -4,6 +4,12 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; +using gint8 = System.Byte; +using gint32 = System.Int32; +using gint = System.Int32; +using guint32 = System.UInt32; +using guint = System.UInt32; +using gdouble = System.Double; namespace Avalonia.Gtk3.Interop { @@ -48,6 +54,9 @@ namespace Avalonia.Gtk3.Interop [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] public delegate int gdk_screen_get_width(IntPtr screen); + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] + public delegate int gdk_window_get_origin(IntPtr gdkWindow, out int x, out int y); + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] @@ -64,6 +73,10 @@ namespace Avalonia.Gtk3.Interop public delegate void gtk_window_get_size(IntPtr 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); + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] + public delegate void gtk_window_get_position(IntPtr 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); [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] public delegate void gtk_widget_queue_draw_area(IntPtr gtkWindow, int x, int y, int width, int height); @@ -102,6 +115,8 @@ namespace Avalonia.Gtk3.Interop public static D.gtk_widget_realize GtkWidgetRealize; public static D.gtk_window_get_size GtkWindowGetSize; public static D.gtk_window_resize GtkWindowResize; + public static D.gtk_window_get_position GtkWindowGetPosition; + public static D.gtk_window_move GtkWindowMove; public static D.g_signal_connect_object GSignalConnectObject; public static D.g_signal_handler_disconnect GSignalHandlerDisconnect; public static D.g_timeout_add GTimeoutAdd; @@ -111,6 +126,7 @@ namespace Avalonia.Gtk3.Interop public static D.gtk_widget_queue_draw_area GtkWidgetQueueDrawArea; public static D.gdk_screen_get_height GdkScreenGetHeight; public static D.gdk_screen_get_width GdkScreenGetWidth; + public static D.gdk_window_get_origin GdkWindowGetOrigin; } @@ -137,4 +153,84 @@ namespace Avalonia.Gtk3.Interop }; } } + + enum GdkEventType + { + Nothing = -1, + Delete = 0, + Destroy = 1, + Expose = 2, + MotionNotify = 3, + ButtonPress = 4, + TwoButtonPress = 5, + ThreeButtonPress = 6, + ButtonRelease = 7, + KeyPress = 8, + KeyRelease = 9, + EnterNotify = 10, + LeaveNotify = 11, + FocusChange = 12, + Configure = 13, + Map = 14, + Unmap = 15, + PropertyNotify = 16, + SelectionClear = 17, + SelectionRequest = 18, + SelectionNotify = 19, + ProximityIn = 20, + ProximityOut = 21, + DragEnter = 22, + DragLeave = 23, + DragMotion = 24, + DragStatus = 25, + DropStart = 26, + DropFinished = 27, + ClientEvent = 28, + VisibilityNotify = 29, + NoExpose = 30, + Scroll = 31, + WindowState = 32, + Setting = 33, + OwnerChange = 34, + GrabBroken = 35, + } + + public enum GdkModifierType + { + ShiftMask = 1, + LockMask = 2, + ControlMask = 4, + Mod1Mask = 8, + Mod2Mask = 16, + Mod3Mask = 32, + Mod4Mask = 64, + Mod5Mask = 128, + Button1Mask = 256, + Button2Mask = 512, + Button3Mask = 1024, + Button4Mask = 2048, + Button5Mask = 4096, + SuperMask = 67108864, + HyperMask = 134217728, + MetaMask = 268435456, + ReleaseMask = 1073741824, + ModifierMask = ReleaseMask | Button5Mask | Button4Mask | Button3Mask | Button2Mask | Button1Mask | Mod5Mask | Mod4Mask | Mod3Mask | Mod2Mask | Mod1Mask | ControlMask | LockMask | ShiftMask, + None = 0, + } + + [StructLayout(LayoutKind.Sequential)] + unsafe struct GdkEventButton + { + public GdkEventType type; + public IntPtr window; + public gint8 send_event; + public guint32 time; + public gdouble x; + public gdouble y; + public gdouble* axes; + public GdkModifierType state; + public guint button; + public IntPtr device; + public gdouble x_root, y_root; + }; } diff --git a/src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs b/src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs index 672e98fe18..c16415828f 100644 --- a/src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs @@ -22,21 +22,73 @@ namespace Avalonia.Gtk3 Native.GtkWidgetRealize(gtkWidget); Connect("draw", OnDraw); Connect("configure-event", OnConfigured); + Connect("button-press-event", OnButton); + Connect("button-release-event", OnButton); } + private Size _lastSize; + private Point _lastPosition; + private bool OnConfigured(IntPtr gtkwidget, IntPtr ev, IntPtr userdata) { - Debug.WriteLine("Configured"); - Resized?.Invoke(ClientSize); + var size = ClientSize; + if (_lastSize != size) + { + _lastSize = size; + Resized?.Invoke(size); + } + var pos = Position; + if (_lastPosition != pos) + { + _lastPosition = pos; + PositionChanged?.Invoke(pos); + } + return false; } + private static InputModifiers GetModifierKeys(GdkModifierType state) + { + var rv = InputModifiers.None; + if (state.HasFlag(GdkModifierType.ControlMask)) + rv |= InputModifiers.Control; + if (state.HasFlag(GdkModifierType.ShiftMask)) + rv |= InputModifiers.Shift; + if (state.HasFlag(GdkModifierType.Mod1Mask)) + rv |= InputModifiers.Control; + if (state.HasFlag(GdkModifierType.Button1Mask)) + rv |= InputModifiers.LeftMouseButton; + if (state.HasFlag(GdkModifierType.Button2Mask)) + rv |= InputModifiers.RightMouseButton; + if (state.HasFlag(GdkModifierType.Button3Mask)) + rv |= InputModifiers.MiddleMouseButton; + return rv; + } + + private unsafe bool OnButton(IntPtr w, IntPtr ev, IntPtr userdata) + { + var evnt = (GdkEventButton*)ev; + var e = new RawMouseEventArgs( + Gtk3Platform.Mouse, + evnt->time, + _inputRoot, + evnt->type == GdkEventType.ButtonRelease + ? evnt->button == 1 + ? RawMouseEventType.LeftButtonUp + : evnt->button == 3 ? RawMouseEventType.RightButtonUp : RawMouseEventType.MiddleButtonUp + : evnt->button == 1 + ? RawMouseEventType.LeftButtonDown + : evnt->button == 3 ? RawMouseEventType.RightButtonDown : RawMouseEventType.MiddleButtonDown, + new Point(evnt->x, evnt->y), GetModifierKeys(evnt->state)); + Input?.Invoke(e); + return false; + } + void Connect(string name, T handler) => _disposables.Add(Signal.Connect(GtkWidget, name, handler)); private bool OnDraw(IntPtr gtkwidget, IntPtr cairocontext, IntPtr userdata) { - Debug.WriteLine("Draw"); Paint?.Invoke(new Rect(ClientSize)); return true; } @@ -49,8 +101,6 @@ namespace Avalonia.Gtk3 //TODO } - public abstract Size ClientSize { get; set; } - public Size MaxClientSize { get @@ -71,9 +121,10 @@ namespace Avalonia.Gtk3 public Action Deactivated { get; set; } //TODO public Action Input { get; set; } //TODO public Action Paint { get; set; } - public Action Resized { get; set; } //TODO + public Action Resized { get; set; } public Action ScalingChanged { get; set; } //TODO - public Action PositionChanged { get; set; } //TODO + public Action PositionChanged { get; set; } + public void Activate() { throw new NotImplementedException(); @@ -88,12 +139,17 @@ namespace Avalonia.Gtk3 public Point PointToClient(Point point) { - throw new NotImplementedException(); + int x, y; + Native.GdkWindowGetOrigin(Native.GtkWidgetGetWindow(GtkWidget), out x, out y); + + return new Point(point.X - x, point.Y - y); } public Point PointToScreen(Point point) { - throw new NotImplementedException(); + int x, y; + Native.GdkWindowGetOrigin(Native.GtkWidgetGetWindow(GtkWidget), out x, out y); + return new Point(point.X + x, point.Y + y); } public void SetCursor(IPlatformHandle cursor) @@ -115,7 +171,28 @@ namespace Avalonia.Gtk3 //STUB } - public Point Position { get; set; } + + public Size ClientSize + { + get + { + int w, h; + Native.GtkWindowGetSize(GtkWidget, out w, out h); + return new Size(w, h); + } + set { Native.GtkWindowResize(GtkWidget, (int)value.Width, (int)value.Height); } + } + + public Point Position + { + get + { + int x, y; + Native.GtkWindowGetPosition(GtkWidget, out x, out y); + return new Point(x, y); + } + set { Native.GtkWindowMove(GtkWidget, (int)value.X, (int)value.Y); } + } IntPtr IPlatformHandle.Handle => Native.GetNativeGdkWindowHandle(Native.GtkWidgetGetWindow(GtkWidget)); public IEnumerable Surfaces => new object[] {Handle}; diff --git a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs index 2cd1c5fd6a..b8c561c56c 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs @@ -31,17 +31,6 @@ namespace Avalonia.Gtk3 { } - public override Size ClientSize - { - get - { - int w, h; - Native.GtkWindowGetSize(GtkWidget, out w, out h); - return new Size(w, h); - } - set { Native.GtkWindowResize(GtkWidget, (int) value.Width, (int) value.Height); } - } - public void SetCoverTaskbarWhenMaximized(bool enable) { //Why do we even have that?