using System; using System.Collections.Generic; using System.Reflection; using Avalonia.Controls; using Avalonia.Controls.Platform; using Avalonia.FreeDesktop; using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.OpenGL; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.X11; using Avalonia.X11.Glx; using Avalonia.X11.NativeDialogs; using static Avalonia.X11.XLib; namespace Avalonia.X11 { class AvaloniaX11Platform : IWindowingPlatform { private Lazy _keyboardDevice = new Lazy(() => new KeyboardDevice()); public KeyboardDevice KeyboardDevice => _keyboardDevice.Value; public Dictionary> Windows = new Dictionary>(); public XI2Manager XI2; public X11Info Info { get; private set; } public IX11Screens X11Screens { get; private set; } public IScreenImpl Screens { get; private set; } public X11PlatformOptions Options { get; private set; } public void Initialize(X11PlatformOptions options) { Options = options; XInitThreads(); Display = XOpenDisplay(IntPtr.Zero); DeferredDisplay = XOpenDisplay(IntPtr.Zero); if (Display == IntPtr.Zero) throw new Exception("XOpenDisplay failed"); XError.Init(); Info = new X11Info(Display, DeferredDisplay); //TODO: log if (options.UseDBusMenu) DBusHelper.TryInitialize(); AvaloniaLocator.CurrentMutable.BindToSelf(this) .Bind().ToConstant(this) .Bind().ToConstant(new X11PlatformThreading(this)) .Bind().ToConstant(new DefaultRenderTimer(60)) .Bind().ToConstant(new RenderLoop()) .Bind().ToConstant(new PlatformHotkeyConfiguration(KeyModifiers.Control)) .Bind().ToFunc(() => KeyboardDevice) .Bind().ToConstant(new X11CursorFactory(Display)) .Bind().ToConstant(new X11Clipboard(this)) .Bind().ToConstant(new PlatformSettingsStub()) .Bind().ToConstant(new X11IconLoader(Info)) .Bind().ToConstant(new GtkSystemDialog()) .Bind().ToConstant(new LinuxMountedVolumeInfoProvider()); X11Screens = Avalonia.X11.X11Screens.Init(this); Screens = new X11Screens(X11Screens); if (Info.XInputVersion != null) { var xi2 = new XI2Manager(); if (xi2.Init(this)) XI2 = xi2; } if (options.UseGpu) { if (options.UseEGL) EglGlPlatformFeature.TryInitialize(); else GlxGlPlatformFeature.TryInitialize(Info, Options.GlProfiles); } } public IntPtr DeferredDisplay { get; set; } public IntPtr Display { get; set; } public IWindowImpl CreateWindow() { return new X11Window(this, null); } public IEmbeddableWindowImpl CreateEmbeddableWindow() { throw new NotSupportedException(); } } } namespace Avalonia { public class X11PlatformOptions { public bool UseEGL { get; set; } public bool UseGpu { get; set; } = true; public bool OverlayPopups { get; set; } public bool UseDBusMenu { get; set; } public bool UseDeferredRendering { get; set; } = true; public List GlProfiles { get; set; } = new List { new GlVersion(GlProfileType.OpenGL, 4, 0), new GlVersion(GlProfileType.OpenGL, 3, 2), new GlVersion(GlProfileType.OpenGL, 3, 0), new GlVersion(GlProfileType.OpenGLES, 3, 2), new GlVersion(GlProfileType.OpenGLES, 3, 0), new GlVersion(GlProfileType.OpenGLES, 2, 0) }; public List GlxRendererBlacklist { get; set; } = new List { // llvmpipe is a software GL rasterizer. If it's returned by glGetString, // that usually means that something in the system is horribly misconfigured // and sometimes attempts to use GLX might cause a segfault "llvmpipe" }; public string WmClass { get; set; } = Assembly.GetEntryAssembly()?.GetName()?.Name ?? "AvaloniaApplication"; public bool? EnableMultiTouch { get; set; } } public static class AvaloniaX11PlatformExtensions { public static T UseX11(this T builder) where T : AppBuilderBase, new() { builder.UseWindowingSubsystem(() => new AvaloniaX11Platform().Initialize(AvaloniaLocator.Current.GetService() ?? new X11PlatformOptions())); return builder; } public static void InitializeX11Platform(X11PlatformOptions options = null) => new AvaloniaX11Platform().Initialize(options ?? new X11PlatformOptions()); } }