WindowBaseImpl.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. using System;
  2. using Avalonia.Controls;
  3. using Avalonia.Input.Raw;
  4. using Avalonia.Platform;
  5. using MonoMac.AppKit;
  6. using MonoMac.CoreGraphics;
  7. using MonoMac.Foundation;
  8. using MonoMac.ObjCRuntime;
  9. namespace Avalonia.MonoMac
  10. {
  11. class WindowBaseImpl : TopLevelImpl, IWindowBaseImpl
  12. {
  13. private readonly ManagedWindowResizeDragHelper _managedDrag;
  14. public CustomWindow Window { get; private set; }
  15. public WindowBaseImpl()
  16. {
  17. _managedDrag = new ManagedWindowResizeDragHelper(this, _ => { }, ResizeForManagedDrag);
  18. Window = new CustomWindow(this)
  19. {
  20. StyleMask = NSWindowStyle.Titled,
  21. BackingType = NSBackingStore.Buffered,
  22. ContentView = View,
  23. // ReSharper disable once VirtualMemberCallInConstructor
  24. Delegate = CreateWindowDelegate()
  25. };
  26. }
  27. public class CustomWindow : NSWindow
  28. {
  29. readonly WindowBaseImpl _impl;
  30. public CustomWindow(WindowBaseImpl impl)
  31. {
  32. _impl = impl;
  33. }
  34. public override void BecomeKeyWindow()
  35. {
  36. _impl.Activated?.Invoke();
  37. base.BecomeKeyWindow();
  38. }
  39. public override void ResignKeyWindow()
  40. {
  41. _impl.Deactivated?.Invoke();
  42. base.ResignKeyWindow();
  43. }
  44. private bool _canBecomeKeyAndMain;
  45. public override bool CanBecomeKeyWindow => _canBecomeKeyAndMain;
  46. public override bool CanBecomeMainWindow => _canBecomeKeyAndMain;
  47. public void SetCanBecomeKeyAndMain() => _canBecomeKeyAndMain = true;
  48. }
  49. protected virtual NSWindowDelegate CreateWindowDelegate() => new WindowBaseDelegate(this);
  50. public class WindowBaseDelegate : NSWindowDelegate
  51. {
  52. readonly WindowBaseImpl _impl;
  53. public WindowBaseDelegate(WindowBaseImpl impl)
  54. {
  55. _impl = impl;
  56. }
  57. public override void DidMoved(global::MonoMac.Foundation.NSNotification notification)
  58. {
  59. _impl.PositionChanged?.Invoke(_impl.Position);
  60. }
  61. public override bool WindowShouldClose(NSObject sender)
  62. {
  63. bool? preventClose = _impl.Closing?.Invoke();
  64. return preventClose != true;
  65. }
  66. public override void WillClose(global::MonoMac.Foundation.NSNotification notification)
  67. {
  68. _impl.Window.Dispose();
  69. _impl.Window = null;
  70. _impl.Dispose();
  71. }
  72. public override CGRect WillUseStandardFrame(NSWindow window, CGRect newFrame)
  73. {
  74. if (_impl is WindowImpl w && w.UndecoratedIsMaximized && w.UndecoratedLastUnmaximizedFrame.HasValue)
  75. return w.UndecoratedLastUnmaximizedFrame.Value;
  76. return window.Screen.VisibleFrame;
  77. }
  78. public override bool ShouldZoom(NSWindow window, CGRect newFrame)
  79. {
  80. return true;
  81. }
  82. }
  83. public Point Position
  84. {
  85. get => Window.Frame.ToAvaloniaRect().BottomLeft.ConvertPointY();
  86. set => Window.SetFrameTopLeftPoint(value.ToMonoMacPoint().ConvertPointY());
  87. }
  88. protected virtual NSWindowStyle GetStyle() => NSWindowStyle.Borderless;
  89. protected void UpdateStyle() => Window.StyleMask = GetStyle();
  90. IPlatformHandle IWindowBaseImpl.Handle => new PlatformHandle(Window.Handle, "NSWindow");
  91. public Size MaxClientSize => NSScreen.Screens[0].Frame.ToAvaloniaRect().Size;
  92. public Action<Point> PositionChanged { get; set; }
  93. public Action Deactivated { get; set; }
  94. public Action Activated { get; set; }
  95. public Func<bool> Closing { get; set; }
  96. public override Size ClientSize => Window.ContentRectFor(Window.Frame).Size.ToAvaloniaSize();
  97. public void Show() => Window.MakeKeyAndOrderFront(Window);
  98. public void Hide() => Window?.OrderOut(Window);
  99. public void BeginMoveDrag()
  100. {
  101. var ev = View.LastMouseDownEvent;
  102. if (ev == null)
  103. return;
  104. var handle = Selector.GetHandle("performWindowDragWithEvent:");
  105. Messaging.void_objc_msgSend_IntPtr(Window.Handle, handle, ev.Handle);
  106. }
  107. public void BeginResizeDrag(WindowEdge edge)
  108. {
  109. var screenPoint = NSEvent.CurrentMouseLocation.ConvertPointY().ToAvaloniaPoint();
  110. _managedDrag.BeginResizeDrag(edge, PointToClient(screenPoint));
  111. }
  112. protected override void OnInput(RawInputEventArgs args)
  113. {
  114. if (_managedDrag.PreprocessInputEvent(ref args))
  115. return;
  116. base.OnInput(args);
  117. }
  118. public void Activate() => Window.MakeKeyWindow();
  119. public void ResizeForManagedDrag(Rect rc)
  120. {
  121. var frame = new CGRect(rc.X, rc.Position.ConvertPointY().Y - rc.Height, rc.Width, rc.Height);
  122. Window.SetFrame(frame, true);
  123. }
  124. public void Resize(Size clientSize)
  125. {
  126. var pos = Position;
  127. Window.SetContentSize(clientSize.ToMonoMacSize());
  128. Position = pos;
  129. }
  130. public void SetMinMaxSize(Size minSize, Size maxSize)
  131. {
  132. }
  133. public IScreenImpl Screen
  134. {
  135. get;
  136. } = new ScreenImpl();
  137. public override Point PointToClient(Point point)
  138. {
  139. var cocoaScreenPoint = point.ToMonoMacPoint().ConvertPointY();
  140. var cocoaViewPoint = Window.ConvertScreenToBase(cocoaScreenPoint).ToAvaloniaPoint();
  141. return View.TranslateLocalPoint(cocoaViewPoint);
  142. }
  143. public override Point PointToScreen(Point point)
  144. {
  145. var cocoaViewPoint = View.TranslateLocalPoint(point).ToMonoMacPoint();
  146. var cocoaScreenPoint = Window.ConvertBaseToScreen(cocoaViewPoint);
  147. return cocoaScreenPoint.ConvertPointY().ToAvaloniaPoint();
  148. }
  149. public override void Dispose()
  150. {
  151. Window?.Close();
  152. Window?.Dispose();
  153. base.Dispose();
  154. }
  155. }
  156. }