From 16ea1f37621b0400c96e5f4085195ce4a4573b53 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sun, 7 Oct 2018 22:05:00 +0300 Subject: [PATCH 01/46] [X11] Platform threading interface and platform sanity checks --- Avalonia.sln | 54 ++++ samples/PlatformSanityChecks/App.xaml | 6 + samples/PlatformSanityChecks/App.xaml.cs | 13 + .../PlatformSanityChecks.csproj | 24 ++ samples/PlatformSanityChecks/Program.cs | 140 ++++++++++ src/Avalonia.X11/Avalonia.X11.csproj | 12 + src/Avalonia.X11/X11Exception.cs | 12 + src/Avalonia.X11/X11Platform.cs | 39 +++ src/Avalonia.X11/X11PlatformThreading.cs | 251 ++++++++++++++++++ src/Avalonia.X11/XLib.cs | 105 ++++++++ 10 files changed, 656 insertions(+) create mode 100644 samples/PlatformSanityChecks/App.xaml create mode 100644 samples/PlatformSanityChecks/App.xaml.cs create mode 100644 samples/PlatformSanityChecks/PlatformSanityChecks.csproj create mode 100644 samples/PlatformSanityChecks/Program.cs create mode 100644 src/Avalonia.X11/Avalonia.X11.csproj create mode 100644 src/Avalonia.X11/X11Exception.cs create mode 100644 src/Avalonia.X11/X11Platform.cs create mode 100644 src/Avalonia.X11/X11PlatformThreading.cs create mode 100644 src/Avalonia.X11/XLib.cs diff --git a/Avalonia.sln b/Avalonia.sln index f71a94888d..388dbb6e6a 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -188,6 +188,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.UnitTests", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.OpenGL", "src\Avalonia.OpenGL\Avalonia.OpenGL.csproj", "{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.X11", "src\Avalonia.X11\Avalonia.X11.csproj", "{212D02D5-C873-469A-8E78-4A6350EC4A1A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlatformSanityChecks", "samples\PlatformSanityChecks\PlatformSanityChecks.csproj", "{8B5768BB-71F9-4E23-89B5-DDBA6458B856}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13 @@ -1689,6 +1693,54 @@ Global {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhone.Build.0 = Release|Any CPU {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.AppStore|iPhone.Build.0 = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Debug|iPhone.Build.0 = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Release|Any CPU.Build.0 = Release|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Release|iPhone.ActiveCfg = Release|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Release|iPhone.Build.0 = Release|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.AppStore|iPhone.Build.0 = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Debug|iPhone.Build.0 = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|Any CPU.Build.0 = Release|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|iPhone.ActiveCfg = Release|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|iPhone.Build.0 = Release|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|iPhoneSimulator.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1742,6 +1794,8 @@ Global {CBFD5788-567D-401B-9DFA-74E4224025A0} = {A59C4C0A-64DF-4621-B450-2BA00D6F61E2} {4ADA61C8-D191-428D-9066-EF4F0D86520F} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} {E1240B49-7B4B-4371-A00E-068778C5CF0B} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {212D02D5-C873-469A-8E78-4A6350EC4A1A} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B} + {8B5768BB-71F9-4E23-89B5-DDBA6458B856} = {9B9E3891-2366-4253-A952-D08BCEB71098} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} diff --git a/samples/PlatformSanityChecks/App.xaml b/samples/PlatformSanityChecks/App.xaml new file mode 100644 index 0000000000..25bab6ae35 --- /dev/null +++ b/samples/PlatformSanityChecks/App.xaml @@ -0,0 +1,6 @@ + + + + + + diff --git a/samples/PlatformSanityChecks/App.xaml.cs b/samples/PlatformSanityChecks/App.xaml.cs new file mode 100644 index 0000000000..508fc1e34b --- /dev/null +++ b/samples/PlatformSanityChecks/App.xaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Markup.Xaml; + +namespace PlatformSanityChecks +{ + public class App : Application + { + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/samples/PlatformSanityChecks/PlatformSanityChecks.csproj b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj new file mode 100644 index 0000000000..00b5b10106 --- /dev/null +++ b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj @@ -0,0 +1,24 @@ + + + + Exe + netcoreapp2.0 + + + + + + + + + + + + + + + + + + + diff --git a/samples/PlatformSanityChecks/Program.cs b/samples/PlatformSanityChecks/Program.cs new file mode 100644 index 0000000000..8a3aa82981 --- /dev/null +++ b/samples/PlatformSanityChecks/Program.cs @@ -0,0 +1,140 @@ +using System; +using System.Diagnostics; +using System.Reactive.Disposables; +using System.Runtime.CompilerServices; +using System.Threading; +using Avalonia; +using Avalonia.Platform; +using Avalonia.Threading; +using Avalonia.X11; + +namespace PlatformSanityChecks +{ + public class Program + { + static Thread UiThread; + + static void Main(string[] args) + { + UiThread = Thread.CurrentThread; + AppBuilder.Configure().RuntimePlatformServicesInitializer(); + var app = new App(); + + new AvaloniaX11Platform().Initialize(); + + CheckPlatformThreading(); + + + + } + + static bool CheckAccess() => UiThread == Thread.CurrentThread; + + static void VerifyAccess() + { + if (!CheckAccess()) + Die("Call from invalid thread"); + } + + static Exception Die(string error) + { + Console.Error.WriteLine(error); + Console.Error.WriteLine(Environment.StackTrace); + Process.GetCurrentProcess().Kill(); + throw new Exception(error); + } + + static IDisposable Enter([CallerMemberName] string caller = null) + { + Console.WriteLine("Entering " + caller); + return Disposable.Create(() => { Console.WriteLine("Leaving " + caller); }); + } + + static void EnterLoop(Action cb, [CallerMemberName] string caller = null) + { + using (Enter(caller)) + { + var cts = new CancellationTokenSource(); + cb(cts); + Dispatcher.UIThread.MainLoop(cts.Token); + if (!cts.IsCancellationRequested) + Die("Unexpected loop exit"); + } + } + + static void CheckTimerOrdering() => EnterLoop(cts => + { + bool firstFired = false, secondFired = false; + DispatcherTimer.Run(() => + { + Console.WriteLine("Second tick"); + VerifyAccess(); + if (!firstFired) + throw Die("Invalid timer ordering"); + if (secondFired) + throw Die("Invocation of finished timer"); + secondFired = true; + cts.Cancel(); + return false; + }, TimeSpan.FromSeconds(2)); + DispatcherTimer.Run(() => + { + Console.WriteLine("First tick"); + VerifyAccess(); + if (secondFired) + throw Die("Invalid timer ordering"); + if (firstFired) + throw Die("Invocation of finished timer"); + firstFired = true; + return false; + }, TimeSpan.FromSeconds(1)); + }); + + static void CheckTimerTicking() => EnterLoop(cts => + { + int ticks = 0; + var st = Stopwatch.StartNew(); + DispatcherTimer.Run(() => + { + ticks++; + Console.WriteLine($"Tick {ticks} at {st.Elapsed}"); + if (ticks == 5) + { + if (st.Elapsed.TotalSeconds < 4.5) + Die("Timer is too fast"); + if (st.Elapsed.TotalSeconds > 6) + Die("Timer is too slow"); + cts.Cancel(); + return false; + } + + return true; + }, TimeSpan.FromSeconds(1)); + + + }); + + + static void CheckSignaling() => EnterLoop(cts => + { + ThreadPool.QueueUserWorkItem(_ => + { + Thread.Sleep(100); + Dispatcher.UIThread.Post(() => + { + VerifyAccess(); + cts.Cancel(); + }); + }); + }); + + static void CheckPlatformThreading() + { + CheckSignaling(); + CheckTimerOrdering(); + CheckTimerTicking(); + + } + + } +} diff --git a/src/Avalonia.X11/Avalonia.X11.csproj b/src/Avalonia.X11/Avalonia.X11.csproj new file mode 100644 index 0000000000..a035febe5b --- /dev/null +++ b/src/Avalonia.X11/Avalonia.X11.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.0 + true + + + + + + + diff --git a/src/Avalonia.X11/X11Exception.cs b/src/Avalonia.X11/X11Exception.cs new file mode 100644 index 0000000000..2ac5a31d9b --- /dev/null +++ b/src/Avalonia.X11/X11Exception.cs @@ -0,0 +1,12 @@ +using System; + +namespace Avalonia.X11 +{ + public class X11Exception : Exception + { + public X11Exception(string message) : base(message) + { + + } + } +} diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs new file mode 100644 index 0000000000..c266433eef --- /dev/null +++ b/src/Avalonia.X11/X11Platform.cs @@ -0,0 +1,39 @@ +using System; +using Avalonia.Controls; +using Avalonia.Platform; +using Avalonia.X11; +using static Avalonia.X11.XLib; +namespace Avalonia.X11 +{ + public class AvaloniaX11Platform + { + public void Initialize() + { + Display = XOpenDisplay(IntPtr.Zero); + DeferredDisplay = XOpenDisplay(IntPtr.Zero); + if (Display == IntPtr.Zero) + throw new Exception("XOpenDisplay failed"); + + + AvaloniaLocator.CurrentMutable.BindToSelf(this) + .Bind().ToConstant(new X11PlatformThreading(Display)); + + } + + public IntPtr DeferredDisplay { get; set; } + public IntPtr Display { get; set; } + } +} + +namespace Avalonia +{ + public static class AvaloniaX11PlatformExtensions + { + public static T UseX11(this T builder) where T : AppBuilderBase, new() + { + builder.UseWindowingSubsystem(() => new AvaloniaX11Platform().Initialize()); + return builder; + } + } + +} diff --git a/src/Avalonia.X11/X11PlatformThreading.cs b/src/Avalonia.X11/X11PlatformThreading.cs new file mode 100644 index 0000000000..18b08085e3 --- /dev/null +++ b/src/Avalonia.X11/X11PlatformThreading.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; +using Avalonia.Platform; +using Avalonia.Threading; +using static Avalonia.X11.XLib; + +namespace Avalonia.X11 +{ + public unsafe class X11PlatformThreading : IPlatformThreadingInterface + { + private readonly IntPtr _display; + private Thread _mainThread; + + [StructLayout(LayoutKind.Explicit)] + struct epoll_data + { + [FieldOffset(0)] + public IntPtr ptr; + [FieldOffset(0)] + public int fd; + [FieldOffset(0)] + public uint u32; + [FieldOffset(0)] + public ulong u64; + } + + private const int EPOLLIN = 1; + private const int EPOLL_CTL_ADD = 1; + private const int O_NONBLOCK = 2048; + + [StructLayout(LayoutKind.Sequential)] + struct epoll_event + { + public uint events; + public epoll_data data; + } + + [DllImport("libc")] + extern static int epoll_create1(int size); + + [DllImport("libc")] + extern static int epoll_ctl(int epfd, int op, int fd, ref epoll_event __event); + + [DllImport("libc")] + extern static int epoll_wait(int epfd, epoll_event* events, int maxevents, int timeout); + + [DllImport("libc")] + extern static int pipe2(int* fds, int flags); + [DllImport("libc")] + extern static IntPtr write(int fd, void* buf, IntPtr count); + + [DllImport("libc")] + extern static IntPtr read(int fd, void* buf, IntPtr count); + + enum EventCodes + { + X11 = 1, + Signal =2 + } + + private int _sigread, _sigwrite; + private object _lock = new object(); + private bool _signaled; + private DispatcherPriority _signaledPriority; + private int _epoll; + private Stopwatch _clock = Stopwatch.StartNew(); + + class X11Timer : IDisposable + { + private readonly X11PlatformThreading _parent; + + public X11Timer(X11PlatformThreading parent, DispatcherPriority prio, TimeSpan interval, Action tick) + { + _parent = parent; + Priority = prio; + Tick = tick; + Interval = interval; + Reschedule(); + } + + public DispatcherPriority Priority { get; } + public TimeSpan NextTick { get; private set; } + public TimeSpan Interval { get; } + public Action Tick { get; } + public bool Disposed { get; private set; } + + public void Reschedule() + { + NextTick = _parent._clock.Elapsed + Interval; + } + + public void Dispose() + { + Disposed = true; + lock (_parent._lock) + _parent._timers.Remove(this); + } + } + + List _timers = new List(); + + public X11PlatformThreading(IntPtr display) + { + _display = display; + _mainThread = Thread.CurrentThread; + var fd = XLib.XConnectionNumber(display); + var ev = new epoll_event() + { + events = EPOLLIN, + data = {u32 = (int)EventCodes.X11} + }; + _epoll = epoll_create1(0); + if (_epoll == -1) + throw new X11Exception("epoll_create1 failed"); + + if (epoll_ctl(_epoll, EPOLL_CTL_ADD, fd, ref ev) == -1) + throw new X11Exception("Unable to attach X11 connection handle to epoll"); + + var fds = stackalloc int[2]; + pipe2(fds, O_NONBLOCK); + _sigread = fds[0]; + _sigwrite = fds[1]; + + ev = new epoll_event + { + events = EPOLLIN, + data = {u32 = (int)EventCodes.Signal} + }; + if (epoll_ctl(_epoll, EPOLL_CTL_ADD, _sigread, ref ev) == -1) + throw new X11Exception("Unable to attach signal pipe to epoll"); + } + + int TimerComparer(X11Timer t1, X11Timer t2) + { + return t2.Priority - t1.Priority; + } + + public void RunLoop(CancellationToken cancellationToken) + { + var readyTimers = new List(); + while (!cancellationToken.IsCancellationRequested) + { + var now = _clock.Elapsed; + TimeSpan? nextTick = null; + readyTimers.Clear(); + lock(_timers) + foreach (var t in _timers) + { + if (nextTick == null || t.NextTick < nextTick.Value) + nextTick = t.NextTick; + if (t.NextTick < now) + readyTimers.Add(t); + } + + readyTimers.Sort(TimerComparer); + + foreach (var t in readyTimers) + { + if (cancellationToken.IsCancellationRequested) + return; + t.Tick(); + if(!t.Disposed) + { + t.Reschedule(); + if (nextTick == null || t.NextTick < nextTick.Value) + nextTick = t.NextTick; + } + } + + if (cancellationToken.IsCancellationRequested) + return; + epoll_event ev; + var len = epoll_wait(_epoll, &ev, 1, + nextTick == null ? -1 : Math.Max(1, (int)(nextTick.Value - _clock.Elapsed).TotalMilliseconds)); + if (cancellationToken.IsCancellationRequested) + return; + if (len == 0) + { + // We handle timer-related stuff at the beginning of the loop + continue; + } + else + { + if (ev.data.u32 == (int)EventCodes.Signal) + { + int buf = 0; + while (read(_sigread, &buf, new IntPtr(4)).ToInt64() > 0) + { + } + + DispatcherPriority prio; + lock (_lock) + { + _signaled = false; + prio = _signaledPriority; + _signaledPriority = DispatcherPriority.MinValue; + } + Signaled?.Invoke(prio); + } + else + { + while (XPending(_display)) + { + if (cancellationToken.IsCancellationRequested) + return; + XNextEvent(_display, out var xev); + } + } + } + } + } + + + + public void Signal(DispatcherPriority priority) + { + lock (_lock) + { + if (priority > _signaledPriority) + _signaledPriority = priority; + + if(_signaled) + return; + _signaled = true; + int buf = 0; + write(_sigwrite, &buf, new IntPtr(1)); + } + } + + public bool CurrentThreadIsLoopThread => Thread.CurrentThread == _mainThread; + public event Action Signaled; + + public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick) + { + if (_mainThread != Thread.CurrentThread) + throw new InvalidOperationException("StartTimer can be only called from UI thread"); + if (interval <= TimeSpan.Zero) + throw new ArgumentException("Interval must be positive", nameof(interval)); + + // We assume that we are on the main thread and outside of epoll_wait, so there is no need for wakeup signal + + var timer = new X11Timer(this, priority, interval, tick); + lock(_timers) + _timers.Add(timer); + return timer; + } + } +} diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs new file mode 100644 index 0000000000..88d36091ca --- /dev/null +++ b/src/Avalonia.X11/XLib.cs @@ -0,0 +1,105 @@ +using System; +using System.Runtime.InteropServices; + +namespace Avalonia.X11 +{ + public static class XLib + { + + [DllImport("libX11.so.6")] + public static extern IntPtr XInitThreads(); + + [DllImport("libX11.so.6")] + public static extern IntPtr XOpenDisplay(IntPtr name); + + [DllImport("libX11.so.6")] + public static extern int XConnectionNumber(IntPtr display); + + [DllImport("libX11.so.6")] + public static extern IntPtr XLockDisplay(IntPtr display); + + [DllImport("libX11.so.6")] + public static extern IntPtr XUnlockDisplay(IntPtr display); + + [DllImport("libX11.so.6")] + public static extern IntPtr XFreeGC(IntPtr display, IntPtr gc); + + [DllImport("libX11.so.6")] + public static extern IntPtr XCreateGC(IntPtr display, IntPtr drawable, ulong valuemask, IntPtr values); + + [DllImport("libX11.so.6")] + public static extern int XInitImage(ref XImage image); + + [DllImport("libX11.so.6")] + public static extern int XDestroyImage(ref XImage image); + + [DllImport("libX11.so.6")] + public static extern IntPtr XSetErrorHandler(XErrorHandler handler); + + [DllImport("libX11.so.6")] + public static extern int XSync(IntPtr display, bool discard); + + [DllImport("libX11.so.6")] + public static extern int XNextEvent(IntPtr display, out XEvent ev); + + [DllImport("libX11.so.6")] + public static extern bool XPending(IntPtr display); + + [StructLayout(LayoutKind.Sequential)] + public struct XAnyEvent + { + + public int Type; + public ulong Serial; /* # of last request processed by server */ + public bool send_event; /* true if this came from a SendEvent request */ + public IntPtr display; /* Display the event was read from */ + public IntPtr window; /* window on which event was requested in event mask */ + } + + [StructLayout(LayoutKind.Explicit)] + public unsafe struct XEvent + { + [FieldOffset(0)] public int Type; + [FieldOffset(0)] public XAnyEvent XAny; + [FieldOffset(0)] private fixed int pad[40]; + } + + public delegate int XErrorHandler(IntPtr display, ref XErrorEvent error); + + [DllImport("libX11.so.6")] + public static extern int XPutImage(IntPtr display, IntPtr drawable, IntPtr gc, ref XImage image, + int srcx, int srcy, int destx, int desty, uint width, uint height); + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct XErrorEvent + { + public int type; + public IntPtr* display; /* Display the event was read from */ + public ulong serial; /* serial number of failed request */ + public byte error_code; /* error code of failed request */ + public byte request_code; /* Major op-code of failed request */ + public byte minor_code; /* Minor op-code of failed request */ + public IntPtr resourceid; /* resource id */ + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct XImage + { + public int width, height; /* size of image */ + public int xoffset; /* number of pixels offset in X direction */ + public int format; /* XYBitmap, XYPixmap, ZPixmap */ + public IntPtr data; /* pointer to image data */ + public int byte_order; /* data byte order, LSBFirst, MSBFirst */ + public int bitmap_unit; /* quant. of scanline 8, 16, 32 */ + public int bitmap_bit_order; /* LSBFirst, MSBFirst */ + public int bitmap_pad; /* 8, 16, 32 either XY or ZPixmap */ + public int depth; /* depth of image */ + public int bytes_per_line; /* accelerator to next scanline */ + public int bits_per_pixel; /* bits per pixel (ZPixmap) */ + public ulong red_mask; /* bits in z arrangement */ + public ulong green_mask; + public ulong blue_mask; + private fixed byte funcs[128]; + } + } +} From 666efd311b4db57b2648725be64847230d5973c5 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 23 Oct 2018 18:06:26 +0300 Subject: [PATCH 02/46] [X11] Initial windowing and mouse events --- samples/PlatformSanityChecks/Program.cs | 2 +- src/Avalonia.Input/MouseDevice.cs | 4 +- src/Avalonia.Input/Raw/RawInputEventArgs.cs | 4 +- src/Avalonia.Input/Raw/RawKeyEventArgs.cs | 2 +- src/Avalonia.Input/Raw/RawMouseEventArgs.cs | 2 +- .../Raw/RawMouseWheelEventArgs.cs | 2 +- .../Raw/RawTextInputEventArgs.cs | 2 +- src/Avalonia.X11/Avalonia.X11.csproj | 1 + src/Avalonia.X11/Stubs.cs | 103 + src/Avalonia.X11/X11Atoms.cs | 341 ++++ src/Avalonia.X11/X11Enums.cs | 110 + src/Avalonia.X11/X11Framebuffer.cs | 57 + src/Avalonia.X11/X11FramebufferSurface.cs | 27 + src/Avalonia.X11/X11Info.cs | 35 + src/Avalonia.X11/X11Platform.cs | 47 +- src/Avalonia.X11/X11PlatformThreading.cs | 24 +- src/Avalonia.X11/X11Structs.cs | 1815 +++++++++++++++++ src/Avalonia.X11/X11Window.cs | 492 +++++ src/Avalonia.X11/XError.cs | 30 + src/Avalonia.X11/XLib.cs | 468 ++++- 20 files changed, 3474 insertions(+), 94 deletions(-) create mode 100644 src/Avalonia.X11/Stubs.cs create mode 100644 src/Avalonia.X11/X11Atoms.cs create mode 100644 src/Avalonia.X11/X11Enums.cs create mode 100644 src/Avalonia.X11/X11Framebuffer.cs create mode 100644 src/Avalonia.X11/X11FramebufferSurface.cs create mode 100644 src/Avalonia.X11/X11Info.cs create mode 100644 src/Avalonia.X11/X11Structs.cs create mode 100644 src/Avalonia.X11/X11Window.cs create mode 100644 src/Avalonia.X11/XError.cs diff --git a/samples/PlatformSanityChecks/Program.cs b/samples/PlatformSanityChecks/Program.cs index 8a3aa82981..3fdc9b1e77 100644 --- a/samples/PlatformSanityChecks/Program.cs +++ b/samples/PlatformSanityChecks/Program.cs @@ -20,7 +20,7 @@ namespace PlatformSanityChecks AppBuilder.Configure().RuntimePlatformServicesInitializer(); var app = new App(); - new AvaloniaX11Platform().Initialize(); + AvaloniaX11PlatformExtensions.InitializeX11Platform(); CheckPlatformThreading(); diff --git a/src/Avalonia.Input/MouseDevice.cs b/src/Avalonia.Input/MouseDevice.cs index e581772978..e01dedeede 100644 --- a/src/Avalonia.Input/MouseDevice.cs +++ b/src/Avalonia.Input/MouseDevice.cs @@ -18,7 +18,7 @@ namespace Avalonia.Input { private int _clickCount; private Rect _lastClickRect; - private uint _lastClickTime; + private ulong _lastClickTime; private IInputElement _captured; private IDisposable _capturedSubscription; @@ -152,7 +152,7 @@ namespace Avalonia.Input ClearPointerOver(this, root); } - private bool MouseDown(IMouseDevice device, uint timestamp, IInputElement root, Point p, MouseButton button, InputModifiers inputModifiers) + private bool MouseDown(IMouseDevice device, ulong timestamp, IInputElement root, Point p, MouseButton button, InputModifiers inputModifiers) { Contract.Requires(device != null); Contract.Requires(root != null); diff --git a/src/Avalonia.Input/Raw/RawInputEventArgs.cs b/src/Avalonia.Input/Raw/RawInputEventArgs.cs index 041c361d30..78c1b58624 100644 --- a/src/Avalonia.Input/Raw/RawInputEventArgs.cs +++ b/src/Avalonia.Input/Raw/RawInputEventArgs.cs @@ -21,7 +21,7 @@ namespace Avalonia.Input.Raw /// /// The associated device. /// The event timestamp. - public RawInputEventArgs(IInputDevice device, uint timestamp) + public RawInputEventArgs(IInputDevice device, ulong timestamp) { Contract.Requires(device != null); @@ -47,6 +47,6 @@ namespace Avalonia.Input.Raw /// /// Gets the timestamp associated with the event. /// - public uint Timestamp { get; private set; } + public ulong Timestamp { get; private set; } } } diff --git a/src/Avalonia.Input/Raw/RawKeyEventArgs.cs b/src/Avalonia.Input/Raw/RawKeyEventArgs.cs index 0c208b4596..044f244138 100644 --- a/src/Avalonia.Input/Raw/RawKeyEventArgs.cs +++ b/src/Avalonia.Input/Raw/RawKeyEventArgs.cs @@ -13,7 +13,7 @@ namespace Avalonia.Input.Raw { public RawKeyEventArgs( IKeyboardDevice device, - uint timestamp, + ulong timestamp, RawKeyEventType type, Key key, InputModifiers modifiers) : base(device, timestamp) diff --git a/src/Avalonia.Input/Raw/RawMouseEventArgs.cs b/src/Avalonia.Input/Raw/RawMouseEventArgs.cs index 914833624f..c5637d66cc 100644 --- a/src/Avalonia.Input/Raw/RawMouseEventArgs.cs +++ b/src/Avalonia.Input/Raw/RawMouseEventArgs.cs @@ -35,7 +35,7 @@ namespace Avalonia.Input.Raw /// The input modifiers. public RawMouseEventArgs( IInputDevice device, - uint timestamp, + ulong timestamp, IInputRoot root, RawMouseEventType type, Point position, diff --git a/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs b/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs index f4078af9e1..d2e5faab6c 100644 --- a/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs +++ b/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs @@ -8,7 +8,7 @@ namespace Avalonia.Input.Raw { public RawMouseWheelEventArgs( IInputDevice device, - uint timestamp, + ulong timestamp, IInputRoot root, Point position, Vector delta, InputModifiers inputModifiers) diff --git a/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs b/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs index 6e427c3751..0d1e5d2422 100644 --- a/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs +++ b/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs @@ -7,7 +7,7 @@ namespace Avalonia.Input.Raw { public string Text { get; set; } - public RawTextInputEventArgs(IKeyboardDevice device, uint timestamp, string text) : base(device, timestamp) + public RawTextInputEventArgs(IKeyboardDevice device, ulong timestamp, string text) : base(device, timestamp) { Text = text; } diff --git a/src/Avalonia.X11/Avalonia.X11.csproj b/src/Avalonia.X11/Avalonia.X11.csproj index a035febe5b..3f61961571 100644 --- a/src/Avalonia.X11/Avalonia.X11.csproj +++ b/src/Avalonia.X11/Avalonia.X11.csproj @@ -7,6 +7,7 @@ + diff --git a/src/Avalonia.X11/Stubs.cs b/src/Avalonia.X11/Stubs.cs new file mode 100644 index 0000000000..ed14ab7878 --- /dev/null +++ b/src/Avalonia.X11/Stubs.cs @@ -0,0 +1,103 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Avalonia.Controls; +using Avalonia.Controls.Platform; +using Avalonia.Input; +using Avalonia.Input.Platform; +using Avalonia.Platform; + +namespace Avalonia.X11 +{ + class CursorFactoryStub : IStandardCursorFactory + { + public IPlatformHandle GetCursor(StandardCursorType cursorType) + { + return new PlatformHandle(IntPtr.Zero, "FAKE"); + } + } + + class ClipboardStub : IClipboard + { + private string _text; + public Task GetTextAsync() + { + return Task.FromResult(_text); + } + + public Task SetTextAsync(string text) + { + _text = text; + return Task.CompletedTask; + } + + public Task ClearAsync() + { + _text = null; + return Task.CompletedTask; + } + } + + class PlatformSettingsStub : IPlatformSettings + { + public Size DoubleClickSize { get; } = new Size(2, 2); + public TimeSpan DoubleClickTime { get; } = TimeSpan.FromMilliseconds(500); + } + + class SystemDialogsStub : ISystemDialogImpl + { + public Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) + { + return Task.FromResult((string[])null); + } + + public Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) + { + return Task.FromResult((string)null); + } + } + + class IconLoaderStub : IPlatformIconLoader + { + class FakeIcon : IWindowIconImpl + { + private readonly byte[] _data; + + public FakeIcon(byte[] data) + { + _data = data; + } + public void Save(Stream outputStream) + { + outputStream.Write(_data, 0, _data.Length); + } + } + + public IWindowIconImpl LoadIcon(string fileName) + { + return new FakeIcon(File.ReadAllBytes(fileName)); + } + + public IWindowIconImpl LoadIcon(Stream stream) + { + var ms = new MemoryStream(); + stream.CopyTo(ms); + return new FakeIcon(ms.ToArray()); + } + + public IWindowIconImpl LoadIcon(IBitmapImpl bitmap) + { + var ms = new MemoryStream(); + bitmap.Save(ms); + return new FakeIcon(ms.ToArray()); + } + } + + class ScreenStub : IScreenImpl + { + public int ScreenCount { get; } = 1; + + public Screen[] AllScreens { get; } = + {new Screen(new Rect(0, 0, 1920, 1280), new Rect(0, 0, 1920, 1280), true)}; + } +} diff --git a/src/Avalonia.X11/X11Atoms.cs b/src/Avalonia.X11/X11Atoms.cs new file mode 100644 index 0000000000..e7b83f59d3 --- /dev/null +++ b/src/Avalonia.X11/X11Atoms.cs @@ -0,0 +1,341 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. (http://www.novell.com) +// +// + +using System; +using static Avalonia.X11.XLib; +// ReSharper disable FieldCanBeMadeReadOnly.Global +// ReSharper disable IdentifierTypo +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedMember.Global +// ReSharper disable CommentTypo +// ReSharper disable ArrangeThisQualifier +// ReSharper disable NotAccessedField.Global +// ReSharper disable InconsistentNaming +// ReSharper disable StringLiteralTypo +#pragma warning disable 649 + +namespace Avalonia.X11 { + + internal class X11Atoms { + + // Our atoms + public readonly IntPtr AnyPropertyType = (IntPtr)0; + public readonly IntPtr XA_PRIMARY = (IntPtr)1; + public readonly IntPtr XA_SECONDARY = (IntPtr)2; + public readonly IntPtr XA_ARC = (IntPtr)3; + public readonly IntPtr XA_ATOM = (IntPtr)4; + public readonly IntPtr XA_BITMAP = (IntPtr)5; + public readonly IntPtr XA_CARDINAL = (IntPtr)6; + public readonly IntPtr XA_COLORMAP = (IntPtr)7; + public readonly IntPtr XA_CURSOR = (IntPtr)8; + public readonly IntPtr XA_CUT_BUFFER0 = (IntPtr)9; + public readonly IntPtr XA_CUT_BUFFER1 = (IntPtr)10; + public readonly IntPtr XA_CUT_BUFFER2 = (IntPtr)11; + public readonly IntPtr XA_CUT_BUFFER3 = (IntPtr)12; + public readonly IntPtr XA_CUT_BUFFER4 = (IntPtr)13; + public readonly IntPtr XA_CUT_BUFFER5 = (IntPtr)14; + public readonly IntPtr XA_CUT_BUFFER6 = (IntPtr)15; + public readonly IntPtr XA_CUT_BUFFER7 = (IntPtr)16; + public readonly IntPtr XA_DRAWABLE = (IntPtr)17; + public readonly IntPtr XA_FONT = (IntPtr)18; + public readonly IntPtr XA_INTEGER = (IntPtr)19; + public readonly IntPtr XA_PIXMAP = (IntPtr)20; + public readonly IntPtr XA_POINT = (IntPtr)21; + public readonly IntPtr XA_RECTANGLE = (IntPtr)22; + public readonly IntPtr XA_RESOURCE_MANAGER = (IntPtr)23; + public readonly IntPtr XA_RGB_COLOR_MAP = (IntPtr)24; + public readonly IntPtr XA_RGB_BEST_MAP = (IntPtr)25; + public readonly IntPtr XA_RGB_BLUE_MAP = (IntPtr)26; + public readonly IntPtr XA_RGB_DEFAULT_MAP = (IntPtr)27; + public readonly IntPtr XA_RGB_GRAY_MAP = (IntPtr)28; + public readonly IntPtr XA_RGB_GREEN_MAP = (IntPtr)29; + public readonly IntPtr XA_RGB_RED_MAP = (IntPtr)30; + public readonly IntPtr XA_STRING = (IntPtr)31; + public readonly IntPtr XA_VISUALID = (IntPtr)32; + public readonly IntPtr XA_WINDOW = (IntPtr)33; + public readonly IntPtr XA_WM_COMMAND = (IntPtr)34; + public readonly IntPtr XA_WM_HINTS = (IntPtr)35; + public readonly IntPtr XA_WM_CLIENT_MACHINE = (IntPtr)36; + public readonly IntPtr XA_WM_ICON_NAME = (IntPtr)37; + public readonly IntPtr XA_WM_ICON_SIZE = (IntPtr)38; + public readonly IntPtr XA_WM_NAME = (IntPtr)39; + public readonly IntPtr XA_WM_NORMAL_HINTS = (IntPtr)40; + public readonly IntPtr XA_WM_SIZE_HINTS = (IntPtr)41; + public readonly IntPtr XA_WM_ZOOM_HINTS = (IntPtr)42; + public readonly IntPtr XA_MIN_SPACE = (IntPtr)43; + public readonly IntPtr XA_NORM_SPACE = (IntPtr)44; + public readonly IntPtr XA_MAX_SPACE = (IntPtr)45; + public readonly IntPtr XA_END_SPACE = (IntPtr)46; + public readonly IntPtr XA_SUPERSCRIPT_X = (IntPtr)47; + public readonly IntPtr XA_SUPERSCRIPT_Y = (IntPtr)48; + public readonly IntPtr XA_SUBSCRIPT_X = (IntPtr)49; + public readonly IntPtr XA_SUBSCRIPT_Y = (IntPtr)50; + public readonly IntPtr XA_UNDERLINE_POSITION = (IntPtr)51; + public readonly IntPtr XA_UNDERLINE_THICKNESS = (IntPtr)52; + public readonly IntPtr XA_STRIKEOUT_ASCENT = (IntPtr)53; + public readonly IntPtr XA_STRIKEOUT_DESCENT = (IntPtr)54; + public readonly IntPtr XA_ITALIC_ANGLE = (IntPtr)55; + public readonly IntPtr XA_X_HEIGHT = (IntPtr)56; + public readonly IntPtr XA_QUAD_WIDTH = (IntPtr)57; + public readonly IntPtr XA_WEIGHT = (IntPtr)58; + public readonly IntPtr XA_POINT_SIZE = (IntPtr)59; + public readonly IntPtr XA_RESOLUTION = (IntPtr)60; + public readonly IntPtr XA_COPYRIGHT = (IntPtr)61; + public readonly IntPtr XA_NOTICE = (IntPtr)62; + public readonly IntPtr XA_FONT_NAME = (IntPtr)63; + public readonly IntPtr XA_FAMILY_NAME = (IntPtr)64; + public readonly IntPtr XA_FULL_NAME = (IntPtr)65; + public readonly IntPtr XA_CAP_HEIGHT = (IntPtr)66; + public readonly IntPtr XA_WM_CLASS = (IntPtr)67; + public readonly IntPtr XA_WM_TRANSIENT_FOR = (IntPtr)68; + + public readonly IntPtr WM_PROTOCOLS; + public readonly IntPtr WM_DELETE_WINDOW; + public readonly IntPtr WM_TAKE_FOCUS; + public readonly IntPtr _NET_SUPPORTED; + public readonly IntPtr _NET_CLIENT_LIST; + public readonly IntPtr _NET_NUMBER_OF_DESKTOPS; + public readonly IntPtr _NET_DESKTOP_GEOMETRY; + public readonly IntPtr _NET_DESKTOP_VIEWPORT; + public readonly IntPtr _NET_CURRENT_DESKTOP; + public readonly IntPtr _NET_DESKTOP_NAMES; + public readonly IntPtr _NET_ACTIVE_WINDOW; + public readonly IntPtr _NET_WORKAREA; + public readonly IntPtr _NET_SUPPORTING_WM_CHECK; + public readonly IntPtr _NET_VIRTUAL_ROOTS; + public readonly IntPtr _NET_DESKTOP_LAYOUT; + public readonly IntPtr _NET_SHOWING_DESKTOP; + public readonly IntPtr _NET_CLOSE_WINDOW; + public readonly IntPtr _NET_MOVERESIZE_WINDOW; + public readonly IntPtr _NET_WM_MOVERESIZE; + public readonly IntPtr _NET_RESTACK_WINDOW; + public readonly IntPtr _NET_REQUEST_FRAME_EXTENTS; + public readonly IntPtr _NET_WM_NAME; + public readonly IntPtr _NET_WM_VISIBLE_NAME; + public readonly IntPtr _NET_WM_ICON_NAME; + public readonly IntPtr _NET_WM_VISIBLE_ICON_NAME; + public readonly IntPtr _NET_WM_DESKTOP; + public readonly IntPtr _NET_WM_WINDOW_TYPE; + public readonly IntPtr _NET_WM_STATE; + public readonly IntPtr _NET_WM_ALLOWED_ACTIONS; + public readonly IntPtr _NET_WM_STRUT; + public readonly IntPtr _NET_WM_STRUT_PARTIAL; + public readonly IntPtr _NET_WM_ICON_GEOMETRY; + public readonly IntPtr _NET_WM_ICON; + public readonly IntPtr _NET_WM_PID; + public readonly IntPtr _NET_WM_HANDLED_ICONS; + public readonly IntPtr _NET_WM_USER_TIME; + public readonly IntPtr _NET_FRAME_EXTENTS; + public readonly IntPtr _NET_WM_PING; + public readonly IntPtr _NET_WM_SYNC_REQUEST; + public readonly IntPtr _NET_SYSTEM_TRAY_S; + public readonly IntPtr _NET_SYSTEM_TRAY_ORIENTATION; + public readonly IntPtr _NET_SYSTEM_TRAY_OPCODE; + public readonly IntPtr _NET_WM_STATE_MAXIMIZED_HORZ; + public readonly IntPtr _NET_WM_STATE_MAXIMIZED_VERT; + public readonly IntPtr _XEMBED; + public readonly IntPtr _XEMBED_INFO; + public readonly IntPtr _MOTIF_WM_HINTS; + public readonly IntPtr _NET_WM_STATE_SKIP_TASKBAR; + public readonly IntPtr _NET_WM_STATE_ABOVE; + public readonly IntPtr _NET_WM_STATE_MODAL; + public readonly IntPtr _NET_WM_STATE_HIDDEN; + public readonly IntPtr _NET_WM_CONTEXT_HELP; + public readonly IntPtr _NET_WM_WINDOW_OPACITY; + public readonly IntPtr _NET_WM_WINDOW_TYPE_DESKTOP; + public readonly IntPtr _NET_WM_WINDOW_TYPE_DOCK; + public readonly IntPtr _NET_WM_WINDOW_TYPE_TOOLBAR; + public readonly IntPtr _NET_WM_WINDOW_TYPE_MENU; + public readonly IntPtr _NET_WM_WINDOW_TYPE_UTILITY; + public readonly IntPtr _NET_WM_WINDOW_TYPE_SPLASH; + public readonly IntPtr _NET_WM_WINDOW_TYPE_DIALOG; + public readonly IntPtr _NET_WM_WINDOW_TYPE_NORMAL; + public readonly IntPtr CLIPBOARD; + public readonly IntPtr PRIMARY; + public readonly IntPtr DIB; + public readonly IntPtr OEMTEXT; + public readonly IntPtr UNICODETEXT; + public readonly IntPtr TARGETS; + public readonly IntPtr PostAtom; + public readonly IntPtr HoverState; + public readonly IntPtr AsyncAtom; + + + public X11Atoms (IntPtr display) { + + // make sure this array stays in sync with the statements below + string [] atom_names = new string[] { + "WM_PROTOCOLS", + "WM_DELETE_WINDOW", + "WM_TAKE_FOCUS", + "_NET_SUPPORTED", + "_NET_CLIENT_LIST", + "_NET_NUMBER_OF_DESKTOPS", + "_NET_DESKTOP_GEOMETRY", + "_NET_DESKTOP_VIEWPORT", + "_NET_CURRENT_DESKTOP", + "_NET_DESKTOP_NAMES", + "_NET_ACTIVE_WINDOW", + "_NET_WORKAREA", + "_NET_SUPPORTING_WM_CHECK", + "_NET_VIRTUAL_ROOTS", + "_NET_DESKTOP_LAYOUT", + "_NET_SHOWING_DESKTOP", + "_NET_CLOSE_WINDOW", + "_NET_MOVERESIZE_WINDOW", + "_NET_WM_MOVERESIZE", + "_NET_RESTACK_WINDOW", + "_NET_REQUEST_FRAME_EXTENTS", + "_NET_WM_NAME", + "_NET_WM_VISIBLE_NAME", + "_NET_WM_ICON_NAME", + "_NET_WM_VISIBLE_ICON_NAME", + "_NET_WM_DESKTOP", + "_NET_WM_WINDOW_TYPE", + "_NET_WM_STATE", + "_NET_WM_ALLOWED_ACTIONS", + "_NET_WM_STRUT", + "_NET_WM_STRUT_PARTIAL", + "_NET_WM_ICON_GEOMETRY", + "_NET_WM_ICON", + "_NET_WM_PID", + "_NET_WM_HANDLED_ICONS", + "_NET_WM_USER_TIME", + "_NET_FRAME_EXTENTS", + "_NET_WM_PING", + "_NET_WM_SYNC_REQUEST", + "_NET_SYSTEM_TRAY_OPCODE", + "_NET_SYSTEM_TRAY_ORIENTATION", + "_NET_WM_STATE_MAXIMIZED_HORZ", + "_NET_WM_STATE_MAXIMIZED_VERT", + "_NET_WM_STATE_HIDDEN", + "_XEMBED", + "_XEMBED_INFO", + "_MOTIF_WM_HINTS", + "_NET_WM_STATE_SKIP_TASKBAR", + "_NET_WM_STATE_ABOVE", + "_NET_WM_STATE_MODAL", + "_NET_WM_CONTEXT_HELP", + "_NET_WM_WINDOW_OPACITY", + "_NET_WM_WINDOW_TYPE_DESKTOP", + "_NET_WM_WINDOW_TYPE_DOCK", + "_NET_WM_WINDOW_TYPE_TOOLBAR", + "_NET_WM_WINDOW_TYPE_MENU", + "_NET_WM_WINDOW_TYPE_UTILITY", + "_NET_WM_WINDOW_TYPE_DIALOG", + "_NET_WM_WINDOW_TYPE_SPLASH", + "_NET_WM_WINDOW_TYPE_NORMAL", + "CLIPBOARD", + "PRIMARY", + "COMPOUND_TEXT", + "UTF8_STRING", + "TARGETS", + "_SWF_AsyncAtom", + "_SWF_PostMessageAtom", + "_SWF_HoverAtom" }; + + IntPtr[] atoms = new IntPtr [atom_names.Length];; + + XInternAtoms (display, atom_names, atom_names.Length, false, atoms); + + int off = 0; + WM_PROTOCOLS = atoms [off++]; + WM_DELETE_WINDOW = atoms [off++]; + WM_TAKE_FOCUS = atoms [off++]; + _NET_SUPPORTED = atoms [off++]; + _NET_CLIENT_LIST = atoms [off++]; + _NET_NUMBER_OF_DESKTOPS = atoms [off++]; + _NET_DESKTOP_GEOMETRY = atoms [off++]; + _NET_DESKTOP_VIEWPORT = atoms [off++]; + _NET_CURRENT_DESKTOP = atoms [off++]; + _NET_DESKTOP_NAMES = atoms [off++]; + _NET_ACTIVE_WINDOW = atoms [off++]; + _NET_WORKAREA = atoms [off++]; + _NET_SUPPORTING_WM_CHECK = atoms [off++]; + _NET_VIRTUAL_ROOTS = atoms [off++]; + _NET_DESKTOP_LAYOUT = atoms [off++]; + _NET_SHOWING_DESKTOP = atoms [off++]; + _NET_CLOSE_WINDOW = atoms [off++]; + _NET_MOVERESIZE_WINDOW = atoms [off++]; + _NET_WM_MOVERESIZE = atoms [off++]; + _NET_RESTACK_WINDOW = atoms [off++]; + _NET_REQUEST_FRAME_EXTENTS = atoms [off++]; + _NET_WM_NAME = atoms [off++]; + _NET_WM_VISIBLE_NAME = atoms [off++]; + _NET_WM_ICON_NAME = atoms [off++]; + _NET_WM_VISIBLE_ICON_NAME = atoms [off++]; + _NET_WM_DESKTOP = atoms [off++]; + _NET_WM_WINDOW_TYPE = atoms [off++]; + _NET_WM_STATE = atoms [off++]; + _NET_WM_ALLOWED_ACTIONS = atoms [off++]; + _NET_WM_STRUT = atoms [off++]; + _NET_WM_STRUT_PARTIAL = atoms [off++]; + _NET_WM_ICON_GEOMETRY = atoms [off++]; + _NET_WM_ICON = atoms [off++]; + _NET_WM_PID = atoms [off++]; + _NET_WM_HANDLED_ICONS = atoms [off++]; + _NET_WM_USER_TIME = atoms [off++]; + _NET_FRAME_EXTENTS = atoms [off++]; + _NET_WM_PING = atoms [off++]; + _NET_WM_SYNC_REQUEST = atoms [off++]; + _NET_SYSTEM_TRAY_OPCODE = atoms [off++]; + _NET_SYSTEM_TRAY_ORIENTATION = atoms [off++]; + _NET_WM_STATE_MAXIMIZED_HORZ = atoms [off++]; + _NET_WM_STATE_MAXIMIZED_VERT = atoms [off++]; + _NET_WM_STATE_HIDDEN = atoms [off++]; + _XEMBED = atoms [off++]; + _XEMBED_INFO = atoms [off++]; + _MOTIF_WM_HINTS = atoms [off++]; + _NET_WM_STATE_SKIP_TASKBAR = atoms [off++]; + _NET_WM_STATE_ABOVE = atoms [off++]; + _NET_WM_STATE_MODAL = atoms [off++]; + _NET_WM_CONTEXT_HELP = atoms [off++]; + _NET_WM_WINDOW_OPACITY = atoms [off++]; + _NET_WM_WINDOW_TYPE_DESKTOP = atoms [off++]; + _NET_WM_WINDOW_TYPE_DOCK = atoms [off++]; + _NET_WM_WINDOW_TYPE_TOOLBAR = atoms [off++]; + _NET_WM_WINDOW_TYPE_MENU = atoms [off++]; + _NET_WM_WINDOW_TYPE_UTILITY = atoms [off++]; + _NET_WM_WINDOW_TYPE_DIALOG = atoms [off++]; + _NET_WM_WINDOW_TYPE_SPLASH = atoms [off++]; + _NET_WM_WINDOW_TYPE_NORMAL = atoms [off++]; + CLIPBOARD = atoms [off++]; + PRIMARY = atoms [off++]; + OEMTEXT = atoms [off++]; + UNICODETEXT = atoms [off++]; + TARGETS = atoms [off++]; + AsyncAtom = atoms [off++]; + PostAtom = atoms [off++]; + HoverState = atoms [off++]; + + DIB = XA_PIXMAP; + + var defScreen = XDefaultScreen(display); + // XXX multi screen stuff here + _NET_SYSTEM_TRAY_S = XInternAtom (display, "_NET_SYSTEM_TRAY_S" + defScreen.ToString(), false); + } + + } + +} + diff --git a/src/Avalonia.X11/X11Enums.cs b/src/Avalonia.X11/X11Enums.cs new file mode 100644 index 0000000000..d97e1c42bb --- /dev/null +++ b/src/Avalonia.X11/X11Enums.cs @@ -0,0 +1,110 @@ +using System; + +namespace Avalonia.X11 +{ + + public enum Status + { + Success = 0, /* everything's okay */ + BadRequest = 1, /* bad request code */ + BadValue = 2, /* int parameter out of range */ + BadWindow = 3, /* parameter not a Window */ + BadPixmap = 4, /* parameter not a Pixmap */ + BadAtom = 5, /* parameter not an Atom */ + BadCursor = 6, /* parameter not a Cursor */ + BadFont = 7, /* parameter not a Font */ + BadMatch = 8, /* parameter mismatch */ + BadDrawable = 9, /* parameter not a Pixmap or Window */ + BadAccess = 10, /* depending on context: + - key/button already grabbed + - attempt to free an illegal + cmap entry + - attempt to store into a read-only + color map entry. + - attempt to modify the access control + list from other than the local host. + */ + BadAlloc = 11, /* insufficient resources */ + BadColor = 12, /* no such colormap */ + BadGC = 13, /* parameter not a GC */ + BadIDChoice = 14, /* choice not in range or already used */ + BadName = 15, /* font or color name doesn't exist */ + BadLength = 16, /* Request length incorrect */ + BadImplementation = 17, /* server is defective */ + + FirstExtensionError = 128, + LastExtensionError = 255, + + } + + [Flags] + public enum XEventMask : int + { + NoEventMask = 0, + KeyPressMask = (1 << 0), + KeyReleaseMask = (1 << 1), + ButtonPressMask = (1 << 2), + ButtonReleaseMask = (1 << 3), + EnterWindowMask = (1 << 4), + LeaveWindowMask = (1 << 5), + PointerMotionMask = (1 << 6), + PointerMotionHintMask = (1 << 7), + Button1MotionMask = (1 << 8), + Button2MotionMask = (1 << 9), + Button3MotionMask = (1 << 10), + Button4MotionMask = (1 << 11), + Button5MotionMask = (1 << 12), + ButtonMotionMask = (1 << 13), + KeymapStateMask = (1 << 14), + ExposureMask = (1 << 15), + VisibilityChangeMask = (1 << 16), + StructureNotifyMask = (1 << 17), + ResizeRedirectMask = (1 << 18), + SubstructureNotifyMask = (1 << 19), + SubstructureRedirectMask = (1 << 20), + FocusChangeMask = (1 << 21), + PropertyChangeMask = (1 << 22), + ColormapChangeMask = (1 << 23), + OwnerGrabButtonMask = (1 << 24) + } + + [Flags] + public enum XModifierMask + { + ShiftMask = (1 << 0), + LockMask = (1 << 1), + ControlMask = (1 << 2), + Mod1Mask = (1 << 3), + Mod2Mask = (1 << 4), + Mod3Mask = (1 << 5), + Mod4Mask = (1 << 6), + Mod5Mask = (1 << 7), + Button1Mask = (1 << 8), + Button2Mask = (1 << 9), + Button3Mask = (1 << 10), + Button4Mask = (1 << 11), + Button5Mask = (1 << 12), + AnyModifier = (1 << 15) + + } + + [Flags] + public enum XCreateWindowFlags + { + CWBackPixmap = (1 << 0), + CWBackPixel = (1 << 1), + CWBorderPixmap = (1 << 2), + CWBorderPixel = (1 << 3), + CWBitGravity = (1 << 4), + CWWinGravity = (1 << 5), + CWBackingStore = (1 << 6), + CWBackingPlanes = (1 << 7), + CWBackingPixel = (1 << 8), + CWOverrideRedirect = (1 << 9), + CWSaveUnder = (1 << 10), + CWEventMask = (1 << 11), + CWDontPropagate = (1 << 12), + CWColormap = (1 << 13), + CWCursor = (1 << 14), + } +} diff --git a/src/Avalonia.X11/X11Framebuffer.cs b/src/Avalonia.X11/X11Framebuffer.cs new file mode 100644 index 0000000000..ef93a7347b --- /dev/null +++ b/src/Avalonia.X11/X11Framebuffer.cs @@ -0,0 +1,57 @@ +using System; +using Avalonia.Platform; +using static Avalonia.X11.XLib; +namespace Avalonia.X11 +{ + class X11Framebuffer : ILockedFramebuffer + { + private readonly IntPtr _display; + private readonly IntPtr _xid; + private IUnmanagedBlob _blob; + + public X11Framebuffer(IntPtr display, IntPtr xid, int width, int height, int factor) + { + _display = display; + _xid = xid; + Width = width*factor; + Height = height*factor; + RowBytes = Width * 4; + Dpi = new Vector(96, 96) * factor; + Format = PixelFormat.Bgra8888; + _blob = AvaloniaLocator.Current.GetService().AllocBlob(RowBytes * Height); + Address = _blob.Address; + } + + public void Dispose() + { + var image = new XImage(); + int bitsPerPixel = 32; + image.width = Width; + image.height = Height; + image.format = 2; //ZPixmap; + image.data = Address; + image.byte_order = 0;// LSBFirst; + image.bitmap_unit = bitsPerPixel; + image.bitmap_bit_order = 0;// LSBFirst; + image.bitmap_pad = bitsPerPixel; + image.depth = 32; + image.bytes_per_line = RowBytes - Width * 4; + image.bits_per_pixel = bitsPerPixel; + XLockDisplay(_display); + XInitImage(ref image); + var gc = XCreateGC(_display, _xid, 0, IntPtr.Zero); + XPutImage(_display, _xid, gc, ref image, 0, 0, 0, 0, (uint) Width, (uint) Height); + XFreeGC(_display, gc); + XSync(_display, true); + XUnlockDisplay(_display); + _blob.Dispose(); + } + + public IntPtr Address { get; } + public int Width { get; } + public int Height { get; } + public int RowBytes { get; } + public Vector Dpi { get; } + public PixelFormat Format { get; } + } +} diff --git a/src/Avalonia.X11/X11FramebufferSurface.cs b/src/Avalonia.X11/X11FramebufferSurface.cs new file mode 100644 index 0000000000..05b21efb0c --- /dev/null +++ b/src/Avalonia.X11/X11FramebufferSurface.cs @@ -0,0 +1,27 @@ +using System; +using Avalonia.Controls.Platform.Surfaces; +using Avalonia.Platform; +using static Avalonia.X11.XLib; +namespace Avalonia.X11 +{ + public class X11FramebufferSurface : IFramebufferPlatformSurface + { + private readonly IntPtr _display; + private readonly IntPtr _xid; + + public X11FramebufferSurface(IntPtr display, IntPtr xid) + { + _display = display; + _xid = xid; + } + + public ILockedFramebuffer Lock() + { + XLockDisplay(_display); + XGetGeometry(_display, _xid, out var root, out var x, out var y, out var width, out var height, + out var bw, out var d); + XUnlockDisplay(_display); + return new X11Framebuffer(_display, _xid, width, height, 1); + } + } +} diff --git a/src/Avalonia.X11/X11Info.cs b/src/Avalonia.X11/X11Info.cs new file mode 100644 index 0000000000..6ad9faffbc --- /dev/null +++ b/src/Avalonia.X11/X11Info.cs @@ -0,0 +1,35 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using static Avalonia.X11.XLib; +// ReSharper disable UnusedAutoPropertyAccessor.Local +namespace Avalonia.X11 +{ + class X11Info + { + public IntPtr Display { get; } + public IntPtr DeferredDisplay { get; } + public int DefaultScreen { get; } + public IntPtr BlackPixel { get; } + public IntPtr RootWindow { get; } + public IntPtr DefaultRootWindow { get; } + public XVisualInfo MatchedVisual { get; } + public X11Atoms Atoms { get; } + + public IntPtr LastActivityTimestamp { get; set; } + + public unsafe X11Info(IntPtr display, IntPtr deferredDisplay) + { + Display = display; + DeferredDisplay = deferredDisplay; + DefaultScreen = XDefaultScreen(display); + BlackPixel = XBlackPixel(display, DefaultScreen); + RootWindow = XRootWindow(display, DefaultScreen); + DefaultRootWindow = XDefaultRootWindow(display); + Atoms = new X11Atoms(display); + XMatchVisualInfo(display, DefaultScreen, 32, 4, out var info); + MatchedVisual = info; + } + } +} diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index c266433eef..33497be411 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -1,27 +1,66 @@ using System; +using System.Collections.Generic; using Avalonia.Controls; +using Avalonia.Controls.Platform; +using Avalonia.Input; +using Avalonia.Input.Platform; +using Avalonia.OpenGL; using Avalonia.Platform; +using Avalonia.Rendering; using Avalonia.X11; using static Avalonia.X11.XLib; namespace Avalonia.X11 { - public class AvaloniaX11Platform + class AvaloniaX11Platform : IWindowingPlatform { + private Lazy _keyboardDevice = new Lazy(() => new KeyboardDevice()); + private Lazy _mouseDevice = new Lazy(() => new MouseDevice()); + public KeyboardDevice KeyboardDevice => _keyboardDevice.Value; + public MouseDevice MouseDevice => _mouseDevice.Value; + public Dictionary> Windows = new Dictionary>(); + public X11Info Info { get; private set; } public void Initialize() { + 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); AvaloniaLocator.CurrentMutable.BindToSelf(this) - .Bind().ToConstant(new X11PlatformThreading(Display)); + .Bind().ToConstant(this) + .Bind().ToConstant(new X11PlatformThreading(Display, Windows)) + .Bind().ToConstant(new DefaultRenderTimer(60)) + .Bind().ToConstant(new RenderLoop()) + .Bind().ToConstant(new PlatformHotkeyConfiguration(InputModifiers.Control)) + .Bind().ToFunc(() => KeyboardDevice) + .Bind().ToConstant(new CursorFactoryStub()) + .Bind().ToSingleton() + .Bind().ToConstant(new PlatformSettingsStub()) + .Bind().ToConstant(new SystemDialogsStub()) + .Bind().ToConstant(new IconLoaderStub()); + EglGlPlatformFeature.TryInitialize(); } public IntPtr DeferredDisplay { get; set; } public IntPtr Display { get; set; } + public IWindowImpl CreateWindow() + { + return new X11Window(this, false); + } + + public IEmbeddableWindowImpl CreateEmbeddableWindow() + { + throw new NotSupportedException(); + } + + public IPopupImpl CreatePopup() + { + return new X11Window(this, true); + } } } @@ -34,6 +73,8 @@ namespace Avalonia builder.UseWindowingSubsystem(() => new AvaloniaX11Platform().Initialize()); return builder; } + + public static void InitializeX11Platform() => new AvaloniaX11Platform().Initialize(); } } diff --git a/src/Avalonia.X11/X11PlatformThreading.cs b/src/Avalonia.X11/X11PlatformThreading.cs index 18b08085e3..298b4da19c 100644 --- a/src/Avalonia.X11/X11PlatformThreading.cs +++ b/src/Avalonia.X11/X11PlatformThreading.cs @@ -9,9 +9,10 @@ using static Avalonia.X11.XLib; namespace Avalonia.X11 { - public unsafe class X11PlatformThreading : IPlatformThreadingInterface + unsafe class X11PlatformThreading : IPlatformThreadingInterface { private readonly IntPtr _display; + private readonly Dictionary> _eventHandlers; private Thread _mainThread; [StructLayout(LayoutKind.Explicit)] @@ -102,9 +103,10 @@ namespace Avalonia.X11 List _timers = new List(); - public X11PlatformThreading(IntPtr display) + public X11PlatformThreading(IntPtr display, Dictionary> eventHandlers) { _display = display; + _eventHandlers = eventHandlers; _mainThread = Thread.CurrentThread; var fd = XLib.XConnectionNumber(display); var ev = new epoll_event() @@ -202,12 +204,22 @@ namespace Avalonia.X11 } else { - while (XPending(_display)) + while (true) { - if (cancellationToken.IsCancellationRequested) - return; - XNextEvent(_display, out var xev); + var pending = XPending(_display); + if (pending == 0) + break; + while (pending > 0) + { + if (cancellationToken.IsCancellationRequested) + return; + XNextEvent(_display, out var xev); + pending--; + if (_eventHandlers.TryGetValue(xev.AnyEvent.window, out var handler)) + handler(xev); + } } + Dispatcher.UIThread.RunJobs(); } } } diff --git a/src/Avalonia.X11/X11Structs.cs b/src/Avalonia.X11/X11Structs.cs new file mode 100644 index 0000000000..a18bd4be74 --- /dev/null +++ b/src/Avalonia.X11/X11Structs.cs @@ -0,0 +1,1815 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software",, to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// NOT COMPLETE + +using System; +using System.ComponentModel; +using System.Collections; +using System.Drawing; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.InteropServices; +// ReSharper disable FieldCanBeMadeReadOnly.Global +// ReSharper disable IdentifierTypo +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedMember.Global +// ReSharper disable CommentTypo +// ReSharper disable ArrangeThisQualifier +// ReSharper disable NotAccessedField.Global +#pragma warning disable 649 + +namespace Avalonia.X11 { + // + // In the structures below, fields of type long are mapped to IntPtr. + // This will work on all platforms where sizeof(long)==sizeof(void*), which + // is almost all platforms except WIN64. + // + + [StructLayout(LayoutKind.Sequential)] + internal struct XAnyEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XKeyEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr root; + internal IntPtr subwindow; + internal IntPtr time; + internal int x; + internal int y; + internal int x_root; + internal int y_root; + internal int state; + internal int keycode; + internal bool same_screen; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XButtonEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr root; + internal IntPtr subwindow; + internal IntPtr time; + internal int x; + internal int y; + internal int x_root; + internal int y_root; + internal XModifierMask state; + internal int button; + internal bool same_screen; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XMotionEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr root; + internal IntPtr subwindow; + internal IntPtr time; + internal int x; + internal int y; + internal int x_root; + internal int y_root; + internal XModifierMask state; + internal byte is_hint; + internal bool same_screen; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XCrossingEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr root; + internal IntPtr subwindow; + internal IntPtr time; + internal int x; + internal int y; + internal int x_root; + internal int y_root; + internal NotifyMode mode; + internal NotifyDetail detail; + internal bool same_screen; + internal bool focus; + internal int state; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XFocusChangeEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal int mode; + internal NotifyDetail detail; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XKeymapEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal byte key_vector0; + internal byte key_vector1; + internal byte key_vector2; + internal byte key_vector3; + internal byte key_vector4; + internal byte key_vector5; + internal byte key_vector6; + internal byte key_vector7; + internal byte key_vector8; + internal byte key_vector9; + internal byte key_vector10; + internal byte key_vector11; + internal byte key_vector12; + internal byte key_vector13; + internal byte key_vector14; + internal byte key_vector15; + internal byte key_vector16; + internal byte key_vector17; + internal byte key_vector18; + internal byte key_vector19; + internal byte key_vector20; + internal byte key_vector21; + internal byte key_vector22; + internal byte key_vector23; + internal byte key_vector24; + internal byte key_vector25; + internal byte key_vector26; + internal byte key_vector27; + internal byte key_vector28; + internal byte key_vector29; + internal byte key_vector30; + internal byte key_vector31; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XExposeEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal int x; + internal int y; + internal int width; + internal int height; + internal int count; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XGraphicsExposeEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr drawable; + internal int x; + internal int y; + internal int width; + internal int height; + internal int count; + internal int major_code; + internal int minor_code; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XNoExposeEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr drawable; + internal int major_code; + internal int minor_code; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XVisibilityEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal int state; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XCreateWindowEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr parent; + internal IntPtr window; + internal int x; + internal int y; + internal int width; + internal int height; + internal int border_width; + internal bool override_redirect; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XDestroyWindowEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XUnmapEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + internal bool from_configure; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XMapEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + internal bool override_redirect; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XMapRequestEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr parent; + internal IntPtr window; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XReparentEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + internal IntPtr parent; + internal int x; + internal int y; + internal bool override_redirect; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XConfigureEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + internal int x; + internal int y; + internal int width; + internal int height; + internal int border_width; + internal IntPtr above; + internal bool override_redirect; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XGravityEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + internal int x; + internal int y; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XResizeRequestEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal int width; + internal int height; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XConfigureRequestEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr parent; + internal IntPtr window; + internal int x; + internal int y; + internal int width; + internal int height; + internal int border_width; + internal IntPtr above; + internal int detail; + internal IntPtr value_mask; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XCirculateEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + internal int place; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XCirculateRequestEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr parent; + internal IntPtr window; + internal int place; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XPropertyEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr atom; + internal IntPtr time; + internal int state; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XSelectionClearEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr selection; + internal IntPtr time; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XSelectionRequestEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr owner; + internal IntPtr requestor; + internal IntPtr selection; + internal IntPtr target; + internal IntPtr property; + internal IntPtr time; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XSelectionEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr requestor; + internal IntPtr selection; + internal IntPtr target; + internal IntPtr property; + internal IntPtr time; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XColormapEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr colormap; + internal bool c_new; + internal int state; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XClientMessageEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr message_type; + internal int format; + internal IntPtr ptr1; + internal IntPtr ptr2; + internal IntPtr ptr3; + internal IntPtr ptr4; + internal IntPtr ptr5; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XMappingEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal int request; + internal int first_keycode; + internal int count; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XErrorEvent { + internal XEventName type; + internal IntPtr display; + internal IntPtr resourceid; + internal IntPtr serial; + internal byte error_code; + internal XRequest request_code; + internal byte minor_code; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XEventPad { + internal IntPtr pad0; + internal IntPtr pad1; + internal IntPtr pad2; + internal IntPtr pad3; + internal IntPtr pad4; + internal IntPtr pad5; + internal IntPtr pad6; + internal IntPtr pad7; + internal IntPtr pad8; + internal IntPtr pad9; + internal IntPtr pad10; + internal IntPtr pad11; + internal IntPtr pad12; + internal IntPtr pad13; + internal IntPtr pad14; + internal IntPtr pad15; + internal IntPtr pad16; + internal IntPtr pad17; + internal IntPtr pad18; + internal IntPtr pad19; + internal IntPtr pad20; + internal IntPtr pad21; + internal IntPtr pad22; + internal IntPtr pad23; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct XEvent { + [ FieldOffset(0) ] internal XEventName type; + [ FieldOffset(0) ] internal XAnyEvent AnyEvent; + [ FieldOffset(0) ] internal XKeyEvent KeyEvent; + [ FieldOffset(0) ] internal XButtonEvent ButtonEvent; + [ FieldOffset(0) ] internal XMotionEvent MotionEvent; + [ FieldOffset(0) ] internal XCrossingEvent CrossingEvent; + [ FieldOffset(0) ] internal XFocusChangeEvent FocusChangeEvent; + [ FieldOffset(0) ] internal XExposeEvent ExposeEvent; + [ FieldOffset(0) ] internal XGraphicsExposeEvent GraphicsExposeEvent; + [ FieldOffset(0) ] internal XNoExposeEvent NoExposeEvent; + [ FieldOffset(0) ] internal XVisibilityEvent VisibilityEvent; + [ FieldOffset(0) ] internal XCreateWindowEvent CreateWindowEvent; + [ FieldOffset(0) ] internal XDestroyWindowEvent DestroyWindowEvent; + [ FieldOffset(0) ] internal XUnmapEvent UnmapEvent; + [ FieldOffset(0) ] internal XMapEvent MapEvent; + [ FieldOffset(0) ] internal XMapRequestEvent MapRequestEvent; + [ FieldOffset(0) ] internal XReparentEvent ReparentEvent; + [ FieldOffset(0) ] internal XConfigureEvent ConfigureEvent; + [ FieldOffset(0) ] internal XGravityEvent GravityEvent; + [ FieldOffset(0) ] internal XResizeRequestEvent ResizeRequestEvent; + [ FieldOffset(0) ] internal XConfigureRequestEvent ConfigureRequestEvent; + [ FieldOffset(0) ] internal XCirculateEvent CirculateEvent; + [ FieldOffset(0) ] internal XCirculateRequestEvent CirculateRequestEvent; + [ FieldOffset(0) ] internal XPropertyEvent PropertyEvent; + [ FieldOffset(0) ] internal XSelectionClearEvent SelectionClearEvent; + [ FieldOffset(0) ] internal XSelectionRequestEvent SelectionRequestEvent; + [ FieldOffset(0) ] internal XSelectionEvent SelectionEvent; + [ FieldOffset(0) ] internal XColormapEvent ColormapEvent; + [ FieldOffset(0) ] internal XClientMessageEvent ClientMessageEvent; + [ FieldOffset(0) ] internal XMappingEvent MappingEvent; + [ FieldOffset(0) ] internal XErrorEvent ErrorEvent; + [ FieldOffset(0) ] internal XKeymapEvent KeymapEvent; + + //[MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=24)] + //[ FieldOffset(0) ] internal int[] pad; + [ FieldOffset(0) ] internal XEventPad Pad; + public override string ToString() { + switch (type) + { + case XEventName.ButtonPress: + case XEventName.ButtonRelease: + return ToString (ButtonEvent); + case XEventName.CirculateNotify: + case XEventName.CirculateRequest: + return ToString (CirculateEvent); + case XEventName.ClientMessage: + return ToString (ClientMessageEvent); + case XEventName.ColormapNotify: + return ToString (ColormapEvent); + case XEventName.ConfigureNotify: + return ToString (ConfigureEvent); + case XEventName.ConfigureRequest: + return ToString (ConfigureRequestEvent); + case XEventName.CreateNotify: + return ToString (CreateWindowEvent); + case XEventName.DestroyNotify: + return ToString (DestroyWindowEvent); + case XEventName.Expose: + return ToString (ExposeEvent); + case XEventName.FocusIn: + case XEventName.FocusOut: + return ToString (FocusChangeEvent); + case XEventName.GraphicsExpose: + return ToString (GraphicsExposeEvent); + case XEventName.GravityNotify: + return ToString (GravityEvent); + case XEventName.KeymapNotify: + return ToString (KeymapEvent); + case XEventName.MapNotify: + return ToString (MapEvent); + case XEventName.MappingNotify: + return ToString (MappingEvent); + case XEventName.MapRequest: + return ToString (MapRequestEvent); + case XEventName.MotionNotify: + return ToString (MotionEvent); + case XEventName.NoExpose: + return ToString (NoExposeEvent); + case XEventName.PropertyNotify: + return ToString (PropertyEvent); + case XEventName.ReparentNotify: + return ToString (ReparentEvent); + case XEventName.ResizeRequest: + return ToString (ResizeRequestEvent); + case XEventName.SelectionClear: + return ToString (SelectionClearEvent); + case XEventName.SelectionNotify: + return ToString (SelectionEvent); + case XEventName.SelectionRequest: + return ToString (SelectionRequestEvent); + case XEventName.UnmapNotify: + return ToString (UnmapEvent); + case XEventName.VisibilityNotify: + return ToString (VisibilityEvent); + case XEventName.EnterNotify: + case XEventName.LeaveNotify: + return ToString (CrossingEvent); + default: + return type.ToString (); + } + } + + public static string ToString (object ev) + { + string result = string.Empty; + Type type = ev.GetType (); + FieldInfo [] fields = type.GetFields (System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance); + for (int i = 0; i < fields.Length; i++) { + if (result != string.Empty) { + result += ", "; + } + object value = fields [i].GetValue (ev); + result += fields [i].Name + "=" + (value == null ? "" : value.ToString ()); + } + return type.Name + " (" + result + ")"; + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XSetWindowAttributes { + internal IntPtr background_pixmap; + internal IntPtr background_pixel; + internal IntPtr border_pixmap; + internal IntPtr border_pixel; + internal Gravity bit_gravity; + internal Gravity win_gravity; + internal int backing_store; + internal IntPtr backing_planes; + internal IntPtr backing_pixel; + internal bool save_under; + internal IntPtr event_mask; + internal IntPtr do_not_propagate_mask; + internal bool override_redirect; + internal IntPtr colormap; + internal IntPtr cursor; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XWindowAttributes { + internal int x; + internal int y; + internal int width; + internal int height; + internal int border_width; + internal int depth; + internal IntPtr visual; + internal IntPtr root; + internal int c_class; + internal Gravity bit_gravity; + internal Gravity win_gravity; + internal int backing_store; + internal IntPtr backing_planes; + internal IntPtr backing_pixel; + internal bool save_under; + internal IntPtr colormap; + internal bool map_installed; + internal MapState map_state; + internal IntPtr all_event_masks; + internal IntPtr your_event_mask; + internal IntPtr do_not_propagate_mask; + internal bool override_direct; + internal IntPtr screen; + + public override string ToString () + { + return XEvent.ToString (this); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XTextProperty { + internal string value; + internal IntPtr encoding; + internal int format; + internal IntPtr nitems; + } + + internal enum XWindowClass { + InputOutput = 1, + InputOnly = 2 + } + + internal enum XEventName { + KeyPress = 2, + KeyRelease = 3, + ButtonPress = 4, + ButtonRelease = 5, + MotionNotify = 6, + EnterNotify = 7, + LeaveNotify = 8, + FocusIn = 9, + FocusOut = 10, + KeymapNotify = 11, + Expose = 12, + GraphicsExpose = 13, + NoExpose = 14, + VisibilityNotify = 15, + CreateNotify = 16, + DestroyNotify = 17, + UnmapNotify = 18, + MapNotify = 19, + MapRequest = 20, + ReparentNotify = 21, + ConfigureNotify = 22, + ConfigureRequest = 23, + GravityNotify = 24, + ResizeRequest = 25, + CirculateNotify = 26, + CirculateRequest = 27, + PropertyNotify = 28, + SelectionClear = 29, + SelectionRequest = 30, + SelectionNotify = 31, + ColormapNotify = 32, + ClientMessage = 33, + MappingNotify = 34, + + LASTEvent + } + + [Flags] + internal enum SetWindowValuemask { + Nothing = 0, + BackPixmap = 1, + BackPixel = 2, + BorderPixmap = 4, + BorderPixel = 8, + BitGravity = 16, + WinGravity = 32, + BackingStore = 64, + BackingPlanes = 128, + BackingPixel = 256, + OverrideRedirect = 512, + SaveUnder = 1024, + EventMask = 2048, + DontPropagate = 4096, + ColorMap = 8192, + Cursor = 16384 + } + + internal enum SendEventValues { + PointerWindow = 0, + InputFocus = 1 + } + + internal enum CreateWindowArgs { + CopyFromParent = 0, + ParentRelative = 1, + InputOutput = 1, + InputOnly = 2 + } + + internal enum Gravity { + ForgetGravity = 0, + NorthWestGravity= 1, + NorthGravity = 2, + NorthEastGravity= 3, + WestGravity = 4, + CenterGravity = 5, + EastGravity = 6, + SouthWestGravity= 7, + SouthGravity = 8, + SouthEastGravity= 9, + StaticGravity = 10 + } + + internal enum XKeySym : uint { + XK_BackSpace = 0xFF08, + XK_Tab = 0xFF09, + XK_Clear = 0xFF0B, + XK_Return = 0xFF0D, + XK_Home = 0xFF50, + XK_Left = 0xFF51, + XK_Up = 0xFF52, + XK_Right = 0xFF53, + XK_Down = 0xFF54, + XK_Page_Up = 0xFF55, + XK_Page_Down = 0xFF56, + XK_End = 0xFF57, + XK_Begin = 0xFF58, + XK_Menu = 0xFF67, + XK_Shift_L = 0xFFE1, + XK_Shift_R = 0xFFE2, + XK_Control_L = 0xFFE3, + XK_Control_R = 0xFFE4, + XK_Caps_Lock = 0xFFE5, + XK_Shift_Lock = 0xFFE6, + XK_Meta_L = 0xFFE7, + XK_Meta_R = 0xFFE8, + XK_Alt_L = 0xFFE9, + XK_Alt_R = 0xFFEA, + XK_Super_L = 0xFFEB, + XK_Super_R = 0xFFEC, + XK_Hyper_L = 0xFFED, + XK_Hyper_R = 0xFFEE, + } + + [Flags] + internal enum EventMask { + NoEventMask = 0, + KeyPressMask = 1<<0, + KeyReleaseMask = 1<<1, + ButtonPressMask = 1<<2, + ButtonReleaseMask = 1<<3, + EnterWindowMask = 1<<4, + LeaveWindowMask = 1<<5, + PointerMotionMask = 1<<6, + PointerMotionHintMask = 1<<7, + Button1MotionMask = 1<<8, + Button2MotionMask = 1<<9, + Button3MotionMask = 1<<10, + Button4MotionMask = 1<<11, + Button5MotionMask = 1<<12, + ButtonMotionMask = 1<<13, + KeymapStateMask = 1<<14, + ExposureMask = 1<<15, + VisibilityChangeMask = 1<<16, + StructureNotifyMask = 1<<17, + ResizeRedirectMask = 1<<18, + SubstructureNotifyMask = 1<<19, + SubstructureRedirectMask= 1<<20, + FocusChangeMask = 1<<21, + PropertyChangeMask = 1<<22, + ColormapChangeMask = 1<<23, + OwnerGrabButtonMask = 1<<24 + } + + internal enum GrabMode { + GrabModeSync = 0, + GrabModeAsync = 1 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XStandardColormap { + internal IntPtr colormap; + internal IntPtr red_max; + internal IntPtr red_mult; + internal IntPtr green_max; + internal IntPtr green_mult; + internal IntPtr blue_max; + internal IntPtr blue_mult; + internal IntPtr base_pixel; + internal IntPtr visualid; + internal IntPtr killid; + } + + [StructLayout(LayoutKind.Sequential, Pack=2)] + internal struct XColor { + internal IntPtr pixel; + internal ushort red; + internal ushort green; + internal ushort blue; + internal byte flags; + internal byte pad; + } + + internal enum Atom { + AnyPropertyType = 0, + XA_PRIMARY = 1, + XA_SECONDARY = 2, + XA_ARC = 3, + XA_ATOM = 4, + XA_BITMAP = 5, + XA_CARDINAL = 6, + XA_COLORMAP = 7, + XA_CURSOR = 8, + XA_CUT_BUFFER0 = 9, + XA_CUT_BUFFER1 = 10, + XA_CUT_BUFFER2 = 11, + XA_CUT_BUFFER3 = 12, + XA_CUT_BUFFER4 = 13, + XA_CUT_BUFFER5 = 14, + XA_CUT_BUFFER6 = 15, + XA_CUT_BUFFER7 = 16, + XA_DRAWABLE = 17, + XA_FONT = 18, + XA_INTEGER = 19, + XA_PIXMAP = 20, + XA_POINT = 21, + XA_RECTANGLE = 22, + XA_RESOURCE_MANAGER = 23, + XA_RGB_COLOR_MAP = 24, + XA_RGB_BEST_MAP = 25, + XA_RGB_BLUE_MAP = 26, + XA_RGB_DEFAULT_MAP = 27, + XA_RGB_GRAY_MAP = 28, + XA_RGB_GREEN_MAP = 29, + XA_RGB_RED_MAP = 30, + XA_STRING = 31, + XA_VISUALID = 32, + XA_WINDOW = 33, + XA_WM_COMMAND = 34, + XA_WM_HINTS = 35, + XA_WM_CLIENT_MACHINE = 36, + XA_WM_ICON_NAME = 37, + XA_WM_ICON_SIZE = 38, + XA_WM_NAME = 39, + XA_WM_NORMAL_HINTS = 40, + XA_WM_SIZE_HINTS = 41, + XA_WM_ZOOM_HINTS = 42, + XA_MIN_SPACE = 43, + XA_NORM_SPACE = 44, + XA_MAX_SPACE = 45, + XA_END_SPACE = 46, + XA_SUPERSCRIPT_X = 47, + XA_SUPERSCRIPT_Y = 48, + XA_SUBSCRIPT_X = 49, + XA_SUBSCRIPT_Y = 50, + XA_UNDERLINE_POSITION = 51, + XA_UNDERLINE_THICKNESS = 52, + XA_STRIKEOUT_ASCENT = 53, + XA_STRIKEOUT_DESCENT = 54, + XA_ITALIC_ANGLE = 55, + XA_X_HEIGHT = 56, + XA_QUAD_WIDTH = 57, + XA_WEIGHT = 58, + XA_POINT_SIZE = 59, + XA_RESOLUTION = 60, + XA_COPYRIGHT = 61, + XA_NOTICE = 62, + XA_FONT_NAME = 63, + XA_FAMILY_NAME = 64, + XA_FULL_NAME = 65, + XA_CAP_HEIGHT = 66, + XA_WM_CLASS = 67, + XA_WM_TRANSIENT_FOR = 68, + + XA_LAST_PREDEFINED = 68 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XScreen { + internal IntPtr ext_data; + internal IntPtr display; + internal IntPtr root; + internal int width; + internal int height; + internal int mwidth; + internal int mheight; + internal int ndepths; + internal IntPtr depths; + internal int root_depth; + internal IntPtr root_visual; + internal IntPtr default_gc; + internal IntPtr cmap; + internal IntPtr white_pixel; + internal IntPtr black_pixel; + internal int max_maps; + internal int min_maps; + internal int backing_store; + internal bool save_unders; + internal IntPtr root_input_mask; + } + + [Flags] + internal enum ChangeWindowFlags { + CWX = 1<<0, + CWY = 1<<1, + CWWidth = 1<<2, + CWHeight = 1<<3, + CWBorderWidth = 1<<4, + CWSibling = 1<<5, + CWStackMode = 1<<6 + } + + internal enum StackMode { + Above = 0, + Below = 1, + TopIf = 2, + BottomIf = 3, + Opposite = 4 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XWindowChanges { + internal int x; + internal int y; + internal int width; + internal int height; + internal int border_width; + internal IntPtr sibling; + internal StackMode stack_mode; + } + + [Flags] + internal enum ColorFlags { + DoRed = 1<<0, + DoGreen = 1<<1, + DoBlue = 1<<2 + } + + internal enum NotifyMode { + NotifyNormal = 0, + NotifyGrab = 1, + NotifyUngrab = 2 + } + + internal enum NotifyDetail { + NotifyAncestor = 0, + NotifyVirtual = 1, + NotifyInferior = 2, + NotifyNonlinear = 3, + NotifyNonlinearVirtual = 4, + NotifyPointer = 5, + NotifyPointerRoot = 6, + NotifyDetailNone = 7 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MotifWmHints { + internal IntPtr flags; + internal IntPtr functions; + internal IntPtr decorations; + internal IntPtr input_mode; + internal IntPtr status; + + public override string ToString () + { + return string.Format("MotifWmHints _eventHandler; + private bool _invalidated; + private XConfigureEvent? _configure; + private IInputRoot _inputRoot; + private IMouseDevice _mouse; + private Point _position; + private IntPtr _handle; + private bool _mapped; + + class InputEventContainer + { + public RawInputEventArgs Event; + } + private Queue _inputQueue = new Queue(); + private InputEventContainer _lastEvent; + + public X11Window(AvaloniaX11Platform platform, bool popup) + { + _platform = platform; + _popup = popup; + _x11 = platform.Info; + _mouse = platform.MouseDevice; + + + XSetWindowAttributes attr = new XSetWindowAttributes(); + var valueMask = default(SetWindowValuemask); + /* + _handle = XCreateSimpleWindow(_x11.Display, _x11.DefaultRootWindow, 10, 10, 100, 100, 0, IntPtr.Zero, + IntPtr.Zero);*/ + var vinfo = _x11.MatchedVisual; + attr.colormap = XCreateColormap(_x11.Display, _x11.RootWindow, vinfo.visual, 0); + attr.backing_store = 2; + attr.bit_gravity = Gravity.NorthWestGravity; + attr.win_gravity = Gravity.NorthWestGravity; + valueMask |= SetWindowValuemask.ColorMap | SetWindowValuemask.BackPixel | SetWindowValuemask.BorderPixel + | SetWindowValuemask.BackPixmap | SetWindowValuemask.BackingStore + | SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity; + + if (popup) + { + attr.override_redirect = true; + valueMask |= SetWindowValuemask.OverrideRedirect; + } + + _handle = XCreateWindow(_x11.Display, _x11.RootWindow, 10, 10, 300, 200, 0, + (int)vinfo.depth, + (int)CreateWindowArgs.InputOutput, vinfo.visual, + new UIntPtr((uint)valueMask), ref attr); + + + Handle = new PlatformHandle(_handle, "XID"); + ClientSize = new Size(400, 400); + _eventHandler = OnEvent; + platform.Windows[_handle] = _eventHandler; + XSelectInput(_x11.Display, _handle, + new IntPtr(0xffffff + ^ (int)XEventMask.SubstructureRedirectMask + ^ (int)XEventMask.ResizeRedirectMask + ^ (int)XEventMask.PointerMotionHintMask)); + var protocols = new[] + { + _x11.Atoms.WM_DELETE_WINDOW + }; + XSetWMProtocols(_x11.Display, _handle, protocols, protocols.Length); + var feature = (EglGlPlatformFeature)AvaloniaLocator.Current.GetService(); + var surfaces = new List + { + new X11FramebufferSurface(_x11.DeferredDisplay, _handle) + }; + if (feature != null) + surfaces.Insert(0, + new EglGlPlatformSurface((EglDisplay)feature.Display, feature.DeferredContext, + new SurfaceInfo(_x11.DeferredDisplay, _handle))); + Surfaces = surfaces.ToArray(); + UpdateWmHits(); + XFlush(_x11.Display); + } + + class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo + { + private readonly IntPtr _display; + + public SurfaceInfo(IntPtr display, IntPtr xid) + { + _display = display; + Handle = xid; + } + public IntPtr Handle { get; } + + public System.Drawing.Size PixelSize + { + get + { + XLockDisplay(_display); + + XGetGeometry(_display, Handle, out var geo); + XUnlockDisplay(_display); + return new System.Drawing.Size(geo.width, geo.height); + } + } + + public double Scaling { get; } = 1; + } + + void UpdateWmHits() + { + var functions = MotifFunctions.All; + var decorations = MotifDecorations.All; + + if (_popup || !_systemDecorations) + { + functions = 0; + decorations = 0; + } + + if (!_canResize) + { + functions ^= MotifFunctions.Resize | MotifFunctions.Maximize; + decorations ^= MotifDecorations.Maximize | MotifDecorations.ResizeH; + } + + var hints = new MotifWmHints(); + hints.flags = new IntPtr((int)(MotifFlags.Decorations | MotifFlags.Functions)); + + hints.decorations = new IntPtr((int)decorations); + hints.functions = new IntPtr((int)functions); + + XChangeProperty(_x11.Display, _handle, + _x11.Atoms._MOTIF_WM_HINTS, _x11.Atoms._MOTIF_WM_HINTS, 32, + PropertyMode.Replace, ref hints, 5); + } + + public Size ClientSize { get; private set; } + public double Scaling { get; } = 1; + public IEnumerable Surfaces { get; } + public Action Input { get; set; } + public Action Paint { get; set; } + public Action Resized { get; set; } + public Action ScalingChanged { get; set; } + public Action Deactivated { get; set; } + public Action Activated { get; set; } + public Func Closing { get; set; } + public WindowState WindowState { get; set; } + public Action WindowStateChanged { get; set; } + public Action Closed { get; set; } + public Action PositionChanged { get; set; } + + public IRenderer CreateRenderer(IRenderRoot root) => + new DeferredRenderer(root, AvaloniaLocator.Current.GetService()); + + unsafe void OnEvent(XEvent ev) + { + if (ev.type == XEventName.MapNotify) + _mapped = true; + else if (ev.type == XEventName.UnmapNotify) + _mapped = false; + else if (ev.type == XEventName.Expose) + DoPaint(); + else if (ev.type == XEventName.FocusIn) + Activated?.Invoke(); + else if (ev.type == XEventName.FocusOut) + Deactivated?.Invoke(); + else if (ev.type == XEventName.MotionNotify) + MouseEvent(RawMouseEventType.Move, ev, ev.MotionEvent.state); + + else if (ev.type == XEventName.ButtonPress) + { + if (ev.ButtonEvent.button < 4) + MouseEvent(ev.ButtonEvent.button == 1 ? RawMouseEventType.LeftButtonDown + : ev.ButtonEvent.button == 2 ? RawMouseEventType.MiddleButtonDown + : RawMouseEventType.RightButtonDown, ev, ev.ButtonEvent.state); + else + { + var delta = ev.ButtonEvent.button == 4 + ? new Vector(0, 1) + : ev.ButtonEvent.button == 5 + ? new Vector(0, -1) + : ev.ButtonEvent.button == 6 + ? new Vector(1, 0) + : new Vector(-1, 0); + ScheduleInput(new RawMouseWheelEventArgs(_mouse, (ulong)ev.ButtonEvent.time.ToInt64(), + _inputRoot, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), delta, + TranslateModifiers(ev.ButtonEvent.state))); + } + + } + else if (ev.type == XEventName.ButtonRelease) + { + if (ev.ButtonEvent.button < 4) + MouseEvent(ev.ButtonEvent.button == 1 ? RawMouseEventType.LeftButtonUp + : ev.ButtonEvent.button == 2 ? RawMouseEventType.MiddleButtonUp + : RawMouseEventType.RightButtonUp, ev, ev.ButtonEvent.state); + } + else if (ev.type == XEventName.ConfigureNotify) + { + var needEnqueue = (_configure == null); + _configure = ev.ConfigureEvent; + if (needEnqueue) + Dispatcher.UIThread.Post(() => + { + if (_configure == null) + return; + var cev = _configure.Value; + _configure = null; + var nsize = new Size(cev.width, cev.height); + var npos = new Point(cev.x, cev.y); + var changedSize = ClientSize != nsize; + var changedPos = npos != _position; + ClientSize = nsize; + _position = npos; + if (changedSize) + Resized?.Invoke(nsize); + if (changedPos) + PositionChanged?.Invoke(npos); + }); + } + else if (ev.type == XEventName.DestroyNotify) + { + if (_handle != IntPtr.Zero) + { + _platform.Windows.Remove(_handle); + _handle = IntPtr.Zero; + Closed?.Invoke(); + } + } + else if (ev.type == XEventName.ClientMessage) + { + if (ev.ClientMessageEvent.message_type == _x11.Atoms.WM_PROTOCOLS) + { + if (ev.ClientMessageEvent.ptr1 == _x11.Atoms.WM_DELETE_WINDOW) + { + if (Closing?.Invoke() != true) + Dispose(); + } + + } + } + } + + + + InputModifiers TranslateModifiers(XModifierMask state) + { + var rv = default(InputModifiers); + if (state.HasFlag(XModifierMask.Button1Mask)) + rv |= InputModifiers.LeftMouseButton; + if (state.HasFlag(XModifierMask.Button2Mask)) + rv |= InputModifiers.RightMouseButton; + if (state.HasFlag(XModifierMask.Button2Mask)) + rv |= InputModifiers.MiddleMouseButton; + if (state.HasFlag(XModifierMask.ShiftMask)) + rv |= InputModifiers.Shift; + if (state.HasFlag(XModifierMask.ControlMask)) + rv |= InputModifiers.Control; + if (state.HasFlag(XModifierMask.Mod1Mask)) + rv |= InputModifiers.Alt; + if (state.HasFlag(XModifierMask.Mod4Mask)) + rv |= InputModifiers.Windows; + return rv; + } + static Stopwatch St = Stopwatch.StartNew(); + private bool _systemDecorations = true; + private bool _canResize = true; + + void ScheduleInput(RawInputEventArgs args) + { + _lastEvent = new InputEventContainer() {Event = args}; + _inputQueue.Enqueue(_lastEvent); + if (_inputQueue.Count == 1) + { + Dispatcher.UIThread.Post(() => + { + while (_inputQueue.Count > 0) + { + Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); + var ev = _inputQueue.Dequeue(); + Input?.Invoke(ev.Event); + } + }, DispatcherPriority.Input); + } + } + + void MouseEvent(RawMouseEventType type, XEvent ev, XModifierMask mods) + { + _x11.LastActivityTimestamp = ev.ButtonEvent.time; + var mev = new RawMouseEventArgs( + _mouse, (ulong)ev.ButtonEvent.time.ToInt64(), _inputRoot, + type, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), TranslateModifiers(mods)); + if(type == RawMouseEventType.Move && _inputQueue.Count>0 && _lastEvent.Event is RawMouseEventArgs ma) + if (ma.Type == RawMouseEventType.Move) + { + _lastEvent.Event = mev; + return; + } + ScheduleInput(mev); + } + + void DoPaint() + { + _invalidated = false; + Paint?.Invoke(new Rect()); + } + + public void Invalidate(Rect rect) + { + if(_invalidated) + return; + _invalidated = true; + Dispatcher.UIThread.InvokeAsync(() => + { + if (_mapped) + DoPaint(); + }); + } + + public void SetInputRoot(IInputRoot inputRoot) + { + _inputRoot = inputRoot; + } + + public void Dispose() + { + if (_handle != IntPtr.Zero) + { + XDestroyWindow(_x11.Display, _handle); + _platform.Windows.Remove(_handle); + _handle = IntPtr.Zero; + Closed?.Invoke(); + + } + } + + public void Show() => XMapWindow(_x11.Display, _handle); + + public void Hide() => XUnmapWindow(_x11.Display, _handle); + + + public Point PointToClient(Point point) => new Point(point.X - _position.X, point.Y - _position.Y); + + public Point PointToScreen(Point point) => new Point(point.X + _position.X, point.Y + _position.Y); + + public void SetSystemDecorations(bool enabled) + { + _systemDecorations = enabled; + UpdateWmHits(); + } + + + public void Resize(Size clientSize) + { + if (clientSize == ClientSize) + return; + var changes = new XWindowChanges(); + changes.width = (int)clientSize.Width; + changes.height = (int)clientSize.Height; + var needResize = clientSize != ClientSize; + XConfigureWindow(_x11.Display, _handle, ChangeWindowFlags.CWHeight | ChangeWindowFlags.CWWidth, + ref changes); + XFlush(_x11.Display); + + if (_popup && needResize) + { + ClientSize = clientSize; + Resized?.Invoke(clientSize); + } + } + + public void CanResize(bool value) + { + _canResize = value; + UpdateWmHits(); + } + + public void SetCursor(IPlatformHandle cursor) + { + } + + public IPlatformHandle Handle { get; } + + public Point Position + { + get => _position; + set + { + var changes = new XWindowChanges(); + changes.x = (int)value.X; + changes.y = (int)value.Y; + XConfigureWindow(_x11.Display, _handle, ChangeWindowFlags.CWX | ChangeWindowFlags.CWY, + ref changes); + XFlush(_x11.Display); + + } + } + + public IMouseDevice MouseDevice => _mouse; + + public unsafe void Activate() + { + if (_x11.Atoms._NET_ACTIVE_WINDOW != IntPtr.Zero) + { + + var ev = new XEvent + { + AnyEvent = + { + type = XEventName.ClientMessage, + window = _handle, + }, + ClientMessageEvent = { + message_type = _x11.Atoms._NET_ACTIVE_WINDOW, + format = 32, + ptr1 = new IntPtr(1), + ptr2 = _x11.LastActivityTimestamp + + } + }; + + XSendEvent(_x11.Display, _x11.RootWindow, false, + new IntPtr((int)(XEventMask.SubstructureRedirectMask | XEventMask.StructureNotifyMask)), ref ev); + } + else + { + XRaiseWindow(_x11.Display, _handle); + XSetInputFocus(_x11.Display, _handle, 0, IntPtr.Zero); + } + } + + + public IScreenImpl Screen { get; } = new ScreenStub(); + public Size MaxClientSize { get; } = new Size(1920, 1280); + + + public void BeginMoveDrag() + { + } + + public void BeginResizeDrag(WindowEdge edge) + { + } + + public void SetTitle(string title) + { + } + + public void SetMinMaxSize(Size minSize, Size maxSize) + { + + } + + public void SetTopmost(bool value) + { + + } + + public IDisposable ShowDialog() + { + return Disposable.Empty; + } + + public void SetIcon(IWindowIconImpl icon) + { + } + + public void ShowTaskbarIcon(bool value) + { + } + + + + + } +} diff --git a/src/Avalonia.X11/XError.cs b/src/Avalonia.X11/XError.cs new file mode 100644 index 0000000000..2cc8f63c96 --- /dev/null +++ b/src/Avalonia.X11/XError.cs @@ -0,0 +1,30 @@ +using System; + +namespace Avalonia.X11 +{ + static class XError + { + private static readonly XErrorHandler s_errorHandlerDelegate = Handler; + public static XErrorEvent LastError; + static int Handler(IntPtr display, ref XErrorEvent error) + { + LastError = error; + return 0; + } + + public static void ThrowLastError(string desc) + { + var err = LastError; + LastError = new XErrorEvent(); + if (err.error_code == 0) + throw new X11Exception(desc); + throw new X11Exception(desc + ": " + err.error_code); + + } + + public static void Init() + { + XLib.XSetErrorHandler(s_errorHandlerDelegate); + } + } +} diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index 88d36091ca..593e6b438f 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -1,105 +1,421 @@ using System; using System.Runtime.InteropServices; +using System.Text; + +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable FieldCanBeMadeReadOnly.Global +// ReSharper disable CommentTypo +// ReSharper disable UnusedMember.Global +// ReSharper disable IdentifierTypo +// ReSharper disable NotAccessedField.Global +// ReSharper disable UnusedMethodReturnValue.Global namespace Avalonia.X11 { - public static class XLib + internal static class XLib { + const string libX11 = "X11"; + + [DllImport(libX11)] + public static extern IntPtr XOpenDisplay(IntPtr display); + + [DllImport(libX11)] + public static extern int XCloseDisplay(IntPtr display); + + [DllImport(libX11)] + public static extern IntPtr XSynchronize(IntPtr display, bool onoff); + + [DllImport(libX11)] + public static extern IntPtr XCreateWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, + int border_width, int depth, int xclass, IntPtr visual, UIntPtr valuemask, + ref XSetWindowAttributes attributes); + + [DllImport(libX11)] + public static extern IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, + int height, int border_width, IntPtr border, IntPtr background); + + [DllImport(libX11)] + public static extern int XMapWindow(IntPtr display, IntPtr window); + + [DllImport(libX11)] + public static extern int XUnmapWindow(IntPtr display, IntPtr window); + + [DllImport(libX11)] + public static extern int XMapSubindows(IntPtr display, IntPtr window); + + [DllImport(libX11)] + public static extern int XUnmapSubwindows(IntPtr display, IntPtr window); + + [DllImport(libX11)] + public static extern IntPtr XRootWindow(IntPtr display, int screen_number); + [DllImport(libX11)] + public static extern IntPtr XDefaultRootWindow(IntPtr display); + + [DllImport(libX11)] + public static extern IntPtr XNextEvent(IntPtr display, out XEvent xevent); + + [DllImport(libX11)] + public static extern int XConnectionNumber(IntPtr diplay); + + [DllImport(libX11)] + public static extern int XPending(IntPtr diplay); + + [DllImport(libX11)] + public static extern IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask); + + [DllImport(libX11)] + public static extern int XDestroyWindow(IntPtr display, IntPtr window); + + [DllImport(libX11)] + public static extern int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y); + + [DllImport(libX11)] + public static extern int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height); + + [DllImport(libX11)] + public static extern int XResizeWindow(IntPtr display, IntPtr window, int width, int height); + + [DllImport(libX11)] + public static extern int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes); + + [DllImport(libX11)] + public static extern int XFlush(IntPtr display); + + [DllImport(libX11)] + public static extern int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop); + + [DllImport(libX11)] + public static extern int XStoreName(IntPtr display, IntPtr window, string window_name); + + [DllImport(libX11)] + public static extern int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name); + + [DllImport(libX11)] + public static extern int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, + ref XEvent send_event); + + [DllImport(libX11)] + public static extern int XQueryTree(IntPtr display, IntPtr window, out IntPtr root_return, + out IntPtr parent_return, out IntPtr children_return, out int nchildren_return); + + [DllImport(libX11)] + public static extern int XFree(IntPtr data); + + [DllImport(libX11)] + public static extern int XRaiseWindow(IntPtr display, IntPtr window); + + [DllImport(libX11)] + public static extern uint XLowerWindow(IntPtr display, IntPtr window); + + [DllImport(libX11)] + public static extern uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, + ref XWindowChanges values); + + [DllImport(libX11)] + public static extern IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists); + + [DllImport(libX11)] + public static extern int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, + IntPtr[] atoms); + + [DllImport(libX11)] + public static extern int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count); + + [DllImport(libX11)] + public static extern int XGrabPointer(IntPtr display, IntPtr window, bool owner_events, EventMask event_mask, + GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, IntPtr timestamp); + + [DllImport(libX11)] + public static extern int XUngrabPointer(IntPtr display, IntPtr timestamp); + + [DllImport(libX11)] + public static extern bool XQueryPointer(IntPtr display, IntPtr window, out IntPtr root, out IntPtr child, + out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons); + + [DllImport(libX11)] + public static extern bool XTranslateCoordinates(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, + int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return); + + [DllImport(libX11)] + public static extern bool XGetGeometry(IntPtr display, IntPtr window, out IntPtr root, out int x, out int y, + out int width, out int height, out int border_width, out int depth); + + [DllImport(libX11)] + public static extern bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, + out int width, out int height, IntPtr border_width, IntPtr depth); + + [DllImport(libX11)] + public static extern bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, + IntPtr width, IntPtr height, IntPtr border_width, IntPtr depth); + + [DllImport(libX11)] + public static extern bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, IntPtr x, IntPtr y, + out int width, out int height, IntPtr border_width, IntPtr depth); + + [DllImport(libX11)] + public static extern uint XWarpPointer(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, + uint src_width, uint src_height, int dest_x, int dest_y); + + [DllImport(libX11)] + public static extern int XClearWindow(IntPtr display, IntPtr window); + + [DllImport(libX11)] + public static extern int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, + bool exposures); + + // Colormaps + [DllImport(libX11)] + public static extern IntPtr XDefaultScreenOfDisplay(IntPtr display); + + [DllImport(libX11)] + public static extern int XScreenNumberOfScreen(IntPtr display, IntPtr Screen); + + [DllImport(libX11)] + public static extern IntPtr XDefaultVisual(IntPtr display, int screen_number); + + [DllImport(libX11)] + public static extern uint XDefaultDepth(IntPtr display, int screen_number); + + [DllImport(libX11)] + public static extern int XDefaultScreen(IntPtr display); + + [DllImport(libX11)] + public static extern IntPtr XDefaultColormap(IntPtr display, int screen_number); + + [DllImport(libX11)] + public static extern int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, + ref XColor exact_def_color, ref XColor screen_def_color); + + [DllImport(libX11)] + public static extern int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def); + + [DllImport(libX11)] + public static extern int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window); + + [DllImport(libX11)] + public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, + int format, PropertyMode mode, ref MotifWmHints data, int nelements); + + [DllImport(libX11)] + public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, + int format, PropertyMode mode, ref uint value, int nelements); + + [DllImport(libX11)] + public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, + int format, PropertyMode mode, ref IntPtr value, int nelements); + + [DllImport(libX11)] + public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, + int format, PropertyMode mode, uint[] data, int nelements); + + [DllImport(libX11)] + public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, + int format, PropertyMode mode, int[] data, int nelements); + + [DllImport(libX11)] + public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, + int format, PropertyMode mode, IntPtr[] data, int nelements); + + [DllImport(libX11)] + public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, + int format, PropertyMode mode, IntPtr atoms, int nelements); + + [DllImport(libX11, CharSet = CharSet.Ansi)] + public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, + int format, PropertyMode mode, string text, int text_length); + + [DllImport(libX11)] + public static extern int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property); + + // Drawing + [DllImport(libX11)] + public static extern IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values); + + [DllImport(libX11)] + public static extern int XFreeGC(IntPtr display, IntPtr gc); + + [DllImport(libX11)] + public static extern int XSetFunction(IntPtr display, IntPtr gc, GXFunction function); + + [DllImport(libX11)] + internal static extern int XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, + GCCapStyle cap_style, GCJoinStyle join_style); + + [DllImport(libX11)] + public static extern int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2); + + [DllImport(libX11)] + public static extern int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, + int height); + + [DllImport(libX11)] + public static extern int XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, + int height); + + [DllImport(libX11)] + public static extern int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background); + + [DllImport(libX11)] + public static extern int XCopyArea(IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int src_x, int src_y, + int width, int height, int dest_x, int dest_y); + + [DllImport(libX11)] + public static extern int XGetWindowProperty(IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset, + IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type, out int actual_format, + out IntPtr nitems, out IntPtr bytes_after, ref IntPtr prop); + + [DllImport(libX11)] + public static extern int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time); + + [DllImport(libX11)] + public static extern int XIconifyWindow(IntPtr display, IntPtr window, int screen_number); + + [DllImport(libX11)] + public static extern int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor); + + [DllImport(libX11)] + public static extern int XUndefineCursor(IntPtr display, IntPtr window); + + [DllImport(libX11)] + public static extern int XFreeCursor(IntPtr display, IntPtr cursor); + + [DllImport(libX11)] + public static extern IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape); + + [DllImport(libX11)] + public static extern IntPtr XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask, + ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot); + + [DllImport(libX11)] + public static extern IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, + int height, IntPtr fg, IntPtr bg, int depth); + + [DllImport(libX11)] + public static extern IntPtr XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth); + + [DllImport(libX11)] + public static extern IntPtr XFreePixmap(IntPtr display, IntPtr pixmap); + + [DllImport(libX11)] + public static extern int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, + out int best_width, out int best_height); + + [DllImport(libX11)] + public static extern IntPtr XWhitePixel(IntPtr display, int screen_no); + + [DllImport(libX11)] + public static extern IntPtr XBlackPixel(IntPtr display, int screen_no); + + [DllImport(libX11)] + public static extern void XGrabServer(IntPtr display); + + [DllImport(libX11)] + public static extern void XUngrabServer(IntPtr display); + + [DllImport(libX11)] + public static extern void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, + out IntPtr supplied_return); + + [DllImport(libX11)] + public static extern void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints); + + [DllImport(libX11)] + public static extern void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints); + + [DllImport(libX11)] + public static extern void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints); + + [DllImport(libX11)] + public static extern int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count); + + [DllImport(libX11)] + public static extern IntPtr XSetErrorHandler(XErrorHandler error_handler); + + [DllImport(libX11)] + public static extern IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length); + + [DllImport(libX11)] + public static extern int XInitThreads(); + + [DllImport(libX11)] + public static extern int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, + IntPtr requestor, IntPtr time); + + [DllImport(libX11)] + public static extern IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection); + + [DllImport(libX11)] + public static extern int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time); + + [DllImport(libX11)] + public static extern int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask); + + [DllImport(libX11)] + public static extern int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground); + + [DllImport(libX11)] + public static extern int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background); + + [DllImport(libX11)] + public static extern int XBell(IntPtr display, int percent); + + [DllImport(libX11)] + public static extern int XChangeActivePointerGrab(IntPtr display, EventMask event_mask, IntPtr cursor, + IntPtr time); + + [DllImport(libX11)] + public static extern bool XFilterEvent(ref XEvent xevent, IntPtr window); + + [DllImport(libX11)] + public static extern void XkbSetDetectableAutoRepeat(IntPtr display, bool detectable, IntPtr supported); + + [DllImport(libX11)] + public static extern void XPeekEvent(IntPtr display, out XEvent xevent); - [DllImport("libX11.so.6")] - public static extern IntPtr XInitThreads(); - - [DllImport("libX11.so.6")] - public static extern IntPtr XOpenDisplay(IntPtr name); - - [DllImport("libX11.so.6")] - public static extern int XConnectionNumber(IntPtr display); + [DllImport(libX11)] + public static extern void XMatchVisualInfo(IntPtr display, int screen, int depth, int klass, out XVisualInfo info); - [DllImport("libX11.so.6")] + [DllImport(libX11)] public static extern IntPtr XLockDisplay(IntPtr display); - [DllImport("libX11.so.6")] + [DllImport(libX11)] public static extern IntPtr XUnlockDisplay(IntPtr display); - [DllImport("libX11.so.6")] - public static extern IntPtr XFreeGC(IntPtr display, IntPtr gc); - - [DllImport("libX11.so.6")] + [DllImport(libX11)] public static extern IntPtr XCreateGC(IntPtr display, IntPtr drawable, ulong valuemask, IntPtr values); - [DllImport("libX11.so.6")] + [DllImport(libX11)] public static extern int XInitImage(ref XImage image); - [DllImport("libX11.so.6")] + [DllImport(libX11)] public static extern int XDestroyImage(ref XImage image); - - [DllImport("libX11.so.6")] - public static extern IntPtr XSetErrorHandler(XErrorHandler handler); - [DllImport("libX11.so.6")] + [DllImport(libX11)] + public static extern int XPutImage(IntPtr display, IntPtr drawable, IntPtr gc, ref XImage image, + int srcx, int srcy, int destx, int desty, uint width, uint height); + [DllImport(libX11)] public static extern int XSync(IntPtr display, bool discard); - [DllImport("libX11.so.6")] - public static extern int XNextEvent(IntPtr display, out XEvent ev); + [DllImport(libX11)] + public static extern IntPtr XCreateColormap(IntPtr display, IntPtr window, IntPtr visual, int create); - [DllImport("libX11.so.6")] - public static extern bool XPending(IntPtr display); - - [StructLayout(LayoutKind.Sequential)] - public struct XAnyEvent + public struct XGeometry { - - public int Type; - public ulong Serial; /* # of last request processed by server */ - public bool send_event; /* true if this came from a SendEvent request */ - public IntPtr display; /* Display the event was read from */ - public IntPtr window; /* window on which event was requested in event mask */ + public IntPtr root; + public int x; + public int y; + public int width; + public int height; + public int bw; + public int d; } - [StructLayout(LayoutKind.Explicit)] - public unsafe struct XEvent + public static bool XGetGeometry(IntPtr display, IntPtr window, out XGeometry geo) { - [FieldOffset(0)] public int Type; - [FieldOffset(0)] public XAnyEvent XAny; - [FieldOffset(0)] private fixed int pad[40]; + geo = new XGeometry(); + return XGetGeometry(display, window, out geo.root, out geo.x, out geo.y, out geo.width, out geo.height, + out geo.bw, out geo.d); } - public delegate int XErrorHandler(IntPtr display, ref XErrorEvent error); - - [DllImport("libX11.so.6")] - public static extern int XPutImage(IntPtr display, IntPtr drawable, IntPtr gc, ref XImage image, - int srcx, int srcy, int destx, int desty, uint width, uint height); - - [StructLayout(LayoutKind.Sequential)] - public unsafe struct XErrorEvent - { - public int type; - public IntPtr* display; /* Display the event was read from */ - public ulong serial; /* serial number of failed request */ - public byte error_code; /* error code of failed request */ - public byte request_code; /* Major op-code of failed request */ - public byte minor_code; /* Minor op-code of failed request */ - public IntPtr resourceid; /* resource id */ - } - - [StructLayout(LayoutKind.Sequential)] - public unsafe struct XImage - { - public int width, height; /* size of image */ - public int xoffset; /* number of pixels offset in X direction */ - public int format; /* XYBitmap, XYPixmap, ZPixmap */ - public IntPtr data; /* pointer to image data */ - public int byte_order; /* data byte order, LSBFirst, MSBFirst */ - public int bitmap_unit; /* quant. of scanline 8, 16, 32 */ - public int bitmap_bit_order; /* LSBFirst, MSBFirst */ - public int bitmap_pad; /* 8, 16, 32 either XY or ZPixmap */ - public int depth; /* depth of image */ - public int bytes_per_line; /* accelerator to next scanline */ - public int bits_per_pixel; /* bits per pixel (ZPixmap) */ - public ulong red_mask; /* bits in z arrangement */ - public ulong green_mask; - public ulong blue_mask; - private fixed byte funcs[128]; - } } } From 80950d0eb17136903799b56edf83b503d32aa3d3 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 24 Oct 2018 11:11:56 +0300 Subject: [PATCH 03/46] [X11] Use 24-bit visuals so GL drawing works on nVidia cards --- src/Avalonia.X11/X11Framebuffer.cs | 2 +- src/Avalonia.X11/X11Info.cs | 3 --- src/Avalonia.X11/X11Window.cs | 16 ++++++---------- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/Avalonia.X11/X11Framebuffer.cs b/src/Avalonia.X11/X11Framebuffer.cs index ef93a7347b..2d6955f47a 100644 --- a/src/Avalonia.X11/X11Framebuffer.cs +++ b/src/Avalonia.X11/X11Framebuffer.cs @@ -34,7 +34,7 @@ namespace Avalonia.X11 image.bitmap_unit = bitsPerPixel; image.bitmap_bit_order = 0;// LSBFirst; image.bitmap_pad = bitsPerPixel; - image.depth = 32; + image.depth = 24; image.bytes_per_line = RowBytes - Width * 4; image.bits_per_pixel = bitsPerPixel; XLockDisplay(_display); diff --git a/src/Avalonia.X11/X11Info.cs b/src/Avalonia.X11/X11Info.cs index 6ad9faffbc..ddad739dd0 100644 --- a/src/Avalonia.X11/X11Info.cs +++ b/src/Avalonia.X11/X11Info.cs @@ -14,7 +14,6 @@ namespace Avalonia.X11 public IntPtr BlackPixel { get; } public IntPtr RootWindow { get; } public IntPtr DefaultRootWindow { get; } - public XVisualInfo MatchedVisual { get; } public X11Atoms Atoms { get; } public IntPtr LastActivityTimestamp { get; set; } @@ -28,8 +27,6 @@ namespace Avalonia.X11 RootWindow = XRootWindow(display, DefaultScreen); DefaultRootWindow = XDefaultRootWindow(display); Atoms = new X11Atoms(display); - XMatchVisualInfo(display, DefaultScreen, 32, 4, out var info); - MatchedVisual = info; } } } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 944044cfa8..6bf59866f1 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -44,15 +44,11 @@ namespace Avalonia.X11 XSetWindowAttributes attr = new XSetWindowAttributes(); var valueMask = default(SetWindowValuemask); - /* - _handle = XCreateSimpleWindow(_x11.Display, _x11.DefaultRootWindow, 10, 10, 100, 100, 0, IntPtr.Zero, - IntPtr.Zero);*/ - var vinfo = _x11.MatchedVisual; - attr.colormap = XCreateColormap(_x11.Display, _x11.RootWindow, vinfo.visual, 0); - attr.backing_store = 2; + + attr.backing_store = 1; attr.bit_gravity = Gravity.NorthWestGravity; attr.win_gravity = Gravity.NorthWestGravity; - valueMask |= SetWindowValuemask.ColorMap | SetWindowValuemask.BackPixel | SetWindowValuemask.BorderPixel + valueMask |= SetWindowValuemask.BackPixel | SetWindowValuemask.BorderPixel | SetWindowValuemask.BackPixmap | SetWindowValuemask.BackingStore | SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity; @@ -63,8 +59,8 @@ namespace Avalonia.X11 } _handle = XCreateWindow(_x11.Display, _x11.RootWindow, 10, 10, 300, 200, 0, - (int)vinfo.depth, - (int)CreateWindowArgs.InputOutput, vinfo.visual, + 24, + (int)CreateWindowArgs.InputOutput, IntPtr.Zero, new UIntPtr((uint)valueMask), ref attr); @@ -278,7 +274,7 @@ namespace Avalonia.X11 rv |= InputModifiers.Windows; return rv; } - static Stopwatch St = Stopwatch.StartNew(); + private bool _systemDecorations = true; private bool _canResize = true; From 9ee771b425d3f4aa0d0a951fc861144c86096bd4 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 24 Oct 2018 11:12:14 +0300 Subject: [PATCH 04/46] [X11] Reference X11 backend from ControlCatalog --- samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj index ec841db5b2..8410a197ab 100644 --- a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj +++ b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj @@ -8,6 +8,7 @@ + From 9b7f8b5f35a1d748158b43c55de44eea80d92e31 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 24 Oct 2018 11:55:48 +0300 Subject: [PATCH 05/46] [X11] Use a child window for OpenGL rendering. Fixes tons of issues on nVidia cards --- src/Avalonia.X11/X11Window.cs | 48 +++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 6bf59866f1..f102a6abff 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -25,6 +25,7 @@ namespace Avalonia.X11 private IMouseDevice _mouse; private Point _position; private IntPtr _handle; + private IntPtr _renderHandle; private bool _mapped; class InputEventContainer @@ -62,8 +63,12 @@ namespace Avalonia.X11 24, (int)CreateWindowArgs.InputOutput, IntPtr.Zero, new UIntPtr((uint)valueMask), ref attr); - - + _renderHandle = XCreateWindow(_x11.Display, _handle, 0, 0, 300, 200, 0, 24, + (int)CreateWindowArgs.InputOutput, + IntPtr.Zero, + new UIntPtr((uint)(SetWindowValuemask.BorderPixel | SetWindowValuemask.BitGravity | + SetWindowValuemask.WinGravity | SetWindowValuemask.BackingStore)), ref attr); + Handle = new PlatformHandle(_handle, "XID"); ClientSize = new Size(400, 400); _eventHandler = OnEvent; @@ -86,7 +91,7 @@ namespace Avalonia.X11 if (feature != null) surfaces.Insert(0, new EglGlPlatformSurface((EglDisplay)feature.Display, feature.DeferredContext, - new SurfaceInfo(_x11.DeferredDisplay, _handle))); + new SurfaceInfo(_x11.DeferredDisplay, _handle, _renderHandle))); Surfaces = surfaces.ToArray(); UpdateWmHits(); XFlush(_x11.Display); @@ -95,10 +100,12 @@ namespace Avalonia.X11 class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo { private readonly IntPtr _display; + private readonly IntPtr _parent; - public SurfaceInfo(IntPtr display, IntPtr xid) + public SurfaceInfo(IntPtr display, IntPtr parent, IntPtr xid) { _display = display; + _parent = parent; Handle = xid; } public IntPtr Handle { get; } @@ -108,8 +115,10 @@ namespace Avalonia.X11 get { XLockDisplay(_display); - - XGetGeometry(_display, Handle, out var geo); + XGetGeometry(_display, _parent, out var geo); + XResizeWindow(_display, Handle, geo.width, geo.height); + XFlush(_display); + XSync(_display, true); XUnlockDisplay(_display); return new System.Drawing.Size(geo.width, geo.height); } @@ -167,7 +176,10 @@ namespace Avalonia.X11 unsafe void OnEvent(XEvent ev) { if (ev.type == XEventName.MapNotify) + { _mapped = true; + XMapWindow(_x11.Display, _renderHandle); + } else if (ev.type == XEventName.UnmapNotify) _mapped = false; else if (ev.type == XEventName.Expose) @@ -232,12 +244,7 @@ namespace Avalonia.X11 } else if (ev.type == XEventName.DestroyNotify) { - if (_handle != IntPtr.Zero) - { - _platform.Windows.Remove(_handle); - _handle = IntPtr.Zero; - Closed?.Invoke(); - } + Cleanup(); } else if (ev.type == XEventName.ClientMessage) { @@ -335,6 +342,15 @@ namespace Avalonia.X11 } public void Dispose() + { + if (_handle != IntPtr.Zero) + { + XDestroyWindow(_x11.Display, _handle); + Cleanup(); + } + } + + void Cleanup() { if (_handle != IntPtr.Zero) { @@ -342,10 +358,16 @@ namespace Avalonia.X11 _platform.Windows.Remove(_handle); _handle = IntPtr.Zero; Closed?.Invoke(); - + } + + if (_renderHandle != IntPtr.Zero) + { + XDestroyWindow(_x11.Display, _renderHandle); + _renderHandle = IntPtr.Zero; } } + public void Show() => XMapWindow(_x11.Display, _handle); public void Hide() => XUnmapWindow(_x11.Display, _handle); From 074d8949a6900b4d8ae2cd89a7fe85dbf4483709 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 24 Oct 2018 12:37:01 +0300 Subject: [PATCH 06/46] [X11] Enforce layout priority --- src/Avalonia.X11/X11Window.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index f102a6abff..deb0491168 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -240,7 +240,8 @@ namespace Avalonia.X11 Resized?.Invoke(nsize); if (changedPos) PositionChanged?.Invoke(npos); - }); + Dispatcher.UIThread.RunJobs(DispatcherPriority.Layout); + }, DispatcherPriority.Layout); } else if (ev.type == XEventName.DestroyNotify) { From 52a0514ee112565a5e3f2d0c7e2d1e799aa7f1a0 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 26 Oct 2018 22:32:21 +0300 Subject: [PATCH 07/46] [X11] BeginMove/ResizeDrag and WindowState --- src/Avalonia.X11/X11Window.cs | 157 ++++++++++++++++++++++++++++------ src/Avalonia.X11/XLib.cs | 61 ++++++++++++- 2 files changed, 189 insertions(+), 29 deletions(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index deb0491168..036c7d0f34 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Diagnostics; +using System.Linq; using System.Reactive.Disposables; using Avalonia.Controls; using Avalonia.Input; @@ -13,7 +14,7 @@ using Avalonia.Threading; using static Avalonia.X11.XLib; namespace Avalonia.X11 { - class X11Window : IWindowImpl, IPopupImpl + unsafe class X11Window : IWindowImpl, IPopupImpl { private readonly AvaloniaX11Platform _platform; private readonly bool _popup; @@ -134,7 +135,6 @@ namespace Avalonia.X11 if (_popup || !_systemDecorations) { - functions = 0; decorations = 0; } @@ -165,7 +165,6 @@ namespace Avalonia.X11 public Action Deactivated { get; set; } public Action Activated { get; set; } public Func Closing { get; set; } - public WindowState WindowState { get; set; } public Action WindowStateChanged { get; set; } public Action Closed { get; set; } public Action PositionChanged { get; set; } @@ -190,7 +189,10 @@ namespace Avalonia.X11 Deactivated?.Invoke(); else if (ev.type == XEventName.MotionNotify) MouseEvent(RawMouseEventType.Move, ev, ev.MotionEvent.state); - + else if (ev.type == XEventName.PropertyNotify) + { + OnPropertyChange(ev.PropertyEvent.atom, ev.PropertyEvent.state == 0); + } else if (ev.type == XEventName.ButtonPress) { if (ev.ButtonEvent.button < 4) @@ -260,8 +262,76 @@ namespace Avalonia.X11 } } } - - + + private WindowState _lastWindowState; + public WindowState WindowState + { + get { return _lastWindowState; } + set + { + _lastWindowState = value; + if (value == WindowState.Minimized) + { + XIconifyWindow(_x11.Display, _handle, _x11.DefaultScreen); + } + else if (value == WindowState.Maximized) + { + SendNetWMMessage(_x11.Atoms._NET_WM_STATE, (IntPtr)0, _x11.Atoms._NET_WM_STATE_HIDDEN, IntPtr.Zero); + SendNetWMMessage(_x11.Atoms._NET_WM_STATE, (IntPtr)1, _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT, + _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ); + } + else + { + SendNetWMMessage(_x11.Atoms._NET_WM_STATE, (IntPtr)0, _x11.Atoms._NET_WM_STATE_HIDDEN, IntPtr.Zero); + SendNetWMMessage(_x11.Atoms._NET_WM_STATE, (IntPtr)0, _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT, + _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ); + } + } + } + + private void OnPropertyChange(IntPtr atom, bool hasValue) + { + if (atom == _x11.Atoms._NET_WM_STATE) + { + WindowState state = WindowState.Normal; + if(hasValue) + { + + XGetWindowProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_STATE, IntPtr.Zero, new IntPtr(256), + false, (IntPtr)Atom.XA_ATOM, out var actualAtom, out var actualFormat, out var nitems, out var bytesAfter, + out var prop); + int maximized = 0; + var pitems = (IntPtr*)prop.ToPointer(); + for (var c = 0; c < nitems.ToInt32(); c++) + { + if (pitems[c] == _x11.Atoms._NET_WM_STATE_HIDDEN) + { + state = WindowState.Minimized; + break; + } + + if (pitems[c] == _x11.Atoms._NET_WM_STATE_MAXIMIZED_HORZ || + pitems[c] == _x11.Atoms._NET_WM_STATE_MAXIMIZED_VERT) + { + maximized++; + if (maximized == 2) + { + state = WindowState.Maximized; + break; + } + } + } + XFree(prop); + } + if (_lastWindowState != state) + { + _lastWindowState = state; + WindowStateChanged?.Invoke(state); + } + } + + } + InputModifiers TranslateModifiers(XModifierMask state) { @@ -437,25 +507,8 @@ namespace Avalonia.X11 { if (_x11.Atoms._NET_ACTIVE_WINDOW != IntPtr.Zero) { - - var ev = new XEvent - { - AnyEvent = - { - type = XEventName.ClientMessage, - window = _handle, - }, - ClientMessageEvent = { - message_type = _x11.Atoms._NET_ACTIVE_WINDOW, - format = 32, - ptr1 = new IntPtr(1), - ptr2 = _x11.LastActivityTimestamp - - } - }; - - XSendEvent(_x11.Display, _x11.RootWindow, false, - new IntPtr((int)(XEventMask.SubstructureRedirectMask | XEventMask.StructureNotifyMask)), ref ev); + SendNetWMMessage(_x11.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, _x11.LastActivityTimestamp, + IntPtr.Zero); } else { @@ -467,14 +520,64 @@ namespace Avalonia.X11 public IScreenImpl Screen { get; } = new ScreenStub(); public Size MaxClientSize { get; } = new Size(1920, 1280); - - + + + + void SendNetWMMessage(IntPtr message_type, IntPtr l0, + IntPtr? l1 = null, IntPtr? l2 = null, IntPtr? l3 = null, IntPtr? l4 = null) + { + XEvent xev; + + xev = new XEvent(); + xev.ClientMessageEvent.type = XEventName.ClientMessage; + xev.ClientMessageEvent.send_event = true; + xev.ClientMessageEvent.window = _handle; + xev.ClientMessageEvent.message_type = message_type; + xev.ClientMessageEvent.format = 32; + xev.ClientMessageEvent.ptr1 = l0; + xev.ClientMessageEvent.ptr2 = l1 ?? IntPtr.Zero; + xev.ClientMessageEvent.ptr3 = l2 ?? IntPtr.Zero; + xev.ClientMessageEvent.ptr4 = l3 ?? IntPtr.Zero; + xev.ClientMessageEvent.ptr4 = l4 ?? IntPtr.Zero; + XSendEvent(_x11.Display, _x11.RootWindow, false, + new IntPtr((int)(EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev); + + } + + void BeginMoveResize(NetWmMoveResize side) + { + var pos = GetCursorPos(_x11); + XUngrabPointer(_x11.Display, _x11.LastActivityTimestamp); + SendNetWMMessage (_x11.Atoms._NET_WM_MOVERESIZE, (IntPtr) pos.x, (IntPtr) pos.y, + (IntPtr) side, + (IntPtr) 1, (IntPtr)1); // left button + } + public void BeginMoveDrag() { + BeginMoveResize(NetWmMoveResize._NET_WM_MOVERESIZE_MOVE); } public void BeginResizeDrag(WindowEdge edge) { + var side = NetWmMoveResize._NET_WM_MOVERESIZE_CANCEL; + if (edge == WindowEdge.East) + side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_RIGHT; + if (edge == WindowEdge.North) + side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_TOP; + if (edge == WindowEdge.South) + side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_BOTTOM; + if (edge == WindowEdge.West) + side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_LEFT; + if (edge == WindowEdge.NorthEast) + side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_TOPRIGHT; + if (edge == WindowEdge.NorthWest) + side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_TOPLEFT; + if (edge == WindowEdge.SouthEast) + side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT; + if (edge == WindowEdge.SouthWest) + side = NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT; + BeginMoveResize(side); } public void SetTitle(string title) diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index 593e6b438f..d6c4ec6593 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -12,7 +12,7 @@ using System.Text; namespace Avalonia.X11 { - internal static class XLib + internal unsafe static class XLib { const string libX11 = "X11"; @@ -262,7 +262,7 @@ namespace Avalonia.X11 [DllImport(libX11)] public static extern int XGetWindowProperty(IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset, IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type, out int actual_format, - out IntPtr nitems, out IntPtr bytes_after, ref IntPtr prop); + out IntPtr nitems, out IntPtr bytes_after, out IntPtr prop); [DllImport(libX11)] public static extern int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time); @@ -416,6 +416,63 @@ namespace Avalonia.X11 return XGetGeometry(display, window, out geo.root, out geo.x, out geo.y, out geo.width, out geo.height, out geo.bw, out geo.d); } + + public static void QueryPointer (IntPtr display, IntPtr w, out IntPtr root, out IntPtr child, + out int root_x, out int root_y, out int child_x, out int child_y, + out int mask) + { + + IntPtr c; + + XGrabServer (display); + + XQueryPointer(display, w, out root, out c, + out root_x, out root_y, out child_x, out child_y, + out mask); + + if (root != w) + c = root; + + IntPtr child_last = IntPtr.Zero; + while (c != IntPtr.Zero) { + child_last = c; + XQueryPointer(display, c, out root, out c, + out root_x, out root_y, out child_x, out child_y, + out mask); + } + XUngrabServer (display); + XFlush (display); + + child = child_last; + } + + public static (int x, int y) GetCursorPos(X11Info x11, IntPtr? handle = null) + { + IntPtr root; + IntPtr child; + int root_x; + int root_y; + int win_x; + int win_y; + int keys_buttons; + + + + QueryPointer(x11.Display, handle ?? x11.RootWindow, out root, out child, out root_x, out root_y, out win_x, out win_y, + out keys_buttons); + + + if (handle != null) + { + return (win_x, win_y); + } + else + { + return (root_x, root_y); + } + } + + } } From 8f80351bcce3229ebdf6b1730fa4bce1440700de Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 26 Oct 2018 22:54:01 +0300 Subject: [PATCH 08/46] [X11] Implemented cursor support --- src/Avalonia.X11/Stubs.cs | 8 ---- src/Avalonia.X11/X11Atoms.cs | 11 +----- src/Avalonia.X11/X11CursorFactory.cs | 57 ++++++++++++++++++++++++++++ src/Avalonia.X11/X11Info.cs | 2 + src/Avalonia.X11/X11Platform.cs | 2 +- src/Avalonia.X11/X11Window.cs | 8 ++++ 6 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 src/Avalonia.X11/X11CursorFactory.cs diff --git a/src/Avalonia.X11/Stubs.cs b/src/Avalonia.X11/Stubs.cs index ed14ab7878..6dda7b81ca 100644 --- a/src/Avalonia.X11/Stubs.cs +++ b/src/Avalonia.X11/Stubs.cs @@ -9,14 +9,6 @@ using Avalonia.Platform; namespace Avalonia.X11 { - class CursorFactoryStub : IStandardCursorFactory - { - public IPlatformHandle GetCursor(StandardCursorType cursorType) - { - return new PlatformHandle(IntPtr.Zero, "FAKE"); - } - } - class ClipboardStub : IClipboard { private string _text; diff --git a/src/Avalonia.X11/X11Atoms.cs b/src/Avalonia.X11/X11Atoms.cs index e7b83f59d3..50a735b2ef 100644 --- a/src/Avalonia.X11/X11Atoms.cs +++ b/src/Avalonia.X11/X11Atoms.cs @@ -176,9 +176,6 @@ namespace Avalonia.X11 { public readonly IntPtr OEMTEXT; public readonly IntPtr UNICODETEXT; public readonly IntPtr TARGETS; - public readonly IntPtr PostAtom; - public readonly IntPtr HoverState; - public readonly IntPtr AsyncAtom; public X11Atoms (IntPtr display) { @@ -249,10 +246,7 @@ namespace Avalonia.X11 { "PRIMARY", "COMPOUND_TEXT", "UTF8_STRING", - "TARGETS", - "_SWF_AsyncAtom", - "_SWF_PostMessageAtom", - "_SWF_HoverAtom" }; + "TARGETS"}; IntPtr[] atoms = new IntPtr [atom_names.Length];; @@ -324,9 +318,6 @@ namespace Avalonia.X11 { OEMTEXT = atoms [off++]; UNICODETEXT = atoms [off++]; TARGETS = atoms [off++]; - AsyncAtom = atoms [off++]; - PostAtom = atoms [off++]; - HoverState = atoms [off++]; DIB = XA_PIXMAP; diff --git a/src/Avalonia.X11/X11CursorFactory.cs b/src/Avalonia.X11/X11CursorFactory.cs new file mode 100644 index 0000000000..d25a0da0a2 --- /dev/null +++ b/src/Avalonia.X11/X11CursorFactory.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Avalonia.Input; +using Avalonia.Platform; + +namespace Avalonia.X11 +{ + class X11CursorFactory : IStandardCursorFactory + { + private readonly IntPtr _display; + private Dictionary _cursors; + + private static readonly Dictionary s_mapping = + new Dictionary + { + {StandardCursorType.Arrow, CursorFontShape.XC_arrow}, + {StandardCursorType.Cross, CursorFontShape.XC_cross}, + {StandardCursorType.Hand, CursorFontShape.XC_hand1}, + {StandardCursorType.Help, CursorFontShape.XC_question_arrow}, + {StandardCursorType.Ibeam, CursorFontShape.XC_xterm}, + {StandardCursorType.No, CursorFontShape.XC_X_cursor}, + {StandardCursorType.Wait, CursorFontShape.XC_watch}, + {StandardCursorType.AppStarting, CursorFontShape.XC_watch}, + {StandardCursorType.BottomSize, CursorFontShape.XC_bottom_side}, + {StandardCursorType.DragCopy, CursorFontShape.XC_center_ptr}, + {StandardCursorType.DragLink, CursorFontShape.XC_fleur}, + {StandardCursorType.DragMove, CursorFontShape.XC_diamond_cross}, + {StandardCursorType.LeftSide, CursorFontShape.XC_left_side}, + {StandardCursorType.RightSide, CursorFontShape.XC_right_side}, + {StandardCursorType.SizeAll, CursorFontShape.XC_sizing}, + {StandardCursorType.TopSide, CursorFontShape.XC_top_side}, + {StandardCursorType.UpArrow, CursorFontShape.XC_sb_up_arrow}, + {StandardCursorType.BottomLeftCorner, CursorFontShape.XC_bottom_left_corner}, + {StandardCursorType.BottomRightCorner, CursorFontShape.XC_bottom_right_corner}, + {StandardCursorType.SizeNorthSouth, CursorFontShape.XC_sb_v_double_arrow}, + {StandardCursorType.SizeWestEast, CursorFontShape.XC_sb_h_double_arrow}, + {StandardCursorType.TopLeftCorner, CursorFontShape.XC_top_left_corner}, + {StandardCursorType.TopRightCorner, CursorFontShape.XC_top_right_corner}, + }; + + public X11CursorFactory(IntPtr display) + { + _display = display; + _cursors = Enum.GetValues(typeof(CursorFontShape)).Cast() + .ToDictionary(id => id, id => XLib.XCreateFontCursor(_display, id)); + } + + public IPlatformHandle GetCursor(StandardCursorType cursorType) + { + var handle = s_mapping.TryGetValue(cursorType, out var shape) + ? _cursors[shape] + : _cursors[CursorFontShape.XC_arrow]; + return new PlatformHandle(handle, "XCURSOR"); + } + } +} diff --git a/src/Avalonia.X11/X11Info.cs b/src/Avalonia.X11/X11Info.cs index ddad739dd0..527cdc31ef 100644 --- a/src/Avalonia.X11/X11Info.cs +++ b/src/Avalonia.X11/X11Info.cs @@ -14,6 +14,7 @@ namespace Avalonia.X11 public IntPtr BlackPixel { get; } public IntPtr RootWindow { get; } public IntPtr DefaultRootWindow { get; } + public IntPtr DefaultCursor { get; } public X11Atoms Atoms { get; } public IntPtr LastActivityTimestamp { get; set; } @@ -25,6 +26,7 @@ namespace Avalonia.X11 DefaultScreen = XDefaultScreen(display); BlackPixel = XBlackPixel(display, DefaultScreen); RootWindow = XRootWindow(display, DefaultScreen); + DefaultCursor = XCreateFontCursor(display, CursorFontShape.XC_arrow); DefaultRootWindow = XDefaultRootWindow(display); Atoms = new X11Atoms(display); } diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 33497be411..b3ffc2a30b 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -36,7 +36,7 @@ namespace Avalonia.X11 .Bind().ToConstant(new RenderLoop()) .Bind().ToConstant(new PlatformHotkeyConfiguration(InputModifiers.Control)) .Bind().ToFunc(() => KeyboardDevice) - .Bind().ToConstant(new CursorFactoryStub()) + .Bind().ToConstant(new X11CursorFactory(Display)) .Bind().ToSingleton() .Bind().ToConstant(new PlatformSettingsStub()) .Bind().ToConstant(new SystemDialogsStub()) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 036c7d0f34..82564e98e0 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -482,6 +482,14 @@ namespace Avalonia.X11 public void SetCursor(IPlatformHandle cursor) { + if (cursor == null) + XDefineCursor(_x11.Display, _handle, _x11.DefaultCursor); + else + { + if (cursor.HandleDescriptor != "XCURSOR") + throw new ArgumentException("Expected XCURSOR handle type"); + XDefineCursor(_x11.Display, _handle, cursor.Handle); + } } public IPlatformHandle Handle { get; } From 2ad8e3162bd671ad02b0dff4700f83df995e8846 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 27 Oct 2018 13:34:11 +0300 Subject: [PATCH 09/46] [X11] MinMax size/SetTopmost/ShowTaskbarIcon/Title --- src/Avalonia.X11/X11Atoms.cs | 150 +++------------------------------- src/Avalonia.X11/X11Window.cs | 56 ++++++++++--- src/Avalonia.X11/XLib.cs | 3 + 3 files changed, 58 insertions(+), 151 deletions(-) diff --git a/src/Avalonia.X11/X11Atoms.cs b/src/Avalonia.X11/X11Atoms.cs index 50a735b2ef..51a4fc52f0 100644 --- a/src/Avalonia.X11/X11Atoms.cs +++ b/src/Avalonia.X11/X11Atoms.cs @@ -22,6 +22,7 @@ // using System; +using System.Linq; using static Avalonia.X11.XLib; // ReSharper disable FieldCanBeMadeReadOnly.Global // ReSharper disable IdentifierTypo @@ -172,158 +173,27 @@ namespace Avalonia.X11 { public readonly IntPtr _NET_WM_WINDOW_TYPE_NORMAL; public readonly IntPtr CLIPBOARD; public readonly IntPtr PRIMARY; - public readonly IntPtr DIB; public readonly IntPtr OEMTEXT; public readonly IntPtr UNICODETEXT; public readonly IntPtr TARGETS; + public readonly IntPtr UTF8_STRING; public X11Atoms (IntPtr display) { // make sure this array stays in sync with the statements below - string [] atom_names = new string[] { - "WM_PROTOCOLS", - "WM_DELETE_WINDOW", - "WM_TAKE_FOCUS", - "_NET_SUPPORTED", - "_NET_CLIENT_LIST", - "_NET_NUMBER_OF_DESKTOPS", - "_NET_DESKTOP_GEOMETRY", - "_NET_DESKTOP_VIEWPORT", - "_NET_CURRENT_DESKTOP", - "_NET_DESKTOP_NAMES", - "_NET_ACTIVE_WINDOW", - "_NET_WORKAREA", - "_NET_SUPPORTING_WM_CHECK", - "_NET_VIRTUAL_ROOTS", - "_NET_DESKTOP_LAYOUT", - "_NET_SHOWING_DESKTOP", - "_NET_CLOSE_WINDOW", - "_NET_MOVERESIZE_WINDOW", - "_NET_WM_MOVERESIZE", - "_NET_RESTACK_WINDOW", - "_NET_REQUEST_FRAME_EXTENTS", - "_NET_WM_NAME", - "_NET_WM_VISIBLE_NAME", - "_NET_WM_ICON_NAME", - "_NET_WM_VISIBLE_ICON_NAME", - "_NET_WM_DESKTOP", - "_NET_WM_WINDOW_TYPE", - "_NET_WM_STATE", - "_NET_WM_ALLOWED_ACTIONS", - "_NET_WM_STRUT", - "_NET_WM_STRUT_PARTIAL", - "_NET_WM_ICON_GEOMETRY", - "_NET_WM_ICON", - "_NET_WM_PID", - "_NET_WM_HANDLED_ICONS", - "_NET_WM_USER_TIME", - "_NET_FRAME_EXTENTS", - "_NET_WM_PING", - "_NET_WM_SYNC_REQUEST", - "_NET_SYSTEM_TRAY_OPCODE", - "_NET_SYSTEM_TRAY_ORIENTATION", - "_NET_WM_STATE_MAXIMIZED_HORZ", - "_NET_WM_STATE_MAXIMIZED_VERT", - "_NET_WM_STATE_HIDDEN", - "_XEMBED", - "_XEMBED_INFO", - "_MOTIF_WM_HINTS", - "_NET_WM_STATE_SKIP_TASKBAR", - "_NET_WM_STATE_ABOVE", - "_NET_WM_STATE_MODAL", - "_NET_WM_CONTEXT_HELP", - "_NET_WM_WINDOW_OPACITY", - "_NET_WM_WINDOW_TYPE_DESKTOP", - "_NET_WM_WINDOW_TYPE_DOCK", - "_NET_WM_WINDOW_TYPE_TOOLBAR", - "_NET_WM_WINDOW_TYPE_MENU", - "_NET_WM_WINDOW_TYPE_UTILITY", - "_NET_WM_WINDOW_TYPE_DIALOG", - "_NET_WM_WINDOW_TYPE_SPLASH", - "_NET_WM_WINDOW_TYPE_NORMAL", - "CLIPBOARD", - "PRIMARY", - "COMPOUND_TEXT", - "UTF8_STRING", - "TARGETS"}; - IntPtr[] atoms = new IntPtr [atom_names.Length];; + var fields = typeof(X11Atoms).GetFields() + .Where(f => f.FieldType == typeof(IntPtr) && (IntPtr)f.GetValue(this) == IntPtr.Zero).ToArray(); + var atomNames = fields.Select(f => f.Name).ToArray(); + + IntPtr[] atoms = new IntPtr [atomNames.Length];; - XInternAtoms (display, atom_names, atom_names.Length, false, atoms); + XInternAtoms (display, atomNames, atomNames.Length, true, atoms); - int off = 0; - WM_PROTOCOLS = atoms [off++]; - WM_DELETE_WINDOW = atoms [off++]; - WM_TAKE_FOCUS = atoms [off++]; - _NET_SUPPORTED = atoms [off++]; - _NET_CLIENT_LIST = atoms [off++]; - _NET_NUMBER_OF_DESKTOPS = atoms [off++]; - _NET_DESKTOP_GEOMETRY = atoms [off++]; - _NET_DESKTOP_VIEWPORT = atoms [off++]; - _NET_CURRENT_DESKTOP = atoms [off++]; - _NET_DESKTOP_NAMES = atoms [off++]; - _NET_ACTIVE_WINDOW = atoms [off++]; - _NET_WORKAREA = atoms [off++]; - _NET_SUPPORTING_WM_CHECK = atoms [off++]; - _NET_VIRTUAL_ROOTS = atoms [off++]; - _NET_DESKTOP_LAYOUT = atoms [off++]; - _NET_SHOWING_DESKTOP = atoms [off++]; - _NET_CLOSE_WINDOW = atoms [off++]; - _NET_MOVERESIZE_WINDOW = atoms [off++]; - _NET_WM_MOVERESIZE = atoms [off++]; - _NET_RESTACK_WINDOW = atoms [off++]; - _NET_REQUEST_FRAME_EXTENTS = atoms [off++]; - _NET_WM_NAME = atoms [off++]; - _NET_WM_VISIBLE_NAME = atoms [off++]; - _NET_WM_ICON_NAME = atoms [off++]; - _NET_WM_VISIBLE_ICON_NAME = atoms [off++]; - _NET_WM_DESKTOP = atoms [off++]; - _NET_WM_WINDOW_TYPE = atoms [off++]; - _NET_WM_STATE = atoms [off++]; - _NET_WM_ALLOWED_ACTIONS = atoms [off++]; - _NET_WM_STRUT = atoms [off++]; - _NET_WM_STRUT_PARTIAL = atoms [off++]; - _NET_WM_ICON_GEOMETRY = atoms [off++]; - _NET_WM_ICON = atoms [off++]; - _NET_WM_PID = atoms [off++]; - _NET_WM_HANDLED_ICONS = atoms [off++]; - _NET_WM_USER_TIME = atoms [off++]; - _NET_FRAME_EXTENTS = atoms [off++]; - _NET_WM_PING = atoms [off++]; - _NET_WM_SYNC_REQUEST = atoms [off++]; - _NET_SYSTEM_TRAY_OPCODE = atoms [off++]; - _NET_SYSTEM_TRAY_ORIENTATION = atoms [off++]; - _NET_WM_STATE_MAXIMIZED_HORZ = atoms [off++]; - _NET_WM_STATE_MAXIMIZED_VERT = atoms [off++]; - _NET_WM_STATE_HIDDEN = atoms [off++]; - _XEMBED = atoms [off++]; - _XEMBED_INFO = atoms [off++]; - _MOTIF_WM_HINTS = atoms [off++]; - _NET_WM_STATE_SKIP_TASKBAR = atoms [off++]; - _NET_WM_STATE_ABOVE = atoms [off++]; - _NET_WM_STATE_MODAL = atoms [off++]; - _NET_WM_CONTEXT_HELP = atoms [off++]; - _NET_WM_WINDOW_OPACITY = atoms [off++]; - _NET_WM_WINDOW_TYPE_DESKTOP = atoms [off++]; - _NET_WM_WINDOW_TYPE_DOCK = atoms [off++]; - _NET_WM_WINDOW_TYPE_TOOLBAR = atoms [off++]; - _NET_WM_WINDOW_TYPE_MENU = atoms [off++]; - _NET_WM_WINDOW_TYPE_UTILITY = atoms [off++]; - _NET_WM_WINDOW_TYPE_DIALOG = atoms [off++]; - _NET_WM_WINDOW_TYPE_SPLASH = atoms [off++]; - _NET_WM_WINDOW_TYPE_NORMAL = atoms [off++]; - CLIPBOARD = atoms [off++]; - PRIMARY = atoms [off++]; - OEMTEXT = atoms [off++]; - UNICODETEXT = atoms [off++]; - TARGETS = atoms [off++]; + for (var c = 0; c < fields.Length; c++) + fields[c].SetValue(this, atoms[c]); - DIB = XA_PIXMAP; - - var defScreen = XDefaultScreen(display); - // XXX multi screen stuff here - _NET_SYSTEM_TRAY_S = XInternAtom (display, "_NET_SYSTEM_TRAY_S" + defScreen.ToString(), false); } } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 82564e98e0..523d4dae29 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.Diagnostics; using System.Linq; using System.Reactive.Disposables; +using System.Text; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Input.Raw; @@ -94,7 +95,7 @@ namespace Avalonia.X11 new EglGlPlatformSurface((EglDisplay)feature.Display, feature.DeferredContext, new SurfaceInfo(_x11.DeferredDisplay, _handle, _renderHandle))); Surfaces = surfaces.ToArray(); - UpdateWmHits(); + UpdateMotifHits(); XFlush(_x11.Display); } @@ -128,7 +129,7 @@ namespace Avalonia.X11 public double Scaling { get; } = 1; } - void UpdateWmHits() + void UpdateMotifHits() { var functions = MotifFunctions.All; var decorations = MotifDecorations.All; @@ -154,13 +155,36 @@ namespace Avalonia.X11 _x11.Atoms._MOTIF_WM_HINTS, _x11.Atoms._MOTIF_WM_HINTS, 32, PropertyMode.Replace, ref hints, 5); } + + void UpdateSizeHits() + { + var hints = new XSizeHints(); + hints.min_width = (int)_minMaxSize.minSize.Width; + hints.min_height = (int)_minMaxSize.minSize.Height; + hints.height_inc = hints.width_inc = 1; + var flags = XSizeHintsFlags.PMinSize | XSizeHintsFlags.PResizeInc; + // People might be passing double.MaxValue + if (_minMaxSize.maxSize.Width < 100000 && _minMaxSize.maxSize.Height < 100000) + { + + hints.max_width = (int)Math.Max(100000, _minMaxSize.maxSize.Width); + hints.max_height = (int)Math.Max(100000, _minMaxSize.maxSize.Height); + flags |= XSizeHintsFlags.PMaxSize; + } + + hints.flags = (IntPtr)flags; + + XSetWMNormalHints(_x11.Display, _handle, ref hints); + } public Size ClientSize { get; private set; } + //TODO public double Scaling { get; } = 1; public IEnumerable Surfaces { get; } public Action Input { get; set; } public Action Paint { get; set; } public Action Resized { get; set; } + //TODO public Action ScalingChanged { get; set; } public Action Deactivated { get; set; } public Action Activated { get; set; } @@ -355,6 +379,7 @@ namespace Avalonia.X11 private bool _systemDecorations = true; private bool _canResize = true; + private (Size minSize, Size maxSize) _minMaxSize; void ScheduleInput(RawInputEventArgs args) { @@ -451,7 +476,7 @@ namespace Avalonia.X11 public void SetSystemDecorations(bool enabled) { _systemDecorations = enabled; - UpdateWmHits(); + UpdateMotifHits(); } @@ -477,7 +502,7 @@ namespace Avalonia.X11 public void CanResize(bool value) { _canResize = value; - UpdateWmHits(); + UpdateMotifHits(); } public void SetCursor(IPlatformHandle cursor) @@ -590,33 +615,42 @@ namespace Avalonia.X11 public void SetTitle(string title) { + var data = Encoding.UTF8.GetBytes(title); + fixed (void* pdata = data) + { + XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_NAME, _x11.Atoms.UTF8_STRING, 8, + PropertyMode.Replace, pdata, data.Length); + XStoreName(_x11.Display, _handle, title); + } } public void SetMinMaxSize(Size minSize, Size maxSize) { - + _minMaxSize = (minSize, maxSize); + UpdateSizeHits(); } public void SetTopmost(bool value) { - + SendNetWMMessage(_x11.Atoms._NET_WM_STATE, + (IntPtr)(value ? 1 : 0), _x11.Atoms._NET_WM_STATE_ABOVE, IntPtr.Zero); } public IDisposable ShowDialog() { + // TODO return Disposable.Empty; } public void SetIcon(IWindowIconImpl icon) { + //TODO } public void ShowTaskbarIcon(bool value) { - } - - - - + SendNetWMMessage(_x11.Atoms._NET_WM_STATE, + (IntPtr)(value ? 0 : 1), _x11.Atoms._NET_WM_STATE_SKIP_TASKBAR, IntPtr.Zero); + } } } diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index d6c4ec6593..0f27191f88 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -215,6 +215,9 @@ namespace Avalonia.X11 [DllImport(libX11)] public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements); + [DllImport(libX11)] + public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, + int format, PropertyMode mode, void* data, int nelements); [DllImport(libX11)] public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, From df6e3eff03aa9d51481c5318300a44019b004f74 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 8 Nov 2018 22:06:58 +0300 Subject: [PATCH 10/46] [X11] Basic (non-IM) keyboard input and some refactorings/fixes --- src/Avalonia.X11/Keysyms.cs | 2108 +++++++++++++++++++++++++++ src/Avalonia.X11/X11Info.cs | 4 + src/Avalonia.X11/X11KeyTransform.cs | 232 +++ src/Avalonia.X11/X11Structs.cs | 2 +- src/Avalonia.X11/X11Window.cs | 143 +- src/Avalonia.X11/XLib.cs | 36 + 6 files changed, 2478 insertions(+), 47 deletions(-) create mode 100644 src/Avalonia.X11/Keysyms.cs create mode 100644 src/Avalonia.X11/X11KeyTransform.cs diff --git a/src/Avalonia.X11/Keysyms.cs b/src/Avalonia.X11/Keysyms.cs new file mode 100644 index 0000000000..651a06f574 --- /dev/null +++ b/src/Avalonia.X11/Keysyms.cs @@ -0,0 +1,2108 @@ +// ReSharper disable UnusedMember.Global +// ReSharper disable IdentifierTypo +// ReSharper disable CommentTypo +namespace Avalonia.X11 +{ + enum X11Key + { + VoidSymbol = 0xffffff /* Void symbol */, + BackSpace = 0xff08 /* Back space, back char */, + Tab = 0xff09, + Linefeed = 0xff0a /* Linefeed, LF */, + Clear = 0xff0b, + Return = 0xff0d /* Return, enter */, + Pause = 0xff13 /* Pause, hold */, + Scroll_Lock = 0xff14, + Sys_Req = 0xff15, + Escape = 0xff1b, + Delete = 0xffff /* Delete, rubout */, + Multi_key = 0xff20 /* Multi-key character compose */, + Codeinput = 0xff37, + SingleCandidate = 0xff3c, + MultipleCandidate = 0xff3d, + PreviousCandidate = 0xff3e, + Kanji = 0xff21 /* Kanji, Kanji convert */, + Muhenkan = 0xff22 /* Cancel Conversion */, + Henkan_Mode = 0xff23 /* Start/Stop Conversion */, + Henkan = 0xff23 /* Alias for Henkan_Mode */, + Romaji = 0xff24 /* to Romaji */, + Hiragana = 0xff25 /* to Hiragana */, + Katakana = 0xff26 /* to Katakana */, + Hiragana_Katakana = 0xff27 /* Hiragana/Katakana toggle */, + Zenkaku = 0xff28 /* to Zenkaku */, + Hankaku = 0xff29 /* to Hankaku */, + Zenkaku_Hankaku = 0xff2a /* Zenkaku/Hankaku toggle */, + Touroku = 0xff2b /* Add to Dictionary */, + Massyo = 0xff2c /* Delete from Dictionary */, + Kana_Lock = 0xff2d /* Kana Lock */, + Kana_Shift = 0xff2e /* Kana Shift */, + Eisu_Shift = 0xff2f /* Alphanumeric Shift */, + Eisu_toggle = 0xff30 /* Alphanumeric toggle */, + Kanji_Bangou = 0xff37 /* Codeinput */, + Zen_Koho = 0xff3d /* Multiple/All Candidate(s) */, + Mae_Koho = 0xff3e /* Previous Candidate */, + Home = 0xff50, + Left = 0xff51 /* Move left, left arrow */, + Up = 0xff52 /* Move up, up arrow */, + Right = 0xff53 /* Move right, right arrow */, + Down = 0xff54 /* Move down, down arrow */, + Prior = 0xff55 /* Prior, previous */, + Page_Up = 0xff55, + Next = 0xff56 /* Next */, + Page_Down = 0xff56, + End = 0xff57 /* EOL */, + Begin = 0xff58 /* BOL */, + Select = 0xff60 /* Select, mark */, + Print = 0xff61, + Execute = 0xff62 /* Execute, run, do */, + Insert = 0xff63 /* Insert, insert here */, + Undo = 0xff65, + Redo = 0xff66 /* Redo, again */, + Menu = 0xff67, + Find = 0xff68 /* Find, search */, + Cancel = 0xff69 /* Cancel, stop, abort, exit */, + Help = 0xff6a /* Help */, + Break = 0xff6b, + Mode_switch = 0xff7e /* Character set switch */, + script_switch = 0xff7e /* Alias for mode_switch */, + Num_Lock = 0xff7f, + KP_Space = 0xff80 /* Space */, + KP_Tab = 0xff89, + KP_Enter = 0xff8d /* Enter */, + KP_F1 = 0xff91 /* PF1, KP_A, ... */, + KP_F2 = 0xff92, + KP_F3 = 0xff93, + KP_F4 = 0xff94, + KP_Home = 0xff95, + KP_Left = 0xff96, + KP_Up = 0xff97, + KP_Right = 0xff98, + KP_Down = 0xff99, + KP_Prior = 0xff9a, + KP_Page_Up = 0xff9a, + KP_Next = 0xff9b, + KP_Page_Down = 0xff9b, + KP_End = 0xff9c, + KP_Begin = 0xff9d, + KP_Insert = 0xff9e, + KP_Delete = 0xff9f, + KP_Equal = 0xffbd /* Equals */, + KP_Multiply = 0xffaa, + KP_Add = 0xffab, + KP_Separator = 0xffac /* Separator, often comma */, + KP_Subtract = 0xffad, + KP_Decimal = 0xffae, + KP_Divide = 0xffaf, + KP_0 = 0xffb0, + KP_1 = 0xffb1, + KP_2 = 0xffb2, + KP_3 = 0xffb3, + KP_4 = 0xffb4, + KP_5 = 0xffb5, + KP_6 = 0xffb6, + KP_7 = 0xffb7, + KP_8 = 0xffb8, + KP_9 = 0xffb9, + F1 = 0xffbe, + F2 = 0xffbf, + F3 = 0xffc0, + F4 = 0xffc1, + F5 = 0xffc2, + F6 = 0xffc3, + F7 = 0xffc4, + F8 = 0xffc5, + F9 = 0xffc6, + F10 = 0xffc7, + F11 = 0xffc8, + L1 = 0xffc8, + F12 = 0xffc9, + L2 = 0xffc9, + F13 = 0xffca, + L3 = 0xffca, + F14 = 0xffcb, + L4 = 0xffcb, + F15 = 0xffcc, + L5 = 0xffcc, + F16 = 0xffcd, + L6 = 0xffcd, + F17 = 0xffce, + L7 = 0xffce, + F18 = 0xffcf, + L8 = 0xffcf, + F19 = 0xffd0, + L9 = 0xffd0, + F20 = 0xffd1, + L10 = 0xffd1, + F21 = 0xffd2, + R1 = 0xffd2, + F22 = 0xffd3, + R2 = 0xffd3, + F23 = 0xffd4, + R3 = 0xffd4, + F24 = 0xffd5, + R4 = 0xffd5, + F25 = 0xffd6, + R5 = 0xffd6, + F26 = 0xffd7, + R6 = 0xffd7, + F27 = 0xffd8, + R7 = 0xffd8, + F28 = 0xffd9, + R8 = 0xffd9, + F29 = 0xffda, + R9 = 0xffda, + F30 = 0xffdb, + R10 = 0xffdb, + F31 = 0xffdc, + R11 = 0xffdc, + F32 = 0xffdd, + R12 = 0xffdd, + F33 = 0xffde, + R13 = 0xffde, + F34 = 0xffdf, + R14 = 0xffdf, + F35 = 0xffe0, + R15 = 0xffe0, + Shift_L = 0xffe1 /* Left shift */, + Shift_R = 0xffe2 /* Right shift */, + Control_L = 0xffe3 /* Left control */, + Control_R = 0xffe4 /* Right control */, + Caps_Lock = 0xffe5 /* Caps lock */, + Shift_Lock = 0xffe6 /* Shift lock */, + Meta_L = 0xffe7 /* Left meta */, + Meta_R = 0xffe8 /* Right meta */, + Alt_L = 0xffe9 /* Left alt */, + Alt_R = 0xffea /* Right alt */, + Super_L = 0xffeb /* Left super */, + Super_R = 0xffec /* Right super */, + Hyper_L = 0xffed /* Left hyper */, + Hyper_R = 0xffee /* Right hyper */, + ISO_Lock = 0xfe01, + ISO_Level2_Latch = 0xfe02, + ISO_Level3_Shift = 0xfe03, + ISO_Level3_Latch = 0xfe04, + ISO_Level3_Lock = 0xfe05, + ISO_Level5_Shift = 0xfe11, + ISO_Level5_Latch = 0xfe12, + ISO_Level5_Lock = 0xfe13, + ISO_Group_Shift = 0xff7e /* Alias for mode_switch */, + ISO_Group_Latch = 0xfe06, + ISO_Group_Lock = 0xfe07, + ISO_Next_Group = 0xfe08, + ISO_Next_Group_Lock = 0xfe09, + ISO_Prev_Group = 0xfe0a, + ISO_Prev_Group_Lock = 0xfe0b, + ISO_First_Group = 0xfe0c, + ISO_First_Group_Lock = 0xfe0d, + ISO_Last_Group = 0xfe0e, + ISO_Last_Group_Lock = 0xfe0f, + ISO_Left_Tab = 0xfe20, + ISO_Move_Line_Up = 0xfe21, + ISO_Move_Line_Down = 0xfe22, + ISO_Partial_Line_Up = 0xfe23, + ISO_Partial_Line_Down = 0xfe24, + ISO_Partial_Space_Left = 0xfe25, + ISO_Partial_Space_Right = 0xfe26, + ISO_Set_Margin_Left = 0xfe27, + ISO_Set_Margin_Right = 0xfe28, + ISO_Release_Margin_Left = 0xfe29, + ISO_Release_Margin_Right = 0xfe2a, + ISO_Release_Both_Margins = 0xfe2b, + ISO_Fast_Cursor_Left = 0xfe2c, + ISO_Fast_Cursor_Right = 0xfe2d, + ISO_Fast_Cursor_Up = 0xfe2e, + ISO_Fast_Cursor_Down = 0xfe2f, + ISO_Continuous_Underline = 0xfe30, + ISO_Discontinuous_Underline = 0xfe31, + ISO_Emphasize = 0xfe32, + ISO_Center_Object = 0xfe33, + ISO_Enter = 0xfe34, + dead_grave = 0xfe50, + dead_acute = 0xfe51, + dead_circumflex = 0xfe52, + dead_tilde = 0xfe53, + dead_perispomeni = 0xfe53 /* alias for dead_tilde */, + dead_macron = 0xfe54, + dead_breve = 0xfe55, + dead_abovedot = 0xfe56, + dead_diaeresis = 0xfe57, + dead_abovering = 0xfe58, + dead_doubleacute = 0xfe59, + dead_caron = 0xfe5a, + dead_cedilla = 0xfe5b, + dead_ogonek = 0xfe5c, + dead_iota = 0xfe5d, + dead_voiced_sound = 0xfe5e, + dead_semivoiced_sound = 0xfe5f, + dead_belowdot = 0xfe60, + dead_hook = 0xfe61, + dead_horn = 0xfe62, + dead_stroke = 0xfe63, + dead_abovecomma = 0xfe64, + dead_psili = 0xfe64 /* alias for dead_abovecomma */, + dead_abovereversedcomma = 0xfe65, + dead_dasia = 0xfe65 /* alias for dead_abovereversedcomma */, + dead_doublegrave = 0xfe66, + dead_belowring = 0xfe67, + dead_belowmacron = 0xfe68, + dead_belowcircumflex = 0xfe69, + dead_belowtilde = 0xfe6a, + dead_belowbreve = 0xfe6b, + dead_belowdiaeresis = 0xfe6c, + dead_invertedbreve = 0xfe6d, + dead_belowcomma = 0xfe6e, + dead_currency = 0xfe6f, + dead_lowline = 0xfe90, + dead_aboveverticalline = 0xfe91, + dead_belowverticalline = 0xfe92, + dead_longsolidusoverlay = 0xfe93, + dead_a = 0xfe80, + dead_A = 0xfe81, + dead_e = 0xfe82, + dead_E = 0xfe83, + dead_i = 0xfe84, + dead_I = 0xfe85, + dead_o = 0xfe86, + dead_O = 0xfe87, + dead_u = 0xfe88, + dead_U = 0xfe89, + dead_small_schwa = 0xfe8a, + dead_capital_schwa = 0xfe8b, + dead_greek = 0xfe8c, + First_Virtual_Screen = 0xfed0, + Prev_Virtual_Screen = 0xfed1, + Next_Virtual_Screen = 0xfed2, + Last_Virtual_Screen = 0xfed4, + Terminate_Server = 0xfed5, + AccessX_Enable = 0xfe70, + AccessX_Feedback_Enable = 0xfe71, + RepeatKeys_Enable = 0xfe72, + SlowKeys_Enable = 0xfe73, + BounceKeys_Enable = 0xfe74, + StickyKeys_Enable = 0xfe75, + MouseKeys_Enable = 0xfe76, + MouseKeys_Accel_Enable = 0xfe77, + Overlay1_Enable = 0xfe78, + Overlay2_Enable = 0xfe79, + AudibleBell_Enable = 0xfe7a, + Pointer_Left = 0xfee0, + Pointer_Right = 0xfee1, + Pointer_Up = 0xfee2, + Pointer_Down = 0xfee3, + Pointer_UpLeft = 0xfee4, + Pointer_UpRight = 0xfee5, + Pointer_DownLeft = 0xfee6, + Pointer_DownRight = 0xfee7, + Pointer_Button_Dflt = 0xfee8, + Pointer_Button1 = 0xfee9, + Pointer_Button2 = 0xfeea, + Pointer_Button3 = 0xfeeb, + Pointer_Button4 = 0xfeec, + Pointer_Button5 = 0xfeed, + Pointer_DblClick_Dflt = 0xfeee, + Pointer_DblClick1 = 0xfeef, + Pointer_DblClick2 = 0xfef0, + Pointer_DblClick3 = 0xfef1, + Pointer_DblClick4 = 0xfef2, + Pointer_DblClick5 = 0xfef3, + Pointer_Drag_Dflt = 0xfef4, + Pointer_Drag1 = 0xfef5, + Pointer_Drag2 = 0xfef6, + Pointer_Drag3 = 0xfef7, + Pointer_Drag4 = 0xfef8, + Pointer_Drag5 = 0xfefd, + Pointer_EnableKeys = 0xfef9, + Pointer_Accelerate = 0xfefa, + Pointer_DfltBtnNext = 0xfefb, + Pointer_DfltBtnPrev = 0xfefc, + ch = 0xfea0, + Ch = 0xfea1, + CH = 0xfea2, + c_h = 0xfea3, + C_h = 0xfea4, + C_H = 0xfea5, + XK_3270_Duplicate = 0xfd01, + XK_3270_FieldMark = 0xfd02, + XK_3270_Right2 = 0xfd03, + XK_3270_Left2 = 0xfd04, + XK_3270_BackTab = 0xfd05, + XK_3270_EraseEOF = 0xfd06, + XK_3270_EraseInput = 0xfd07, + XK_3270_Reset = 0xfd08, + XK_3270_Quit = 0xfd09, + XK_3270_PA1 = 0xfd0a, + XK_3270_PA2 = 0xfd0b, + XK_3270_PA3 = 0xfd0c, + XK_3270_Test = 0xfd0d, + XK_3270_Attn = 0xfd0e, + XK_3270_CursorBlink = 0xfd0f, + XK_3270_AltCursor = 0xfd10, + XK_3270_KeyClick = 0xfd11, + XK_3270_Jump = 0xfd12, + XK_3270_Ident = 0xfd13, + XK_3270_Rule = 0xfd14, + XK_3270_Copy = 0xfd15, + XK_3270_Play = 0xfd16, + XK_3270_Setup = 0xfd17, + XK_3270_Record = 0xfd18, + XK_3270_ChangeScreen = 0xfd19, + XK_3270_DeleteWord = 0xfd1a, + XK_3270_ExSelect = 0xfd1b, + XK_3270_CursorSelect = 0xfd1c, + XK_3270_PrintScreen = 0xfd1d, + XK_3270_Enter = 0xfd1e, + space = 0x0020 /* U+0020 SPACE */, + exclam = 0x0021 /* U+0021 EXCLAMATION MARK */, + quotedbl = 0x0022 /* U+0022 QUOTATION MARK */, + numbersign = 0x0023 /* U+0023 NUMBER SIGN */, + dollar = 0x0024 /* U+0024 DOLLAR SIGN */, + percent = 0x0025 /* U+0025 PERCENT SIGN */, + ampersand = 0x0026 /* U+0026 AMPERSAND */, + apostrophe = 0x0027 /* U+0027 APOSTROPHE */, + quoteright = 0x0027 /* deprecated */, + parenleft = 0x0028 /* U+0028 LEFT PARENTHESIS */, + parenright = 0x0029 /* U+0029 RIGHT PARENTHESIS */, + asterisk = 0x002a /* U+002A ASTERISK */, + plus = 0x002b /* U+002B PLUS SIGN */, + comma = 0x002c /* U+002C COMMA */, + minus = 0x002d /* U+002D HYPHEN-MINUS */, + period = 0x002e /* U+002E FULL STOP */, + slash = 0x002f /* U+002F SOLIDUS */, + XK_0 = 0x0030 /* U+0030 DIGIT ZERO */, + XK_1 = 0x0031 /* U+0031 DIGIT ONE */, + XK_2 = 0x0032 /* U+0032 DIGIT TWO */, + XK_3 = 0x0033 /* U+0033 DIGIT THREE */, + XK_4 = 0x0034 /* U+0034 DIGIT FOUR */, + XK_5 = 0x0035 /* U+0035 DIGIT FIVE */, + XK_6 = 0x0036 /* U+0036 DIGIT SIX */, + XK_7 = 0x0037 /* U+0037 DIGIT SEVEN */, + XK_8 = 0x0038 /* U+0038 DIGIT EIGHT */, + XK_9 = 0x0039 /* U+0039 DIGIT NINE */, + colon = 0x003a /* U+003A COLON */, + semicolon = 0x003b /* U+003B SEMICOLON */, + less = 0x003c /* U+003C LESS-THAN SIGN */, + equal = 0x003d /* U+003D EQUALS SIGN */, + greater = 0x003e /* U+003E GREATER-THAN SIGN */, + question = 0x003f /* U+003F QUESTION MARK */, + at = 0x0040 /* U+0040 COMMERCIAL AT */, + A = 0x0041 /* U+0041 LATIN CAPITAL LETTER A */, + B = 0x0042 /* U+0042 LATIN CAPITAL LETTER B */, + C = 0x0043 /* U+0043 LATIN CAPITAL LETTER C */, + D = 0x0044 /* U+0044 LATIN CAPITAL LETTER D */, + E = 0x0045 /* U+0045 LATIN CAPITAL LETTER E */, + F = 0x0046 /* U+0046 LATIN CAPITAL LETTER F */, + G = 0x0047 /* U+0047 LATIN CAPITAL LETTER G */, + H = 0x0048 /* U+0048 LATIN CAPITAL LETTER H */, + I = 0x0049 /* U+0049 LATIN CAPITAL LETTER I */, + J = 0x004a /* U+004A LATIN CAPITAL LETTER J */, + K = 0x004b /* U+004B LATIN CAPITAL LETTER K */, + L = 0x004c /* U+004C LATIN CAPITAL LETTER L */, + M = 0x004d /* U+004D LATIN CAPITAL LETTER M */, + N = 0x004e /* U+004E LATIN CAPITAL LETTER N */, + O = 0x004f /* U+004F LATIN CAPITAL LETTER O */, + P = 0x0050 /* U+0050 LATIN CAPITAL LETTER P */, + Q = 0x0051 /* U+0051 LATIN CAPITAL LETTER Q */, + R = 0x0052 /* U+0052 LATIN CAPITAL LETTER R */, + S = 0x0053 /* U+0053 LATIN CAPITAL LETTER S */, + T = 0x0054 /* U+0054 LATIN CAPITAL LETTER T */, + U = 0x0055 /* U+0055 LATIN CAPITAL LETTER U */, + V = 0x0056 /* U+0056 LATIN CAPITAL LETTER V */, + W = 0x0057 /* U+0057 LATIN CAPITAL LETTER W */, + X = 0x0058 /* U+0058 LATIN CAPITAL LETTER X */, + Y = 0x0059 /* U+0059 LATIN CAPITAL LETTER Y */, + Z = 0x005a /* U+005A LATIN CAPITAL LETTER Z */, + bracketleft = 0x005b /* U+005B LEFT SQUARE BRACKET */, + backslash = 0x005c /* U+005C REVERSE SOLIDUS */, + bracketright = 0x005d /* U+005D RIGHT SQUARE BRACKET */, + asciicircum = 0x005e /* U+005E CIRCUMFLEX ACCENT */, + underscore = 0x005f /* U+005F LOW LINE */, + grave = 0x0060 /* U+0060 GRAVE ACCENT */, + quoteleft = 0x0060 /* deprecated */, + a = 0x0061 /* U+0061 LATIN SMALL LETTER A */, + b = 0x0062 /* U+0062 LATIN SMALL LETTER B */, + c = 0x0063 /* U+0063 LATIN SMALL LETTER C */, + d = 0x0064 /* U+0064 LATIN SMALL LETTER D */, + e = 0x0065 /* U+0065 LATIN SMALL LETTER E */, + f = 0x0066 /* U+0066 LATIN SMALL LETTER F */, + g = 0x0067 /* U+0067 LATIN SMALL LETTER G */, + h = 0x0068 /* U+0068 LATIN SMALL LETTER H */, + i = 0x0069 /* U+0069 LATIN SMALL LETTER I */, + j = 0x006a /* U+006A LATIN SMALL LETTER J */, + k = 0x006b /* U+006B LATIN SMALL LETTER K */, + l = 0x006c /* U+006C LATIN SMALL LETTER L */, + m = 0x006d /* U+006D LATIN SMALL LETTER M */, + n = 0x006e /* U+006E LATIN SMALL LETTER N */, + o = 0x006f /* U+006F LATIN SMALL LETTER O */, + p = 0x0070 /* U+0070 LATIN SMALL LETTER P */, + q = 0x0071 /* U+0071 LATIN SMALL LETTER Q */, + r = 0x0072 /* U+0072 LATIN SMALL LETTER R */, + s = 0x0073 /* U+0073 LATIN SMALL LETTER S */, + t = 0x0074 /* U+0074 LATIN SMALL LETTER T */, + u = 0x0075 /* U+0075 LATIN SMALL LETTER U */, + v = 0x0076 /* U+0076 LATIN SMALL LETTER V */, + w = 0x0077 /* U+0077 LATIN SMALL LETTER W */, + x = 0x0078 /* U+0078 LATIN SMALL LETTER X */, + y = 0x0079 /* U+0079 LATIN SMALL LETTER Y */, + z = 0x007a /* U+007A LATIN SMALL LETTER Z */, + braceleft = 0x007b /* U+007B LEFT CURLY BRACKET */, + bar = 0x007c /* U+007C VERTICAL LINE */, + braceright = 0x007d /* U+007D RIGHT CURLY BRACKET */, + asciitilde = 0x007e /* U+007E TILDE */, + nobreakspace = 0x00a0 /* U+00A0 NO-BREAK SPACE */, + exclamdown = 0x00a1 /* U+00A1 INVERTED EXCLAMATION MARK */, + cent = 0x00a2 /* U+00A2 CENT SIGN */, + sterling = 0x00a3 /* U+00A3 POUND SIGN */, + currency = 0x00a4 /* U+00A4 CURRENCY SIGN */, + yen = 0x00a5 /* U+00A5 YEN SIGN */, + brokenbar = 0x00a6 /* U+00A6 BROKEN BAR */, + section = 0x00a7 /* U+00A7 SECTION SIGN */, + diaeresis = 0x00a8 /* U+00A8 DIAERESIS */, + copyright = 0x00a9 /* U+00A9 COPYRIGHT SIGN */, + ordfeminine = 0x00aa /* U+00AA FEMININE ORDINAL INDICATOR */, + guillemotleft = 0x00ab /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */, + notsign = 0x00ac /* U+00AC NOT SIGN */, + hyphen = 0x00ad /* U+00AD SOFT HYPHEN */, + registered = 0x00ae /* U+00AE REGISTERED SIGN */, + macron = 0x00af /* U+00AF MACRON */, + degree = 0x00b0 /* U+00B0 DEGREE SIGN */, + plusminus = 0x00b1 /* U+00B1 PLUS-MINUS SIGN */, + twosuperior = 0x00b2 /* U+00B2 SUPERSCRIPT TWO */, + threesuperior = 0x00b3 /* U+00B3 SUPERSCRIPT THREE */, + acute = 0x00b4 /* U+00B4 ACUTE ACCENT */, + mu = 0x00b5 /* U+00B5 MICRO SIGN */, + paragraph = 0x00b6 /* U+00B6 PILCROW SIGN */, + periodcentered = 0x00b7 /* U+00B7 MIDDLE DOT */, + cedilla = 0x00b8 /* U+00B8 CEDILLA */, + onesuperior = 0x00b9 /* U+00B9 SUPERSCRIPT ONE */, + masculine = 0x00ba /* U+00BA MASCULINE ORDINAL INDICATOR */, + guillemotright = 0x00bb /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */, + onequarter = 0x00bc /* U+00BC VULGAR FRACTION ONE QUARTER */, + onehalf = 0x00bd /* U+00BD VULGAR FRACTION ONE HALF */, + threequarters = 0x00be /* U+00BE VULGAR FRACTION THREE QUARTERS */, + questiondown = 0x00bf /* U+00BF INVERTED QUESTION MARK */, + Agrave = 0x00c0 /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */, + Aacute = 0x00c1 /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */, + Acircumflex = 0x00c2 /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */, + Atilde = 0x00c3 /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */, + Adiaeresis = 0x00c4 /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */, + Aring = 0x00c5 /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */, + AE = 0x00c6 /* U+00C6 LATIN CAPITAL LETTER AE */, + Ccedilla = 0x00c7 /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */, + Egrave = 0x00c8 /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */, + Eacute = 0x00c9 /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */, + Ecircumflex = 0x00ca /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */, + Ediaeresis = 0x00cb /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */, + Igrave = 0x00cc /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */, + Iacute = 0x00cd /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */, + Icircumflex = 0x00ce /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */, + Idiaeresis = 0x00cf /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */, + ETH = 0x00d0 /* U+00D0 LATIN CAPITAL LETTER ETH */, + Eth = 0x00d0 /* deprecated */, + Ntilde = 0x00d1 /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */, + Ograve = 0x00d2 /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */, + Oacute = 0x00d3 /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */, + Ocircumflex = 0x00d4 /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */, + Otilde = 0x00d5 /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */, + Odiaeresis = 0x00d6 /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */, + multiply = 0x00d7 /* U+00D7 MULTIPLICATION SIGN */, + Oslash = 0x00d8 /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */, + Ooblique = 0x00d8 /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */, + Ugrave = 0x00d9 /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */, + Uacute = 0x00da /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */, + Ucircumflex = 0x00db /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */, + Udiaeresis = 0x00dc /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */, + Yacute = 0x00dd /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */, + THORN = 0x00de /* U+00DE LATIN CAPITAL LETTER THORN */, + Thorn = 0x00de /* deprecated */, + ssharp = 0x00df /* U+00DF LATIN SMALL LETTER SHARP S */, + agrave = 0x00e0 /* U+00E0 LATIN SMALL LETTER A WITH GRAVE */, + aacute = 0x00e1 /* U+00E1 LATIN SMALL LETTER A WITH ACUTE */, + acircumflex = 0x00e2 /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */, + atilde = 0x00e3 /* U+00E3 LATIN SMALL LETTER A WITH TILDE */, + adiaeresis = 0x00e4 /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */, + aring = 0x00e5 /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */, + ae = 0x00e6 /* U+00E6 LATIN SMALL LETTER AE */, + ccedilla = 0x00e7 /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */, + egrave = 0x00e8 /* U+00E8 LATIN SMALL LETTER E WITH GRAVE */, + eacute = 0x00e9 /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */, + ecircumflex = 0x00ea /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */, + ediaeresis = 0x00eb /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */, + igrave = 0x00ec /* U+00EC LATIN SMALL LETTER I WITH GRAVE */, + iacute = 0x00ed /* U+00ED LATIN SMALL LETTER I WITH ACUTE */, + icircumflex = 0x00ee /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */, + idiaeresis = 0x00ef /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */, + eth = 0x00f0 /* U+00F0 LATIN SMALL LETTER ETH */, + ntilde = 0x00f1 /* U+00F1 LATIN SMALL LETTER N WITH TILDE */, + ograve = 0x00f2 /* U+00F2 LATIN SMALL LETTER O WITH GRAVE */, + oacute = 0x00f3 /* U+00F3 LATIN SMALL LETTER O WITH ACUTE */, + ocircumflex = 0x00f4 /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */, + otilde = 0x00f5 /* U+00F5 LATIN SMALL LETTER O WITH TILDE */, + odiaeresis = 0x00f6 /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */, + division = 0x00f7 /* U+00F7 DIVISION SIGN */, + oslash = 0x00f8 /* U+00F8 LATIN SMALL LETTER O WITH STROKE */, + ooblique = 0x00f8 /* U+00F8 LATIN SMALL LETTER O WITH STROKE */, + ugrave = 0x00f9 /* U+00F9 LATIN SMALL LETTER U WITH GRAVE */, + uacute = 0x00fa /* U+00FA LATIN SMALL LETTER U WITH ACUTE */, + ucircumflex = 0x00fb /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */, + udiaeresis = 0x00fc /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */, + yacute = 0x00fd /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */, + thorn = 0x00fe /* U+00FE LATIN SMALL LETTER THORN */, + ydiaeresis = 0x00ff /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */, + Aogonek = 0x01a1 /* U+0104 LATIN CAPITAL LETTER A WITH OGONEK */, + breve = 0x01a2 /* U+02D8 BREVE */, + Lstroke = 0x01a3 /* U+0141 LATIN CAPITAL LETTER L WITH STROKE */, + Lcaron = 0x01a5 /* U+013D LATIN CAPITAL LETTER L WITH CARON */, + Sacute = 0x01a6 /* U+015A LATIN CAPITAL LETTER S WITH ACUTE */, + Scaron = 0x01a9 /* U+0160 LATIN CAPITAL LETTER S WITH CARON */, + Scedilla = 0x01aa /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA */, + Tcaron = 0x01ab /* U+0164 LATIN CAPITAL LETTER T WITH CARON */, + Zacute = 0x01ac /* U+0179 LATIN CAPITAL LETTER Z WITH ACUTE */, + Zcaron = 0x01ae /* U+017D LATIN CAPITAL LETTER Z WITH CARON */, + Zabovedot = 0x01af /* U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE */, + aogonek = 0x01b1 /* U+0105 LATIN SMALL LETTER A WITH OGONEK */, + ogonek = 0x01b2 /* U+02DB OGONEK */, + lstroke = 0x01b3 /* U+0142 LATIN SMALL LETTER L WITH STROKE */, + lcaron = 0x01b5 /* U+013E LATIN SMALL LETTER L WITH CARON */, + sacute = 0x01b6 /* U+015B LATIN SMALL LETTER S WITH ACUTE */, + caron = 0x01b7 /* U+02C7 CARON */, + scaron = 0x01b9 /* U+0161 LATIN SMALL LETTER S WITH CARON */, + scedilla = 0x01ba /* U+015F LATIN SMALL LETTER S WITH CEDILLA */, + tcaron = 0x01bb /* U+0165 LATIN SMALL LETTER T WITH CARON */, + zacute = 0x01bc /* U+017A LATIN SMALL LETTER Z WITH ACUTE */, + doubleacute = 0x01bd /* U+02DD DOUBLE ACUTE ACCENT */, + zcaron = 0x01be /* U+017E LATIN SMALL LETTER Z WITH CARON */, + zabovedot = 0x01bf /* U+017C LATIN SMALL LETTER Z WITH DOT ABOVE */, + Racute = 0x01c0 /* U+0154 LATIN CAPITAL LETTER R WITH ACUTE */, + Abreve = 0x01c3 /* U+0102 LATIN CAPITAL LETTER A WITH BREVE */, + Lacute = 0x01c5 /* U+0139 LATIN CAPITAL LETTER L WITH ACUTE */, + Cacute = 0x01c6 /* U+0106 LATIN CAPITAL LETTER C WITH ACUTE */, + Ccaron = 0x01c8 /* U+010C LATIN CAPITAL LETTER C WITH CARON */, + Eogonek = 0x01ca /* U+0118 LATIN CAPITAL LETTER E WITH OGONEK */, + Ecaron = 0x01cc /* U+011A LATIN CAPITAL LETTER E WITH CARON */, + Dcaron = 0x01cf /* U+010E LATIN CAPITAL LETTER D WITH CARON */, + Dstroke = 0x01d0 /* U+0110 LATIN CAPITAL LETTER D WITH STROKE */, + Nacute = 0x01d1 /* U+0143 LATIN CAPITAL LETTER N WITH ACUTE */, + Ncaron = 0x01d2 /* U+0147 LATIN CAPITAL LETTER N WITH CARON */, + Odoubleacute = 0x01d5 /* U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */, + Rcaron = 0x01d8 /* U+0158 LATIN CAPITAL LETTER R WITH CARON */, + Uring = 0x01d9 /* U+016E LATIN CAPITAL LETTER U WITH RING ABOVE */, + Udoubleacute = 0x01db /* U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */, + Tcedilla = 0x01de /* U+0162 LATIN CAPITAL LETTER T WITH CEDILLA */, + racute = 0x01e0 /* U+0155 LATIN SMALL LETTER R WITH ACUTE */, + abreve = 0x01e3 /* U+0103 LATIN SMALL LETTER A WITH BREVE */, + lacute = 0x01e5 /* U+013A LATIN SMALL LETTER L WITH ACUTE */, + cacute = 0x01e6 /* U+0107 LATIN SMALL LETTER C WITH ACUTE */, + ccaron = 0x01e8 /* U+010D LATIN SMALL LETTER C WITH CARON */, + eogonek = 0x01ea /* U+0119 LATIN SMALL LETTER E WITH OGONEK */, + ecaron = 0x01ec /* U+011B LATIN SMALL LETTER E WITH CARON */, + dcaron = 0x01ef /* U+010F LATIN SMALL LETTER D WITH CARON */, + dstroke = 0x01f0 /* U+0111 LATIN SMALL LETTER D WITH STROKE */, + nacute = 0x01f1 /* U+0144 LATIN SMALL LETTER N WITH ACUTE */, + ncaron = 0x01f2 /* U+0148 LATIN SMALL LETTER N WITH CARON */, + odoubleacute = 0x01f5 /* U+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE */, + rcaron = 0x01f8 /* U+0159 LATIN SMALL LETTER R WITH CARON */, + uring = 0x01f9 /* U+016F LATIN SMALL LETTER U WITH RING ABOVE */, + udoubleacute = 0x01fb /* U+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE */, + tcedilla = 0x01fe /* U+0163 LATIN SMALL LETTER T WITH CEDILLA */, + abovedot = 0x01ff /* U+02D9 DOT ABOVE */, + Hstroke = 0x02a1 /* U+0126 LATIN CAPITAL LETTER H WITH STROKE */, + Hcircumflex = 0x02a6 /* U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX */, + Iabovedot = 0x02a9 /* U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE */, + Gbreve = 0x02ab /* U+011E LATIN CAPITAL LETTER G WITH BREVE */, + Jcircumflex = 0x02ac /* U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX */, + hstroke = 0x02b1 /* U+0127 LATIN SMALL LETTER H WITH STROKE */, + hcircumflex = 0x02b6 /* U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX */, + idotless = 0x02b9 /* U+0131 LATIN SMALL LETTER DOTLESS I */, + gbreve = 0x02bb /* U+011F LATIN SMALL LETTER G WITH BREVE */, + jcircumflex = 0x02bc /* U+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX */, + Cabovedot = 0x02c5 /* U+010A LATIN CAPITAL LETTER C WITH DOT ABOVE */, + Ccircumflex = 0x02c6 /* U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX */, + Gabovedot = 0x02d5 /* U+0120 LATIN CAPITAL LETTER G WITH DOT ABOVE */, + Gcircumflex = 0x02d8 /* U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX */, + Ubreve = 0x02dd /* U+016C LATIN CAPITAL LETTER U WITH BREVE */, + Scircumflex = 0x02de /* U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX */, + cabovedot = 0x02e5 /* U+010B LATIN SMALL LETTER C WITH DOT ABOVE */, + ccircumflex = 0x02e6 /* U+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX */, + gabovedot = 0x02f5 /* U+0121 LATIN SMALL LETTER G WITH DOT ABOVE */, + gcircumflex = 0x02f8 /* U+011D LATIN SMALL LETTER G WITH CIRCUMFLEX */, + ubreve = 0x02fd /* U+016D LATIN SMALL LETTER U WITH BREVE */, + scircumflex = 0x02fe /* U+015D LATIN SMALL LETTER S WITH CIRCUMFLEX */, + kra = 0x03a2 /* U+0138 LATIN SMALL LETTER KRA */, + kappa = 0x03a2 /* deprecated */, + Rcedilla = 0x03a3 /* U+0156 LATIN CAPITAL LETTER R WITH CEDILLA */, + Itilde = 0x03a5 /* U+0128 LATIN CAPITAL LETTER I WITH TILDE */, + Lcedilla = 0x03a6 /* U+013B LATIN CAPITAL LETTER L WITH CEDILLA */, + Emacron = 0x03aa /* U+0112 LATIN CAPITAL LETTER E WITH MACRON */, + Gcedilla = 0x03ab /* U+0122 LATIN CAPITAL LETTER G WITH CEDILLA */, + Tslash = 0x03ac /* U+0166 LATIN CAPITAL LETTER T WITH STROKE */, + rcedilla = 0x03b3 /* U+0157 LATIN SMALL LETTER R WITH CEDILLA */, + itilde = 0x03b5 /* U+0129 LATIN SMALL LETTER I WITH TILDE */, + lcedilla = 0x03b6 /* U+013C LATIN SMALL LETTER L WITH CEDILLA */, + emacron = 0x03ba /* U+0113 LATIN SMALL LETTER E WITH MACRON */, + gcedilla = 0x03bb /* U+0123 LATIN SMALL LETTER G WITH CEDILLA */, + tslash = 0x03bc /* U+0167 LATIN SMALL LETTER T WITH STROKE */, + ENG = 0x03bd /* U+014A LATIN CAPITAL LETTER ENG */, + eng = 0x03bf /* U+014B LATIN SMALL LETTER ENG */, + Amacron = 0x03c0 /* U+0100 LATIN CAPITAL LETTER A WITH MACRON */, + Iogonek = 0x03c7 /* U+012E LATIN CAPITAL LETTER I WITH OGONEK */, + Eabovedot = 0x03cc /* U+0116 LATIN CAPITAL LETTER E WITH DOT ABOVE */, + Imacron = 0x03cf /* U+012A LATIN CAPITAL LETTER I WITH MACRON */, + Ncedilla = 0x03d1 /* U+0145 LATIN CAPITAL LETTER N WITH CEDILLA */, + Omacron = 0x03d2 /* U+014C LATIN CAPITAL LETTER O WITH MACRON */, + Kcedilla = 0x03d3 /* U+0136 LATIN CAPITAL LETTER K WITH CEDILLA */, + Uogonek = 0x03d9 /* U+0172 LATIN CAPITAL LETTER U WITH OGONEK */, + Utilde = 0x03dd /* U+0168 LATIN CAPITAL LETTER U WITH TILDE */, + Umacron = 0x03de /* U+016A LATIN CAPITAL LETTER U WITH MACRON */, + amacron = 0x03e0 /* U+0101 LATIN SMALL LETTER A WITH MACRON */, + iogonek = 0x03e7 /* U+012F LATIN SMALL LETTER I WITH OGONEK */, + eabovedot = 0x03ec /* U+0117 LATIN SMALL LETTER E WITH DOT ABOVE */, + imacron = 0x03ef /* U+012B LATIN SMALL LETTER I WITH MACRON */, + ncedilla = 0x03f1 /* U+0146 LATIN SMALL LETTER N WITH CEDILLA */, + omacron = 0x03f2 /* U+014D LATIN SMALL LETTER O WITH MACRON */, + kcedilla = 0x03f3 /* U+0137 LATIN SMALL LETTER K WITH CEDILLA */, + uogonek = 0x03f9 /* U+0173 LATIN SMALL LETTER U WITH OGONEK */, + utilde = 0x03fd /* U+0169 LATIN SMALL LETTER U WITH TILDE */, + umacron = 0x03fe /* U+016B LATIN SMALL LETTER U WITH MACRON */, + Wcircumflex = 0x1000174 /* U+0174 LATIN CAPITAL LETTER W WITH CIRCUMFLEX */, + wcircumflex = 0x1000175 /* U+0175 LATIN SMALL LETTER W WITH CIRCUMFLEX */, + Ycircumflex = 0x1000176 /* U+0176 LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */, + ycircumflex = 0x1000177 /* U+0177 LATIN SMALL LETTER Y WITH CIRCUMFLEX */, + Babovedot = 0x1001e02 /* U+1E02 LATIN CAPITAL LETTER B WITH DOT ABOVE */, + babovedot = 0x1001e03 /* U+1E03 LATIN SMALL LETTER B WITH DOT ABOVE */, + Dabovedot = 0x1001e0a /* U+1E0A LATIN CAPITAL LETTER D WITH DOT ABOVE */, + dabovedot = 0x1001e0b /* U+1E0B LATIN SMALL LETTER D WITH DOT ABOVE */, + Fabovedot = 0x1001e1e /* U+1E1E LATIN CAPITAL LETTER F WITH DOT ABOVE */, + fabovedot = 0x1001e1f /* U+1E1F LATIN SMALL LETTER F WITH DOT ABOVE */, + Mabovedot = 0x1001e40 /* U+1E40 LATIN CAPITAL LETTER M WITH DOT ABOVE */, + mabovedot = 0x1001e41 /* U+1E41 LATIN SMALL LETTER M WITH DOT ABOVE */, + Pabovedot = 0x1001e56 /* U+1E56 LATIN CAPITAL LETTER P WITH DOT ABOVE */, + pabovedot = 0x1001e57 /* U+1E57 LATIN SMALL LETTER P WITH DOT ABOVE */, + Sabovedot = 0x1001e60 /* U+1E60 LATIN CAPITAL LETTER S WITH DOT ABOVE */, + sabovedot = 0x1001e61 /* U+1E61 LATIN SMALL LETTER S WITH DOT ABOVE */, + Tabovedot = 0x1001e6a /* U+1E6A LATIN CAPITAL LETTER T WITH DOT ABOVE */, + tabovedot = 0x1001e6b /* U+1E6B LATIN SMALL LETTER T WITH DOT ABOVE */, + Wgrave = 0x1001e80 /* U+1E80 LATIN CAPITAL LETTER W WITH GRAVE */, + wgrave = 0x1001e81 /* U+1E81 LATIN SMALL LETTER W WITH GRAVE */, + Wacute = 0x1001e82 /* U+1E82 LATIN CAPITAL LETTER W WITH ACUTE */, + wacute = 0x1001e83 /* U+1E83 LATIN SMALL LETTER W WITH ACUTE */, + Wdiaeresis = 0x1001e84 /* U+1E84 LATIN CAPITAL LETTER W WITH DIAERESIS */, + wdiaeresis = 0x1001e85 /* U+1E85 LATIN SMALL LETTER W WITH DIAERESIS */, + Ygrave = 0x1001ef2 /* U+1EF2 LATIN CAPITAL LETTER Y WITH GRAVE */, + ygrave = 0x1001ef3 /* U+1EF3 LATIN SMALL LETTER Y WITH GRAVE */, + OE = 0x13bc /* U+0152 LATIN CAPITAL LIGATURE OE */, + oe = 0x13bd /* U+0153 LATIN SMALL LIGATURE OE */, + Ydiaeresis = 0x13be /* U+0178 LATIN CAPITAL LETTER Y WITH DIAERESIS */, + overline = 0x047e /* U+203E OVERLINE */, + kana_fullstop = 0x04a1 /* U+3002 IDEOGRAPHIC FULL STOP */, + kana_openingbracket = 0x04a2 /* U+300C LEFT CORNER BRACKET */, + kana_closingbracket = 0x04a3 /* U+300D RIGHT CORNER BRACKET */, + kana_comma = 0x04a4 /* U+3001 IDEOGRAPHIC COMMA */, + kana_conjunctive = 0x04a5 /* U+30FB KATAKANA MIDDLE DOT */, + kana_middledot = 0x04a5 /* deprecated */, + kana_WO = 0x04a6 /* U+30F2 KATAKANA LETTER WO */, + kana_a = 0x04a7 /* U+30A1 KATAKANA LETTER SMALL A */, + kana_i = 0x04a8 /* U+30A3 KATAKANA LETTER SMALL I */, + kana_u = 0x04a9 /* U+30A5 KATAKANA LETTER SMALL U */, + kana_e = 0x04aa /* U+30A7 KATAKANA LETTER SMALL E */, + kana_o = 0x04ab /* U+30A9 KATAKANA LETTER SMALL O */, + kana_ya = 0x04ac /* U+30E3 KATAKANA LETTER SMALL YA */, + kana_yu = 0x04ad /* U+30E5 KATAKANA LETTER SMALL YU */, + kana_yo = 0x04ae /* U+30E7 KATAKANA LETTER SMALL YO */, + kana_tsu = 0x04af /* U+30C3 KATAKANA LETTER SMALL TU */, + kana_tu = 0x04af /* deprecated */, + prolongedsound = 0x04b0 /* U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK */, + kana_A = 0x04b1 /* U+30A2 KATAKANA LETTER A */, + kana_I = 0x04b2 /* U+30A4 KATAKANA LETTER I */, + kana_U = 0x04b3 /* U+30A6 KATAKANA LETTER U */, + kana_E = 0x04b4 /* U+30A8 KATAKANA LETTER E */, + kana_O = 0x04b5 /* U+30AA KATAKANA LETTER O */, + kana_KA = 0x04b6 /* U+30AB KATAKANA LETTER KA */, + kana_KI = 0x04b7 /* U+30AD KATAKANA LETTER KI */, + kana_KU = 0x04b8 /* U+30AF KATAKANA LETTER KU */, + kana_KE = 0x04b9 /* U+30B1 KATAKANA LETTER KE */, + kana_KO = 0x04ba /* U+30B3 KATAKANA LETTER KO */, + kana_SA = 0x04bb /* U+30B5 KATAKANA LETTER SA */, + kana_SHI = 0x04bc /* U+30B7 KATAKANA LETTER SI */, + kana_SU = 0x04bd /* U+30B9 KATAKANA LETTER SU */, + kana_SE = 0x04be /* U+30BB KATAKANA LETTER SE */, + kana_SO = 0x04bf /* U+30BD KATAKANA LETTER SO */, + kana_TA = 0x04c0 /* U+30BF KATAKANA LETTER TA */, + kana_CHI = 0x04c1 /* U+30C1 KATAKANA LETTER TI */, + kana_TI = 0x04c1 /* deprecated */, + kana_TSU = 0x04c2 /* U+30C4 KATAKANA LETTER TU */, + kana_TU = 0x04c2 /* deprecated */, + kana_TE = 0x04c3 /* U+30C6 KATAKANA LETTER TE */, + kana_TO = 0x04c4 /* U+30C8 KATAKANA LETTER TO */, + kana_NA = 0x04c5 /* U+30CA KATAKANA LETTER NA */, + kana_NI = 0x04c6 /* U+30CB KATAKANA LETTER NI */, + kana_NU = 0x04c7 /* U+30CC KATAKANA LETTER NU */, + kana_NE = 0x04c8 /* U+30CD KATAKANA LETTER NE */, + kana_NO = 0x04c9 /* U+30CE KATAKANA LETTER NO */, + kana_HA = 0x04ca /* U+30CF KATAKANA LETTER HA */, + kana_HI = 0x04cb /* U+30D2 KATAKANA LETTER HI */, + kana_FU = 0x04cc /* U+30D5 KATAKANA LETTER HU */, + kana_HU = 0x04cc /* deprecated */, + kana_HE = 0x04cd /* U+30D8 KATAKANA LETTER HE */, + kana_HO = 0x04ce /* U+30DB KATAKANA LETTER HO */, + kana_MA = 0x04cf /* U+30DE KATAKANA LETTER MA */, + kana_MI = 0x04d0 /* U+30DF KATAKANA LETTER MI */, + kana_MU = 0x04d1 /* U+30E0 KATAKANA LETTER MU */, + kana_ME = 0x04d2 /* U+30E1 KATAKANA LETTER ME */, + kana_MO = 0x04d3 /* U+30E2 KATAKANA LETTER MO */, + kana_YA = 0x04d4 /* U+30E4 KATAKANA LETTER YA */, + kana_YU = 0x04d5 /* U+30E6 KATAKANA LETTER YU */, + kana_YO = 0x04d6 /* U+30E8 KATAKANA LETTER YO */, + kana_RA = 0x04d7 /* U+30E9 KATAKANA LETTER RA */, + kana_RI = 0x04d8 /* U+30EA KATAKANA LETTER RI */, + kana_RU = 0x04d9 /* U+30EB KATAKANA LETTER RU */, + kana_RE = 0x04da /* U+30EC KATAKANA LETTER RE */, + kana_RO = 0x04db /* U+30ED KATAKANA LETTER RO */, + kana_WA = 0x04dc /* U+30EF KATAKANA LETTER WA */, + kana_N = 0x04dd /* U+30F3 KATAKANA LETTER N */, + voicedsound = 0x04de /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */, + semivoicedsound = 0x04df /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */, + kana_switch = 0xff7e /* Alias for mode_switch */, + Farsi_0 = 0x10006f0 /* U+06F0 EXTENDED ARABIC-INDIC DIGIT ZERO */, + Farsi_1 = 0x10006f1 /* U+06F1 EXTENDED ARABIC-INDIC DIGIT ONE */, + Farsi_2 = 0x10006f2 /* U+06F2 EXTENDED ARABIC-INDIC DIGIT TWO */, + Farsi_3 = 0x10006f3 /* U+06F3 EXTENDED ARABIC-INDIC DIGIT THREE */, + Farsi_4 = 0x10006f4 /* U+06F4 EXTENDED ARABIC-INDIC DIGIT FOUR */, + Farsi_5 = 0x10006f5 /* U+06F5 EXTENDED ARABIC-INDIC DIGIT FIVE */, + Farsi_6 = 0x10006f6 /* U+06F6 EXTENDED ARABIC-INDIC DIGIT SIX */, + Farsi_7 = 0x10006f7 /* U+06F7 EXTENDED ARABIC-INDIC DIGIT SEVEN */, + Farsi_8 = 0x10006f8 /* U+06F8 EXTENDED ARABIC-INDIC DIGIT EIGHT */, + Farsi_9 = 0x10006f9 /* U+06F9 EXTENDED ARABIC-INDIC DIGIT NINE */, + Arabic_percent = 0x100066a /* U+066A ARABIC PERCENT SIGN */, + Arabic_superscript_alef = 0x1000670 /* U+0670 ARABIC LETTER SUPERSCRIPT ALEF */, + Arabic_tteh = 0x1000679 /* U+0679 ARABIC LETTER TTEH */, + Arabic_peh = 0x100067e /* U+067E ARABIC LETTER PEH */, + Arabic_tcheh = 0x1000686 /* U+0686 ARABIC LETTER TCHEH */, + Arabic_ddal = 0x1000688 /* U+0688 ARABIC LETTER DDAL */, + Arabic_rreh = 0x1000691 /* U+0691 ARABIC LETTER RREH */, + Arabic_comma = 0x05ac /* U+060C ARABIC COMMA */, + Arabic_fullstop = 0x10006d4 /* U+06D4 ARABIC FULL STOP */, + Arabic_0 = 0x1000660 /* U+0660 ARABIC-INDIC DIGIT ZERO */, + Arabic_1 = 0x1000661 /* U+0661 ARABIC-INDIC DIGIT ONE */, + Arabic_2 = 0x1000662 /* U+0662 ARABIC-INDIC DIGIT TWO */, + Arabic_3 = 0x1000663 /* U+0663 ARABIC-INDIC DIGIT THREE */, + Arabic_4 = 0x1000664 /* U+0664 ARABIC-INDIC DIGIT FOUR */, + Arabic_5 = 0x1000665 /* U+0665 ARABIC-INDIC DIGIT FIVE */, + Arabic_6 = 0x1000666 /* U+0666 ARABIC-INDIC DIGIT SIX */, + Arabic_7 = 0x1000667 /* U+0667 ARABIC-INDIC DIGIT SEVEN */, + Arabic_8 = 0x1000668 /* U+0668 ARABIC-INDIC DIGIT EIGHT */, + Arabic_9 = 0x1000669 /* U+0669 ARABIC-INDIC DIGIT NINE */, + Arabic_semicolon = 0x05bb /* U+061B ARABIC SEMICOLON */, + Arabic_question_mark = 0x05bf /* U+061F ARABIC QUESTION MARK */, + Arabic_hamza = 0x05c1 /* U+0621 ARABIC LETTER HAMZA */, + Arabic_maddaonalef = 0x05c2 /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */, + Arabic_hamzaonalef = 0x05c3 /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */, + Arabic_hamzaonwaw = 0x05c4 /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */, + Arabic_hamzaunderalef = 0x05c5 /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */, + Arabic_hamzaonyeh = 0x05c6 /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */, + Arabic_alef = 0x05c7 /* U+0627 ARABIC LETTER ALEF */, + Arabic_beh = 0x05c8 /* U+0628 ARABIC LETTER BEH */, + Arabic_tehmarbuta = 0x05c9 /* U+0629 ARABIC LETTER TEH MARBUTA */, + Arabic_teh = 0x05ca /* U+062A ARABIC LETTER TEH */, + Arabic_theh = 0x05cb /* U+062B ARABIC LETTER THEH */, + Arabic_jeem = 0x05cc /* U+062C ARABIC LETTER JEEM */, + Arabic_hah = 0x05cd /* U+062D ARABIC LETTER HAH */, + Arabic_khah = 0x05ce /* U+062E ARABIC LETTER KHAH */, + Arabic_dal = 0x05cf /* U+062F ARABIC LETTER DAL */, + Arabic_thal = 0x05d0 /* U+0630 ARABIC LETTER THAL */, + Arabic_ra = 0x05d1 /* U+0631 ARABIC LETTER REH */, + Arabic_zain = 0x05d2 /* U+0632 ARABIC LETTER ZAIN */, + Arabic_seen = 0x05d3 /* U+0633 ARABIC LETTER SEEN */, + Arabic_sheen = 0x05d4 /* U+0634 ARABIC LETTER SHEEN */, + Arabic_sad = 0x05d5 /* U+0635 ARABIC LETTER SAD */, + Arabic_dad = 0x05d6 /* U+0636 ARABIC LETTER DAD */, + Arabic_tah = 0x05d7 /* U+0637 ARABIC LETTER TAH */, + Arabic_zah = 0x05d8 /* U+0638 ARABIC LETTER ZAH */, + Arabic_ain = 0x05d9 /* U+0639 ARABIC LETTER AIN */, + Arabic_ghain = 0x05da /* U+063A ARABIC LETTER GHAIN */, + Arabic_tatweel = 0x05e0 /* U+0640 ARABIC TATWEEL */, + Arabic_feh = 0x05e1 /* U+0641 ARABIC LETTER FEH */, + Arabic_qaf = 0x05e2 /* U+0642 ARABIC LETTER QAF */, + Arabic_kaf = 0x05e3 /* U+0643 ARABIC LETTER KAF */, + Arabic_lam = 0x05e4 /* U+0644 ARABIC LETTER LAM */, + Arabic_meem = 0x05e5 /* U+0645 ARABIC LETTER MEEM */, + Arabic_noon = 0x05e6 /* U+0646 ARABIC LETTER NOON */, + Arabic_ha = 0x05e7 /* U+0647 ARABIC LETTER HEH */, + Arabic_heh = 0x05e7 /* deprecated */, + Arabic_waw = 0x05e8 /* U+0648 ARABIC LETTER WAW */, + Arabic_alefmaksura = 0x05e9 /* U+0649 ARABIC LETTER ALEF MAKSURA */, + Arabic_yeh = 0x05ea /* U+064A ARABIC LETTER YEH */, + Arabic_fathatan = 0x05eb /* U+064B ARABIC FATHATAN */, + Arabic_dammatan = 0x05ec /* U+064C ARABIC DAMMATAN */, + Arabic_kasratan = 0x05ed /* U+064D ARABIC KASRATAN */, + Arabic_fatha = 0x05ee /* U+064E ARABIC FATHA */, + Arabic_damma = 0x05ef /* U+064F ARABIC DAMMA */, + Arabic_kasra = 0x05f0 /* U+0650 ARABIC KASRA */, + Arabic_shadda = 0x05f1 /* U+0651 ARABIC SHADDA */, + Arabic_sukun = 0x05f2 /* U+0652 ARABIC SUKUN */, + Arabic_madda_above = 0x1000653 /* U+0653 ARABIC MADDAH ABOVE */, + Arabic_hamza_above = 0x1000654 /* U+0654 ARABIC HAMZA ABOVE */, + Arabic_hamza_below = 0x1000655 /* U+0655 ARABIC HAMZA BELOW */, + Arabic_jeh = 0x1000698 /* U+0698 ARABIC LETTER JEH */, + Arabic_veh = 0x10006a4 /* U+06A4 ARABIC LETTER VEH */, + Arabic_keheh = 0x10006a9 /* U+06A9 ARABIC LETTER KEHEH */, + Arabic_gaf = 0x10006af /* U+06AF ARABIC LETTER GAF */, + Arabic_noon_ghunna = 0x10006ba /* U+06BA ARABIC LETTER NOON GHUNNA */, + Arabic_heh_doachashmee = 0x10006be /* U+06BE ARABIC LETTER HEH DOACHASHMEE */, + Farsi_yeh = 0x10006cc /* U+06CC ARABIC LETTER FARSI YEH */, + Arabic_farsi_yeh = 0x10006cc /* U+06CC ARABIC LETTER FARSI YEH */, + Arabic_yeh_baree = 0x10006d2 /* U+06D2 ARABIC LETTER YEH BARREE */, + Arabic_heh_goal = 0x10006c1 /* U+06C1 ARABIC LETTER HEH GOAL */, + Arabic_switch = 0xff7e /* Alias for mode_switch */, + Cyrillic_GHE_bar = 0x1000492 /* U+0492 CYRILLIC CAPITAL LETTER GHE WITH STROKE */, + Cyrillic_ghe_bar = 0x1000493 /* U+0493 CYRILLIC SMALL LETTER GHE WITH STROKE */, + Cyrillic_ZHE_descender = 0x1000496 /* U+0496 CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER */, + Cyrillic_zhe_descender = 0x1000497 /* U+0497 CYRILLIC SMALL LETTER ZHE WITH DESCENDER */, + Cyrillic_KA_descender = 0x100049a /* U+049A CYRILLIC CAPITAL LETTER KA WITH DESCENDER */, + Cyrillic_ka_descender = 0x100049b /* U+049B CYRILLIC SMALL LETTER KA WITH DESCENDER */, + Cyrillic_KA_vertstroke = 0x100049c /* U+049C CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE */, + Cyrillic_ka_vertstroke = 0x100049d /* U+049D CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE */, + Cyrillic_EN_descender = 0x10004a2 /* U+04A2 CYRILLIC CAPITAL LETTER EN WITH DESCENDER */, + Cyrillic_en_descender = 0x10004a3 /* U+04A3 CYRILLIC SMALL LETTER EN WITH DESCENDER */, + Cyrillic_U_straight = 0x10004ae /* U+04AE CYRILLIC CAPITAL LETTER STRAIGHT U */, + Cyrillic_u_straight = 0x10004af /* U+04AF CYRILLIC SMALL LETTER STRAIGHT U */, + Cyrillic_U_straight_bar = 0x10004b0 /* U+04B0 CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE */, + Cyrillic_u_straight_bar = 0x10004b1 /* U+04B1 CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE */, + Cyrillic_HA_descender = 0x10004b2 /* U+04B2 CYRILLIC CAPITAL LETTER HA WITH DESCENDER */, + Cyrillic_ha_descender = 0x10004b3 /* U+04B3 CYRILLIC SMALL LETTER HA WITH DESCENDER */, + Cyrillic_CHE_descender = 0x10004b6 /* U+04B6 CYRILLIC CAPITAL LETTER CHE WITH DESCENDER */, + Cyrillic_che_descender = 0x10004b7 /* U+04B7 CYRILLIC SMALL LETTER CHE WITH DESCENDER */, + Cyrillic_CHE_vertstroke = 0x10004b8 /* U+04B8 CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE */, + Cyrillic_che_vertstroke = 0x10004b9 /* U+04B9 CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE */, + Cyrillic_SHHA = 0x10004ba /* U+04BA CYRILLIC CAPITAL LETTER SHHA */, + Cyrillic_shha = 0x10004bb /* U+04BB CYRILLIC SMALL LETTER SHHA */, + Cyrillic_SCHWA = 0x10004d8 /* U+04D8 CYRILLIC CAPITAL LETTER SCHWA */, + Cyrillic_schwa = 0x10004d9 /* U+04D9 CYRILLIC SMALL LETTER SCHWA */, + Cyrillic_I_macron = 0x10004e2 /* U+04E2 CYRILLIC CAPITAL LETTER I WITH MACRON */, + Cyrillic_i_macron = 0x10004e3 /* U+04E3 CYRILLIC SMALL LETTER I WITH MACRON */, + Cyrillic_O_bar = 0x10004e8 /* U+04E8 CYRILLIC CAPITAL LETTER BARRED O */, + Cyrillic_o_bar = 0x10004e9 /* U+04E9 CYRILLIC SMALL LETTER BARRED O */, + Cyrillic_U_macron = 0x10004ee /* U+04EE CYRILLIC CAPITAL LETTER U WITH MACRON */, + Cyrillic_u_macron = 0x10004ef /* U+04EF CYRILLIC SMALL LETTER U WITH MACRON */, + Serbian_dje = 0x06a1 /* U+0452 CYRILLIC SMALL LETTER DJE */, + Macedonia_gje = 0x06a2 /* U+0453 CYRILLIC SMALL LETTER GJE */, + Cyrillic_io = 0x06a3 /* U+0451 CYRILLIC SMALL LETTER IO */, + Ukrainian_ie = 0x06a4 /* U+0454 CYRILLIC SMALL LETTER UKRAINIAN IE */, + Ukranian_je = 0x06a4 /* deprecated */, + Macedonia_dse = 0x06a5 /* U+0455 CYRILLIC SMALL LETTER DZE */, + Ukrainian_i = 0x06a6 /* U+0456 CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */, + Ukranian_i = 0x06a6 /* deprecated */, + Ukrainian_yi = 0x06a7 /* U+0457 CYRILLIC SMALL LETTER YI */, + Ukranian_yi = 0x06a7 /* deprecated */, + Cyrillic_je = 0x06a8 /* U+0458 CYRILLIC SMALL LETTER JE */, + Serbian_je = 0x06a8 /* deprecated */, + Cyrillic_lje = 0x06a9 /* U+0459 CYRILLIC SMALL LETTER LJE */, + Serbian_lje = 0x06a9 /* deprecated */, + Cyrillic_nje = 0x06aa /* U+045A CYRILLIC SMALL LETTER NJE */, + Serbian_nje = 0x06aa /* deprecated */, + Serbian_tshe = 0x06ab /* U+045B CYRILLIC SMALL LETTER TSHE */, + Macedonia_kje = 0x06ac /* U+045C CYRILLIC SMALL LETTER KJE */, + Ukrainian_ghe_with_upturn = 0x06ad /* U+0491 CYRILLIC SMALL LETTER GHE WITH UPTURN */, + Byelorussian_shortu = 0x06ae /* U+045E CYRILLIC SMALL LETTER SHORT U */, + Cyrillic_dzhe = 0x06af /* U+045F CYRILLIC SMALL LETTER DZHE */, + Serbian_dze = 0x06af /* deprecated */, + numerosign = 0x06b0 /* U+2116 NUMERO SIGN */, + Serbian_DJE = 0x06b1 /* U+0402 CYRILLIC CAPITAL LETTER DJE */, + Macedonia_GJE = 0x06b2 /* U+0403 CYRILLIC CAPITAL LETTER GJE */, + Cyrillic_IO = 0x06b3 /* U+0401 CYRILLIC CAPITAL LETTER IO */, + Ukrainian_IE = 0x06b4 /* U+0404 CYRILLIC CAPITAL LETTER UKRAINIAN IE */, + Ukranian_JE = 0x06b4 /* deprecated */, + Macedonia_DSE = 0x06b5 /* U+0405 CYRILLIC CAPITAL LETTER DZE */, + Ukrainian_I = 0x06b6 /* U+0406 CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */, + Ukranian_I = 0x06b6 /* deprecated */, + Ukrainian_YI = 0x06b7 /* U+0407 CYRILLIC CAPITAL LETTER YI */, + Ukranian_YI = 0x06b7 /* deprecated */, + Cyrillic_JE = 0x06b8 /* U+0408 CYRILLIC CAPITAL LETTER JE */, + Serbian_JE = 0x06b8 /* deprecated */, + Cyrillic_LJE = 0x06b9 /* U+0409 CYRILLIC CAPITAL LETTER LJE */, + Serbian_LJE = 0x06b9 /* deprecated */, + Cyrillic_NJE = 0x06ba /* U+040A CYRILLIC CAPITAL LETTER NJE */, + Serbian_NJE = 0x06ba /* deprecated */, + Serbian_TSHE = 0x06bb /* U+040B CYRILLIC CAPITAL LETTER TSHE */, + Macedonia_KJE = 0x06bc /* U+040C CYRILLIC CAPITAL LETTER KJE */, + Ukrainian_GHE_WITH_UPTURN = 0x06bd /* U+0490 CYRILLIC CAPITAL LETTER GHE WITH UPTURN */, + Byelorussian_SHORTU = 0x06be /* U+040E CYRILLIC CAPITAL LETTER SHORT U */, + Cyrillic_DZHE = 0x06bf /* U+040F CYRILLIC CAPITAL LETTER DZHE */, + Serbian_DZE = 0x06bf /* deprecated */, + Cyrillic_yu = 0x06c0 /* U+044E CYRILLIC SMALL LETTER YU */, + Cyrillic_a = 0x06c1 /* U+0430 CYRILLIC SMALL LETTER A */, + Cyrillic_be = 0x06c2 /* U+0431 CYRILLIC SMALL LETTER BE */, + Cyrillic_tse = 0x06c3 /* U+0446 CYRILLIC SMALL LETTER TSE */, + Cyrillic_de = 0x06c4 /* U+0434 CYRILLIC SMALL LETTER DE */, + Cyrillic_ie = 0x06c5 /* U+0435 CYRILLIC SMALL LETTER IE */, + Cyrillic_ef = 0x06c6 /* U+0444 CYRILLIC SMALL LETTER EF */, + Cyrillic_ghe = 0x06c7 /* U+0433 CYRILLIC SMALL LETTER GHE */, + Cyrillic_ha = 0x06c8 /* U+0445 CYRILLIC SMALL LETTER HA */, + Cyrillic_i = 0x06c9 /* U+0438 CYRILLIC SMALL LETTER I */, + Cyrillic_shorti = 0x06ca /* U+0439 CYRILLIC SMALL LETTER SHORT I */, + Cyrillic_ka = 0x06cb /* U+043A CYRILLIC SMALL LETTER KA */, + Cyrillic_el = 0x06cc /* U+043B CYRILLIC SMALL LETTER EL */, + Cyrillic_em = 0x06cd /* U+043C CYRILLIC SMALL LETTER EM */, + Cyrillic_en = 0x06ce /* U+043D CYRILLIC SMALL LETTER EN */, + Cyrillic_o = 0x06cf /* U+043E CYRILLIC SMALL LETTER O */, + Cyrillic_pe = 0x06d0 /* U+043F CYRILLIC SMALL LETTER PE */, + Cyrillic_ya = 0x06d1 /* U+044F CYRILLIC SMALL LETTER YA */, + Cyrillic_er = 0x06d2 /* U+0440 CYRILLIC SMALL LETTER ER */, + Cyrillic_es = 0x06d3 /* U+0441 CYRILLIC SMALL LETTER ES */, + Cyrillic_te = 0x06d4 /* U+0442 CYRILLIC SMALL LETTER TE */, + Cyrillic_u = 0x06d5 /* U+0443 CYRILLIC SMALL LETTER U */, + Cyrillic_zhe = 0x06d6 /* U+0436 CYRILLIC SMALL LETTER ZHE */, + Cyrillic_ve = 0x06d7 /* U+0432 CYRILLIC SMALL LETTER VE */, + Cyrillic_softsign = 0x06d8 /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */, + Cyrillic_yeru = 0x06d9 /* U+044B CYRILLIC SMALL LETTER YERU */, + Cyrillic_ze = 0x06da /* U+0437 CYRILLIC SMALL LETTER ZE */, + Cyrillic_sha = 0x06db /* U+0448 CYRILLIC SMALL LETTER SHA */, + Cyrillic_e = 0x06dc /* U+044D CYRILLIC SMALL LETTER E */, + Cyrillic_shcha = 0x06dd /* U+0449 CYRILLIC SMALL LETTER SHCHA */, + Cyrillic_che = 0x06de /* U+0447 CYRILLIC SMALL LETTER CHE */, + Cyrillic_hardsign = 0x06df /* U+044A CYRILLIC SMALL LETTER HARD SIGN */, + Cyrillic_YU = 0x06e0 /* U+042E CYRILLIC CAPITAL LETTER YU */, + Cyrillic_A = 0x06e1 /* U+0410 CYRILLIC CAPITAL LETTER A */, + Cyrillic_BE = 0x06e2 /* U+0411 CYRILLIC CAPITAL LETTER BE */, + Cyrillic_TSE = 0x06e3 /* U+0426 CYRILLIC CAPITAL LETTER TSE */, + Cyrillic_DE = 0x06e4 /* U+0414 CYRILLIC CAPITAL LETTER DE */, + Cyrillic_IE = 0x06e5 /* U+0415 CYRILLIC CAPITAL LETTER IE */, + Cyrillic_EF = 0x06e6 /* U+0424 CYRILLIC CAPITAL LETTER EF */, + Cyrillic_GHE = 0x06e7 /* U+0413 CYRILLIC CAPITAL LETTER GHE */, + Cyrillic_HA = 0x06e8 /* U+0425 CYRILLIC CAPITAL LETTER HA */, + Cyrillic_I = 0x06e9 /* U+0418 CYRILLIC CAPITAL LETTER I */, + Cyrillic_SHORTI = 0x06ea /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */, + Cyrillic_KA = 0x06eb /* U+041A CYRILLIC CAPITAL LETTER KA */, + Cyrillic_EL = 0x06ec /* U+041B CYRILLIC CAPITAL LETTER EL */, + Cyrillic_EM = 0x06ed /* U+041C CYRILLIC CAPITAL LETTER EM */, + Cyrillic_EN = 0x06ee /* U+041D CYRILLIC CAPITAL LETTER EN */, + Cyrillic_O = 0x06ef /* U+041E CYRILLIC CAPITAL LETTER O */, + Cyrillic_PE = 0x06f0 /* U+041F CYRILLIC CAPITAL LETTER PE */, + Cyrillic_YA = 0x06f1 /* U+042F CYRILLIC CAPITAL LETTER YA */, + Cyrillic_ER = 0x06f2 /* U+0420 CYRILLIC CAPITAL LETTER ER */, + Cyrillic_ES = 0x06f3 /* U+0421 CYRILLIC CAPITAL LETTER ES */, + Cyrillic_TE = 0x06f4 /* U+0422 CYRILLIC CAPITAL LETTER TE */, + Cyrillic_U = 0x06f5 /* U+0423 CYRILLIC CAPITAL LETTER U */, + Cyrillic_ZHE = 0x06f6 /* U+0416 CYRILLIC CAPITAL LETTER ZHE */, + Cyrillic_VE = 0x06f7 /* U+0412 CYRILLIC CAPITAL LETTER VE */, + Cyrillic_SOFTSIGN = 0x06f8 /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */, + Cyrillic_YERU = 0x06f9 /* U+042B CYRILLIC CAPITAL LETTER YERU */, + Cyrillic_ZE = 0x06fa /* U+0417 CYRILLIC CAPITAL LETTER ZE */, + Cyrillic_SHA = 0x06fb /* U+0428 CYRILLIC CAPITAL LETTER SHA */, + Cyrillic_E = 0x06fc /* U+042D CYRILLIC CAPITAL LETTER E */, + Cyrillic_SHCHA = 0x06fd /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */, + Cyrillic_CHE = 0x06fe /* U+0427 CYRILLIC CAPITAL LETTER CHE */, + Cyrillic_HARDSIGN = 0x06ff /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */, + Greek_ALPHAaccent = 0x07a1 /* U+0386 GREEK CAPITAL LETTER ALPHA WITH TONOS */, + Greek_EPSILONaccent = 0x07a2 /* U+0388 GREEK CAPITAL LETTER EPSILON WITH TONOS */, + Greek_ETAaccent = 0x07a3 /* U+0389 GREEK CAPITAL LETTER ETA WITH TONOS */, + Greek_IOTAaccent = 0x07a4 /* U+038A GREEK CAPITAL LETTER IOTA WITH TONOS */, + Greek_IOTAdieresis = 0x07a5 /* U+03AA GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */, + Greek_IOTAdiaeresis = 0x07a5 /* old typo */, + Greek_OMICRONaccent = 0x07a7 /* U+038C GREEK CAPITAL LETTER OMICRON WITH TONOS */, + Greek_UPSILONaccent = 0x07a8 /* U+038E GREEK CAPITAL LETTER UPSILON WITH TONOS */, + Greek_UPSILONdieresis = 0x07a9 /* U+03AB GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */, + Greek_OMEGAaccent = 0x07ab /* U+038F GREEK CAPITAL LETTER OMEGA WITH TONOS */, + Greek_accentdieresis = 0x07ae /* U+0385 GREEK DIALYTIKA TONOS */, + Greek_horizbar = 0x07af /* U+2015 HORIZONTAL BAR */, + Greek_alphaaccent = 0x07b1 /* U+03AC GREEK SMALL LETTER ALPHA WITH TONOS */, + Greek_epsilonaccent = 0x07b2 /* U+03AD GREEK SMALL LETTER EPSILON WITH TONOS */, + Greek_etaaccent = 0x07b3 /* U+03AE GREEK SMALL LETTER ETA WITH TONOS */, + Greek_iotaaccent = 0x07b4 /* U+03AF GREEK SMALL LETTER IOTA WITH TONOS */, + Greek_iotadieresis = 0x07b5 /* U+03CA GREEK SMALL LETTER IOTA WITH DIALYTIKA */, + Greek_iotaaccentdieresis = 0x07b6 /* U+0390 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */, + Greek_omicronaccent = 0x07b7 /* U+03CC GREEK SMALL LETTER OMICRON WITH TONOS */, + Greek_upsilonaccent = 0x07b8 /* U+03CD GREEK SMALL LETTER UPSILON WITH TONOS */, + Greek_upsilondieresis = 0x07b9 /* U+03CB GREEK SMALL LETTER UPSILON WITH DIALYTIKA */, + Greek_upsilonaccentdieresis = 0x07ba /* U+03B0 GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */, + Greek_omegaaccent = 0x07bb /* U+03CE GREEK SMALL LETTER OMEGA WITH TONOS */, + Greek_ALPHA = 0x07c1 /* U+0391 GREEK CAPITAL LETTER ALPHA */, + Greek_BETA = 0x07c2 /* U+0392 GREEK CAPITAL LETTER BETA */, + Greek_GAMMA = 0x07c3 /* U+0393 GREEK CAPITAL LETTER GAMMA */, + Greek_DELTA = 0x07c4 /* U+0394 GREEK CAPITAL LETTER DELTA */, + Greek_EPSILON = 0x07c5 /* U+0395 GREEK CAPITAL LETTER EPSILON */, + Greek_ZETA = 0x07c6 /* U+0396 GREEK CAPITAL LETTER ZETA */, + Greek_ETA = 0x07c7 /* U+0397 GREEK CAPITAL LETTER ETA */, + Greek_THETA = 0x07c8 /* U+0398 GREEK CAPITAL LETTER THETA */, + Greek_IOTA = 0x07c9 /* U+0399 GREEK CAPITAL LETTER IOTA */, + Greek_KAPPA = 0x07ca /* U+039A GREEK CAPITAL LETTER KAPPA */, + Greek_LAMDA = 0x07cb /* U+039B GREEK CAPITAL LETTER LAMDA */, + Greek_LAMBDA = 0x07cb /* U+039B GREEK CAPITAL LETTER LAMDA */, + Greek_MU = 0x07cc /* U+039C GREEK CAPITAL LETTER MU */, + Greek_NU = 0x07cd /* U+039D GREEK CAPITAL LETTER NU */, + Greek_XI = 0x07ce /* U+039E GREEK CAPITAL LETTER XI */, + Greek_OMICRON = 0x07cf /* U+039F GREEK CAPITAL LETTER OMICRON */, + Greek_PI = 0x07d0 /* U+03A0 GREEK CAPITAL LETTER PI */, + Greek_RHO = 0x07d1 /* U+03A1 GREEK CAPITAL LETTER RHO */, + Greek_SIGMA = 0x07d2 /* U+03A3 GREEK CAPITAL LETTER SIGMA */, + Greek_TAU = 0x07d4 /* U+03A4 GREEK CAPITAL LETTER TAU */, + Greek_UPSILON = 0x07d5 /* U+03A5 GREEK CAPITAL LETTER UPSILON */, + Greek_PHI = 0x07d6 /* U+03A6 GREEK CAPITAL LETTER PHI */, + Greek_CHI = 0x07d7 /* U+03A7 GREEK CAPITAL LETTER CHI */, + Greek_PSI = 0x07d8 /* U+03A8 GREEK CAPITAL LETTER PSI */, + Greek_OMEGA = 0x07d9 /* U+03A9 GREEK CAPITAL LETTER OMEGA */, + Greek_alpha = 0x07e1 /* U+03B1 GREEK SMALL LETTER ALPHA */, + Greek_beta = 0x07e2 /* U+03B2 GREEK SMALL LETTER BETA */, + Greek_gamma = 0x07e3 /* U+03B3 GREEK SMALL LETTER GAMMA */, + Greek_delta = 0x07e4 /* U+03B4 GREEK SMALL LETTER DELTA */, + Greek_epsilon = 0x07e5 /* U+03B5 GREEK SMALL LETTER EPSILON */, + Greek_zeta = 0x07e6 /* U+03B6 GREEK SMALL LETTER ZETA */, + Greek_eta = 0x07e7 /* U+03B7 GREEK SMALL LETTER ETA */, + Greek_theta = 0x07e8 /* U+03B8 GREEK SMALL LETTER THETA */, + Greek_iota = 0x07e9 /* U+03B9 GREEK SMALL LETTER IOTA */, + Greek_kappa = 0x07ea /* U+03BA GREEK SMALL LETTER KAPPA */, + Greek_lamda = 0x07eb /* U+03BB GREEK SMALL LETTER LAMDA */, + Greek_lambda = 0x07eb /* U+03BB GREEK SMALL LETTER LAMDA */, + Greek_mu = 0x07ec /* U+03BC GREEK SMALL LETTER MU */, + Greek_nu = 0x07ed /* U+03BD GREEK SMALL LETTER NU */, + Greek_xi = 0x07ee /* U+03BE GREEK SMALL LETTER XI */, + Greek_omicron = 0x07ef /* U+03BF GREEK SMALL LETTER OMICRON */, + Greek_pi = 0x07f0 /* U+03C0 GREEK SMALL LETTER PI */, + Greek_rho = 0x07f1 /* U+03C1 GREEK SMALL LETTER RHO */, + Greek_sigma = 0x07f2 /* U+03C3 GREEK SMALL LETTER SIGMA */, + Greek_finalsmallsigma = 0x07f3 /* U+03C2 GREEK SMALL LETTER FINAL SIGMA */, + Greek_tau = 0x07f4 /* U+03C4 GREEK SMALL LETTER TAU */, + Greek_upsilon = 0x07f5 /* U+03C5 GREEK SMALL LETTER UPSILON */, + Greek_phi = 0x07f6 /* U+03C6 GREEK SMALL LETTER PHI */, + Greek_chi = 0x07f7 /* U+03C7 GREEK SMALL LETTER CHI */, + Greek_psi = 0x07f8 /* U+03C8 GREEK SMALL LETTER PSI */, + Greek_omega = 0x07f9 /* U+03C9 GREEK SMALL LETTER OMEGA */, + Greek_switch = 0xff7e /* Alias for mode_switch */, + leftradical = 0x08a1 /* U+23B7 RADICAL SYMBOL BOTTOM */, + topleftradical = 0x08a2 /*(U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT)*/, + horizconnector = 0x08a3 /*(U+2500 BOX DRAWINGS LIGHT HORIZONTAL)*/, + topintegral = 0x08a4 /* U+2320 TOP HALF INTEGRAL */, + botintegral = 0x08a5 /* U+2321 BOTTOM HALF INTEGRAL */, + vertconnector = 0x08a6 /*(U+2502 BOX DRAWINGS LIGHT VERTICAL)*/, + topleftsqbracket = 0x08a7 /* U+23A1 LEFT SQUARE BRACKET UPPER CORNER */, + botleftsqbracket = 0x08a8 /* U+23A3 LEFT SQUARE BRACKET LOWER CORNER */, + toprightsqbracket = 0x08a9 /* U+23A4 RIGHT SQUARE BRACKET UPPER CORNER */, + botrightsqbracket = 0x08aa /* U+23A6 RIGHT SQUARE BRACKET LOWER CORNER */, + topleftparens = 0x08ab /* U+239B LEFT PARENTHESIS UPPER HOOK */, + botleftparens = 0x08ac /* U+239D LEFT PARENTHESIS LOWER HOOK */, + toprightparens = 0x08ad /* U+239E RIGHT PARENTHESIS UPPER HOOK */, + botrightparens = 0x08ae /* U+23A0 RIGHT PARENTHESIS LOWER HOOK */, + leftmiddlecurlybrace = 0x08af /* U+23A8 LEFT CURLY BRACKET MIDDLE PIECE */, + rightmiddlecurlybrace = 0x08b0 /* U+23AC RIGHT CURLY BRACKET MIDDLE PIECE */, + topleftsummation = 0x08b1, + botleftsummation = 0x08b2, + topvertsummationconnector = 0x08b3, + botvertsummationconnector = 0x08b4, + toprightsummation = 0x08b5, + botrightsummation = 0x08b6, + rightmiddlesummation = 0x08b7, + lessthanequal = 0x08bc /* U+2264 LESS-THAN OR EQUAL TO */, + notequal = 0x08bd /* U+2260 NOT EQUAL TO */, + greaterthanequal = 0x08be /* U+2265 GREATER-THAN OR EQUAL TO */, + integral = 0x08bf /* U+222B INTEGRAL */, + therefore = 0x08c0 /* U+2234 THEREFORE */, + variation = 0x08c1 /* U+221D PROPORTIONAL TO */, + infinity = 0x08c2 /* U+221E INFINITY */, + nabla = 0x08c5 /* U+2207 NABLA */, + approximate = 0x08c8 /* U+223C TILDE OPERATOR */, + similarequal = 0x08c9 /* U+2243 ASYMPTOTICALLY EQUAL TO */, + ifonlyif = 0x08cd /* U+21D4 LEFT RIGHT DOUBLE ARROW */, + implies = 0x08ce /* U+21D2 RIGHTWARDS DOUBLE ARROW */, + identical = 0x08cf /* U+2261 IDENTICAL TO */, + radical = 0x08d6 /* U+221A SQUARE ROOT */, + includedin = 0x08da /* U+2282 SUBSET OF */, + includes = 0x08db /* U+2283 SUPERSET OF */, + intersection = 0x08dc /* U+2229 INTERSECTION */, + union = 0x08dd /* U+222A UNION */, + logicaland = 0x08de /* U+2227 LOGICAL AND */, + logicalor = 0x08df /* U+2228 LOGICAL OR */, + partialderivative = 0x08ef /* U+2202 PARTIAL DIFFERENTIAL */, + function = 0x08f6 /* U+0192 LATIN SMALL LETTER F WITH HOOK */, + leftarrow = 0x08fb /* U+2190 LEFTWARDS ARROW */, + uparrow = 0x08fc /* U+2191 UPWARDS ARROW */, + rightarrow = 0x08fd /* U+2192 RIGHTWARDS ARROW */, + downarrow = 0x08fe /* U+2193 DOWNWARDS ARROW */, + blank = 0x09df, + soliddiamond = 0x09e0 /* U+25C6 BLACK DIAMOND */, + checkerboard = 0x09e1 /* U+2592 MEDIUM SHADE */, + ht = 0x09e2 /* U+2409 SYMBOL FOR HORIZONTAL TABULATION */, + ff = 0x09e3 /* U+240C SYMBOL FOR FORM FEED */, + cr = 0x09e4 /* U+240D SYMBOL FOR CARRIAGE RETURN */, + lf = 0x09e5 /* U+240A SYMBOL FOR LINE FEED */, + nl = 0x09e8 /* U+2424 SYMBOL FOR NEWLINE */, + vt = 0x09e9 /* U+240B SYMBOL FOR VERTICAL TABULATION */, + lowrightcorner = 0x09ea /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT */, + uprightcorner = 0x09eb /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT */, + upleftcorner = 0x09ec /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT */, + lowleftcorner = 0x09ed /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT */, + crossinglines = 0x09ee /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */, + horizlinescan1 = 0x09ef /* U+23BA HORIZONTAL SCAN LINE-1 */, + horizlinescan3 = 0x09f0 /* U+23BB HORIZONTAL SCAN LINE-3 */, + horizlinescan5 = 0x09f1 /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL */, + horizlinescan7 = 0x09f2 /* U+23BC HORIZONTAL SCAN LINE-7 */, + horizlinescan9 = 0x09f3 /* U+23BD HORIZONTAL SCAN LINE-9 */, + leftt = 0x09f4 /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */, + rightt = 0x09f5 /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT */, + bott = 0x09f6 /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL */, + topt = 0x09f7 /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */, + vertbar = 0x09f8 /* U+2502 BOX DRAWINGS LIGHT VERTICAL */, + emspace = 0x0aa1 /* U+2003 EM SPACE */, + enspace = 0x0aa2 /* U+2002 EN SPACE */, + em3space = 0x0aa3 /* U+2004 THREE-PER-EM SPACE */, + em4space = 0x0aa4 /* U+2005 FOUR-PER-EM SPACE */, + digitspace = 0x0aa5 /* U+2007 FIGURE SPACE */, + punctspace = 0x0aa6 /* U+2008 PUNCTUATION SPACE */, + thinspace = 0x0aa7 /* U+2009 THIN SPACE */, + hairspace = 0x0aa8 /* U+200A HAIR SPACE */, + emdash = 0x0aa9 /* U+2014 EM DASH */, + endash = 0x0aaa /* U+2013 EN DASH */, + signifblank = 0x0aac /*(U+2423 OPEN BOX)*/, + ellipsis = 0x0aae /* U+2026 HORIZONTAL ELLIPSIS */, + doubbaselinedot = 0x0aaf /* U+2025 TWO DOT LEADER */, + onethird = 0x0ab0 /* U+2153 VULGAR FRACTION ONE THIRD */, + twothirds = 0x0ab1 /* U+2154 VULGAR FRACTION TWO THIRDS */, + onefifth = 0x0ab2 /* U+2155 VULGAR FRACTION ONE FIFTH */, + twofifths = 0x0ab3 /* U+2156 VULGAR FRACTION TWO FIFTHS */, + threefifths = 0x0ab4 /* U+2157 VULGAR FRACTION THREE FIFTHS */, + fourfifths = 0x0ab5 /* U+2158 VULGAR FRACTION FOUR FIFTHS */, + onesixth = 0x0ab6 /* U+2159 VULGAR FRACTION ONE SIXTH */, + fivesixths = 0x0ab7 /* U+215A VULGAR FRACTION FIVE SIXTHS */, + careof = 0x0ab8 /* U+2105 CARE OF */, + figdash = 0x0abb /* U+2012 FIGURE DASH */, + leftanglebracket = 0x0abc /*(U+27E8 MATHEMATICAL LEFT ANGLE BRACKET)*/, + decimalpoint = 0x0abd /*(U+002E FULL STOP)*/, + rightanglebracket = 0x0abe /*(U+27E9 MATHEMATICAL RIGHT ANGLE BRACKET)*/, + marker = 0x0abf, + oneeighth = 0x0ac3 /* U+215B VULGAR FRACTION ONE EIGHTH */, + threeeighths = 0x0ac4 /* U+215C VULGAR FRACTION THREE EIGHTHS */, + fiveeighths = 0x0ac5 /* U+215D VULGAR FRACTION FIVE EIGHTHS */, + seveneighths = 0x0ac6 /* U+215E VULGAR FRACTION SEVEN EIGHTHS */, + trademark = 0x0ac9 /* U+2122 TRADE MARK SIGN */, + signaturemark = 0x0aca /*(U+2613 SALTIRE)*/, + trademarkincircle = 0x0acb, + leftopentriangle = 0x0acc /*(U+25C1 WHITE LEFT-POINTING TRIANGLE)*/, + rightopentriangle = 0x0acd /*(U+25B7 WHITE RIGHT-POINTING TRIANGLE)*/, + emopencircle = 0x0ace /*(U+25CB WHITE CIRCLE)*/, + emopenrectangle = 0x0acf /*(U+25AF WHITE VERTICAL RECTANGLE)*/, + leftsinglequotemark = 0x0ad0 /* U+2018 LEFT SINGLE QUOTATION MARK */, + rightsinglequotemark = 0x0ad1 /* U+2019 RIGHT SINGLE QUOTATION MARK */, + leftdoublequotemark = 0x0ad2 /* U+201C LEFT DOUBLE QUOTATION MARK */, + rightdoublequotemark = 0x0ad3 /* U+201D RIGHT DOUBLE QUOTATION MARK */, + prescription = 0x0ad4 /* U+211E PRESCRIPTION TAKE */, + permille = 0x0ad5 /* U+2030 PER MILLE SIGN */, + minutes = 0x0ad6 /* U+2032 PRIME */, + seconds = 0x0ad7 /* U+2033 DOUBLE PRIME */, + latincross = 0x0ad9 /* U+271D LATIN CROSS */, + hexagram = 0x0ada, + filledrectbullet = 0x0adb /*(U+25AC BLACK RECTANGLE)*/, + filledlefttribullet = 0x0adc /*(U+25C0 BLACK LEFT-POINTING TRIANGLE)*/, + filledrighttribullet = 0x0add /*(U+25B6 BLACK RIGHT-POINTING TRIANGLE)*/, + emfilledcircle = 0x0ade /*(U+25CF BLACK CIRCLE)*/, + emfilledrect = 0x0adf /*(U+25AE BLACK VERTICAL RECTANGLE)*/, + enopencircbullet = 0x0ae0 /*(U+25E6 WHITE BULLET)*/, + enopensquarebullet = 0x0ae1 /*(U+25AB WHITE SMALL SQUARE)*/, + openrectbullet = 0x0ae2 /*(U+25AD WHITE RECTANGLE)*/, + opentribulletup = 0x0ae3 /*(U+25B3 WHITE UP-POINTING TRIANGLE)*/, + opentribulletdown = 0x0ae4 /*(U+25BD WHITE DOWN-POINTING TRIANGLE)*/, + openstar = 0x0ae5 /*(U+2606 WHITE STAR)*/, + enfilledcircbullet = 0x0ae6 /*(U+2022 BULLET)*/, + enfilledsqbullet = 0x0ae7 /*(U+25AA BLACK SMALL SQUARE)*/, + filledtribulletup = 0x0ae8 /*(U+25B2 BLACK UP-POINTING TRIANGLE)*/, + filledtribulletdown = 0x0ae9 /*(U+25BC BLACK DOWN-POINTING TRIANGLE)*/, + leftpointer = 0x0aea /*(U+261C WHITE LEFT POINTING INDEX)*/, + rightpointer = 0x0aeb /*(U+261E WHITE RIGHT POINTING INDEX)*/, + club = 0x0aec /* U+2663 BLACK CLUB SUIT */, + diamond = 0x0aed /* U+2666 BLACK DIAMOND SUIT */, + heart = 0x0aee /* U+2665 BLACK HEART SUIT */, + maltesecross = 0x0af0 /* U+2720 MALTESE CROSS */, + dagger = 0x0af1 /* U+2020 DAGGER */, + doubledagger = 0x0af2 /* U+2021 DOUBLE DAGGER */, + checkmark = 0x0af3 /* U+2713 CHECK MARK */, + ballotcross = 0x0af4 /* U+2717 BALLOT X */, + musicalsharp = 0x0af5 /* U+266F MUSIC SHARP SIGN */, + musicalflat = 0x0af6 /* U+266D MUSIC FLAT SIGN */, + malesymbol = 0x0af7 /* U+2642 MALE SIGN */, + femalesymbol = 0x0af8 /* U+2640 FEMALE SIGN */, + telephone = 0x0af9 /* U+260E BLACK TELEPHONE */, + telephonerecorder = 0x0afa /* U+2315 TELEPHONE RECORDER */, + phonographcopyright = 0x0afb /* U+2117 SOUND RECORDING COPYRIGHT */, + caret = 0x0afc /* U+2038 CARET */, + singlelowquotemark = 0x0afd /* U+201A SINGLE LOW-9 QUOTATION MARK */, + doublelowquotemark = 0x0afe /* U+201E DOUBLE LOW-9 QUOTATION MARK */, + cursor = 0x0aff, + leftcaret = 0x0ba3 /*(U+003C LESS-THAN SIGN)*/, + rightcaret = 0x0ba6 /*(U+003E GREATER-THAN SIGN)*/, + downcaret = 0x0ba8 /*(U+2228 LOGICAL OR)*/, + upcaret = 0x0ba9 /*(U+2227 LOGICAL AND)*/, + overbar = 0x0bc0 /*(U+00AF MACRON)*/, + downtack = 0x0bc2 /* U+22A4 DOWN TACK */, + upshoe = 0x0bc3 /*(U+2229 INTERSECTION)*/, + downstile = 0x0bc4 /* U+230A LEFT FLOOR */, + underbar = 0x0bc6 /*(U+005F LOW LINE)*/, + jot = 0x0bca /* U+2218 RING OPERATOR */, + quad = 0x0bcc /* U+2395 APL FUNCTIONAL SYMBOL QUAD */, + uptack = 0x0bce /* U+22A5 UP TACK */, + circle = 0x0bcf /* U+25CB WHITE CIRCLE */, + upstile = 0x0bd3 /* U+2308 LEFT CEILING */, + downshoe = 0x0bd6 /*(U+222A UNION)*/, + rightshoe = 0x0bd8 /*(U+2283 SUPERSET OF)*/, + leftshoe = 0x0bda /*(U+2282 SUBSET OF)*/, + lefttack = 0x0bdc /* U+22A3 LEFT TACK */, + righttack = 0x0bfc /* U+22A2 RIGHT TACK */, + hebrew_doublelowline = 0x0cdf /* U+2017 DOUBLE LOW LINE */, + hebrew_aleph = 0x0ce0 /* U+05D0 HEBREW LETTER ALEF */, + hebrew_bet = 0x0ce1 /* U+05D1 HEBREW LETTER BET */, + hebrew_beth = 0x0ce1 /* deprecated */, + hebrew_gimel = 0x0ce2 /* U+05D2 HEBREW LETTER GIMEL */, + hebrew_gimmel = 0x0ce2 /* deprecated */, + hebrew_dalet = 0x0ce3 /* U+05D3 HEBREW LETTER DALET */, + hebrew_daleth = 0x0ce3 /* deprecated */, + hebrew_he = 0x0ce4 /* U+05D4 HEBREW LETTER HE */, + hebrew_waw = 0x0ce5 /* U+05D5 HEBREW LETTER VAV */, + hebrew_zain = 0x0ce6 /* U+05D6 HEBREW LETTER ZAYIN */, + hebrew_zayin = 0x0ce6 /* deprecated */, + hebrew_chet = 0x0ce7 /* U+05D7 HEBREW LETTER HET */, + hebrew_het = 0x0ce7 /* deprecated */, + hebrew_tet = 0x0ce8 /* U+05D8 HEBREW LETTER TET */, + hebrew_teth = 0x0ce8 /* deprecated */, + hebrew_yod = 0x0ce9 /* U+05D9 HEBREW LETTER YOD */, + hebrew_finalkaph = 0x0cea /* U+05DA HEBREW LETTER FINAL KAF */, + hebrew_kaph = 0x0ceb /* U+05DB HEBREW LETTER KAF */, + hebrew_lamed = 0x0cec /* U+05DC HEBREW LETTER LAMED */, + hebrew_finalmem = 0x0ced /* U+05DD HEBREW LETTER FINAL MEM */, + hebrew_mem = 0x0cee /* U+05DE HEBREW LETTER MEM */, + hebrew_finalnun = 0x0cef /* U+05DF HEBREW LETTER FINAL NUN */, + hebrew_nun = 0x0cf0 /* U+05E0 HEBREW LETTER NUN */, + hebrew_samech = 0x0cf1 /* U+05E1 HEBREW LETTER SAMEKH */, + hebrew_samekh = 0x0cf1 /* deprecated */, + hebrew_ayin = 0x0cf2 /* U+05E2 HEBREW LETTER AYIN */, + hebrew_finalpe = 0x0cf3 /* U+05E3 HEBREW LETTER FINAL PE */, + hebrew_pe = 0x0cf4 /* U+05E4 HEBREW LETTER PE */, + hebrew_finalzade = 0x0cf5 /* U+05E5 HEBREW LETTER FINAL TSADI */, + hebrew_finalzadi = 0x0cf5 /* deprecated */, + hebrew_zade = 0x0cf6 /* U+05E6 HEBREW LETTER TSADI */, + hebrew_zadi = 0x0cf6 /* deprecated */, + hebrew_qoph = 0x0cf7 /* U+05E7 HEBREW LETTER QOF */, + hebrew_kuf = 0x0cf7 /* deprecated */, + hebrew_resh = 0x0cf8 /* U+05E8 HEBREW LETTER RESH */, + hebrew_shin = 0x0cf9 /* U+05E9 HEBREW LETTER SHIN */, + hebrew_taw = 0x0cfa /* U+05EA HEBREW LETTER TAV */, + hebrew_taf = 0x0cfa /* deprecated */, + Hebrew_switch = 0xff7e /* Alias for mode_switch */, + Thai_kokai = 0x0da1 /* U+0E01 THAI CHARACTER KO KAI */, + Thai_khokhai = 0x0da2 /* U+0E02 THAI CHARACTER KHO KHAI */, + Thai_khokhuat = 0x0da3 /* U+0E03 THAI CHARACTER KHO KHUAT */, + Thai_khokhwai = 0x0da4 /* U+0E04 THAI CHARACTER KHO KHWAI */, + Thai_khokhon = 0x0da5 /* U+0E05 THAI CHARACTER KHO KHON */, + Thai_khorakhang = 0x0da6 /* U+0E06 THAI CHARACTER KHO RAKHANG */, + Thai_ngongu = 0x0da7 /* U+0E07 THAI CHARACTER NGO NGU */, + Thai_chochan = 0x0da8 /* U+0E08 THAI CHARACTER CHO CHAN */, + Thai_choching = 0x0da9 /* U+0E09 THAI CHARACTER CHO CHING */, + Thai_chochang = 0x0daa /* U+0E0A THAI CHARACTER CHO CHANG */, + Thai_soso = 0x0dab /* U+0E0B THAI CHARACTER SO SO */, + Thai_chochoe = 0x0dac /* U+0E0C THAI CHARACTER CHO CHOE */, + Thai_yoying = 0x0dad /* U+0E0D THAI CHARACTER YO YING */, + Thai_dochada = 0x0dae /* U+0E0E THAI CHARACTER DO CHADA */, + Thai_topatak = 0x0daf /* U+0E0F THAI CHARACTER TO PATAK */, + Thai_thothan = 0x0db0 /* U+0E10 THAI CHARACTER THO THAN */, + Thai_thonangmontho = 0x0db1 /* U+0E11 THAI CHARACTER THO NANGMONTHO */, + Thai_thophuthao = 0x0db2 /* U+0E12 THAI CHARACTER THO PHUTHAO */, + Thai_nonen = 0x0db3 /* U+0E13 THAI CHARACTER NO NEN */, + Thai_dodek = 0x0db4 /* U+0E14 THAI CHARACTER DO DEK */, + Thai_totao = 0x0db5 /* U+0E15 THAI CHARACTER TO TAO */, + Thai_thothung = 0x0db6 /* U+0E16 THAI CHARACTER THO THUNG */, + Thai_thothahan = 0x0db7 /* U+0E17 THAI CHARACTER THO THAHAN */, + Thai_thothong = 0x0db8 /* U+0E18 THAI CHARACTER THO THONG */, + Thai_nonu = 0x0db9 /* U+0E19 THAI CHARACTER NO NU */, + Thai_bobaimai = 0x0dba /* U+0E1A THAI CHARACTER BO BAIMAI */, + Thai_popla = 0x0dbb /* U+0E1B THAI CHARACTER PO PLA */, + Thai_phophung = 0x0dbc /* U+0E1C THAI CHARACTER PHO PHUNG */, + Thai_fofa = 0x0dbd /* U+0E1D THAI CHARACTER FO FA */, + Thai_phophan = 0x0dbe /* U+0E1E THAI CHARACTER PHO PHAN */, + Thai_fofan = 0x0dbf /* U+0E1F THAI CHARACTER FO FAN */, + Thai_phosamphao = 0x0dc0 /* U+0E20 THAI CHARACTER PHO SAMPHAO */, + Thai_moma = 0x0dc1 /* U+0E21 THAI CHARACTER MO MA */, + Thai_yoyak = 0x0dc2 /* U+0E22 THAI CHARACTER YO YAK */, + Thai_rorua = 0x0dc3 /* U+0E23 THAI CHARACTER RO RUA */, + Thai_ru = 0x0dc4 /* U+0E24 THAI CHARACTER RU */, + Thai_loling = 0x0dc5 /* U+0E25 THAI CHARACTER LO LING */, + Thai_lu = 0x0dc6 /* U+0E26 THAI CHARACTER LU */, + Thai_wowaen = 0x0dc7 /* U+0E27 THAI CHARACTER WO WAEN */, + Thai_sosala = 0x0dc8 /* U+0E28 THAI CHARACTER SO SALA */, + Thai_sorusi = 0x0dc9 /* U+0E29 THAI CHARACTER SO RUSI */, + Thai_sosua = 0x0dca /* U+0E2A THAI CHARACTER SO SUA */, + Thai_hohip = 0x0dcb /* U+0E2B THAI CHARACTER HO HIP */, + Thai_lochula = 0x0dcc /* U+0E2C THAI CHARACTER LO CHULA */, + Thai_oang = 0x0dcd /* U+0E2D THAI CHARACTER O ANG */, + Thai_honokhuk = 0x0dce /* U+0E2E THAI CHARACTER HO NOKHUK */, + Thai_paiyannoi = 0x0dcf /* U+0E2F THAI CHARACTER PAIYANNOI */, + Thai_saraa = 0x0dd0 /* U+0E30 THAI CHARACTER SARA A */, + Thai_maihanakat = 0x0dd1 /* U+0E31 THAI CHARACTER MAI HAN-AKAT */, + Thai_saraaa = 0x0dd2 /* U+0E32 THAI CHARACTER SARA AA */, + Thai_saraam = 0x0dd3 /* U+0E33 THAI CHARACTER SARA AM */, + Thai_sarai = 0x0dd4 /* U+0E34 THAI CHARACTER SARA I */, + Thai_saraii = 0x0dd5 /* U+0E35 THAI CHARACTER SARA II */, + Thai_saraue = 0x0dd6 /* U+0E36 THAI CHARACTER SARA UE */, + Thai_sarauee = 0x0dd7 /* U+0E37 THAI CHARACTER SARA UEE */, + Thai_sarau = 0x0dd8 /* U+0E38 THAI CHARACTER SARA U */, + Thai_sarauu = 0x0dd9 /* U+0E39 THAI CHARACTER SARA UU */, + Thai_phinthu = 0x0dda /* U+0E3A THAI CHARACTER PHINTHU */, + Thai_maihanakat_maitho = 0x0dde, + Thai_baht = 0x0ddf /* U+0E3F THAI CURRENCY SYMBOL BAHT */, + Thai_sarae = 0x0de0 /* U+0E40 THAI CHARACTER SARA E */, + Thai_saraae = 0x0de1 /* U+0E41 THAI CHARACTER SARA AE */, + Thai_sarao = 0x0de2 /* U+0E42 THAI CHARACTER SARA O */, + Thai_saraaimaimuan = 0x0de3 /* U+0E43 THAI CHARACTER SARA AI MAIMUAN */, + Thai_saraaimaimalai = 0x0de4 /* U+0E44 THAI CHARACTER SARA AI MAIMALAI */, + Thai_lakkhangyao = 0x0de5 /* U+0E45 THAI CHARACTER LAKKHANGYAO */, + Thai_maiyamok = 0x0de6 /* U+0E46 THAI CHARACTER MAIYAMOK */, + Thai_maitaikhu = 0x0de7 /* U+0E47 THAI CHARACTER MAITAIKHU */, + Thai_maiek = 0x0de8 /* U+0E48 THAI CHARACTER MAI EK */, + Thai_maitho = 0x0de9 /* U+0E49 THAI CHARACTER MAI THO */, + Thai_maitri = 0x0dea /* U+0E4A THAI CHARACTER MAI TRI */, + Thai_maichattawa = 0x0deb /* U+0E4B THAI CHARACTER MAI CHATTAWA */, + Thai_thanthakhat = 0x0dec /* U+0E4C THAI CHARACTER THANTHAKHAT */, + Thai_nikhahit = 0x0ded /* U+0E4D THAI CHARACTER NIKHAHIT */, + Thai_leksun = 0x0df0 /* U+0E50 THAI DIGIT ZERO */, + Thai_leknung = 0x0df1 /* U+0E51 THAI DIGIT ONE */, + Thai_leksong = 0x0df2 /* U+0E52 THAI DIGIT TWO */, + Thai_leksam = 0x0df3 /* U+0E53 THAI DIGIT THREE */, + Thai_leksi = 0x0df4 /* U+0E54 THAI DIGIT FOUR */, + Thai_lekha = 0x0df5 /* U+0E55 THAI DIGIT FIVE */, + Thai_lekhok = 0x0df6 /* U+0E56 THAI DIGIT SIX */, + Thai_lekchet = 0x0df7 /* U+0E57 THAI DIGIT SEVEN */, + Thai_lekpaet = 0x0df8 /* U+0E58 THAI DIGIT EIGHT */, + Thai_lekkao = 0x0df9 /* U+0E59 THAI DIGIT NINE */, + Hangul = 0xff31 /* Hangul start/stop(toggle) */, + Hangul_Start = 0xff32 /* Hangul start */, + Hangul_End = 0xff33 /* Hangul end, English start */, + Hangul_Hanja = 0xff34 /* Start Hangul->Hanja Conversion */, + Hangul_Jamo = 0xff35 /* Hangul Jamo mode */, + Hangul_Romaja = 0xff36 /* Hangul Romaja mode */, + Hangul_Codeinput = 0xff37 /* Hangul code input mode */, + Hangul_Jeonja = 0xff38 /* Jeonja mode */, + Hangul_Banja = 0xff39 /* Banja mode */, + Hangul_PreHanja = 0xff3a /* Pre Hanja conversion */, + Hangul_PostHanja = 0xff3b /* Post Hanja conversion */, + Hangul_SingleCandidate = 0xff3c /* Single candidate */, + Hangul_MultipleCandidate = 0xff3d /* Multiple candidate */, + Hangul_PreviousCandidate = 0xff3e /* Previous candidate */, + Hangul_Special = 0xff3f /* Special symbols */, + Hangul_switch = 0xff7e /* Alias for mode_switch */, + Hangul_Kiyeog = 0x0ea1, + Hangul_SsangKiyeog = 0x0ea2, + Hangul_KiyeogSios = 0x0ea3, + Hangul_Nieun = 0x0ea4, + Hangul_NieunJieuj = 0x0ea5, + Hangul_NieunHieuh = 0x0ea6, + Hangul_Dikeud = 0x0ea7, + Hangul_SsangDikeud = 0x0ea8, + Hangul_Rieul = 0x0ea9, + Hangul_RieulKiyeog = 0x0eaa, + Hangul_RieulMieum = 0x0eab, + Hangul_RieulPieub = 0x0eac, + Hangul_RieulSios = 0x0ead, + Hangul_RieulTieut = 0x0eae, + Hangul_RieulPhieuf = 0x0eaf, + Hangul_RieulHieuh = 0x0eb0, + Hangul_Mieum = 0x0eb1, + Hangul_Pieub = 0x0eb2, + Hangul_SsangPieub = 0x0eb3, + Hangul_PieubSios = 0x0eb4, + Hangul_Sios = 0x0eb5, + Hangul_SsangSios = 0x0eb6, + Hangul_Ieung = 0x0eb7, + Hangul_Jieuj = 0x0eb8, + Hangul_SsangJieuj = 0x0eb9, + Hangul_Cieuc = 0x0eba, + Hangul_Khieuq = 0x0ebb, + Hangul_Tieut = 0x0ebc, + Hangul_Phieuf = 0x0ebd, + Hangul_Hieuh = 0x0ebe, + Hangul_A = 0x0ebf, + Hangul_AE = 0x0ec0, + Hangul_YA = 0x0ec1, + Hangul_YAE = 0x0ec2, + Hangul_EO = 0x0ec3, + Hangul_E = 0x0ec4, + Hangul_YEO = 0x0ec5, + Hangul_YE = 0x0ec6, + Hangul_O = 0x0ec7, + Hangul_WA = 0x0ec8, + Hangul_WAE = 0x0ec9, + Hangul_OE = 0x0eca, + Hangul_YO = 0x0ecb, + Hangul_U = 0x0ecc, + Hangul_WEO = 0x0ecd, + Hangul_WE = 0x0ece, + Hangul_WI = 0x0ecf, + Hangul_YU = 0x0ed0, + Hangul_EU = 0x0ed1, + Hangul_YI = 0x0ed2, + Hangul_I = 0x0ed3, + Hangul_J_Kiyeog = 0x0ed4, + Hangul_J_SsangKiyeog = 0x0ed5, + Hangul_J_KiyeogSios = 0x0ed6, + Hangul_J_Nieun = 0x0ed7, + Hangul_J_NieunJieuj = 0x0ed8, + Hangul_J_NieunHieuh = 0x0ed9, + Hangul_J_Dikeud = 0x0eda, + Hangul_J_Rieul = 0x0edb, + Hangul_J_RieulKiyeog = 0x0edc, + Hangul_J_RieulMieum = 0x0edd, + Hangul_J_RieulPieub = 0x0ede, + Hangul_J_RieulSios = 0x0edf, + Hangul_J_RieulTieut = 0x0ee0, + Hangul_J_RieulPhieuf = 0x0ee1, + Hangul_J_RieulHieuh = 0x0ee2, + Hangul_J_Mieum = 0x0ee3, + Hangul_J_Pieub = 0x0ee4, + Hangul_J_PieubSios = 0x0ee5, + Hangul_J_Sios = 0x0ee6, + Hangul_J_SsangSios = 0x0ee7, + Hangul_J_Ieung = 0x0ee8, + Hangul_J_Jieuj = 0x0ee9, + Hangul_J_Cieuc = 0x0eea, + Hangul_J_Khieuq = 0x0eeb, + Hangul_J_Tieut = 0x0eec, + Hangul_J_Phieuf = 0x0eed, + Hangul_J_Hieuh = 0x0eee, + Hangul_RieulYeorinHieuh = 0x0eef, + Hangul_SunkyeongeumMieum = 0x0ef0, + Hangul_SunkyeongeumPieub = 0x0ef1, + Hangul_PanSios = 0x0ef2, + Hangul_KkogjiDalrinIeung = 0x0ef3, + Hangul_SunkyeongeumPhieuf = 0x0ef4, + Hangul_YeorinHieuh = 0x0ef5, + Hangul_AraeA = 0x0ef6, + Hangul_AraeAE = 0x0ef7, + Hangul_J_PanSios = 0x0ef8, + Hangul_J_KkogjiDalrinIeung = 0x0ef9, + Hangul_J_YeorinHieuh = 0x0efa, + Korean_Won = 0x0eff /*(U+20A9 WON SIGN)*/, + Armenian_ligature_ew = 0x1000587 /* U+0587 ARMENIAN SMALL LIGATURE ECH YIWN */, + Armenian_full_stop = 0x1000589 /* U+0589 ARMENIAN FULL STOP */, + Armenian_verjaket = 0x1000589 /* U+0589 ARMENIAN FULL STOP */, + Armenian_separation_mark = 0x100055d /* U+055D ARMENIAN COMMA */, + Armenian_but = 0x100055d /* U+055D ARMENIAN COMMA */, + Armenian_hyphen = 0x100058a /* U+058A ARMENIAN HYPHEN */, + Armenian_yentamna = 0x100058a /* U+058A ARMENIAN HYPHEN */, + Armenian_exclam = 0x100055c /* U+055C ARMENIAN EXCLAMATION MARK */, + Armenian_amanak = 0x100055c /* U+055C ARMENIAN EXCLAMATION MARK */, + Armenian_accent = 0x100055b /* U+055B ARMENIAN EMPHASIS MARK */, + Armenian_shesht = 0x100055b /* U+055B ARMENIAN EMPHASIS MARK */, + Armenian_question = 0x100055e /* U+055E ARMENIAN QUESTION MARK */, + Armenian_paruyk = 0x100055e /* U+055E ARMENIAN QUESTION MARK */, + Armenian_AYB = 0x1000531 /* U+0531 ARMENIAN CAPITAL LETTER AYB */, + Armenian_ayb = 0x1000561 /* U+0561 ARMENIAN SMALL LETTER AYB */, + Armenian_BEN = 0x1000532 /* U+0532 ARMENIAN CAPITAL LETTER BEN */, + Armenian_ben = 0x1000562 /* U+0562 ARMENIAN SMALL LETTER BEN */, + Armenian_GIM = 0x1000533 /* U+0533 ARMENIAN CAPITAL LETTER GIM */, + Armenian_gim = 0x1000563 /* U+0563 ARMENIAN SMALL LETTER GIM */, + Armenian_DA = 0x1000534 /* U+0534 ARMENIAN CAPITAL LETTER DA */, + Armenian_da = 0x1000564 /* U+0564 ARMENIAN SMALL LETTER DA */, + Armenian_YECH = 0x1000535 /* U+0535 ARMENIAN CAPITAL LETTER ECH */, + Armenian_yech = 0x1000565 /* U+0565 ARMENIAN SMALL LETTER ECH */, + Armenian_ZA = 0x1000536 /* U+0536 ARMENIAN CAPITAL LETTER ZA */, + Armenian_za = 0x1000566 /* U+0566 ARMENIAN SMALL LETTER ZA */, + Armenian_E = 0x1000537 /* U+0537 ARMENIAN CAPITAL LETTER EH */, + Armenian_e = 0x1000567 /* U+0567 ARMENIAN SMALL LETTER EH */, + Armenian_AT = 0x1000538 /* U+0538 ARMENIAN CAPITAL LETTER ET */, + Armenian_at = 0x1000568 /* U+0568 ARMENIAN SMALL LETTER ET */, + Armenian_TO = 0x1000539 /* U+0539 ARMENIAN CAPITAL LETTER TO */, + Armenian_to = 0x1000569 /* U+0569 ARMENIAN SMALL LETTER TO */, + Armenian_ZHE = 0x100053a /* U+053A ARMENIAN CAPITAL LETTER ZHE */, + Armenian_zhe = 0x100056a /* U+056A ARMENIAN SMALL LETTER ZHE */, + Armenian_INI = 0x100053b /* U+053B ARMENIAN CAPITAL LETTER INI */, + Armenian_ini = 0x100056b /* U+056B ARMENIAN SMALL LETTER INI */, + Armenian_LYUN = 0x100053c /* U+053C ARMENIAN CAPITAL LETTER LIWN */, + Armenian_lyun = 0x100056c /* U+056C ARMENIAN SMALL LETTER LIWN */, + Armenian_KHE = 0x100053d /* U+053D ARMENIAN CAPITAL LETTER XEH */, + Armenian_khe = 0x100056d /* U+056D ARMENIAN SMALL LETTER XEH */, + Armenian_TSA = 0x100053e /* U+053E ARMENIAN CAPITAL LETTER CA */, + Armenian_tsa = 0x100056e /* U+056E ARMENIAN SMALL LETTER CA */, + Armenian_KEN = 0x100053f /* U+053F ARMENIAN CAPITAL LETTER KEN */, + Armenian_ken = 0x100056f /* U+056F ARMENIAN SMALL LETTER KEN */, + Armenian_HO = 0x1000540 /* U+0540 ARMENIAN CAPITAL LETTER HO */, + Armenian_ho = 0x1000570 /* U+0570 ARMENIAN SMALL LETTER HO */, + Armenian_DZA = 0x1000541 /* U+0541 ARMENIAN CAPITAL LETTER JA */, + Armenian_dza = 0x1000571 /* U+0571 ARMENIAN SMALL LETTER JA */, + Armenian_GHAT = 0x1000542 /* U+0542 ARMENIAN CAPITAL LETTER GHAD */, + Armenian_ghat = 0x1000572 /* U+0572 ARMENIAN SMALL LETTER GHAD */, + Armenian_TCHE = 0x1000543 /* U+0543 ARMENIAN CAPITAL LETTER CHEH */, + Armenian_tche = 0x1000573 /* U+0573 ARMENIAN SMALL LETTER CHEH */, + Armenian_MEN = 0x1000544 /* U+0544 ARMENIAN CAPITAL LETTER MEN */, + Armenian_men = 0x1000574 /* U+0574 ARMENIAN SMALL LETTER MEN */, + Armenian_HI = 0x1000545 /* U+0545 ARMENIAN CAPITAL LETTER YI */, + Armenian_hi = 0x1000575 /* U+0575 ARMENIAN SMALL LETTER YI */, + Armenian_NU = 0x1000546 /* U+0546 ARMENIAN CAPITAL LETTER NOW */, + Armenian_nu = 0x1000576 /* U+0576 ARMENIAN SMALL LETTER NOW */, + Armenian_SHA = 0x1000547 /* U+0547 ARMENIAN CAPITAL LETTER SHA */, + Armenian_sha = 0x1000577 /* U+0577 ARMENIAN SMALL LETTER SHA */, + Armenian_VO = 0x1000548 /* U+0548 ARMENIAN CAPITAL LETTER VO */, + Armenian_vo = 0x1000578 /* U+0578 ARMENIAN SMALL LETTER VO */, + Armenian_CHA = 0x1000549 /* U+0549 ARMENIAN CAPITAL LETTER CHA */, + Armenian_cha = 0x1000579 /* U+0579 ARMENIAN SMALL LETTER CHA */, + Armenian_PE = 0x100054a /* U+054A ARMENIAN CAPITAL LETTER PEH */, + Armenian_pe = 0x100057a /* U+057A ARMENIAN SMALL LETTER PEH */, + Armenian_JE = 0x100054b /* U+054B ARMENIAN CAPITAL LETTER JHEH */, + Armenian_je = 0x100057b /* U+057B ARMENIAN SMALL LETTER JHEH */, + Armenian_RA = 0x100054c /* U+054C ARMENIAN CAPITAL LETTER RA */, + Armenian_ra = 0x100057c /* U+057C ARMENIAN SMALL LETTER RA */, + Armenian_SE = 0x100054d /* U+054D ARMENIAN CAPITAL LETTER SEH */, + Armenian_se = 0x100057d /* U+057D ARMENIAN SMALL LETTER SEH */, + Armenian_VEV = 0x100054e /* U+054E ARMENIAN CAPITAL LETTER VEW */, + Armenian_vev = 0x100057e /* U+057E ARMENIAN SMALL LETTER VEW */, + Armenian_TYUN = 0x100054f /* U+054F ARMENIAN CAPITAL LETTER TIWN */, + Armenian_tyun = 0x100057f /* U+057F ARMENIAN SMALL LETTER TIWN */, + Armenian_RE = 0x1000550 /* U+0550 ARMENIAN CAPITAL LETTER REH */, + Armenian_re = 0x1000580 /* U+0580 ARMENIAN SMALL LETTER REH */, + Armenian_TSO = 0x1000551 /* U+0551 ARMENIAN CAPITAL LETTER CO */, + Armenian_tso = 0x1000581 /* U+0581 ARMENIAN SMALL LETTER CO */, + Armenian_VYUN = 0x1000552 /* U+0552 ARMENIAN CAPITAL LETTER YIWN */, + Armenian_vyun = 0x1000582 /* U+0582 ARMENIAN SMALL LETTER YIWN */, + Armenian_PYUR = 0x1000553 /* U+0553 ARMENIAN CAPITAL LETTER PIWR */, + Armenian_pyur = 0x1000583 /* U+0583 ARMENIAN SMALL LETTER PIWR */, + Armenian_KE = 0x1000554 /* U+0554 ARMENIAN CAPITAL LETTER KEH */, + Armenian_ke = 0x1000584 /* U+0584 ARMENIAN SMALL LETTER KEH */, + Armenian_O = 0x1000555 /* U+0555 ARMENIAN CAPITAL LETTER OH */, + Armenian_o = 0x1000585 /* U+0585 ARMENIAN SMALL LETTER OH */, + Armenian_FE = 0x1000556 /* U+0556 ARMENIAN CAPITAL LETTER FEH */, + Armenian_fe = 0x1000586 /* U+0586 ARMENIAN SMALL LETTER FEH */, + Armenian_apostrophe = 0x100055a /* U+055A ARMENIAN APOSTROPHE */, + Georgian_an = 0x10010d0 /* U+10D0 GEORGIAN LETTER AN */, + Georgian_ban = 0x10010d1 /* U+10D1 GEORGIAN LETTER BAN */, + Georgian_gan = 0x10010d2 /* U+10D2 GEORGIAN LETTER GAN */, + Georgian_don = 0x10010d3 /* U+10D3 GEORGIAN LETTER DON */, + Georgian_en = 0x10010d4 /* U+10D4 GEORGIAN LETTER EN */, + Georgian_vin = 0x10010d5 /* U+10D5 GEORGIAN LETTER VIN */, + Georgian_zen = 0x10010d6 /* U+10D6 GEORGIAN LETTER ZEN */, + Georgian_tan = 0x10010d7 /* U+10D7 GEORGIAN LETTER TAN */, + Georgian_in = 0x10010d8 /* U+10D8 GEORGIAN LETTER IN */, + Georgian_kan = 0x10010d9 /* U+10D9 GEORGIAN LETTER KAN */, + Georgian_las = 0x10010da /* U+10DA GEORGIAN LETTER LAS */, + Georgian_man = 0x10010db /* U+10DB GEORGIAN LETTER MAN */, + Georgian_nar = 0x10010dc /* U+10DC GEORGIAN LETTER NAR */, + Georgian_on = 0x10010dd /* U+10DD GEORGIAN LETTER ON */, + Georgian_par = 0x10010de /* U+10DE GEORGIAN LETTER PAR */, + Georgian_zhar = 0x10010df /* U+10DF GEORGIAN LETTER ZHAR */, + Georgian_rae = 0x10010e0 /* U+10E0 GEORGIAN LETTER RAE */, + Georgian_san = 0x10010e1 /* U+10E1 GEORGIAN LETTER SAN */, + Georgian_tar = 0x10010e2 /* U+10E2 GEORGIAN LETTER TAR */, + Georgian_un = 0x10010e3 /* U+10E3 GEORGIAN LETTER UN */, + Georgian_phar = 0x10010e4 /* U+10E4 GEORGIAN LETTER PHAR */, + Georgian_khar = 0x10010e5 /* U+10E5 GEORGIAN LETTER KHAR */, + Georgian_ghan = 0x10010e6 /* U+10E6 GEORGIAN LETTER GHAN */, + Georgian_qar = 0x10010e7 /* U+10E7 GEORGIAN LETTER QAR */, + Georgian_shin = 0x10010e8 /* U+10E8 GEORGIAN LETTER SHIN */, + Georgian_chin = 0x10010e9 /* U+10E9 GEORGIAN LETTER CHIN */, + Georgian_can = 0x10010ea /* U+10EA GEORGIAN LETTER CAN */, + Georgian_jil = 0x10010eb /* U+10EB GEORGIAN LETTER JIL */, + Georgian_cil = 0x10010ec /* U+10EC GEORGIAN LETTER CIL */, + Georgian_char = 0x10010ed /* U+10ED GEORGIAN LETTER CHAR */, + Georgian_xan = 0x10010ee /* U+10EE GEORGIAN LETTER XAN */, + Georgian_jhan = 0x10010ef /* U+10EF GEORGIAN LETTER JHAN */, + Georgian_hae = 0x10010f0 /* U+10F0 GEORGIAN LETTER HAE */, + Georgian_he = 0x10010f1 /* U+10F1 GEORGIAN LETTER HE */, + Georgian_hie = 0x10010f2 /* U+10F2 GEORGIAN LETTER HIE */, + Georgian_we = 0x10010f3 /* U+10F3 GEORGIAN LETTER WE */, + Georgian_har = 0x10010f4 /* U+10F4 GEORGIAN LETTER HAR */, + Georgian_hoe = 0x10010f5 /* U+10F5 GEORGIAN LETTER HOE */, + Georgian_fi = 0x10010f6 /* U+10F6 GEORGIAN LETTER FI */, + Xabovedot = 0x1001e8a /* U+1E8A LATIN CAPITAL LETTER X WITH DOT ABOVE */, + Ibreve = 0x100012c /* U+012C LATIN CAPITAL LETTER I WITH BREVE */, + Zstroke = 0x10001b5 /* U+01B5 LATIN CAPITAL LETTER Z WITH STROKE */, + Gcaron = 0x10001e6 /* U+01E6 LATIN CAPITAL LETTER G WITH CARON */, + Ocaron = 0x10001d1 /* U+01D2 LATIN CAPITAL LETTER O WITH CARON */, + Obarred = 0x100019f /* U+019F LATIN CAPITAL LETTER O WITH MIDDLE TILDE */, + xabovedot = 0x1001e8b /* U+1E8B LATIN SMALL LETTER X WITH DOT ABOVE */, + ibreve = 0x100012d /* U+012D LATIN SMALL LETTER I WITH BREVE */, + zstroke = 0x10001b6 /* U+01B6 LATIN SMALL LETTER Z WITH STROKE */, + gcaron = 0x10001e7 /* U+01E7 LATIN SMALL LETTER G WITH CARON */, + ocaron = 0x10001d2 /* U+01D2 LATIN SMALL LETTER O WITH CARON */, + obarred = 0x1000275 /* U+0275 LATIN SMALL LETTER BARRED O */, + SCHWA = 0x100018f /* U+018F LATIN CAPITAL LETTER SCHWA */, + schwa = 0x1000259 /* U+0259 LATIN SMALL LETTER SCHWA */, + EZH = 0x10001b7 /* U+01B7 LATIN CAPITAL LETTER EZH */, + ezh = 0x1000292 /* U+0292 LATIN SMALL LETTER EZH */, + Lbelowdot = 0x1001e36 /* U+1E36 LATIN CAPITAL LETTER L WITH DOT BELOW */, + lbelowdot = 0x1001e37 /* U+1E37 LATIN SMALL LETTER L WITH DOT BELOW */, + Abelowdot = 0x1001ea0 /* U+1EA0 LATIN CAPITAL LETTER A WITH DOT BELOW */, + abelowdot = 0x1001ea1 /* U+1EA1 LATIN SMALL LETTER A WITH DOT BELOW */, + Ahook = 0x1001ea2 /* U+1EA2 LATIN CAPITAL LETTER A WITH HOOK ABOVE */, + ahook = 0x1001ea3 /* U+1EA3 LATIN SMALL LETTER A WITH HOOK ABOVE */, + Acircumflexacute = 0x1001ea4 /* U+1EA4 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE */, + acircumflexacute = 0x1001ea5 /* U+1EA5 LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE */, + Acircumflexgrave = 0x1001ea6 /* U+1EA6 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE */, + acircumflexgrave = 0x1001ea7 /* U+1EA7 LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE */, + Acircumflexhook = 0x1001ea8 /* U+1EA8 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */, + acircumflexhook = 0x1001ea9 /* U+1EA9 LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */, + Acircumflextilde = 0x1001eaa /* U+1EAA LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE */, + acircumflextilde = 0x1001eab /* U+1EAB LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE */, + Acircumflexbelowdot = 0x1001eac /* U+1EAC LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW */, + acircumflexbelowdot = 0x1001ead /* U+1EAD LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW */, + Abreveacute = 0x1001eae /* U+1EAE LATIN CAPITAL LETTER A WITH BREVE AND ACUTE */, + abreveacute = 0x1001eaf /* U+1EAF LATIN SMALL LETTER A WITH BREVE AND ACUTE */, + Abrevegrave = 0x1001eb0 /* U+1EB0 LATIN CAPITAL LETTER A WITH BREVE AND GRAVE */, + abrevegrave = 0x1001eb1 /* U+1EB1 LATIN SMALL LETTER A WITH BREVE AND GRAVE */, + Abrevehook = 0x1001eb2 /* U+1EB2 LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE */, + abrevehook = 0x1001eb3 /* U+1EB3 LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE */, + Abrevetilde = 0x1001eb4 /* U+1EB4 LATIN CAPITAL LETTER A WITH BREVE AND TILDE */, + abrevetilde = 0x1001eb5 /* U+1EB5 LATIN SMALL LETTER A WITH BREVE AND TILDE */, + Abrevebelowdot = 0x1001eb6 /* U+1EB6 LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW */, + abrevebelowdot = 0x1001eb7 /* U+1EB7 LATIN SMALL LETTER A WITH BREVE AND DOT BELOW */, + Ebelowdot = 0x1001eb8 /* U+1EB8 LATIN CAPITAL LETTER E WITH DOT BELOW */, + ebelowdot = 0x1001eb9 /* U+1EB9 LATIN SMALL LETTER E WITH DOT BELOW */, + Ehook = 0x1001eba /* U+1EBA LATIN CAPITAL LETTER E WITH HOOK ABOVE */, + ehook = 0x1001ebb /* U+1EBB LATIN SMALL LETTER E WITH HOOK ABOVE */, + Etilde = 0x1001ebc /* U+1EBC LATIN CAPITAL LETTER E WITH TILDE */, + etilde = 0x1001ebd /* U+1EBD LATIN SMALL LETTER E WITH TILDE */, + Ecircumflexacute = 0x1001ebe /* U+1EBE LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE */, + ecircumflexacute = 0x1001ebf /* U+1EBF LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE */, + Ecircumflexgrave = 0x1001ec0 /* U+1EC0 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE */, + ecircumflexgrave = 0x1001ec1 /* U+1EC1 LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE */, + Ecircumflexhook = 0x1001ec2 /* U+1EC2 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */, + ecircumflexhook = 0x1001ec3 /* U+1EC3 LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */, + Ecircumflextilde = 0x1001ec4 /* U+1EC4 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE */, + ecircumflextilde = 0x1001ec5 /* U+1EC5 LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE */, + Ecircumflexbelowdot = 0x1001ec6 /* U+1EC6 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW */, + ecircumflexbelowdot = 0x1001ec7 /* U+1EC7 LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW */, + Ihook = 0x1001ec8 /* U+1EC8 LATIN CAPITAL LETTER I WITH HOOK ABOVE */, + ihook = 0x1001ec9 /* U+1EC9 LATIN SMALL LETTER I WITH HOOK ABOVE */, + Ibelowdot = 0x1001eca /* U+1ECA LATIN CAPITAL LETTER I WITH DOT BELOW */, + ibelowdot = 0x1001ecb /* U+1ECB LATIN SMALL LETTER I WITH DOT BELOW */, + Obelowdot = 0x1001ecc /* U+1ECC LATIN CAPITAL LETTER O WITH DOT BELOW */, + obelowdot = 0x1001ecd /* U+1ECD LATIN SMALL LETTER O WITH DOT BELOW */, + Ohook = 0x1001ece /* U+1ECE LATIN CAPITAL LETTER O WITH HOOK ABOVE */, + ohook = 0x1001ecf /* U+1ECF LATIN SMALL LETTER O WITH HOOK ABOVE */, + Ocircumflexacute = 0x1001ed0 /* U+1ED0 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE */, + ocircumflexacute = 0x1001ed1 /* U+1ED1 LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE */, + Ocircumflexgrave = 0x1001ed2 /* U+1ED2 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE */, + ocircumflexgrave = 0x1001ed3 /* U+1ED3 LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE */, + Ocircumflexhook = 0x1001ed4 /* U+1ED4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */, + ocircumflexhook = 0x1001ed5 /* U+1ED5 LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */, + Ocircumflextilde = 0x1001ed6 /* U+1ED6 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE */, + ocircumflextilde = 0x1001ed7 /* U+1ED7 LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE */, + Ocircumflexbelowdot = 0x1001ed8 /* U+1ED8 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW */, + ocircumflexbelowdot = 0x1001ed9 /* U+1ED9 LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW */, + Ohornacute = 0x1001eda /* U+1EDA LATIN CAPITAL LETTER O WITH HORN AND ACUTE */, + ohornacute = 0x1001edb /* U+1EDB LATIN SMALL LETTER O WITH HORN AND ACUTE */, + Ohorngrave = 0x1001edc /* U+1EDC LATIN CAPITAL LETTER O WITH HORN AND GRAVE */, + ohorngrave = 0x1001edd /* U+1EDD LATIN SMALL LETTER O WITH HORN AND GRAVE */, + Ohornhook = 0x1001ede /* U+1EDE LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE */, + ohornhook = 0x1001edf /* U+1EDF LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE */, + Ohorntilde = 0x1001ee0 /* U+1EE0 LATIN CAPITAL LETTER O WITH HORN AND TILDE */, + ohorntilde = 0x1001ee1 /* U+1EE1 LATIN SMALL LETTER O WITH HORN AND TILDE */, + Ohornbelowdot = 0x1001ee2 /* U+1EE2 LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW */, + ohornbelowdot = 0x1001ee3 /* U+1EE3 LATIN SMALL LETTER O WITH HORN AND DOT BELOW */, + Ubelowdot = 0x1001ee4 /* U+1EE4 LATIN CAPITAL LETTER U WITH DOT BELOW */, + ubelowdot = 0x1001ee5 /* U+1EE5 LATIN SMALL LETTER U WITH DOT BELOW */, + Uhook = 0x1001ee6 /* U+1EE6 LATIN CAPITAL LETTER U WITH HOOK ABOVE */, + uhook = 0x1001ee7 /* U+1EE7 LATIN SMALL LETTER U WITH HOOK ABOVE */, + Uhornacute = 0x1001ee8 /* U+1EE8 LATIN CAPITAL LETTER U WITH HORN AND ACUTE */, + uhornacute = 0x1001ee9 /* U+1EE9 LATIN SMALL LETTER U WITH HORN AND ACUTE */, + Uhorngrave = 0x1001eea /* U+1EEA LATIN CAPITAL LETTER U WITH HORN AND GRAVE */, + uhorngrave = 0x1001eeb /* U+1EEB LATIN SMALL LETTER U WITH HORN AND GRAVE */, + Uhornhook = 0x1001eec /* U+1EEC LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE */, + uhornhook = 0x1001eed /* U+1EED LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE */, + Uhorntilde = 0x1001eee /* U+1EEE LATIN CAPITAL LETTER U WITH HORN AND TILDE */, + uhorntilde = 0x1001eef /* U+1EEF LATIN SMALL LETTER U WITH HORN AND TILDE */, + Uhornbelowdot = 0x1001ef0 /* U+1EF0 LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW */, + uhornbelowdot = 0x1001ef1 /* U+1EF1 LATIN SMALL LETTER U WITH HORN AND DOT BELOW */, + Ybelowdot = 0x1001ef4 /* U+1EF4 LATIN CAPITAL LETTER Y WITH DOT BELOW */, + ybelowdot = 0x1001ef5 /* U+1EF5 LATIN SMALL LETTER Y WITH DOT BELOW */, + Yhook = 0x1001ef6 /* U+1EF6 LATIN CAPITAL LETTER Y WITH HOOK ABOVE */, + yhook = 0x1001ef7 /* U+1EF7 LATIN SMALL LETTER Y WITH HOOK ABOVE */, + Ytilde = 0x1001ef8 /* U+1EF8 LATIN CAPITAL LETTER Y WITH TILDE */, + ytilde = 0x1001ef9 /* U+1EF9 LATIN SMALL LETTER Y WITH TILDE */, + Ohorn = 0x10001a0 /* U+01A0 LATIN CAPITAL LETTER O WITH HORN */, + ohorn = 0x10001a1 /* U+01A1 LATIN SMALL LETTER O WITH HORN */, + Uhorn = 0x10001af /* U+01AF LATIN CAPITAL LETTER U WITH HORN */, + uhorn = 0x10001b0 /* U+01B0 LATIN SMALL LETTER U WITH HORN */, + EcuSign = 0x10020a0 /* U+20A0 EURO-CURRENCY SIGN */, + ColonSign = 0x10020a1 /* U+20A1 COLON SIGN */, + CruzeiroSign = 0x10020a2 /* U+20A2 CRUZEIRO SIGN */, + FFrancSign = 0x10020a3 /* U+20A3 FRENCH FRANC SIGN */, + LiraSign = 0x10020a4 /* U+20A4 LIRA SIGN */, + MillSign = 0x10020a5 /* U+20A5 MILL SIGN */, + NairaSign = 0x10020a6 /* U+20A6 NAIRA SIGN */, + PesetaSign = 0x10020a7 /* U+20A7 PESETA SIGN */, + RupeeSign = 0x10020a8 /* U+20A8 RUPEE SIGN */, + WonSign = 0x10020a9 /* U+20A9 WON SIGN */, + NewSheqelSign = 0x10020aa /* U+20AA NEW SHEQEL SIGN */, + DongSign = 0x10020ab /* U+20AB DONG SIGN */, + EuroSign = 0x20ac /* U+20AC EURO SIGN */, + zerosuperior = 0x1002070 /* U+2070 SUPERSCRIPT ZERO */, + foursuperior = 0x1002074 /* U+2074 SUPERSCRIPT FOUR */, + fivesuperior = 0x1002075 /* U+2075 SUPERSCRIPT FIVE */, + sixsuperior = 0x1002076 /* U+2076 SUPERSCRIPT SIX */, + sevensuperior = 0x1002077 /* U+2077 SUPERSCRIPT SEVEN */, + eightsuperior = 0x1002078 /* U+2078 SUPERSCRIPT EIGHT */, + ninesuperior = 0x1002079 /* U+2079 SUPERSCRIPT NINE */, + zerosubscript = 0x1002080 /* U+2080 SUBSCRIPT ZERO */, + onesubscript = 0x1002081 /* U+2081 SUBSCRIPT ONE */, + twosubscript = 0x1002082 /* U+2082 SUBSCRIPT TWO */, + threesubscript = 0x1002083 /* U+2083 SUBSCRIPT THREE */, + foursubscript = 0x1002084 /* U+2084 SUBSCRIPT FOUR */, + fivesubscript = 0x1002085 /* U+2085 SUBSCRIPT FIVE */, + sixsubscript = 0x1002086 /* U+2086 SUBSCRIPT SIX */, + sevensubscript = 0x1002087 /* U+2087 SUBSCRIPT SEVEN */, + eightsubscript = 0x1002088 /* U+2088 SUBSCRIPT EIGHT */, + ninesubscript = 0x1002089 /* U+2089 SUBSCRIPT NINE */, + partdifferential = 0x1002202 /* U+2202 PARTIAL DIFFERENTIAL */, + emptyset = 0x1002205 /* U+2205 NULL SET */, + elementof = 0x1002208 /* U+2208 ELEMENT OF */, + notelementof = 0x1002209 /* U+2209 NOT AN ELEMENT OF */, + containsas = 0x100220B /* U+220B CONTAINS AS MEMBER */, + squareroot = 0x100221A /* U+221A SQUARE ROOT */, + cuberoot = 0x100221B /* U+221B CUBE ROOT */, + fourthroot = 0x100221C /* U+221C FOURTH ROOT */, + dintegral = 0x100222C /* U+222C DOUBLE INTEGRAL */, + tintegral = 0x100222D /* U+222D TRIPLE INTEGRAL */, + because = 0x1002235 /* U+2235 BECAUSE */, + approxeq = 0x1002248 /* U+2245 ALMOST EQUAL TO */, + notapproxeq = 0x1002247 /* U+2247 NOT ALMOST EQUAL TO */, + notidentical = 0x1002262 /* U+2262 NOT IDENTICAL TO */, + stricteq = 0x1002263 /* U+2263 STRICTLY EQUIVALENT TO */, + braille_dot_1 = 0xfff1, + braille_dot_2 = 0xfff2, + braille_dot_3 = 0xfff3, + braille_dot_4 = 0xfff4, + braille_dot_5 = 0xfff5, + braille_dot_6 = 0xfff6, + braille_dot_7 = 0xfff7, + braille_dot_8 = 0xfff8, + braille_dot_9 = 0xfff9, + braille_dot_10 = 0xfffa, + braille_blank = 0x1002800 /* U+2800 BRAILLE PATTERN BLANK */, + braille_dots_1 = 0x1002801 /* U+2801 BRAILLE PATTERN DOTS-1 */, + braille_dots_2 = 0x1002802 /* U+2802 BRAILLE PATTERN DOTS-2 */, + braille_dots_12 = 0x1002803 /* U+2803 BRAILLE PATTERN DOTS-12 */, + braille_dots_3 = 0x1002804 /* U+2804 BRAILLE PATTERN DOTS-3 */, + braille_dots_13 = 0x1002805 /* U+2805 BRAILLE PATTERN DOTS-13 */, + braille_dots_23 = 0x1002806 /* U+2806 BRAILLE PATTERN DOTS-23 */, + braille_dots_123 = 0x1002807 /* U+2807 BRAILLE PATTERN DOTS-123 */, + braille_dots_4 = 0x1002808 /* U+2808 BRAILLE PATTERN DOTS-4 */, + braille_dots_14 = 0x1002809 /* U+2809 BRAILLE PATTERN DOTS-14 */, + braille_dots_24 = 0x100280a /* U+280a BRAILLE PATTERN DOTS-24 */, + braille_dots_124 = 0x100280b /* U+280b BRAILLE PATTERN DOTS-124 */, + braille_dots_34 = 0x100280c /* U+280c BRAILLE PATTERN DOTS-34 */, + braille_dots_134 = 0x100280d /* U+280d BRAILLE PATTERN DOTS-134 */, + braille_dots_234 = 0x100280e /* U+280e BRAILLE PATTERN DOTS-234 */, + braille_dots_1234 = 0x100280f /* U+280f BRAILLE PATTERN DOTS-1234 */, + braille_dots_5 = 0x1002810 /* U+2810 BRAILLE PATTERN DOTS-5 */, + braille_dots_15 = 0x1002811 /* U+2811 BRAILLE PATTERN DOTS-15 */, + braille_dots_25 = 0x1002812 /* U+2812 BRAILLE PATTERN DOTS-25 */, + braille_dots_125 = 0x1002813 /* U+2813 BRAILLE PATTERN DOTS-125 */, + braille_dots_35 = 0x1002814 /* U+2814 BRAILLE PATTERN DOTS-35 */, + braille_dots_135 = 0x1002815 /* U+2815 BRAILLE PATTERN DOTS-135 */, + braille_dots_235 = 0x1002816 /* U+2816 BRAILLE PATTERN DOTS-235 */, + braille_dots_1235 = 0x1002817 /* U+2817 BRAILLE PATTERN DOTS-1235 */, + braille_dots_45 = 0x1002818 /* U+2818 BRAILLE PATTERN DOTS-45 */, + braille_dots_145 = 0x1002819 /* U+2819 BRAILLE PATTERN DOTS-145 */, + braille_dots_245 = 0x100281a /* U+281a BRAILLE PATTERN DOTS-245 */, + braille_dots_1245 = 0x100281b /* U+281b BRAILLE PATTERN DOTS-1245 */, + braille_dots_345 = 0x100281c /* U+281c BRAILLE PATTERN DOTS-345 */, + braille_dots_1345 = 0x100281d /* U+281d BRAILLE PATTERN DOTS-1345 */, + braille_dots_2345 = 0x100281e /* U+281e BRAILLE PATTERN DOTS-2345 */, + braille_dots_12345 = 0x100281f /* U+281f BRAILLE PATTERN DOTS-12345 */, + braille_dots_6 = 0x1002820 /* U+2820 BRAILLE PATTERN DOTS-6 */, + braille_dots_16 = 0x1002821 /* U+2821 BRAILLE PATTERN DOTS-16 */, + braille_dots_26 = 0x1002822 /* U+2822 BRAILLE PATTERN DOTS-26 */, + braille_dots_126 = 0x1002823 /* U+2823 BRAILLE PATTERN DOTS-126 */, + braille_dots_36 = 0x1002824 /* U+2824 BRAILLE PATTERN DOTS-36 */, + braille_dots_136 = 0x1002825 /* U+2825 BRAILLE PATTERN DOTS-136 */, + braille_dots_236 = 0x1002826 /* U+2826 BRAILLE PATTERN DOTS-236 */, + braille_dots_1236 = 0x1002827 /* U+2827 BRAILLE PATTERN DOTS-1236 */, + braille_dots_46 = 0x1002828 /* U+2828 BRAILLE PATTERN DOTS-46 */, + braille_dots_146 = 0x1002829 /* U+2829 BRAILLE PATTERN DOTS-146 */, + braille_dots_246 = 0x100282a /* U+282a BRAILLE PATTERN DOTS-246 */, + braille_dots_1246 = 0x100282b /* U+282b BRAILLE PATTERN DOTS-1246 */, + braille_dots_346 = 0x100282c /* U+282c BRAILLE PATTERN DOTS-346 */, + braille_dots_1346 = 0x100282d /* U+282d BRAILLE PATTERN DOTS-1346 */, + braille_dots_2346 = 0x100282e /* U+282e BRAILLE PATTERN DOTS-2346 */, + braille_dots_12346 = 0x100282f /* U+282f BRAILLE PATTERN DOTS-12346 */, + braille_dots_56 = 0x1002830 /* U+2830 BRAILLE PATTERN DOTS-56 */, + braille_dots_156 = 0x1002831 /* U+2831 BRAILLE PATTERN DOTS-156 */, + braille_dots_256 = 0x1002832 /* U+2832 BRAILLE PATTERN DOTS-256 */, + braille_dots_1256 = 0x1002833 /* U+2833 BRAILLE PATTERN DOTS-1256 */, + braille_dots_356 = 0x1002834 /* U+2834 BRAILLE PATTERN DOTS-356 */, + braille_dots_1356 = 0x1002835 /* U+2835 BRAILLE PATTERN DOTS-1356 */, + braille_dots_2356 = 0x1002836 /* U+2836 BRAILLE PATTERN DOTS-2356 */, + braille_dots_12356 = 0x1002837 /* U+2837 BRAILLE PATTERN DOTS-12356 */, + braille_dots_456 = 0x1002838 /* U+2838 BRAILLE PATTERN DOTS-456 */, + braille_dots_1456 = 0x1002839 /* U+2839 BRAILLE PATTERN DOTS-1456 */, + braille_dots_2456 = 0x100283a /* U+283a BRAILLE PATTERN DOTS-2456 */, + braille_dots_12456 = 0x100283b /* U+283b BRAILLE PATTERN DOTS-12456 */, + braille_dots_3456 = 0x100283c /* U+283c BRAILLE PATTERN DOTS-3456 */, + braille_dots_13456 = 0x100283d /* U+283d BRAILLE PATTERN DOTS-13456 */, + braille_dots_23456 = 0x100283e /* U+283e BRAILLE PATTERN DOTS-23456 */, + braille_dots_123456 = 0x100283f /* U+283f BRAILLE PATTERN DOTS-123456 */, + braille_dots_7 = 0x1002840 /* U+2840 BRAILLE PATTERN DOTS-7 */, + braille_dots_17 = 0x1002841 /* U+2841 BRAILLE PATTERN DOTS-17 */, + braille_dots_27 = 0x1002842 /* U+2842 BRAILLE PATTERN DOTS-27 */, + braille_dots_127 = 0x1002843 /* U+2843 BRAILLE PATTERN DOTS-127 */, + braille_dots_37 = 0x1002844 /* U+2844 BRAILLE PATTERN DOTS-37 */, + braille_dots_137 = 0x1002845 /* U+2845 BRAILLE PATTERN DOTS-137 */, + braille_dots_237 = 0x1002846 /* U+2846 BRAILLE PATTERN DOTS-237 */, + braille_dots_1237 = 0x1002847 /* U+2847 BRAILLE PATTERN DOTS-1237 */, + braille_dots_47 = 0x1002848 /* U+2848 BRAILLE PATTERN DOTS-47 */, + braille_dots_147 = 0x1002849 /* U+2849 BRAILLE PATTERN DOTS-147 */, + braille_dots_247 = 0x100284a /* U+284a BRAILLE PATTERN DOTS-247 */, + braille_dots_1247 = 0x100284b /* U+284b BRAILLE PATTERN DOTS-1247 */, + braille_dots_347 = 0x100284c /* U+284c BRAILLE PATTERN DOTS-347 */, + braille_dots_1347 = 0x100284d /* U+284d BRAILLE PATTERN DOTS-1347 */, + braille_dots_2347 = 0x100284e /* U+284e BRAILLE PATTERN DOTS-2347 */, + braille_dots_12347 = 0x100284f /* U+284f BRAILLE PATTERN DOTS-12347 */, + braille_dots_57 = 0x1002850 /* U+2850 BRAILLE PATTERN DOTS-57 */, + braille_dots_157 = 0x1002851 /* U+2851 BRAILLE PATTERN DOTS-157 */, + braille_dots_257 = 0x1002852 /* U+2852 BRAILLE PATTERN DOTS-257 */, + braille_dots_1257 = 0x1002853 /* U+2853 BRAILLE PATTERN DOTS-1257 */, + braille_dots_357 = 0x1002854 /* U+2854 BRAILLE PATTERN DOTS-357 */, + braille_dots_1357 = 0x1002855 /* U+2855 BRAILLE PATTERN DOTS-1357 */, + braille_dots_2357 = 0x1002856 /* U+2856 BRAILLE PATTERN DOTS-2357 */, + braille_dots_12357 = 0x1002857 /* U+2857 BRAILLE PATTERN DOTS-12357 */, + braille_dots_457 = 0x1002858 /* U+2858 BRAILLE PATTERN DOTS-457 */, + braille_dots_1457 = 0x1002859 /* U+2859 BRAILLE PATTERN DOTS-1457 */, + braille_dots_2457 = 0x100285a /* U+285a BRAILLE PATTERN DOTS-2457 */, + braille_dots_12457 = 0x100285b /* U+285b BRAILLE PATTERN DOTS-12457 */, + braille_dots_3457 = 0x100285c /* U+285c BRAILLE PATTERN DOTS-3457 */, + braille_dots_13457 = 0x100285d /* U+285d BRAILLE PATTERN DOTS-13457 */, + braille_dots_23457 = 0x100285e /* U+285e BRAILLE PATTERN DOTS-23457 */, + braille_dots_123457 = 0x100285f /* U+285f BRAILLE PATTERN DOTS-123457 */, + braille_dots_67 = 0x1002860 /* U+2860 BRAILLE PATTERN DOTS-67 */, + braille_dots_167 = 0x1002861 /* U+2861 BRAILLE PATTERN DOTS-167 */, + braille_dots_267 = 0x1002862 /* U+2862 BRAILLE PATTERN DOTS-267 */, + braille_dots_1267 = 0x1002863 /* U+2863 BRAILLE PATTERN DOTS-1267 */, + braille_dots_367 = 0x1002864 /* U+2864 BRAILLE PATTERN DOTS-367 */, + braille_dots_1367 = 0x1002865 /* U+2865 BRAILLE PATTERN DOTS-1367 */, + braille_dots_2367 = 0x1002866 /* U+2866 BRAILLE PATTERN DOTS-2367 */, + braille_dots_12367 = 0x1002867 /* U+2867 BRAILLE PATTERN DOTS-12367 */, + braille_dots_467 = 0x1002868 /* U+2868 BRAILLE PATTERN DOTS-467 */, + braille_dots_1467 = 0x1002869 /* U+2869 BRAILLE PATTERN DOTS-1467 */, + braille_dots_2467 = 0x100286a /* U+286a BRAILLE PATTERN DOTS-2467 */, + braille_dots_12467 = 0x100286b /* U+286b BRAILLE PATTERN DOTS-12467 */, + braille_dots_3467 = 0x100286c /* U+286c BRAILLE PATTERN DOTS-3467 */, + braille_dots_13467 = 0x100286d /* U+286d BRAILLE PATTERN DOTS-13467 */, + braille_dots_23467 = 0x100286e /* U+286e BRAILLE PATTERN DOTS-23467 */, + braille_dots_123467 = 0x100286f /* U+286f BRAILLE PATTERN DOTS-123467 */, + braille_dots_567 = 0x1002870 /* U+2870 BRAILLE PATTERN DOTS-567 */, + braille_dots_1567 = 0x1002871 /* U+2871 BRAILLE PATTERN DOTS-1567 */, + braille_dots_2567 = 0x1002872 /* U+2872 BRAILLE PATTERN DOTS-2567 */, + braille_dots_12567 = 0x1002873 /* U+2873 BRAILLE PATTERN DOTS-12567 */, + braille_dots_3567 = 0x1002874 /* U+2874 BRAILLE PATTERN DOTS-3567 */, + braille_dots_13567 = 0x1002875 /* U+2875 BRAILLE PATTERN DOTS-13567 */, + braille_dots_23567 = 0x1002876 /* U+2876 BRAILLE PATTERN DOTS-23567 */, + braille_dots_123567 = 0x1002877 /* U+2877 BRAILLE PATTERN DOTS-123567 */, + braille_dots_4567 = 0x1002878 /* U+2878 BRAILLE PATTERN DOTS-4567 */, + braille_dots_14567 = 0x1002879 /* U+2879 BRAILLE PATTERN DOTS-14567 */, + braille_dots_24567 = 0x100287a /* U+287a BRAILLE PATTERN DOTS-24567 */, + braille_dots_124567 = 0x100287b /* U+287b BRAILLE PATTERN DOTS-124567 */, + braille_dots_34567 = 0x100287c /* U+287c BRAILLE PATTERN DOTS-34567 */, + braille_dots_134567 = 0x100287d /* U+287d BRAILLE PATTERN DOTS-134567 */, + braille_dots_234567 = 0x100287e /* U+287e BRAILLE PATTERN DOTS-234567 */, + braille_dots_1234567 = 0x100287f /* U+287f BRAILLE PATTERN DOTS-1234567 */, + braille_dots_8 = 0x1002880 /* U+2880 BRAILLE PATTERN DOTS-8 */, + braille_dots_18 = 0x1002881 /* U+2881 BRAILLE PATTERN DOTS-18 */, + braille_dots_28 = 0x1002882 /* U+2882 BRAILLE PATTERN DOTS-28 */, + braille_dots_128 = 0x1002883 /* U+2883 BRAILLE PATTERN DOTS-128 */, + braille_dots_38 = 0x1002884 /* U+2884 BRAILLE PATTERN DOTS-38 */, + braille_dots_138 = 0x1002885 /* U+2885 BRAILLE PATTERN DOTS-138 */, + braille_dots_238 = 0x1002886 /* U+2886 BRAILLE PATTERN DOTS-238 */, + braille_dots_1238 = 0x1002887 /* U+2887 BRAILLE PATTERN DOTS-1238 */, + braille_dots_48 = 0x1002888 /* U+2888 BRAILLE PATTERN DOTS-48 */, + braille_dots_148 = 0x1002889 /* U+2889 BRAILLE PATTERN DOTS-148 */, + braille_dots_248 = 0x100288a /* U+288a BRAILLE PATTERN DOTS-248 */, + braille_dots_1248 = 0x100288b /* U+288b BRAILLE PATTERN DOTS-1248 */, + braille_dots_348 = 0x100288c /* U+288c BRAILLE PATTERN DOTS-348 */, + braille_dots_1348 = 0x100288d /* U+288d BRAILLE PATTERN DOTS-1348 */, + braille_dots_2348 = 0x100288e /* U+288e BRAILLE PATTERN DOTS-2348 */, + braille_dots_12348 = 0x100288f /* U+288f BRAILLE PATTERN DOTS-12348 */, + braille_dots_58 = 0x1002890 /* U+2890 BRAILLE PATTERN DOTS-58 */, + braille_dots_158 = 0x1002891 /* U+2891 BRAILLE PATTERN DOTS-158 */, + braille_dots_258 = 0x1002892 /* U+2892 BRAILLE PATTERN DOTS-258 */, + braille_dots_1258 = 0x1002893 /* U+2893 BRAILLE PATTERN DOTS-1258 */, + braille_dots_358 = 0x1002894 /* U+2894 BRAILLE PATTERN DOTS-358 */, + braille_dots_1358 = 0x1002895 /* U+2895 BRAILLE PATTERN DOTS-1358 */, + braille_dots_2358 = 0x1002896 /* U+2896 BRAILLE PATTERN DOTS-2358 */, + braille_dots_12358 = 0x1002897 /* U+2897 BRAILLE PATTERN DOTS-12358 */, + braille_dots_458 = 0x1002898 /* U+2898 BRAILLE PATTERN DOTS-458 */, + braille_dots_1458 = 0x1002899 /* U+2899 BRAILLE PATTERN DOTS-1458 */, + braille_dots_2458 = 0x100289a /* U+289a BRAILLE PATTERN DOTS-2458 */, + braille_dots_12458 = 0x100289b /* U+289b BRAILLE PATTERN DOTS-12458 */, + braille_dots_3458 = 0x100289c /* U+289c BRAILLE PATTERN DOTS-3458 */, + braille_dots_13458 = 0x100289d /* U+289d BRAILLE PATTERN DOTS-13458 */, + braille_dots_23458 = 0x100289e /* U+289e BRAILLE PATTERN DOTS-23458 */, + braille_dots_123458 = 0x100289f /* U+289f BRAILLE PATTERN DOTS-123458 */, + braille_dots_68 = 0x10028a0 /* U+28a0 BRAILLE PATTERN DOTS-68 */, + braille_dots_168 = 0x10028a1 /* U+28a1 BRAILLE PATTERN DOTS-168 */, + braille_dots_268 = 0x10028a2 /* U+28a2 BRAILLE PATTERN DOTS-268 */, + braille_dots_1268 = 0x10028a3 /* U+28a3 BRAILLE PATTERN DOTS-1268 */, + braille_dots_368 = 0x10028a4 /* U+28a4 BRAILLE PATTERN DOTS-368 */, + braille_dots_1368 = 0x10028a5 /* U+28a5 BRAILLE PATTERN DOTS-1368 */, + braille_dots_2368 = 0x10028a6 /* U+28a6 BRAILLE PATTERN DOTS-2368 */, + braille_dots_12368 = 0x10028a7 /* U+28a7 BRAILLE PATTERN DOTS-12368 */, + braille_dots_468 = 0x10028a8 /* U+28a8 BRAILLE PATTERN DOTS-468 */, + braille_dots_1468 = 0x10028a9 /* U+28a9 BRAILLE PATTERN DOTS-1468 */, + braille_dots_2468 = 0x10028aa /* U+28aa BRAILLE PATTERN DOTS-2468 */, + braille_dots_12468 = 0x10028ab /* U+28ab BRAILLE PATTERN DOTS-12468 */, + braille_dots_3468 = 0x10028ac /* U+28ac BRAILLE PATTERN DOTS-3468 */, + braille_dots_13468 = 0x10028ad /* U+28ad BRAILLE PATTERN DOTS-13468 */, + braille_dots_23468 = 0x10028ae /* U+28ae BRAILLE PATTERN DOTS-23468 */, + braille_dots_123468 = 0x10028af /* U+28af BRAILLE PATTERN DOTS-123468 */, + braille_dots_568 = 0x10028b0 /* U+28b0 BRAILLE PATTERN DOTS-568 */, + braille_dots_1568 = 0x10028b1 /* U+28b1 BRAILLE PATTERN DOTS-1568 */, + braille_dots_2568 = 0x10028b2 /* U+28b2 BRAILLE PATTERN DOTS-2568 */, + braille_dots_12568 = 0x10028b3 /* U+28b3 BRAILLE PATTERN DOTS-12568 */, + braille_dots_3568 = 0x10028b4 /* U+28b4 BRAILLE PATTERN DOTS-3568 */, + braille_dots_13568 = 0x10028b5 /* U+28b5 BRAILLE PATTERN DOTS-13568 */, + braille_dots_23568 = 0x10028b6 /* U+28b6 BRAILLE PATTERN DOTS-23568 */, + braille_dots_123568 = 0x10028b7 /* U+28b7 BRAILLE PATTERN DOTS-123568 */, + braille_dots_4568 = 0x10028b8 /* U+28b8 BRAILLE PATTERN DOTS-4568 */, + braille_dots_14568 = 0x10028b9 /* U+28b9 BRAILLE PATTERN DOTS-14568 */, + braille_dots_24568 = 0x10028ba /* U+28ba BRAILLE PATTERN DOTS-24568 */, + braille_dots_124568 = 0x10028bb /* U+28bb BRAILLE PATTERN DOTS-124568 */, + braille_dots_34568 = 0x10028bc /* U+28bc BRAILLE PATTERN DOTS-34568 */, + braille_dots_134568 = 0x10028bd /* U+28bd BRAILLE PATTERN DOTS-134568 */, + braille_dots_234568 = 0x10028be /* U+28be BRAILLE PATTERN DOTS-234568 */, + braille_dots_1234568 = 0x10028bf /* U+28bf BRAILLE PATTERN DOTS-1234568 */, + braille_dots_78 = 0x10028c0 /* U+28c0 BRAILLE PATTERN DOTS-78 */, + braille_dots_178 = 0x10028c1 /* U+28c1 BRAILLE PATTERN DOTS-178 */, + braille_dots_278 = 0x10028c2 /* U+28c2 BRAILLE PATTERN DOTS-278 */, + braille_dots_1278 = 0x10028c3 /* U+28c3 BRAILLE PATTERN DOTS-1278 */, + braille_dots_378 = 0x10028c4 /* U+28c4 BRAILLE PATTERN DOTS-378 */, + braille_dots_1378 = 0x10028c5 /* U+28c5 BRAILLE PATTERN DOTS-1378 */, + braille_dots_2378 = 0x10028c6 /* U+28c6 BRAILLE PATTERN DOTS-2378 */, + braille_dots_12378 = 0x10028c7 /* U+28c7 BRAILLE PATTERN DOTS-12378 */, + braille_dots_478 = 0x10028c8 /* U+28c8 BRAILLE PATTERN DOTS-478 */, + braille_dots_1478 = 0x10028c9 /* U+28c9 BRAILLE PATTERN DOTS-1478 */, + braille_dots_2478 = 0x10028ca /* U+28ca BRAILLE PATTERN DOTS-2478 */, + braille_dots_12478 = 0x10028cb /* U+28cb BRAILLE PATTERN DOTS-12478 */, + braille_dots_3478 = 0x10028cc /* U+28cc BRAILLE PATTERN DOTS-3478 */, + braille_dots_13478 = 0x10028cd /* U+28cd BRAILLE PATTERN DOTS-13478 */, + braille_dots_23478 = 0x10028ce /* U+28ce BRAILLE PATTERN DOTS-23478 */, + braille_dots_123478 = 0x10028cf /* U+28cf BRAILLE PATTERN DOTS-123478 */, + braille_dots_578 = 0x10028d0 /* U+28d0 BRAILLE PATTERN DOTS-578 */, + braille_dots_1578 = 0x10028d1 /* U+28d1 BRAILLE PATTERN DOTS-1578 */, + braille_dots_2578 = 0x10028d2 /* U+28d2 BRAILLE PATTERN DOTS-2578 */, + braille_dots_12578 = 0x10028d3 /* U+28d3 BRAILLE PATTERN DOTS-12578 */, + braille_dots_3578 = 0x10028d4 /* U+28d4 BRAILLE PATTERN DOTS-3578 */, + braille_dots_13578 = 0x10028d5 /* U+28d5 BRAILLE PATTERN DOTS-13578 */, + braille_dots_23578 = 0x10028d6 /* U+28d6 BRAILLE PATTERN DOTS-23578 */, + braille_dots_123578 = 0x10028d7 /* U+28d7 BRAILLE PATTERN DOTS-123578 */, + braille_dots_4578 = 0x10028d8 /* U+28d8 BRAILLE PATTERN DOTS-4578 */, + braille_dots_14578 = 0x10028d9 /* U+28d9 BRAILLE PATTERN DOTS-14578 */, + braille_dots_24578 = 0x10028da /* U+28da BRAILLE PATTERN DOTS-24578 */, + braille_dots_124578 = 0x10028db /* U+28db BRAILLE PATTERN DOTS-124578 */, + braille_dots_34578 = 0x10028dc /* U+28dc BRAILLE PATTERN DOTS-34578 */, + braille_dots_134578 = 0x10028dd /* U+28dd BRAILLE PATTERN DOTS-134578 */, + braille_dots_234578 = 0x10028de /* U+28de BRAILLE PATTERN DOTS-234578 */, + braille_dots_1234578 = 0x10028df /* U+28df BRAILLE PATTERN DOTS-1234578 */, + braille_dots_678 = 0x10028e0 /* U+28e0 BRAILLE PATTERN DOTS-678 */, + braille_dots_1678 = 0x10028e1 /* U+28e1 BRAILLE PATTERN DOTS-1678 */, + braille_dots_2678 = 0x10028e2 /* U+28e2 BRAILLE PATTERN DOTS-2678 */, + braille_dots_12678 = 0x10028e3 /* U+28e3 BRAILLE PATTERN DOTS-12678 */, + braille_dots_3678 = 0x10028e4 /* U+28e4 BRAILLE PATTERN DOTS-3678 */, + braille_dots_13678 = 0x10028e5 /* U+28e5 BRAILLE PATTERN DOTS-13678 */, + braille_dots_23678 = 0x10028e6 /* U+28e6 BRAILLE PATTERN DOTS-23678 */, + braille_dots_123678 = 0x10028e7 /* U+28e7 BRAILLE PATTERN DOTS-123678 */, + braille_dots_4678 = 0x10028e8 /* U+28e8 BRAILLE PATTERN DOTS-4678 */, + braille_dots_14678 = 0x10028e9 /* U+28e9 BRAILLE PATTERN DOTS-14678 */, + braille_dots_24678 = 0x10028ea /* U+28ea BRAILLE PATTERN DOTS-24678 */, + braille_dots_124678 = 0x10028eb /* U+28eb BRAILLE PATTERN DOTS-124678 */, + braille_dots_34678 = 0x10028ec /* U+28ec BRAILLE PATTERN DOTS-34678 */, + braille_dots_134678 = 0x10028ed /* U+28ed BRAILLE PATTERN DOTS-134678 */, + braille_dots_234678 = 0x10028ee /* U+28ee BRAILLE PATTERN DOTS-234678 */, + braille_dots_1234678 = 0x10028ef /* U+28ef BRAILLE PATTERN DOTS-1234678 */, + braille_dots_5678 = 0x10028f0 /* U+28f0 BRAILLE PATTERN DOTS-5678 */, + braille_dots_15678 = 0x10028f1 /* U+28f1 BRAILLE PATTERN DOTS-15678 */, + braille_dots_25678 = 0x10028f2 /* U+28f2 BRAILLE PATTERN DOTS-25678 */, + braille_dots_125678 = 0x10028f3 /* U+28f3 BRAILLE PATTERN DOTS-125678 */, + braille_dots_35678 = 0x10028f4 /* U+28f4 BRAILLE PATTERN DOTS-35678 */, + braille_dots_135678 = 0x10028f5 /* U+28f5 BRAILLE PATTERN DOTS-135678 */, + braille_dots_235678 = 0x10028f6 /* U+28f6 BRAILLE PATTERN DOTS-235678 */, + braille_dots_1235678 = 0x10028f7 /* U+28f7 BRAILLE PATTERN DOTS-1235678 */, + braille_dots_45678 = 0x10028f8 /* U+28f8 BRAILLE PATTERN DOTS-45678 */, + braille_dots_145678 = 0x10028f9 /* U+28f9 BRAILLE PATTERN DOTS-145678 */, + braille_dots_245678 = 0x10028fa /* U+28fa BRAILLE PATTERN DOTS-245678 */, + braille_dots_1245678 = 0x10028fb /* U+28fb BRAILLE PATTERN DOTS-1245678 */, + braille_dots_345678 = 0x10028fc /* U+28fc BRAILLE PATTERN DOTS-345678 */, + braille_dots_1345678 = 0x10028fd /* U+28fd BRAILLE PATTERN DOTS-1345678 */, + braille_dots_2345678 = 0x10028fe /* U+28fe BRAILLE PATTERN DOTS-2345678 */, + braille_dots_12345678 = 0x10028ff /* U+28ff BRAILLE PATTERN DOTS-12345678 */, + Sinh_ng = 0x1000d82 /* U+0D82 SINHALA ANUSVARAYA */, + Sinh_h2 = 0x1000d83 /* U+0D83 SINHALA VISARGAYA */, + Sinh_a = 0x1000d85 /* U+0D85 SINHALA AYANNA */, + Sinh_aa = 0x1000d86 /* U+0D86 SINHALA AAYANNA */, + Sinh_ae = 0x1000d87 /* U+0D87 SINHALA AEYANNA */, + Sinh_aee = 0x1000d88 /* U+0D88 SINHALA AEEYANNA */, + Sinh_i = 0x1000d89 /* U+0D89 SINHALA IYANNA */, + Sinh_ii = 0x1000d8a /* U+0D8A SINHALA IIYANNA */, + Sinh_u = 0x1000d8b /* U+0D8B SINHALA UYANNA */, + Sinh_uu = 0x1000d8c /* U+0D8C SINHALA UUYANNA */, + Sinh_ri = 0x1000d8d /* U+0D8D SINHALA IRUYANNA */, + Sinh_rii = 0x1000d8e /* U+0D8E SINHALA IRUUYANNA */, + Sinh_lu = 0x1000d8f /* U+0D8F SINHALA ILUYANNA */, + Sinh_luu = 0x1000d90 /* U+0D90 SINHALA ILUUYANNA */, + Sinh_e = 0x1000d91 /* U+0D91 SINHALA EYANNA */, + Sinh_ee = 0x1000d92 /* U+0D92 SINHALA EEYANNA */, + Sinh_ai = 0x1000d93 /* U+0D93 SINHALA AIYANNA */, + Sinh_o = 0x1000d94 /* U+0D94 SINHALA OYANNA */, + Sinh_oo = 0x1000d95 /* U+0D95 SINHALA OOYANNA */, + Sinh_au = 0x1000d96 /* U+0D96 SINHALA AUYANNA */, + Sinh_ka = 0x1000d9a /* U+0D9A SINHALA KAYANNA */, + Sinh_kha = 0x1000d9b /* U+0D9B SINHALA MAHA. KAYANNA */, + Sinh_ga = 0x1000d9c /* U+0D9C SINHALA GAYANNA */, + Sinh_gha = 0x1000d9d /* U+0D9D SINHALA MAHA. GAYANNA */, + Sinh_ng2 = 0x1000d9e /* U+0D9E SINHALA KANTAJA NAASIKYAYA */, + Sinh_nga = 0x1000d9f /* U+0D9F SINHALA SANYAKA GAYANNA */, + Sinh_ca = 0x1000da0 /* U+0DA0 SINHALA CAYANNA */, + Sinh_cha = 0x1000da1 /* U+0DA1 SINHALA MAHA. CAYANNA */, + Sinh_ja = 0x1000da2 /* U+0DA2 SINHALA JAYANNA */, + Sinh_jha = 0x1000da3 /* U+0DA3 SINHALA MAHA. JAYANNA */, + Sinh_nya = 0x1000da4 /* U+0DA4 SINHALA TAALUJA NAASIKYAYA */, + Sinh_jnya = 0x1000da5 /* U+0DA5 SINHALA TAALUJA SANYOOGA NAASIKYAYA */, + Sinh_nja = 0x1000da6 /* U+0DA6 SINHALA SANYAKA JAYANNA */, + Sinh_tta = 0x1000da7 /* U+0DA7 SINHALA TTAYANNA */, + Sinh_ttha = 0x1000da8 /* U+0DA8 SINHALA MAHA. TTAYANNA */, + Sinh_dda = 0x1000da9 /* U+0DA9 SINHALA DDAYANNA */, + Sinh_ddha = 0x1000daa /* U+0DAA SINHALA MAHA. DDAYANNA */, + Sinh_nna = 0x1000dab /* U+0DAB SINHALA MUURDHAJA NAYANNA */, + Sinh_ndda = 0x1000dac /* U+0DAC SINHALA SANYAKA DDAYANNA */, + Sinh_tha = 0x1000dad /* U+0DAD SINHALA TAYANNA */, + Sinh_thha = 0x1000dae /* U+0DAE SINHALA MAHA. TAYANNA */, + Sinh_dha = 0x1000daf /* U+0DAF SINHALA DAYANNA */, + Sinh_dhha = 0x1000db0 /* U+0DB0 SINHALA MAHA. DAYANNA */, + Sinh_na = 0x1000db1 /* U+0DB1 SINHALA DANTAJA NAYANNA */, + Sinh_ndha = 0x1000db3 /* U+0DB3 SINHALA SANYAKA DAYANNA */, + Sinh_pa = 0x1000db4 /* U+0DB4 SINHALA PAYANNA */, + Sinh_pha = 0x1000db5 /* U+0DB5 SINHALA MAHA. PAYANNA */, + Sinh_ba = 0x1000db6 /* U+0DB6 SINHALA BAYANNA */, + Sinh_bha = 0x1000db7 /* U+0DB7 SINHALA MAHA. BAYANNA */, + Sinh_ma = 0x1000db8 /* U+0DB8 SINHALA MAYANNA */, + Sinh_mba = 0x1000db9 /* U+0DB9 SINHALA AMBA BAYANNA */, + Sinh_ya = 0x1000dba /* U+0DBA SINHALA YAYANNA */, + Sinh_ra = 0x1000dbb /* U+0DBB SINHALA RAYANNA */, + Sinh_la = 0x1000dbd /* U+0DBD SINHALA DANTAJA LAYANNA */, + Sinh_va = 0x1000dc0 /* U+0DC0 SINHALA VAYANNA */, + Sinh_sha = 0x1000dc1 /* U+0DC1 SINHALA TAALUJA SAYANNA */, + Sinh_ssha = 0x1000dc2 /* U+0DC2 SINHALA MUURDHAJA SAYANNA */, + Sinh_sa = 0x1000dc3 /* U+0DC3 SINHALA DANTAJA SAYANNA */, + Sinh_ha = 0x1000dc4 /* U+0DC4 SINHALA HAYANNA */, + Sinh_lla = 0x1000dc5 /* U+0DC5 SINHALA MUURDHAJA LAYANNA */, + Sinh_fa = 0x1000dc6 /* U+0DC6 SINHALA FAYANNA */, + Sinh_al = 0x1000dca /* U+0DCA SINHALA AL-LAKUNA */, + Sinh_aa2 = 0x1000dcf /* U+0DCF SINHALA AELA-PILLA */, + Sinh_ae2 = 0x1000dd0 /* U+0DD0 SINHALA AEDA-PILLA */, + Sinh_aee2 = 0x1000dd1 /* U+0DD1 SINHALA DIGA AEDA-PILLA */, + Sinh_i2 = 0x1000dd2 /* U+0DD2 SINHALA IS-PILLA */, + Sinh_ii2 = 0x1000dd3 /* U+0DD3 SINHALA DIGA IS-PILLA */, + Sinh_u2 = 0x1000dd4 /* U+0DD4 SINHALA PAA-PILLA */, + Sinh_uu2 = 0x1000dd6 /* U+0DD6 SINHALA DIGA PAA-PILLA */, + Sinh_ru2 = 0x1000dd8 /* U+0DD8 SINHALA GAETTA-PILLA */, + Sinh_e2 = 0x1000dd9 /* U+0DD9 SINHALA KOMBUVA */, + Sinh_ee2 = 0x1000dda /* U+0DDA SINHALA DIGA KOMBUVA */, + Sinh_ai2 = 0x1000ddb /* U+0DDB SINHALA KOMBU DEKA */, + Sinh_o2 = 0x1000ddc /* U+0DDC SINHALA KOMBUVA HAA AELA-PILLA*/, + Sinh_oo2 = 0x1000ddd /* U+0DDD SINHALA KOMBUVA HAA DIGA AELA-PILLA*/, + Sinh_au2 = 0x1000dde /* U+0DDE SINHALA KOMBUVA HAA GAYANUKITTA */, + Sinh_lu2 = 0x1000ddf /* U+0DDF SINHALA GAYANUKITTA */, + Sinh_ruu2 = 0x1000df2 /* U+0DF2 SINHALA DIGA GAETTA-PILLA */, + Sinh_luu2 = 0x1000df3 /* U+0DF3 SINHALA DIGA GAYANUKITTA */, + Sinh_kunddaliya = 0x1000df4 /* U+0DF4 SINHALA KUNDDALIYA */ + } +} diff --git a/src/Avalonia.X11/X11Info.cs b/src/Avalonia.X11/X11Info.cs index 527cdc31ef..fece7c2ba2 100644 --- a/src/Avalonia.X11/X11Info.cs +++ b/src/Avalonia.X11/X11Info.cs @@ -16,6 +16,7 @@ namespace Avalonia.X11 public IntPtr DefaultRootWindow { get; } public IntPtr DefaultCursor { get; } public X11Atoms Atoms { get; } + public IntPtr Xim { get; } public IntPtr LastActivityTimestamp { get; set; } @@ -29,6 +30,9 @@ namespace Avalonia.X11 DefaultCursor = XCreateFontCursor(display, CursorFontShape.XC_arrow); DefaultRootWindow = XDefaultRootWindow(display); Atoms = new X11Atoms(display); + //TODO: Open an actual XIM once we get support for preedit in our textbox + XSetLocaleModifiers("@im=none"); + Xim = XOpenIM(display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); } } } diff --git a/src/Avalonia.X11/X11KeyTransform.cs b/src/Avalonia.X11/X11KeyTransform.cs new file mode 100644 index 0000000000..26495111d1 --- /dev/null +++ b/src/Avalonia.X11/X11KeyTransform.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using Avalonia.Input; + +namespace Avalonia.X11 +{ + static class X11KeyTransform + { + private static readonly Dictionary KeyDic = new Dictionary + { + {X11Key.Cancel, Key.Cancel}, + {X11Key.BackSpace, Key.Back}, + {X11Key.Tab, Key.Tab}, + {X11Key.Linefeed, Key.LineFeed}, + {X11Key.Clear, Key.Clear}, + {X11Key.Return, Key.Return}, + {X11Key.KP_Enter, Key.Return}, + {X11Key.Pause, Key.Pause}, + {X11Key.Caps_Lock, Key.CapsLock}, + //{ X11Key.?, Key.HangulMode } + //{ X11Key.?, Key.JunjaMode } + //{ X11Key.?, Key.FinalMode } + //{ X11Key.?, Key.KanjiMode } + {X11Key.Escape, Key.Escape}, + //{ X11Key.?, Key.ImeConvert } + //{ X11Key.?, Key.ImeNonConvert } + //{ X11Key.?, Key.ImeAccept } + //{ X11Key.?, Key.ImeModeChange } + {X11Key.space, Key.Space}, + {X11Key.Prior, Key.Prior}, + {X11Key.KP_Prior, Key.Prior}, + {X11Key.Page_Down, Key.PageDown}, + {X11Key.KP_Page_Down, Key.PageDown}, + {X11Key.End, Key.End}, + {X11Key.KP_End, Key.End}, + {X11Key.Home, Key.Home}, + {X11Key.KP_Home, Key.Home}, + {X11Key.Left, Key.Left}, + {X11Key.KP_Left, Key.Left}, + {X11Key.Up, Key.Up}, + {X11Key.KP_Up, Key.Up}, + {X11Key.Right, Key.Right}, + {X11Key.KP_Right, Key.Right}, + {X11Key.Down, Key.Down}, + {X11Key.KP_Down, Key.Down}, + {X11Key.Select, Key.Select}, + {X11Key.Print, Key.Print}, + {X11Key.Execute, Key.Execute}, + //{ X11Key.?, Key.Snapshot } + {X11Key.Insert, Key.Insert}, + {X11Key.KP_Insert, Key.Insert}, + {X11Key.Delete, Key.Delete}, + {X11Key.KP_Delete, Key.Delete}, + {X11Key.Help, Key.Help}, + {X11Key.XK_0, Key.D0}, + {X11Key.XK_1, Key.D1}, + {X11Key.XK_2, Key.D2}, + {X11Key.XK_3, Key.D3}, + {X11Key.XK_4, Key.D4}, + {X11Key.XK_5, Key.D5}, + {X11Key.XK_6, Key.D6}, + {X11Key.XK_7, Key.D7}, + {X11Key.XK_8, Key.D8}, + {X11Key.XK_9, Key.D9}, + {X11Key.A, Key.A}, + {X11Key.B, Key.B}, + {X11Key.C, Key.C}, + {X11Key.D, Key.D}, + {X11Key.E, Key.E}, + {X11Key.F, Key.F}, + {X11Key.G, Key.G}, + {X11Key.H, Key.H}, + {X11Key.I, Key.I}, + {X11Key.J, Key.J}, + {X11Key.K, Key.K}, + {X11Key.L, Key.L}, + {X11Key.M, Key.M}, + {X11Key.N, Key.N}, + {X11Key.O, Key.O}, + {X11Key.P, Key.P}, + {X11Key.Q, Key.Q}, + {X11Key.R, Key.R}, + {X11Key.S, Key.S}, + {X11Key.T, Key.T}, + {X11Key.U, Key.U}, + {X11Key.V, Key.V}, + {X11Key.W, Key.W}, + {X11Key.X, Key.X}, + {X11Key.Y, Key.Y}, + {X11Key.Z, Key.Z}, + {X11Key.a, Key.A}, + {X11Key.b, Key.B}, + {X11Key.c, Key.C}, + {X11Key.d, Key.D}, + {X11Key.e, Key.E}, + {X11Key.f, Key.F}, + {X11Key.g, Key.G}, + {X11Key.h, Key.H}, + {X11Key.i, Key.I}, + {X11Key.j, Key.J}, + {X11Key.k, Key.K}, + {X11Key.l, Key.L}, + {X11Key.m, Key.M}, + {X11Key.n, Key.N}, + {X11Key.o, Key.O}, + {X11Key.p, Key.P}, + {X11Key.q, Key.Q}, + {X11Key.r, Key.R}, + {X11Key.s, Key.S}, + {X11Key.t, Key.T}, + {X11Key.u, Key.U}, + {X11Key.v, Key.V}, + {X11Key.w, Key.W}, + {X11Key.x, Key.X}, + {X11Key.y, Key.Y}, + {X11Key.z, Key.Z}, + //{ X11Key.?, Key.LWin } + //{ X11Key.?, Key.RWin } + {X11Key.Menu, Key.Apps}, + //{ X11Key.?, Key.Sleep } + {X11Key.KP_0, Key.NumPad0}, + {X11Key.KP_1, Key.NumPad1}, + {X11Key.KP_2, Key.NumPad2}, + {X11Key.KP_3, Key.NumPad3}, + {X11Key.KP_4, Key.NumPad4}, + {X11Key.KP_5, Key.NumPad5}, + {X11Key.KP_6, Key.NumPad6}, + {X11Key.KP_7, Key.NumPad7}, + {X11Key.KP_8, Key.NumPad8}, + {X11Key.KP_9, Key.NumPad9}, + {X11Key.multiply, Key.Multiply}, + {X11Key.KP_Multiply, Key.Multiply}, + {X11Key.KP_Add, Key.Add}, + //{ X11Key.?, Key.Separator } + {X11Key.KP_Subtract, Key.Subtract}, + {X11Key.KP_Decimal, Key.Decimal}, + {X11Key.KP_Divide, Key.Divide}, + {X11Key.F1, Key.F1}, + {X11Key.F2, Key.F2}, + {X11Key.F3, Key.F3}, + {X11Key.F4, Key.F4}, + {X11Key.F5, Key.F5}, + {X11Key.F6, Key.F6}, + {X11Key.F7, Key.F7}, + {X11Key.F8, Key.F8}, + {X11Key.F9, Key.F9}, + {X11Key.F10, Key.F10}, + {X11Key.F11, Key.F11}, + {X11Key.F12, Key.F12}, + {X11Key.L3, Key.F13}, + {X11Key.F14, Key.F14}, + {X11Key.L5, Key.F15}, + {X11Key.F16, Key.F16}, + {X11Key.F17, Key.F17}, + {X11Key.L8, Key.F18}, + {X11Key.L9, Key.F19}, + {X11Key.L10, Key.F20}, + {X11Key.R1, Key.F21}, + {X11Key.R2, Key.F22}, + {X11Key.F23, Key.F23}, + {X11Key.R4, Key.F24}, + {X11Key.Num_Lock, Key.NumLock}, + {X11Key.Scroll_Lock, Key.Scroll}, + {X11Key.Shift_L, Key.LeftShift}, + {X11Key.Shift_R, Key.RightShift}, + {X11Key.Control_L, Key.LeftCtrl}, + {X11Key.Control_R, Key.RightCtrl}, + {X11Key.Alt_L, Key.LeftAlt}, + {X11Key.Alt_R, Key.RightAlt}, + //{ X11Key.?, Key.BrowserBack } + //{ X11Key.?, Key.BrowserForward } + //{ X11Key.?, Key.BrowserRefresh } + //{ X11Key.?, Key.BrowserStop } + //{ X11Key.?, Key.BrowserSearch } + //{ X11Key.?, Key.BrowserFavorites } + //{ X11Key.?, Key.BrowserHome } + //{ X11Key.?, Key.VolumeMute } + //{ X11Key.?, Key.VolumeDown } + //{ X11Key.?, Key.VolumeUp } + //{ X11Key.?, Key.MediaNextTrack } + //{ X11Key.?, Key.MediaPreviousTrack } + //{ X11Key.?, Key.MediaStop } + //{ X11Key.?, Key.MediaPlayPause } + //{ X11Key.?, Key.LaunchMail } + //{ X11Key.?, Key.SelectMedia } + //{ X11Key.?, Key.LaunchApplication1 } + //{ X11Key.?, Key.LaunchApplication2 } + {X11Key.semicolon, Key.OemSemicolon}, + {X11Key.plus, Key.OemPlus}, + {X11Key.equal, Key.OemPlus}, + {X11Key.comma, Key.OemComma}, + {X11Key.minus, Key.OemMinus}, + {X11Key.period, Key.OemPeriod}, + {X11Key.slash, Key.Oem2}, + {X11Key.grave, Key.OemTilde}, + //{ X11Key.?, Key.AbntC1 } + //{ X11Key.?, Key.AbntC2 } + {X11Key.bracketleft, Key.OemOpenBrackets}, + {X11Key.backslash, Key.OemPipe}, + {X11Key.bracketright, Key.OemCloseBrackets}, + {X11Key.apostrophe, Key.OemQuotes}, + //{ X11Key.?, Key.Oem8 } + //{ X11Key.?, Key.Oem102 } + //{ X11Key.?, Key.ImeProcessed } + //{ X11Key.?, Key.System } + //{ X11Key.?, Key.OemAttn } + //{ X11Key.?, Key.OemFinish } + //{ X11Key.?, Key.DbeHiragana } + //{ X11Key.?, Key.OemAuto } + //{ X11Key.?, Key.DbeDbcsChar } + //{ X11Key.?, Key.OemBackTab } + //{ X11Key.?, Key.Attn } + //{ X11Key.?, Key.DbeEnterWordRegisterMode } + //{ X11Key.?, Key.DbeEnterImeConfigureMode } + //{ X11Key.?, Key.EraseEof } + //{ X11Key.?, Key.Play } + //{ X11Key.?, Key.Zoom } + //{ X11Key.?, Key.NoName } + //{ X11Key.?, Key.DbeEnterDialogConversionMode } + //{ X11Key.?, Key.OemClear } + //{ X11Key.?, Key.DeadCharProcessed } + }; + + public static Key ConvertKey(IntPtr key) + { + var ikey = key.ToInt32(); + Key result; + return KeyDic.TryGetValue((X11Key)ikey, out result) ? result : Key.None; + } +} + +} diff --git a/src/Avalonia.X11/X11Structs.cs b/src/Avalonia.X11/X11Structs.cs index a18bd4be74..6d73975b39 100644 --- a/src/Avalonia.X11/X11Structs.cs +++ b/src/Avalonia.X11/X11Structs.cs @@ -72,7 +72,7 @@ namespace Avalonia.X11 { internal int y; internal int x_root; internal int y_root; - internal int state; + internal XModifierMask state; internal int keycode; internal bool same_screen; } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 523d4dae29..16907cfe1a 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -13,6 +13,8 @@ using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Threading; using static Avalonia.X11.XLib; +// ReSharper disable IdentifierTypo +// ReSharper disable StringLiteralTypo namespace Avalonia.X11 { unsafe class X11Window : IWindowImpl, IPopupImpl @@ -20,13 +22,14 @@ namespace Avalonia.X11 private readonly AvaloniaX11Platform _platform; private readonly bool _popup; private readonly X11Info _x11; - private readonly Action _eventHandler; private bool _invalidated; private XConfigureEvent? _configure; private IInputRoot _inputRoot; - private IMouseDevice _mouse; + private readonly IMouseDevice _mouse; + private readonly IKeyboardDevice _keyboard; private Point _position; private IntPtr _handle; + private IntPtr _xic; private IntPtr _renderHandle; private bool _mapped; @@ -34,7 +37,7 @@ namespace Avalonia.X11 { public RawInputEventArgs Event; } - private Queue _inputQueue = new Queue(); + private readonly Queue _inputQueue = new Queue(); private InputEventContainer _lastEvent; public X11Window(AvaloniaX11Platform platform, bool popup) @@ -43,7 +46,9 @@ namespace Avalonia.X11 _popup = popup; _x11 = platform.Info; _mouse = platform.MouseDevice; - + _keyboard = platform.KeyboardDevice; + _xic = XCreateIC(_x11.Xim, XNames.XNInputStyle, XIMProperties.XIMPreeditNothing | XIMProperties.XIMStatusNothing, + XNames.XNClientWindow, _handle, IntPtr.Zero); XSetWindowAttributes attr = new XSetWindowAttributes(); var valueMask = default(SetWindowValuemask); @@ -73,8 +78,7 @@ namespace Avalonia.X11 Handle = new PlatformHandle(_handle, "XID"); ClientSize = new Size(400, 400); - _eventHandler = OnEvent; - platform.Windows[_handle] = _eventHandler; + platform.Windows[_handle] = OnEvent; XSelectInput(_x11.Display, _handle, new IntPtr(0xffffff ^ (int)XEventMask.SubstructureRedirectMask @@ -145,12 +149,14 @@ namespace Avalonia.X11 decorations ^= MotifDecorations.Maximize | MotifDecorations.ResizeH; } - var hints = new MotifWmHints(); - hints.flags = new IntPtr((int)(MotifFlags.Decorations | MotifFlags.Functions)); + var hints = new MotifWmHints + { + flags = new IntPtr((int)(MotifFlags.Decorations | MotifFlags.Functions)), + decorations = new IntPtr((int)decorations), + functions = new IntPtr((int)functions) + }; + - hints.decorations = new IntPtr((int)decorations); - hints.functions = new IntPtr((int)functions); - XChangeProperty(_x11.Display, _handle, _x11.Atoms._MOTIF_WM_HINTS, _x11.Atoms._MOTIF_WM_HINTS, 32, PropertyMode.Replace, ref hints, 5); @@ -158,9 +164,11 @@ namespace Avalonia.X11 void UpdateSizeHits() { - var hints = new XSizeHints(); - hints.min_width = (int)_minMaxSize.minSize.Width; - hints.min_height = (int)_minMaxSize.minSize.Height; + var hints = new XSizeHints + { + min_width = (int)_minMaxSize.minSize.Width, + min_height = (int)_minMaxSize.minSize.Height + }; hints.height_inc = hints.width_inc = 1; var flags = XSizeHintsFlags.PMinSize | XSizeHintsFlags.PResizeInc; // People might be passing double.MaxValue @@ -196,8 +204,10 @@ namespace Avalonia.X11 public IRenderer CreateRenderer(IRenderRoot root) => new DeferredRenderer(root, AvaloniaLocator.Current.GetService()); - unsafe void OnEvent(XEvent ev) + void OnEvent(XEvent ev) { + if(XFilterEvent(ref ev, _handle)) + return; if (ev.type == XEventName.MapNotify) { _mapped = true; @@ -212,7 +222,7 @@ namespace Avalonia.X11 else if (ev.type == XEventName.FocusOut) Deactivated?.Invoke(); else if (ev.type == XEventName.MotionNotify) - MouseEvent(RawMouseEventType.Move, ev, ev.MotionEvent.state); + MouseEvent(RawMouseEventType.Move, ref ev, ev.MotionEvent.state); else if (ev.type == XEventName.PropertyNotify) { OnPropertyChange(ev.PropertyEvent.atom, ev.PropertyEvent.state == 0); @@ -222,7 +232,7 @@ namespace Avalonia.X11 if (ev.ButtonEvent.button < 4) MouseEvent(ev.ButtonEvent.button == 1 ? RawMouseEventType.LeftButtonDown : ev.ButtonEvent.button == 2 ? RawMouseEventType.MiddleButtonDown - : RawMouseEventType.RightButtonDown, ev, ev.ButtonEvent.state); + : RawMouseEventType.RightButtonDown, ref ev, ev.ButtonEvent.state); else { var delta = ev.ButtonEvent.button == 4 @@ -234,7 +244,7 @@ namespace Avalonia.X11 : new Vector(-1, 0); ScheduleInput(new RawMouseWheelEventArgs(_mouse, (ulong)ev.ButtonEvent.time.ToInt64(), _inputRoot, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), delta, - TranslateModifiers(ev.ButtonEvent.state))); + TranslateModifiers(ev.ButtonEvent.state)), ref ev); } } @@ -243,12 +253,13 @@ namespace Avalonia.X11 if (ev.ButtonEvent.button < 4) MouseEvent(ev.ButtonEvent.button == 1 ? RawMouseEventType.LeftButtonUp : ev.ButtonEvent.button == 2 ? RawMouseEventType.MiddleButtonUp - : RawMouseEventType.RightButtonUp, ev, ev.ButtonEvent.state); + : RawMouseEventType.RightButtonUp, ref ev, ev.ButtonEvent.state); } else if (ev.type == XEventName.ConfigureNotify) { var needEnqueue = (_configure == null); _configure = ev.ConfigureEvent; + Console.WriteLine($"{ev.ConfigureEvent.x} {ev.ConfigureEvent.y} {ev.ConfigureEvent.width} {ev.ConfigureEvent.height}"); if (needEnqueue) Dispatcher.UIThread.Post(() => { @@ -257,7 +268,9 @@ namespace Avalonia.X11 var cev = _configure.Value; _configure = null; var nsize = new Size(cev.width, cev.height); - var npos = new Point(cev.x, cev.y); + XTranslateCoordinates(_x11.Display, _handle, _x11.DefaultRootWindow, 0, 0, out var xret, + out var yret, out var _); + var npos = new Point(xret, yret); var changedSize = ClientSize != nsize; var changedPos = npos != _position; ClientSize = nsize; @@ -285,12 +298,37 @@ namespace Avalonia.X11 } } + else if (ev.type == XEventName.KeyPress || ev.type == XEventName.KeyRelease) + { + var buffer = stackalloc byte[40]; + + var latinKeysym = XKeycodeToKeysym(_x11.Display, ev.KeyEvent.keycode, 0); + ScheduleInput(new RawKeyEventArgs(_keyboard, (ulong)ev.KeyEvent.time.ToInt64(), + ev.type == XEventName.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp, + X11KeyTransform.ConvertKey(latinKeysym), TranslateModifiers(ev.KeyEvent.state)), ref ev); + + if (ev.type == XEventName.KeyPress) + { + var len = Xutf8LookupString(_xic, ref ev, buffer, 40, out _, out _); + if (len != 0) + { + var text = Encoding.UTF8.GetString(buffer, len); + if (text.Length == 1) + { + if (text[0] < ' ' || text[0] == 0x7f) //Control codes or DEL + return; + } + ScheduleInput(new RawTextInputEventArgs(_keyboard, (ulong)ev.KeyEvent.time.ToInt64(), text), + ref ev); + } + } + } } private WindowState _lastWindowState; public WindowState WindowState { - get { return _lastWindowState; } + get => _lastWindowState; set { _lastWindowState = value; @@ -322,7 +360,7 @@ namespace Avalonia.X11 { XGetWindowProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_STATE, IntPtr.Zero, new IntPtr(256), - false, (IntPtr)Atom.XA_ATOM, out var actualAtom, out var actualFormat, out var nitems, out var bytesAfter, + false, (IntPtr)Atom.XA_ATOM, out _, out _, out var nitems, out _, out var prop); int maximized = 0; var pitems = (IntPtr*)prop.ToPointer(); @@ -381,8 +419,9 @@ namespace Avalonia.X11 private bool _canResize = true; private (Size minSize, Size maxSize) _minMaxSize; - void ScheduleInput(RawInputEventArgs args) + void ScheduleInput(RawInputEventArgs args, ref XEvent xev) { + _x11.LastActivityTimestamp = xev.ButtonEvent.time; _lastEvent = new InputEventContainer() {Event = args}; _inputQueue.Enqueue(_lastEvent); if (_inputQueue.Count == 1) @@ -399,9 +438,8 @@ namespace Avalonia.X11 } } - void MouseEvent(RawMouseEventType type, XEvent ev, XModifierMask mods) + void MouseEvent(RawMouseEventType type, ref XEvent ev, XModifierMask mods) { - _x11.LastActivityTimestamp = ev.ButtonEvent.time; var mev = new RawMouseEventArgs( _mouse, (ulong)ev.ButtonEvent.time.ToInt64(), _inputRoot, type, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), TranslateModifiers(mods)); @@ -411,7 +449,7 @@ namespace Avalonia.X11 _lastEvent.Event = mev; return; } - ScheduleInput(mev); + ScheduleInput(mev, ref ev); } void DoPaint() @@ -448,6 +486,12 @@ namespace Avalonia.X11 void Cleanup() { + if (_xic != IntPtr.Zero) + { + XDestroyIC(_xic); + _xic = IntPtr.Zero; + } + if (_handle != IntPtr.Zero) { XDestroyWindow(_x11.Display, _handle); @@ -455,7 +499,7 @@ namespace Avalonia.X11 _handle = IntPtr.Zero; Closed?.Invoke(); } - + if (_renderHandle != IntPtr.Zero) { XDestroyWindow(_x11.Display, _renderHandle); @@ -484,9 +528,11 @@ namespace Avalonia.X11 { if (clientSize == ClientSize) return; - var changes = new XWindowChanges(); - changes.width = (int)clientSize.Width; - changes.height = (int)clientSize.Height; + var changes = new XWindowChanges + { + width = (int)clientSize.Width, + height = (int)clientSize.Height + }; var needResize = clientSize != ClientSize; XConfigureWindow(_x11.Display, _handle, ChangeWindowFlags.CWHeight | ChangeWindowFlags.CWWidth, ref changes); @@ -524,9 +570,11 @@ namespace Avalonia.X11 get => _position; set { - var changes = new XWindowChanges(); - changes.x = (int)value.X; - changes.y = (int)value.Y; + var changes = new XWindowChanges + { + x = (int)value.X, + y = (int)value.Y + }; XConfigureWindow(_x11.Display, _handle, ChangeWindowFlags.CWX | ChangeWindowFlags.CWY, ref changes); XFlush(_x11.Display); @@ -536,7 +584,7 @@ namespace Avalonia.X11 public IMouseDevice MouseDevice => _mouse; - public unsafe void Activate() + public void Activate() { if (_x11.Atoms._NET_ACTIVE_WINDOW != IntPtr.Zero) { @@ -559,18 +607,21 @@ namespace Avalonia.X11 void SendNetWMMessage(IntPtr message_type, IntPtr l0, IntPtr? l1 = null, IntPtr? l2 = null, IntPtr? l3 = null, IntPtr? l4 = null) { - XEvent xev; - - xev = new XEvent(); - xev.ClientMessageEvent.type = XEventName.ClientMessage; - xev.ClientMessageEvent.send_event = true; - xev.ClientMessageEvent.window = _handle; - xev.ClientMessageEvent.message_type = message_type; - xev.ClientMessageEvent.format = 32; - xev.ClientMessageEvent.ptr1 = l0; - xev.ClientMessageEvent.ptr2 = l1 ?? IntPtr.Zero; - xev.ClientMessageEvent.ptr3 = l2 ?? IntPtr.Zero; - xev.ClientMessageEvent.ptr4 = l3 ?? IntPtr.Zero; + var xev = new XEvent + { + ClientMessageEvent = + { + type = XEventName.ClientMessage, + send_event = true, + window = _handle, + message_type = message_type, + format = 32, + ptr1 = l0, + ptr2 = l1 ?? IntPtr.Zero, + ptr3 = l2 ?? IntPtr.Zero, + ptr4 = l3 ?? IntPtr.Zero + } + }; xev.ClientMessageEvent.ptr4 = l4 ?? IntPtr.Zero; XSendEvent(_x11.Display, _x11.RootWindow, false, new IntPtr((int)(EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev); diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index 0f27191f88..32f563b14b 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -402,6 +402,42 @@ namespace Avalonia.X11 [DllImport(libX11)] public static extern IntPtr XCreateColormap(IntPtr display, IntPtr window, IntPtr visual, int create); + public enum XLookupStatus + { + XBufferOverflow = -1, + XLookupNone = 1, + XLookupChars = 2, + XLookupKeySym = 3, + XLookupBoth = 4 + } + + [DllImport (libX11)] + public static extern unsafe int XLookupString(ref XEvent xevent, void* buffer, int num_bytes, out IntPtr keysym, out IntPtr status); + + [DllImport ("libX11")] + public static extern unsafe int Xutf8LookupString(IntPtr xic, ref XEvent xevent, void* buffer, int num_bytes, out IntPtr keysym, out IntPtr status); + + [DllImport (libX11)] + public static extern unsafe IntPtr XKeycodeToKeysym(IntPtr display, int keycode, int index); + + [DllImport (libX11)] + public static extern unsafe IntPtr XSetLocaleModifiers(string modifiers); + + [DllImport (libX11)] + public static extern IntPtr XOpenIM (IntPtr display, IntPtr rdb, IntPtr res_name, IntPtr res_class); + + [DllImport (libX11)] + public static extern IntPtr XCreateIC (IntPtr xim, string name, XIMProperties im_style, string name2, IntPtr value2, IntPtr terminator); + + [DllImport (libX11)] + public static extern IntPtr XCreateIC (IntPtr xim, string name, XIMProperties im_style, string name2, IntPtr value2, string name3, IntPtr value3, IntPtr terminator); + + [DllImport (libX11)] + public static extern void XCloseIM (IntPtr xim); + + [DllImport (libX11)] + public static extern void XDestroyIC (IntPtr xic); + public struct XGeometry { public IntPtr root; From 666f779cfff8812092b83ac59204795fce25de9e Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 8 Nov 2018 22:10:31 +0300 Subject: [PATCH 11/46] [X11] Removed debug line --- src/Avalonia.X11/X11Window.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 16907cfe1a..f4d62b268b 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -259,7 +259,6 @@ namespace Avalonia.X11 { var needEnqueue = (_configure == null); _configure = ev.ConfigureEvent; - Console.WriteLine($"{ev.ConfigureEvent.x} {ev.ConfigureEvent.y} {ev.ConfigureEvent.width} {ev.ConfigureEvent.height}"); if (needEnqueue) Dispatcher.UIThread.Post(() => { From 00bab51c700f2c08fc9c35aae07a53d17e301ed5 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 8 Nov 2018 22:10:53 +0300 Subject: [PATCH 12/46] Call XFlush after XMapWindow --- src/Avalonia.X11/X11Window.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index f4d62b268b..71c9c980f8 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -507,7 +507,11 @@ namespace Avalonia.X11 } - public void Show() => XMapWindow(_x11.Display, _handle); + public void Show() + { + XMapWindow(_x11.Display, _handle); + XFlush(_x11.Display); + } public void Hide() => XUnmapWindow(_x11.Display, _handle); From 4993e0d3225aa3b6ff91d01ff3f5490ff4cdfdd7 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 8 Nov 2018 22:33:09 +0300 Subject: [PATCH 13/46] [X11] Reference Avalonia package --- src/Avalonia.X11/Avalonia.X11.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Avalonia.X11/Avalonia.X11.csproj b/src/Avalonia.X11/Avalonia.X11.csproj index 3f61961571..62771d847b 100644 --- a/src/Avalonia.X11/Avalonia.X11.csproj +++ b/src/Avalonia.X11/Avalonia.X11.csproj @@ -6,8 +6,7 @@ - - + From 97faa23d384819ab982970d8ccd1617d44abcc2f Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 9 Nov 2018 12:22:22 +0300 Subject: [PATCH 14/46] [X11] Fixed references and update to new API --- .../ControlCatalog.NetCore.csproj | 4 +--- src/Avalonia.Desktop/Avalonia.Desktop.csproj | 2 +- src/Avalonia.X11/Avalonia.X11.csproj | 2 +- src/Avalonia.X11/X11Framebuffer.cs | 18 ++++++++---------- src/Avalonia.X11/X11Window.cs | 4 ++-- 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj index 0c47c6728e..589f41c06b 100644 --- a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj +++ b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj @@ -6,12 +6,10 @@ - - - + diff --git a/src/Avalonia.Desktop/Avalonia.Desktop.csproj b/src/Avalonia.Desktop/Avalonia.Desktop.csproj index 3fc20150a7..52fee8a291 100644 --- a/src/Avalonia.Desktop/Avalonia.Desktop.csproj +++ b/src/Avalonia.Desktop/Avalonia.Desktop.csproj @@ -1,6 +1,6 @@ - netstandard2.0 + netstandard2.0 diff --git a/src/Avalonia.X11/Avalonia.X11.csproj b/src/Avalonia.X11/Avalonia.X11.csproj index 62771d847b..681eb0a2be 100644 --- a/src/Avalonia.X11/Avalonia.X11.csproj +++ b/src/Avalonia.X11/Avalonia.X11.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Avalonia.X11/X11Framebuffer.cs b/src/Avalonia.X11/X11Framebuffer.cs index 2d6955f47a..8e48a4089a 100644 --- a/src/Avalonia.X11/X11Framebuffer.cs +++ b/src/Avalonia.X11/X11Framebuffer.cs @@ -13,12 +13,11 @@ namespace Avalonia.X11 { _display = display; _xid = xid; - Width = width*factor; - Height = height*factor; - RowBytes = Width * 4; + Size = new PixelSize(width * factor, height * factor); + RowBytes = width * 4; Dpi = new Vector(96, 96) * factor; Format = PixelFormat.Bgra8888; - _blob = AvaloniaLocator.Current.GetService().AllocBlob(RowBytes * Height); + _blob = AvaloniaLocator.Current.GetService().AllocBlob(RowBytes * height); Address = _blob.Address; } @@ -26,8 +25,8 @@ namespace Avalonia.X11 { var image = new XImage(); int bitsPerPixel = 32; - image.width = Width; - image.height = Height; + image.width = Size.Width; + image.height = Size.Height; image.format = 2; //ZPixmap; image.data = Address; image.byte_order = 0;// LSBFirst; @@ -35,12 +34,12 @@ namespace Avalonia.X11 image.bitmap_bit_order = 0;// LSBFirst; image.bitmap_pad = bitsPerPixel; image.depth = 24; - image.bytes_per_line = RowBytes - Width * 4; + image.bytes_per_line = RowBytes - Size.Width * 4; image.bits_per_pixel = bitsPerPixel; XLockDisplay(_display); XInitImage(ref image); var gc = XCreateGC(_display, _xid, 0, IntPtr.Zero); - XPutImage(_display, _xid, gc, ref image, 0, 0, 0, 0, (uint) Width, (uint) Height); + XPutImage(_display, _xid, gc, ref image, 0, 0, 0, 0, (uint) Size.Width, (uint) Size.Height); XFreeGC(_display, gc); XSync(_display, true); XUnlockDisplay(_display); @@ -48,8 +47,7 @@ namespace Avalonia.X11 } public IntPtr Address { get; } - public int Width { get; } - public int Height { get; } + public PixelSize Size { get; } public int RowBytes { get; } public Vector Dpi { get; } public PixelFormat Format { get; } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 71c9c980f8..4b7b7fc8e1 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -116,7 +116,7 @@ namespace Avalonia.X11 } public IntPtr Handle { get; } - public System.Drawing.Size PixelSize + public PixelSize Size { get { @@ -126,7 +126,7 @@ namespace Avalonia.X11 XFlush(_display); XSync(_display, true); XUnlockDisplay(_display); - return new System.Drawing.Size(geo.width, geo.height); + return new PixelSize(geo.width, geo.height); } } From e184f8bfc44b98c7003daa571a8ad8402efa577c Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 9 Nov 2018 12:22:32 +0300 Subject: [PATCH 15/46] Fixed sln file --- Avalonia.sln | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/Avalonia.sln b/Avalonia.sln index 6e265e7298..7f46379038 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -178,8 +178,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.UnitTests", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.OpenGL", "src\Avalonia.OpenGL\Avalonia.OpenGL.csproj", "{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Native", "src\Avalonia.Native\Avalonia.Native.csproj", "{12A91A62-C064-42CA-9A8C-A1272F354388}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesktopRuntime", "src\Avalonia.DesktopRuntime\Avalonia.DesktopRuntime.csproj", "{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Packages", "Packages", "{E870DCD7-F46A-498D-83FC-D0FD13E0A11C}" @@ -189,7 +187,9 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.X11", "src\Avalonia.X11\Avalonia.X11.csproj", "{212D02D5-C873-469A-8E78-4A6350EC4A1A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlatformSanityChecks", "samples\PlatformSanityChecks\PlatformSanityChecks.csproj", "{8B5768BB-71F9-4E23-89B5-DDBA6458B856}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Native", "src\Avalonia.Native\Avalonia.Native.csproj", "{12A91A62-C064-42CA-9A8C-A1272F354388}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Desktop", "src\Avalonia.Desktop\Avalonia.Desktop.csproj", "{3C471044-3640-45E3-B1B2-16D2FF8399EE}" EndProject Global @@ -1643,30 +1643,6 @@ Global {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|iPhone.Build.0 = Release|Any CPU {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhone.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|Any CPU.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhone.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|Any CPU.ActiveCfg = Release|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|Any CPU.Build.0 = Release|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhone.ActiveCfg = Release|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhone.Build.0 = Release|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU From 4bde2c464067cf77ad86b6a55f1ad16564663dbe Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 9 Nov 2018 12:26:04 +0300 Subject: [PATCH 16/46] [X11] Fixed references --- .../PlatformSanityChecks.csproj | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/samples/PlatformSanityChecks/PlatformSanityChecks.csproj b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj index 00b5b10106..2adef5f64e 100644 --- a/samples/PlatformSanityChecks/PlatformSanityChecks.csproj +++ b/samples/PlatformSanityChecks/PlatformSanityChecks.csproj @@ -6,19 +6,8 @@ - - - + - - - - - - - - - From a29d74fb9891cc99605716c8d22a807893f30103 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 9 Nov 2018 17:26:05 +0300 Subject: [PATCH 17/46] [X11] Implemented clipboard support --- src/Avalonia.X11/Stubs.cs | 21 --- src/Avalonia.X11/X11Atoms.cs | 5 + src/Avalonia.X11/X11Clipboard.cs | 235 +++++++++++++++++++++++++++++++ src/Avalonia.X11/X11Platform.cs | 2 +- src/Avalonia.X11/XLib.cs | 13 ++ 5 files changed, 254 insertions(+), 22 deletions(-) create mode 100644 src/Avalonia.X11/X11Clipboard.cs diff --git a/src/Avalonia.X11/Stubs.cs b/src/Avalonia.X11/Stubs.cs index 6dda7b81ca..f70c7fee25 100644 --- a/src/Avalonia.X11/Stubs.cs +++ b/src/Avalonia.X11/Stubs.cs @@ -9,27 +9,6 @@ using Avalonia.Platform; namespace Avalonia.X11 { - class ClipboardStub : IClipboard - { - private string _text; - public Task GetTextAsync() - { - return Task.FromResult(_text); - } - - public Task SetTextAsync(string text) - { - _text = text; - return Task.CompletedTask; - } - - public Task ClearAsync() - { - _text = null; - return Task.CompletedTask; - } - } - class PlatformSettingsStub : IPlatformSettings { public Size DoubleClickSize { get; } = new Size(2, 2); diff --git a/src/Avalonia.X11/X11Atoms.cs b/src/Avalonia.X11/X11Atoms.cs index 51a4fc52f0..5c418c032b 100644 --- a/src/Avalonia.X11/X11Atoms.cs +++ b/src/Avalonia.X11/X11Atoms.cs @@ -172,11 +172,16 @@ namespace Avalonia.X11 { public readonly IntPtr _NET_WM_WINDOW_TYPE_DIALOG; public readonly IntPtr _NET_WM_WINDOW_TYPE_NORMAL; public readonly IntPtr CLIPBOARD; + public readonly IntPtr CLIPBOARD_MANAGER; + public readonly IntPtr SAVE_TARGETS; + public readonly IntPtr MULTIPLE; public readonly IntPtr PRIMARY; public readonly IntPtr OEMTEXT; public readonly IntPtr UNICODETEXT; public readonly IntPtr TARGETS; public readonly IntPtr UTF8_STRING; + public readonly IntPtr UTF16_STRING; + public readonly IntPtr ATOM_PAIR; public X11Atoms (IntPtr display) { diff --git a/src/Avalonia.X11/X11Clipboard.cs b/src/Avalonia.X11/X11Clipboard.cs new file mode 100644 index 0000000000..74d26d1d08 --- /dev/null +++ b/src/Avalonia.X11/X11Clipboard.cs @@ -0,0 +1,235 @@ +using System; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Input.Platform; +using static Avalonia.X11.XLib; +namespace Avalonia.X11 +{ + class X11Clipboard : IClipboard + { + private readonly X11Info _x11; + private string _storedString; + private IntPtr _handle; + private TaskCompletionSource _requestedFormatsTcs; + private TaskCompletionSource _requestedTextTcs; + private readonly IntPtr[] _textAtoms; + private readonly IntPtr _avaloniaSaveTargetsAtom; + + public X11Clipboard(AvaloniaX11Platform platform) + { + _x11 = platform.Info; + _handle = XCreateSimpleWindow(_x11.Display, _x11.DefaultRootWindow, 0, 0, 1, 1, 0, IntPtr.Zero, IntPtr.Zero); + _avaloniaSaveTargetsAtom = XInternAtom(_x11.Display, "AVALONIA_SAVE_TARGETS_PROPERTY_ATOM", false); + platform.Windows[_handle] = OnEvent; + _textAtoms = new[] + { + _x11.Atoms.XA_STRING, + _x11.Atoms.OEMTEXT, + _x11.Atoms.UTF8_STRING, + _x11.Atoms.UTF16_STRING + }.Where(a => a != IntPtr.Zero).ToArray(); + } + + Encoding GetStringEncoding(IntPtr atom) + { + return (atom == _x11.Atoms.XA_STRING + || atom == _x11.Atoms.OEMTEXT) + ? Encoding.ASCII + : atom == _x11.Atoms.UTF8_STRING + ? Encoding.UTF8 + : atom == _x11.Atoms.UTF16_STRING + ? Encoding.Unicode + : null; + } + + private unsafe void OnEvent(XEvent ev) + { + if (ev.type == XEventName.SelectionRequest) + { + var sel = ev.SelectionRequestEvent; + var resp = new XEvent + { + SelectionEvent = + { + type = XEventName.SelectionNotify, + send_event = true, + display = _x11.Display, + selection = sel.selection, + target = sel.target, + requestor = sel.requestor, + time = sel.time, + property = IntPtr.Zero + } + }; + if (sel.selection == _x11.Atoms.CLIPBOARD) + { + resp.SelectionEvent.property = WriteTargetToProperty(sel.target, sel.requestor, sel.property); + } + + XSendEvent(_x11.Display, sel.requestor, false, new IntPtr((int)EventMask.NoEventMask), ref resp); + } + + IntPtr WriteTargetToProperty(IntPtr target, IntPtr window, IntPtr property) + { + Encoding textEnc; + if (target == _x11.Atoms.TARGETS) + { + var atoms = _textAtoms; + atoms = atoms.Concat(new[] {_x11.Atoms.TARGETS, _x11.Atoms.MULTIPLE}) + .ToArray(); + XChangeProperty(_x11.Display, window, property, + target, 32, PropertyMode.Replace, atoms, atoms.Length); + return property; + } + else if(target == _x11.Atoms.SAVE_TARGETS && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero) + { + return property; + } + else if ((textEnc = GetStringEncoding(target)) != null) + { + + var data = textEnc.GetBytes(_storedString ?? ""); + fixed (void* pdata = data) + XChangeProperty(_x11.Display, window, property, target, 8, + PropertyMode.Replace, + pdata, data.Length); + return property; + } + else if (target == _x11.Atoms.MULTIPLE && _x11.Atoms.MULTIPLE != IntPtr.Zero) + { + XGetWindowProperty(_x11.Display, window, property, IntPtr.Zero, new IntPtr(0x7fffffff), false, + _x11.Atoms.ATOM_PAIR, out _, out var actualFormat, out var nitems, out _, out var prop); + if (nitems == IntPtr.Zero) + return IntPtr.Zero; + if (actualFormat == 32) + { + var data = (IntPtr*)prop.ToPointer(); + for (var c = 0; c < nitems.ToInt32(); c += 2) + { + var subTarget = data[c]; + var subProp = data[c + 1]; + var converted = WriteTargetToProperty(subTarget, window, subProp); + data[c + 1] = converted; + } + + XChangeProperty(_x11.Display, window, property, _x11.Atoms.ATOM_PAIR, 32, PropertyMode.Replace, + prop.ToPointer(), nitems.ToInt32()); + } + + XFree(prop); + + return property; + } + else + return IntPtr.Zero; + } + + if (ev.type == XEventName.SelectionNotify && ev.SelectionEvent.selection == _x11.Atoms.CLIPBOARD) + { + var sel = ev.SelectionEvent; + if (sel.property == IntPtr.Zero) + { + _requestedFormatsTcs?.TrySetResult(null); + _requestedTextTcs?.TrySetResult(null); + } + XGetWindowProperty(_x11.Display, _handle, sel.property, IntPtr.Zero, new IntPtr (0x7fffffff), true, (IntPtr)Atom.AnyPropertyType, + out var actualAtom, out var actualFormat, out var nitems, out var bytes_after, out var prop); + Encoding textEnc = null; + if (nitems == IntPtr.Zero) + { + _requestedFormatsTcs?.TrySetResult(null); + _requestedTextTcs?.TrySetResult(null); + } + else + { + if (sel.property == _x11.Atoms.TARGETS) + { + if (actualFormat != 32) + _requestedFormatsTcs?.TrySetResult(null); + else + { + var formats = new IntPtr[nitems.ToInt32()]; + Marshal.Copy(prop, formats, 0, formats.Length); + _requestedFormatsTcs?.TrySetResult(formats); + } + } + else if ((textEnc = GetStringEncoding(sel.property)) != null) + { + var text = textEnc.GetString((byte*)prop.ToPointer(), nitems.ToInt32()); + _requestedTextTcs?.TrySetResult(text); + } + } + + XFree(prop); + } + } + + Task SendFormatRequest() + { + if (_requestedFormatsTcs == null || _requestedFormatsTcs.Task.IsCompleted) + _requestedFormatsTcs = new TaskCompletionSource(); + XConvertSelection(_x11.Display, _x11.Atoms.CLIPBOARD, _x11.Atoms.TARGETS, _x11.Atoms.TARGETS, _handle, + IntPtr.Zero); + return _requestedFormatsTcs.Task; + } + + Task SendTextRequest(IntPtr format) + { + if (_requestedTextTcs == null || _requestedFormatsTcs.Task.IsCompleted) + _requestedTextTcs = new TaskCompletionSource(); + XConvertSelection(_x11.Display, _x11.Atoms.CLIPBOARD, format, format, _handle, IntPtr.Zero); + return _requestedTextTcs.Task; + } + + public async Task GetTextAsync() + { + if (XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD) == IntPtr.Zero) + return null; + var res = await SendFormatRequest(); + var target = _x11.Atoms.UTF8_STRING; + if (res != null) + { + var preferredFormats = new[] {_x11.Atoms.UTF16_STRING, _x11.Atoms.UTF8_STRING, _x11.Atoms.XA_STRING}; + foreach (var pf in preferredFormats) + if (res.Contains(pf)) + { + target = pf; + break; + } + } + + return await SendTextRequest(target); + } + + void StoreAtomsInClipboardManager(IntPtr[] atoms) + { + if (_x11.Atoms.CLIPBOARD_MANAGER != IntPtr.Zero && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero) + { + var clipboardManager = XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD_MANAGER); + if (clipboardManager != IntPtr.Zero) + { + XChangeProperty(_x11.Display, _handle, _avaloniaSaveTargetsAtom, _x11.Atoms.XA_ATOM, 32, + PropertyMode.Replace, + atoms, atoms.Length); + XConvertSelection(_x11.Display, _x11.Atoms.CLIPBOARD_MANAGER, _x11.Atoms.SAVE_TARGETS, + _avaloniaSaveTargetsAtom, _handle, IntPtr.Zero); + } + } + } + + public Task SetTextAsync(string text) + { + _storedString = text; + XSetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD, _handle, IntPtr.Zero); + StoreAtomsInClipboardManager(_textAtoms); + return Task.CompletedTask; + } + + public Task ClearAsync() + { + return SetTextAsync(null); + } + } +} diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index b3ffc2a30b..cce5299843 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -37,7 +37,7 @@ namespace Avalonia.X11 .Bind().ToConstant(new PlatformHotkeyConfiguration(InputModifiers.Control)) .Bind().ToFunc(() => KeyboardDevice) .Bind().ToConstant(new X11CursorFactory(Display)) - .Bind().ToSingleton() + .Bind().ToConstant(new X11Clipboard(this)) .Bind().ToConstant(new PlatformSettingsStub()) .Bind().ToConstant(new SystemDialogsStub()) .Bind().ToConstant(new IconLoaderStub()); diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index 32f563b14b..7f9233c252 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -117,6 +117,19 @@ namespace Avalonia.X11 [DllImport(libX11)] public static extern int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms); + + [DllImport(libX11)] + public static extern IntPtr XGetAtomName(IntPtr display, IntPtr atom); + + public static string GetAtomName(IntPtr display, IntPtr atom) + { + var ptr = XGetAtomName(display, atom); + if (ptr == IntPtr.Zero) + return null; + var s = Marshal.PtrToStringAnsi(ptr); + XFree(ptr); + return s; + } [DllImport(libX11)] public static extern int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count); From 276b88161e7cc72c277687f211adaeaed633aed1 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 20 Dec 2018 23:04:23 +0300 Subject: [PATCH 18/46] [X11] Support for the new dialogs API --- src/Avalonia.X11/X11Window.cs | 43 +++++++++++++++++++++++++++++++---- src/Avalonia.X11/XLib.cs | 2 +- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 4b7b7fc8e1..7a05bc896d 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -32,6 +32,8 @@ namespace Avalonia.X11 private IntPtr _xic; private IntPtr _renderHandle; private bool _mapped; + private HashSet _transientChildren = new HashSet(); + private X11Window _transientParent; class InputEventContainer { @@ -218,7 +220,11 @@ namespace Avalonia.X11 else if (ev.type == XEventName.Expose) DoPaint(); else if (ev.type == XEventName.FocusIn) + { + if (ActivateTransientChildIfNeeded()) + return; Activated?.Invoke(); + } else if (ev.type == XEventName.FocusOut) Deactivated?.Invoke(); else if (ev.type == XEventName.MotionNotify) @@ -229,6 +235,8 @@ namespace Avalonia.X11 } else if (ev.type == XEventName.ButtonPress) { + if (ActivateTransientChildIfNeeded()) + return; if (ev.ButtonEvent.button < 4) MouseEvent(ev.ButtonEvent.button == 1 ? RawMouseEventType.LeftButtonDown : ev.ButtonEvent.button == 2 ? RawMouseEventType.MiddleButtonDown @@ -299,6 +307,8 @@ namespace Avalonia.X11 } else if (ev.type == XEventName.KeyPress || ev.type == XEventName.KeyRelease) { + if (ActivateTransientChildIfNeeded()) + return; var buffer = stackalloc byte[40]; var latinKeysym = XKeycodeToKeysym(_x11.Display, ev.KeyEvent.keycode, 0); @@ -485,6 +495,7 @@ namespace Avalonia.X11 void Cleanup() { + SetTransientParent(null, false); if (_xic != IntPtr.Zero) { XDestroyIC(_xic); @@ -505,9 +516,33 @@ namespace Avalonia.X11 _renderHandle = IntPtr.Zero; } } + + bool ActivateTransientChildIfNeeded() + { + if (_transientChildren.Count == 0) + return false; + var child = _transientChildren.First(); + if (!child.ActivateTransientChildIfNeeded()) + child.Activate(); + return true; + } - + void SetTransientParent(X11Window window, bool informServer = true) + { + _transientParent?._transientChildren.Remove(this); + _transientParent = window; + _transientParent?._transientChildren.Add(this); + if (informServer) + XSetTransientForHint(_x11.Display, _handle, _transientParent?._handle ?? IntPtr.Zero); + } + public void Show() + { + SetTransientParent(null); + ShowCore(); + } + + void ShowCore() { XMapWindow(_x11.Display, _handle); XFlush(_x11.Display); @@ -690,10 +725,10 @@ namespace Avalonia.X11 (IntPtr)(value ? 1 : 0), _x11.Atoms._NET_WM_STATE_ABOVE, IntPtr.Zero); } - public IDisposable ShowDialog() + public void ShowDialog(IWindowImpl parent) { - // TODO - return Disposable.Empty; + SetTransientParent((X11Window)parent); + ShowCore(); } public void SetIcon(IWindowIconImpl icon) diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index 7f9233c252..89eab88966 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -203,7 +203,7 @@ namespace Avalonia.X11 public static extern int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def); [DllImport(libX11)] - public static extern int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window); + public static extern int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr parent); [DllImport(libX11)] public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, From 08b50a6830219677ecdb415080352ae0ecc3f237 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 10 Jan 2019 00:59:29 +0300 Subject: [PATCH 19/46] [X11] Get screen info (including scale factor) via RANDR 1.5 --- samples/ControlCatalog.NetCore/Program.cs | 2 +- src/Avalonia.X11/Avalonia.X11.csproj | 2 +- src/Avalonia.X11/Stubs.cs | 8 - src/Avalonia.X11/X11Info.cs | 23 ++ src/Avalonia.X11/X11Platform.cs | 1 + src/Avalonia.X11/X11Screens.cs | 254 ++++++++++++++++++++++ src/Avalonia.X11/X11Structs.cs | 52 ++++- src/Avalonia.X11/X11Window.cs | 4 +- src/Avalonia.X11/XLib.cs | 19 +- 9 files changed, 351 insertions(+), 14 deletions(-) create mode 100644 src/Avalonia.X11/X11Screens.cs diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs index 57c8b700df..2a7d0b30a9 100644 --- a/samples/ControlCatalog.NetCore/Program.cs +++ b/samples/ControlCatalog.NetCore/Program.cs @@ -43,7 +43,7 @@ namespace ControlCatalog.NetCore /// This method is needed for IDE previewer infrastructure /// public static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure().UsePlatformDetect().UseSkia().UseReactiveUI(); + => AppBuilder.Configure().UsePlatformDetect().UseSkia().UseReactiveUI().UseX11(); static void ConsoleSilencer() { diff --git a/src/Avalonia.X11/Avalonia.X11.csproj b/src/Avalonia.X11/Avalonia.X11.csproj index 681eb0a2be..3e75180468 100644 --- a/src/Avalonia.X11/Avalonia.X11.csproj +++ b/src/Avalonia.X11/Avalonia.X11.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 diff --git a/src/Avalonia.X11/Stubs.cs b/src/Avalonia.X11/Stubs.cs index f70c7fee25..91d788c576 100644 --- a/src/Avalonia.X11/Stubs.cs +++ b/src/Avalonia.X11/Stubs.cs @@ -63,12 +63,4 @@ namespace Avalonia.X11 return new FakeIcon(ms.ToArray()); } } - - class ScreenStub : IScreenImpl - { - public int ScreenCount { get; } = 1; - - public Screen[] AllScreens { get; } = - {new Screen(new Rect(0, 0, 1920, 1280), new Rect(0, 0, 1920, 1280), true)}; - } } diff --git a/src/Avalonia.X11/X11Info.cs b/src/Avalonia.X11/X11Info.cs index fece7c2ba2..e102283f87 100644 --- a/src/Avalonia.X11/X11Info.cs +++ b/src/Avalonia.X11/X11Info.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; +using JetBrains.Annotations; using static Avalonia.X11.XLib; // ReSharper disable UnusedAutoPropertyAccessor.Local namespace Avalonia.X11 @@ -17,6 +18,12 @@ namespace Avalonia.X11 public IntPtr DefaultCursor { get; } public X11Atoms Atoms { get; } public IntPtr Xim { get; } + + public int RandrEventBase { get; } + public int RandrErrorBase { get; } + + public Version RandrVersion { get; } + public IntPtr LastActivityTimestamp { get; set; } @@ -33,6 +40,22 @@ namespace Avalonia.X11 //TODO: Open an actual XIM once we get support for preedit in our textbox XSetLocaleModifiers("@im=none"); Xim = XOpenIM(display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + + try + { + if (XRRQueryExtension(display, out int randrEventBase, out var randrErrorBase) != 0) + { + RandrEventBase = randrEventBase; + RandrErrorBase = randrErrorBase; + if (XRRQueryVersion(display, out var major, out var minor) != 0) + RandrVersion = new Version(major, minor); + } + } + catch + { + //Ignore, randr is not supported + } + } } } diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index cce5299843..d315ba5ffb 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -41,6 +41,7 @@ namespace Avalonia.X11 .Bind().ToConstant(new PlatformSettingsStub()) .Bind().ToConstant(new SystemDialogsStub()) .Bind().ToConstant(new IconLoaderStub()); + X11Screens.Init(this); EglGlPlatformFeature.TryInitialize(); } diff --git a/src/Avalonia.X11/X11Screens.cs b/src/Avalonia.X11/X11Screens.cs new file mode 100644 index 0000000000..4a9cbe98a4 --- /dev/null +++ b/src/Avalonia.X11/X11Screens.cs @@ -0,0 +1,254 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Runtime.InteropServices; +using Avalonia.Platform; +using static Avalonia.X11.XLib; +using JetBrains.Annotations; + +namespace Avalonia.X11 +{ + class X11Screens : IScreenImpl + { + private IX11Screens _impl; + + private X11Screens(IX11Screens impl) + { + _impl = impl; + } + + static unsafe X11Screen[] UpdateWorkArea(X11Info info, X11Screen[] screens) + { + var rect = default(Rect); + foreach (var s in screens) + { + rect = rect.Union(s.Bounds); + //Fallback value + s.WorkingArea = s.Bounds; + } + + var res = XGetWindowProperty(info.Display, + info.RootWindow, + info.Atoms._NET_WORKAREA, + IntPtr.Zero, + new IntPtr(128), + false, + info.Atoms.AnyPropertyType, + out var type, + out var format, + out var count, + out var bytesAfter, + out var prop); + + if (res != (int)Status.Success || type == IntPtr.Zero || + format == 0 || bytesAfter.ToInt64() != 0 || count.ToInt64() % 4 != 0) + return screens; + + var pwa = (IntPtr*)prop; + var wa = new Rect(pwa[0].ToInt32(), pwa[1].ToInt32(), pwa[2].ToInt32(), pwa[3].ToInt32()); + + + foreach (var s in screens) + s.WorkingArea = s.Bounds.Intersect(wa); + + XFree(prop); + return screens; + } + + class Randr15ScreensImpl : IX11Screens + { + private readonly X11ScreensUserSettings _settings; + private X11Screen[] _cache; + private X11Info _x11; + private IntPtr _window; + + public Randr15ScreensImpl(AvaloniaX11Platform platform, X11ScreensUserSettings settings) + { + _settings = settings; + _x11 = platform.Info; + _window = XCreateSimpleWindow(_x11.Display, _x11.DefaultRootWindow, 0, 0, 1, 1, 0, IntPtr.Zero, IntPtr.Zero); + platform.Windows[_window] = OnEvent; + XRRSelectInput(_x11.Display, _window, RandrEventMask.RRScreenChangeNotify); + } + + private void OnEvent(XEvent ev) + { + // Invalidate cache on RRScreenChangeNotify + if ((int)ev.type == _x11.RandrEventBase + (int)RandrEvent.RRScreenChangeNotify) + _cache = null; + } + + public unsafe X11Screen[] Screens + { + get + { + if (_cache != null) + return _cache; + var monitors = XRRGetMonitors(_x11.Display, _window, true, out var count); + + var screens = new X11Screen[count]; + for (var c = 0; c < count; c++) + { + var mon = monitors[c]; + var namePtr = XGetAtomName(_x11.Display, mon.Name); + var name = Marshal.PtrToStringAnsi(namePtr); + XFree(namePtr); + + var density = 1d; + if (_settings.NamedScaleFactors?.TryGetValue(name, out density) != true) + { + if (mon.MWidth == 0) + density = 1; + else + density = X11Screen.GuessPixelDensity(mon.Width, mon.MWidth); + } + + density *= _settings.GlobalScaleFactor; + + var bounds = new Rect(mon.X, mon.Y, mon.Width, mon.Height); + screens[0] = new X11Screen(bounds, + mon.Primary != 0, + name, + (mon.MWidth == 0 || mon.MHeight == 0) ? (Size?)null : new Size(mon.MWidth, mon.MHeight), + density); + } + + XFree(new IntPtr(monitors)); + _cache = UpdateWorkArea(_x11, screens); + return screens; + } + } + } + + class FallbackScreensImpl : IX11Screens + { + public FallbackScreensImpl(X11Info info, X11ScreensUserSettings settings) + { + if (XGetGeometry(info.Display, info.RootWindow, out var geo)) + { + + Screens = UpdateWorkArea(info, + new[] + { + new X11Screen(new Rect(0, 0, geo.width, geo.height), true, "Default", null, + settings.GlobalScaleFactor) + }); + } + + Screens = new[] {new X11Screen(new Rect(0, 0, 1920, 1280), true, "Default", null, settings.GlobalScaleFactor)}; + } + + public X11Screen[] Screens { get; } + } + + public static void Init(AvaloniaX11Platform platform) + { + var info = platform.Info; + var settings = X11ScreensUserSettings.Detect(); + var impl = (info.RandrVersion != null && info.RandrVersion >= new Version(1, 5)) + ? new Randr15ScreensImpl(platform, settings) + : (IX11Screens)new FallbackScreensImpl(info, settings); + + AvaloniaLocator.CurrentMutable.Bind().ToConstant(impl); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(new X11Screens(impl)); + + } + + + public int ScreenCount => _impl.Screens.Length; + + public Screen[] AllScreens => + _impl.Screens.Select(s => new Screen(s.Bounds, s.WorkingArea, s.Primary)).ToArray(); + } + + interface IX11Screens + { + X11Screen[] Screens { get; } + } + + class X11ScreensUserSettings + { + public double GlobalScaleFactor { get; set; } = 1; + public Dictionary NamedScaleFactors { get; set; } + + static double? TryParse(string s) + { + if (s == null) + return null; + if (double.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out var rv)) + return rv; + return null; + } + + + public static X11ScreensUserSettings DetectEnvironment() + { + var globalFactor = Environment.GetEnvironmentVariable("AVALONIA_GLOBAL_SCALE_FACTOR"); + var screenFactors = Environment.GetEnvironmentVariable("AVALONIA_SCREEN_SCALE_FACTORS"); + if (globalFactor == null && screenFactors == null) + return null; + + var rv = new X11ScreensUserSettings + { + GlobalScaleFactor = TryParse(globalFactor) ?? 1 + }; + + try + { + if (!string.IsNullOrWhiteSpace(screenFactors)) + { + rv.NamedScaleFactors = screenFactors.Split(';').Where(x => !string.IsNullOrWhiteSpace(x)) + .Select(x => x.Split('=')).ToDictionary(x => x[0], + x => double.Parse(x[1], CultureInfo.InvariantCulture)); + } + } + catch + { + //Ignore + } + + return null; + } + + + public static X11ScreensUserSettings Detect() + { + return DetectEnvironment() ?? new X11ScreensUserSettings(); + } + } + + class X11Screen + { + public bool Primary { get; } + public string Name { get; set; } + public Rect Bounds { get; set; } + public Size? PhysicalSize { get; set; } + public double PixelDensity { get; set; } + public Rect WorkingArea { get; set; } + + public X11Screen(Rect bounds, bool primary, + string name, Size? physicalSize, double? pixelDensity) + { + Primary = primary; + Name = name; + Bounds = bounds; + if (physicalSize == null && pixelDensity == null) + { + PixelDensity = 1; + } + else if (pixelDensity == null) + { + PixelDensity = GuessPixelDensity(bounds.Width, physicalSize.Value.Width); + } + else + { + PixelDensity = pixelDensity.Value; + PhysicalSize = physicalSize; + } + } + + public static double GuessPixelDensity(double pixelWidth, double mmWidth) + => Math.Max(1, Math.Round(pixelWidth / mmWidth * 25.4 / 96)); + } +} diff --git a/src/Avalonia.X11/X11Structs.cs b/src/Avalonia.X11/X11Structs.cs index 6d73975b39..fc1bb01b6e 100644 --- a/src/Avalonia.X11/X11Structs.cs +++ b/src/Avalonia.X11/X11Structs.cs @@ -849,7 +849,43 @@ namespace Avalonia.X11 { OwnerGrabButtonMask = 1<<24 } - internal enum GrabMode { + [Flags] + internal enum RandrEventMask + { + RRScreenChangeNotify = 1 << 0, + +/* V1.2 additions */ + RRCrtcChangeNotifyMask = 1 << 1, + RROutputChangeNotifyMask = 1 << 2, + RROutputPropertyNotifyMask = 1 << 3, + +/* V1.4 additions */ + RRProviderChangeNotifyMask = 1 << 4, + RRProviderPropertyNotifyMask = 1 << 5, + RRResourceChangeNotifyMask = 1 << 6, + +/* V1.6 additions */ + RRLeaseNotifyMask = 1 << 7 + } + + internal enum RandrEvent + { + RRScreenChangeNotify = 0, + + /* V1.2 additions */ + RRNotify = 1 + } + + internal enum RandrRotate + { + /* used in the rotation field; rotation and reflection in 0.1 proto. */ + RR_Rotate_0 = 1, + RR_Rotate_90 = 2, + RR_Rotate_180 = 4, + RR_Rotate_270 = 8 + } + + internal enum GrabMode { GrabModeSync = 0, GrabModeAsync = 1 } @@ -1812,4 +1848,18 @@ namespace Avalonia.X11 { public const string XNSpotLocation = "spotLocation"; public const string XNFontSet = "fontSet"; } + + struct XRRMonitorInfo { + public IntPtr Name; + public int Primary; + public int Automatic; + public int NOutput; + public int X; + public int Y; + public int Width; + public int Height; + public int MWidth; + public int MHeight; + public IntPtr Outputs; + } } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 7a05bc896d..3212123238 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -636,8 +636,8 @@ namespace Avalonia.X11 } } - - public IScreenImpl Screen { get; } = new ScreenStub(); + + public IScreenImpl Screen { get; } = AvaloniaLocator.CurrentMutable.GetService(); public Size MaxClientSize { get; } = new Size(1920, 1280); diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index 89eab88966..1688d69f4f 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -14,7 +14,8 @@ namespace Avalonia.X11 { internal unsafe static class XLib { - const string libX11 = "X11"; + const string libX11 = "libX11.so.6"; + const string libX11Randr = "libXrandr.so.2"; [DllImport(libX11)] public static extern IntPtr XOpenDisplay(IntPtr display); @@ -451,6 +452,22 @@ namespace Avalonia.X11 [DllImport (libX11)] public static extern void XDestroyIC (IntPtr xic); + [DllImport(libX11Randr)] + public static extern int XRRQueryExtension (IntPtr dpy, + out int event_base_return, + out int error_base_return); + + [DllImport(libX11Randr)] + public static extern int XRRQueryVersion(IntPtr dpy, + out int major_version_return, + out int minor_version_return); + + [DllImport(libX11Randr)] + public static extern XRRMonitorInfo* + XRRGetMonitors(IntPtr dpy, IntPtr window, bool get_active, out int nmonitors); + [DllImport(libX11Randr)] + public static extern void XRRSelectInput(IntPtr dpy, IntPtr window, RandrEventMask mask); + public struct XGeometry { public IntPtr root; From 35c0fcdf6a266e3b9098c0ce4dd121f8ee0df0a3 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 12 Jan 2019 20:44:09 +0000 Subject: [PATCH 20/46] temporary allow pr build to publish --- azure-pipelines.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fd40118888..39333f37ba 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -92,13 +92,13 @@ jobs: inputs: pathToPublish: '$(Build.SourcesDirectory)/Build/Products/Release/' artifactName: 'Avalonia.Native.OSX' - condition: and(succeeded(), eq(variables['system.pullrequest.isfork'], false)) + condition: succeeded() - task: PublishBuildArtifacts@1 inputs: pathtoPublish: '$(Build.SourcesDirectory)/artifacts/nuget' artifactName: 'NuGetOSX' - condition: and(succeeded(), eq(variables['system.pullrequest.isfork'], false)) + condition: succeeded() - job: Windows pool: @@ -127,10 +127,10 @@ jobs: inputs: pathtoPublish: '$(Build.SourcesDirectory)/artifacts/nuget' artifactName: 'NuGet' - condition: and(succeeded(), eq(variables['system.pullrequest.isfork'], false)) + condition: succeeded() - task: PublishBuildArtifacts@1 inputs: pathToPublish: '$(Build.SourcesDirectory)/artifacts/zip' artifactName: 'Samples' - condition: and(succeeded(), eq(variables['system.pullrequest.isfork'], false)) + condition: succeeded() From 24a0592890fdec3689f7d7beaa2569fe9301bb33 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sun, 13 Jan 2019 21:51:43 +0300 Subject: [PATCH 21/46] Added XI2 support for mouse events (smooth scrolling!) --- src/Avalonia.X11/X11Clipboard.cs | 2 +- src/Avalonia.X11/X11Info.cs | 26 ++- src/Avalonia.X11/X11Platform.cs | 9 +- src/Avalonia.X11/X11PlatformThreading.cs | 32 ++- src/Avalonia.X11/X11Screens.cs | 3 +- src/Avalonia.X11/X11Structs.cs | 27 ++- src/Avalonia.X11/X11Window.cs | 25 +- src/Avalonia.X11/XI2Manager.cs | 269 +++++++++++++++++++++ src/Avalonia.X11/XIStructs.cs | 283 +++++++++++++++++++++++ src/Avalonia.X11/XLib.cs | 70 ++++++ 10 files changed, 726 insertions(+), 20 deletions(-) create mode 100644 src/Avalonia.X11/XI2Manager.cs create mode 100644 src/Avalonia.X11/XIStructs.cs diff --git a/src/Avalonia.X11/X11Clipboard.cs b/src/Avalonia.X11/X11Clipboard.cs index 74d26d1d08..55eb4b563e 100644 --- a/src/Avalonia.X11/X11Clipboard.cs +++ b/src/Avalonia.X11/X11Clipboard.cs @@ -20,9 +20,9 @@ namespace Avalonia.X11 public X11Clipboard(AvaloniaX11Platform platform) { _x11 = platform.Info; + _handle = CreateEventWindow(platform, OnEvent); _handle = XCreateSimpleWindow(_x11.Display, _x11.DefaultRootWindow, 0, 0, 1, 1, 0, IntPtr.Zero, IntPtr.Zero); _avaloniaSaveTargetsAtom = XInternAtom(_x11.Display, "AVALONIA_SAVE_TARGETS_PROPERTY_ATOM", false); - platform.Windows[_handle] = OnEvent; _textAtoms = new[] { _x11.Atoms.XA_STRING, diff --git a/src/Avalonia.X11/X11Info.cs b/src/Avalonia.X11/X11Info.cs index e102283f87..53da9e0cf3 100644 --- a/src/Avalonia.X11/X11Info.cs +++ b/src/Avalonia.X11/X11Info.cs @@ -24,6 +24,11 @@ namespace Avalonia.X11 public Version RandrVersion { get; } + public int XInputOpcode { get; } + public int XInputEventBase { get; } + public int XInputErrorBase { get; } + + public Version XInputVersion { get; } public IntPtr LastActivityTimestamp { get; set; } @@ -55,7 +60,26 @@ namespace Avalonia.X11 { //Ignore, randr is not supported } - + + try + { + if (XQueryExtension(display, "XInputExtension", + out var xiopcode, out var xievent, out var xierror)) + { + int major = 2, minor = 2; + if (XIQueryVersion(display, ref major, ref minor) == Status.Success) + { + XInputVersion = new Version(major, minor); + XInputOpcode = xiopcode; + XInputEventBase = xievent; + XInputErrorBase = xierror; + } + } + } + catch + { + //Ignore, XI is not supported + } } } } diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index d315ba5ffb..79aef75e4c 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -18,6 +18,7 @@ namespace Avalonia.X11 public KeyboardDevice KeyboardDevice => _keyboardDevice.Value; public MouseDevice MouseDevice => _mouseDevice.Value; public Dictionary> Windows = new Dictionary>(); + public XI2Manager XI2; public X11Info Info { get; private set; } public void Initialize() { @@ -31,7 +32,7 @@ namespace Avalonia.X11 AvaloniaLocator.CurrentMutable.BindToSelf(this) .Bind().ToConstant(this) - .Bind().ToConstant(new X11PlatformThreading(Display, Windows)) + .Bind().ToConstant(new X11PlatformThreading(this)) .Bind().ToConstant(new DefaultRenderTimer(60)) .Bind().ToConstant(new RenderLoop()) .Bind().ToConstant(new PlatformHotkeyConfiguration(InputModifiers.Control)) @@ -42,6 +43,12 @@ namespace Avalonia.X11 .Bind().ToConstant(new SystemDialogsStub()) .Bind().ToConstant(new IconLoaderStub()); X11Screens.Init(this); + if (Info.XInputVersion != null) + { + var xi2 = new XI2Manager(); + if (xi2.Init(this)) + XI2 = xi2; + } EglGlPlatformFeature.TryInitialize(); } diff --git a/src/Avalonia.X11/X11PlatformThreading.cs b/src/Avalonia.X11/X11PlatformThreading.cs index 298b4da19c..5736500262 100644 --- a/src/Avalonia.X11/X11PlatformThreading.cs +++ b/src/Avalonia.X11/X11PlatformThreading.cs @@ -11,6 +11,7 @@ namespace Avalonia.X11 { unsafe class X11PlatformThreading : IPlatformThreadingInterface { + private readonly AvaloniaX11Platform _platform; private readonly IntPtr _display; private readonly Dictionary> _eventHandlers; private Thread _mainThread; @@ -103,12 +104,13 @@ namespace Avalonia.X11 List _timers = new List(); - public X11PlatformThreading(IntPtr display, Dictionary> eventHandlers) + public X11PlatformThreading(AvaloniaX11Platform platform) { - _display = display; - _eventHandlers = eventHandlers; + _platform = platform; + _display = platform.Display; + _eventHandlers = platform.Windows; _mainThread = Thread.CurrentThread; - var fd = XLib.XConnectionNumber(display); + var fd = XLib.XConnectionNumber(_display); var ev = new epoll_event() { events = EPOLLIN, @@ -214,9 +216,27 @@ namespace Avalonia.X11 if (cancellationToken.IsCancellationRequested) return; XNextEvent(_display, out var xev); + if (xev.type == XEventName.GenericEvent) + XGetEventData(_display, &xev.GenericEventCookie); pending--; - if (_eventHandlers.TryGetValue(xev.AnyEvent.window, out var handler)) - handler(xev); + try + { + if (xev.type == XEventName.GenericEvent) + { + if (_platform.XI2 != null && _platform.Info.XInputOpcode == + xev.GenericEventCookie.extension) + { + _platform.XI2.OnEvent((XIEvent*)xev.GenericEventCookie.data); + } + } + else if (_eventHandlers.TryGetValue(xev.AnyEvent.window, out var handler)) + handler(xev); + } + finally + { + if (xev.type == XEventName.GenericEvent && xev.GenericEventCookie.data != null) + XFreeEventData(_display, &xev.GenericEventCookie); + } } } Dispatcher.UIThread.RunJobs(); diff --git a/src/Avalonia.X11/X11Screens.cs b/src/Avalonia.X11/X11Screens.cs index 4a9cbe98a4..46ad4d7320 100644 --- a/src/Avalonia.X11/X11Screens.cs +++ b/src/Avalonia.X11/X11Screens.cs @@ -67,8 +67,7 @@ namespace Avalonia.X11 { _settings = settings; _x11 = platform.Info; - _window = XCreateSimpleWindow(_x11.Display, _x11.DefaultRootWindow, 0, 0, 1, 1, 0, IntPtr.Zero, IntPtr.Zero); - platform.Windows[_window] = OnEvent; + _window = CreateEventWindow(platform, OnEvent); XRRSelectInput(_x11.Display, _window, RandrEventMask.RRScreenChangeNotify); } diff --git a/src/Avalonia.X11/X11Structs.cs b/src/Avalonia.X11/X11Structs.cs index fc1bb01b6e..0ae5c16aef 100644 --- a/src/Avalonia.X11/X11Structs.cs +++ b/src/Avalonia.X11/X11Structs.cs @@ -133,7 +133,7 @@ namespace Avalonia.X11 { internal NotifyDetail detail; internal bool same_screen; internal bool focus; - internal int state; + internal XModifierMask state; } [StructLayout(LayoutKind.Sequential)] @@ -520,7 +520,27 @@ namespace Avalonia.X11 { internal IntPtr pad23; } - [StructLayout(LayoutKind.Explicit)] + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct XGenericEventCookie + { + internal int type; /* of event. Always GenericEvent */ + internal IntPtr serial; /* # of last request processed */ + internal bool send_event; /* true if from SendEvent request */ + internal IntPtr display; /* Display the event was read from */ + internal int extension; /* major opcode of extension that caused the event */ + internal int evtype; /* actual event type. */ + internal uint cookie; + internal void* data; + + public T GetEvent() where T : unmanaged + { + if (data == null) + throw new InvalidOperationException(); + return *(T*)data; + } + } + + [StructLayout(LayoutKind.Explicit)] internal struct XEvent { [ FieldOffset(0) ] internal XEventName type; [ FieldOffset(0) ] internal XAnyEvent AnyEvent; @@ -554,6 +574,7 @@ namespace Avalonia.X11 { [ FieldOffset(0) ] internal XMappingEvent MappingEvent; [ FieldOffset(0) ] internal XErrorEvent ErrorEvent; [ FieldOffset(0) ] internal XKeymapEvent KeymapEvent; + [ FieldOffset(0) ] internal XGenericEventCookie GenericEventCookie; //[MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=24)] //[ FieldOffset(0) ] internal int[] pad; @@ -738,7 +759,7 @@ namespace Avalonia.X11 { ColormapNotify = 32, ClientMessage = 33, MappingNotify = 34, - + GenericEvent = 35, LASTEvent } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 3212123238..4441006fda 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -17,7 +17,7 @@ using static Avalonia.X11.XLib; // ReSharper disable StringLiteralTypo namespace Avalonia.X11 { - unsafe class X11Window : IWindowImpl, IPopupImpl + unsafe class X11Window : IWindowImpl, IPopupImpl, IXI2Client { private readonly AvaloniaX11Platform _platform; private readonly bool _popup; @@ -81,11 +81,13 @@ namespace Avalonia.X11 Handle = new PlatformHandle(_handle, "XID"); ClientSize = new Size(400, 400); platform.Windows[_handle] = OnEvent; - XSelectInput(_x11.Display, _handle, - new IntPtr(0xffffff - ^ (int)XEventMask.SubstructureRedirectMask - ^ (int)XEventMask.ResizeRedirectMask - ^ (int)XEventMask.PointerMotionHintMask)); + XEventMask ignoredMask = XEventMask.SubstructureRedirectMask + | XEventMask.ResizeRedirectMask + | XEventMask.PointerMotionHintMask; + if (platform.XI2 != null) + ignoredMask |= platform.XI2.AddWindow(_handle, this); + var mask = new IntPtr(0xffffff ^ (int)ignoredMask); + XSelectInput(_x11.Display, _handle, mask); var protocols = new[] { _x11.Atoms.WM_DELETE_WINDOW @@ -229,6 +231,8 @@ namespace Avalonia.X11 Deactivated?.Invoke(); else if (ev.type == XEventName.MotionNotify) MouseEvent(RawMouseEventType.Move, ref ev, ev.MotionEvent.state); + else if (ev.type == XEventName.LeaveNotify) + MouseEvent(RawMouseEventType.LeaveWindow, ref ev, ev.CrossingEvent.state); else if (ev.type == XEventName.PropertyNotify) { OnPropertyChange(ev.PropertyEvent.atom, ev.PropertyEvent.state == 0); @@ -431,6 +435,12 @@ namespace Avalonia.X11 void ScheduleInput(RawInputEventArgs args, ref XEvent xev) { _x11.LastActivityTimestamp = xev.ButtonEvent.time; + ScheduleInput(args); + } + + public void ScheduleInput(RawInputEventArgs args) + { + _lastEvent = new InputEventContainer() {Event = args}; _inputQueue.Enqueue(_lastEvent); if (_inputQueue.Count == 1) @@ -479,6 +489,8 @@ namespace Avalonia.X11 }); } + public IInputRoot InputRoot => _inputRoot; + public void SetInputRoot(IInputRoot inputRoot) { _inputRoot = inputRoot; @@ -506,6 +518,7 @@ namespace Avalonia.X11 { XDestroyWindow(_x11.Display, _handle); _platform.Windows.Remove(_handle); + _platform.XI2?.OnWindowDestroyed(_handle); _handle = IntPtr.Zero; Closed?.Invoke(); } diff --git a/src/Avalonia.X11/XI2Manager.cs b/src/Avalonia.X11/XI2Manager.cs new file mode 100644 index 0000000000..ee73ccc907 --- /dev/null +++ b/src/Avalonia.X11/XI2Manager.cs @@ -0,0 +1,269 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using Avalonia.Input; +using Avalonia.Input.Raw; +using static Avalonia.X11.XLib; +namespace Avalonia.X11 +{ + unsafe class XI2Manager + { + private X11Info _x11; + private Dictionary _clients = new Dictionary(); + class DeviceInfo + { + public int Id { get; } + public XIValuatorClassInfo[] Valuators { get; private set; } + public XIScrollClassInfo[] Scrollers { get; private set; } + public DeviceInfo(XIDeviceInfo info) + { + Id = info.Deviceid; + Update(info.Classes, info.NumClasses); + } + + public virtual void Update(XIAnyClassInfo** classes, int num) + { + var valuators = new List(); + var scrollers = new List(); + for (var c = 0; c < num; c++) + { + if (classes[c]->Type == XiDeviceClass.XIValuatorClass) + valuators.Add(*((XIValuatorClassInfo**)classes)[c]); + if (classes[c]->Type == XiDeviceClass.XIScrollClass) + scrollers.Add(*((XIScrollClassInfo**)classes)[c]); + } + + Valuators = valuators.ToArray(); + Scrollers = scrollers.ToArray(); + } + + public void UpdateValuators(Dictionary valuators) + { + foreach (var v in valuators) + { + if (Valuators.Length > v.Key) + Valuators[v.Key].Value = v.Value; + } + } + } + + class PointerDeviceInfo : DeviceInfo + { + public PointerDeviceInfo(XIDeviceInfo info) : base(info) + { + } + + public bool HasScroll(ParsedDeviceEvent ev) + { + foreach (var val in ev.Valuators) + if (Scrollers.Any(s => s.Number == val.Key)) + return true; + + return false; + } + + public bool HasMotion(ParsedDeviceEvent ev) + { + foreach (var val in ev.Valuators) + if (Scrollers.All(s => s.Number != val.Key)) + return true; + + return false; + } + + } + + private PointerDeviceInfo _pointerDevice; + private AvaloniaX11Platform _platform; + + public bool Init(AvaloniaX11Platform platform) + { + _platform = platform; + _x11 = platform.Info; + var devices =(XIDeviceInfo*) XIQueryDevice(_x11.Display, + (int)XiPredefinedDeviceId.XIAllMasterDevices, out int num); + for (var c = 0; c < num; c++) + { + if (devices[c].Use == XiDeviceType.XIMasterPointer) + { + _pointerDevice = new PointerDeviceInfo(devices[c]); + break; + } + } + if(_pointerDevice == null) + return false; + /* + int mask = 0; + + XISetMask(ref mask, XiEventType.XI_DeviceChanged); + var emask = new XIEventMask + { + Mask = &mask, + Deviceid = _pointerDevice.Id, + MaskLen = XiEventMaskLen + }; + + if (XISelectEvents(_x11.Display, _x11.RootWindow, &emask, 1) != Status.Success) + return false; + return true; + */ + return XiSelectEvents(_x11.Display, _x11.RootWindow, new Dictionary> + { + [_pointerDevice.Id] = new List + { + XiEventType.XI_DeviceChanged + } + }) == Status.Success; + } + + public XEventMask AddWindow(IntPtr xid, IXI2Client window) + { + _clients[xid] = window; + + XiSelectEvents(_x11.Display, xid, new Dictionary> + { + [_pointerDevice.Id] = new List() + { + XiEventType.XI_Motion, + XiEventType.XI_ButtonPress, + XiEventType.XI_ButtonRelease, + } + }); + + // We are taking over mouse input handling from here + return XEventMask.PointerMotionMask + | XEventMask.ButtonMotionMask + | XEventMask.Button1MotionMask + | XEventMask.Button2MotionMask + | XEventMask.Button3MotionMask + | XEventMask.Button4MotionMask + | XEventMask.Button5MotionMask + | XEventMask.ButtonPressMask + | XEventMask.ButtonReleaseMask; + } + + public void OnWindowDestroyed(IntPtr xid) => _clients.Remove(xid); + + public void OnEvent(XIEvent* xev) + { + if (xev->evtype == XiEventType.XI_DeviceChanged) + { + var changed = (XIDeviceChangedEvent*)xev; + _pointerDevice.Update(changed->Classes, changed->NumClasses); + } + + //TODO: this should only be used for non-touch devices + if (xev->evtype >= XiEventType.XI_ButtonPress && xev->evtype <= XiEventType.XI_Motion) + { + var dev = (XIDeviceEvent*)xev; + if (_clients.TryGetValue(dev->EventWindow, out var client)) + OnDeviceEvent(client, new ParsedDeviceEvent(dev)); + } + } + + void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev) + { + if (ev.Type == XiEventType.XI_Motion) + { + Vector scrollDelta = default; + foreach (var v in ev.Valuators) + { + foreach (var scroller in _pointerDevice.Scrollers) + { + if (scroller.Number == v.Key) + { + var old = _pointerDevice.Valuators[scroller.Number].Value; + // Value was zero after reset, ignore the event and use it as a reference next time + if (old == 0) + continue; + var diff = (old - v.Value) / scroller.Increment; + if (scroller.ScrollType == XiScrollType.Horizontal) + scrollDelta = scrollDelta.WithX(scrollDelta.X + diff); + else + scrollDelta = scrollDelta.WithY(scrollDelta.Y + diff); + + } + } + + + } + + if (scrollDelta != default) + client.ScheduleInput(new RawMouseWheelEventArgs(_platform.MouseDevice, ev.Timestamp, + client.InputRoot, ev.Position, scrollDelta, ev.Modifiers)); + if (_pointerDevice.HasMotion(ev)) + client.ScheduleInput(new RawMouseEventArgs(_platform.MouseDevice, ev.Timestamp, client.InputRoot, + RawMouseEventType.Move, ev.Position, ev.Modifiers)); + } + + if (ev.Type == XiEventType.XI_ButtonPress || ev.Type == XiEventType.XI_ButtonRelease) + { + var down = ev.Type == XiEventType.XI_ButtonPress; + var type = + ev.Button == 1 ? (down ? RawMouseEventType.LeftButtonDown : RawMouseEventType.LeftButtonUp) + : ev.Button == 2 ? (down ? RawMouseEventType.MiddleButtonDown : RawMouseEventType.MiddleButtonUp) + : ev.Button == 3 ? (down ? RawMouseEventType.RightButtonDown : RawMouseEventType.RightButtonUp) + : (RawMouseEventType?)null; + if (type.HasValue) + client.ScheduleInput(new RawMouseEventArgs(_platform.MouseDevice, ev.Timestamp, client.InputRoot, + type.Value, ev.Position, ev.Modifiers)); + } + + _pointerDevice.UpdateValuators(ev.Valuators); + } + } + + unsafe class ParsedDeviceEvent + { + public XiEventType Type { get; } + public InputModifiers Modifiers { get; } + public ulong Timestamp { get; } + public Point Position { get; } + public int Button { get; set; } + public Dictionary Valuators { get; } + public ParsedDeviceEvent(XIDeviceEvent* ev) + { + Type = ev->evtype; + Timestamp = (ulong)ev->time.ToInt64(); + var state = (XModifierMask)ev->mods.Effective; + if (state.HasFlag(XModifierMask.ShiftMask)) + Modifiers |= InputModifiers.Shift; + if (state.HasFlag(XModifierMask.ControlMask)) + Modifiers |= InputModifiers.Control; + if (state.HasFlag(XModifierMask.Mod1Mask)) + Modifiers |= InputModifiers.Alt; + if (state.HasFlag(XModifierMask.Mod4Mask)) + Modifiers |= InputModifiers.Windows; + + if (ev->buttons.MaskLen > 0) + { + var buttons = ev->buttons.Mask; + if (XIMaskIsSet(buttons, 1)) + Modifiers |= InputModifiers.LeftMouseButton; + + if (XIMaskIsSet(buttons, 2)) + Modifiers |= InputModifiers.MiddleMouseButton; + + if (XIMaskIsSet(buttons, 3)) + Modifiers |= InputModifiers.RightMouseButton; + } + + Valuators = new Dictionary(); + Position = new Point(ev->event_x, ev->event_y); + var values = ev->valuators.Values; + for (var c = 0; c < ev->valuators.MaskLen * 8; c++) + if (XIMaskIsSet(ev->valuators.Mask, c)) + Valuators[c] = *values++; + if (Type == XiEventType.XI_ButtonPress || Type == XiEventType.XI_ButtonRelease) + Button = ev->detail; + } + } + + interface IXI2Client + { + IInputRoot InputRoot { get; } + void ScheduleInput(RawInputEventArgs args); + } +} diff --git a/src/Avalonia.X11/XIStructs.cs b/src/Avalonia.X11/XIStructs.cs new file mode 100644 index 0000000000..772bd1989c --- /dev/null +++ b/src/Avalonia.X11/XIStructs.cs @@ -0,0 +1,283 @@ +using System; +using System.Runtime.InteropServices; +using Bool = System.Boolean; +using Atom = System.IntPtr; +// ReSharper disable IdentifierTypo +// ReSharper disable FieldCanBeMadeReadOnly.Global +// ReSharper disable MemberCanBePrivate.Global +#pragma warning disable 649 + +namespace Avalonia.X11 +{ + [StructLayout(LayoutKind.Sequential)] + struct XIAddMasterInfo + { + public int Type; + public IntPtr Name; + public Bool SendCore; + public Bool Enable; + } + + [StructLayout(LayoutKind.Sequential)] + struct XIRemoveMasterInfo + { + public int Type; + public int Deviceid; + public int ReturnMode; /* AttachToMaster, Floating */ + public int ReturnPointer; + public int ReturnKeyboard; + }; + + [StructLayout(LayoutKind.Sequential)] + struct XIAttachSlaveInfo + { + public int Type; + public int Deviceid; + public int NewMaster; + }; + + [StructLayout(LayoutKind.Sequential)] + struct XIDetachSlaveInfo + { + public int Type; + public int Deviceid; + }; + + [StructLayout(LayoutKind.Explicit)] + struct XIAnyHierarchyChangeInfo + { + [FieldOffset(0)] + public int type; /* must be first element */ + [FieldOffset(4)] + public XIAddMasterInfo add; + [FieldOffset(4)] + public XIRemoveMasterInfo remove; + [FieldOffset(4)] + public XIAttachSlaveInfo attach; + [FieldOffset(4)] + public XIDetachSlaveInfo detach; + }; + + [StructLayout(LayoutKind.Sequential)] + struct XIModifierState + { + public int Base; + public int Latched; + public int Locked; + public int Effective; + }; + + [StructLayout(LayoutKind.Sequential)] + unsafe struct XIButtonState + { + public int MaskLen; + public byte* Mask; + }; + + [StructLayout(LayoutKind.Sequential)] + unsafe struct XIValuatorState + { + public int MaskLen; + public byte* Mask; + public double* Values; + }; + + [StructLayout(LayoutKind.Sequential)] + unsafe struct XIEventMask + { + public int Deviceid; + public int MaskLen; + public int* Mask; + }; + + [StructLayout(LayoutKind.Sequential)] + struct XIAnyClassInfo + { + public XiDeviceClass Type; + public int Sourceid; + }; + + [StructLayout(LayoutKind.Sequential)] + unsafe struct XIButtonClassInfo + { + public int Type; + public int Sourceid; + public int NumButtons; + public IntPtr* Labels; + public XIButtonState State; + }; + + [StructLayout(LayoutKind.Sequential)] + unsafe struct XIKeyClassInfo + { + public int Type; + public int Sourceid; + public int NumKeycodes; + public int* Keycodes; + }; + + [StructLayout(LayoutKind.Sequential)] + struct XIValuatorClassInfo + { + public int Type; + public int Sourceid; + public int Number; + public IntPtr Label; + public double Min; + public double Max; + public double Value; + public int Resolution; + public int Mode; + }; + +/* new in XI 2.1 */ + [StructLayout(LayoutKind.Sequential)] + struct XIScrollClassInfo + { + public int Type; + public int Sourceid; + public int Number; + public XiScrollType ScrollType; + public double Increment; + public int Flags; + }; + + enum XiScrollType + { + Vertical = 1, + Horizontal = 2 + } + + [StructLayout(LayoutKind.Sequential)] + struct XITouchClassInfo + { + public int Type; + public int Sourceid; + public int Mode; + public int NumTouches; + }; + + [StructLayout(LayoutKind.Sequential)] + unsafe struct XIDeviceInfo + { + public int Deviceid; + public IntPtr Name; + public XiDeviceType Use; + public int Attachment; + public Bool Enabled; + public int NumClasses; + public XIAnyClassInfo** Classes; + } + + enum XiDeviceType + { + XIMasterPointer = 1, + XIMasterKeyboard = 2, + XISlavePointer = 3, + XISlaveKeyboard = 4, + XIFloatingSlave = 5 + } + + enum XiPredefinedDeviceId : int + { + XIAllDevices = 0, + XIAllMasterDevices = 1 + } + + enum XiDeviceClass + { + XIKeyClass = 0, + XIButtonClass = 1, + XIValuatorClass = 2, + XIScrollClass = 3, + XITouchClass = 8, + } + + [StructLayout(LayoutKind.Sequential)] + unsafe struct XIDeviceChangedEvent + { + public int Type; /* GenericEvent */ + public ulong Serial; /* # of last request processed by server */ + public Bool SendEvent; /* true if this came from a SendEvent request */ + public IntPtr Display; /* Display the event was read from */ + public int Extension; /* XI extension offset */ + public int Evtype; /* XI_DeviceChanged */ + public IntPtr Time; + public int Deviceid; /* id of the device that changed */ + public int Sourceid; /* Source for the new classes. */ + public int Reason; /* Reason for the change */ + public int NumClasses; + public XIAnyClassInfo** Classes; /* same as in XIDeviceInfo */ + } + + [StructLayout(LayoutKind.Sequential)] + struct XIDeviceEvent + { + public XEventName type; /* GenericEvent */ + public ulong serial; /* # of last request processed by server */ + public Bool send_event; /* true if this came from a SendEvent request */ + public IntPtr display; /* Display the event was read from */ + public int extension; /* XI extension offset */ + public XiEventType evtype; + public IntPtr time; + public int deviceid; + public int sourceid; + public int detail; + public IntPtr RootWindow; + public IntPtr EventWindow; + public IntPtr ChildWindow; + public double root_x; + public double root_y; + public double event_x; + public double event_y; + public int flags; + public XIButtonState buttons; + public XIValuatorState valuators; + public XIModifierState mods; + public XIModifierState group; + } + + [StructLayout(LayoutKind.Sequential)] + unsafe struct XIEvent + { + public int type; /* GenericEvent */ + public ulong serial; /* # of last request processed by server */ + public Bool send_event; /* true if this came from a SendEvent request */ + public IntPtr display; /* Display the event was read from */ + public int extension; /* XI extension offset */ + public XiEventType evtype; + public IntPtr time; + } + + enum XiEventType + { + XI_DeviceChanged = 1, + XI_KeyPress = 2, + XI_KeyRelease = 3, + XI_ButtonPress = 4, + XI_ButtonRelease = 5, + XI_Motion = 6, + XI_Enter = 7, + XI_Leave = 8, + XI_FocusIn = 9, + XI_FocusOut = 10, + XI_HierarchyChanged = 11, + XI_PropertyEvent = 12, + XI_RawKeyPress = 13, + XI_RawKeyRelease = 14, + XI_RawButtonPress = 15, + XI_RawButtonRelease = 16, + XI_RawMotion = 17, + XI_TouchBegin = 18 /* XI 2.2 */, + XI_TouchUpdate = 19, + XI_TouchEnd = 20, + XI_TouchOwnership = 21, + XI_RawTouchBegin = 22, + XI_RawTouchUpdate = 23, + XI_RawTouchEnd = 24, + XI_BarrierHit = 25 /* XI 2.3 */, + XI_BarrierLeave = 26, + XI_LASTEVENT = XI_BarrierLeave, + } + +} diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index 1688d69f4f..a6c2c6ac1c 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; @@ -16,6 +17,8 @@ namespace Avalonia.X11 { const string libX11 = "libX11.so.6"; const string libX11Randr = "libXrandr.so.2"; + const string libX11Ext = "libXext.so.6"; + const string libXInput = "libXi.so.6"; [DllImport(libX11)] public static extern IntPtr XOpenDisplay(IntPtr display); @@ -451,6 +454,16 @@ namespace Avalonia.X11 [DllImport (libX11)] public static extern void XDestroyIC (IntPtr xic); + + [DllImport(libX11)] + public static extern bool XQueryExtension(IntPtr display, [MarshalAs(UnmanagedType.LPStr)] string name, + out int majorOpcode, out int firstEvent, out int firstError); + + [DllImport(libX11)] + public static extern bool XGetEventData(IntPtr display, void* cookie); + + [DllImport(libX11)] + public static extern void XFreeEventData(IntPtr display, void* cookie); [DllImport(libX11Randr)] public static extern int XRRQueryExtension (IntPtr dpy, @@ -467,7 +480,57 @@ namespace Avalonia.X11 XRRGetMonitors(IntPtr dpy, IntPtr window, bool get_active, out int nmonitors); [DllImport(libX11Randr)] public static extern void XRRSelectInput(IntPtr dpy, IntPtr window, RandrEventMask mask); + + [DllImport(libXInput)] + public static extern Status XIQueryVersion(IntPtr dpy, ref int major, ref int minor); + + [DllImport(libXInput)] + public static extern IntPtr XIQueryDevice(IntPtr dpy, int deviceid, out int ndevices_return); + + [DllImport(libXInput)] + public static extern void XIFreeDeviceInfo(XIDeviceInfo* info); + + public static void XISetMask(ref int mask, XiEventType ev) + { + mask |= (1 << (int)ev); + } + public static int XiEventMaskLen { get; } = 4; + + public static bool XIMaskIsSet(void* ptr, int shift) => + (((byte*)(ptr))[(shift) >> 3] & (1 << (shift & 7))) != 0; + + [DllImport(libXInput)] + public static extern Status XISelectEvents( + IntPtr dpy, + IntPtr win, + XIEventMask* masks, + int num_masks + ); + + public static Status XiSelectEvents(IntPtr display, IntPtr window, Dictionary> devices) + { + var masks = stackalloc int[devices.Count]; + var emasks = stackalloc XIEventMask[devices.Count]; + int c = 0; + foreach (var d in devices) + { + foreach (var ev in d.Value) + XISetMask(ref masks[c], ev); + emasks[c] = new XIEventMask + { + Mask = &masks[c], + Deviceid = d.Key, + MaskLen = XiEventMaskLen + }; + c++; + } + + + return XISelectEvents(display, window, emasks, devices.Count); + + } + public struct XGeometry { public IntPtr root; @@ -541,6 +604,13 @@ namespace Avalonia.X11 } } + public static IntPtr CreateEventWindow(AvaloniaX11Platform plat, Action handler) + { + var win = XCreateSimpleWindow(plat.Display, plat.Info.DefaultRootWindow, + 0, 0, 1, 1, 0, IntPtr.Zero, IntPtr.Zero); + plat.Windows[win] = handler; + return win; + } } From e9c5e42de9c4cfabbafd3db14e1c510c04809bc6 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sun, 13 Jan 2019 22:51:25 +0300 Subject: [PATCH 22/46] [X11] For now use GtkFileChooser on a separate thread --- src/Avalonia.X11/Avalonia.X11.csproj | 1 + src/Avalonia.X11/X11Platform.cs | 4 +- .../Gtk3ForeignX11SystemDialog.cs | 115 ++++++++++++++++++ src/Gtk/Avalonia.Gtk3/Interop/Native.cs | 13 +- src/Gtk/Avalonia.Gtk3/SystemDialogs.cs | 36 ++++-- 5 files changed, 156 insertions(+), 13 deletions(-) create mode 100644 src/Gtk/Avalonia.Gtk3/Gtk3ForeignX11SystemDialog.cs diff --git a/src/Avalonia.X11/Avalonia.X11.csproj b/src/Avalonia.X11/Avalonia.X11.csproj index 3e75180468..40db6d8c62 100644 --- a/src/Avalonia.X11/Avalonia.X11.csproj +++ b/src/Avalonia.X11/Avalonia.X11.csproj @@ -7,6 +7,7 @@ + diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 79aef75e4c..675ed4bd53 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Avalonia.Controls; using Avalonia.Controls.Platform; +using Avalonia.Gtk3; using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.OpenGL; @@ -41,7 +42,8 @@ namespace Avalonia.X11 .Bind().ToConstant(new X11Clipboard(this)) .Bind().ToConstant(new PlatformSettingsStub()) .Bind().ToConstant(new SystemDialogsStub()) - .Bind().ToConstant(new IconLoaderStub()); + .Bind().ToConstant(new IconLoaderStub()) + .Bind().ToConstant(new Gtk3ForeignX11SystemDialog()); X11Screens.Init(this); if (Info.XInputVersion != null) { diff --git a/src/Gtk/Avalonia.Gtk3/Gtk3ForeignX11SystemDialog.cs b/src/Gtk/Avalonia.Gtk3/Gtk3ForeignX11SystemDialog.cs new file mode 100644 index 0000000000..b80914572b --- /dev/null +++ b/src/Gtk/Avalonia.Gtk3/Gtk3ForeignX11SystemDialog.cs @@ -0,0 +1,115 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Avalonia.Controls; +using Avalonia.Controls.Platform; +using Avalonia.Gtk3.Interop; +using Avalonia.Platform; +using Avalonia.Platform.Interop; + +namespace Avalonia.Gtk3 +{ + public class Gtk3ForeignX11SystemDialog : ISystemDialogImpl + { + private Task _initialized; + private SystemDialogBase _inner = new SystemDialogBase(); + + + public async Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) + { + await EnsureInitialized(); + var xid = parent.Handle.Handle; + return await await RunOnGtkThread( + () => _inner.ShowFileDialogAsync(dialog, GtkWindow.Null, chooser => UpdateParent(chooser, xid))); + } + + public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) + { + await EnsureInitialized(); + var xid = parent.Handle.Handle; + return await await RunOnGtkThread( + () => _inner.ShowFolderDialogAsync(dialog, GtkWindow.Null, chooser => UpdateParent(chooser, xid))); + } + + void UpdateParent(GtkFileChooser chooser, IntPtr xid) + { + Native.GtkWidgetRealize(chooser); + var window = Native.GtkWidgetGetWindow(chooser); + var parent = Native.GdkWindowForeignNewForDisplay(GdkDisplay, xid); + if (window != IntPtr.Zero && parent != IntPtr.Zero) + Native.GdkWindowSetTransientFor(window, parent); + } + + async Task EnsureInitialized() + { + if (_initialized == null) + { + var tcs = new TaskCompletionSource(); + _initialized = tcs.Task; + new Thread(() => GtkThread(tcs)) + { + IsBackground = true + }.Start(); + } + + if (!(await _initialized)) + throw new Exception("Unable to initialize GTK on separate thread"); + + } + + Task RunOnGtkThread(Func action) + { + var tcs = new TaskCompletionSource(); + GlibTimeout.Add(0, 0, () => + { + + try + { + tcs.SetResult(action()); + } + catch (Exception e) + { + tcs.TrySetException(e); + } + + return false; + }); + return tcs.Task; + } + + + void GtkThread(TaskCompletionSource tcs) + { + try + { + X11.XInitThreads(); + }catch{} + Resolver.Resolve(); + if (Native.GdkWindowForeignNewForDisplay == null) + throw new Exception("gdk_x11_window_foreign_new_for_display is not found in your libgdk-3.so"); + using (var backends = new Utf8Buffer("x11")) + Native.GdkSetAllowedBackends?.Invoke(backends); + if (!Native.GtkInitCheck(0, IntPtr.Zero)) + { + tcs.SetResult(false); + return; + } + + using (var utf = new Utf8Buffer($"avalonia.app.a{Guid.NewGuid().ToString("N")}")) + App = Native.GtkApplicationNew(utf, 0); + if (App == IntPtr.Zero) + { + tcs.SetResult(false); + return; + } + GdkDisplay = Native.GdkGetDefaultDisplay(); + tcs.SetResult(true); + while (true) + Native.GtkMainIteration(); + } + + private IntPtr GdkDisplay { get; set; } + private IntPtr App { get; set; } + } +} diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs index bf973119a9..765c19a796 100644 --- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs +++ b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs @@ -50,6 +50,9 @@ namespace Avalonia.Gtk3.Interop [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] public delegate IntPtr gtk_init(int argc, IntPtr argv); + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] + public delegate bool gtk_init_check(int argc, IntPtr argv); + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk, optional: true)] public delegate IntPtr gdk_set_allowed_backends (Utf8Buffer backends); @@ -288,6 +291,12 @@ namespace Avalonia.Gtk3.Interop [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] public delegate void gdk_window_end_paint(IntPtr window); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk, optional: true)] + public delegate IntPtr gdk_x11_window_foreign_new_for_display(IntPtr display, IntPtr xid); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] + public delegate void gdk_window_set_transient_for(IntPtr window, IntPtr parent); [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] public delegate void gdk_event_request_motions(IntPtr ev); @@ -414,6 +423,7 @@ namespace Avalonia.Gtk3.Interop public static D.gtk_window_set_transient_for GtkWindowSetTransientFor; public static D.gdk_set_allowed_backends GdkSetAllowedBackends; public static D.gtk_init GtkInit; + public static D.gtk_init_check GtkInitCheck; public static D.gtk_window_present GtkWindowPresent; public static D.gtk_widget_hide GtkWidgetHide; public static D.gtk_widget_show GtkWidgetShow; @@ -483,8 +493,9 @@ namespace Avalonia.Gtk3.Interop public static D.gdk_window_process_updates GdkWindowProcessUpdates; public static D.gdk_window_begin_paint_rect GdkWindowBeginPaintRect; public static D.gdk_window_end_paint GdkWindowEndPaint; + public static D.gdk_x11_window_foreign_new_for_display GdkWindowForeignNewForDisplay; + public static D.gdk_window_set_transient_for GdkWindowSetTransientFor; - public static D.gdk_pixbuf_new_from_file GdkPixbufNewFromFile; public static D.gtk_icon_theme_get_default GtkIconThemeGetDefault; public static D.gtk_icon_theme_load_icon GtkIconThemeLoadIcon; diff --git a/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs b/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs index 5e6615f92d..1e85eaa156 100644 --- a/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs +++ b/src/Gtk/Avalonia.Gtk3/SystemDialogs.cs @@ -11,16 +11,17 @@ using Avalonia.Platform.Interop; namespace Avalonia.Gtk3 { - class SystemDialog : ISystemDialogImpl + class SystemDialogBase { - unsafe static Task ShowDialog(string title, GtkWindow parent, GtkFileChooserAction action, - bool multiselect, string initialFileName) + public unsafe static Task ShowDialog(string title, GtkWindow parent, GtkFileChooserAction action, + bool multiselect, string initialFileName, Action modify) { GtkFileChooser dlg; parent = parent ?? GtkWindow.Null; using (var name = new Utf8Buffer(title)) dlg = Native.GtkFileChooserDialogNew(name, parent, action, IntPtr.Zero); + modify?.Invoke(dlg); if (multiselect) Native.GtkFileChooserSetSelectMultiple(dlg, true); @@ -42,7 +43,7 @@ namespace Avalonia.Gtk3 dispose(); return false; }), - Signal.Connect(dlg, "response", (_, resp, __)=> + Signal.Connect(dlg, "response", (_, resp, __) => { string[] result = null; if (resp == GtkResponseType.Accept) @@ -56,9 +57,11 @@ namespace Avalonia.Gtk3 rlst.Add(Utf8Buffer.StringFromPtr(cgs->Data)); cgs = cgs->Next; } + Native.GSlistFree(gs); result = rlst.ToArray(); } + Native.GtkWidgetHide(dlg); dispose(); tcs.TrySetResult(result); @@ -70,27 +73,38 @@ namespace Avalonia.Gtk3 Native.GtkDialogAddButton(dlg, open, GtkResponseType.Accept); using (var open = new Utf8Buffer("Cancel")) Native.GtkDialogAddButton(dlg, open, GtkResponseType.Cancel); - if(initialFileName!=null) + if (initialFileName != null) using (var fn = new Utf8Buffer(initialFileName)) Native.GtkFileChooserSetFilename(dlg, fn); Native.GtkWindowPresent(dlg); return tcs.Task; } - public Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) + public Task ShowFileDialogAsync(FileDialog dialog, GtkWindow parent, + Action modify = null) { - return ShowDialog(dialog.Title, ((WindowBaseImpl)parent)?.GtkWidget, + return ShowDialog(dialog.Title, parent, dialog is OpenFileDialog ? GtkFileChooserAction.Open : GtkFileChooserAction.Save, (dialog as OpenFileDialog)?.AllowMultiple ?? false, Path.Combine(string.IsNullOrEmpty(dialog.InitialDirectory) ? "" : dialog.InitialDirectory, - string.IsNullOrEmpty(dialog.InitialFileName) ? "" : dialog.InitialFileName)); + string.IsNullOrEmpty(dialog.InitialFileName) ? "" : dialog.InitialFileName), modify); } - public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) + public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, GtkWindow parent, + Action modify = null) { - var res = await ShowDialog(dialog.Title, ((WindowBaseImpl) parent)?.GtkWidget, - GtkFileChooserAction.SelectFolder, false, dialog.InitialDirectory); + var res = await ShowDialog(dialog.Title, parent, + GtkFileChooserAction.SelectFolder, false, dialog.InitialDirectory, modify); return res?.FirstOrDefault(); } } + + class SystemDialog : SystemDialogBase, ISystemDialogImpl + { + public Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) + => ShowFolderDialogAsync(dialog, ((WindowBaseImpl)parent)?.GtkWidget); + + public Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) + => ShowFileDialogAsync(dialog, ((WindowBaseImpl)parent)?.GtkWidget); + } } From 37c65262ac1db3f2cf89669253a44639adcd03fe Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 14 Jan 2019 11:25:56 +0300 Subject: [PATCH 23/46] [RENDER] Don't copy "resized" layer contents + properly remove unneded layers --- .../Rendering/DeferredRenderer.cs | 33 +++++++++++++++---- src/Avalonia.Visuals/Rendering/RenderLayer.cs | 12 +++---- .../Rendering/RenderLayers.cs | 6 ++-- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index b48efaa34e..0a46abbf92 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -336,16 +336,34 @@ namespace Avalonia.Rendering private void RenderToLayers(Scene scene) { - if (scene.Layers.HasDirty) + foreach (var layer in scene.Layers) { - foreach (var layer in scene.Layers) - { - var renderTarget = Layers[layer.LayerRoot].Bitmap; - var node = (VisualNode)scene.FindNode(layer.LayerRoot); + var renderLayer = Layers[layer.LayerRoot]; + if (layer.Dirty.IsEmpty && !renderLayer.IsEmpty) + continue; + var renderTarget = renderLayer.Bitmap; + var node = (VisualNode)scene.FindNode(layer.LayerRoot); - if (node != null) + if (node != null) + { + using (var context = renderTarget.Item.CreateDrawingContext(this)) { - using (var context = renderTarget.Item.CreateDrawingContext(this)) + if (renderLayer.IsEmpty) + { + // Render entire layer root node + context.Clear(Colors.Transparent); + context.Transform = Matrix.Identity; + context.PushClip(node.ClipBounds); + Render(context, node, layer.LayerRoot, node.ClipBounds); + context.PopClip(); + if (DrawDirtyRects) + { + _dirtyRectsDisplay.Add(node.ClipBounds); + } + + renderLayer.IsEmpty = false; + } + else { foreach (var rect in layer.Dirty) { @@ -364,6 +382,7 @@ namespace Avalonia.Rendering } } } + } private void RenderOverlay(Scene scene, IDrawingContextImpl parentContent) diff --git a/src/Avalonia.Visuals/Rendering/RenderLayer.cs b/src/Avalonia.Visuals/Rendering/RenderLayer.cs index cd09bdee10..d6676e25ff 100644 --- a/src/Avalonia.Visuals/Rendering/RenderLayer.cs +++ b/src/Avalonia.Visuals/Rendering/RenderLayer.cs @@ -7,39 +7,39 @@ namespace Avalonia.Rendering { public class RenderLayer { - private readonly IDrawingContextImpl _drawingContext; - public RenderLayer( IDrawingContextImpl drawingContext, Size size, double scaling, IVisual layerRoot) { - _drawingContext = drawingContext; Bitmap = RefCountable.Create(drawingContext.CreateLayer(size)); Size = size; Scaling = scaling; LayerRoot = layerRoot; + IsEmpty = true; } public IRef Bitmap { get; private set; } + public bool IsEmpty { get; set; } public double Scaling { get; private set; } public Size Size { get; private set; } public IVisual LayerRoot { get; } - public void ResizeBitmap(Size size, double scaling) + public void RecreateBitmap(IDrawingContextImpl drawingContext, Size size, double scaling) { if (Size != size || Scaling != scaling) { - var resized = RefCountable.Create(_drawingContext.CreateLayer(size)); + var resized = RefCountable.Create(drawingContext.CreateLayer(size)); using (var context = resized.Item.CreateDrawingContext(null)) { context.Clear(Colors.Transparent); - context.DrawImage(Bitmap, 1, new Rect(Size), new Rect(Size)); Bitmap.Dispose(); Bitmap = resized; + Scaling = scaling; Size = size; + IsEmpty = true; } } } diff --git a/src/Avalonia.Visuals/Rendering/RenderLayers.cs b/src/Avalonia.Visuals/Rendering/RenderLayers.cs index 9b0ce944e7..0ff7862ab6 100644 --- a/src/Avalonia.Visuals/Rendering/RenderLayers.cs +++ b/src/Avalonia.Visuals/Rendering/RenderLayers.cs @@ -29,11 +29,11 @@ namespace Avalonia.Rendering } else { - layer.ResizeBitmap(scene.Size, scene.Scaling); + layer.RecreateBitmap(context, scene.Size, scene.Scaling); } } - for (var i = _inner.Count - 1; i >= 0; --i) + for (var i = 0; i < _inner.Count;) { var layer = _inner[i]; @@ -43,6 +43,8 @@ namespace Avalonia.Rendering _inner.RemoveAt(i); _index.Remove(layer.LayerRoot); } + else + i++; } } From a1ad8f0bea90dc06a68c03fb4f4f4350a82005c8 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 14 Jan 2019 11:26:52 +0300 Subject: [PATCH 24/46] [X11] Per-monitor DPI support --- src/Avalonia.Input/Raw/RawDragEvent.cs | 2 +- src/Avalonia.X11/Avalonia.X11.csproj | 1 + src/Avalonia.X11/X11Framebuffer.cs | 8 +- src/Avalonia.X11/X11FramebufferSurface.cs | 6 +- src/Avalonia.X11/X11Platform.cs | 6 +- src/Avalonia.X11/X11Screens.cs | 11 +- src/Avalonia.X11/X11Window.cs | 132 +++++++++++++++------- src/Avalonia.X11/XLib.cs | 15 +++ 8 files changed, 129 insertions(+), 52 deletions(-) diff --git a/src/Avalonia.Input/Raw/RawDragEvent.cs b/src/Avalonia.Input/Raw/RawDragEvent.cs index d251fe8640..208d898a8a 100644 --- a/src/Avalonia.Input/Raw/RawDragEvent.cs +++ b/src/Avalonia.Input/Raw/RawDragEvent.cs @@ -3,7 +3,7 @@ public class RawDragEvent : RawInputEventArgs { public IInputElement InputRoot { get; } - public Point Location { get; } + public Point Location { get; set; } public IDataObject Data { get; } public DragDropEffects Effects { get; set; } public RawDragEventType Type { get; } diff --git a/src/Avalonia.X11/Avalonia.X11.csproj b/src/Avalonia.X11/Avalonia.X11.csproj index 40db6d8c62..087ba017ae 100644 --- a/src/Avalonia.X11/Avalonia.X11.csproj +++ b/src/Avalonia.X11/Avalonia.X11.csproj @@ -8,6 +8,7 @@ + diff --git a/src/Avalonia.X11/X11Framebuffer.cs b/src/Avalonia.X11/X11Framebuffer.cs index 8e48a4089a..d99d7970b6 100644 --- a/src/Avalonia.X11/X11Framebuffer.cs +++ b/src/Avalonia.X11/X11Framebuffer.cs @@ -1,5 +1,7 @@ using System; +using System.IO; using Avalonia.Platform; +using SkiaSharp; using static Avalonia.X11.XLib; namespace Avalonia.X11 { @@ -9,11 +11,11 @@ namespace Avalonia.X11 private readonly IntPtr _xid; private IUnmanagedBlob _blob; - public X11Framebuffer(IntPtr display, IntPtr xid, int width, int height, int factor) + public X11Framebuffer(IntPtr display, IntPtr xid, int width, int height, double factor) { _display = display; _xid = xid; - Size = new PixelSize(width * factor, height * factor); + Size = new PixelSize(width, height); RowBytes = width * 4; Dpi = new Vector(96, 96) * factor; Format = PixelFormat.Bgra8888; @@ -34,7 +36,7 @@ namespace Avalonia.X11 image.bitmap_bit_order = 0;// LSBFirst; image.bitmap_pad = bitsPerPixel; image.depth = 24; - image.bytes_per_line = RowBytes - Size.Width * 4; + image.bytes_per_line = RowBytes; image.bits_per_pixel = bitsPerPixel; XLockDisplay(_display); XInitImage(ref image); diff --git a/src/Avalonia.X11/X11FramebufferSurface.cs b/src/Avalonia.X11/X11FramebufferSurface.cs index 05b21efb0c..6caec0a66f 100644 --- a/src/Avalonia.X11/X11FramebufferSurface.cs +++ b/src/Avalonia.X11/X11FramebufferSurface.cs @@ -8,11 +8,13 @@ namespace Avalonia.X11 { private readonly IntPtr _display; private readonly IntPtr _xid; + private readonly Func _scaling; - public X11FramebufferSurface(IntPtr display, IntPtr xid) + public X11FramebufferSurface(IntPtr display, IntPtr xid, Func scaling) { _display = display; _xid = xid; + _scaling = scaling; } public ILockedFramebuffer Lock() @@ -21,7 +23,7 @@ namespace Avalonia.X11 XGetGeometry(_display, _xid, out var root, out var x, out var y, out var width, out var height, out var bw, out var d); XUnlockDisplay(_display); - return new X11Framebuffer(_display, _xid, width, height, 1); + return new X11Framebuffer(_display, _xid, width, height, _scaling()); } } } diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 675ed4bd53..efda30b2fc 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -21,6 +21,8 @@ namespace Avalonia.X11 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 void Initialize() { XInitThreads(); @@ -44,7 +46,9 @@ namespace Avalonia.X11 .Bind().ToConstant(new SystemDialogsStub()) .Bind().ToConstant(new IconLoaderStub()) .Bind().ToConstant(new Gtk3ForeignX11SystemDialog()); - X11Screens.Init(this); + + X11Screens = Avalonia.X11.X11Screens.Init(this); + Screens = new X11Screens(X11Screens); if (Info.XInputVersion != null) { var xi2 = new XI2Manager(); diff --git a/src/Avalonia.X11/X11Screens.cs b/src/Avalonia.X11/X11Screens.cs index 46ad4d7320..560cc04a28 100644 --- a/src/Avalonia.X11/X11Screens.cs +++ b/src/Avalonia.X11/X11Screens.cs @@ -13,7 +13,7 @@ namespace Avalonia.X11 { private IX11Screens _impl; - private X11Screens(IX11Screens impl) + public X11Screens(IX11Screens impl) { _impl = impl; } @@ -141,16 +141,15 @@ namespace Avalonia.X11 public X11Screen[] Screens { get; } } - public static void Init(AvaloniaX11Platform platform) + public static IX11Screens Init(AvaloniaX11Platform platform) { var info = platform.Info; var settings = X11ScreensUserSettings.Detect(); var impl = (info.RandrVersion != null && info.RandrVersion >= new Version(1, 5)) ? new Randr15ScreensImpl(platform, settings) : (IX11Screens)new FallbackScreensImpl(info, settings); - - AvaloniaLocator.CurrentMutable.Bind().ToConstant(impl); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new X11Screens(impl)); + + return impl; } @@ -207,7 +206,7 @@ namespace Avalonia.X11 //Ignore } - return null; + return rv; } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 4441006fda..b919424efe 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -27,13 +27,15 @@ namespace Avalonia.X11 private IInputRoot _inputRoot; private readonly IMouseDevice _mouse; private readonly IKeyboardDevice _keyboard; - private Point _position; + private Point? _position; + private PixelSize _realSize; private IntPtr _handle; private IntPtr _xic; private IntPtr _renderHandle; private bool _mapped; private HashSet _transientChildren = new HashSet(); private X11Window _transientParent; + public object SyncRoot { get; } = new object(); class InputEventContainer { @@ -79,7 +81,7 @@ namespace Avalonia.X11 SetWindowValuemask.WinGravity | SetWindowValuemask.BackingStore)), ref attr); Handle = new PlatformHandle(_handle, "XID"); - ClientSize = new Size(400, 400); + _realSize = new PixelSize(300, 200); platform.Windows[_handle] = OnEvent; XEventMask ignoredMask = XEventMask.SubstructureRedirectMask | XEventMask.ResizeRedirectMask @@ -96,12 +98,12 @@ namespace Avalonia.X11 var feature = (EglGlPlatformFeature)AvaloniaLocator.Current.GetService(); var surfaces = new List { - new X11FramebufferSurface(_x11.DeferredDisplay, _handle) + new X11FramebufferSurface(_x11.DeferredDisplay, _renderHandle, () => Scaling) }; if (feature != null) surfaces.Insert(0, new EglGlPlatformSurface((EglDisplay)feature.Display, feature.DeferredContext, - new SurfaceInfo(_x11.DeferredDisplay, _handle, _renderHandle))); + new SurfaceInfo(this, _x11.DeferredDisplay, _handle, _renderHandle))); Surfaces = surfaces.ToArray(); UpdateMotifHits(); XFlush(_x11.Display); @@ -109,11 +111,13 @@ namespace Avalonia.X11 class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo { + private readonly X11Window _window; private readonly IntPtr _display; private readonly IntPtr _parent; - public SurfaceInfo(IntPtr display, IntPtr parent, IntPtr xid) + public SurfaceInfo(X11Window window, IntPtr display, IntPtr parent, IntPtr xid) { + _window = window; _display = display; _parent = parent; Handle = xid; @@ -134,7 +138,7 @@ namespace Avalonia.X11 } } - public double Scaling { get; } = 1; + public double Scaling => _window.Scaling; } void UpdateMotifHits() @@ -188,10 +192,20 @@ namespace Avalonia.X11 XSetWMNormalHints(_x11.Display, _handle, ref hints); } - - public Size ClientSize { get; private set; } - //TODO - public double Scaling { get; } = 1; + + public Size ClientSize => new Size(_realSize.Width / Scaling, _realSize.Height / Scaling); + + public double Scaling + { + get + { + lock (SyncRoot) + return _scaling; + + } + private set => _scaling = value; + } + public IEnumerable Surfaces { get; } public Action Input { get; set; } public Action Paint { get; set; } @@ -209,6 +223,11 @@ namespace Avalonia.X11 new DeferredRenderer(root, AvaloniaLocator.Current.GetService()); void OnEvent(XEvent ev) + { + lock (SyncRoot) + OnEventSync(ev); + } + void OnEventSync(XEvent ev) { if(XFilterEvent(ref ev, _handle)) return; @@ -269,6 +288,8 @@ namespace Avalonia.X11 } else if (ev.type == XEventName.ConfigureNotify) { + if (ev.ConfigureEvent.window != _handle) + return; var needEnqueue = (_configure == null); _configure = ev.ConfigureEvent; if (needEnqueue) @@ -278,22 +299,27 @@ namespace Avalonia.X11 return; var cev = _configure.Value; _configure = null; - var nsize = new Size(cev.width, cev.height); - XTranslateCoordinates(_x11.Display, _handle, _x11.DefaultRootWindow, 0, 0, out var xret, - out var yret, out var _); - var npos = new Point(xret, yret); - var changedSize = ClientSize != nsize; - var changedPos = npos != _position; - ClientSize = nsize; + var nsize = new PixelSize(cev.width, cev.height); + var npos = new Point(cev.x, cev.y); + var changedSize = _realSize != nsize; + var changedPos = _position == null || npos != _position; + _realSize = nsize; _position = npos; - if (changedSize) - Resized?.Invoke(nsize); + bool updatedSizeViaScaling = false; if (changedPos) + { PositionChanged?.Invoke(npos); + updatedSizeViaScaling = UpdateScaling(); + } + + if (changedSize && !updatedSizeViaScaling) + Resized?.Invoke(ClientSize); + Dispatcher.UIThread.RunJobs(DispatcherPriority.Layout); }, DispatcherPriority.Layout); + XConfigureResizeWindow(_x11.Display, _renderHandle, ev.ConfigureEvent.width, ev.ConfigureEvent.height); } - else if (ev.type == XEventName.DestroyNotify) + else if (ev.type == XEventName.DestroyNotify && ev.AnyEvent.window == _handle) { Cleanup(); } @@ -338,6 +364,28 @@ namespace Avalonia.X11 } } + private bool UpdateScaling() + { + lock (SyncRoot) + { + var monitor = _platform.X11Screens.Screens.OrderBy(x => x.PixelDensity) + .FirstOrDefault(m => m.Bounds.Contains(Position)); + var newScaling = monitor?.PixelDensity ?? Scaling; + if (Scaling != newScaling) + { + Console.WriteLine( + $"Updating scaling from {Scaling} to {newScaling} as a response to position change to {Position}"); + var oldScaledSize = ClientSize; + Scaling = newScaling; + ScalingChanged?.Invoke(Scaling); + Resize(oldScaledSize, true); + return true; + } + + return false; + } + } + private WindowState _lastWindowState; public WindowState WindowState { @@ -431,6 +479,7 @@ namespace Avalonia.X11 private bool _systemDecorations = true; private bool _canResize = true; private (Size minSize, Size maxSize) _minMaxSize; + private double _scaling = 1; void ScheduleInput(RawInputEventArgs args, ref XEvent xev) { @@ -440,6 +489,10 @@ namespace Avalonia.X11 public void ScheduleInput(RawInputEventArgs args) { + if (args is RawMouseEventArgs mouse) + mouse.Position = mouse.Position / Scaling; + if (args is RawDragEvent drag) + drag.Location = drag.Location / Scaling; _lastEvent = new InputEventContainer() {Event = args}; _inputQueue.Enqueue(_lastEvent); @@ -564,35 +617,35 @@ namespace Avalonia.X11 public void Hide() => XUnmapWindow(_x11.Display, _handle); - public Point PointToClient(Point point) => new Point(point.X - _position.X, point.Y - _position.Y); + public Point PointToClient(Point point) => new Point((point.X - Position.X) / Scaling, (point.Y - Position.Y) / Scaling); - public Point PointToScreen(Point point) => new Point(point.X + _position.X, point.Y + _position.Y); + public Point PointToScreen(Point point) => new Point(point.X * Scaling + Position.X, point.Y * Scaling + Position.Y); public void SetSystemDecorations(bool enabled) { _systemDecorations = enabled; UpdateMotifHits(); } + + + public void Resize(Size clientSize) => Resize(clientSize, false); - - public void Resize(Size clientSize) + void Resize(Size clientSize, bool force) { - if (clientSize == ClientSize) + if (!force && clientSize == ClientSize) return; - var changes = new XWindowChanges - { - width = (int)clientSize.Width, - height = (int)clientSize.Height - }; - var needResize = clientSize != ClientSize; - XConfigureWindow(_x11.Display, _handle, ChangeWindowFlags.CWHeight | ChangeWindowFlags.CWWidth, - ref changes); + + var needImmediatePopupResize = clientSize != ClientSize; + + var pixelSize = new PixelSize((int)(clientSize.Width * Scaling), (int)(clientSize.Height * Scaling)); + XConfigureResizeWindow(_x11.Display, _handle, pixelSize); + XConfigureResizeWindow(_x11.Display, _renderHandle, pixelSize); XFlush(_x11.Display); - if (_popup && needResize) + if (force || (_popup && needImmediatePopupResize)) { - ClientSize = clientSize; - Resized?.Invoke(clientSize); + _realSize = pixelSize; + Resized?.Invoke(ClientSize); } } @@ -618,7 +671,7 @@ namespace Avalonia.X11 public Point Position { - get => _position; + get => _position ?? default; set { var changes = new XWindowChanges @@ -650,9 +703,10 @@ namespace Avalonia.X11 } - public IScreenImpl Screen { get; } = AvaloniaLocator.CurrentMutable.GetService(); - public Size MaxClientSize { get; } = new Size(1920, 1280); + public IScreenImpl Screen => _platform.Screens; + public Size MaxClientSize => _platform.X11Screens.Screens.Select(s => s.Bounds.Size / s.PixelDensity) + .OrderByDescending(x => x.Width + x.Height).FirstOrDefault(); void SendNetWMMessage(IntPtr message_type, IntPtr l0, diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index a6c2c6ac1c..b47f79d7bd 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -115,6 +115,21 @@ namespace Avalonia.X11 public static extern uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values); + public static uint XConfigureResizeWindow(IntPtr display, IntPtr window, PixelSize size) + => XConfigureResizeWindow(display, window, size.Width, size.Height); + + public static uint XConfigureResizeWindow(IntPtr display, IntPtr window, int width, int height) + { + var changes = new XWindowChanges + { + width = width, + height = height + }; + + return XConfigureWindow(display, window, ChangeWindowFlags.CWHeight | ChangeWindowFlags.CWWidth, + ref changes); + } + [DllImport(libX11)] public static extern IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists); From ec682e2e1de5b3004c3e629d9b2ac9caa96b55be Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 14 Jan 2019 13:23:16 +0300 Subject: [PATCH 25/46] [X11] Implemented icons --- src/Avalonia.X11/Stubs.cs | 49 ------------- src/Avalonia.X11/X11Framebuffer.cs | 6 +- src/Avalonia.X11/X11FramebufferSurface.cs | 2 +- src/Avalonia.X11/X11IconLoader.cs | 85 +++++++++++++++++++++++ src/Avalonia.X11/X11Platform.cs | 3 +- src/Avalonia.X11/X11Window.cs | 6 +- 6 files changed, 96 insertions(+), 55 deletions(-) create mode 100644 src/Avalonia.X11/X11IconLoader.cs diff --git a/src/Avalonia.X11/Stubs.cs b/src/Avalonia.X11/Stubs.cs index 91d788c576..ec694ba9a8 100644 --- a/src/Avalonia.X11/Stubs.cs +++ b/src/Avalonia.X11/Stubs.cs @@ -14,53 +14,4 @@ namespace Avalonia.X11 public Size DoubleClickSize { get; } = new Size(2, 2); public TimeSpan DoubleClickTime { get; } = TimeSpan.FromMilliseconds(500); } - - class SystemDialogsStub : ISystemDialogImpl - { - public Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) - { - return Task.FromResult((string[])null); - } - - public Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) - { - return Task.FromResult((string)null); - } - } - - class IconLoaderStub : IPlatformIconLoader - { - class FakeIcon : IWindowIconImpl - { - private readonly byte[] _data; - - public FakeIcon(byte[] data) - { - _data = data; - } - public void Save(Stream outputStream) - { - outputStream.Write(_data, 0, _data.Length); - } - } - - public IWindowIconImpl LoadIcon(string fileName) - { - return new FakeIcon(File.ReadAllBytes(fileName)); - } - - public IWindowIconImpl LoadIcon(Stream stream) - { - var ms = new MemoryStream(); - stream.CopyTo(ms); - return new FakeIcon(ms.ToArray()); - } - - public IWindowIconImpl LoadIcon(IBitmapImpl bitmap) - { - var ms = new MemoryStream(); - bitmap.Save(ms); - return new FakeIcon(ms.ToArray()); - } - } } diff --git a/src/Avalonia.X11/X11Framebuffer.cs b/src/Avalonia.X11/X11Framebuffer.cs index d99d7970b6..00288f300d 100644 --- a/src/Avalonia.X11/X11Framebuffer.cs +++ b/src/Avalonia.X11/X11Framebuffer.cs @@ -9,12 +9,14 @@ namespace Avalonia.X11 { private readonly IntPtr _display; private readonly IntPtr _xid; + private readonly int _depth; private IUnmanagedBlob _blob; - public X11Framebuffer(IntPtr display, IntPtr xid, int width, int height, double factor) + public X11Framebuffer(IntPtr display, IntPtr xid, int depth, int width, int height, double factor) { _display = display; _xid = xid; + _depth = depth; Size = new PixelSize(width, height); RowBytes = width * 4; Dpi = new Vector(96, 96) * factor; @@ -35,7 +37,7 @@ namespace Avalonia.X11 image.bitmap_unit = bitsPerPixel; image.bitmap_bit_order = 0;// LSBFirst; image.bitmap_pad = bitsPerPixel; - image.depth = 24; + image.depth = _depth; image.bytes_per_line = RowBytes; image.bits_per_pixel = bitsPerPixel; XLockDisplay(_display); diff --git a/src/Avalonia.X11/X11FramebufferSurface.cs b/src/Avalonia.X11/X11FramebufferSurface.cs index 6caec0a66f..70220cebcd 100644 --- a/src/Avalonia.X11/X11FramebufferSurface.cs +++ b/src/Avalonia.X11/X11FramebufferSurface.cs @@ -23,7 +23,7 @@ namespace Avalonia.X11 XGetGeometry(_display, _xid, out var root, out var x, out var y, out var width, out var height, out var bw, out var d); XUnlockDisplay(_display); - return new X11Framebuffer(_display, _xid, width, height, _scaling()); + return new X11Framebuffer(_display, _xid, 24,width, height, _scaling()); } } } diff --git a/src/Avalonia.X11/X11IconLoader.cs b/src/Avalonia.X11/X11IconLoader.cs new file mode 100644 index 0000000000..2c57dca157 --- /dev/null +++ b/src/Avalonia.X11/X11IconLoader.cs @@ -0,0 +1,85 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using Avalonia.Controls.Platform.Surfaces; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using Avalonia.Utilities; +using Avalonia.Visuals.Media.Imaging; +using static Avalonia.X11.XLib; +namespace Avalonia.X11 +{ + class X11IconLoader : IPlatformIconLoader + { + private readonly X11Info _x11; + + public X11IconLoader(X11Info x11) + { + _x11 = x11; + } + + IWindowIconImpl LoadIcon(Bitmap bitmap) => new X11IconData(bitmap); + + public IWindowIconImpl LoadIcon(string fileName) => LoadIcon(new Bitmap(fileName)); + + public IWindowIconImpl LoadIcon(Stream stream) => LoadIcon(new Bitmap(stream)); + + public IWindowIconImpl LoadIcon(IBitmapImpl bitmap) + { + var ms = new MemoryStream(); + bitmap.Save(ms); + ms.Position = 0; + return LoadIcon(ms); + } + } + + unsafe class X11IconData : IWindowIconImpl, IFramebufferPlatformSurface + { + private readonly Bitmap _bitmap; + private int _width; + private int _height; + private uint[] _bdata; + public IntPtr[] Data { get; } + + public X11IconData(Bitmap bitmap) + { + _bitmap = bitmap; + _width = Math.Min(_bitmap.PixelSize.Width, 128); + _height = Math.Min(_bitmap.PixelSize.Height, 128); + _bdata = new uint[_width * _height]; + fixed (void* ptr = _bdata) + { + var iptr = (int*)ptr; + iptr[0] = _width; + iptr[1] = _height; + } + using(var rt = AvaloniaLocator.Current.GetService().CreateRenderTarget(new[]{this})) + using (var ctx = rt.CreateDrawingContext(null)) + ctx.DrawImage(bitmap.PlatformImpl, 1, new Rect(bitmap.Size), + new Rect(0, 0, _width, _height)); + Data = new IntPtr[_width * _height + 2]; + Data[0] = new IntPtr(_width); + Data[1] = new IntPtr(_height); + for (var y = 0; y < _height; y++) + { + var r = y * _width; + for (var x = 0; x < _width; x++) + Data[r + x] = new IntPtr(_bdata[r + x]); + } + } + + public void Save(Stream outputStream) + { + _bitmap.Save(outputStream); + } + + public ILockedFramebuffer Lock() + { + var h = GCHandle.Alloc(_bdata, GCHandleType.Pinned); + return new LockedFramebuffer(h.AddrOfPinnedObject(), new PixelSize(_width, _height), _width * 4, + new Vector(96, 96), PixelFormat.Bgra8888, + () => h.Free()); + } + } +} diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index efda30b2fc..3b50dff5c8 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -43,8 +43,7 @@ namespace Avalonia.X11 .Bind().ToConstant(new X11CursorFactory(Display)) .Bind().ToConstant(new X11Clipboard(this)) .Bind().ToConstant(new PlatformSettingsStub()) - .Bind().ToConstant(new SystemDialogsStub()) - .Bind().ToConstant(new IconLoaderStub()) + .Bind().ToConstant(new X11IconLoader(Info)) .Bind().ToConstant(new Gtk3ForeignX11SystemDialog()); X11Screens = Avalonia.X11.X11Screens.Init(this); diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index b919424efe..85eade8be3 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -800,7 +800,11 @@ namespace Avalonia.X11 public void SetIcon(IWindowIconImpl icon) { - //TODO + var data = ((X11IconData)icon).Data; + fixed (void* pdata = data) + XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_ICON, + new IntPtr((int)Atom.XA_CARDINAL), 32, PropertyMode.Replace, + pdata, data.Length); } public void ShowTaskbarIcon(bool value) From 847d051dc6612a49aab204e5c38f1721ee931dc6 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 16 Jan 2019 15:26:29 +0300 Subject: [PATCH 26/46] Cleanup --- Avalonia.sln | 173 ++++++++++++++-------- samples/ControlCatalog.NetCore/Program.cs | 2 +- samples/PlatformSanityChecks/Program.cs | 8 - 3 files changed, 110 insertions(+), 73 deletions(-) diff --git a/Avalonia.sln b/Avalonia.sln index ac68b85553..2f7560049c 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -1,4 +1,5 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.27130.2027 MinimumVisualStudioVersion = 10.0.40219.1 @@ -130,6 +131,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1 ProjectSection(SolutionItems) = preProject build\Base.props = build\Base.props build\Binding.props = build\Binding.props + build\BuildTargets.targets = build\BuildTargets.targets build\JetBrains.Annotations.props = build\JetBrains.Annotations.props build\JetBrains.dotMemoryUnit.props = build\JetBrains.dotMemoryUnit.props build\Magick.NET-Q16-AnyCPU.props = build\Magick.NET-Q16-AnyCPU.props @@ -147,7 +149,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1 build\Splat.props = build\Splat.props build\System.Memory.props = build\System.Memory.props build\XUnit.props = build\XUnit.props - build\BuildTargets.targets = build\BuildTargets.targets EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Targets", "Targets", "{4D6FAF79-58B4-482F-9122-0668C346364C}" @@ -179,25 +180,25 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.UnitTests", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.OpenGL", "src\Avalonia.OpenGL\Avalonia.OpenGL.csproj", "{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Native", "src\Avalonia.Native\Avalonia.Native.csproj", "{12A91A62-C064-42CA-9A8C-A1272F354388}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesktopRuntime", "src\Avalonia.DesktopRuntime\Avalonia.DesktopRuntime.csproj", "{878FEFE0-CD14-41CB-90B0-DBCB163E8F15}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Packages", "Packages", "{E870DCD7-F46A-498D-83FC-D0FD13E0A11C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia", "packages\Avalonia\Avalonia.csproj", "{D49233F8-F29C-47DD-9975-C4C9E4502720}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.X11", "src\Avalonia.X11\Avalonia.X11.csproj", "{212D02D5-C873-469A-8E78-4A6350EC4A1A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlatformSanityChecks", "samples\PlatformSanityChecks\PlatformSanityChecks.csproj", "{8B5768BB-71F9-4E23-89B5-DDBA6458B856}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Native", "src\Avalonia.Native\Avalonia.Native.csproj", "{12A91A62-C064-42CA-9A8C-A1272F354388}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Desktop", "src\Avalonia.Desktop\Avalonia.Desktop.csproj", "{3C471044-3640-45E3-B1B2-16D2FF8399EE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Build.Tasks", "src\Avalonia.Build.Tasks\Avalonia.Build.Tasks.csproj", "{BF28998D-072C-439A-AFBB-2FE5021241E0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Build.Tasks", "src\Avalonia.Build.Tasks\Avalonia.Build.Tasks.csproj", "{BF28998D-072C-439A-AFBB-2FE5021241E0}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "nukebuild\_build.csproj", "{3F00BC43-5095-477F-93D8-E65B08179A00}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Animation.UnitTests", "tests\Avalonia.Animation.UnitTests\Avalonia.Animation.UnitTests.csproj", "{AF227847-E65C-4BE9-BCE9-B551357788E0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Animation.UnitTests", "tests\Avalonia.Animation.UnitTests\Avalonia.Animation.UnitTests.csproj", "{AF227847-E65C-4BE9-BCE9-B551357788E0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.X11", "src\Avalonia.X11\Avalonia.X11.csproj", "{41B02319-965D-4945-8005-C1A3D1224165}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlatformSanityChecks", "samples\PlatformSanityChecks\PlatformSanityChecks.csproj", "{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution @@ -224,10 +225,6 @@ Global Release|iPhoneSimulator = Release|iPhoneSimulator EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.Build.0 = Release|Any CPU {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU @@ -1606,54 +1603,30 @@ Global {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhone.Build.0 = Release|Any CPU {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.AppStore|iPhone.Build.0 = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Debug|iPhone.Build.0 = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Release|Any CPU.Build.0 = Release|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Release|iPhone.ActiveCfg = Release|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Release|iPhone.Build.0 = Release|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {212D02D5-C873-469A-8E78-4A6350EC4A1A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.AppStore|iPhone.Build.0 = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Debug|iPhone.Build.0 = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|Any CPU.Build.0 = Release|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|iPhone.ActiveCfg = Release|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|iPhone.Build.0 = Release|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {8B5768BB-71F9-4E23-89B5-DDBA6458B856}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhone.Build.0 = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|Any CPU.Build.0 = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhone.Build.0 = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|Any CPU.ActiveCfg = Release|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|Any CPU.Build.0 = Release|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhone.ActiveCfg = Release|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhone.Build.0 = Release|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {878FEFE0-CD14-41CB-90B0-DBCB163E8F15}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU @@ -1750,6 +1723,30 @@ Global {BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|iPhone.Build.0 = Release|Any CPU {BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.AppStore|Any CPU.Build.0 = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.AppStore|iPhone.Build.0 = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|iPhone.Build.0 = Debug|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.Build.0 = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|iPhone.ActiveCfg = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|iPhone.Build.0 = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {AF227847-E65C-4BE9-BCE9-B551357788E0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {AF227847-E65C-4BE9-BCE9-B551357788E0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {AF227847-E65C-4BE9-BCE9-B551357788E0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU @@ -1774,6 +1771,54 @@ Global {AF227847-E65C-4BE9-BCE9-B551357788E0}.Release|iPhone.Build.0 = Release|Any CPU {AF227847-E65C-4BE9-BCE9-B551357788E0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {AF227847-E65C-4BE9-BCE9-B551357788E0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|iPhone.Build.0 = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Debug|iPhone.Build.0 = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Release|Any CPU.ActiveCfg = Release|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Release|Any CPU.Build.0 = Release|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Release|iPhone.ActiveCfg = Release|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Release|iPhone.Build.0 = Release|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {41B02319-965D-4945-8005-C1A3D1224165}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|iPhone.Build.0 = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|iPhone.Build.0 = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|Any CPU.Build.0 = Release|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|iPhone.ActiveCfg = Release|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|iPhone.Build.0 = Release|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1825,11 +1870,11 @@ Global {050CC912-FF49-4A8B-B534-9544017446DD} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE} = {9B9E3891-2366-4253-A952-D08BCEB71098} {E1240B49-7B4B-4371-A00E-068778C5CF0B} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {212D02D5-C873-469A-8E78-4A6350EC4A1A} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B} - {8B5768BB-71F9-4E23-89B5-DDBA6458B856} = {9B9E3891-2366-4253-A952-D08BCEB71098} {D49233F8-F29C-47DD-9975-C4C9E4502720} = {E870DCD7-F46A-498D-83FC-D0FD13E0A11C} {3C471044-3640-45E3-B1B2-16D2FF8399EE} = {E870DCD7-F46A-498D-83FC-D0FD13E0A11C} {AF227847-E65C-4BE9-BCE9-B551357788E0} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {41B02319-965D-4945-8005-C1A3D1224165} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B} + {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B} = {9B9E3891-2366-4253-A952-D08BCEB71098} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs index 2a7d0b30a9..57c8b700df 100644 --- a/samples/ControlCatalog.NetCore/Program.cs +++ b/samples/ControlCatalog.NetCore/Program.cs @@ -43,7 +43,7 @@ namespace ControlCatalog.NetCore /// This method is needed for IDE previewer infrastructure /// public static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure().UsePlatformDetect().UseSkia().UseReactiveUI().UseX11(); + => AppBuilder.Configure().UsePlatformDetect().UseSkia().UseReactiveUI(); static void ConsoleSilencer() { diff --git a/samples/PlatformSanityChecks/Program.cs b/samples/PlatformSanityChecks/Program.cs index 3fdc9b1e77..99474bd0ab 100644 --- a/samples/PlatformSanityChecks/Program.cs +++ b/samples/PlatformSanityChecks/Program.cs @@ -23,9 +23,6 @@ namespace PlatformSanityChecks AvaloniaX11PlatformExtensions.InitializeX11Platform(); CheckPlatformThreading(); - - - } static bool CheckAccess() => UiThread == Thread.CurrentThread; @@ -110,11 +107,8 @@ namespace PlatformSanityChecks return true; }, TimeSpan.FromSeconds(1)); - - }); - static void CheckSignaling() => EnterLoop(cts => { ThreadPool.QueueUserWorkItem(_ => @@ -133,8 +127,6 @@ namespace PlatformSanityChecks CheckSignaling(); CheckTimerOrdering(); CheckTimerTicking(); - } - } } From 2a8ee50be8beb0da2105122c3902fa1b4bb782ad Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 16 Jan 2019 14:08:16 +0000 Subject: [PATCH 27/46] fix monitor initialization bug --- src/Avalonia.X11/X11Screens.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.X11/X11Screens.cs b/src/Avalonia.X11/X11Screens.cs index 560cc04a28..d775261de0 100644 --- a/src/Avalonia.X11/X11Screens.cs +++ b/src/Avalonia.X11/X11Screens.cs @@ -106,7 +106,7 @@ namespace Avalonia.X11 density *= _settings.GlobalScaleFactor; var bounds = new Rect(mon.X, mon.Y, mon.Width, mon.Height); - screens[0] = new X11Screen(bounds, + screens[c] = new X11Screen(bounds, mon.Primary != 0, name, (mon.MWidth == 0 || mon.MHeight == 0) ? (Size?)null : new Size(mon.MWidth, mon.MHeight), From 6105b64b66a725aa58e61e189d1391c11ec415ba Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 16 Jan 2019 17:37:12 +0300 Subject: [PATCH 28/46] Pass CurrentTime to XUngrabPointer --- src/Avalonia.X11/X11Window.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 85eade8be3..3be3f2e88e 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -736,7 +736,7 @@ namespace Avalonia.X11 void BeginMoveResize(NetWmMoveResize side) { var pos = GetCursorPos(_x11); - XUngrabPointer(_x11.Display, _x11.LastActivityTimestamp); + XUngrabPointer(_x11.Display, new IntPtr(0)); SendNetWMMessage (_x11.Atoms._NET_WM_MOVERESIZE, (IntPtr) pos.x, (IntPtr) pos.y, (IntPtr) side, (IntPtr) 1, (IntPtr)1); // left button From 359f15f7a15d8ae086d6f4d6f500436f5640c866 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 16 Jan 2019 14:45:30 +0000 Subject: [PATCH 29/46] fix text input --- src/Avalonia.X11/XLib.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index b47f79d7bd..8a146f922d 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -446,7 +446,7 @@ namespace Avalonia.X11 [DllImport (libX11)] public static extern unsafe int XLookupString(ref XEvent xevent, void* buffer, int num_bytes, out IntPtr keysym, out IntPtr status); - [DllImport ("libX11")] + [DllImport (libX11)] public static extern unsafe int Xutf8LookupString(IntPtr xic, ref XEvent xevent, void* buffer, int num_bytes, out IntPtr keysym, out IntPtr status); [DllImport (libX11)] From db5d3aa854e4484e936962febbb5419835163a10 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 16 Jan 2019 21:23:55 +0300 Subject: [PATCH 30/46] [X11] Fixed maximize behavior for transient windows --- samples/ControlCatalog/Pages/DialogsPage.xaml | 1 + .../ControlCatalog/Pages/DialogsPage.xaml.cs | 10 +++++++--- src/Avalonia.X11/X11PlatformThreading.cs | 2 ++ src/Avalonia.X11/X11Window.cs | 20 ++++++++++++------- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml b/samples/ControlCatalog/Pages/DialogsPage.xaml index 1e4e9fef1c..2bd9a39300 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml @@ -6,6 +6,7 @@ + diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs index e380c677c9..187250b6ea 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs @@ -31,9 +31,13 @@ namespace ControlCatalog.Pages }.ShowAsync(GetWindow()); }; this.FindControl