Program.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. using System;
  2. using System.Diagnostics;
  3. using System.Globalization;
  4. using System.Linq;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using Avalonia;
  8. using Avalonia.Controls;
  9. using Avalonia.Controls.ApplicationLifetimes;
  10. using Avalonia.Fonts.Inter;
  11. using Avalonia.Headless;
  12. using Avalonia.LinuxFramebuffer.Output;
  13. using Avalonia.LogicalTree;
  14. using Avalonia.Rendering.Composition;
  15. using Avalonia.Threading;
  16. using Avalonia.Vulkan;
  17. using ControlCatalog.Pages;
  18. namespace ControlCatalog.NetCore
  19. {
  20. static class Program
  21. {
  22. private static bool s_useFramebuffer;
  23. [STAThread]
  24. static int Main(string[] args)
  25. {
  26. if (args.Contains("--fbdev"))
  27. {
  28. s_useFramebuffer = true;
  29. }
  30. if (args.Contains("--wait-for-attach"))
  31. {
  32. Console.WriteLine("Attach debugger and use 'Set next statement'");
  33. while (true)
  34. {
  35. Thread.Sleep(100);
  36. if (Debugger.IsAttached)
  37. break;
  38. }
  39. }
  40. var builder = BuildAvaloniaApp();
  41. double GetScaling()
  42. {
  43. var idx = Array.IndexOf(args, "--scaling");
  44. if (idx != 0 && args.Length > idx + 1 &&
  45. double.TryParse(args[idx + 1], NumberStyles.Any, CultureInfo.InvariantCulture, out var scaling))
  46. return scaling;
  47. return 1;
  48. }
  49. if (s_useFramebuffer)
  50. {
  51. SilenceConsole();
  52. return builder.StartLinuxFbDev(args, new FbDevOutputOptions()
  53. {
  54. Scaling = GetScaling()
  55. });
  56. }
  57. else if (args.Contains("--vnc"))
  58. {
  59. return builder.StartWithHeadlessVncPlatform(null, 5901, args, ShutdownMode.OnMainWindowClose);
  60. }
  61. else if (args.Contains("--full-headless"))
  62. {
  63. return builder
  64. .UseHeadless(new AvaloniaHeadlessPlatformOptions
  65. {
  66. UseHeadlessDrawing = true
  67. })
  68. .AfterSetup(_ =>
  69. {
  70. DispatcherTimer.RunOnce(async () =>
  71. {
  72. var window = ((IClassicDesktopStyleApplicationLifetime)Application.Current.ApplicationLifetime)
  73. .MainWindow;
  74. var tc = window.GetLogicalDescendants().OfType<TabControl>().First();
  75. foreach (var page in tc.Items.Cast<TabItem>().ToList())
  76. {
  77. if (page.Header.ToString() == "DatePicker" || page.Header.ToString() == "TreeView")
  78. continue;
  79. Console.WriteLine("Selecting " + page.Header);
  80. tc.SelectedItem = page;
  81. await Task.Delay(50);
  82. }
  83. Console.WriteLine("Selecting the first page");
  84. tc.SelectedItem = tc.Items.OfType<object>().First();
  85. await Task.Delay(500);
  86. Console.WriteLine("Clicked through all pages, triggering GC");
  87. for (var c = 0; c < 3; c++)
  88. {
  89. GC.Collect(2, GCCollectionMode.Forced);
  90. await Task.Delay(50);
  91. }
  92. void FormatMem(string metric, long bytes)
  93. {
  94. Console.WriteLine(metric + ": " + bytes / 1024 / 1024 + "MB");
  95. }
  96. FormatMem("GC allocated bytes", GC.GetTotalMemory(true));
  97. FormatMem("WorkingSet64", Process.GetCurrentProcess().WorkingSet64);
  98. }, TimeSpan.FromSeconds(1));
  99. })
  100. .StartWithClassicDesktopLifetime(args);
  101. }
  102. else if (args.Contains("--drm"))
  103. {
  104. SilenceConsole();
  105. return builder.StartLinuxDrm(args, scaling: GetScaling());
  106. }
  107. else if (args.Contains("--dxgi"))
  108. {
  109. builder.With(new Win32PlatformOptions()
  110. {
  111. CompositionMode = new [] { Win32CompositionMode.LowLatencyDxgiSwapChain }
  112. });
  113. return builder.StartWithClassicDesktopLifetime(args);
  114. }
  115. else
  116. return builder.StartWithClassicDesktopLifetime(args);
  117. }
  118. /// <summary>
  119. /// This method is needed for IDE previewer infrastructure
  120. /// </summary>
  121. public static AppBuilder BuildAvaloniaApp()
  122. => AppBuilder.Configure<App>()
  123. .UsePlatformDetect()
  124. .With(new X11PlatformOptions
  125. {
  126. EnableMultiTouch = true,
  127. UseDBusMenu = true,
  128. EnableIme = true,
  129. })
  130. .With(new VulkanOptions
  131. {
  132. VulkanInstanceCreationOptions = new ()
  133. {
  134. UseDebug = true
  135. }
  136. })
  137. .With(new CompositionOptions()
  138. {
  139. UseRegionDirtyRectClipping = true
  140. })
  141. .UseSkia()
  142. .WithInterFont()
  143. .AfterSetup(builder =>
  144. {
  145. if (!s_useFramebuffer)
  146. {
  147. builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions()
  148. {
  149. StartupScreenIndex = 1,
  150. });
  151. }
  152. EmbedSample.Implementation = OperatingSystem.IsWindows() ? (INativeDemoControl)new EmbedSampleWin()
  153. : OperatingSystem.IsMacOS() ? new EmbedSampleMac()
  154. : OperatingSystem.IsLinux() ? new EmbedSampleGtk()
  155. : null;
  156. })
  157. .LogToTrace();
  158. static void SilenceConsole()
  159. {
  160. new Thread(() =>
  161. {
  162. Console.CursorVisible = false;
  163. while (true)
  164. Console.ReadKey(true);
  165. })
  166. { IsBackground = true }.Start();
  167. }
  168. }
  169. }