RemoteServerTopLevelImpl.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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.Layout;
  8. using Avalonia.Platform;
  9. using Avalonia.Remote.Protocol;
  10. using Avalonia.Remote.Protocol.Viewport;
  11. using Avalonia.Threading;
  12. using PixelFormat = Avalonia.Platform.PixelFormat;
  13. using ProtocolPixelFormat = Avalonia.Remote.Protocol.Viewport.PixelFormat;
  14. namespace Avalonia.Controls.Remote.Server
  15. {
  16. public class RemoteServerTopLevelImpl : OffscreenTopLevelImplBase, IFramebufferPlatformSurface
  17. {
  18. private readonly IAvaloniaRemoteTransportConnection _transport;
  19. private LockedFramebuffer _framebuffer;
  20. private object _lock = new object();
  21. private long _lastSentFrame = -1;
  22. private long _lastReceivedFrame = -1;
  23. private long _nextFrameNumber = 1;
  24. private ClientViewportAllocatedMessage _pendingAllocation;
  25. private bool _invalidated;
  26. private Vector _dpi = new Vector(96, 96);
  27. private ProtocolPixelFormat[] _supportedFormats;
  28. public RemoteServerTopLevelImpl(IAvaloniaRemoteTransportConnection transport)
  29. {
  30. _transport = transport;
  31. _transport.OnMessage += OnMessage;
  32. }
  33. protected virtual void OnMessage(IAvaloniaRemoteTransportConnection transport, object obj)
  34. {
  35. lock (_lock)
  36. {
  37. if (obj is FrameReceivedMessage lastFrame)
  38. {
  39. lock (_lock)
  40. {
  41. _lastReceivedFrame = lastFrame.SequenceId;
  42. }
  43. Dispatcher.UIThread.Post(RenderIfNeeded);
  44. }
  45. if (obj is ClientSupportedPixelFormatsMessage supportedFormats)
  46. {
  47. lock (_lock)
  48. _supportedFormats = supportedFormats.Formats;
  49. Dispatcher.UIThread.Post(RenderIfNeeded);
  50. }
  51. if (obj is MeasureViewportMessage measure)
  52. Dispatcher.UIThread.Post(() =>
  53. {
  54. var m = Measure(new Size(measure.Width, measure.Height));
  55. _transport.Send(new MeasureViewportMessage
  56. {
  57. Width = m.Width,
  58. Height = m.Height
  59. });
  60. });
  61. if (obj is ClientViewportAllocatedMessage allocated)
  62. {
  63. lock (_lock)
  64. {
  65. if (_pendingAllocation == null)
  66. Dispatcher.UIThread.Post(() =>
  67. {
  68. ClientViewportAllocatedMessage allocation;
  69. lock (_lock)
  70. {
  71. allocation = _pendingAllocation;
  72. _pendingAllocation = null;
  73. }
  74. _dpi = new Vector(allocation.DpiX, allocation.DpiY);
  75. ClientSize = new Size(allocation.Width, allocation.Height);
  76. RenderIfNeeded();
  77. });
  78. _pendingAllocation = allocated;
  79. }
  80. }
  81. }
  82. }
  83. protected void SetDpi(Vector dpi)
  84. {
  85. _dpi = dpi;
  86. RenderIfNeeded();
  87. }
  88. protected virtual Size Measure(Size constraint)
  89. {
  90. var l = (ILayoutable) InputRoot;
  91. l.Measure(constraint);
  92. return l.DesiredSize;
  93. }
  94. public override IEnumerable<object> Surfaces => new[] { this };
  95. FrameMessage RenderFrame(int width, int height, ProtocolPixelFormat? format)
  96. {
  97. var fmt = format ?? ProtocolPixelFormat.Rgba8888;
  98. var bpp = fmt == ProtocolPixelFormat.Rgb565 ? 2 : 4;
  99. var data = new byte[width * height * bpp];
  100. var handle = GCHandle.Alloc(data, GCHandleType.Pinned);
  101. try
  102. {
  103. _framebuffer = new LockedFramebuffer(handle.AddrOfPinnedObject(), width, height, width * bpp, _dpi, (PixelFormat)fmt,
  104. null);
  105. Paint?.Invoke(new Rect(0, 0, width, height));
  106. }
  107. finally
  108. {
  109. _framebuffer = null;
  110. handle.Free();
  111. }
  112. return new FrameMessage
  113. {
  114. Data = data,
  115. Format = (ProtocolPixelFormat) format,
  116. Width = width,
  117. Height = height,
  118. Stride = width * bpp,
  119. };
  120. }
  121. public ILockedFramebuffer Lock()
  122. {
  123. if (_framebuffer == null)
  124. throw new InvalidOperationException("Paint was not requested, wait for Paint event");
  125. return _framebuffer;
  126. }
  127. protected void RenderIfNeeded()
  128. {
  129. lock (_lock)
  130. {
  131. if (_lastReceivedFrame != _lastSentFrame || !_invalidated || _supportedFormats == null)
  132. return;
  133. }
  134. if (ClientSize.Width < 1 || ClientSize.Height < 1)
  135. return;
  136. var format = ProtocolPixelFormat.Rgba8888;
  137. foreach(var fmt in _supportedFormats)
  138. if (fmt <= ProtocolPixelFormat.MaxValue)
  139. {
  140. format = fmt;
  141. break;
  142. }
  143. var frame = RenderFrame((int) ClientSize.Width, (int) ClientSize.Height, format);
  144. lock (_lock)
  145. {
  146. _lastSentFrame = _nextFrameNumber++;
  147. frame.SequenceId = _lastSentFrame;
  148. _invalidated = false;
  149. }
  150. _transport.Send(frame);
  151. }
  152. public override void Invalidate(Rect rect)
  153. {
  154. _invalidated = true;
  155. Dispatcher.UIThread.Post(RenderIfNeeded);
  156. }
  157. public override IMouseDevice MouseDevice { get; } = new MouseDevice();
  158. }
  159. }