RemoteWidget.cs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using Avalonia.Media;
  4. using Avalonia.Media.Imaging;
  5. using Avalonia.Remote.Protocol;
  6. using Avalonia.Remote.Protocol.Viewport;
  7. using Avalonia.Threading;
  8. using PixelFormat = Avalonia.Platform.PixelFormat;
  9. namespace Avalonia.Controls.Remote
  10. {
  11. public class RemoteWidget : Control
  12. {
  13. private readonly IAvaloniaRemoteTransportConnection _connection;
  14. private FrameMessage _lastFrame;
  15. private WriteableBitmap _bitmap;
  16. public RemoteWidget(IAvaloniaRemoteTransportConnection connection)
  17. {
  18. _connection = connection;
  19. _connection.OnMessage += (t, msg) => Dispatcher.UIThread.Post(() => OnMessage(msg));
  20. _connection.Send(new ClientSupportedPixelFormatsMessage
  21. {
  22. Formats = new[]
  23. {
  24. Avalonia.Remote.Protocol.Viewport.PixelFormat.Bgra8888,
  25. Avalonia.Remote.Protocol.Viewport.PixelFormat.Rgba8888,
  26. }
  27. });
  28. }
  29. private void OnMessage(object msg)
  30. {
  31. if (msg is FrameMessage frame)
  32. {
  33. _connection.Send(new FrameReceivedMessage
  34. {
  35. SequenceId = frame.SequenceId
  36. });
  37. _lastFrame = frame;
  38. InvalidateVisual();
  39. }
  40. }
  41. protected override void ArrangeCore(Rect finalRect)
  42. {
  43. _connection.Send(new ClientViewportAllocatedMessage
  44. {
  45. Width = finalRect.Width,
  46. Height = finalRect.Height,
  47. DpiX = 96,
  48. DpiY = 96 //TODO: Somehow detect the actual DPI
  49. });
  50. base.ArrangeCore(finalRect);
  51. }
  52. public override void Render(DrawingContext context)
  53. {
  54. if (_lastFrame != null)
  55. {
  56. var fmt = (PixelFormat) _lastFrame.Format;
  57. if (_bitmap == null || _bitmap.PixelWidth != _lastFrame.Width ||
  58. _bitmap.PixelHeight != _lastFrame.Height)
  59. _bitmap = new WriteableBitmap(_lastFrame.Width, _lastFrame.Height, fmt);
  60. using (var l = _bitmap.Lock())
  61. {
  62. var lineLen = (fmt == PixelFormat.Rgb565 ? 2 : 4) * _lastFrame.Width;
  63. for (var y = 0; y < _lastFrame.Height; y++)
  64. Marshal.Copy(_lastFrame.Data, y * _lastFrame.Stride,
  65. new IntPtr(l.Address.ToInt64() + l.RowBytes * y), lineLen);
  66. }
  67. context.DrawImage(_bitmap, 1, new Rect(0, 0, _bitmap.PixelWidth, _bitmap.PixelHeight),
  68. new Rect(Bounds.Size));
  69. }
  70. base.Render(context);
  71. }
  72. }
  73. }