RemoteWidget.cs 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  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. public enum SizingMode
  14. {
  15. Local,
  16. Remote
  17. }
  18. private readonly IAvaloniaRemoteTransportConnection _connection;
  19. private FrameMessage _lastFrame;
  20. private WriteableBitmap _bitmap;
  21. public RemoteWidget(IAvaloniaRemoteTransportConnection connection)
  22. {
  23. Mode = SizingMode.Local;
  24. _connection = connection;
  25. _connection.OnMessage += (t, msg) => Dispatcher.UIThread.Post(() => OnMessage(msg));
  26. _connection.Send(new ClientSupportedPixelFormatsMessage
  27. {
  28. Formats = new[]
  29. {
  30. Avalonia.Remote.Protocol.Viewport.PixelFormat.Bgra8888,
  31. Avalonia.Remote.Protocol.Viewport.PixelFormat.Rgba8888,
  32. }
  33. });
  34. }
  35. public SizingMode Mode { get; set; }
  36. private void OnMessage(object msg)
  37. {
  38. if (msg is FrameMessage frame)
  39. {
  40. _connection.Send(new FrameReceivedMessage
  41. {
  42. SequenceId = frame.SequenceId
  43. });
  44. _lastFrame = frame;
  45. InvalidateVisual();
  46. }
  47. }
  48. protected override void ArrangeCore(Rect finalRect)
  49. {
  50. if (Mode == SizingMode.Local)
  51. {
  52. _connection.Send(new ClientViewportAllocatedMessage
  53. {
  54. Width = finalRect.Width,
  55. Height = finalRect.Height,
  56. DpiX = 10 * 96,
  57. DpiY = 10 * 96 //TODO: Somehow detect the actual DPI
  58. });
  59. }
  60. base.ArrangeCore(finalRect);
  61. }
  62. public override void Render(DrawingContext context)
  63. {
  64. if (_lastFrame != null)
  65. {
  66. var fmt = (PixelFormat) _lastFrame.Format;
  67. if (_bitmap == null || _bitmap.PixelSize.Width != _lastFrame.Width ||
  68. _bitmap.PixelSize.Height != _lastFrame.Height)
  69. _bitmap = new WriteableBitmap(new PixelSize(_lastFrame.Width, _lastFrame.Height), new Vector(96, 96), fmt);
  70. using (var l = _bitmap.Lock())
  71. {
  72. var lineLen = (fmt == PixelFormat.Rgb565 ? 2 : 4) * _lastFrame.Width;
  73. for (var y = 0; y < _lastFrame.Height; y++)
  74. Marshal.Copy(_lastFrame.Data, y * _lastFrame.Stride,
  75. new IntPtr(l.Address.ToInt64() + l.RowBytes * y), lineLen);
  76. }
  77. context.DrawImage(_bitmap, 1, new Rect(0, 0, _bitmap.PixelSize.Width, _bitmap.PixelSize.Height),
  78. new Rect(Bounds.Size));
  79. }
  80. base.Render(context);
  81. }
  82. }
  83. }