1
0

LinuxFramebufferPlatform.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. using System;
  2. using System.Diagnostics;
  3. using System.Threading;
  4. using Avalonia.Controls;
  5. using Avalonia.Controls.ApplicationLifetimes;
  6. using Avalonia.Controls.Embedding;
  7. using Avalonia.Controls.Platform;
  8. using Avalonia.Input;
  9. using Avalonia.Input.Platform;
  10. using Avalonia.LinuxFramebuffer;
  11. using Avalonia.LinuxFramebuffer.Input;
  12. using Avalonia.LinuxFramebuffer.Input.EvDev;
  13. using Avalonia.LinuxFramebuffer.Input.LibInput;
  14. using Avalonia.LinuxFramebuffer.Output;
  15. using Avalonia.OpenGL;
  16. using Avalonia.Platform;
  17. using Avalonia.Rendering;
  18. using Avalonia.Rendering.Composition;
  19. using Avalonia.Threading;
  20. using JetBrains.Annotations;
  21. namespace Avalonia.LinuxFramebuffer
  22. {
  23. class LinuxFramebufferPlatform
  24. {
  25. IOutputBackend _fb;
  26. private static readonly Stopwatch St = Stopwatch.StartNew();
  27. internal static uint Timestamp => (uint)St.ElapsedTicks;
  28. public static InternalPlatformThreadingInterface Threading;
  29. internal static Compositor Compositor { get; private set; }
  30. LinuxFramebufferPlatform(IOutputBackend backend)
  31. {
  32. _fb = backend;
  33. }
  34. void Initialize()
  35. {
  36. Threading = new InternalPlatformThreadingInterface();
  37. if (_fb is IGlOutputBackend gl)
  38. AvaloniaLocator.CurrentMutable.Bind<IPlatformOpenGlInterface>().ToConstant(gl.PlatformOpenGlInterface);
  39. var opts = AvaloniaLocator.Current.GetService<LinuxFramebufferPlatformOptions>() ?? new LinuxFramebufferPlatformOptions();
  40. AvaloniaLocator.CurrentMutable
  41. .Bind<IPlatformThreadingInterface>().ToConstant(Threading)
  42. .Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(opts.Fps))
  43. .Bind<IRenderLoop>().ToConstant(new RenderLoop())
  44. .Bind<ICursorFactory>().ToTransient<CursorFactoryStub>()
  45. .Bind<IKeyboardDevice>().ToConstant(new KeyboardDevice())
  46. .Bind<IPlatformSettings>().ToSingleton<PlatformSettings>()
  47. .Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
  48. Compositor = new Compositor(
  49. AvaloniaLocator.Current.GetRequiredService<IRenderLoop>(),
  50. AvaloniaLocator.Current.GetService<IPlatformOpenGlInterface>());
  51. }
  52. internal static LinuxFramebufferLifetime Initialize<T>(T builder, IOutputBackend outputBackend) where T : AppBuilderBase<T>, new()
  53. {
  54. var platform = new LinuxFramebufferPlatform(outputBackend);
  55. builder.UseSkia().UseWindowingSubsystem(platform.Initialize, "fbdev");
  56. return new LinuxFramebufferLifetime(platform._fb);
  57. }
  58. }
  59. class LinuxFramebufferLifetime : IControlledApplicationLifetime, ISingleViewApplicationLifetime
  60. {
  61. private readonly IOutputBackend _fb;
  62. [CanBeNull] private readonly IInputBackend _inputBackend;
  63. private TopLevel _topLevel;
  64. private readonly CancellationTokenSource _cts = new CancellationTokenSource();
  65. public CancellationToken Token => _cts.Token;
  66. public LinuxFramebufferLifetime(IOutputBackend fb)
  67. {
  68. _fb = fb;
  69. }
  70. public LinuxFramebufferLifetime(IOutputBackend fb, IInputBackend input)
  71. {
  72. _fb = fb;
  73. _inputBackend = input;
  74. }
  75. public Control MainView
  76. {
  77. get => (Control)_topLevel?.Content;
  78. set
  79. {
  80. if (_topLevel == null)
  81. {
  82. var inputBackend = _inputBackend;
  83. if (inputBackend == null)
  84. {
  85. if (Environment.GetEnvironmentVariable("AVALONIA_USE_EVDEV") == "1")
  86. inputBackend = EvDevBackend.CreateFromEnvironment();
  87. else
  88. inputBackend = new LibInputBackend();
  89. }
  90. var tl = new EmbeddableControlRoot(new FramebufferToplevelImpl(_fb, inputBackend));
  91. tl.Prepare();
  92. _topLevel = tl;
  93. _topLevel.Renderer.Start();
  94. if (_topLevel is IFocusScope scope)
  95. {
  96. FocusManager.Instance?.SetFocusScope(scope);
  97. }
  98. }
  99. _topLevel.Content = value;
  100. }
  101. }
  102. public int ExitCode { get; private set; }
  103. public event EventHandler<ControlledApplicationLifetimeStartupEventArgs> Startup;
  104. public event EventHandler<ControlledApplicationLifetimeExitEventArgs> Exit;
  105. public void Start(string[] args)
  106. {
  107. Startup?.Invoke(this, new ControlledApplicationLifetimeStartupEventArgs(args));
  108. }
  109. public void Shutdown(int exitCode)
  110. {
  111. ExitCode = exitCode;
  112. var e = new ControlledApplicationLifetimeExitEventArgs(exitCode);
  113. Exit?.Invoke(this, e);
  114. ExitCode = e.ApplicationExitCode;
  115. _cts.Cancel();
  116. }
  117. }
  118. }
  119. public static class LinuxFramebufferPlatformExtensions
  120. {
  121. public static int StartLinuxFbDev<T>(this T builder, string[] args, string fbdev = null, double scaling = 1)
  122. where T : AppBuilderBase<T>, new() =>
  123. StartLinuxDirect(builder, args, new FbdevOutput(fileName: fbdev, format: null) { Scaling = scaling });
  124. public static int StartLinuxFbDev<T>(this T builder, string[] args, string fbdev, PixelFormat? format, double scaling)
  125. where T : AppBuilderBase<T>, new() =>
  126. StartLinuxDirect(builder, args, new FbdevOutput(fileName: fbdev, format: format) { Scaling = scaling });
  127. public static int StartLinuxDrm<T>(this T builder, string[] args, string card = null, double scaling = 1)
  128. where T : AppBuilderBase<T>, new() => StartLinuxDirect(builder, args, new DrmOutput(card) {Scaling = scaling});
  129. public static int StartLinuxDrm<T>(this T builder, string[] args, string card = null, bool connectorsForceProbe = false, [CanBeNull] DrmOutputOptions options = null)
  130. where T : AppBuilderBase<T>, new() => StartLinuxDirect(builder, args, new DrmOutput(card, connectorsForceProbe, options));
  131. public static int StartLinuxDirect<T>(this T builder, string[] args, IOutputBackend backend)
  132. where T : AppBuilderBase<T>, new()
  133. {
  134. var lifetime = LinuxFramebufferPlatform.Initialize(builder, backend);
  135. builder.SetupWithLifetime(lifetime);
  136. lifetime.Start(args);
  137. builder.Instance.Run(lifetime.Token);
  138. return lifetime.ExitCode;
  139. }
  140. }