RemoteServerTopLevelImpl.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using Avalonia.Controls.Embedding.Offscreen;
  5. using Avalonia.Controls.Platform.Surfaces;
  6. using Avalonia.Input;
  7. using Avalonia.Input.Raw;
  8. using Avalonia.Layout;
  9. using Avalonia.Platform;
  10. using Avalonia.Remote.Protocol;
  11. using Avalonia.Remote.Protocol.Input;
  12. using Avalonia.Remote.Protocol.Viewport;
  13. using Avalonia.Threading;
  14. using InputModifiers = Avalonia.Input.InputModifiers;
  15. using Key = Avalonia.Input.Key;
  16. using PixelFormat = Avalonia.Platform.PixelFormat;
  17. using ProtocolPixelFormat = Avalonia.Remote.Protocol.Viewport.PixelFormat;
  18. namespace Avalonia.Controls.Remote.Server
  19. {
  20. public class RemoteServerTopLevelImpl : OffscreenTopLevelImplBase, IFramebufferPlatformSurface
  21. {
  22. private readonly IAvaloniaRemoteTransportConnection _transport;
  23. private LockedFramebuffer _framebuffer;
  24. private object _lock = new object();
  25. private long _lastSentFrame = -1;
  26. private long _lastReceivedFrame = -1;
  27. private long _nextFrameNumber = 1;
  28. private ClientViewportAllocatedMessage _pendingAllocation;
  29. private bool _invalidated;
  30. private Vector _dpi = new Vector(96, 96);
  31. private ProtocolPixelFormat[] _supportedFormats;
  32. public RemoteServerTopLevelImpl(IAvaloniaRemoteTransportConnection transport)
  33. {
  34. _transport = transport;
  35. _transport.OnMessage += OnMessage;
  36. KeyboardDevice = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
  37. }
  38. private static RawMouseEventType GetAvaloniaEventType (Avalonia.Remote.Protocol.Input.MouseButton button, bool pressed)
  39. {
  40. switch (button)
  41. {
  42. case Avalonia.Remote.Protocol.Input.MouseButton.Left:
  43. return pressed ? RawMouseEventType.LeftButtonDown : RawMouseEventType.LeftButtonUp;
  44. case Avalonia.Remote.Protocol.Input.MouseButton.Middle:
  45. return pressed ? RawMouseEventType.MiddleButtonDown : RawMouseEventType.MiddleButtonUp;
  46. case Avalonia.Remote.Protocol.Input.MouseButton.Right:
  47. return pressed ? RawMouseEventType.RightButtonDown : RawMouseEventType.RightButtonUp;
  48. default:
  49. return RawMouseEventType.Move;
  50. }
  51. }
  52. private static InputModifiers GetAvaloniaInputModifiers (Avalonia.Remote.Protocol.Input.InputModifiers[] modifiers)
  53. {
  54. var result = InputModifiers.None;
  55. foreach(var modifier in modifiers)
  56. {
  57. switch (modifier)
  58. {
  59. case Avalonia.Remote.Protocol.Input.InputModifiers.Control:
  60. result |= InputModifiers.Control;
  61. break;
  62. case Avalonia.Remote.Protocol.Input.InputModifiers.Alt:
  63. result |= InputModifiers.Alt;
  64. break;
  65. case Avalonia.Remote.Protocol.Input.InputModifiers.Shift:
  66. result |= InputModifiers.Shift;
  67. break;
  68. case Avalonia.Remote.Protocol.Input.InputModifiers.Windows:
  69. result |= InputModifiers.Windows;
  70. break;
  71. case Avalonia.Remote.Protocol.Input.InputModifiers.LeftMouseButton:
  72. result |= InputModifiers.LeftMouseButton;
  73. break;
  74. case Avalonia.Remote.Protocol.Input.InputModifiers.MiddleMouseButton:
  75. result |= InputModifiers.MiddleMouseButton;
  76. break;
  77. case Avalonia.Remote.Protocol.Input.InputModifiers.RightMouseButton:
  78. result |= InputModifiers.RightMouseButton;
  79. break;
  80. }
  81. }
  82. return result;
  83. }
  84. protected virtual void OnMessage(IAvaloniaRemoteTransportConnection transport, object obj)
  85. {
  86. lock (_lock)
  87. {
  88. if (obj is FrameReceivedMessage lastFrame)
  89. {
  90. lock (_lock)
  91. {
  92. _lastReceivedFrame = lastFrame.SequenceId;
  93. }
  94. Dispatcher.UIThread.Post(RenderIfNeeded);
  95. }
  96. if(obj is ClientRenderInfoMessage renderInfo)
  97. {
  98. lock(_lock)
  99. {
  100. _dpi = new Vector(renderInfo.DpiX, renderInfo.DpiY);
  101. _invalidated = true;
  102. }
  103. Dispatcher.UIThread.Post(RenderIfNeeded);
  104. }
  105. if (obj is ClientSupportedPixelFormatsMessage supportedFormats)
  106. {
  107. lock (_lock)
  108. _supportedFormats = supportedFormats.Formats;
  109. Dispatcher.UIThread.Post(RenderIfNeeded);
  110. }
  111. if (obj is MeasureViewportMessage measure)
  112. Dispatcher.UIThread.Post(() =>
  113. {
  114. var m = Measure(new Size(measure.Width, measure.Height));
  115. _transport.Send(new MeasureViewportMessage
  116. {
  117. Width = m.Width,
  118. Height = m.Height
  119. });
  120. });
  121. if (obj is ClientViewportAllocatedMessage allocated)
  122. {
  123. lock (_lock)
  124. {
  125. if (_pendingAllocation == null)
  126. Dispatcher.UIThread.Post(() =>
  127. {
  128. ClientViewportAllocatedMessage allocation;
  129. lock (_lock)
  130. {
  131. allocation = _pendingAllocation;
  132. _pendingAllocation = null;
  133. }
  134. _dpi = new Vector(allocation.DpiX, allocation.DpiY);
  135. ClientSize = new Size(allocation.Width, allocation.Height);
  136. RenderIfNeeded();
  137. });
  138. _pendingAllocation = allocated;
  139. }
  140. }
  141. if(obj is PointerMovedEventMessage pointer)
  142. {
  143. Dispatcher.UIThread.Post(() =>
  144. {
  145. Input?.Invoke(new RawMouseEventArgs(
  146. MouseDevice,
  147. 0,
  148. InputRoot,
  149. RawMouseEventType.Move,
  150. new Point(pointer.X, pointer.Y),
  151. GetAvaloniaInputModifiers(pointer.Modifiers)));
  152. }, DispatcherPriority.Input);
  153. }
  154. if(obj is PointerPressedEventMessage pressed)
  155. {
  156. Dispatcher.UIThread.Post(() =>
  157. {
  158. Input?.Invoke(new RawMouseEventArgs(
  159. MouseDevice,
  160. 0,
  161. InputRoot,
  162. GetAvaloniaEventType(pressed.Button, true),
  163. new Point(pressed.X, pressed.Y),
  164. GetAvaloniaInputModifiers(pressed.Modifiers)));
  165. }, DispatcherPriority.Input);
  166. }
  167. if (obj is PointerPressedEventMessage released)
  168. {
  169. Dispatcher.UIThread.Post(() =>
  170. {
  171. Input?.Invoke(new RawMouseEventArgs(
  172. MouseDevice,
  173. 0,
  174. InputRoot,
  175. GetAvaloniaEventType(released.Button, false),
  176. new Point(released.X, released.Y),
  177. GetAvaloniaInputModifiers(released.Modifiers)));
  178. }, DispatcherPriority.Input);
  179. }
  180. if(obj is ScrollEventMessage scroll)
  181. {
  182. Dispatcher.UIThread.Post(() =>
  183. {
  184. Input?.Invoke(new RawMouseWheelEventArgs(
  185. MouseDevice,
  186. 0,
  187. InputRoot,
  188. new Point(scroll.X, scroll.Y),
  189. new Vector(scroll.DeltaX, scroll.DeltaY),
  190. GetAvaloniaInputModifiers(scroll.Modifiers)));
  191. }, DispatcherPriority.Input);
  192. }
  193. if(obj is KeyEventMessage key)
  194. {
  195. Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
  196. Dispatcher.UIThread.Post(() =>
  197. {
  198. Input?.Invoke(new RawKeyEventArgs(
  199. KeyboardDevice,
  200. 0,
  201. key.IsDown ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
  202. (Key)key.Key,
  203. GetAvaloniaInputModifiers(key.Modifiers)));
  204. }, DispatcherPriority.Input);
  205. }
  206. if(obj is TextInputEventMessage text)
  207. {
  208. Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
  209. Dispatcher.UIThread.Post(() =>
  210. {
  211. Input?.Invoke(new RawTextInputEventArgs(
  212. KeyboardDevice,
  213. 0,
  214. text.Text));
  215. }, DispatcherPriority.Input);
  216. }
  217. }
  218. }
  219. protected void SetDpi(Vector dpi)
  220. {
  221. _dpi = dpi;
  222. RenderIfNeeded();
  223. }
  224. protected virtual Size Measure(Size constraint)
  225. {
  226. var l = (ILayoutable) InputRoot;
  227. l.Measure(constraint);
  228. return l.DesiredSize;
  229. }
  230. public override IEnumerable<object> Surfaces => new[] { this };
  231. FrameMessage RenderFrame(int width, int height, ProtocolPixelFormat? format)
  232. {
  233. var scalingX = _dpi.X / 96.0;
  234. var scalingY = _dpi.Y / 96.0;
  235. width = (int)(width * scalingX);
  236. height = (int)(height * scalingY);
  237. var fmt = format ?? ProtocolPixelFormat.Rgba8888;
  238. var bpp = fmt == ProtocolPixelFormat.Rgb565 ? 2 : 4;
  239. var data = new byte[width * height * bpp];
  240. var handle = GCHandle.Alloc(data, GCHandleType.Pinned);
  241. try
  242. {
  243. _framebuffer = new LockedFramebuffer(handle.AddrOfPinnedObject(), width, height, width * bpp, _dpi, (PixelFormat)fmt,
  244. null);
  245. Paint?.Invoke(new Rect(0, 0, width, height));
  246. }
  247. finally
  248. {
  249. _framebuffer = null;
  250. handle.Free();
  251. }
  252. return new FrameMessage
  253. {
  254. Data = data,
  255. Format = (ProtocolPixelFormat) format,
  256. Width = width,
  257. Height = height,
  258. Stride = width * bpp,
  259. };
  260. }
  261. public ILockedFramebuffer Lock()
  262. {
  263. if (_framebuffer == null)
  264. throw new InvalidOperationException("Paint was not requested, wait for Paint event");
  265. return _framebuffer;
  266. }
  267. protected void RenderIfNeeded()
  268. {
  269. lock (_lock)
  270. {
  271. if (_lastReceivedFrame != _lastSentFrame || !_invalidated || _supportedFormats == null)
  272. return;
  273. }
  274. if (ClientSize.Width < 1 || ClientSize.Height < 1)
  275. return;
  276. var format = ProtocolPixelFormat.Rgba8888;
  277. foreach(var fmt in _supportedFormats)
  278. if (fmt <= ProtocolPixelFormat.MaxValue)
  279. {
  280. format = fmt;
  281. break;
  282. }
  283. var frame = RenderFrame((int) ClientSize.Width, (int) ClientSize.Height, format);
  284. lock (_lock)
  285. {
  286. _lastSentFrame = _nextFrameNumber++;
  287. frame.SequenceId = _lastSentFrame;
  288. _invalidated = false;
  289. }
  290. _transport.Send(frame);
  291. }
  292. public override void Invalidate(Rect rect)
  293. {
  294. _invalidated = true;
  295. Dispatcher.UIThread.Post(RenderIfNeeded);
  296. }
  297. public override IMouseDevice MouseDevice { get; } = new MouseDevice();
  298. public IKeyboardDevice KeyboardDevice { get; }
  299. }
  300. }