diff --git a/samples/ControlCatalog/DecoratedWindow.xaml.cs b/samples/ControlCatalog/DecoratedWindow.xaml.cs
index 4a11e45519..d28281e476 100644
--- a/samples/ControlCatalog/DecoratedWindow.xaml.cs
+++ b/samples/ControlCatalog/DecoratedWindow.xaml.cs
@@ -33,8 +33,8 @@ namespace ControlCatalog
};
SetupSide("Left", StandardCursorType.LeftSide, WindowEdge.West);
SetupSide("Right", StandardCursorType.RightSide, WindowEdge.East);
- SetupSide("Top", StandardCursorType.TopSide, WindowEdge.South);
- SetupSide("Bottom", StandardCursorType.BottomSize, WindowEdge.North);
+ SetupSide("Top", StandardCursorType.TopSide, WindowEdge.North);
+ SetupSide("Bottom", StandardCursorType.BottomSize, WindowEdge.South);
SetupSide("TopLeft", StandardCursorType.TopLeftCorner, WindowEdge.NorthWest);
SetupSide("TopRight", StandardCursorType.TopRightCorner, WindowEdge.NorthEast);
SetupSide("BottomLeft", StandardCursorType.BottomLeftCorner, WindowEdge.SouthWest);
diff --git a/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj b/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj
index 43816fc801..d5aa038b0e 100644
--- a/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj
+++ b/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj
@@ -3,6 +3,9 @@
netstandard2.0
True
+
+
+
diff --git a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs b/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs
index c2a5e15b44..2744474214 100644
--- a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs
+++ b/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs
@@ -22,6 +22,11 @@ namespace Avalonia.MonoMac
View = new TopLevelView(this);
}
+ protected virtual void OnInput(RawInputEventArgs args)
+ {
+ Input?.Invoke(args);
+ }
+
[Adopts("NSTextInputClient")]
public class TopLevelView : NSView
{
@@ -135,11 +140,11 @@ namespace Avalonia.MonoMac
if (delta.X == 0 && delta.Y == 0)
return;
// ReSharper restore CompareOfFloatsByEqualityOperator
- _tl.Input?.Invoke(new RawMouseWheelEventArgs(_mouse, ts, _tl.InputRoot, loc,
+ _tl.OnInput(new RawMouseWheelEventArgs(_mouse, ts, _tl.InputRoot, loc,
delta, mod));
}
else
- _tl.Input?.Invoke(new RawMouseEventArgs(_mouse, ts, _tl.InputRoot, type, loc, mod));
+ _tl.OnInput(new RawMouseEventArgs(_mouse, ts, _tl.InputRoot, type, loc, mod));
}
public override void MouseMoved(NSEvent theEvent)
@@ -229,7 +234,7 @@ namespace Avalonia.MonoMac
var code = KeyTransform.TransformKeyCode(ev.KeyCode);
if (!code.HasValue)
return;
- _tl.Input?.Invoke(new RawKeyEventArgs(_keyboard, GetTimeStamp(ev),
+ _tl.OnInput(new RawKeyEventArgs(_keyboard, GetTimeStamp(ev),
type, code.Value, GetModifiers(ev.ModifierFlags)));
}
@@ -294,7 +299,7 @@ namespace Avalonia.MonoMac
public void InsertText(NSString str, NSRange range)
{
//TODO: timestamp
- _tl.Input?.Invoke(new RawTextInputEventArgs(_keyboard, 0, str.ToString()));
+ _tl.OnInput(new RawTextInputEventArgs(_keyboard, 0, str.ToString()));
}
[Export("characterIndexForPoint:")]
diff --git a/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs b/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs
index 8e2569efb4..dbced9fd91 100644
--- a/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs
+++ b/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs
@@ -1,5 +1,6 @@
using System;
using Avalonia.Controls;
+using Avalonia.Input.Raw;
using Avalonia.Platform;
using MonoMac.AppKit;
using MonoMac.CoreGraphics;
@@ -9,10 +10,12 @@ namespace Avalonia.MonoMac
{
class WindowBaseImpl : TopLevelImpl, IWindowBaseImpl
{
+ private readonly ManagedWindowResizeDragHelper _managedDrag;
public CustomWindow Window { get; private set; }
public WindowBaseImpl()
{
+ _managedDrag = new ManagedWindowResizeDragHelper(this, _ => { }, ResizeForManagedDrag);
Window = new CustomWindow(this)
{
StyleMask = NSWindowStyle.Titled,
@@ -92,7 +95,7 @@ namespace Avalonia.MonoMac
public Point Position
{
get => Window.Frame.ToAvaloniaRect().BottomLeft.ConvertPointY();
- set => Window.CascadeTopLeftFromPoint(value.ToMonoMacPoint().ConvertPointY());
+ set => Window.SetFrameTopLeftPoint(value.ToMonoMacPoint().ConvertPointY());
}
@@ -126,11 +129,25 @@ namespace Avalonia.MonoMac
public void BeginResizeDrag(WindowEdge edge)
{
- //TODO: Intercept mouse events and implement resize drag manually
+ var screenPoint = NSEvent.CurrentMouseLocation.ConvertPointY().ToAvaloniaPoint();
+ _managedDrag.BeginResizeDrag(edge, PointToClient(screenPoint));
+ }
+
+ protected override void OnInput(RawInputEventArgs args)
+ {
+ if (_managedDrag.PreprocessInputEvent(ref args))
+ return;
+ base.OnInput(args);
}
public void Activate() => Window.MakeKeyWindow();
+ public void ResizeForManagedDrag(Rect rc)
+ {
+ var frame = new CGRect(rc.X, rc.Position.ConvertPointY().Y - rc.Height, rc.Width, rc.Height);
+ Window.SetFrame(frame, true);
+ }
+
public void Resize(Size clientSize)
{
var pos = Position;
diff --git a/src/Shared/WindowResizeDragHelper.cs b/src/Shared/WindowResizeDragHelper.cs
new file mode 100644
index 0000000000..c133e493fa
--- /dev/null
+++ b/src/Shared/WindowResizeDragHelper.cs
@@ -0,0 +1,85 @@
+using System;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+using Avalonia.Platform;
+
+namespace Avalonia
+{
+ internal class ManagedWindowResizeDragHelper
+ {
+ private readonly IWindowBaseImpl _window;
+ private readonly Action _captureMouse;
+ private readonly Action _resize;
+ private WindowEdge? _edge;
+ private Point _prevPoint;
+
+ public ManagedWindowResizeDragHelper(IWindowBaseImpl window, Action captureMouse, Action resize = null)
+ {
+ _window = window;
+ _captureMouse = captureMouse;
+ _resize = resize;
+ }
+
+ public void BeginResizeDrag(WindowEdge edge, Point currentMousePosition)
+ {
+ _captureMouse(true);
+ _prevPoint = currentMousePosition;
+ _edge = edge;
+ }
+
+ public bool PreprocessInputEvent(ref RawInputEventArgs e)
+ {
+ if (_edge == null)
+ return false;
+ if (e is RawMouseEventArgs args)
+ {
+ if (args.Type == RawMouseEventType.LeftButtonUp)
+ {
+ _edge = null;
+ _captureMouse(false);
+ }
+ if (args.Type == RawMouseEventType.Move)
+ {
+ MoveWindow(args.Position);
+ return true;
+ }
+
+
+ _edge = null;
+ }
+
+ return false;
+ }
+
+ private void MoveWindow(Point position)
+ {
+ var diff = position - _prevPoint;
+ var edge = _edge.Value;
+ var rc = new Rect(_window.Position, _window.ClientSize);
+ if (edge == WindowEdge.East || edge == WindowEdge.NorthEast || edge == WindowEdge.SouthEast)
+ {
+ rc = rc.WithWidth(rc.Width + diff.X);
+ _prevPoint = _prevPoint.WithX(position.X);
+ }
+ if (edge == WindowEdge.West || edge == WindowEdge.NorthWest || edge == WindowEdge.SouthWest)
+ rc = rc.WithX(rc.X + diff.X).WithWidth(rc.Width - diff.X);
+ if (edge == WindowEdge.South || edge == WindowEdge.SouthWest || edge == WindowEdge.SouthEast)
+ {
+ rc = rc.WithHeight(rc.Height + diff.Y);
+ _prevPoint = _prevPoint.WithY(position.Y);
+ }
+ if (edge == WindowEdge.North || edge == WindowEdge.NorthWest || edge == WindowEdge.NorthEast)
+ rc = rc.WithY(rc.Y + diff.Y).WithHeight(rc.Height - diff.Y);
+ if (_resize != null)
+ _resize(rc);
+ else
+ {
+ if (_window.Position != rc.Position)
+ _window.Position = rc.Position;
+ if (_window.ClientSize != rc.Size)
+ _window.Resize(rc.Size);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.Shared.projitems b/src/Windows/Avalonia.Win32/Avalonia.Win32.Shared.projitems
index 74a2b83efe..4599a0741e 100644
--- a/src/Windows/Avalonia.Win32/Avalonia.Win32.Shared.projitems
+++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.Shared.projitems
@@ -24,6 +24,7 @@
+
Properties\SharedAssemblyInfo.cs
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index 72485379a7..cdbb66d0fc 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -38,9 +38,21 @@ namespace Avalonia.Win32
private double _scaling = 1;
private WindowState _showWindowState;
private FramebufferManager _framebuffer;
+#if USE_MANAGED_DRAG
+ private readonly ManagedWindowResizeDragHelper _managedDrag;
+#endif
public WindowImpl()
{
+#if USE_MANAGED_DRAG
+ _managedDrag = new ManagedWindowResizeDragHelper(this, capture =>
+ {
+ if (capture)
+ UnmanagedMethods.SetCapture(Handle.Handle);
+ else
+ UnmanagedMethods.ReleaseCapture();
+ });
+#endif
CreateWindow();
_framebuffer = new FramebufferManager(_hwnd);
s_instances.Add(this);
@@ -327,8 +339,12 @@ namespace Avalonia.Win32
public void BeginResizeDrag(WindowEdge edge)
{
+#if USE_MANAGED_DRAG
+ _managedDrag.BeginResizeDrag(edge, ScreenToClient(MouseDevice.Position));
+#else
UnmanagedMethods.DefWindowProc(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN,
new IntPtr((int)EdgeDic[edge]), IntPtr.Zero);
+#endif
}
public Point Position
@@ -583,6 +599,11 @@ namespace Avalonia.Win32
PositionChanged?.Invoke(new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)));
return IntPtr.Zero;
}
+#if USE_MANAGED_DRAG
+
+ if (_managedDrag.PreprocessInputEvent(ref e))
+ return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);
+#endif
if (e != null && Input != null)
{