Browse Source

[X11] Initial windowing and mouse events

pull/2011/head
Nikita Tsukanov 8 years ago
parent
commit
666efd311b
  1. 2
      samples/PlatformSanityChecks/Program.cs
  2. 4
      src/Avalonia.Input/MouseDevice.cs
  3. 4
      src/Avalonia.Input/Raw/RawInputEventArgs.cs
  4. 2
      src/Avalonia.Input/Raw/RawKeyEventArgs.cs
  5. 2
      src/Avalonia.Input/Raw/RawMouseEventArgs.cs
  6. 2
      src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs
  7. 2
      src/Avalonia.Input/Raw/RawTextInputEventArgs.cs
  8. 1
      src/Avalonia.X11/Avalonia.X11.csproj
  9. 103
      src/Avalonia.X11/Stubs.cs
  10. 341
      src/Avalonia.X11/X11Atoms.cs
  11. 110
      src/Avalonia.X11/X11Enums.cs
  12. 57
      src/Avalonia.X11/X11Framebuffer.cs
  13. 27
      src/Avalonia.X11/X11FramebufferSurface.cs
  14. 35
      src/Avalonia.X11/X11Info.cs
  15. 47
      src/Avalonia.X11/X11Platform.cs
  16. 24
      src/Avalonia.X11/X11PlatformThreading.cs
  17. 1815
      src/Avalonia.X11/X11Structs.cs
  18. 492
      src/Avalonia.X11/X11Window.cs
  19. 30
      src/Avalonia.X11/XError.cs
  20. 468
      src/Avalonia.X11/XLib.cs

2
samples/PlatformSanityChecks/Program.cs

@ -20,7 +20,7 @@ namespace PlatformSanityChecks
AppBuilder.Configure<App>().RuntimePlatformServicesInitializer();
var app = new App();
new AvaloniaX11Platform().Initialize();
AvaloniaX11PlatformExtensions.InitializeX11Platform();
CheckPlatformThreading();

4
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<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null);

4
src/Avalonia.Input/Raw/RawInputEventArgs.cs

@ -21,7 +21,7 @@ namespace Avalonia.Input.Raw
/// </summary>
/// <param name="device">The associated device.</param>
/// <param name="timestamp">The event timestamp.</param>
public RawInputEventArgs(IInputDevice device, uint timestamp)
public RawInputEventArgs(IInputDevice device, ulong timestamp)
{
Contract.Requires<ArgumentNullException>(device != null);
@ -47,6 +47,6 @@ namespace Avalonia.Input.Raw
/// <summary>
/// Gets the timestamp associated with the event.
/// </summary>
public uint Timestamp { get; private set; }
public ulong Timestamp { get; private set; }
}
}

2
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)

2
src/Avalonia.Input/Raw/RawMouseEventArgs.cs

@ -35,7 +35,7 @@ namespace Avalonia.Input.Raw
/// <param name="inputModifiers">The input modifiers.</param>
public RawMouseEventArgs(
IInputDevice device,
uint timestamp,
ulong timestamp,
IInputRoot root,
RawMouseEventType type,
Point position,

2
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)

2
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;
}

1
src/Avalonia.X11/Avalonia.X11.csproj

@ -7,6 +7,7 @@
<ItemGroup>
<ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\Avalonia.OpenGL\Avalonia.OpenGL.csproj" />
</ItemGroup>
</Project>

103
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<string> 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<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
{
return Task.FromResult((string[])null);
}
public Task<string> 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)};
}
}

341
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);
}
}
}

110
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),
}
}

57
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<IRuntimePlatform>().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; }
}
}

27
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);
}
}
}

35
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;
}
}
}

47
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> _keyboardDevice = new Lazy<KeyboardDevice>(() => new KeyboardDevice());
private Lazy<MouseDevice> _mouseDevice = new Lazy<MouseDevice>(() => new MouseDevice());
public KeyboardDevice KeyboardDevice => _keyboardDevice.Value;
public MouseDevice MouseDevice => _mouseDevice.Value;
public Dictionary<IntPtr, Action<XEvent>> Windows = new Dictionary<IntPtr, Action<XEvent>>();
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<IPlatformThreadingInterface>().ToConstant(new X11PlatformThreading(Display));
.Bind<IWindowingPlatform>().ToConstant(this)
.Bind<IPlatformThreadingInterface>().ToConstant(new X11PlatformThreading(Display, Windows))
.Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration(InputModifiers.Control))
.Bind<IKeyboardDevice>().ToFunc(() => KeyboardDevice)
.Bind<IStandardCursorFactory>().ToConstant(new CursorFactoryStub())
.Bind<IClipboard>().ToSingleton<ClipboardStub>()
.Bind<IPlatformSettings>().ToConstant(new PlatformSettingsStub())
.Bind<ISystemDialogImpl>().ToConstant(new SystemDialogsStub())
.Bind<IPlatformIconLoader>().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();
}
}

24
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<IntPtr, Action<XEvent>> _eventHandlers;
private Thread _mainThread;
[StructLayout(LayoutKind.Explicit)]
@ -102,9 +103,10 @@ namespace Avalonia.X11
List<X11Timer> _timers = new List<X11Timer>();
public X11PlatformThreading(IntPtr display)
public X11PlatformThreading(IntPtr display, Dictionary<IntPtr, Action<XEvent>> 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();
}
}
}

1815
src/Avalonia.X11/X11Structs.cs

File diff suppressed because it is too large

492
src/Avalonia.X11/X11Window.cs

@ -0,0 +1,492 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Reactive.Disposables;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.OpenGL;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
class X11Window : IWindowImpl, IPopupImpl
{
private readonly AvaloniaX11Platform _platform;
private readonly bool _popup;
private readonly X11Info _x11;
private readonly Action<XEvent> _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<InputEventContainer> _inputQueue = new Queue<InputEventContainer>();
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<IWindowingPlatformGlFeature>();
var surfaces = new List<object>
{
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<object> Surfaces { get; }
public Action<RawInputEventArgs> Input { get; set; }
public Action<Rect> Paint { get; set; }
public Action<Size> Resized { get; set; }
public Action<double> ScalingChanged { get; set; }
public Action Deactivated { get; set; }
public Action Activated { get; set; }
public Func<bool> Closing { get; set; }
public WindowState WindowState { get; set; }
public Action<WindowState> WindowStateChanged { get; set; }
public Action Closed { get; set; }
public Action<Point> PositionChanged { get; set; }
public IRenderer CreateRenderer(IRenderRoot root) =>
new DeferredRenderer(root, AvaloniaLocator.Current.GetService<IRenderLoop>());
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)
{
}
}
}

30
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);
}
}
}

468
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];
}
}
}

Loading…
Cancel
Save