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