WindowImplBase.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. using System;
  2. using System.Collections.Generic;
  3. using Avalonia.Controls;
  4. using Avalonia.Controls.Platform.Surfaces;
  5. using Avalonia.Input;
  6. using Avalonia.Input.Raw;
  7. using Avalonia.Native.Interop;
  8. using Avalonia.Platform;
  9. using Avalonia.Rendering;
  10. using Avalonia.Threading;
  11. namespace Avalonia.Native
  12. {
  13. public class WindowBaseImpl : IWindowBaseImpl, IFramebufferPlatformSurface
  14. {
  15. IInputRoot _inputRoot;
  16. IAvnWindowBase _native;
  17. private object _syncRoot = new object();
  18. private bool _deferredRendering = true;
  19. private readonly IMouseDevice _mouse;
  20. private readonly IKeyboardDevice _keyboard;
  21. private readonly IStandardCursorFactory _cursorFactory;
  22. private Size _savedLogicalSize;
  23. private Size _lastRenderedLogicalSize;
  24. private double _savedScaling;
  25. public WindowBaseImpl()
  26. {
  27. _keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
  28. _mouse = AvaloniaLocator.Current.GetService<IMouseDevice>();
  29. _cursorFactory = AvaloniaLocator.Current.GetService<IStandardCursorFactory>();
  30. }
  31. protected void Init(IAvnWindowBase window, IAvnScreens screens)
  32. {
  33. _native = window;
  34. Screen = new ScreenImpl(screens);
  35. _savedLogicalSize = ClientSize;
  36. _savedScaling = Scaling;
  37. }
  38. public Size ClientSize
  39. {
  40. get
  41. {
  42. var s = _native.GetClientSize();
  43. return new Size(s.Width, s.Height);
  44. }
  45. }
  46. SavedFramebuffer _framebuffer;
  47. public IEnumerable<object> Surfaces => new[] { this };
  48. public ILockedFramebuffer Lock()
  49. {
  50. if(_deferredRendering)
  51. {
  52. var w = _savedLogicalSize.Width * _savedScaling;
  53. var h = _savedLogicalSize.Height * _savedScaling;
  54. var dpi = _savedScaling * 96;
  55. return new DeferredFramebuffer(cb =>
  56. {
  57. lock (_syncRoot)
  58. {
  59. if (_native == null)
  60. return false;
  61. cb(_native);
  62. _lastRenderedLogicalSize = _savedLogicalSize;
  63. return true;
  64. }
  65. }, (int)w, (int)h, new Vector(dpi, dpi));
  66. }
  67. var fb = _framebuffer;
  68. _framebuffer = null;
  69. if (fb == null)
  70. throw new InvalidOperationException("Lock call without corresponding Paint event");
  71. return fb;
  72. }
  73. public Action<Rect> Paint { get; set; }
  74. public Action<Size> Resized { get; set; }
  75. public Action Closed { get; set; }
  76. public IMouseDevice MouseDevice => AvaloniaNativePlatform.MouseDevice;
  77. class SavedFramebuffer : ILockedFramebuffer
  78. {
  79. public IntPtr Address { get; set; }
  80. public int Width { get; set; }
  81. public int Height { get; set; }
  82. public int RowBytes {get;set;}
  83. public Vector Dpi { get; set; }
  84. public PixelFormat Format => PixelFormat.Rgba8888;
  85. public void Dispose()
  86. {
  87. // Do nothing
  88. }
  89. }
  90. protected class WindowBaseEvents : CallbackBase, IAvnWindowBaseEvents
  91. {
  92. private readonly WindowBaseImpl _parent;
  93. public WindowBaseEvents(WindowBaseImpl parent)
  94. {
  95. _parent = parent;
  96. }
  97. void IAvnWindowBaseEvents.Closed() => _parent.Closed?.Invoke();
  98. void IAvnWindowBaseEvents.Activated() => _parent.Activated?.Invoke();
  99. void IAvnWindowBaseEvents.Deactivated() => _parent.Deactivated?.Invoke();
  100. void IAvnWindowBaseEvents.SoftwareDraw(ref AvnFramebuffer fb)
  101. {
  102. Dispatcher.UIThread.RunJobs(DispatcherPriority.Render);
  103. _parent._framebuffer = new SavedFramebuffer
  104. {
  105. Address = fb.Data,
  106. RowBytes = fb.Stride,
  107. Width = fb.Width,
  108. Height = fb.Height,
  109. Dpi = new Vector(fb.Dpi.X, fb.Dpi.Y)
  110. };
  111. _parent.Paint?.Invoke(new Rect(0, 0, fb.Width / (fb.Dpi.X / 96), fb.Height / (fb.Dpi.Y / 96)));
  112. }
  113. void IAvnWindowBaseEvents.Resized(AvnSize size)
  114. {
  115. var s = new Size(size.Width, size.Height);
  116. _parent._savedLogicalSize = s;
  117. _parent.Resized?.Invoke(s);
  118. }
  119. void IAvnWindowBaseEvents.PositionChanged(AvnPoint position)
  120. {
  121. _parent.PositionChanged?.Invoke(position.ToAvaloniaPoint());
  122. }
  123. void IAvnWindowBaseEvents.RawMouseEvent(AvnRawMouseEventType type, uint timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta)
  124. {
  125. _parent.RawMouseEvent(type, timeStamp, modifiers, point, delta);
  126. }
  127. bool IAvnWindowBaseEvents.RawKeyEvent(AvnRawKeyEventType type, uint timeStamp, AvnInputModifiers modifiers, uint key)
  128. {
  129. return _parent.RawKeyEvent(type, timeStamp, modifiers, key);
  130. }
  131. bool IAvnWindowBaseEvents.RawTextInputEvent(uint timeStamp, string text)
  132. {
  133. return _parent.RawTextInputEvent(timeStamp, text);
  134. }
  135. void IAvnWindowBaseEvents.ScalingChanged(double scaling)
  136. {
  137. _parent._savedScaling = scaling;
  138. _parent.ScalingChanged?.Invoke(scaling);
  139. }
  140. void IAvnWindowBaseEvents.RunRenderPriorityJobs()
  141. {
  142. if (_parent._deferredRendering
  143. && _parent._lastRenderedLogicalSize != _parent.ClientSize)
  144. // Hack to trigger Paint event on the renderer
  145. _parent.Paint?.Invoke(new Rect());
  146. Dispatcher.UIThread.RunJobs(DispatcherPriority.Render);
  147. }
  148. }
  149. public void Activate()
  150. {
  151. _native.Activate();
  152. }
  153. public bool RawTextInputEvent(uint timeStamp, string text)
  154. {
  155. var args = new RawTextInputEventArgs(_keyboard, timeStamp, text);
  156. Input?.Invoke(args);
  157. return args.Handled;
  158. }
  159. public bool RawKeyEvent(AvnRawKeyEventType type, uint timeStamp, AvnInputModifiers modifiers, uint key)
  160. {
  161. var args = new RawKeyEventArgs(_keyboard, timeStamp, (RawKeyEventType)type, (Key)key, (InputModifiers)modifiers);
  162. Input?.Invoke(args);
  163. return args.Handled;
  164. }
  165. public void RawMouseEvent(AvnRawMouseEventType type, uint timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta)
  166. {
  167. Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
  168. switch (type)
  169. {
  170. case AvnRawMouseEventType.Wheel:
  171. Input?.Invoke(new RawMouseWheelEventArgs(_mouse, timeStamp, _inputRoot, point.ToAvaloniaPoint(), new Vector(delta.X, delta.Y), (InputModifiers)modifiers));
  172. break;
  173. default:
  174. Input?.Invoke(new RawMouseEventArgs(_mouse, timeStamp, _inputRoot, (RawMouseEventType)type, point.ToAvaloniaPoint(), (InputModifiers)modifiers));
  175. break;
  176. }
  177. }
  178. public void Resize(Size clientSize)
  179. {
  180. _native.Resize(clientSize.Width, clientSize.Height);
  181. }
  182. public IRenderer CreateRenderer(IRenderRoot root)
  183. {
  184. if(_deferredRendering)
  185. return new DeferredRendererProxy(root);
  186. return new ImmediateRenderer(root);
  187. }
  188. public virtual void Dispose()
  189. {
  190. _native.Close();
  191. _native.Dispose();
  192. _native = null;
  193. (Screen as ScreenImpl)?.Dispose();
  194. }
  195. public void Invalidate(Rect rect)
  196. {
  197. if (!_deferredRendering)
  198. _native.Invalidate(new AvnRect { Height = rect.Height, Width = rect.Width, X = rect.X, Y = rect.Y });
  199. }
  200. public void SetInputRoot(IInputRoot inputRoot)
  201. {
  202. _inputRoot = inputRoot;
  203. }
  204. public void Show()
  205. {
  206. _native.Show();
  207. }
  208. public Point Position
  209. {
  210. get => _native.GetPosition().ToAvaloniaPoint();
  211. set => _native.SetPosition(value.ToAvnPoint());
  212. }
  213. public Point PointToClient(Point point)
  214. {
  215. return _native.PointToClient(point.ToAvnPoint()).ToAvaloniaPoint();
  216. }
  217. public Point PointToScreen(Point point)
  218. {
  219. return _native.PointToScreen(point.ToAvnPoint()).ToAvaloniaPoint();
  220. }
  221. public void Hide()
  222. {
  223. _native.Hide();
  224. }
  225. public void BeginMoveDrag()
  226. {
  227. _native.BeginMoveDrag();
  228. }
  229. public Size MaxClientSize => _native.GetMaxClientSize().ToAvaloniaSize();
  230. public void SetTopmost(bool value)
  231. {
  232. _native.SetTopMost(value);
  233. }
  234. public double Scaling => _native.GetScaling();
  235. public Action Deactivated { get; set; }
  236. public Action Activated { get; set; }
  237. #region Stubs
  238. public Action<Point> PositionChanged { get; set; }
  239. public Action<RawInputEventArgs> Input { get; set; }
  240. Action<double> ScalingChanged { get; set; }
  241. public IPlatformHandle Handle => new PlatformHandle(IntPtr.Zero, "NOT SUPPORTED");
  242. public IScreenImpl Screen { get; private set; }
  243. Action<double> ITopLevelImpl.ScalingChanged { get; set; }
  244. public void SetMinMaxSize(Size minSize, Size maxSize)
  245. {
  246. }
  247. public void SetCursor(IPlatformHandle cursor)
  248. {
  249. var newCursor = cursor as AvaloniaNativeCursor;
  250. newCursor = newCursor ?? (_cursorFactory.GetCursor(StandardCursorType.Arrow) as AvaloniaNativeCursor);
  251. _native.Cursor = newCursor.Cursor;
  252. }
  253. public void BeginResizeDrag(WindowEdge edge)
  254. {
  255. }
  256. #endregion
  257. }
  258. }