WindowImplBase.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using Avalonia.Controls;
  7. using Avalonia.Controls.Platform.Surfaces;
  8. using Avalonia.Input;
  9. using Avalonia.Input.Raw;
  10. using Avalonia.Native.Interop;
  11. using Avalonia.OpenGL;
  12. using Avalonia.Platform;
  13. using Avalonia.Rendering;
  14. using Avalonia.Threading;
  15. namespace Avalonia.Native
  16. {
  17. public class MacOSTopLevelWindowHandle : IPlatformHandle, IMacOSTopLevelPlatformHandle
  18. {
  19. IAvnWindowBase _native;
  20. public MacOSTopLevelWindowHandle(IAvnWindowBase native)
  21. {
  22. _native = native;
  23. }
  24. public IntPtr Handle => NSWindow;
  25. public string HandleDescriptor => "NSWindow";
  26. public IntPtr NSView => _native.ObtainNSViewHandle();
  27. public IntPtr NSWindow => _native.ObtainNSWindowHandle();
  28. public IntPtr GetNSViewRetained()
  29. {
  30. return _native.ObtainNSViewHandleRetained();
  31. }
  32. public IntPtr GetNSWindowRetained()
  33. {
  34. return _native.ObtainNSWindowHandleRetained();
  35. }
  36. }
  37. public abstract class WindowBaseImpl : IWindowBaseImpl,
  38. IFramebufferPlatformSurface
  39. {
  40. IInputRoot _inputRoot;
  41. IAvnWindowBase _native;
  42. private object _syncRoot = new object();
  43. private bool _deferredRendering = false;
  44. private bool _gpu = false;
  45. private readonly MouseDevice _mouse;
  46. private readonly IKeyboardDevice _keyboard;
  47. private readonly IStandardCursorFactory _cursorFactory;
  48. private Size _savedLogicalSize;
  49. private Size _lastRenderedLogicalSize;
  50. private double _savedScaling;
  51. private GlPlatformSurface _glSurface;
  52. internal WindowBaseImpl(AvaloniaNativePlatformOptions opts, GlPlatformFeature glFeature)
  53. {
  54. _gpu = opts.UseGpu && glFeature != null;
  55. _deferredRendering = opts.UseDeferredRendering;
  56. _keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
  57. _mouse = new MouseDevice();
  58. _cursorFactory = AvaloniaLocator.Current.GetService<IStandardCursorFactory>();
  59. }
  60. protected void Init(IAvnWindowBase window, IAvnScreens screens)
  61. {
  62. _native = window;
  63. Handle = new MacOSTopLevelWindowHandle(window);
  64. if (_gpu)
  65. _glSurface = new GlPlatformSurface(window);
  66. Screen = new ScreenImpl(screens);
  67. _savedLogicalSize = ClientSize;
  68. _savedScaling = Scaling;
  69. var monitor = Screen.AllScreens.OrderBy(x => x.PixelDensity)
  70. .FirstOrDefault(m => m.Bounds.Contains(Position));
  71. Resize(new Size(monitor.WorkingArea.Width * 0.75d, monitor.WorkingArea.Height * 0.7d));
  72. }
  73. public Size ClientSize
  74. {
  75. get
  76. {
  77. var s = _native.GetClientSize();
  78. return new Size(s.Width, s.Height);
  79. }
  80. }
  81. public IEnumerable<object> Surfaces => new[] {
  82. (_gpu ? _glSurface : (object)null),
  83. this
  84. };
  85. public ILockedFramebuffer Lock()
  86. {
  87. var w = _savedLogicalSize.Width * _savedScaling;
  88. var h = _savedLogicalSize.Height * _savedScaling;
  89. var dpi = _savedScaling * 96;
  90. return new DeferredFramebuffer(cb =>
  91. {
  92. lock (_syncRoot)
  93. {
  94. if (_native == null)
  95. return false;
  96. cb(_native);
  97. _lastRenderedLogicalSize = _savedLogicalSize;
  98. return true;
  99. }
  100. }, (int)w, (int)h, new Vector(dpi, dpi));
  101. }
  102. public Action<Rect> Paint { get; set; }
  103. public Action<Size> Resized { get; set; }
  104. public Action Closed { get; set; }
  105. public IMouseDevice MouseDevice => _mouse;
  106. public abstract IPopupImpl CreatePopup();
  107. protected class WindowBaseEvents : CallbackBase, IAvnWindowBaseEvents
  108. {
  109. private readonly WindowBaseImpl _parent;
  110. public WindowBaseEvents(WindowBaseImpl parent)
  111. {
  112. _parent = parent;
  113. }
  114. void IAvnWindowBaseEvents.Closed()
  115. {
  116. var n = _parent._native;
  117. _parent._native = null;
  118. try
  119. {
  120. _parent?.Closed?.Invoke();
  121. }
  122. finally
  123. {
  124. n?.Dispose();
  125. }
  126. _parent._mouse.Dispose();
  127. }
  128. void IAvnWindowBaseEvents.Activated() => _parent.Activated?.Invoke();
  129. void IAvnWindowBaseEvents.Deactivated() => _parent.Deactivated?.Invoke();
  130. void IAvnWindowBaseEvents.Paint()
  131. {
  132. Dispatcher.UIThread.RunJobs(DispatcherPriority.Render);
  133. var s = _parent.ClientSize;
  134. _parent.Paint?.Invoke(new Rect(0, 0, s.Width, s.Height));
  135. }
  136. void IAvnWindowBaseEvents.Resized(AvnSize size)
  137. {
  138. var s = new Size(size.Width, size.Height);
  139. _parent._savedLogicalSize = s;
  140. _parent.Resized?.Invoke(s);
  141. }
  142. void IAvnWindowBaseEvents.PositionChanged(AvnPoint position)
  143. {
  144. _parent.PositionChanged?.Invoke(position.ToAvaloniaPixelPoint());
  145. }
  146. void IAvnWindowBaseEvents.RawMouseEvent(AvnRawMouseEventType type, uint timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta)
  147. {
  148. _parent.RawMouseEvent(type, timeStamp, modifiers, point, delta);
  149. }
  150. bool IAvnWindowBaseEvents.RawKeyEvent(AvnRawKeyEventType type, uint timeStamp, AvnInputModifiers modifiers, uint key)
  151. {
  152. return _parent.RawKeyEvent(type, timeStamp, modifiers, key);
  153. }
  154. bool IAvnWindowBaseEvents.RawTextInputEvent(uint timeStamp, string text)
  155. {
  156. return _parent.RawTextInputEvent(timeStamp, text);
  157. }
  158. void IAvnWindowBaseEvents.ScalingChanged(double scaling)
  159. {
  160. _parent._savedScaling = scaling;
  161. _parent.ScalingChanged?.Invoke(scaling);
  162. }
  163. void IAvnWindowBaseEvents.RunRenderPriorityJobs()
  164. {
  165. Dispatcher.UIThread.RunJobs(DispatcherPriority.Render);
  166. }
  167. }
  168. public void Activate()
  169. {
  170. _native.Activate();
  171. }
  172. public bool RawTextInputEvent(uint timeStamp, string text)
  173. {
  174. Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
  175. var args = new RawTextInputEventArgs(_keyboard, timeStamp, _inputRoot, text);
  176. Input?.Invoke(args);
  177. return args.Handled;
  178. }
  179. public bool RawKeyEvent(AvnRawKeyEventType type, uint timeStamp, AvnInputModifiers modifiers, uint key)
  180. {
  181. Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
  182. var args = new RawKeyEventArgs(_keyboard, timeStamp, _inputRoot, (RawKeyEventType)type, (Key)key, (RawInputModifiers)modifiers);
  183. Input?.Invoke(args);
  184. return args.Handled;
  185. }
  186. public void RawMouseEvent(AvnRawMouseEventType type, uint timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta)
  187. {
  188. Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
  189. switch (type)
  190. {
  191. case AvnRawMouseEventType.Wheel:
  192. Input?.Invoke(new RawMouseWheelEventArgs(_mouse, timeStamp, _inputRoot, point.ToAvaloniaPoint(), new Vector(delta.X, delta.Y), (RawInputModifiers)modifiers));
  193. break;
  194. default:
  195. Input?.Invoke(new RawPointerEventArgs(_mouse, timeStamp, _inputRoot, (RawPointerEventType)type, point.ToAvaloniaPoint(), (RawInputModifiers)modifiers));
  196. break;
  197. }
  198. }
  199. public void Resize(Size clientSize)
  200. {
  201. _native.Resize(clientSize.Width, clientSize.Height);
  202. }
  203. public IRenderer CreateRenderer(IRenderRoot root)
  204. {
  205. if (_deferredRendering)
  206. return new DeferredRenderer(root, AvaloniaLocator.Current.GetService<IRenderLoop>());
  207. return new ImmediateRenderer(root);
  208. }
  209. public virtual void Dispose()
  210. {
  211. _native?.Close();
  212. _native?.Dispose();
  213. _native = null;
  214. (Screen as ScreenImpl)?.Dispose();
  215. }
  216. public void Invalidate(Rect rect)
  217. {
  218. if (!_deferredRendering && _native != null)
  219. _native.Invalidate(new AvnRect { Height = rect.Height, Width = rect.Width, X = rect.X, Y = rect.Y });
  220. }
  221. public void SetInputRoot(IInputRoot inputRoot)
  222. {
  223. _inputRoot = inputRoot;
  224. }
  225. public void Show()
  226. {
  227. _native.Show();
  228. }
  229. public PixelPoint Position
  230. {
  231. get => _native.GetPosition().ToAvaloniaPixelPoint();
  232. set => _native.SetPosition(value.ToAvnPoint());
  233. }
  234. public Point PointToClient(PixelPoint point)
  235. {
  236. return _native.PointToClient(point.ToAvnPoint()).ToAvaloniaPoint();
  237. }
  238. public PixelPoint PointToScreen(Point point)
  239. {
  240. return _native.PointToScreen(point.ToAvnPoint()).ToAvaloniaPixelPoint();
  241. }
  242. public void Hide()
  243. {
  244. _native.Hide();
  245. }
  246. public void BeginMoveDrag(PointerPressedEventArgs e)
  247. {
  248. _native.BeginMoveDrag();
  249. }
  250. public Size MaxClientSize => Screen.AllScreens.Select(s => s.Bounds.Size.ToSize(s.PixelDensity))
  251. .OrderByDescending(x => x.Width + x.Height).FirstOrDefault();
  252. public void SetTopmost(bool value)
  253. {
  254. _native.SetTopMost(value);
  255. }
  256. public double Scaling => _native.GetScaling();
  257. public Action Deactivated { get; set; }
  258. public Action Activated { get; set; }
  259. public void SetCursor(IPlatformHandle cursor)
  260. {
  261. if (_native == null)
  262. {
  263. return;
  264. }
  265. var newCursor = cursor as AvaloniaNativeCursor;
  266. newCursor = newCursor ?? (_cursorFactory.GetCursor(StandardCursorType.Arrow) as AvaloniaNativeCursor);
  267. _native.Cursor = newCursor.Cursor;
  268. }
  269. public Action<PixelPoint> PositionChanged { get; set; }
  270. public Action<RawInputEventArgs> Input { get; set; }
  271. Action<double> ScalingChanged { get; set; }
  272. Action<double> ITopLevelImpl.ScalingChanged { get; set; }
  273. public IScreenImpl Screen { get; private set; }
  274. // TODO
  275. public void SetMinMaxSize(Size minSize, Size maxSize)
  276. {
  277. _native.SetMinMaxSize(minSize.ToAvnSize(), maxSize.ToAvnSize());
  278. }
  279. public void BeginResizeDrag(WindowEdge edge, PointerPressedEventArgs e)
  280. {
  281. }
  282. public IPlatformHandle Handle { get; private set; }
  283. }
  284. }