Gtk3Platform.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.Threading;
  4. using Avalonia.Controls;
  5. using Avalonia.Controls.Platform;
  6. using Avalonia.Gtk3;
  7. using Avalonia.Gtk3.Interop;
  8. using Avalonia.Input;
  9. using Avalonia.Input.Platform;
  10. using Avalonia.OpenGL;
  11. using Avalonia.Platform;
  12. using Avalonia.Platform.Interop;
  13. using Avalonia.Rendering;
  14. using Avalonia.Threading;
  15. namespace Avalonia.Gtk3
  16. {
  17. public class Gtk3Platform : IWindowingPlatform, IPlatformSettings, IPlatformThreadingInterface
  18. {
  19. internal static readonly Gtk3Platform Instance = new Gtk3Platform();
  20. internal static readonly MouseDevice Mouse = new MouseDevice();
  21. internal static readonly KeyboardDevice Keyboard = new KeyboardDevice();
  22. internal static IntPtr App { get; set; }
  23. internal static string DisplayClassName;
  24. public static bool UseDeferredRendering = true;
  25. private static bool s_gtkInitialized;
  26. static bool EnvOption(string option, bool def, bool? specified)
  27. {
  28. bool? Parse(string env)
  29. {
  30. var v = Environment.GetEnvironmentVariable("AVALONIA_GTK3_" + env);
  31. if (v == null)
  32. return null;
  33. if (v.ToLowerInvariant() == "false" || v == "0")
  34. return false;
  35. return true;
  36. }
  37. var overridden = Parse(option + "_OVERRIDE");
  38. if (overridden.HasValue)
  39. return overridden.Value;
  40. if (specified.HasValue)
  41. return specified.Value;
  42. var envValue = Parse(option);
  43. return envValue ?? def;
  44. }
  45. public static void Initialize(Gtk3PlatformOptions options)
  46. {
  47. Resolver.Custom = options.CustomResolver;
  48. UseDeferredRendering = EnvOption("USE_DEFERRED_RENDERING", true, options.UseDeferredRendering);
  49. var useGpu = EnvOption("USE_GPU", true, options.UseGpuAcceleration);
  50. if (!s_gtkInitialized)
  51. {
  52. try
  53. {
  54. X11.XInitThreads();
  55. }catch{}
  56. Resolver.Resolve();
  57. if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  58. using (var backends = new Utf8Buffer("x11"))
  59. Native.GdkSetAllowedBackends?.Invoke(backends);
  60. Native.GtkInit(0, IntPtr.Zero);
  61. var disp = Native.GdkGetDefaultDisplay();
  62. DisplayClassName =
  63. Utf8Buffer.StringFromPtr(Native.GTypeName(Marshal.ReadIntPtr(Marshal.ReadIntPtr(disp))));
  64. using (var utf = new Utf8Buffer($"avalonia.app.a{Guid.NewGuid().ToString("N")}"))
  65. App = Native.GtkApplicationNew(utf, 0);
  66. //Mark current thread as UI thread
  67. s_tlsMarker = true;
  68. s_gtkInitialized = true;
  69. }
  70. AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatform>().ToConstant(Instance)
  71. .Bind<IClipboard>().ToSingleton<ClipboardImpl>()
  72. .Bind<IStandardCursorFactory>().ToConstant(new CursorFactory())
  73. .Bind<IKeyboardDevice>().ToConstant(Keyboard)
  74. .Bind<IPlatformSettings>().ToConstant(Instance)
  75. .Bind<IPlatformThreadingInterface>().ToConstant(Instance)
  76. .Bind<ISystemDialogImpl>().ToSingleton<SystemDialog>()
  77. .Bind<IRenderLoop>().ToConstant(new RenderLoop())
  78. .Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
  79. .Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
  80. .Bind<IPlatformIconLoader>().ToConstant(new PlatformIconLoader());
  81. if (useGpu)
  82. EglGlPlatformFeature.TryInitialize();
  83. }
  84. public IWindowImpl CreateWindow() => new WindowImpl();
  85. public IEmbeddableWindowImpl CreateEmbeddableWindow()
  86. {
  87. throw new NotImplementedException();
  88. }
  89. public IPopupImpl CreatePopup() => new PopupImpl();
  90. public Size DoubleClickSize => new Size(4, 4);
  91. public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(100); //STUB
  92. public double RenderScalingFactor { get; } = 1;
  93. public double LayoutScalingFactor { get; } = 1;
  94. public void RunLoop(CancellationToken cancellationToken)
  95. {
  96. while (!cancellationToken.IsCancellationRequested)
  97. Native.GtkMainIteration();
  98. }
  99. public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
  100. {
  101. var msec = interval.TotalMilliseconds;
  102. var imsec = (uint) msec;
  103. if (imsec == 0)
  104. imsec = 1;
  105. return GlibTimeout.StartTimer(GlibPriority.FromDispatcherPriority(priority), imsec, tick);
  106. }
  107. private bool[] _signaled = new bool[(int) DispatcherPriority.MaxValue + 1];
  108. object _lock = new object();
  109. public void Signal(DispatcherPriority prio)
  110. {
  111. var idx = (int) prio;
  112. lock(_lock)
  113. if (!_signaled[idx])
  114. {
  115. _signaled[idx] = true;
  116. GlibTimeout.Add(GlibPriority.FromDispatcherPriority(prio), 0, () =>
  117. {
  118. lock (_lock)
  119. {
  120. _signaled[idx] = false;
  121. }
  122. Signaled?.Invoke(prio);
  123. return false;
  124. });
  125. }
  126. }
  127. public event Action<DispatcherPriority?> Signaled;
  128. [ThreadStatic]
  129. private static bool s_tlsMarker;
  130. public bool CurrentThreadIsLoopThread => s_tlsMarker;
  131. }
  132. public class Gtk3PlatformOptions
  133. {
  134. public bool? UseDeferredRendering { get; set; }
  135. public bool? UseGpuAcceleration { get; set; }
  136. public ICustomGtk3NativeLibraryResolver CustomResolver { get; set; }
  137. }
  138. }
  139. namespace Avalonia
  140. {
  141. public static class Gtk3AppBuilderExtensions
  142. {
  143. public static T UseGtk3<T>(this AppBuilderBase<T> builder, Gtk3PlatformOptions options = null)
  144. where T : AppBuilderBase<T>, new()
  145. {
  146. return builder.UseWindowingSubsystem(() => Gtk3Platform.Initialize(options ?? new Gtk3PlatformOptions()),
  147. "GTK3");
  148. }
  149. }
  150. }