using System; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Fonts.Inter; using Avalonia.Headless; using Avalonia.LinuxFramebuffer.Output; using Avalonia.Logging; using Avalonia.LogicalTree; using Avalonia.Rendering.Composition; using Avalonia.Threading; using Avalonia.Vulkan; using ControlCatalog.Pages; namespace ControlCatalog.NetCore { static class Program { private static bool s_useFramebuffer; [STAThread] static int Main(string[] args) { if (args.Contains("--fbdev")) { s_useFramebuffer = true; } if (args.Contains("--wait-for-attach")) { Console.WriteLine("Attach debugger and use 'Set next statement'"); while (true) { Thread.Sleep(100); if (Debugger.IsAttached) break; } } var builder = BuildAvaloniaApp(); if (args.FirstOrDefault(x => x.StartsWith("--log-level=")) is { } logLevelArg) { var levelStr = logLevelArg.Substring("--log-level=".Length); if (Enum.TryParse(levelStr, true, out var level)) { string[] areas = []; if (args.FirstOrDefault(x => x.StartsWith("--log-areas=")) is { } logAreasArg) { var areasStr = logAreasArg.Substring("--log-areas=".Length); areas = areasStr.Split(',', StringSplitOptions.RemoveEmptyEntries); } var l = new object(); builder.LogToDelegate(s => { lock (l) Console.WriteLine(s); }, level, areas); } } else builder.LogToTrace(); double GetScaling() { var idx = Array.IndexOf(args, "--scaling"); if (idx != 0 && args.Length > idx + 1 && double.TryParse(args[idx + 1], NumberStyles.Any, CultureInfo.InvariantCulture, out var scaling)) return scaling; return 1; } if (s_useFramebuffer) { SilenceConsole(); return builder.StartLinuxFbDev(args, new FbDevOutputOptions() { Scaling = GetScaling() }); } else if (args.Contains("--vnc")) { return builder.StartWithHeadlessVncPlatform(null, 5901, args, ShutdownMode.OnMainWindowClose); } else if (args.Contains("--full-headless")) { return builder .UseHeadless(new AvaloniaHeadlessPlatformOptions { UseHeadlessDrawing = true }) .AfterSetup(_ => { DispatcherTimer.RunOnce(async () => { var window = ((IClassicDesktopStyleApplicationLifetime)Application.Current.ApplicationLifetime) .MainWindow; var tc = window.GetLogicalDescendants().OfType().First(); foreach (var page in tc.Items.Cast().ToList()) { if (page.Header.ToString() == "DatePicker" || page.Header.ToString() == "TreeView") continue; Console.WriteLine("Selecting " + page.Header); tc.SelectedItem = page; await Task.Delay(50); } Console.WriteLine("Selecting the first page"); tc.SelectedItem = tc.Items.OfType().First(); await Task.Delay(500); Console.WriteLine("Clicked through all pages, triggering GC"); for (var c = 0; c < 3; c++) { GC.Collect(2, GCCollectionMode.Forced); await Task.Delay(50); } void FormatMem(string metric, long bytes) { Console.WriteLine(metric + ": " + bytes / 1024 / 1024 + "MB"); } FormatMem("GC allocated bytes", GC.GetTotalMemory(true)); FormatMem("WorkingSet64", Process.GetCurrentProcess().WorkingSet64); }, TimeSpan.FromSeconds(1)); }) .StartWithClassicDesktopLifetime(args); } else if (args.Contains("--drm")) { SilenceConsole(); return builder.StartLinuxDrm(args, scaling: GetScaling()); } else if (args.Contains("--dxgi")) { builder.With(new Win32PlatformOptions() { CompositionMode = new [] { Win32CompositionMode.LowLatencyDxgiSwapChain } }); return builder.StartWithClassicDesktopLifetime(args); } else return builder.StartWithClassicDesktopLifetime(args); } /// /// This method is needed for IDE previewer infrastructure /// public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .With(new X11PlatformOptions { EnableMultiTouch = true, UseDBusMenu = true, EnableIme = true, RenderingMode = new []{X11RenderingMode.OffscreenGbmEgl} }) .With(new VulkanOptions { VulkanInstanceCreationOptions = new() { UseDebug = true, VulkanVersion = new Version(1, 3 ) }, VulkanDeviceCreationOptions = { AllowDevicesWithoutKhrSurfaces = true } }) .With(new CompositionOptions() { UseRegionDirtyRectClipping = true }) .UseSkia() .WithInterFont() .AfterSetup(builder => { if (!s_useFramebuffer) { builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions() { StartupScreenIndex = 1, }); } EmbedSample.Implementation = OperatingSystem.IsWindows() ? (INativeDemoControl)new EmbedSampleWin() : OperatingSystem.IsMacOS() ? new EmbedSampleMac() : OperatingSystem.IsLinux() ? new EmbedSampleGtk() : null; }); static void SilenceConsole() { new Thread(() => { Console.CursorVisible = false; while (true) Console.ReadKey(true); }) { IsBackground = true }.Start(); } } }