mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-23 16:15:34 +00:00
Merge pull request #151 from thefiddler/kms
[KMS] Implement Linux/KMS platform
This commit is contained in:
commit
17aa8051f6
|
@ -23,16 +23,35 @@ namespace Examples.Tests
|
||||||
DisplayDevice dev = DisplayDevice.GetDisplay(DisplayIndex.First + i);
|
DisplayDevice dev = DisplayDevice.GetDisplay(DisplayIndex.First + i);
|
||||||
if (dev != null)
|
if (dev != null)
|
||||||
{
|
{
|
||||||
Trace.WriteLine(dev.ToString());
|
Print(dev.ToString());
|
||||||
MessageBox.Show(dev.ToString());
|
|
||||||
dev.ChangeResolution(dev.SelectResolution(640, 480, 32, 60.0f));
|
dev.ChangeResolution(dev.SelectResolution(640, 480, 32, 60.0f));
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
MessageBox.Show(dev.ToString());
|
Print(dev.ToString());
|
||||||
|
|
||||||
dev.RestoreResolution();
|
dev.RestoreResolution();
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
MessageBox.Show(dev.ToString());
|
Print(dev.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Print(string msg)
|
||||||
|
{
|
||||||
|
Trace.WriteLine(msg);
|
||||||
|
|
||||||
|
// Also display a MessageBox when running on a platform
|
||||||
|
// with WinForms support.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Configuration.RunningOnWindows || Configuration.RunningOnX11 || Configuration.RunningOnMacOS)
|
||||||
|
{
|
||||||
|
MessageBox.Show(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ namespace OpenTK
|
||||||
|
|
||||||
#region public static bool RunningOnLinux
|
#region public static bool RunningOnLinux
|
||||||
|
|
||||||
/// <summary>Gets a System.Boolean indicating whether OpenTK is running on an X11 platform.</summary>
|
/// <summary>Gets a System.Boolean indicating whether OpenTK is running on the Linux kernel.</summary>
|
||||||
public static bool RunningOnLinux { get { return runningOnLinux; } }
|
public static bool RunningOnLinux { get { return runningOnLinux; } }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -351,6 +351,26 @@ namespace OpenTK
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region FromPoint
|
||||||
|
|
||||||
|
internal static DisplayDevice FromPoint(int x, int y)
|
||||||
|
{
|
||||||
|
for (DisplayIndex i = DisplayIndex.First; i < DisplayIndex.Sixth; i++)
|
||||||
|
{
|
||||||
|
DisplayDevice display = DisplayDevice.GetDisplay(i);
|
||||||
|
if (display != null)
|
||||||
|
{
|
||||||
|
if (display.Bounds.Contains(x, y))
|
||||||
|
{
|
||||||
|
return display;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region --- Private Methods ---
|
#region --- Private Methods ---
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace OpenTK.Graphics
|
namespace OpenTK.Graphics
|
||||||
|
@ -84,6 +85,8 @@ namespace OpenTK.Graphics
|
||||||
// validation necessary.)
|
// validation necessary.)
|
||||||
internal override void LoadEntryPoints()
|
internal override void LoadEntryPoints()
|
||||||
{
|
{
|
||||||
|
Debug.Print("Loading entry points for {0}", GetType().FullName);
|
||||||
|
|
||||||
IGraphicsContext context = GraphicsContext.CurrentContext;
|
IGraphicsContext context = GraphicsContext.CurrentContext;
|
||||||
if (context == null)
|
if (context == null)
|
||||||
throw new GraphicsContextMissingException();
|
throw new GraphicsContextMissingException();
|
||||||
|
|
|
@ -38,7 +38,8 @@ namespace OpenTK.Input
|
||||||
{
|
{
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
int x, y;
|
internal const int MaxButtons = 16; // we are storing in an ushort
|
||||||
|
Vector2 position;
|
||||||
MouseScroll scroll;
|
MouseScroll scroll;
|
||||||
ushort buttons;
|
ushort buttons;
|
||||||
bool is_connected;
|
bool is_connected;
|
||||||
|
@ -101,7 +102,7 @@ namespace OpenTK.Input
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a <see cref="OpenTK.Input.MouseScrollWheel"/> instance,
|
/// Gets a <see cref="OpenTK.Input.MouseScroll"/> instance,
|
||||||
/// representing the current state of the mouse scroll wheel.
|
/// representing the current state of the mouse scroll wheel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MouseScroll Scroll
|
public MouseScroll Scroll
|
||||||
|
@ -114,8 +115,8 @@ namespace OpenTK.Input
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int X
|
public int X
|
||||||
{
|
{
|
||||||
get { return x; }
|
get { return (int)Math.Round(position.X); }
|
||||||
internal set { x = value; }
|
internal set { position.X = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -123,8 +124,8 @@ namespace OpenTK.Input
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Y
|
public int Y
|
||||||
{
|
{
|
||||||
get { return y; }
|
get { return (int)Math.Round(position.Y); }
|
||||||
internal set { y = value; }
|
internal set { position.Y = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -272,6 +273,12 @@ namespace OpenTK.Input
|
||||||
|
|
||||||
#region Internal Members
|
#region Internal Members
|
||||||
|
|
||||||
|
internal Vector2 Position
|
||||||
|
{
|
||||||
|
get { return position; }
|
||||||
|
set { position = value; }
|
||||||
|
}
|
||||||
|
|
||||||
internal bool ReadBit(int offset)
|
internal bool ReadBit(int offset)
|
||||||
{
|
{
|
||||||
ValidateOffset(offset);
|
ValidateOffset(offset);
|
||||||
|
|
|
@ -343,9 +343,6 @@
|
||||||
<Compile Include="Platform\X11\X11WindowInfo.cs">
|
<Compile Include="Platform\X11\X11WindowInfo.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Platform\X11\X11Joystick.cs">
|
|
||||||
<SubType>Code</SubType>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Platform\X11\Functions.cs">
|
<Compile Include="Platform\X11\Functions.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -806,6 +803,27 @@
|
||||||
<Compile Include="Platform\X11\XI2Input.cs" />
|
<Compile Include="Platform\X11\XI2Input.cs" />
|
||||||
<Compile Include="Platform\X11\XI2MouseKeyboard.cs" />
|
<Compile Include="Platform\X11\XI2MouseKeyboard.cs" />
|
||||||
<Compile Include="Platform\MacOS\Cocoa\NSFloat.cs" />
|
<Compile Include="Platform\MacOS\Cocoa\NSFloat.cs" />
|
||||||
|
<Compile Include="Platform\Linux\Bindings\Drm.cs" />
|
||||||
|
<Compile Include="Platform\Linux\LinuxFactory.cs" />
|
||||||
|
<Compile Include="Platform\Linux\LinuxNativeWindow.cs" />
|
||||||
|
<Compile Include="Platform\Linux\Bindings\Gbm.cs" />
|
||||||
|
<Compile Include="Platform\Linux\LinuxDisplayDriver.cs" />
|
||||||
|
<Compile Include="Platform\Linux\LinuxJoystick.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Platform\Linux\Bindings\Libc.cs" />
|
||||||
|
<Compile Include="Platform\Linux\LinuxWindowInfo.cs" />
|
||||||
|
<Compile Include="Platform\Linux\LinuxGraphicsContext.cs" />
|
||||||
|
<Compile Include="Platform\Linux\Bindings\Poll.cs" />
|
||||||
|
<Compile Include="Platform\Linux\LinuxKeyboardTTY.cs" />
|
||||||
|
<Compile Include="Platform\Linux\Bindings\Udev.cs" />
|
||||||
|
<Compile Include="Platform\Linux\Bindings\LibInput.cs" />
|
||||||
|
<Compile Include="Platform\Linux\LinuxInput.cs" />
|
||||||
|
<Compile Include="Platform\Linux\Bindings\Terminal.cs" />
|
||||||
|
<Compile Include="Platform\DeviceCollection.cs" />
|
||||||
|
<Compile Include="Platform\Linux\Bindings\Evdev.cs" />
|
||||||
|
<Compile Include="Platform\Linux\DefaultCursor.cs" />
|
||||||
|
<Compile Include="Platform\Linux\Bindings\Kms.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
@ -836,4 +854,8 @@
|
||||||
</MonoDevelop>
|
</MonoDevelop>
|
||||||
</ProjectExtensions>
|
</ProjectExtensions>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Platform\Linux\" />
|
||||||
|
<Folder Include="Platform\Linux\Bindings\" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
151
Source/OpenTK/Platform/DeviceCollection.cs
Normal file
151
Source/OpenTK/Platform/DeviceCollection.cs
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// DeviceCollection.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform
|
||||||
|
{
|
||||||
|
// Holds a collection of hardware devices with an associated id.
|
||||||
|
// Note: 'id' refers to a unique hardware-specific device identifier.
|
||||||
|
// Note: 'index' refers to the offset of the device in the Devices array.
|
||||||
|
// Indices are allocated sequentially as devices are added to the system.
|
||||||
|
// If a device is removed, its index will be reused for the next device
|
||||||
|
// that is added.
|
||||||
|
class DeviceCollection<T> : IEnumerable<T>
|
||||||
|
{
|
||||||
|
readonly Dictionary<int, int> Map = new Dictionary<int, int>();
|
||||||
|
readonly List<T> Devices = new List<T>();
|
||||||
|
|
||||||
|
#region IEnumerable<T> Members
|
||||||
|
|
||||||
|
public IEnumerator<T> GetEnumerator()
|
||||||
|
{
|
||||||
|
return Devices.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IEnumerable implementation
|
||||||
|
|
||||||
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Members
|
||||||
|
|
||||||
|
public void Add(int id, T device)
|
||||||
|
{
|
||||||
|
if (!Map.ContainsKey(id))
|
||||||
|
{
|
||||||
|
int index = GetIndex();
|
||||||
|
Map.Add(id, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Devices[Map[id]] = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(int id)
|
||||||
|
{
|
||||||
|
if (!TryRemove(id))
|
||||||
|
{
|
||||||
|
Debug.Print("Invalid DeviceCollection<{0}> id: {1}", typeof(T).FullName, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryRemove(int id)
|
||||||
|
{
|
||||||
|
if (!Map.ContainsKey(id))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Devices[Map[id]] = default(T);
|
||||||
|
Map.Remove(id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T FromIndex(int index)
|
||||||
|
{
|
||||||
|
if (index >= 0 && index < Devices.Count)
|
||||||
|
{
|
||||||
|
return Devices[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public T FromHardwareId(int id)
|
||||||
|
{
|
||||||
|
if (Map.ContainsKey(id))
|
||||||
|
{
|
||||||
|
return FromIndex(Map[id]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get { return Map.Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private Members
|
||||||
|
|
||||||
|
// Return the index of the first empty slot in Devices.
|
||||||
|
// If no empty slot exists, append a new one and return
|
||||||
|
// that index.
|
||||||
|
int GetIndex()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Devices.Count; i++)
|
||||||
|
{
|
||||||
|
if (Devices[i] == null)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Devices.Add(default(T));
|
||||||
|
return Devices.Count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,13 @@ namespace OpenTK.Platform.Egl
|
||||||
using EGLSurface = IntPtr;
|
using EGLSurface = IntPtr;
|
||||||
using EGLClientBuffer = IntPtr;
|
using EGLClientBuffer = IntPtr;
|
||||||
|
|
||||||
|
enum RenderApi
|
||||||
|
{
|
||||||
|
ES = Egl.OPENGL_ES_API,
|
||||||
|
GL = Egl.OPENGL_API,
|
||||||
|
VG = Egl.OPENVG_API
|
||||||
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
enum RenderableFlags
|
enum RenderableFlags
|
||||||
{
|
{
|
||||||
|
@ -50,6 +57,24 @@ namespace OpenTK.Platform.Egl
|
||||||
VG = Egl.OPENVG_BIT,
|
VG = Egl.OPENVG_BIT,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ErrorCode
|
||||||
|
{
|
||||||
|
SUCCESS = 12288,
|
||||||
|
NOT_INITIALIZED = 12289,
|
||||||
|
BAD_ACCESS = 12290,
|
||||||
|
BAD_ALLOC = 12291,
|
||||||
|
BAD_ATTRIBUTE = 12292,
|
||||||
|
BAD_CONFIG = 12293,
|
||||||
|
BAD_CONTEXT = 12294,
|
||||||
|
BAD_CURRENT_SURFACE = 12295,
|
||||||
|
BAD_DISPLAY = 12296,
|
||||||
|
BAD_MATCH = 12297,
|
||||||
|
BAD_NATIVE_PIXMAP = 12298,
|
||||||
|
BAD_NATIVE_WINDOW = 12299,
|
||||||
|
BAD_PARAMETER = 12300,
|
||||||
|
BAD_SURFACE = 12301,
|
||||||
|
}
|
||||||
|
|
||||||
static partial class Egl
|
static partial class Egl
|
||||||
{
|
{
|
||||||
public const int VERSION_1_0 = 1;
|
public const int VERSION_1_0 = 1;
|
||||||
|
@ -60,20 +85,6 @@ namespace OpenTK.Platform.Egl
|
||||||
public const int FALSE = 0;
|
public const int FALSE = 0;
|
||||||
public const int TRUE = 1;
|
public const int TRUE = 1;
|
||||||
public const int DONT_CARE = -1;
|
public const int DONT_CARE = -1;
|
||||||
public const int SUCCESS = 12288;
|
|
||||||
public const int NOT_INITIALIZED = 12289;
|
|
||||||
public const int BAD_ACCESS = 12290;
|
|
||||||
public const int BAD_ALLOC = 12291;
|
|
||||||
public const int BAD_ATTRIBUTE = 12292;
|
|
||||||
public const int BAD_CONFIG = 12293;
|
|
||||||
public const int BAD_CONTEXT = 12294;
|
|
||||||
public const int BAD_CURRENT_SURFACE = 12295;
|
|
||||||
public const int BAD_DISPLAY = 12296;
|
|
||||||
public const int BAD_MATCH = 12297;
|
|
||||||
public const int BAD_NATIVE_PIXMAP = 12298;
|
|
||||||
public const int BAD_NATIVE_WINDOW = 12299;
|
|
||||||
public const int BAD_PARAMETER = 12300;
|
|
||||||
public const int BAD_SURFACE = 12301;
|
|
||||||
public const int CONTEXT_LOST = 12302;
|
public const int CONTEXT_LOST = 12302;
|
||||||
public const int BUFFER_SIZE = 12320;
|
public const int BUFFER_SIZE = 12320;
|
||||||
public const int ALPHA_SIZE = 12321;
|
public const int ALPHA_SIZE = 12321;
|
||||||
|
@ -178,7 +189,7 @@ namespace OpenTK.Platform.Egl
|
||||||
public const int ALPHA_FORMAT_PRE = VG_ALPHA_FORMAT_PRE;
|
public const int ALPHA_FORMAT_PRE = VG_ALPHA_FORMAT_PRE;
|
||||||
|
|
||||||
[DllImportAttribute("libEGL.dll", EntryPoint = "eglGetError")]
|
[DllImportAttribute("libEGL.dll", EntryPoint = "eglGetError")]
|
||||||
public static extern int GetError();
|
public static extern ErrorCode GetError();
|
||||||
|
|
||||||
[DllImportAttribute("libEGL.dll", EntryPoint = "eglGetDisplay")]
|
[DllImportAttribute("libEGL.dll", EntryPoint = "eglGetDisplay")]
|
||||||
public static extern EGLDisplay GetDisplay(EGLNativeDisplayType display_id);
|
public static extern EGLDisplay GetDisplay(EGLNativeDisplayType display_id);
|
||||||
|
@ -225,7 +236,7 @@ namespace OpenTK.Platform.Egl
|
||||||
|
|
||||||
[DllImportAttribute("libEGL.dll", EntryPoint = "eglBindAPI")]
|
[DllImportAttribute("libEGL.dll", EntryPoint = "eglBindAPI")]
|
||||||
[return: MarshalAsAttribute(UnmanagedType.I1)]
|
[return: MarshalAsAttribute(UnmanagedType.I1)]
|
||||||
public static extern bool BindAPI(int api);
|
public static extern bool BindAPI(RenderApi api);
|
||||||
|
|
||||||
[DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryAPI")]
|
[DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryAPI")]
|
||||||
public static extern int QueryAPI();
|
public static extern int QueryAPI();
|
||||||
|
|
|
@ -35,9 +35,9 @@ namespace OpenTK.Platform.Egl
|
||||||
{
|
{
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
readonly RenderableFlags Renderable;
|
protected readonly RenderableFlags Renderable;
|
||||||
|
protected EglWindowInfo WindowInfo;
|
||||||
|
|
||||||
EglWindowInfo WindowInfo;
|
|
||||||
IntPtr HandleAsEGLContext { get { return Handle.Handle; } set { Handle = new ContextHandle(value); } }
|
IntPtr HandleAsEGLContext { get { return Handle.Handle; } set { Handle = new ContextHandle(value); } }
|
||||||
int swap_interval = 1; // Default interval is defined as 1 in EGL.
|
int swap_interval = 1; // Default interval is defined as 1 in EGL.
|
||||||
|
|
||||||
|
@ -60,7 +60,20 @@ namespace OpenTK.Platform.Egl
|
||||||
// Select an EGLConfig that matches the desired mode. We cannot use the 'mode'
|
// Select an EGLConfig that matches the desired mode. We cannot use the 'mode'
|
||||||
// parameter directly, since it may have originated on a different system (e.g. GLX)
|
// parameter directly, since it may have originated on a different system (e.g. GLX)
|
||||||
// and it may not support the desired renderer.
|
// and it may not support the desired renderer.
|
||||||
|
|
||||||
|
Renderable = RenderableFlags.GL;
|
||||||
|
if ((flags & GraphicsContextFlags.Embedded) != 0)
|
||||||
|
{
|
||||||
Renderable = major > 1 ? RenderableFlags.ES2 : RenderableFlags.ES;
|
Renderable = major > 1 ? RenderableFlags.ES2 : RenderableFlags.ES;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderApi api = (Renderable & RenderableFlags.GL) != 0 ? RenderApi.GL : RenderApi.ES;
|
||||||
|
Debug.Print("[EGL] Binding {0} rendering API.", api);
|
||||||
|
if (!Egl.BindAPI(api))
|
||||||
|
{
|
||||||
|
Debug.Print("[EGL] Failed to bind rendering API. Error: {0}", Egl.GetError());
|
||||||
|
}
|
||||||
|
|
||||||
Mode = new EglGraphicsMode().SelectGraphicsMode(window,
|
Mode = new EglGraphicsMode().SelectGraphicsMode(window,
|
||||||
mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples,
|
mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples,
|
||||||
mode.AccumulatorFormat, mode.Buffers, mode.Stereo,
|
mode.AccumulatorFormat, mode.Buffers, mode.Stereo,
|
||||||
|
@ -133,7 +146,8 @@ namespace OpenTK.Platform.Egl
|
||||||
if (Egl.SwapInterval(WindowInfo.Display, value))
|
if (Egl.SwapInterval(WindowInfo.Display, value))
|
||||||
swap_interval = value;
|
swap_interval = value;
|
||||||
else
|
else
|
||||||
Debug.Print("[Warning] Egl.SwapInterval({0}, {1}) failed.", WindowInfo.Display, value);
|
Debug.Print("[Warning] Egl.SwapInterval({0}, {1}) failed. Error: {2}",
|
||||||
|
WindowInfo.Display, value, Egl.GetError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,15 @@ namespace OpenTK.Platform.Egl
|
||||||
{
|
{
|
||||||
class EglGraphicsMode
|
class EglGraphicsMode
|
||||||
{
|
{
|
||||||
|
public GraphicsMode SelectGraphicsMode(EglWindowInfo window,
|
||||||
|
GraphicsMode mode, RenderableFlags flags)
|
||||||
|
{
|
||||||
|
return SelectGraphicsMode(window,
|
||||||
|
mode.ColorFormat, mode.Depth, mode.Stencil,
|
||||||
|
mode.Samples, mode.AccumulatorFormat, mode.Buffers, mode.Stereo,
|
||||||
|
flags);
|
||||||
|
}
|
||||||
|
|
||||||
public GraphicsMode SelectGraphicsMode(EglWindowInfo window,
|
public GraphicsMode SelectGraphicsMode(EglWindowInfo window,
|
||||||
ColorFormat color, int depth, int stencil,
|
ColorFormat color, int depth, int stencil,
|
||||||
int samples, ColorFormat accum, int buffers, bool stereo,
|
int samples, ColorFormat accum, int buffers, bool stereo,
|
||||||
|
|
|
@ -28,14 +28,16 @@
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace OpenTK.Platform.Egl
|
namespace OpenTK.Platform.Egl
|
||||||
{
|
{
|
||||||
class EglUnixContext : EglContext
|
class EglUnixContext : EglContext
|
||||||
{
|
{
|
||||||
readonly IntPtr ES1 = OpenTK.Platform.X11.DL.Open("libGLESv1_CM", X11.DLOpenFlags.Lazy);
|
IntPtr ES1 = OpenTK.Platform.X11.DL.Open("libGLESv1_CM", X11.DLOpenFlags.Lazy);
|
||||||
readonly IntPtr ES2 = OpenTK.Platform.X11.DL.Open("libGLESv2", X11.DLOpenFlags.Lazy);
|
IntPtr ES2 = OpenTK.Platform.X11.DL.Open("libGLESv2", X11.DLOpenFlags.Lazy);
|
||||||
|
IntPtr GL = OpenTK.Platform.X11.DL.Open("libGL", X11.DLOpenFlags.Lazy);
|
||||||
|
|
||||||
public EglUnixContext(GraphicsMode mode, EglWindowInfo window, IGraphicsContext sharedContext,
|
public EglUnixContext(GraphicsMode mode, EglWindowInfo window, IGraphicsContext sharedContext,
|
||||||
int major, int minor, GraphicsContextFlags flags)
|
int major, int minor, GraphicsContextFlags flags)
|
||||||
|
@ -59,6 +61,10 @@ namespace OpenTK.Platform.Egl
|
||||||
{
|
{
|
||||||
return X11.DL.Symbol(ES2, function);
|
return X11.DL.Symbol(ES2, function);
|
||||||
}
|
}
|
||||||
|
else if ((renderable & RenderableFlags.GL) != 0 && GL != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
return X11.DL.Symbol(GL, function);
|
||||||
|
}
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,8 +78,32 @@ namespace OpenTK.Platform.Egl
|
||||||
{
|
{
|
||||||
X11.DL.Close(ES2);
|
X11.DL.Close(ES2);
|
||||||
}
|
}
|
||||||
|
if (GL != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
X11.DL.Close(GL);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL = ES1 = ES2 = IntPtr.Zero;
|
||||||
|
|
||||||
base.Dispose(manual);
|
base.Dispose(manual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void LoadAll()
|
||||||
|
{
|
||||||
|
// Modern unices can use EGL to create
|
||||||
|
// both GL and ES contexts, so we need
|
||||||
|
// to load all entry points. This is
|
||||||
|
// especially true on KMS, Wayland and Mir.
|
||||||
|
|
||||||
|
Stopwatch time = Stopwatch.StartNew();
|
||||||
|
|
||||||
|
new OpenTK.Graphics.OpenGL.GL().LoadEntryPoints();
|
||||||
|
new OpenTK.Graphics.OpenGL4.GL().LoadEntryPoints();
|
||||||
|
new OpenTK.Graphics.ES11.GL().LoadEntryPoints();
|
||||||
|
new OpenTK.Graphics.ES20.GL().LoadEntryPoints();
|
||||||
|
new OpenTK.Graphics.ES30.GL().LoadEntryPoints();
|
||||||
|
|
||||||
|
Debug.Print("Bindings loaded in {0} ms.", time.Elapsed.TotalMilliseconds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ namespace OpenTK.Platform.Egl
|
||||||
|
|
||||||
#region Public Members
|
#region Public Members
|
||||||
|
|
||||||
public IntPtr Handle { get { return handle; } private set { handle = value; } }
|
public IntPtr Handle { get { return handle; } set { handle = value; } }
|
||||||
|
|
||||||
public IntPtr Display { get { return display; } private set { display = value; } }
|
public IntPtr Display { get { return display; } private set { display = value; } }
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ namespace OpenTK.Platform.Egl
|
||||||
if (Surface==IntPtr.Zero)
|
if (Surface==IntPtr.Zero)
|
||||||
{
|
{
|
||||||
throw new GraphicsContextException(String.Format(
|
throw new GraphicsContextException(String.Format(
|
||||||
"[Error] Failed to create EGL window surface, error {0}.", Egl.GetError()));
|
"[EGL] Failed to create window surface, error {0}.", Egl.GetError()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ namespace OpenTK.Platform
|
||||||
// Create regular platform backend
|
// Create regular platform backend
|
||||||
if (Configuration.RunningOnSdl2) Default = new SDL2.Sdl2Factory();
|
if (Configuration.RunningOnSdl2) Default = new SDL2.Sdl2Factory();
|
||||||
else if (Configuration.RunningOnX11) Default = new X11.X11Factory();
|
else if (Configuration.RunningOnX11) Default = new X11.X11Factory();
|
||||||
|
else if (Configuration.RunningOnLinux) Default = new Linux.LinuxFactory();
|
||||||
else if (Configuration.RunningOnWindows) Default = new Windows.WinFactory();
|
else if (Configuration.RunningOnWindows) Default = new Windows.WinFactory();
|
||||||
else if (Configuration.RunningOnMacOS) Default = new MacOS.MacOSFactory();
|
else if (Configuration.RunningOnMacOS) Default = new MacOS.MacOSFactory();
|
||||||
else Default = new UnsupportedPlatform();
|
else Default = new UnsupportedPlatform();
|
||||||
|
@ -70,7 +71,8 @@ namespace OpenTK.Platform
|
||||||
}
|
}
|
||||||
else if (Egl.Egl.IsSupported)
|
else if (Egl.Egl.IsSupported)
|
||||||
{
|
{
|
||||||
if (Configuration.RunningOnX11) Embedded = new Egl.EglX11PlatformFactory();
|
if (Configuration.RunningOnLinux) Embedded = Default;
|
||||||
|
else if (Configuration.RunningOnX11) Embedded = new Egl.EglX11PlatformFactory();
|
||||||
else if (Configuration.RunningOnWindows) Embedded = new Egl.EglWinPlatformFactory();
|
else if (Configuration.RunningOnWindows) Embedded = new Egl.EglWinPlatformFactory();
|
||||||
else if (Configuration.RunningOnMacOS) Embedded = new Egl.EglMacPlatformFactory();
|
else if (Configuration.RunningOnMacOS) Embedded = new Egl.EglMacPlatformFactory();
|
||||||
else Embedded = new UnsupportedPlatform();
|
else Embedded = new UnsupportedPlatform();
|
||||||
|
|
209
Source/OpenTK/Platform/Linux/Bindings/Drm.cs
Normal file
209
Source/OpenTK/Platform/Linux/Bindings/Drm.cs
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// Drm.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate void VBlankCallback(int fd,
|
||||||
|
int sequence,
|
||||||
|
int tv_sec,
|
||||||
|
int tv_usec,
|
||||||
|
IntPtr user_data);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate void PageFlipCallback(int fd,
|
||||||
|
int sequence,
|
||||||
|
int tv_sec,
|
||||||
|
int tv_usec,
|
||||||
|
IntPtr user_data);
|
||||||
|
|
||||||
|
class Drm
|
||||||
|
{
|
||||||
|
const string lib = "libdrm";
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmHandleEvent", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int HandleEvent(int fd, ref EventContext evctx);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmModeAddFB", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int ModeAddFB(int fd, int width, int height, byte depth,
|
||||||
|
byte bpp, int pitch, int bo_handle,
|
||||||
|
out int buf_id);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmModeRmFB", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int ModeRmFB(int fd, int bufferId);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmModeFreeCrtc", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void ModeFreeCrtc(IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmModeGetCrtc", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr ModeGetCrtc(int fd, int crtcId);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmModeFreeConnector", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void ModeFreeConnector(IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmModeFreeEncoder", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void ModeFreeEncoder(IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmModeGetConnector", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr ModeGetConnector(int fd, int connector_id);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmModeGetEncoder", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr ModeGetEncoder(int fd, int encoder_id);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmModeGetResources", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr ModeGetResources(int fd);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmModePageFlip", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int ModePageFlip(int fd, int crtc_id, int fb_id,
|
||||||
|
PageFlipFlags flags, IntPtr user_data);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmModeSetCrtc", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
unsafe public static extern int ModeSetCrtc(int fd, int crtcId, int bufferId,
|
||||||
|
int x, int y, int* connectors, int count, ModeInfo* mode);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmModeSetCursor2", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int SetCursor(int fd, int crtcId, int bo_handle, int width, int height, int hot_x, int hot_y);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "drmModeMoveCursor", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int MoveCursor(int fd, int crtcId, int x, int y);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ModeConnection
|
||||||
|
{
|
||||||
|
Connected = 1,
|
||||||
|
Disconnected = 2,
|
||||||
|
Unknown = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ModeSubPixel
|
||||||
|
{
|
||||||
|
Unknown = 1,
|
||||||
|
HorizontalRgb = 2,
|
||||||
|
HorizontalBgr = 3,
|
||||||
|
VerticalRgb = 4,
|
||||||
|
VerticalBgr = 5,
|
||||||
|
None = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum PageFlipFlags
|
||||||
|
{
|
||||||
|
FlipEvent = 0x01,
|
||||||
|
FlipAsync = 0x02,
|
||||||
|
FlipFlags = FlipEvent | FlipAsync
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
struct EventContext
|
||||||
|
{
|
||||||
|
public int version;
|
||||||
|
public IntPtr vblank_handler;
|
||||||
|
public IntPtr page_flip_handler;
|
||||||
|
|
||||||
|
public static readonly int Version = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
unsafe struct ModeConnector
|
||||||
|
{
|
||||||
|
public int connector_id;
|
||||||
|
public int encoder_id;
|
||||||
|
public int connector_type;
|
||||||
|
public int connector_type_id;
|
||||||
|
public ModeConnection connection;
|
||||||
|
public int mmWidth, mmHeight;
|
||||||
|
public ModeSubPixel subpixel;
|
||||||
|
|
||||||
|
public int count_modes;
|
||||||
|
public ModeInfo* modes;
|
||||||
|
|
||||||
|
public int count_props;
|
||||||
|
public int *props;
|
||||||
|
public long *prop_values;
|
||||||
|
|
||||||
|
public int count_encoders;
|
||||||
|
public int *encoders;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ModeCrtc
|
||||||
|
{
|
||||||
|
public int crtc_id;
|
||||||
|
public int buffer_id;
|
||||||
|
|
||||||
|
public int x, y;
|
||||||
|
public int width, height;
|
||||||
|
public int mode_valid;
|
||||||
|
public ModeInfo mode;
|
||||||
|
|
||||||
|
public int gamma_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ModeEncoder
|
||||||
|
{
|
||||||
|
public int encoder_id;
|
||||||
|
public int encoder_type;
|
||||||
|
public int crtc_id;
|
||||||
|
public int possible_crtcs;
|
||||||
|
public int possible_clones;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
unsafe struct ModeInfo
|
||||||
|
{
|
||||||
|
public uint clock;
|
||||||
|
public ushort hdisplay, hsync_start, hsync_end, htotal, hskew;
|
||||||
|
public ushort vdisplay, vsync_start, vsync_end, vtotal, vscan;
|
||||||
|
|
||||||
|
public int vrefresh; // refresh rate * 1000
|
||||||
|
|
||||||
|
public uint flags;
|
||||||
|
public uint type;
|
||||||
|
public fixed sbyte name[32];
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
unsafe struct ModeRes
|
||||||
|
{
|
||||||
|
public int count_fbs;
|
||||||
|
public int* fbs;
|
||||||
|
public int count_crtcs;
|
||||||
|
public int* crtcs;
|
||||||
|
public int count_connectors;
|
||||||
|
public int* connectors;
|
||||||
|
public int count_encoders;
|
||||||
|
public int* encoders;
|
||||||
|
public int min_width, max_width;
|
||||||
|
public int min_height, max_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
452
Source/OpenTK/Platform/Linux/Bindings/Evdev.cs
Normal file
452
Source/OpenTK/Platform/Linux/Bindings/Evdev.cs
Normal file
|
@ -0,0 +1,452 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// Evdev.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using OpenTK.Input;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
// Bindings for linux/input.h
|
||||||
|
class Evdev
|
||||||
|
{
|
||||||
|
#region KeyMap
|
||||||
|
|
||||||
|
public static readonly Key[] KeyMap = new Key[]
|
||||||
|
{
|
||||||
|
// 0-7
|
||||||
|
Key.Unknown,
|
||||||
|
Key.Escape,
|
||||||
|
Key.Number1,
|
||||||
|
Key.Number2,
|
||||||
|
Key.Number3,
|
||||||
|
Key.Number4,
|
||||||
|
Key.Number5,
|
||||||
|
Key.Number6,
|
||||||
|
// 8-15
|
||||||
|
Key.Number7,
|
||||||
|
Key.Number8,
|
||||||
|
Key.Number9,
|
||||||
|
Key.Number0,
|
||||||
|
Key.Minus,
|
||||||
|
Key.Plus,
|
||||||
|
Key.BackSpace,
|
||||||
|
Key.Tab,
|
||||||
|
// 16-23
|
||||||
|
Key.Q,
|
||||||
|
Key.W,
|
||||||
|
Key.E,
|
||||||
|
Key.R,
|
||||||
|
Key.T,
|
||||||
|
Key.Y,
|
||||||
|
Key.U,
|
||||||
|
Key.I,
|
||||||
|
// 24-31
|
||||||
|
Key.O,
|
||||||
|
Key.P,
|
||||||
|
Key.BracketLeft,
|
||||||
|
Key.BracketRight,
|
||||||
|
Key.Enter,
|
||||||
|
Key.ControlLeft,
|
||||||
|
Key.A,
|
||||||
|
Key.S,
|
||||||
|
// 32-39
|
||||||
|
Key.D,
|
||||||
|
Key.F,
|
||||||
|
Key.G,
|
||||||
|
Key.H,
|
||||||
|
Key.J,
|
||||||
|
Key.K,
|
||||||
|
Key.L,
|
||||||
|
Key.Semicolon,
|
||||||
|
// 40-47
|
||||||
|
Key.Quote,
|
||||||
|
Key.Tilde,
|
||||||
|
Key.ShiftLeft,
|
||||||
|
Key.BackSlash, //Key.Execute,
|
||||||
|
Key.Z,
|
||||||
|
Key.X,
|
||||||
|
Key.C,
|
||||||
|
Key.V, //Key.Help,
|
||||||
|
// 48-55
|
||||||
|
Key.B,
|
||||||
|
Key.N,
|
||||||
|
Key.M,
|
||||||
|
Key.Comma,
|
||||||
|
Key.Period,
|
||||||
|
Key.Slash,
|
||||||
|
Key.ShiftRight,
|
||||||
|
Key.KeypadMultiply,
|
||||||
|
// 56-63
|
||||||
|
Key.AltLeft,
|
||||||
|
Key.Space,
|
||||||
|
Key.CapsLock,
|
||||||
|
Key.F1,
|
||||||
|
Key.F2,
|
||||||
|
Key.F3,
|
||||||
|
Key.F4,
|
||||||
|
Key.F5,
|
||||||
|
// 64-71
|
||||||
|
Key.F6,
|
||||||
|
Key.F7,
|
||||||
|
Key.F8,
|
||||||
|
Key.F9,
|
||||||
|
Key.F10,
|
||||||
|
Key.NumLock,
|
||||||
|
Key.ScrollLock,
|
||||||
|
Key.Keypad7,
|
||||||
|
// 72-79
|
||||||
|
Key.Keypad8,
|
||||||
|
Key.Keypad9,
|
||||||
|
Key.KeypadSubtract,
|
||||||
|
Key.Keypad4,
|
||||||
|
Key.Keypad5,
|
||||||
|
Key.Keypad6,
|
||||||
|
Key.KeypadPlus,
|
||||||
|
Key.Keypad1,
|
||||||
|
// 80-87
|
||||||
|
Key.Keypad2,
|
||||||
|
Key.Keypad3,
|
||||||
|
Key.Keypad0,
|
||||||
|
Key.KeypadPeriod,
|
||||||
|
Key.Unknown,
|
||||||
|
Key.Unknown, // zenkakuhankaku
|
||||||
|
Key.Unknown, // 102ND
|
||||||
|
Key.F11,
|
||||||
|
// 88-95
|
||||||
|
Key.F12,
|
||||||
|
Key.Unknown, // ro
|
||||||
|
Key.Unknown, // katakana
|
||||||
|
Key.Unknown, // hiragana
|
||||||
|
Key.Unknown, // henkan
|
||||||
|
Key.Unknown, // katakanahiragana
|
||||||
|
Key.Unknown, // muhenkan
|
||||||
|
Key.Unknown, // kpjpcomma
|
||||||
|
// 96-103
|
||||||
|
Key.KeypadEnter,
|
||||||
|
Key.ControlRight,
|
||||||
|
Key.KeypadDivide,
|
||||||
|
Key.Unknown, // sysrq
|
||||||
|
Key.AltRight,
|
||||||
|
Key.Unknown, // linefeed
|
||||||
|
Key.Home,
|
||||||
|
Key.Up,
|
||||||
|
// 104-111
|
||||||
|
Key.PageUp,
|
||||||
|
Key.Left,
|
||||||
|
Key.Right,
|
||||||
|
Key.End,
|
||||||
|
Key.Down,
|
||||||
|
Key.PageDown,
|
||||||
|
Key.Insert,
|
||||||
|
Key.Delete,
|
||||||
|
// 112-119
|
||||||
|
Key.Unknown, // macro
|
||||||
|
Key.Unknown, // mute
|
||||||
|
Key.Unknown, // volumedown
|
||||||
|
Key.Unknown, // volumeup
|
||||||
|
Key.Unknown, // power
|
||||||
|
Key.Unknown, // kpequal
|
||||||
|
Key.Unknown, // kpplusminus
|
||||||
|
Key.Pause,
|
||||||
|
// 120-127
|
||||||
|
Key.Unknown, // scale
|
||||||
|
Key.Unknown, // kpcomma
|
||||||
|
Key.Unknown, // hangeul / hanguel
|
||||||
|
Key.Unknown, // hanja
|
||||||
|
Key.Unknown, // yen
|
||||||
|
Key.WinLeft,
|
||||||
|
Key.WinRight,
|
||||||
|
Key.Unknown, // compose
|
||||||
|
// 128-135
|
||||||
|
Key.Unknown, // stop
|
||||||
|
Key.Unknown, // again
|
||||||
|
Key.Unknown, // props
|
||||||
|
Key.Unknown, // undo
|
||||||
|
Key.Unknown, // front
|
||||||
|
Key.Unknown, // copy
|
||||||
|
Key.Unknown, // open
|
||||||
|
Key.Unknown, // paste
|
||||||
|
// 136-143
|
||||||
|
Key.Unknown, // find
|
||||||
|
Key.Unknown, // cut
|
||||||
|
Key.Unknown, // help
|
||||||
|
Key.Unknown, // menu
|
||||||
|
Key.Unknown, // calc
|
||||||
|
Key.Unknown, // setup
|
||||||
|
Key.Unknown, // sleep
|
||||||
|
Key.Unknown, // wakeup
|
||||||
|
// 144-151
|
||||||
|
Key.Unknown, // file
|
||||||
|
Key.Unknown, // send file
|
||||||
|
Key.Unknown, // delete file
|
||||||
|
Key.Unknown, // xfer
|
||||||
|
Key.Unknown, // prog1
|
||||||
|
Key.Unknown, // prog2
|
||||||
|
Key.Unknown, // www
|
||||||
|
Key.Unknown, // msdos
|
||||||
|
// 152-159
|
||||||
|
Key.Unknown, // coffee / screenlock
|
||||||
|
Key.Unknown, // direction
|
||||||
|
Key.Unknown, // cycle windows
|
||||||
|
Key.Unknown, // mail
|
||||||
|
Key.Unknown, // bookmarks
|
||||||
|
Key.Unknown, // computer
|
||||||
|
Key.Back,
|
||||||
|
Key.Unknown, // forward
|
||||||
|
// 160-167
|
||||||
|
Key.Unknown, // close cd
|
||||||
|
Key.Unknown, // eject cd
|
||||||
|
Key.Unknown, // eject/close cd
|
||||||
|
Key.Unknown, // next song
|
||||||
|
Key.Unknown, // play/pause
|
||||||
|
Key.Unknown, // previous song
|
||||||
|
Key.Unknown, // stop cd
|
||||||
|
Key.Unknown, // record
|
||||||
|
// 168-175
|
||||||
|
Key.Unknown, // rewind
|
||||||
|
Key.Unknown, // phone
|
||||||
|
Key.Unknown, // iso
|
||||||
|
Key.Unknown, // config
|
||||||
|
Key.Unknown, // homepage
|
||||||
|
Key.Unknown, // refresh
|
||||||
|
Key.Unknown, // exit
|
||||||
|
Key.Unknown, // move,
|
||||||
|
// 176-183
|
||||||
|
Key.Unknown, // edit,
|
||||||
|
Key.Unknown, // scroll up,
|
||||||
|
Key.Unknown, // scroll down,
|
||||||
|
Key.Unknown, // kp left paren,
|
||||||
|
Key.Unknown, // kp right paren,
|
||||||
|
Key.Unknown, // new,
|
||||||
|
Key.Unknown, // redo,
|
||||||
|
Key.F13,
|
||||||
|
// 184-191
|
||||||
|
Key.F14,
|
||||||
|
Key.F15,
|
||||||
|
Key.F16,
|
||||||
|
Key.F17,
|
||||||
|
Key.F18,
|
||||||
|
Key.F19,
|
||||||
|
Key.F20,
|
||||||
|
Key.F21,
|
||||||
|
// 192-199
|
||||||
|
Key.F22,
|
||||||
|
Key.F23,
|
||||||
|
Key.F24,
|
||||||
|
Key.Unknown,
|
||||||
|
Key.Unknown,
|
||||||
|
Key.Unknown,
|
||||||
|
Key.Unknown,
|
||||||
|
Key.Unknown,
|
||||||
|
// 200-207
|
||||||
|
Key.Unknown, // play cd
|
||||||
|
Key.Unknown, // pause cd
|
||||||
|
Key.Unknown, // prog3
|
||||||
|
Key.Unknown, // prog4
|
||||||
|
Key.Unknown, // dashboard
|
||||||
|
Key.Unknown, // suspend
|
||||||
|
Key.Unknown, // close
|
||||||
|
Key.Unknown, // play
|
||||||
|
// 208-215
|
||||||
|
Key.Unknown, // fast forward
|
||||||
|
Key.Unknown, // bass boost
|
||||||
|
Key.Unknown, // print
|
||||||
|
Key.Unknown, // hp
|
||||||
|
Key.Unknown, // camera
|
||||||
|
Key.Unknown, // sound
|
||||||
|
Key.Unknown, // question
|
||||||
|
Key.Unknown, // email
|
||||||
|
// 216-223
|
||||||
|
Key.Unknown, // chat
|
||||||
|
Key.Unknown, // search
|
||||||
|
Key.Unknown, // connect
|
||||||
|
Key.Unknown, // finance
|
||||||
|
Key.Unknown, // sport
|
||||||
|
Key.Unknown, // shop
|
||||||
|
Key.Unknown, // alt erase
|
||||||
|
Key.Unknown, // cancel
|
||||||
|
// 224-231
|
||||||
|
Key.Unknown, // brightness down
|
||||||
|
Key.Unknown, // brightness up
|
||||||
|
Key.Unknown, // media
|
||||||
|
Key.Unknown, // switch video mode
|
||||||
|
Key.Unknown, // dillum toggle
|
||||||
|
Key.Unknown, // dillum down
|
||||||
|
Key.Unknown, // dillum up
|
||||||
|
Key.Unknown, // send
|
||||||
|
// 232-239
|
||||||
|
Key.Unknown, // reply
|
||||||
|
Key.Unknown, // forward email
|
||||||
|
Key.Unknown, // save
|
||||||
|
Key.Unknown, // documents
|
||||||
|
Key.Unknown, // battery
|
||||||
|
Key.Unknown, // bluetooth
|
||||||
|
Key.Unknown, // wlan
|
||||||
|
Key.Unknown, // uwb
|
||||||
|
// 240-247
|
||||||
|
Key.Unknown,
|
||||||
|
Key.Unknown, // video next
|
||||||
|
Key.Unknown, // video prev
|
||||||
|
Key.Unknown, // brightness cycle
|
||||||
|
Key.Unknown, // brightness zero
|
||||||
|
Key.Unknown, // display off
|
||||||
|
Key.Unknown, // wwan / wimax
|
||||||
|
Key.Unknown, // rfkill
|
||||||
|
// 248-255
|
||||||
|
Key.Unknown, // mic mute
|
||||||
|
Key.Unknown,
|
||||||
|
Key.Unknown,
|
||||||
|
Key.Unknown,
|
||||||
|
Key.Unknown,
|
||||||
|
Key.Unknown,
|
||||||
|
Key.Unknown,
|
||||||
|
Key.Unknown, // reserved
|
||||||
|
};
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public static MouseButton GetMouseButton(EvdevButton button)
|
||||||
|
{
|
||||||
|
switch (button)
|
||||||
|
{
|
||||||
|
case EvdevButton.LEFT:
|
||||||
|
return MouseButton.Left;
|
||||||
|
case EvdevButton.RIGHT:
|
||||||
|
return MouseButton.Right;
|
||||||
|
case EvdevButton.MIDDLE:
|
||||||
|
return MouseButton.Middle;
|
||||||
|
case EvdevButton.BTN0:
|
||||||
|
return MouseButton.Button1;
|
||||||
|
case EvdevButton.BTN1:
|
||||||
|
return MouseButton.Button2;
|
||||||
|
case EvdevButton.BTN2:
|
||||||
|
return MouseButton.Button3;
|
||||||
|
case EvdevButton.BTN3:
|
||||||
|
return MouseButton.Button4;
|
||||||
|
case EvdevButton.BTN4:
|
||||||
|
return MouseButton.Button5;
|
||||||
|
case EvdevButton.BTN5:
|
||||||
|
return MouseButton.Button6;
|
||||||
|
case EvdevButton.BTN6:
|
||||||
|
return MouseButton.Button7;
|
||||||
|
case EvdevButton.BTN7:
|
||||||
|
return MouseButton.Button8;
|
||||||
|
case EvdevButton.BTN8:
|
||||||
|
return MouseButton.Button9;
|
||||||
|
default:
|
||||||
|
Debug.Print("[Input] Unknown EvdevButton {0}", button);
|
||||||
|
return MouseButton.Left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum EvdevButton : uint
|
||||||
|
{
|
||||||
|
MISC = 0x100,
|
||||||
|
BTN0 = 0x100,
|
||||||
|
BTN1 = 0x101,
|
||||||
|
BTN2 = 0x102,
|
||||||
|
BTN3 = 0x103,
|
||||||
|
BTN4 = 0x104,
|
||||||
|
BTN5 = 0x105,
|
||||||
|
BTN6 = 0x106,
|
||||||
|
BTN7 = 0x107,
|
||||||
|
BTN8 = 0x108,
|
||||||
|
BTN9 = 0x109,
|
||||||
|
|
||||||
|
MOUSE = 0x110,
|
||||||
|
LEFT = 0x110,
|
||||||
|
RIGHT = 0x111,
|
||||||
|
MIDDLE = 0x112,
|
||||||
|
SIDE = 0x113,
|
||||||
|
EXTRA = 0x114,
|
||||||
|
FORWARD = 0x115,
|
||||||
|
BACK = 0x116,
|
||||||
|
TASK = 0x117,
|
||||||
|
|
||||||
|
JOYSTICK = 0x120,
|
||||||
|
TRIGGER = 0x120,
|
||||||
|
THUMB = 0x121,
|
||||||
|
THUMB2 = 0x122,
|
||||||
|
TOP = 0x123,
|
||||||
|
TOP2 = 0x124,
|
||||||
|
PINKIE = 0x125,
|
||||||
|
BASE = 0x126,
|
||||||
|
BASE2 = 0x127,
|
||||||
|
BASE3 = 0x128,
|
||||||
|
BASE4 = 0x129,
|
||||||
|
BASE5 = 0x12a,
|
||||||
|
BASE6 = 0x12b,
|
||||||
|
DEAD = 0x12f,
|
||||||
|
|
||||||
|
GAMEPAD = 0x130,
|
||||||
|
SOUTH = 0x130,
|
||||||
|
A = SOUTH,
|
||||||
|
EAST = 0x131,
|
||||||
|
B = EAST,
|
||||||
|
C = 0x132,
|
||||||
|
NORTH = 0x133,
|
||||||
|
X = NORTH,
|
||||||
|
WEST = 0x134,
|
||||||
|
Y = WEST,
|
||||||
|
Z = 0x135,
|
||||||
|
TL = 0x136,
|
||||||
|
TR = 0x137,
|
||||||
|
TL2 = 0x138,
|
||||||
|
TR2 = 0x139,
|
||||||
|
SELECT = 0x13a,
|
||||||
|
START = 0x13b,
|
||||||
|
MODE = 0x13c,
|
||||||
|
THUMBL = 0x13d,
|
||||||
|
THUMBR = 0x13e,
|
||||||
|
|
||||||
|
DIGI = 0x140,
|
||||||
|
TOOL_PEN = 0x140,
|
||||||
|
TOOL_RUBBER = 0x141,
|
||||||
|
TOOL_BRUSH = 0x142,
|
||||||
|
TOOL_PENCIL = 0x143,
|
||||||
|
TOOL_AIRBRUSH = 0x144,
|
||||||
|
TOOL_FINGER = 0x145,
|
||||||
|
TOOL_MOUSE = 0x146,
|
||||||
|
TOOL_LENS = 0x147,
|
||||||
|
TOOL_QUINTTAP = 0x148, // Five fingers on trackpad
|
||||||
|
TOUCH = 0x14a,
|
||||||
|
STYLUS = 0x14b,
|
||||||
|
STYLUS2 = 0x14c,
|
||||||
|
TOOL_DOUBLETAP = 0x14d,
|
||||||
|
TOOL_TRIPLETAP = 0x14e,
|
||||||
|
TOOL_QUADTAP = 0x14f, // Four fingers on trackpad
|
||||||
|
|
||||||
|
WHEEL = 0x150,
|
||||||
|
GEAR_DOWN = 0x150,
|
||||||
|
GEAR_UP = 0x151,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
278
Source/OpenTK/Platform/Linux/Bindings/Gbm.cs
Normal file
278
Source/OpenTK/Platform/Linux/Bindings/Gbm.cs
Normal file
|
@ -0,0 +1,278 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// Gbm.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
using Device = IntPtr; // struct gbm_device*
|
||||||
|
using Surface = IntPtr;
|
||||||
|
using BufferObjectHandle = IntPtr;
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate void DestroyUserDataCallback(BufferObject bo, IntPtr data);
|
||||||
|
|
||||||
|
class Gbm
|
||||||
|
{
|
||||||
|
const string lib = "gbm";
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_bo_create", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern BufferObject CreateBuffer(Device gbm, int width, int height, SurfaceFormat format, SurfaceFlags flags);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_bo_destroy", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void DestroyBuffer(BufferObject bo);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_bo_write", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int BOWrite(IntPtr bo, IntPtr buf, IntPtr count);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_bo_get_device", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern Device BOGetDevice(IntPtr bo);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_bo_get_handle", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern BufferObjectHandle BOGetHandle(IntPtr bo);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_bo_get_height", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int BOGetHeight(IntPtr bo);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_bo_get_width", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int BOGetWidth(IntPtr bo);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_bo_get_stride", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int BOGetStride(IntPtr bo);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_bo_set_user_data", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void BOSetUserData(IntPtr bo, IntPtr data, DestroyUserDataCallback callback);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_create_device", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern Device CreateDevice(int fd);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_device_destroy", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void DestroyDevice(Device gbm);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_device_get_fd", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int DeviceGetFD(IntPtr gbm);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_surface_create", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern Surface CreateSurface(Device gbm, int width, int height, SurfaceFormat format, SurfaceFlags flags);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_surface_destroy", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void DestroySurface(IntPtr surface);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_device_is_format_supported", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
public static extern bool IsFormatSupported(Device gbm, SurfaceFormat format, SurfaceFlags usage);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_surface_lock_front_buffer", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern BufferObject LockFrontBuffer(Surface surface);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "gbm_surface_release_buffer", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void ReleaseBuffer(Surface surface, BufferObject buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SurfaceFormat
|
||||||
|
{
|
||||||
|
BigEndian = 1 << 31,
|
||||||
|
C8 = ((int)('C') | ((int)('8') << 8) | ((int)(' ') << 16) | ((int)(' ') << 24)),
|
||||||
|
|
||||||
|
RGB332 = ((int)('R') | ((int)('G') << 8) | ((int)('B') << 16) | ((int)('8') << 24)),
|
||||||
|
BGR233 = ((int)('B') | ((int)('G') << 8) | ((int)('R') << 16) | ((int)('8') << 24)),
|
||||||
|
|
||||||
|
XRGB4444 = ((int)('X') | ((int)('R') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
|
||||||
|
XBGR4444 = ((int)('X') | ((int)('B') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
|
||||||
|
RGBX4444 = ((int)('R') | ((int)('X') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
|
||||||
|
BGRX4444 = ((int)('B') | ((int)('X') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
|
||||||
|
|
||||||
|
ARGB4444 = ((int)('A') | ((int)('R') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
|
||||||
|
ABGR4444 = ((int)('A') | ((int)('B') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
|
||||||
|
RGBA4444 = ((int)('R') | ((int)('A') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
|
||||||
|
BGRA4444 = ((int)('B') | ((int)('A') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
|
||||||
|
|
||||||
|
XRGB1555 = ((int)('X') | ((int)('R') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
|
||||||
|
XBGR1555 = ((int)('X') | ((int)('B') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
|
||||||
|
RGBX5551 = ((int)('R') | ((int)('X') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
|
||||||
|
BGRX5551 = ((int)('B') | ((int)('X') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
|
||||||
|
|
||||||
|
ARGB1555 = ((int)('A') | ((int)('R') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
|
||||||
|
ABGR1555 = ((int)('A') | ((int)('B') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
|
||||||
|
RGBA5551 = ((int)('R') | ((int)('A') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
|
||||||
|
BGRA5551 = ((int)('B') | ((int)('A') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
|
||||||
|
|
||||||
|
RGB565 = ((int)('R') | ((int)('G') << 8) | ((int)('1') << 16) | ((int)('6') << 24)),
|
||||||
|
BGR565 = ((int)('B') | ((int)('G') << 8) | ((int)('1') << 16) | ((int)('6') << 24)),
|
||||||
|
|
||||||
|
RGB888 = ((int)('R') | ((int)('G') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
|
||||||
|
BGR888 = ((int)('B') | ((int)('G') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
|
||||||
|
|
||||||
|
XRGB8888 = ((int)('X') | ((int)('R') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
|
||||||
|
XBGR8888 = ((int)('X') | ((int)('B') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
|
||||||
|
RGBX8888 = ((int)('R') | ((int)('X') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
|
||||||
|
BGRX8888 = ((int)('B') | ((int)('X') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
|
||||||
|
|
||||||
|
ARGB8888 = ((int)('A') | ((int)('R') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
|
||||||
|
ABGR8888 = ((int)('A') | ((int)('B') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
|
||||||
|
RGBA8888 = ((int)('R') | ((int)('A') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
|
||||||
|
BGRA8888 = ((int)('B') | ((int)('A') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
|
||||||
|
|
||||||
|
XRGB2101010 = ((int)('X') | ((int)('R') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
|
||||||
|
XBGR2101010 = ((int)('X') | ((int)('B') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
|
||||||
|
RGBX1010102 = ((int)('R') | ((int)('X') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
|
||||||
|
BGRX1010102 = ((int)('B') | ((int)('X') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
|
||||||
|
|
||||||
|
ARGB2101010 = ((int)('A') | ((int)('R') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
|
||||||
|
ABGR2101010 = ((int)('A') | ((int)('B') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
|
||||||
|
RGBA1010102 = ((int)('R') | ((int)('A') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
|
||||||
|
BGRA1010102 = ((int)('B') | ((int)('A') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
|
||||||
|
|
||||||
|
YUYV = ((int)('Y') | ((int)('U') << 8) | ((int)('Y') << 16) | ((int)('V') << 24)),
|
||||||
|
YVYU = ((int)('Y') | ((int)('V') << 8) | ((int)('Y') << 16) | ((int)('U') << 24)),
|
||||||
|
UYVY = ((int)('U') | ((int)('Y') << 8) | ((int)('V') << 16) | ((int)('Y') << 24)),
|
||||||
|
VYUY = ((int)('V') | ((int)('Y') << 8) | ((int)('U') << 16) | ((int)('Y') << 24)),
|
||||||
|
|
||||||
|
AYUV = ((int)('A') | ((int)('Y') << 8) | ((int)('U') << 16) | ((int)('V') << 24)),
|
||||||
|
|
||||||
|
NV12 = ((int)('N') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
|
||||||
|
NV21 = ((int)('N') | ((int)('V') << 8) | ((int)('2') << 16) | ((int)('1') << 24)),
|
||||||
|
NV16 = ((int)('N') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('6') << 24)),
|
||||||
|
NV61 = ((int)('N') | ((int)('V') << 8) | ((int)('6') << 16) | ((int)('1') << 24)),
|
||||||
|
|
||||||
|
YUV410 = ((int)('Y') | ((int)('U') << 8) | ((int)('V') << 16) | ((int)('9') << 24)),
|
||||||
|
YVU410 = ((int)('Y') | ((int)('V') << 8) | ((int)('U') << 16) | ((int)('9') << 24)),
|
||||||
|
YUV411 = ((int)('Y') | ((int)('U') << 8) | ((int)('1') << 16) | ((int)('1') << 24)),
|
||||||
|
YVU411 = ((int)('Y') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('1') << 24)),
|
||||||
|
YUV420 = ((int)('Y') | ((int)('U') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
|
||||||
|
YVU420 = ((int)('Y') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
|
||||||
|
YUV422 = ((int)('Y') | ((int)('U') << 8) | ((int)('1') << 16) | ((int)('6') << 24)),
|
||||||
|
YVU422 = ((int)('Y') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('6') << 24)),
|
||||||
|
YUV444 = ((int)('Y') | ((int)('U') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
|
||||||
|
YVU444 = ((int)('Y') | ((int)('V') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum SurfaceFlags
|
||||||
|
{
|
||||||
|
Scanout = (1 << 0),
|
||||||
|
Cursor64x64 = (1 << 1),
|
||||||
|
Rendering = (1 << 2),
|
||||||
|
Write = (1 << 3),
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
struct BufferObject : IEquatable<BufferObject>
|
||||||
|
{
|
||||||
|
IntPtr buffer;
|
||||||
|
|
||||||
|
public static readonly BufferObject Zero =
|
||||||
|
default(BufferObject);
|
||||||
|
|
||||||
|
public int Write(byte[] data)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* pdata = data)
|
||||||
|
{
|
||||||
|
return Gbm.BOWrite(buffer, (IntPtr)pdata, (IntPtr)data.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUserData(IntPtr data, DestroyUserDataCallback destroyFB)
|
||||||
|
{
|
||||||
|
Gbm.BOSetUserData(buffer, data, destroyFB);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Device Device
|
||||||
|
{
|
||||||
|
get { return Gbm.BOGetDevice(buffer); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Handle
|
||||||
|
{
|
||||||
|
get { return Gbm.BOGetHandle(buffer).ToInt32(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Width
|
||||||
|
{
|
||||||
|
get { return Gbm.BOGetWidth(buffer); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Height
|
||||||
|
{
|
||||||
|
get { return Gbm.BOGetHeight(buffer); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Stride
|
||||||
|
{
|
||||||
|
get { return Gbm.BOGetStride(buffer); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Gbm.DestroyBuffer(this);
|
||||||
|
buffer = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(BufferObject left, BufferObject right)
|
||||||
|
{
|
||||||
|
return left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(BufferObject left, BufferObject right)
|
||||||
|
{
|
||||||
|
return !left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
obj is BufferObject &&
|
||||||
|
this.Equals((BufferObject)obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return buffer.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("[BufferObject: {0}]", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IEquatable implementation
|
||||||
|
|
||||||
|
public bool Equals(BufferObject other)
|
||||||
|
{
|
||||||
|
return buffer == other.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
46
Source/OpenTK/Platform/Linux/Bindings/Kms.cs
Normal file
46
Source/OpenTK/Platform/Linux/Bindings/Kms.cs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// Kms.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
class Kms
|
||||||
|
{
|
||||||
|
const string lib = "libkms";
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "kms_bo_map", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int MapBuffer(IntPtr bo, out IntPtr @out);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "kms_bo_unmap", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int UnmapBuffer(IntPtr bo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
330
Source/OpenTK/Platform/Linux/Bindings/LibInput.cs
Normal file
330
Source/OpenTK/Platform/Linux/Bindings/LibInput.cs
Normal file
|
@ -0,0 +1,330 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// LibInput.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#pragma warning disable 0169, 0219
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int OpenRestrictedCallback(IntPtr path, int flags, IntPtr data);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate void CloseRestrictedCallback(int fd, IntPtr data);
|
||||||
|
|
||||||
|
class LibInput
|
||||||
|
{
|
||||||
|
internal const string lib = "libinput";
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_udev_create_for_seat", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr CreateContext(InputInterface @interface,
|
||||||
|
IntPtr user_data, IntPtr udev, string seat_id);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_destroy", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void DestroyContext(IntPtr libinput);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_event_destroy", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void DestroyEvent(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_device_get_sysname", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern IntPtr DeviceGetNameInternal(IntPtr device);
|
||||||
|
public static string DeviceGetName(IntPtr device)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return new string((sbyte*)DeviceGetNameInternal(device));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_device_get_user_data", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr DeviceGetData(IntPtr device);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_device_set_user_data", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void DeviceSetData(IntPtr device, IntPtr user_data);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_device_get_output_name", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern IntPtr DeviceGetOutputNameInternal(IntPtr device);
|
||||||
|
public static string DeviceGetOutputName(IntPtr device)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
sbyte* pname = (sbyte*)DeviceGetOutputNameInternal(device);
|
||||||
|
return pname == null ? String.Empty : new string(pname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_device_get_seat", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr DeviceGetSeat(IntPtr device);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_device_has_capability", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
public static extern bool DeviceHasCapability(IntPtr device, DeviceCapability capability);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_dispatch", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int Dispatch(IntPtr libinput);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_event_get_device", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr GetDevice(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_get_event", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr GetEvent(IntPtr libinput);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_event_get_keyboard_event", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern KeyboardEvent GetKeyboardEvent(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_event_get_pointer_event", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern PointerEvent GetPointerEvent(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_event_get_type", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern InputEventType GetEventType(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_get_fd", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int GetFD(IntPtr libinput);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_next_event_type", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern InputEventType NextEventType(IntPtr libinput);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_resume", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void Resume(IntPtr libinput);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_suspend", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void Suspend(IntPtr libinput);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_seat_get_logical_name", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern public IntPtr SeatGetLogicalNameInternal(IntPtr seat);
|
||||||
|
public static string SeatGetLogicalName(IntPtr seat)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return new string((sbyte*)SeatGetLogicalNameInternal(seat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "libinput_seat_get_physical_name", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern public IntPtr SeatGetPhysicalNameInternal(IntPtr seat);
|
||||||
|
public static string SeatGetPhysicalName(IntPtr seat)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return new string((sbyte*)SeatGetPhysicalNameInternal(seat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum DeviceCapability
|
||||||
|
{
|
||||||
|
Keyboard = 0,
|
||||||
|
Mouse,
|
||||||
|
Touch
|
||||||
|
}
|
||||||
|
|
||||||
|
enum InputEventType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
DeviceAdded,
|
||||||
|
DeviceRemoved,
|
||||||
|
|
||||||
|
KeyboardKey = 300,
|
||||||
|
|
||||||
|
PointerMotion = 400,
|
||||||
|
PointerMotionAbsolute,
|
||||||
|
PointerButton,
|
||||||
|
PointerAxis,
|
||||||
|
|
||||||
|
TouchDown = 500,
|
||||||
|
TouchUP,
|
||||||
|
TouchMotion,
|
||||||
|
TouchCancel,
|
||||||
|
|
||||||
|
/// \internal
|
||||||
|
/// <summary>
|
||||||
|
/// Signals the end of a set of touchpoints at one device sample
|
||||||
|
/// time. This event has no coordinate information attached.
|
||||||
|
/// </summary>
|
||||||
|
TouchFrame
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ButtonState
|
||||||
|
{
|
||||||
|
Released = 0,
|
||||||
|
Pressed = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
enum KeyState
|
||||||
|
{
|
||||||
|
Released = 0,
|
||||||
|
Pressed = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PointerAxis
|
||||||
|
{
|
||||||
|
VerticalScroll = 0,
|
||||||
|
HorizontalScroll = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Fixed24
|
||||||
|
{
|
||||||
|
internal readonly int Value;
|
||||||
|
|
||||||
|
public static implicit operator double(Fixed24 n)
|
||||||
|
{
|
||||||
|
long l = ((1023L + 44L) << 52) + (1L << 51) + n.Value;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
double d = *(double*)&l;
|
||||||
|
return d - (3L << 43);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator float(Fixed24 n)
|
||||||
|
{
|
||||||
|
return (float)(double)n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator int(Fixed24 n)
|
||||||
|
{
|
||||||
|
return n.Value >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
class InputInterface
|
||||||
|
{
|
||||||
|
internal readonly IntPtr open;
|
||||||
|
internal readonly IntPtr close;
|
||||||
|
|
||||||
|
public InputInterface(
|
||||||
|
OpenRestrictedCallback open_restricted,
|
||||||
|
CloseRestrictedCallback close_restricted)
|
||||||
|
{
|
||||||
|
if (open_restricted == null || close_restricted == null)
|
||||||
|
throw new ArgumentNullException();
|
||||||
|
|
||||||
|
open = Marshal.GetFunctionPointerForDelegate(open_restricted);
|
||||||
|
close = Marshal.GetFunctionPointerForDelegate(close_restricted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
struct KeyboardEvent
|
||||||
|
{
|
||||||
|
IntPtr @event;
|
||||||
|
|
||||||
|
public IntPtr BaseEvent { get { return GetBaseEvent(@event); } }
|
||||||
|
public IntPtr Event { get { return @event; } }
|
||||||
|
public uint Time { get { return GetTime(@event); } }
|
||||||
|
public uint Key { get { return GetKey(@event); } }
|
||||||
|
public uint KeyCount { get { return GetSeatKeyCount(@event); } }
|
||||||
|
public KeyState KeyState { get { return GetKeyState(@event); } }
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_keyboard_get_time", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern uint GetTime(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_keyboard_get_base_event", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern IntPtr GetBaseEvent(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_keyboard_get_seat_key_count", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern uint GetSeatKeyCount(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_keyboard_get_key", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern uint GetKey(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_keyboard_get_key_state", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern KeyState GetKeyState(IntPtr @event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
struct PointerEvent
|
||||||
|
{
|
||||||
|
IntPtr @event;
|
||||||
|
|
||||||
|
public IntPtr BaseEvent { get { return GetBaseEvent(@event); } }
|
||||||
|
public IntPtr Event { get { return @event; } }
|
||||||
|
public uint Time { get { return GetTime(@event); } }
|
||||||
|
public EvdevButton Button { get { return (EvdevButton)GetButton(@event); } }
|
||||||
|
public uint ButtonCount { get { return GetButtonCount(@event); } }
|
||||||
|
public ButtonState ButtonState { get { return GetButtonState(@event); } }
|
||||||
|
public PointerAxis Axis { get { return GetAxis(@event); } }
|
||||||
|
public Fixed24 AxisValue { get { return GetAxisValue(@event); } }
|
||||||
|
public Fixed24 DeltaX { get { return GetDX(@event); } }
|
||||||
|
public Fixed24 DeltaY { get { return GetDY(@event); } }
|
||||||
|
public Fixed24 X { get { return GetAbsX(@event); } }
|
||||||
|
public Fixed24 Y { get { return GetAbsY(@event); } }
|
||||||
|
public Fixed24 TransformedX(int width) { return GetAbsXTransformed(@event, width); }
|
||||||
|
public Fixed24 TransformedY(int height) { return GetAbsYTransformed(@event, height); }
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_time", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern uint GetTime(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_base_event", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern IntPtr GetBaseEvent(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_seat_key_count", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern uint GetSeatKeyCount(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_button", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern uint GetButton(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_seat_button_count", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern uint GetButtonCount(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_button_state", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern ButtonState GetButtonState(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_axis", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern PointerAxis GetAxis(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_axis_value", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern Fixed24 GetAxisValue(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_dx", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern Fixed24 GetDX(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_dy", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern Fixed24 GetDY(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_absolute_x", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern Fixed24 GetAbsX(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_absolute_y", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern Fixed24 GetAbsY(IntPtr @event);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_absolute_x_transformed", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern Fixed24 GetAbsXTransformed(IntPtr @event, int width);
|
||||||
|
|
||||||
|
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_absolute_y_transformed", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern Fixed24 GetAbsYTransformed(IntPtr @event, int height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
178
Source/OpenTK/Platform/Linux/Bindings/Libc.cs
Normal file
178
Source/OpenTK/Platform/Linux/Bindings/Libc.cs
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// Linux.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
partial class Libc
|
||||||
|
{
|
||||||
|
const string lib = "libc";
|
||||||
|
|
||||||
|
[DllImport(lib)]
|
||||||
|
public static extern int dup(int file);
|
||||||
|
|
||||||
|
[DllImport(lib)]
|
||||||
|
public static extern int dup2(int file1, int file2);
|
||||||
|
|
||||||
|
[DllImport(lib)]
|
||||||
|
public static extern int ioctl(int d, JoystickIoctlCode request, ref int data);
|
||||||
|
|
||||||
|
[DllImport(lib)]
|
||||||
|
public static extern int ioctl(int d, JoystickIoctlCode request, StringBuilder data);
|
||||||
|
|
||||||
|
[DllImport(lib)]
|
||||||
|
public static extern int ioctl(int d, EvdevIoctlCode request, out EvdevInputId data);
|
||||||
|
|
||||||
|
[DllImport(lib)]
|
||||||
|
public static extern int ioctl(int d, KeyboardIoctlCode request, ref IntPtr data);
|
||||||
|
|
||||||
|
[DllImport(lib)]
|
||||||
|
public static extern int ioctl(int d, KeyboardIoctlCode request, int data);
|
||||||
|
|
||||||
|
[DllImport(lib)]
|
||||||
|
public static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, OpenFlags flags);
|
||||||
|
|
||||||
|
[DllImport(lib)]
|
||||||
|
public static extern int open(IntPtr pathname, OpenFlags flags);
|
||||||
|
|
||||||
|
[DllImport(lib)]
|
||||||
|
public static extern int close(int fd);
|
||||||
|
|
||||||
|
[DllImport(lib)]
|
||||||
|
unsafe public static extern IntPtr read(int fd, void* buffer, UIntPtr count);
|
||||||
|
|
||||||
|
public static int read(int fd, out byte b)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* pb = &b)
|
||||||
|
{
|
||||||
|
return read(fd, pb, (UIntPtr)1).ToInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int read(int fd, out short s)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (short* ps = &s)
|
||||||
|
{
|
||||||
|
return read(fd, ps, (UIntPtr)2).ToInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport(lib)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
public static extern bool isatty(int fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ErrorNumber
|
||||||
|
{
|
||||||
|
Interrupted = 4,
|
||||||
|
Again = 11,
|
||||||
|
InvalidValue = 22,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum OpenFlags
|
||||||
|
{
|
||||||
|
ReadOnly = 0x0000,
|
||||||
|
WriteOnly = 0x0001,
|
||||||
|
ReadWrite = 0x0002,
|
||||||
|
NonBlock = 0x0800,
|
||||||
|
CloseOnExec = 0x0080000
|
||||||
|
}
|
||||||
|
|
||||||
|
enum EvdevIoctlCode : uint
|
||||||
|
{
|
||||||
|
Id = ((byte)'E' << 8) | (0x02 << 0) //EVIOCGID, which is _IOR('E', 0x02, struct input_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum JoystickEventType : byte
|
||||||
|
{
|
||||||
|
Button = 0x01, // button pressed/released
|
||||||
|
Axis = 0x02, // joystick moved
|
||||||
|
Init = 0x80 // initial state of device
|
||||||
|
}
|
||||||
|
|
||||||
|
enum JoystickIoctlCode : uint
|
||||||
|
{
|
||||||
|
Version = 0x80046a01,
|
||||||
|
Axes = 0x80016a11,
|
||||||
|
Buttons = 0x80016a12,
|
||||||
|
Name128 = (2u << 30) | (0x6A << 8) | (0x13 << 0) | (128 << 16) //JSIOCGNAME(128), which is _IOC(_IO_READ, 'j', 0x13, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum KeyboardIoctlCode
|
||||||
|
{
|
||||||
|
GetMode = 0x4b44,
|
||||||
|
SetMode = 0x4b45,
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
struct Stat
|
||||||
|
{
|
||||||
|
public IntPtr dev; /* ID of device containing file */
|
||||||
|
public IntPtr ino; /* inode number */
|
||||||
|
public IntPtr mode; /* protection */
|
||||||
|
public IntPtr nlink; /* number of hard links */
|
||||||
|
public IntPtr uid; /* user ID of owner */
|
||||||
|
public IntPtr gid; /* group ID of owner */
|
||||||
|
public IntPtr rdev; /* device ID (if special file) */
|
||||||
|
public IntPtr size; /* total size, in bytes */
|
||||||
|
public IntPtr blksize; /* blocksize for file system I/O */
|
||||||
|
public IntPtr blocks; /* number of 512B blocks allocated */
|
||||||
|
public IntPtr atime; /* time of last access */
|
||||||
|
public IntPtr mtime; /* time of last modification */
|
||||||
|
public IntPtr ctime; /* time of last status change */
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EvdevInputId
|
||||||
|
{
|
||||||
|
public ushort BusType;
|
||||||
|
public ushort Vendor;
|
||||||
|
public ushort Product;
|
||||||
|
public ushort Version;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct JoystickEvent
|
||||||
|
{
|
||||||
|
public uint Time; // (u32) event timestamp in milliseconds
|
||||||
|
public short Value; // (s16) value
|
||||||
|
public JoystickEventType Type; // (u8) event type
|
||||||
|
public byte Number; // (u8) axis/button number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
65
Source/OpenTK/Platform/Linux/Bindings/Poll.cs
Normal file
65
Source/OpenTK/Platform/Linux/Bindings/Poll.cs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// Poll.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
partial class Libc
|
||||||
|
{
|
||||||
|
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
|
||||||
|
public static extern int poll(ref PollFD fd, IntPtr fd_count, int timeout);
|
||||||
|
|
||||||
|
public static int poll(ref PollFD fd, int fd_count, int timeout)
|
||||||
|
{
|
||||||
|
return poll(ref fd, (IntPtr)fd_count, timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum PollFlags : short
|
||||||
|
{
|
||||||
|
In = 0x01,
|
||||||
|
Pri = 0x02,
|
||||||
|
Out = 0x04,
|
||||||
|
Error = 0x08,
|
||||||
|
Hup = 0x10,
|
||||||
|
Invalid = 0x20,
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
struct PollFD
|
||||||
|
{
|
||||||
|
public int fd;
|
||||||
|
public PollFlags events;
|
||||||
|
public PollFlags revents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
170
Source/OpenTK/Platform/Linux/Bindings/Terminal.cs
Normal file
170
Source/OpenTK/Platform/Linux/Bindings/Terminal.cs
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// Terminal.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
class Terminal
|
||||||
|
{
|
||||||
|
const string lib = "libc";
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "isatty", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I4)]
|
||||||
|
public static extern bool IsTerminal(int fd);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "tcgetattr", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int GetAttributes(int fd, out TerminalState state);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "tcsetattr", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int SetAttributes(int fd, OptionalActions actions, ref TerminalState state);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum InputFlags
|
||||||
|
{
|
||||||
|
IGNBRK = 1 << 0,
|
||||||
|
BRKINT = 1 << 1,
|
||||||
|
IGNPAR = 1 << 2,
|
||||||
|
PARMRK = 1 << 3,
|
||||||
|
INPCK = 1 << 4,
|
||||||
|
ISTRIP = 1 << 5,
|
||||||
|
INLCR = 1 << 6,
|
||||||
|
IGNCR = 1 << 7,
|
||||||
|
ICRNL = 1 << 8,
|
||||||
|
IUCLC = 1 << 9,
|
||||||
|
IXON = 1 << 10,
|
||||||
|
IXANY = 1 << 11,
|
||||||
|
IXOFF = 1 << 12,
|
||||||
|
IMAXBEL = 1 << 13,
|
||||||
|
IUTF8 = 1 << 14,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum OutputFlags
|
||||||
|
{
|
||||||
|
OPOST = 1 << 1,
|
||||||
|
OLCUC = 1 << 2,
|
||||||
|
ONLCR = 1 << 3,
|
||||||
|
OCRNL = 1 << 4,
|
||||||
|
ONOCR = 1 << 5,
|
||||||
|
ONLRET = 1 << 6,
|
||||||
|
OFILL = 1 << 7,
|
||||||
|
OFDEL = 1 << 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum ControlFlags
|
||||||
|
{
|
||||||
|
B0 = 0, // hang up
|
||||||
|
B50,
|
||||||
|
B75,
|
||||||
|
B110,
|
||||||
|
B134,
|
||||||
|
B150,
|
||||||
|
B200,
|
||||||
|
B300,
|
||||||
|
B600,
|
||||||
|
B1200,
|
||||||
|
B1800,
|
||||||
|
B2400,
|
||||||
|
B4800,
|
||||||
|
B9600,
|
||||||
|
B19200,
|
||||||
|
B38400,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum LocalFlags
|
||||||
|
{
|
||||||
|
ISIG = 0x01,
|
||||||
|
ICANON = 0x02,
|
||||||
|
ECHO = 0x08,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum OptionalActions
|
||||||
|
{
|
||||||
|
NOW = 0,
|
||||||
|
DRAIN = 1,
|
||||||
|
FLUSH = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
struct TerminalState
|
||||||
|
{
|
||||||
|
public InputFlags InputMode;
|
||||||
|
public OutputFlags OutputMode;
|
||||||
|
public ControlFlags ControlMode;
|
||||||
|
public LocalFlags LocalMode;
|
||||||
|
public byte LineDiscipline;
|
||||||
|
public ControlCharacters ControlCharacters;
|
||||||
|
public int InputSpeed;
|
||||||
|
public int OutputSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
struct ControlCharacters
|
||||||
|
{
|
||||||
|
public byte VINTR;
|
||||||
|
public byte VQUIT;
|
||||||
|
public byte VERASE;
|
||||||
|
public byte VKILL;
|
||||||
|
public byte VEOF;
|
||||||
|
public byte VTIME;
|
||||||
|
public byte VMIN;
|
||||||
|
public byte VSWTC;
|
||||||
|
public byte VSTART;
|
||||||
|
public byte VSTOP;
|
||||||
|
public byte VSUSP;
|
||||||
|
public byte VEOL;
|
||||||
|
public byte VREPRINT;
|
||||||
|
public byte VDISCARD;
|
||||||
|
public byte VWERASE;
|
||||||
|
public byte VLNEXT;
|
||||||
|
public byte VEOL2;
|
||||||
|
public byte C17;
|
||||||
|
public byte C18;
|
||||||
|
public byte C19;
|
||||||
|
public byte C20;
|
||||||
|
public byte C21;
|
||||||
|
public byte C22;
|
||||||
|
public byte C23;
|
||||||
|
public byte C24;
|
||||||
|
public byte C25;
|
||||||
|
public byte C26;
|
||||||
|
public byte C27;
|
||||||
|
public byte C28;
|
||||||
|
public byte C29;
|
||||||
|
public byte C30;
|
||||||
|
public byte C31;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
46
Source/OpenTK/Platform/Linux/Bindings/Udev.cs
Normal file
46
Source/OpenTK/Platform/Linux/Bindings/Udev.cs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// Udev.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
class Udev
|
||||||
|
{
|
||||||
|
const string lib = "libudev";
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "udev_new", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr New();
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "udev_destroy", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void Destroy(IntPtr Udev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
76
Source/OpenTK/Platform/Linux/DefaultCursor.cs
Normal file
76
Source/OpenTK/Platform/Linux/DefaultCursor.cs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// DefaultCursor.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
static class Cursors
|
||||||
|
{
|
||||||
|
public static readonly MouseCursor Default =
|
||||||
|
new MouseCursor(8, 4, 32, 32, new byte[]
|
||||||
|
{
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1A, 0x1A, 0x1A, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0xF1, 0xF1, 0xF1, 0xF3, 0x16, 0x16, 0x16, 0x2B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xEC, 0xEC, 0xF4, 0x11, 0x11, 0x11, 0x37, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE9, 0xE9, 0xE9, 0xF3, 0x0C, 0x0C, 0x0C, 0x33, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0x99, 0x99, 0xFF, 0xF7, 0xF7, 0xF7, 0xFF, 0xE4, 0xE4, 0xE4, 0xF0, 0x07, 0x07, 0x07, 0x2D, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x61, 0x61, 0xFF, 0x52, 0x52, 0x52, 0xFF, 0xF9, 0xF9, 0xF9, 0xFF, 0xE0, 0xE0, 0xE0, 0xEC, 0x03, 0x03, 0x03, 0x29, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x5F, 0x5F, 0x5F, 0xFF, 0x13, 0x13, 0x13, 0xFF, 0x5C, 0x5C, 0x5C, 0xFF, 0xFC, 0xFC, 0xFC, 0xFF, 0xD9, 0xD9, 0xD9, 0xE7, 0x01, 0x01, 0x01, 0x26, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x5C, 0x5C, 0x5C, 0xFF, 0x10, 0x10, 0x10, 0xFF, 0x19, 0x19, 0x19, 0xFF, 0x66, 0x66, 0x66, 0xFF, 0xFD, 0xFD, 0xFD, 0xFF, 0xD3, 0xD3, 0xD3, 0xE2, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x59, 0x59, 0x59, 0xFF, 0x0C, 0x0C, 0x0C, 0xFF, 0x15, 0x15, 0x15, 0xFF, 0x1E, 0x1E, 0x1E, 0xFF, 0x72, 0x72, 0x72, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xCA, 0xCA, 0xCA, 0xDB, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x58, 0x58, 0xFF, 0x08, 0x08, 0x08, 0xFF, 0x11, 0x11, 0x11, 0xFF, 0x1A, 0x1A, 0x1A, 0xFF, 0x24, 0x24, 0x24, 0xFF, 0x7C, 0x7C, 0x7C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xC1, 0xC1, 0xD4, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x58, 0x58, 0xFF, 0x04, 0x04, 0x04, 0xFF, 0x0D, 0x0D, 0x0D, 0xFF, 0x16, 0x16, 0x16, 0xFF, 0x20, 0x20, 0x20, 0xFF, 0x29, 0x29, 0x29, 0xFF, 0x88, 0x88, 0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0xB7, 0xB7, 0xCD, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x58, 0x58, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x09, 0x09, 0x09, 0xFF, 0x12, 0x12, 0x12, 0xFF, 0x1C, 0x1C, 0x1C, 0xFF, 0x25, 0x25, 0x25, 0xFF, 0x2F, 0x2F, 0x2F, 0xFF, 0x92, 0x92, 0x92, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAD, 0xAD, 0xAD, 0xC5, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x58, 0x58, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x05, 0x05, 0x05, 0xFF, 0x0E, 0x0E, 0x0E, 0xFF, 0x18, 0x18, 0x18, 0xFF, 0x21, 0x21, 0x21, 0xFF, 0x2B, 0x2B, 0x2B, 0xFF, 0x34, 0x34, 0x34, 0xFF, 0x9C, 0x9C, 0x9C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xA1, 0xA1, 0xA1, 0xBC, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x58, 0x58, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x01, 0x01, 0x01, 0xFF, 0x0A, 0x0A, 0x0A, 0xFF, 0x14, 0x14, 0x14, 0xFF, 0x1D, 0x1D, 0x1D, 0xFF, 0x27, 0x27, 0x27, 0xFF, 0x30, 0x30, 0x30, 0xFF, 0x39, 0x39, 0x39, 0xFF, 0xA7, 0xA7, 0xA7, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0x96, 0x96, 0x96, 0xB3, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x58, 0x58, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x07, 0x07, 0x07, 0xFF, 0x10, 0x10, 0x10, 0xFF, 0x19, 0x19, 0x19, 0xFF, 0x23, 0x23, 0x23, 0xFF, 0x2C, 0x2C, 0x2C, 0xFF, 0x35, 0x35, 0x35, 0xFF, 0x3F, 0x3F, 0x3F, 0xFF, 0xB0, 0xB0, 0xB0, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0x8B, 0x8B, 0x8B, 0xAB, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x58, 0x58, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x03, 0x03, 0xFF, 0x0C, 0x0C, 0x0C, 0xFF, 0x15, 0x15, 0x15, 0xFF, 0x1F, 0x1F, 0x1F, 0xFF, 0x28, 0x28, 0x28, 0xFF, 0x31, 0x31, 0x31, 0xFF, 0x3B, 0x3B, 0x3B, 0xFF, 0x45, 0x45, 0x45, 0xFF, 0xB7, 0xB7, 0xB7, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0x80, 0x80, 0x80, 0xA2, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x58, 0x58, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x08, 0x08, 0x08, 0xFF, 0x11, 0x11, 0x11, 0xFF, 0x1F, 0x1F, 0x1F, 0xFF, 0x61, 0x61, 0x61, 0xFF, 0x69, 0x69, 0x69, 0xFF, 0x6F, 0x6F, 0x6F, 0xFF, 0x76, 0x76, 0x76, 0xFF, 0x7D, 0x7D, 0x7D, 0xFF, 0xE1, 0xE1, 0xE1, 0xFF, 0xFD, 0xFD, 0xFD, 0xFF, 0x75, 0x75, 0x75, 0x97, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x58, 0x58, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x04, 0x04, 0x04, 0xFF, 0x0D, 0x0D, 0x0D, 0xFF, 0x17, 0x17, 0x17, 0xFF, 0xCD, 0xCD, 0xCD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x66, 0x66, 0x66, 0x85, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x58, 0x58, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x5B, 0x5B, 0x5B, 0xFF, 0x10, 0x10, 0x10, 0xFF, 0x13, 0x13, 0x13, 0xFF, 0x61, 0x61, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x69, 0x69, 0x69, 0xBA, 0x1E, 0x1E, 0x1E, 0x83, 0x1E, 0x1E, 0x1E, 0x78, 0x1E, 0x1E, 0x1E, 0x77, 0x1E, 0x1E, 0x1E, 0x74, 0x1E, 0x1E, 0x1E, 0x6B, 0x15, 0x15, 0x15, 0x4A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x58, 0x58, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x6D, 0x6D, 0x6D, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0x6D, 0x6D, 0x6D, 0xFF, 0x0F, 0x0F, 0x0F, 0xFF, 0x19, 0x19, 0x19, 0xFF, 0xDE, 0xDE, 0xDE, 0xFF, 0xDB, 0xDB, 0xDB, 0xEE, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x58, 0x58, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x75, 0x75, 0x75, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xF7, 0xF7, 0xFC, 0xE6, 0xE6, 0xE6, 0xFF, 0x10, 0x10, 0x10, 0xFF, 0x14, 0x14, 0x14, 0xFF, 0x71, 0x71, 0x71, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0x36, 0x36, 0x36, 0x75, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x58, 0x58, 0xFF, 0x7E, 0x7E, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xAF, 0xAF, 0xD9, 0x36, 0x36, 0x36, 0x8F, 0xFD, 0xFD, 0xFD, 0xFF, 0x67, 0x67, 0x67, 0xFF, 0x10, 0x10, 0x10, 0xFF, 0x1E, 0x1E, 0x1E, 0xFF, 0xEA, 0xEA, 0xEA, 0xFF, 0xCD, 0xCD, 0xCD, 0xE2, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0xCC, 0xCC, 0xCC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xA7, 0xA7, 0xA7, 0xD5, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x3A, 0xD5, 0xD5, 0xD5, 0xE3, 0xE1, 0xE1, 0xE1, 0xFF, 0x0F, 0x0F, 0x0F, 0xFF, 0x16, 0x16, 0x16, 0xFF, 0x81, 0x81, 0x81, 0xFF, 0xFC, 0xFC, 0xFC, 0xFF, 0x20, 0x20, 0x20, 0x5E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0x9F, 0x9F, 0x9F, 0xCF, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x12, 0x3D, 0x3D, 0x3D, 0x59, 0xFD, 0xFD, 0xFD, 0xFF, 0x61, 0x61, 0x61, 0xFF, 0x12, 0x12, 0x12, 0xFF, 0x25, 0x25, 0x25, 0xFF, 0xFA, 0xFA, 0xFA, 0xFF, 0x97, 0x97, 0x97, 0xC0, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0D, 0xFF, 0xFF, 0xFF, 0xFF, 0x97, 0x97, 0x97, 0xC1, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0xD9, 0xD9, 0xD9, 0xE5, 0xDC, 0xDC, 0xDC, 0xFF, 0x19, 0x19, 0x19, 0xFF, 0x34, 0x34, 0x34, 0xFF, 0xFB, 0xFB, 0xFB, 0xFF, 0xA2, 0xA2, 0xA2, 0xCB, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x8E, 0x8E, 0x8E, 0xA1, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x45, 0x45, 0x45, 0x5F, 0xFA, 0xFA, 0xFA, 0xFF, 0xF2, 0xF2, 0xF2, 0xFF, 0xFB, 0xFB, 0xFB, 0xFF, 0xF2, 0xF2, 0xF2, 0xFC, 0x30, 0x30, 0x30, 0x83, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0x34, 0x34, 0x34, 0x5D, 0xBB, 0xBB, 0xBB, 0xD5, 0x95, 0x95, 0x95, 0xC4, 0x16, 0x16, 0x16, 0x72, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
});
|
||||||
|
|
||||||
|
public static readonly MouseCursor Empty = MouseCursor.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
413
Source/OpenTK/Platform/Linux/LinuxDisplayDriver.cs
Normal file
413
Source/OpenTK/Platform/Linux/LinuxDisplayDriver.cs
Normal file
|
@ -0,0 +1,413 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// LinuxDisplayDriver.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using OpenTK;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
// Stores platform-specific information about a display
|
||||||
|
class LinuxDisplay
|
||||||
|
{
|
||||||
|
public int FD;
|
||||||
|
public IntPtr Connector;
|
||||||
|
public IntPtr Crtc;
|
||||||
|
public IntPtr Encoder;
|
||||||
|
|
||||||
|
unsafe public ModeConnector* pConnector { get { return (ModeConnector*)Connector; } }
|
||||||
|
unsafe public ModeCrtc* pCrtc { get { return (ModeCrtc*)Crtc; } }
|
||||||
|
unsafe public ModeEncoder* pEncoder { get { return (ModeEncoder*)Encoder; } }
|
||||||
|
/*
|
||||||
|
public ModeInfo Mode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Crtc == IntPtr.Zero)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return pCrtc->mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public ModeInfo OriginalMode;
|
||||||
|
|
||||||
|
public int Id
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Crtc == IntPtr.Zero)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return (int)pCrtc->crtc_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LinuxDisplay(int fd, IntPtr c, IntPtr e, IntPtr r)
|
||||||
|
{
|
||||||
|
FD = fd;
|
||||||
|
Connector = c;
|
||||||
|
Encoder = e;
|
||||||
|
Crtc = r;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
OriginalMode = pCrtc->mode; // in case we change resolution later on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LinuxDisplayDriver : DisplayDeviceBase
|
||||||
|
{
|
||||||
|
readonly int FD;
|
||||||
|
readonly Dictionary<int, int> DisplayIds =
|
||||||
|
new Dictionary<int, int>();
|
||||||
|
|
||||||
|
public LinuxDisplayDriver(int fd)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Creating LinuxDisplayDriver for fd:{0}", fd);
|
||||||
|
Debug.Indent();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FD = fd;
|
||||||
|
UpdateDisplays(fd);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Debug.Unindent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \internal
|
||||||
|
/// <summary>
|
||||||
|
/// Queries the specified GPU for connected displays and, optionally,
|
||||||
|
/// returns the list of displays.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns><c>true</c>, if at least one display is connected, <c>false</c> otherwise.</returns>
|
||||||
|
/// <param name="fd">The fd for the GPU to query, obtained through open("/dev/dri/card0").</param>
|
||||||
|
/// <param name="displays">
|
||||||
|
/// If not null, this will contain a list <see cref="LinuxDisplay"/> instances,
|
||||||
|
/// one for each connected display.
|
||||||
|
/// </param>
|
||||||
|
internal static bool QueryDisplays(int fd, List<LinuxDisplay> displays)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
bool has_displays = false;
|
||||||
|
if (displays != null)
|
||||||
|
{
|
||||||
|
displays.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ModeRes* resources = (ModeRes*)Drm.ModeGetResources(fd);
|
||||||
|
if (resources == null)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Drm.ModeGetResources failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Debug.Print("[KMS] DRM found {0} connectors", resources->count_connectors);
|
||||||
|
|
||||||
|
// Search for a valid connector
|
||||||
|
ModeConnector* connector = null;
|
||||||
|
for (int i = 0; i < resources->count_connectors; i++)
|
||||||
|
{
|
||||||
|
connector = (ModeConnector*)Drm.ModeGetConnector(fd,
|
||||||
|
*(resources->connectors + i));
|
||||||
|
if (connector != null)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
LinuxDisplay display = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (connector->connection == ModeConnection.Connected &&
|
||||||
|
connector->count_modes > 0)
|
||||||
|
{
|
||||||
|
success = QueryDisplay(fd, connector, out display);
|
||||||
|
has_displays |= success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Failed to add display. Error: {0}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success && displays != null)
|
||||||
|
{
|
||||||
|
displays.Add(display);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Drm.ModeFreeConnector((IntPtr)connector);
|
||||||
|
connector = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return has_displays;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDisplays(int fd)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
AvailableDevices.Clear();
|
||||||
|
DisplayIds.Clear();
|
||||||
|
|
||||||
|
List<LinuxDisplay> displays = new List<LinuxDisplay>();
|
||||||
|
if (QueryDisplays(fd, displays))
|
||||||
|
{
|
||||||
|
foreach (LinuxDisplay display in displays)
|
||||||
|
{
|
||||||
|
AddDisplay(display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AvailableDevices.Count == 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Failed to find any active displays");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe static ModeEncoder* GetEncoder(int fd, ModeConnector* c)
|
||||||
|
{
|
||||||
|
ModeEncoder* encoder = null;
|
||||||
|
for (int i = 0; i < c->count_encoders && encoder == null; i++)
|
||||||
|
{
|
||||||
|
ModeEncoder* e = (ModeEncoder*)Drm.ModeGetEncoder(
|
||||||
|
fd, *(c->encoders + i));
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
if (e->encoder_id == c->encoder_id)
|
||||||
|
{
|
||||||
|
encoder = e;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Drm.ModeFreeEncoder((IntPtr)e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoder != null)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Encoder {0} found for connector {1}",
|
||||||
|
encoder->encoder_id, c->connector_id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Failed to find encoder for connector {0}", c->connector_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe static ModeCrtc* GetCrtc(int fd, ModeEncoder* encoder)
|
||||||
|
{
|
||||||
|
ModeCrtc* crtc = (ModeCrtc*)Drm.ModeGetCrtc(fd, encoder->crtc_id);
|
||||||
|
if (crtc != null)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] CRTC {0} found for encoder {1}",
|
||||||
|
encoder->crtc_id, encoder->encoder_id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Failed to find crtc {0} for encoder {1}",
|
||||||
|
encoder->crtc_id, encoder->encoder_id);
|
||||||
|
}
|
||||||
|
return crtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe static void GetModes(LinuxDisplay display, DisplayResolution[] modes, out DisplayResolution current)
|
||||||
|
{
|
||||||
|
int mode_count = display.pConnector->count_modes;
|
||||||
|
Debug.Print("[KMS] Display supports {0} mode(s)", mode_count);
|
||||||
|
for (int i = 0; i < mode_count; i++)
|
||||||
|
{
|
||||||
|
ModeInfo* mode = display.pConnector->modes + i;
|
||||||
|
if (mode != null)
|
||||||
|
{
|
||||||
|
Debug.Print("Mode {0}: {1}x{2} @{3}", i,
|
||||||
|
mode->hdisplay, mode->vdisplay, mode->vrefresh);
|
||||||
|
DisplayResolution res = GetDisplayResolution(mode);
|
||||||
|
modes[i] = res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (display.pCrtc->mode_valid != 0)
|
||||||
|
{
|
||||||
|
ModeInfo cmode = display.pCrtc->mode;
|
||||||
|
current = GetDisplayResolution(&cmode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current = GetDisplayResolution(display.pConnector->modes);
|
||||||
|
}
|
||||||
|
Debug.Print("Current mode: {0}", current.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Drawing.Rectangle GetBounds(DisplayResolution current)
|
||||||
|
{
|
||||||
|
// Note: since we are not running a display manager, we are free
|
||||||
|
// to choose the display layout for multiple displays ourselves.
|
||||||
|
// We choose the simplest layout: displays are laid out side-by-side
|
||||||
|
// from left to right. Primary display is the first display we encounter.
|
||||||
|
int x = AvailableDevices.Count == 0 ?
|
||||||
|
0 : AvailableDevices[AvailableDevices.Count - 1].Bounds.Right;
|
||||||
|
int y = 0;
|
||||||
|
|
||||||
|
return new System.Drawing.Rectangle(
|
||||||
|
x, y, current.Width, current.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDisplayIndices(LinuxDisplay display, DisplayDevice device)
|
||||||
|
{
|
||||||
|
if (!DisplayIds.ContainsKey(display.Id))
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Adding display {0} as {1}", display.Id, AvailableDevices.Count);
|
||||||
|
DisplayIds.Add(display.Id, AvailableDevices.Count);
|
||||||
|
}
|
||||||
|
int index = DisplayIds[display.Id];
|
||||||
|
if (index >= AvailableDevices.Count)
|
||||||
|
{
|
||||||
|
AvailableDevices.Add(device);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AvailableDevices[index] = device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe static bool QueryDisplay(int fd, ModeConnector* c, out LinuxDisplay display)
|
||||||
|
{
|
||||||
|
display = null;
|
||||||
|
|
||||||
|
// Find corresponding encoder
|
||||||
|
ModeEncoder* encoder = GetEncoder(fd, c);
|
||||||
|
if (encoder == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ModeCrtc* crtc = GetCrtc(fd, encoder);
|
||||||
|
if (crtc == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
display = new LinuxDisplay(fd, (IntPtr)c, (IntPtr)encoder, (IntPtr)crtc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe void AddDisplay(LinuxDisplay display)
|
||||||
|
{
|
||||||
|
DisplayResolution[] modes = new DisplayResolution[display.pConnector->count_modes];
|
||||||
|
DisplayResolution current;
|
||||||
|
GetModes(display, modes, out current);
|
||||||
|
|
||||||
|
bool is_primary = AvailableDevices.Count == 0;
|
||||||
|
DisplayDevice device = new DisplayDevice(current, is_primary,
|
||||||
|
modes, GetBounds(current), display);
|
||||||
|
|
||||||
|
if (is_primary)
|
||||||
|
{
|
||||||
|
Primary = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateDisplayIndices(display, device);
|
||||||
|
|
||||||
|
Debug.Print("[KMS] Added DisplayDevice {0}", device);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe static DisplayResolution GetDisplayResolution(ModeInfo* mode)
|
||||||
|
{
|
||||||
|
return new DisplayResolution(
|
||||||
|
0, 0,
|
||||||
|
mode->hdisplay, mode->vdisplay,
|
||||||
|
32, // This is actually part of the framebuffer, not the DisplayResolution
|
||||||
|
mode->vrefresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe static ModeInfo* GetModeInfo(LinuxDisplay display, DisplayResolution resolution)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < display.pConnector->count_modes; i++)
|
||||||
|
{
|
||||||
|
ModeInfo* mode = display.pConnector->modes + i;
|
||||||
|
if (mode != null &&
|
||||||
|
mode->hdisplay == resolution.Width &&
|
||||||
|
mode->vdisplay == resolution.Height)
|
||||||
|
{
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IDisplayDeviceDriver
|
||||||
|
|
||||||
|
public override bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
LinuxDisplay display = (LinuxDisplay)device.Id;
|
||||||
|
ModeInfo* mode = GetModeInfo(display, resolution);
|
||||||
|
int connector_id = display.pConnector->connector_id;
|
||||||
|
if (mode != null)
|
||||||
|
{
|
||||||
|
return Drm.ModeSetCrtc(FD, display.Id, 0, 0, 0,
|
||||||
|
&connector_id, 1, mode) == 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool TryRestoreResolution(DisplayDevice device)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
LinuxDisplay display = (LinuxDisplay)device.Id;
|
||||||
|
ModeInfo mode = display.OriginalMode;
|
||||||
|
int connector_id = display.pConnector->connector_id;
|
||||||
|
return Drm.ModeSetCrtc(FD, display.Id, 0, 0, 0,
|
||||||
|
&connector_id, 1, &mode) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
248
Source/OpenTK/Platform/Linux/LinuxFactory.cs
Normal file
248
Source/OpenTK/Platform/Linux/LinuxFactory.cs
Normal file
|
@ -0,0 +1,248 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// LinuxFactory.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
using OpenTK.Input;
|
||||||
|
using OpenTK.Platform.Egl;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
using Egl = OpenTK.Platform.Egl.Egl;
|
||||||
|
|
||||||
|
// Linux KMS platform
|
||||||
|
class LinuxFactory : PlatformFactoryBase
|
||||||
|
{
|
||||||
|
int _fd;
|
||||||
|
IntPtr gbm_device;
|
||||||
|
IntPtr egl_display;
|
||||||
|
|
||||||
|
IJoystickDriver2 JoystickDriver;
|
||||||
|
LinuxInput MouseKeyboardDriver;
|
||||||
|
|
||||||
|
const string gpu_path = "/dev/dri"; // card0, card1, ...
|
||||||
|
|
||||||
|
public LinuxFactory()
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Using Linux/KMS backend.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Private Members
|
||||||
|
|
||||||
|
int gpu_fd
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (_fd == 0)
|
||||||
|
{
|
||||||
|
_fd = CreateDisplay(out gbm_device, out egl_display);
|
||||||
|
}
|
||||||
|
return _fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CreateDisplay(out IntPtr gbm_device, out IntPtr egl_display)
|
||||||
|
{
|
||||||
|
// Query all GPUs until we find one that has a connected display.
|
||||||
|
// This is necessary in multi-gpu systems, where only one GPU
|
||||||
|
// can output a signal.
|
||||||
|
// Todo: allow OpenTK to drive multiple GPUs
|
||||||
|
// Todo: allow OpenTK to run on an offscreen GPU
|
||||||
|
// Todo: allow the user to pick a GPU
|
||||||
|
int fd = 0;
|
||||||
|
gbm_device = IntPtr.Zero;
|
||||||
|
egl_display = IntPtr.Zero;
|
||||||
|
|
||||||
|
var files = Directory.GetFiles(gpu_path);
|
||||||
|
foreach (var gpu in files)
|
||||||
|
{
|
||||||
|
if (Path.GetFileName(gpu).StartsWith("card"))
|
||||||
|
{
|
||||||
|
int test_fd = SetupDisplay(gpu, out gbm_device, out egl_display);
|
||||||
|
if (test_fd >= 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (LinuxDisplayDriver.QueryDisplays(test_fd, null))
|
||||||
|
{
|
||||||
|
fd = test_fd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.WriteLine(e.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Print("[KMS] GPU '{0}' is not connected, skipping.", gpu);
|
||||||
|
Libc.close(test_fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd == 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[Error] No valid GPU found, bailing out.");
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SetupDisplay(string gpu, out IntPtr gbm_device, out IntPtr egl_display)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Attempting to use gpu '{0}'.", gpu);
|
||||||
|
|
||||||
|
gbm_device = IntPtr.Zero;
|
||||||
|
egl_display = IntPtr.Zero;
|
||||||
|
|
||||||
|
int fd = Libc.open(gpu, OpenFlags.ReadWrite | OpenFlags.CloseOnExec);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Failed to open gpu");
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
Debug.Print("[KMS] GPU '{0}' opened as fd:{1}", gpu, fd);
|
||||||
|
|
||||||
|
gbm_device = Gbm.CreateDevice(fd);
|
||||||
|
if (gbm_device == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("[KMS] Failed to create GBM device");
|
||||||
|
}
|
||||||
|
Debug.Print("[KMS] GBM {0:x} created successfully; ", gbm_device);
|
||||||
|
|
||||||
|
egl_display = Egl.GetDisplay(gbm_device);
|
||||||
|
if (egl_display == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("[KMS] Failed to create EGL display");
|
||||||
|
}
|
||||||
|
Debug.Print("[KMS] EGL display {0:x} created successfully", egl_display);
|
||||||
|
|
||||||
|
int major, minor;
|
||||||
|
if (!Egl.Initialize(egl_display, out major, out minor))
|
||||||
|
{
|
||||||
|
ErrorCode error = Egl.GetError();
|
||||||
|
throw new NotSupportedException("[KMS] Failed to initialize EGL display. Error code: " + error);
|
||||||
|
}
|
||||||
|
Debug.Print("[KMS] EGL {0}.{1} initialized successfully on display {2:x}", major, minor, egl_display);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Protected Members
|
||||||
|
|
||||||
|
protected override void Dispose(bool manual)
|
||||||
|
{
|
||||||
|
if (egl_display != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Terminating EGL.");
|
||||||
|
Egl.Terminate(egl_display);
|
||||||
|
egl_display = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
if (gbm_device != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Destroying GBM device.");
|
||||||
|
Gbm.DestroyDevice(gbm_device);
|
||||||
|
gbm_device = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
if (_fd >= 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Closing GPU fd.");
|
||||||
|
Libc.close(_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Dispose(manual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IPlatformFactory Members
|
||||||
|
|
||||||
|
public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice display_device)
|
||||||
|
{
|
||||||
|
return new LinuxNativeWindow(egl_display, gbm_device, gpu_fd, x, y, width, height, title, mode, options, display_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
|
||||||
|
{
|
||||||
|
return new LinuxDisplayDriver(gpu_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
|
||||||
|
{
|
||||||
|
return new LinuxGraphicsContext(mode, (LinuxWindowInfo)window, shareContext, major, minor, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
|
||||||
|
{
|
||||||
|
return (GraphicsContext.GetCurrentContextDelegate)delegate
|
||||||
|
{
|
||||||
|
return new ContextHandle(Egl.GetCurrentContext());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IKeyboardDriver2 CreateKeyboardDriver()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
MouseKeyboardDriver = MouseKeyboardDriver ?? new LinuxInput();
|
||||||
|
return MouseKeyboardDriver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IMouseDriver2 CreateMouseDriver()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
MouseKeyboardDriver = MouseKeyboardDriver ?? new LinuxInput();
|
||||||
|
return MouseKeyboardDriver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IJoystickDriver2 CreateJoystickDriver()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
JoystickDriver = JoystickDriver ?? new LinuxJoystick();
|
||||||
|
return JoystickDriver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
303
Source/OpenTK/Platform/Linux/LinuxGraphicsContext.cs
Normal file
303
Source/OpenTK/Platform/Linux/LinuxGraphicsContext.cs
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// LinuxGraphicsContext.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// thefiddler <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
/// \internal
|
||||||
|
/// <summary>
|
||||||
|
/// Defines an IGraphicsContext implementation for the Linux KMS framebuffer.
|
||||||
|
/// For Linux/X11 and other Unix operating systems, use the more generic
|
||||||
|
/// <see cref="OpenTK.Platform.Egl.EglUnixContext"/> instead.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Note: to display our results, we need to allocate a GBM framebuffer
|
||||||
|
/// and point the scanout address to that via Drm.ModeSetCrtc.
|
||||||
|
/// </remarks>
|
||||||
|
class LinuxGraphicsContext : Egl.EglUnixContext
|
||||||
|
{
|
||||||
|
BufferObject bo, bo_next;
|
||||||
|
int fd;
|
||||||
|
bool is_flip_queued;
|
||||||
|
int swap_interval;
|
||||||
|
|
||||||
|
public LinuxGraphicsContext(GraphicsMode mode, LinuxWindowInfo window, IGraphicsContext sharedContext,
|
||||||
|
int major, int minor, GraphicsContextFlags flags)
|
||||||
|
: base(mode, window, sharedContext, major, minor, flags)
|
||||||
|
{
|
||||||
|
if (mode.Buffers < 1)
|
||||||
|
throw new ArgumentException();
|
||||||
|
fd = window.FD;
|
||||||
|
|
||||||
|
PageFlip = HandlePageFlip;
|
||||||
|
PageFlipPtr = Marshal.GetFunctionPointerForDelegate(PageFlip);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SwapBuffers()
|
||||||
|
{
|
||||||
|
base.SwapBuffers();
|
||||||
|
|
||||||
|
bo_next = LockSurface();
|
||||||
|
int fb = GetFramebuffer(bo_next);
|
||||||
|
|
||||||
|
if (is_flip_queued)
|
||||||
|
{
|
||||||
|
// Todo: if we don't wait for the page flip,
|
||||||
|
// we drop all rendering buffers and get a crash
|
||||||
|
// in Egl.SwapBuffers(). We need to fix that
|
||||||
|
// before we can disable vsync.
|
||||||
|
WaitFlip(true); // WaitFlip(SwapInterval > 0)
|
||||||
|
if (is_flip_queued)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Dropping frame");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QueueFlip(fb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(IWindowInfo window)
|
||||||
|
{
|
||||||
|
WaitFlip(true);
|
||||||
|
|
||||||
|
base.SwapBuffers();
|
||||||
|
|
||||||
|
bo = LockSurface();
|
||||||
|
int fb = GetFramebuffer(bo);
|
||||||
|
SetScanoutRegion(fb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int SwapInterval
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return swap_interval;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
// We only support a SwapInterval of 0 (immediate)
|
||||||
|
// or 1 (vsynced).
|
||||||
|
// Todo: add support for SwapInterval of -1 (adaptive).
|
||||||
|
// This requires a small change in WaitFlip().
|
||||||
|
swap_interval = MathHelper.Clamp(value, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitFlip(bool block)
|
||||||
|
{
|
||||||
|
PollFD fds = new PollFD();
|
||||||
|
fds.fd = fd;
|
||||||
|
fds.events = PollFlags.In;
|
||||||
|
|
||||||
|
EventContext evctx = new EventContext();
|
||||||
|
evctx.version = EventContext.Version;
|
||||||
|
evctx.page_flip_handler = PageFlipPtr;
|
||||||
|
|
||||||
|
int timeout = block ? -1 : 0;
|
||||||
|
|
||||||
|
while (is_flip_queued)
|
||||||
|
{
|
||||||
|
fds.revents = 0;
|
||||||
|
if (Libc.poll(ref fds, 1, timeout) < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((fds.revents & (PollFlags.Hup | PollFlags.Error)) != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((fds.revents & PollFlags.In) != 0)
|
||||||
|
Drm.HandleEvent(fd, ref evctx);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page flip has taken place, update buffer objects
|
||||||
|
if (!is_flip_queued)
|
||||||
|
{
|
||||||
|
IntPtr gbm_surface = WindowInfo.Handle;
|
||||||
|
Gbm.ReleaseBuffer(gbm_surface, bo);
|
||||||
|
bo = bo_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QueueFlip(int buffer)
|
||||||
|
{
|
||||||
|
LinuxWindowInfo wnd = WindowInfo as LinuxWindowInfo;
|
||||||
|
if (wnd == null)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
int ret = Drm.ModePageFlip(fd, wnd.DisplayDevice.Id, buffer,
|
||||||
|
PageFlipFlags.FlipEvent, IntPtr.Zero);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Failed to enqueue framebuffer flip. Error: {0}", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
is_flip_queued = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetScanoutRegion(int buffer)
|
||||||
|
{
|
||||||
|
LinuxWindowInfo wnd = WindowInfo as LinuxWindowInfo;
|
||||||
|
if (wnd == null)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
ModeInfo* mode = wnd.DisplayDevice.pConnector->modes;
|
||||||
|
int connector_id = wnd.DisplayDevice.pConnector->connector_id;
|
||||||
|
int crtc_id = wnd.DisplayDevice.Id;
|
||||||
|
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
int connector_count = 1;
|
||||||
|
int ret = Drm.ModeSetCrtc(fd, crtc_id, buffer, x, y,
|
||||||
|
&connector_id, connector_count, mode);
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Drm.ModeSetCrtc{0}, {1}, {2}, {3}, {4:x}, {5}, {6:x}) failed. Error: {7}",
|
||||||
|
fd, crtc_id, buffer, x, y, (IntPtr)connector_id, connector_count, (IntPtr)mode, ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferObject LockSurface()
|
||||||
|
{
|
||||||
|
IntPtr gbm_surface = WindowInfo.Handle;
|
||||||
|
return Gbm.LockFrontBuffer(gbm_surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetFramebuffer(BufferObject bo)
|
||||||
|
{
|
||||||
|
if (bo == BufferObject.Zero)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
int bo_handle = bo.Handle;
|
||||||
|
if (bo_handle == 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Gbm.BOGetHandle({0:x}) failed.", bo);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = bo.Width;
|
||||||
|
int height = bo.Height;
|
||||||
|
int bpp = Mode.ColorFormat.BitsPerPixel;
|
||||||
|
int depth = Mode.Depth;
|
||||||
|
int stride = bo.Stride;
|
||||||
|
|
||||||
|
if (width == 0 || height == 0 || bpp == 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Invalid framebuffer format: {0}x{1} {2} {3} {4}",
|
||||||
|
width, height, stride, bpp, depth);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer;
|
||||||
|
int ret = Drm.ModeAddFB(
|
||||||
|
fd, width, height,
|
||||||
|
(byte)depth, (byte)bpp, stride, bo_handle,
|
||||||
|
out buffer);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Drm.ModeAddFB({0}, {1}, {2}, {3}, {4}, {5}, {6}) failed. Error: {7}",
|
||||||
|
fd, width, height, depth, bpp, stride, bo_handle, ret);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
bo.SetUserData((IntPtr)buffer, DestroyFB);
|
||||||
|
return buffer;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
Debug.Print("[Error] Failed to create framebuffer.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly IntPtr PageFlipPtr;
|
||||||
|
readonly PageFlipCallback PageFlip;
|
||||||
|
void HandlePageFlip(int fd,
|
||||||
|
int sequence,
|
||||||
|
int tv_sec,
|
||||||
|
int tv_usec,
|
||||||
|
IntPtr user_data)
|
||||||
|
{
|
||||||
|
is_flip_queued = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly DestroyUserDataCallback DestroyFB = HandleDestroyFB;
|
||||||
|
static void HandleDestroyFB(BufferObject bo, IntPtr data)
|
||||||
|
{
|
||||||
|
IntPtr gbm = bo.Device;
|
||||||
|
int fb = data.ToInt32();
|
||||||
|
Debug.Print("[KMS] Destroying framebuffer {0}", fb);
|
||||||
|
|
||||||
|
if (fb != 0)
|
||||||
|
{
|
||||||
|
Drm.ModeRmFB(Gbm.DeviceGetFD(gbm), fb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool manual)
|
||||||
|
{
|
||||||
|
if (manual)
|
||||||
|
{
|
||||||
|
// Reset the scanout region
|
||||||
|
LinuxWindowInfo wnd = WindowInfo as LinuxWindowInfo;
|
||||||
|
if (wnd != null)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
int connector_id = wnd.DisplayDevice.pConnector->connector_id;
|
||||||
|
ModeInfo mode = wnd.DisplayDevice.OriginalMode;
|
||||||
|
Drm.ModeSetCrtc(fd,
|
||||||
|
wnd.DisplayDevice.pCrtc->crtc_id,
|
||||||
|
wnd.DisplayDevice.pCrtc->buffer_id,
|
||||||
|
wnd.DisplayDevice.pCrtc->x,
|
||||||
|
wnd.DisplayDevice.pCrtc->y,
|
||||||
|
&connector_id,
|
||||||
|
1,
|
||||||
|
&mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
base.Dispose(manual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
717
Source/OpenTK/Platform/Linux/LinuxInput.cs
Normal file
717
Source/OpenTK/Platform/Linux/LinuxInput.cs
Normal file
|
@ -0,0 +1,717 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// LinuxKeyboardLibInput.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
|
using OpenTK.Input;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
class LinuxInput : IKeyboardDriver2, IMouseDriver2, IDisposable
|
||||||
|
{
|
||||||
|
class DeviceBase
|
||||||
|
{
|
||||||
|
readonly IntPtr Device;
|
||||||
|
string name;
|
||||||
|
string output;
|
||||||
|
string logical_seat;
|
||||||
|
string physical_seat;
|
||||||
|
|
||||||
|
public DeviceBase(IntPtr device, int id)
|
||||||
|
{
|
||||||
|
Device = device;
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Id
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetId(Device);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
LibInput.DeviceSetData(Device, (IntPtr)value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
name = name ?? LibInput.DeviceGetName(Device);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPtr Seat
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return LibInput.DeviceGetSeat(Device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string LogicalSeatName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
logical_seat = logical_seat ?? LibInput.SeatGetLogicalName(Seat);
|
||||||
|
return logical_seat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PhysicalSeatName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
physical_seat = physical_seat ?? LibInput.SeatGetPhysicalName(Seat);
|
||||||
|
return physical_seat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Output
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
output = output ?? LibInput.DeviceGetOutputName(Device);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KeyboardDevice : DeviceBase
|
||||||
|
{
|
||||||
|
public KeyboardState State;
|
||||||
|
|
||||||
|
public KeyboardDevice(IntPtr device, int id)
|
||||||
|
: base(device, id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MouseDevice : DeviceBase
|
||||||
|
{
|
||||||
|
public MouseState State;
|
||||||
|
|
||||||
|
public MouseDevice(IntPtr device, int id)
|
||||||
|
: base(device, id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly object Sync = new object();
|
||||||
|
static readonly Key[] KeyMap = Evdev.KeyMap;
|
||||||
|
static long DeviceFDCount;
|
||||||
|
|
||||||
|
// libinput returns various devices with keyboard/pointer even though
|
||||||
|
// they are not traditional keyboards/mice (for example "Integrated Camera"
|
||||||
|
// can be detected as a keyboard.)
|
||||||
|
// Since there is no API to retrieve actual device capabilities,
|
||||||
|
// we add all detected devices to a "candidate" list and promote them
|
||||||
|
// to an actual keyboard/mouse only when we receive a valid input event.
|
||||||
|
// This is far from optimal, but it appears to be the only viable solution
|
||||||
|
// unless a new API is added to libinput.
|
||||||
|
DeviceCollection<KeyboardDevice> KeyboardCandidates = new DeviceCollection<KeyboardDevice>();
|
||||||
|
DeviceCollection<MouseDevice> MouseCandidates = new DeviceCollection<MouseDevice>();
|
||||||
|
DeviceCollection<KeyboardDevice> Keyboards = new DeviceCollection<KeyboardDevice>();
|
||||||
|
DeviceCollection<MouseDevice> Mice = new DeviceCollection<MouseDevice>();
|
||||||
|
|
||||||
|
// Todo: do we need to maintain the geometry of each display separately?
|
||||||
|
Rectangle bounds;
|
||||||
|
|
||||||
|
// Global mouse cursor state
|
||||||
|
Vector2 CursorPosition = Vector2.Zero;
|
||||||
|
// Global mouse cursor offset (used for emulating SetPosition)
|
||||||
|
Vector2 CursorOffset = Vector2.Zero;
|
||||||
|
|
||||||
|
IntPtr udev;
|
||||||
|
IntPtr input_context;
|
||||||
|
InputInterface input_interface = new InputInterface(
|
||||||
|
OpenRestricted, CloseRestricted);
|
||||||
|
int fd;
|
||||||
|
Thread input_thread;
|
||||||
|
long exit;
|
||||||
|
|
||||||
|
public LinuxInput()
|
||||||
|
{
|
||||||
|
Debug.Print("[Linux] Initializing {0}", GetType().Name);
|
||||||
|
Debug.Indent();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Semaphore ready = new Semaphore(0, 1);
|
||||||
|
input_thread = new Thread(InputThreadLoop);
|
||||||
|
input_thread.IsBackground = true;
|
||||||
|
input_thread.Start(ready);
|
||||||
|
|
||||||
|
// Wait until the input thread is ready.
|
||||||
|
// Note: it would be nicer if we could avoid this.
|
||||||
|
// however we need to marshal errors back to the caller
|
||||||
|
// as exceptions.
|
||||||
|
// Todo: in a future version, we should add an "Application" object
|
||||||
|
// to handle all communication with the OS (including event processing.)
|
||||||
|
// Once we do that, we can remove all separate input threads.
|
||||||
|
ready.WaitOne();
|
||||||
|
if (exit != 0)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Debug.Print("Initialization {0}", exit == 0 ?
|
||||||
|
"complete" : "failed");
|
||||||
|
Debug.Unindent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Private Members
|
||||||
|
|
||||||
|
static CloseRestrictedCallback CloseRestricted = CloseRestrictedHandler;
|
||||||
|
static void CloseRestrictedHandler(int fd, IntPtr data)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] Closing fd {0}", fd);
|
||||||
|
int ret = Libc.close(fd);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] Failed to close fd {0}. Error: {1}", fd, ret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Interlocked.Decrement(ref DeviceFDCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static OpenRestrictedCallback OpenRestricted = OpenRestrictedHandler;
|
||||||
|
static int OpenRestrictedHandler(IntPtr path, int flags, IntPtr data)
|
||||||
|
{
|
||||||
|
int fd = Libc.open(path, (OpenFlags)flags);
|
||||||
|
Debug.Print("[Input] Opening '{0}' with flags {1}. fd:{2}",
|
||||||
|
Marshal.PtrToStringAnsi(path), (OpenFlags)flags, fd);
|
||||||
|
|
||||||
|
if (fd >= 0)
|
||||||
|
{
|
||||||
|
Interlocked.Increment(ref DeviceFDCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputThreadLoop(object semaphore)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] Running on thread {0}", Thread.CurrentThread.ManagedThreadId);
|
||||||
|
Setup();
|
||||||
|
|
||||||
|
// Inform the parent thread that initialization has completed successfully
|
||||||
|
(semaphore as Semaphore).Release();
|
||||||
|
Debug.Print("[Input] Released main thread.", input_context);
|
||||||
|
|
||||||
|
// Use a blocking poll for input messages, in order to reduce CPU usage
|
||||||
|
PollFD poll_fd = new PollFD();
|
||||||
|
poll_fd.fd = fd;
|
||||||
|
poll_fd.events = PollFlags.In;
|
||||||
|
Debug.Print("[Input] Created PollFD({0}, {1})", poll_fd.fd, poll_fd.events);
|
||||||
|
|
||||||
|
Debug.Print("[Input] Entering input loop.", poll_fd.fd, poll_fd.events);
|
||||||
|
while (Interlocked.Read(ref exit) == 0)
|
||||||
|
{
|
||||||
|
int ret = Libc.poll(ref poll_fd, 1, -1);
|
||||||
|
ErrorNumber error = (ErrorNumber)Marshal.GetLastWin32Error();
|
||||||
|
bool is_error =
|
||||||
|
ret < 0 && !(error == ErrorNumber.Again || error == ErrorNumber.Interrupted) ||
|
||||||
|
(poll_fd.revents & (PollFlags.Hup | PollFlags.Error | PollFlags.Invalid)) != 0;
|
||||||
|
|
||||||
|
// We need to query the desktop bounds in order to position the mouse cursor correctly.
|
||||||
|
// This value will be used for the current bunch of input events. If a monitor changes
|
||||||
|
// resolution in the meantime, we might be slightly off in our calculations - this error
|
||||||
|
// will be corrected when the next bunch of input events arrives.
|
||||||
|
UpdateDisplayBounds();
|
||||||
|
|
||||||
|
if (ret > 0 && (poll_fd.revents & (PollFlags.In | PollFlags.Pri)) != 0)
|
||||||
|
{
|
||||||
|
ProcessEvents(input_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_error)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] Exiting input loop {0} due to poll error [ret:{1} events:{2}]. Error: {3}.",
|
||||||
|
input_thread.ManagedThreadId, ret, poll_fd.revents, error);
|
||||||
|
Interlocked.Increment(ref exit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Debug.Print("[Input] Exited input loop.", poll_fd.fd, poll_fd.events);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDisplayBounds()
|
||||||
|
{
|
||||||
|
bounds = Rectangle.Empty;
|
||||||
|
for (DisplayIndex i = DisplayIndex.First; i < DisplayIndex.Sixth; i++)
|
||||||
|
{
|
||||||
|
DisplayDevice display = DisplayDevice.GetDisplay(i);
|
||||||
|
if (display != null)
|
||||||
|
{
|
||||||
|
bounds = Rectangle.Union(bounds, display.Bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateCursor()
|
||||||
|
{
|
||||||
|
Point p = new Point(
|
||||||
|
(int)Math.Round(CursorPosition.X + CursorOffset.X),
|
||||||
|
(int)Math.Round(CursorPosition.Y + CursorOffset.Y));
|
||||||
|
|
||||||
|
DisplayDevice display = DisplayDevice.FromPoint(p.X, p.Y) ?? DisplayDevice.Default;
|
||||||
|
if (display != null)
|
||||||
|
{
|
||||||
|
LinuxDisplay d = (LinuxDisplay)display.Id;
|
||||||
|
Drm.MoveCursor(d.FD, d.Id, p.X, p.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Setup()
|
||||||
|
{
|
||||||
|
// Todo: add static path fallback when udev is not installed.
|
||||||
|
udev = Udev.New();
|
||||||
|
if (udev == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] Udev.New() failed.");
|
||||||
|
Interlocked.Increment(ref exit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Debug.Print("[Input] Udev.New() = {0:x}", udev);
|
||||||
|
|
||||||
|
input_context = LibInput.CreateContext(input_interface, IntPtr.Zero, udev, "seat0");
|
||||||
|
if (input_context == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] LibInput.CreateContext({0:x}) failed.", udev);
|
||||||
|
Interlocked.Increment(ref exit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Debug.Print("[Input] LibInput.CreateContext({0:x}) = {1:x}", udev, input_context);
|
||||||
|
|
||||||
|
fd = LibInput.GetFD(input_context);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] LibInput.GetFD({0:x}) failed.", input_context);
|
||||||
|
Interlocked.Increment(ref exit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Debug.Print("[Input] LibInput.GetFD({0:x}) = {1}.", input_context, fd);
|
||||||
|
|
||||||
|
ProcessEvents(input_context);
|
||||||
|
LibInput.Resume(input_context);
|
||||||
|
Debug.Print("[Input] LibInput.Resume({0:x})", input_context);
|
||||||
|
|
||||||
|
if (Interlocked.Read(ref DeviceFDCount) <= 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[Error] Failed to open any input devices.");
|
||||||
|
Debug.Print("[Error] Ensure that you have access to '/dev/input/event*'.");
|
||||||
|
Interlocked.Increment(ref exit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessEvents(IntPtr input_context)
|
||||||
|
{
|
||||||
|
// Process all events in the event queue
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// Data available
|
||||||
|
int ret = LibInput.Dispatch(input_context);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] LibInput.Dispatch({0:x}) failed. Error: {1}",
|
||||||
|
input_context, ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntPtr pevent = LibInput.GetEvent(input_context);
|
||||||
|
if (pevent == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntPtr device = LibInput.GetDevice(pevent);
|
||||||
|
InputEventType type = LibInput.GetEventType(pevent);
|
||||||
|
|
||||||
|
lock (Sync)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case InputEventType.DeviceAdded:
|
||||||
|
HandleDeviceAdded(input_context, device);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InputEventType.DeviceRemoved:
|
||||||
|
HandleDeviceRemoved(input_context, device);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InputEventType.KeyboardKey:
|
||||||
|
HandleKeyboard(GetKeyboard(device), LibInput.GetKeyboardEvent(pevent));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InputEventType.PointerAxis:
|
||||||
|
HandlePointerAxis(GetMouse(device), LibInput.GetPointerEvent(pevent));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InputEventType.PointerButton:
|
||||||
|
HandlePointerButton(GetMouse(device), LibInput.GetPointerEvent(pevent));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InputEventType.PointerMotion:
|
||||||
|
HandlePointerMotion(GetMouse(device), LibInput.GetPointerEvent(pevent));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InputEventType.PointerMotionAbsolute:
|
||||||
|
HandlePointerMotionAbsolute(GetMouse(device), LibInput.GetPointerEvent(pevent));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LibInput.DestroyEvent(pevent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleDeviceAdded(IntPtr context, IntPtr device)
|
||||||
|
{
|
||||||
|
if (LibInput.DeviceHasCapability(device, DeviceCapability.Keyboard))
|
||||||
|
{
|
||||||
|
KeyboardDevice keyboard = new KeyboardDevice(device, Keyboards.Count);
|
||||||
|
KeyboardCandidates.Add(keyboard.Id, keyboard);
|
||||||
|
Debug.Print("[Input] Added keyboard device {0} '{1}' on '{2}' ('{3}')",
|
||||||
|
keyboard.Id, keyboard.Name, keyboard.LogicalSeatName, keyboard.PhysicalSeatName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LibInput.DeviceHasCapability(device, DeviceCapability.Mouse))
|
||||||
|
{
|
||||||
|
MouseDevice mouse = new MouseDevice(device, Mice.Count);
|
||||||
|
MouseCandidates.Add(mouse.Id, mouse);
|
||||||
|
Debug.Print("[Input] Added mouse device {0} '{1}' on '{2}' ('{3}')",
|
||||||
|
mouse.Id, mouse.Name, mouse.LogicalSeatName, mouse.PhysicalSeatName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LibInput.DeviceHasCapability(device, DeviceCapability.Touch))
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] Todo: touch device.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleDeviceRemoved(IntPtr context, IntPtr device)
|
||||||
|
{
|
||||||
|
if (LibInput.DeviceHasCapability(device, DeviceCapability.Keyboard))
|
||||||
|
{
|
||||||
|
int id = GetId(device);
|
||||||
|
Keyboards.TryRemove(id);
|
||||||
|
KeyboardCandidates.TryRemove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LibInput.DeviceHasCapability(device, DeviceCapability.Mouse))
|
||||||
|
{
|
||||||
|
int id = GetId(device);
|
||||||
|
Mice.TryRemove(id);
|
||||||
|
MouseCandidates.TryRemove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleKeyboard(KeyboardDevice device, KeyboardEvent e)
|
||||||
|
{
|
||||||
|
if (device != null)
|
||||||
|
{
|
||||||
|
device.State.SetIsConnected(true);
|
||||||
|
Debug.Print("[Input] Added keyboard {0}", device.Id);
|
||||||
|
|
||||||
|
Key key = Key.Unknown;
|
||||||
|
uint raw = e.Key;
|
||||||
|
if (raw >= 0 && raw < KeyMap.Length)
|
||||||
|
{
|
||||||
|
key = KeyMap[raw];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == Key.Unknown)
|
||||||
|
{
|
||||||
|
Debug.Print("[Linux] Unknown key with code '{0}'", raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
device.State.SetKeyState(key, e.KeyState == KeyState.Pressed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlePointerAxis(MouseDevice mouse, PointerEvent e)
|
||||||
|
{
|
||||||
|
if (mouse != null)
|
||||||
|
{
|
||||||
|
mouse.State.SetIsConnected(true);
|
||||||
|
|
||||||
|
double value = e.AxisValue;
|
||||||
|
PointerAxis axis = e.Axis;
|
||||||
|
switch (axis)
|
||||||
|
{
|
||||||
|
case PointerAxis.HorizontalScroll:
|
||||||
|
mouse.State.SetScrollRelative((float)value, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PointerAxis.VerticalScroll:
|
||||||
|
mouse.State.SetScrollRelative(0, (float)value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Debug.Print("[Input] Unknown scroll axis {0}.", axis);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlePointerButton(MouseDevice mouse, PointerEvent e)
|
||||||
|
{
|
||||||
|
if (mouse != null)
|
||||||
|
{
|
||||||
|
mouse.State.SetIsConnected(true);
|
||||||
|
|
||||||
|
MouseButton button = Evdev.GetMouseButton(e.Button);
|
||||||
|
ButtonState state = e.ButtonState;
|
||||||
|
mouse.State[(MouseButton)button] = state == ButtonState.Pressed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlePointerMotion(MouseDevice mouse, PointerEvent e)
|
||||||
|
{
|
||||||
|
Vector2 delta = new Vector2((float)e.X, (float)e.Y);
|
||||||
|
if (mouse != null)
|
||||||
|
{
|
||||||
|
mouse.State.SetIsConnected(true);
|
||||||
|
mouse.State.Position += delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
CursorPosition = new Vector2(
|
||||||
|
MathHelper.Clamp(CursorPosition.X + delta.X, bounds.Left, bounds.Right - 1),
|
||||||
|
MathHelper.Clamp(CursorPosition.Y + delta.Y, bounds.Top, bounds.Bottom - 1));
|
||||||
|
UpdateCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlePointerMotionAbsolute(MouseDevice mouse, PointerEvent e)
|
||||||
|
{
|
||||||
|
if (mouse != null)
|
||||||
|
{
|
||||||
|
mouse.State.SetIsConnected(true);
|
||||||
|
mouse.State.Position = new Vector2(e.X, e.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
CursorPosition = new Vector2(
|
||||||
|
e.TransformedX(bounds.Width),
|
||||||
|
e.TransformedY(bounds.Height));
|
||||||
|
UpdateCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GetId(IntPtr device)
|
||||||
|
{
|
||||||
|
return LibInput.DeviceGetData(device).ToInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardDevice GetKeyboard(IntPtr device)
|
||||||
|
{
|
||||||
|
int id = GetId(device);
|
||||||
|
KeyboardDevice keyboard = KeyboardCandidates.FromHardwareId(id);
|
||||||
|
if (keyboard != null)
|
||||||
|
{
|
||||||
|
Keyboards.Add(id, keyboard);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] Keyboard {0} does not exist in device list.", id);
|
||||||
|
}
|
||||||
|
return keyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseDevice GetMouse(IntPtr device)
|
||||||
|
{
|
||||||
|
int id = GetId(device);
|
||||||
|
MouseDevice mouse = MouseCandidates.FromHardwareId(id);
|
||||||
|
if (mouse != null)
|
||||||
|
{
|
||||||
|
Mice.Add(id, mouse);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] Mouse {0} does not exist in device list.", id);
|
||||||
|
}
|
||||||
|
return mouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IKeyboardDriver2 implementation
|
||||||
|
|
||||||
|
KeyboardState IKeyboardDriver2.GetState()
|
||||||
|
{
|
||||||
|
lock (Sync)
|
||||||
|
{
|
||||||
|
KeyboardState state = new KeyboardState();
|
||||||
|
foreach (KeyboardDevice keyboard in Keyboards)
|
||||||
|
{
|
||||||
|
state.MergeBits(keyboard.State);
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardState IKeyboardDriver2.GetState(int index)
|
||||||
|
{
|
||||||
|
lock (Sync)
|
||||||
|
{
|
||||||
|
KeyboardDevice device = Keyboards.FromIndex(index);
|
||||||
|
if (device != null)
|
||||||
|
{
|
||||||
|
return device.State;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new KeyboardState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string IKeyboardDriver2.GetDeviceName(int index)
|
||||||
|
{
|
||||||
|
lock (Sync)
|
||||||
|
{
|
||||||
|
KeyboardDevice device = Keyboards.FromIndex(index);
|
||||||
|
if (device != null)
|
||||||
|
{
|
||||||
|
return device.Name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return String.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IMouseDriver2 implementation
|
||||||
|
|
||||||
|
MouseState IMouseDriver2.GetState()
|
||||||
|
{
|
||||||
|
lock (Sync)
|
||||||
|
{
|
||||||
|
MouseState state = new MouseState();
|
||||||
|
foreach (MouseDevice mouse in Mice)
|
||||||
|
{
|
||||||
|
state.MergeBits(mouse.State);
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseState IMouseDriver2.GetState(int index)
|
||||||
|
{
|
||||||
|
lock (Sync)
|
||||||
|
{
|
||||||
|
MouseDevice device = Mice.FromIndex(index);
|
||||||
|
if (device != null)
|
||||||
|
{
|
||||||
|
return device.State;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new MouseState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IMouseDriver2.SetPosition(double x, double y)
|
||||||
|
{
|
||||||
|
// Todo: this does not appear to be supported in libinput.
|
||||||
|
// We will have to emulate this in the KMS mouse rendering code.
|
||||||
|
CursorOffset = new Vector2(
|
||||||
|
(float)x - CursorPosition.X,
|
||||||
|
(float)y - CursorPosition.Y);
|
||||||
|
UpdateCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseState IMouseDriver2.GetCursorState()
|
||||||
|
{
|
||||||
|
MouseState state = (this as IMouseDriver2).GetState();
|
||||||
|
state.Position = CursorPosition + CursorOffset;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable implementation
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
if (input_context != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] Destroying libinput context");
|
||||||
|
LibInput.Suspend(input_context);
|
||||||
|
Interlocked.Increment(ref exit);
|
||||||
|
|
||||||
|
LibInput.DestroyContext(input_context);
|
||||||
|
input_context = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (udev != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] Destroying udev context");
|
||||||
|
Udev.Destroy(udev);
|
||||||
|
udev = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_interface = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] {0} leaked. Did you forget to call Dispose()?", GetType().FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~LinuxInput()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -33,9 +33,9 @@ using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
|
|
||||||
namespace OpenTK.Platform.X11
|
namespace OpenTK.Platform.Linux
|
||||||
{
|
{
|
||||||
struct X11JoyDetails
|
struct LinuxJoyDetails
|
||||||
{
|
{
|
||||||
public Guid Guid;
|
public Guid Guid;
|
||||||
public int FileDescriptor;
|
public int FileDescriptor;
|
||||||
|
@ -43,7 +43,7 @@ namespace OpenTK.Platform.X11
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: despite what the name says, this class is Linux-specific.
|
// Note: despite what the name says, this class is Linux-specific.
|
||||||
sealed class X11Joystick : IJoystickDriver2
|
sealed class LinuxJoystick : IJoystickDriver2
|
||||||
{
|
{
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ namespace OpenTK.Platform.X11
|
||||||
readonly FileSystemWatcher watcher = new FileSystemWatcher();
|
readonly FileSystemWatcher watcher = new FileSystemWatcher();
|
||||||
|
|
||||||
readonly Dictionary<int, int> index_to_stick = new Dictionary<int, int>();
|
readonly Dictionary<int, int> index_to_stick = new Dictionary<int, int>();
|
||||||
List<JoystickDevice<X11JoyDetails>> sticks = new List<JoystickDevice<X11JoyDetails>>();
|
List<JoystickDevice<LinuxJoyDetails>> sticks = new List<JoystickDevice<LinuxJoyDetails>>();
|
||||||
|
|
||||||
bool disposed;
|
bool disposed;
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public X11Joystick()
|
public LinuxJoystick()
|
||||||
{
|
{
|
||||||
string path =
|
string path =
|
||||||
Directory.Exists(JoystickPath) ? JoystickPath :
|
Directory.Exists(JoystickPath) ? JoystickPath :
|
||||||
|
@ -89,7 +89,7 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
foreach (string file in Directory.GetFiles(path))
|
foreach (string file in Directory.GetFiles(path))
|
||||||
{
|
{
|
||||||
JoystickDevice<X11JoyDetails> stick = OpenJoystick(file);
|
JoystickDevice<LinuxJoyDetails> stick = OpenJoystick(file);
|
||||||
if (stick != null)
|
if (stick != null)
|
||||||
{
|
{
|
||||||
//stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
|
//stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
|
||||||
|
@ -155,7 +155,7 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
#region Private Members
|
#region Private Members
|
||||||
|
|
||||||
Guid CreateGuid(JoystickDevice<X11JoyDetails> js, string path, int number)
|
Guid CreateGuid(JoystickDevice<LinuxJoyDetails> js, string path, int number)
|
||||||
{
|
{
|
||||||
byte[] bytes = new byte[16];
|
byte[] bytes = new byte[16];
|
||||||
for (int i = 0; i < Math.Min(bytes.Length, js.Description.Length); i++)
|
for (int i = 0; i < Math.Min(bytes.Length, js.Description.Length); i++)
|
||||||
|
@ -221,9 +221,9 @@ namespace OpenTK.Platform.X11
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
JoystickDevice<X11JoyDetails> OpenJoystick(string path)
|
JoystickDevice<LinuxJoyDetails> OpenJoystick(string path)
|
||||||
{
|
{
|
||||||
JoystickDevice<X11JoyDetails> stick = null;
|
JoystickDevice<LinuxJoyDetails> stick = null;
|
||||||
|
|
||||||
int number = GetJoystickNumber(Path.GetFileName(path));
|
int number = GetJoystickNumber(Path.GetFileName(path));
|
||||||
if (number >= 0)
|
if (number >= 0)
|
||||||
|
@ -231,28 +231,28 @@ namespace OpenTK.Platform.X11
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
fd = UnsafeNativeMethods.open(path, OpenFlags.NonBlock);
|
fd = Libc.open(path, OpenFlags.NonBlock);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Check joystick driver version (must be 1.0+)
|
// Check joystick driver version (must be 1.0+)
|
||||||
int driver_version = 0x00000800;
|
int driver_version = 0x00000800;
|
||||||
UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Version, ref driver_version);
|
Libc.ioctl(fd, JoystickIoctlCode.Version, ref driver_version);
|
||||||
if (driver_version < 0x00010000)
|
if (driver_version < 0x00010000)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Get number of joystick axes
|
// Get number of joystick axes
|
||||||
int axes = 0;
|
int axes = 0;
|
||||||
UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Axes, ref axes);
|
Libc.ioctl(fd, JoystickIoctlCode.Axes, ref axes);
|
||||||
|
|
||||||
// Get number of joystick buttons
|
// Get number of joystick buttons
|
||||||
int buttons = 0;
|
int buttons = 0;
|
||||||
UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Buttons, ref buttons);
|
Libc.ioctl(fd, JoystickIoctlCode.Buttons, ref buttons);
|
||||||
|
|
||||||
stick = new JoystickDevice<X11JoyDetails>(number, axes, buttons);
|
stick = new JoystickDevice<LinuxJoyDetails>(number, axes, buttons);
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder(128);
|
StringBuilder sb = new StringBuilder(128);
|
||||||
UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Name128, sb);
|
Libc.ioctl(fd, JoystickIoctlCode.Name128, sb);
|
||||||
stick.Description = sb.ToString();
|
stick.Description = sb.ToString();
|
||||||
|
|
||||||
stick.Details.FileDescriptor = fd;
|
stick.Details.FileDescriptor = fd;
|
||||||
|
@ -287,16 +287,16 @@ namespace OpenTK.Platform.X11
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (stick == null && fd != -1)
|
if (stick == null && fd != -1)
|
||||||
UnsafeNativeMethods.close(fd);
|
Libc.close(fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return stick;
|
return stick;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloseJoystick(JoystickDevice<X11JoyDetails> js)
|
void CloseJoystick(JoystickDevice<LinuxJoyDetails> js)
|
||||||
{
|
{
|
||||||
UnsafeNativeMethods.close(js.Details.FileDescriptor);
|
Libc.close(js.Details.FileDescriptor);
|
||||||
js.Details.State = new JoystickState(); // clear joystick state
|
js.Details.State = new JoystickState(); // clear joystick state
|
||||||
js.Details.FileDescriptor = -1;
|
js.Details.FileDescriptor = -1;
|
||||||
|
|
||||||
|
@ -317,13 +317,13 @@ namespace OpenTK.Platform.X11
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PollJoystick(JoystickDevice<X11JoyDetails> js)
|
void PollJoystick(JoystickDevice<LinuxJoyDetails> js)
|
||||||
{
|
{
|
||||||
JoystickEvent e;
|
JoystickEvent e;
|
||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
while ((long)UnsafeNativeMethods.read(js.Details.FileDescriptor, (void*)&e, (UIntPtr)sizeof(JoystickEvent)) > 0)
|
while ((long)Libc.read(js.Details.FileDescriptor, (void*)&e, (UIntPtr)sizeof(JoystickEvent)) > 0)
|
||||||
{
|
{
|
||||||
e.Type &= ~JoystickEventType.Init;
|
e.Type &= ~JoystickEventType.Init;
|
||||||
|
|
||||||
|
@ -352,78 +352,9 @@ namespace OpenTK.Platform.X11
|
||||||
return index_to_stick.ContainsKey(index);
|
return index_to_stick.ContainsKey(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region UnsafeNativeMethods
|
|
||||||
|
|
||||||
struct EvdevInputId
|
|
||||||
{
|
|
||||||
public ushort BusType;
|
|
||||||
public ushort Vendor;
|
|
||||||
public ushort Product;
|
|
||||||
public ushort Version;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum EvdevIoctlCode : uint
|
|
||||||
{
|
|
||||||
Id = ((byte)'E' << 8) | (0x02 << 0) //EVIOCGID, which is _IOR('E', 0x02, struct input_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct JoystickEvent
|
|
||||||
{
|
|
||||||
public uint Time; // (u32) event timestamp in milliseconds
|
|
||||||
public short Value; // (s16) value
|
|
||||||
public JoystickEventType Type; // (u8) event type
|
|
||||||
public byte Number; // (u8) axis/button number
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
enum JoystickEventType : byte
|
|
||||||
{
|
|
||||||
Button = 0x01, // button pressed/released
|
|
||||||
Axis = 0x02, // joystick moved
|
|
||||||
Init = 0x80 // initial state of device
|
|
||||||
}
|
|
||||||
|
|
||||||
enum JoystickIoctlCode : uint
|
|
||||||
{
|
|
||||||
Version = 0x80046a01,
|
|
||||||
Axes = 0x80016a11,
|
|
||||||
Buttons = 0x80016a12,
|
|
||||||
Name128 = (2u << 30) | (0x6A << 8) | (0x13 << 0) | (128 << 16) //JSIOCGNAME(128), which is _IOC(_IO_READ, 'j', 0x13, len)
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly string JoystickPath = "/dev/input";
|
static readonly string JoystickPath = "/dev/input";
|
||||||
static readonly string JoystickPathLegacy = "/dev";
|
static readonly string JoystickPathLegacy = "/dev";
|
||||||
|
|
||||||
[Flags]
|
|
||||||
enum OpenFlags
|
|
||||||
{
|
|
||||||
NonBlock = 0x00000800
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UnsafeNativeMethods
|
|
||||||
{
|
|
||||||
[DllImport("libc", SetLastError = true)]
|
|
||||||
public static extern int ioctl(int d, JoystickIoctlCode request, ref int data);
|
|
||||||
|
|
||||||
[DllImport("libc", SetLastError = true)]
|
|
||||||
public static extern int ioctl(int d, JoystickIoctlCode request, StringBuilder data);
|
|
||||||
|
|
||||||
[DllImport("libc", SetLastError = true)]
|
|
||||||
public static extern int ioctl(int d, EvdevIoctlCode request, out EvdevInputId data);
|
|
||||||
|
|
||||||
[DllImport("libc", SetLastError = true)]
|
|
||||||
public static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, OpenFlags flags);
|
|
||||||
|
|
||||||
[DllImport("libc", SetLastError = true)]
|
|
||||||
public static extern int close(int fd);
|
|
||||||
|
|
||||||
[DllImport("libc", SetLastError = true)]
|
|
||||||
unsafe public static extern IntPtr read(int fd, void* buffer, UIntPtr count);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IDisposable Members
|
#region IDisposable Members
|
||||||
|
@ -443,7 +374,7 @@ namespace OpenTK.Platform.X11
|
||||||
}
|
}
|
||||||
|
|
||||||
watcher.Dispose();
|
watcher.Dispose();
|
||||||
foreach (JoystickDevice<X11JoyDetails> js in sticks)
|
foreach (JoystickDevice<LinuxJoyDetails> js in sticks)
|
||||||
{
|
{
|
||||||
CloseJoystick(js);
|
CloseJoystick(js);
|
||||||
}
|
}
|
||||||
|
@ -452,7 +383,7 @@ namespace OpenTK.Platform.X11
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~X11Joystick()
|
~LinuxJoystick()
|
||||||
{
|
{
|
||||||
Dispose(false);
|
Dispose(false);
|
||||||
}
|
}
|
||||||
|
@ -465,7 +396,7 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
if (IsValid(index))
|
if (IsValid(index))
|
||||||
{
|
{
|
||||||
JoystickDevice<X11JoyDetails> js =
|
JoystickDevice<LinuxJoyDetails> js =
|
||||||
sticks[index_to_stick[index]];
|
sticks[index_to_stick[index]];
|
||||||
PollJoystick(js);
|
PollJoystick(js);
|
||||||
return js.Details.State;
|
return js.Details.State;
|
||||||
|
@ -478,7 +409,7 @@ namespace OpenTK.Platform.X11
|
||||||
JoystickCapabilities caps = new JoystickCapabilities();
|
JoystickCapabilities caps = new JoystickCapabilities();
|
||||||
if (IsValid(index))
|
if (IsValid(index))
|
||||||
{
|
{
|
||||||
JoystickDevice<X11JoyDetails> js = sticks[index_to_stick[index]];
|
JoystickDevice<LinuxJoyDetails> js = sticks[index_to_stick[index]];
|
||||||
caps = new JoystickCapabilities(
|
caps = new JoystickCapabilities(
|
||||||
js.Axis.Count,
|
js.Axis.Count,
|
||||||
js.Button.Count,
|
js.Button.Count,
|
||||||
|
@ -492,7 +423,7 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
if (IsValid(index))
|
if (IsValid(index))
|
||||||
{
|
{
|
||||||
JoystickDevice<X11JoyDetails> js = sticks[index_to_stick[index]];
|
JoystickDevice<LinuxJoyDetails> js = sticks[index_to_stick[index]];
|
||||||
return js.Details.Guid;
|
return js.Details.Guid;
|
||||||
}
|
}
|
||||||
return new Guid();
|
return new Guid();
|
268
Source/OpenTK/Platform/Linux/LinuxKeyboardTTY.cs
Normal file
268
Source/OpenTK/Platform/Linux/LinuxKeyboardTTY.cs
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// LinuxKeyboardTTY.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// thefiddler <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using OpenTK.Input;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
// Todo: this has terrible side-effects on process exit
|
||||||
|
// (the keyboard remains tied up.) We need to find a
|
||||||
|
// proper way to clean up after ourselves, even in case
|
||||||
|
// of a crash.
|
||||||
|
#if EXPERIMENTAL
|
||||||
|
class LinuxKeyboardTTY : IKeyboardDriver2, IDisposable
|
||||||
|
{
|
||||||
|
const int stdin = 0; // STDIN_FILENO
|
||||||
|
readonly object sync = new object();
|
||||||
|
Thread input_thread;
|
||||||
|
long exit;
|
||||||
|
KeyboardState state;
|
||||||
|
|
||||||
|
TerminalState original_state;
|
||||||
|
TerminalState current_state;
|
||||||
|
|
||||||
|
IntPtr original_mode = new IntPtr(-1);
|
||||||
|
int original_stdin;
|
||||||
|
|
||||||
|
public LinuxKeyboardTTY()
|
||||||
|
{
|
||||||
|
Debug.Print("[Linux] Using TTY keyboard input.");
|
||||||
|
|
||||||
|
if (!SetupTTY(stdin))
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
input_thread = new Thread(ProcessEvents);
|
||||||
|
input_thread.IsBackground = true;
|
||||||
|
input_thread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Private Members
|
||||||
|
|
||||||
|
bool SetupTTY(int stdin)
|
||||||
|
{
|
||||||
|
// Ensure that we are using a real terminal,
|
||||||
|
// rather than some short of file redirection.thing.
|
||||||
|
if (!Terminal.IsTerminal(stdin))
|
||||||
|
{
|
||||||
|
Debug.Print("[Linux] Terminal.IsTerminal({0}) returned false.", stdin);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//original_stdin = Libc.dup(stdin);
|
||||||
|
|
||||||
|
int ret = Terminal.GetAttributes(stdin, out original_state);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[Linux] Terminal.GetAttributes({0}) failed. Error: {1}",
|
||||||
|
stdin, ret);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve current keyboard mode
|
||||||
|
ret = Libc.ioctl(stdin, KeyboardIoctlCode.GetMode, ref original_mode);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[Linux] Libc.ioctl({0}, KeyboardIoctlCode.GetMode) failed. Error: {1}",
|
||||||
|
stdin, ret);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update terminal state
|
||||||
|
current_state = original_state;
|
||||||
|
current_state.LocalMode &= ~(/*LocalFlags.ECHO |*/ LocalFlags.ICANON | LocalFlags.ISIG);
|
||||||
|
current_state.InputMode &= ~(
|
||||||
|
InputFlags.ISTRIP | InputFlags.IGNCR | InputFlags.ICRNL |
|
||||||
|
InputFlags.INLCR | InputFlags.IXOFF | InputFlags.IXON);
|
||||||
|
current_state.ControlCharacters.VMIN = 0;
|
||||||
|
current_state.ControlCharacters.VTIME = 0;
|
||||||
|
Terminal.SetAttributes(stdin, OptionalActions.FLUSH, ref current_state);
|
||||||
|
|
||||||
|
// Request keycodes
|
||||||
|
int mode = 0x02; // K_MEDIUMRAW
|
||||||
|
ret = Libc.ioctl(stdin, KeyboardIoctlCode.SetMode, mode);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[Linux] Libc.ioctl({0}, KeyboardIoctlCode.SetMode, {1}) failed. Error: {2}",
|
||||||
|
stdin, mode, ret);
|
||||||
|
ExitTTY(this, EventArgs.Empty);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we reset the original keyboard/terminal state on exit,
|
||||||
|
// even if we crash.
|
||||||
|
HookEvents();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExitTTY(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (original_mode != new IntPtr(-1))
|
||||||
|
{
|
||||||
|
Debug.Print("[Linux] Exiting TTY keyboard input.");
|
||||||
|
|
||||||
|
Libc.ioctl(stdin, KeyboardIoctlCode.SetMode, ref original_mode);
|
||||||
|
Terminal.SetAttributes(stdin, OptionalActions.FLUSH, ref original_state);
|
||||||
|
original_mode = new IntPtr(-1);
|
||||||
|
|
||||||
|
UnhookEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HookEvents()
|
||||||
|
{
|
||||||
|
Process.GetCurrentProcess().Exited += ExitTTY;
|
||||||
|
Console.CancelKeyPress += ExitTTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnhookEvents()
|
||||||
|
{
|
||||||
|
Process.GetCurrentProcess().Exited -= ExitTTY;
|
||||||
|
Console.CancelKeyPress -= ExitTTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessEvents()
|
||||||
|
{
|
||||||
|
state.SetIsConnected(true);
|
||||||
|
|
||||||
|
while (Interlocked.Read(ref exit) == 0)
|
||||||
|
{
|
||||||
|
byte scancode;
|
||||||
|
short extended;
|
||||||
|
|
||||||
|
while (Libc.read(stdin, out scancode) > 0)
|
||||||
|
{
|
||||||
|
bool pressed = (scancode & 0x80) == 0;
|
||||||
|
int key = scancode & ~0x80;
|
||||||
|
KeyModifiers mods;
|
||||||
|
Debug.Print("{0}:{1} is {2}", key, (int)TranslateKey(key, out mods), pressed);
|
||||||
|
|
||||||
|
if (key == 0)
|
||||||
|
{
|
||||||
|
// This is an extended scancode, ignore
|
||||||
|
Libc.read(stdin, out extended);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lock (sync)
|
||||||
|
{
|
||||||
|
state[(Key)key] = pressed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input_thread = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key TranslateKey(int key, out KeyModifiers mods)
|
||||||
|
{
|
||||||
|
int k = MathHelper.Clamp((int)key, 0, KeyMap.Length);
|
||||||
|
Key result = KeyMap[k];
|
||||||
|
mods = 0;
|
||||||
|
mods |= (result == Key.AltLeft || result == Key.AltRight) ? KeyModifiers.Alt : 0;
|
||||||
|
mods |= (result == Key.ControlLeft || result == Key.ControlRight) ? KeyModifiers.Control : 0;
|
||||||
|
mods |= (result == Key.ShiftLeft || result == Key.ShiftRight) ? KeyModifiers.Shift : 0;
|
||||||
|
return KeyMap[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly Key[] KeyMap = Evdev.KeyMap;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IKeyboardDriver2 implementation
|
||||||
|
|
||||||
|
public KeyboardState GetState()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyboardState GetState(int index)
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
return state;
|
||||||
|
else
|
||||||
|
return new KeyboardState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetDeviceName(int index)
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
return "Standard Input";
|
||||||
|
else
|
||||||
|
return String.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable Implementation
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
Interlocked.Increment(ref exit);
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
ExitTTY(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Print("{0} leaked, did you forget to call Dispose()?", typeof(LinuxKeyboardTTY).FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~LinuxKeyboardTTY()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
549
Source/OpenTK/Platform/Linux/LinuxNativeWindow.cs
Normal file
549
Source/OpenTK/Platform/Linux/LinuxNativeWindow.cs
Normal file
|
@ -0,0 +1,549 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// LinuxNativeWindow.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
using OpenTK.Input;
|
||||||
|
using OpenTK.Platform.Egl;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
using Egl = OpenTK.Platform.Egl.Egl;
|
||||||
|
|
||||||
|
class LinuxNativeWindow : NativeWindowBase
|
||||||
|
{
|
||||||
|
LinuxWindowInfo window;
|
||||||
|
string title;
|
||||||
|
Icon icon;
|
||||||
|
Rectangle bounds;
|
||||||
|
Size client_size;
|
||||||
|
bool exists;
|
||||||
|
bool is_focused;
|
||||||
|
bool is_cursor_visible = true;
|
||||||
|
|
||||||
|
KeyboardState previous_keyboard;
|
||||||
|
MouseState previous_mouse;
|
||||||
|
|
||||||
|
MouseCursor cursor_current;
|
||||||
|
BufferObject cursor_custom;
|
||||||
|
BufferObject cursor_default;
|
||||||
|
BufferObject cursor_empty;
|
||||||
|
|
||||||
|
IntPtr gbm_surface;
|
||||||
|
|
||||||
|
public LinuxNativeWindow(IntPtr display, IntPtr gbm, int fd,
|
||||||
|
int x, int y, int width, int height, string title,
|
||||||
|
GraphicsMode mode, GameWindowFlags options,
|
||||||
|
DisplayDevice display_device)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Creating window on display {0:x}", display);
|
||||||
|
|
||||||
|
Title = title;
|
||||||
|
|
||||||
|
display_device = display_device ?? DisplayDevice.Default;
|
||||||
|
if (display_device == null)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("[KMS] Driver does not currently support headless systems");
|
||||||
|
}
|
||||||
|
|
||||||
|
window = new LinuxWindowInfo(display, fd, gbm, display_device.Id as LinuxDisplay);
|
||||||
|
|
||||||
|
// Note: we only support fullscreen windows on KMS.
|
||||||
|
// We implicitly override the requested width and height
|
||||||
|
// by the width and height of the DisplayDevice, if any.
|
||||||
|
width = display_device.Width;
|
||||||
|
height = display_device.Height;
|
||||||
|
bounds = new Rectangle(0, 0, width, height);
|
||||||
|
client_size = bounds.Size;
|
||||||
|
|
||||||
|
if (!mode.Index.HasValue)
|
||||||
|
{
|
||||||
|
mode = new EglGraphicsMode().SelectGraphicsMode(window, mode, 0);
|
||||||
|
}
|
||||||
|
Debug.Print("[KMS] Selected EGL mode {0}", mode);
|
||||||
|
|
||||||
|
SurfaceFormat format = GetSurfaceFormat(display, mode);
|
||||||
|
SurfaceFlags usage = SurfaceFlags.Rendering | SurfaceFlags.Scanout;
|
||||||
|
if (!Gbm.IsFormatSupported(gbm, format, usage))
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Failed to find suitable surface format, using XRGB8888");
|
||||||
|
format = SurfaceFormat.XRGB8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Print("[KMS] Creating GBM surface on {0:x} with {1}x{2} {3} [{4}]",
|
||||||
|
gbm, width, height, format, usage);
|
||||||
|
IntPtr gbm_surface = Gbm.CreateSurface(gbm,
|
||||||
|
width, height, format, usage);
|
||||||
|
if (gbm_surface == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("[KMS] Failed to create GBM surface for rendering");
|
||||||
|
}
|
||||||
|
|
||||||
|
window.Handle = gbm_surface;
|
||||||
|
Debug.Print("[KMS] Created GBM surface {0:x}", window.Handle);
|
||||||
|
|
||||||
|
window.CreateWindowSurface(mode.Index.Value);
|
||||||
|
Debug.Print("[KMS] Created EGL surface {0:x}", window.Surface);
|
||||||
|
|
||||||
|
cursor_default = CreateCursor(gbm, Cursors.Default);
|
||||||
|
cursor_empty = CreateCursor(gbm, Cursors.Empty);
|
||||||
|
Cursor = MouseCursor.Default;
|
||||||
|
exists = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Private Members
|
||||||
|
|
||||||
|
static BufferObject CreateCursor(IntPtr gbm, MouseCursor cursor)
|
||||||
|
{
|
||||||
|
if (cursor.Width > 64 || cursor.Height > 64)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Cursor size {0}x{1} unsupported. Maximum is 64x64.",
|
||||||
|
cursor.Width, cursor.Height);
|
||||||
|
return default(BufferObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = 64;
|
||||||
|
int height = 64;
|
||||||
|
SurfaceFormat format = SurfaceFormat.ARGB8888;
|
||||||
|
SurfaceFlags usage = SurfaceFlags.Cursor64x64 | SurfaceFlags.Write;
|
||||||
|
|
||||||
|
Debug.Print("[KMS] Gbm.CreateBuffer({0:X}, {1}, {2}, {3}, {4}).",
|
||||||
|
gbm, width, height, format, usage);
|
||||||
|
|
||||||
|
BufferObject bo = Gbm.CreateBuffer(
|
||||||
|
gbm, width, height, format, usage);
|
||||||
|
|
||||||
|
if (bo == BufferObject.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Failed to create buffer.");
|
||||||
|
return bo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy cursor.Data into a new buffer of the correct size
|
||||||
|
byte[] cursor_data = new byte[width * height * 4];
|
||||||
|
for (int y = 0; y < cursor.Height; y++)
|
||||||
|
{
|
||||||
|
int dst_offset = y * width * 4;
|
||||||
|
int src_offset = y * cursor.Width * 4;
|
||||||
|
int src_length = cursor.Width * 4;
|
||||||
|
Array.Copy(
|
||||||
|
cursor.Data, src_offset,
|
||||||
|
cursor_data, dst_offset,
|
||||||
|
src_length);
|
||||||
|
}
|
||||||
|
bo.Write(cursor_data);
|
||||||
|
|
||||||
|
return bo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCursor(MouseCursor cursor)
|
||||||
|
{
|
||||||
|
BufferObject bo = default(BufferObject);
|
||||||
|
if (cursor == MouseCursor.Default)
|
||||||
|
{
|
||||||
|
bo = cursor_default;
|
||||||
|
}
|
||||||
|
else if (cursor == MouseCursor.Empty)
|
||||||
|
{
|
||||||
|
bo = cursor_empty;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (cursor_custom != BufferObject.Zero)
|
||||||
|
cursor_custom.Dispose();
|
||||||
|
cursor_custom = CreateCursor(window.BufferManager, cursor);
|
||||||
|
bo = cursor_custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we failed to create a proper cursor, try falling back
|
||||||
|
// to the empty cursor. We do not want to crash here!
|
||||||
|
if (bo == BufferObject.Zero)
|
||||||
|
{
|
||||||
|
bo = cursor_empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bo != BufferObject.Zero)
|
||||||
|
{
|
||||||
|
Drm.SetCursor(window.FD, window.DisplayDevice.Id,
|
||||||
|
bo.Handle, bo.Width, bo.Height, cursor.X, cursor.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static SurfaceFormat GetSurfaceFormat(IntPtr display, GraphicsMode mode)
|
||||||
|
{
|
||||||
|
// Use EGL 1.4 EGL_NATIVE_VISUAL_ID to retrieve
|
||||||
|
// the corresponding surface format. If that fails
|
||||||
|
// fall back to a manual algorithm.
|
||||||
|
int format;
|
||||||
|
Egl.GetConfigAttrib(display, mode.Index.Value,
|
||||||
|
Egl.NATIVE_VISUAL_ID, out format);
|
||||||
|
if ((SurfaceFormat)format != 0)
|
||||||
|
return (SurfaceFormat)format;
|
||||||
|
|
||||||
|
Debug.Print("[KMS] Failed to retrieve EGL visual from GBM surface. Error: {0}",
|
||||||
|
Egl.GetError());
|
||||||
|
Debug.Print("[KMS] Falling back to hardcoded formats.");
|
||||||
|
|
||||||
|
int r = mode.ColorFormat.Red;
|
||||||
|
int g = mode.ColorFormat.Green;
|
||||||
|
int b = mode.ColorFormat.Blue;
|
||||||
|
int a = mode.ColorFormat.Alpha;
|
||||||
|
|
||||||
|
if (mode.ColorFormat.IsIndexed)
|
||||||
|
return SurfaceFormat.C8;
|
||||||
|
if (r == 3 && g == 3 && b == 2 && a == 0)
|
||||||
|
return SurfaceFormat.RGB332;
|
||||||
|
if (r == 5 && g == 6 && b == 5 && a == 0)
|
||||||
|
return SurfaceFormat.RGB565;
|
||||||
|
if (r == 5 && g == 6 && b == 5 && a == 0)
|
||||||
|
return SurfaceFormat.RGB565;
|
||||||
|
if (r == 8 && g == 8 && b == 8 && a == 0)
|
||||||
|
return SurfaceFormat.RGB888;
|
||||||
|
if (r == 5 && g == 5 && b == 5 && a == 1)
|
||||||
|
return SurfaceFormat.RGBA5551;
|
||||||
|
if (r == 10 && g == 10 && b == 10 && a == 2)
|
||||||
|
return SurfaceFormat.RGBA1010102;
|
||||||
|
if (r == 4 && g == 4 && b == 4 && a == 4)
|
||||||
|
return SurfaceFormat.RGBA4444;
|
||||||
|
if (r == 8 && g == 8 && b == 8 && a == 8)
|
||||||
|
return SurfaceFormat.RGBA8888;
|
||||||
|
|
||||||
|
return SurfaceFormat.RGBA8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardState ProcessKeyboard(KeyboardState keyboard)
|
||||||
|
{
|
||||||
|
for (Key i = 0; i < Key.LastKey; i++)
|
||||||
|
{
|
||||||
|
if (keyboard[i])
|
||||||
|
{
|
||||||
|
OnKeyDown(i, previous_keyboard[i]);
|
||||||
|
// Todo: implement libxkb-common binding for text input
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keyboard[i] && previous_keyboard[i])
|
||||||
|
{
|
||||||
|
OnKeyUp(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseState ProcessMouse(MouseState mouse)
|
||||||
|
{
|
||||||
|
// Handle mouse buttons
|
||||||
|
for (MouseButton i = 0; i < MouseButton.LastButton; i++)
|
||||||
|
{
|
||||||
|
if (mouse[i] && !previous_mouse[i])
|
||||||
|
{
|
||||||
|
OnMouseDown(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mouse[i] && previous_mouse[i])
|
||||||
|
{
|
||||||
|
OnMouseUp(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle mouse movement
|
||||||
|
{
|
||||||
|
int x = mouse.X;
|
||||||
|
int y = mouse.Y;
|
||||||
|
|
||||||
|
// Make sure the mouse cannot leave the GameWindow when captured
|
||||||
|
if (!CursorVisible)
|
||||||
|
{
|
||||||
|
x = MathHelper.Clamp(mouse.X, Bounds.Left, Bounds.Right - 1);
|
||||||
|
y = MathHelper.Clamp(mouse.Y, Bounds.Top, Bounds.Bottom - 1);
|
||||||
|
if (x != mouse.X || y != mouse.Y)
|
||||||
|
{
|
||||||
|
Mouse.SetPosition(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x != previous_mouse.X || y != previous_mouse.Y)
|
||||||
|
{
|
||||||
|
OnMouseMove(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle mouse scroll
|
||||||
|
if (mouse.Scroll != previous_mouse.Scroll)
|
||||||
|
{
|
||||||
|
float dx = mouse.Scroll.X - previous_mouse.Scroll.X;
|
||||||
|
float dy = mouse.Scroll.Y - previous_mouse.Scroll.Y;
|
||||||
|
OnMouseWheel(dx, dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle mouse focus
|
||||||
|
// Note: focus follows mouse. Literally.
|
||||||
|
bool cursor_in = Bounds.Contains(new Point(mouse.X, mouse.Y));
|
||||||
|
if (!cursor_in && Focused)
|
||||||
|
{
|
||||||
|
OnMouseLeave(EventArgs.Empty);
|
||||||
|
SetFocus(false);
|
||||||
|
}
|
||||||
|
else if (cursor_in && !Focused)
|
||||||
|
{
|
||||||
|
OnMouseEnter(EventArgs.Empty);
|
||||||
|
SetFocus(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetFocus(bool focus)
|
||||||
|
{
|
||||||
|
if (is_focused != focus)
|
||||||
|
{
|
||||||
|
is_focused = focus;
|
||||||
|
OnFocusedChanged(EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region INativeWindow Members
|
||||||
|
|
||||||
|
public override void ProcessEvents()
|
||||||
|
{
|
||||||
|
// Note: there is no event-based keyboard/mouse input available.
|
||||||
|
// We will fake that by polling OpenTK.Input.
|
||||||
|
previous_keyboard = ProcessKeyboard(Keyboard.GetState());
|
||||||
|
previous_mouse = ProcessMouse(Mouse.GetCursorState());
|
||||||
|
|
||||||
|
base.ProcessEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Close()
|
||||||
|
{
|
||||||
|
exists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Point PointToClient(Point point)
|
||||||
|
{
|
||||||
|
var origin = Point.Empty;
|
||||||
|
var display = DisplayDevice.Default;
|
||||||
|
if (display != null)
|
||||||
|
{
|
||||||
|
origin = display.Bounds.Location;
|
||||||
|
}
|
||||||
|
var client = Location;
|
||||||
|
return new Point(point.X + client.X - origin.X, point.Y + client.Y - origin.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Point PointToScreen(Point point)
|
||||||
|
{
|
||||||
|
var origin = Point.Empty;
|
||||||
|
var display = DisplayDevice.Default;
|
||||||
|
if (display != null)
|
||||||
|
{
|
||||||
|
origin = display.Bounds.Location;
|
||||||
|
}
|
||||||
|
var client = Location;
|
||||||
|
return new Point(point.X + origin.X - client.X, point.Y + origin.Y - client.Y);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] Destroying window {0}.", window.Handle);
|
||||||
|
window.Dispose();
|
||||||
|
Gbm.DestroySurface(window.Handle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Print("[KMS] {0} leaked. Did you forget to call Dispose()?", GetType().FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Icon Icon
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (icon != value)
|
||||||
|
{
|
||||||
|
icon = value;
|
||||||
|
OnIconChanged(EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Title
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (title != value)
|
||||||
|
{
|
||||||
|
title = value;
|
||||||
|
OnTitleChanged(EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Focused
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return is_focused;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Visible
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Exists
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IWindowInfo WindowInfo
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override WindowState WindowState
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return WindowState.Fullscreen;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override WindowBorder WindowBorder
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return WindowBorder.Hidden;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Rectangle Bounds
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Size ClientSize
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return client_size;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CursorVisible
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return is_cursor_visible;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value && !is_cursor_visible)
|
||||||
|
{
|
||||||
|
SetCursor(cursor_current);
|
||||||
|
}
|
||||||
|
else if (!value && is_cursor_visible)
|
||||||
|
{
|
||||||
|
SetCursor(MouseCursor.Empty);
|
||||||
|
}
|
||||||
|
is_cursor_visible = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override MouseCursor Cursor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return cursor_current;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (cursor_current != value)
|
||||||
|
{
|
||||||
|
if (cursor_custom != BufferObject.Zero)
|
||||||
|
{
|
||||||
|
cursor_custom.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CursorVisible)
|
||||||
|
{
|
||||||
|
SetCursor(value);
|
||||||
|
}
|
||||||
|
cursor_current = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
56
Source/OpenTK/Platform/Linux/LinuxWindowInfo.cs
Normal file
56
Source/OpenTK/Platform/Linux/LinuxWindowInfo.cs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// LinuxWindowInfo.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos A. <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using OpenTK.Platform.Egl;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.Linux
|
||||||
|
{
|
||||||
|
class LinuxWindowInfo : EglWindowInfo
|
||||||
|
{
|
||||||
|
public int FD { get; private set; }
|
||||||
|
public LinuxDisplay DisplayDevice { get; private set; }
|
||||||
|
public IntPtr BufferManager { get; private set; }
|
||||||
|
|
||||||
|
public LinuxWindowInfo(IntPtr display, int fd, IntPtr gbm, LinuxDisplay display_device)
|
||||||
|
: base(IntPtr.Zero, display, IntPtr.Zero)
|
||||||
|
{
|
||||||
|
if (display_device == null)
|
||||||
|
throw new ArgumentNullException();
|
||||||
|
|
||||||
|
FD = fd;
|
||||||
|
BufferManager = gbm;
|
||||||
|
DisplayDevice = display_device;
|
||||||
|
// The window handle and surface handle must
|
||||||
|
// be filled in manually once they are known.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
readonly X11Mouse mouse = new X11Mouse();
|
readonly X11Mouse mouse = new X11Mouse();
|
||||||
readonly X11Keyboard keyboard = new X11Keyboard();
|
readonly X11Keyboard keyboard = new X11Keyboard();
|
||||||
readonly X11Joystick joystick = new X11Joystick();
|
readonly Linux.LinuxJoystick joystick = new Linux.LinuxJoystick();
|
||||||
readonly IGamePadDriver gamepad = new MappedGamePadDriver();
|
readonly IGamePadDriver gamepad = new MappedGamePadDriver();
|
||||||
|
|
||||||
internal X11Input()
|
internal X11Input()
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace OpenTK.Platform.X11
|
||||||
class XI2Input : IInputDriver2
|
class XI2Input : IInputDriver2
|
||||||
{
|
{
|
||||||
readonly XI2MouseKeyboard mouse_keyboard = new XI2MouseKeyboard();
|
readonly XI2MouseKeyboard mouse_keyboard = new XI2MouseKeyboard();
|
||||||
readonly X11Joystick joystick = new X11Joystick();
|
readonly Linux.LinuxJoystick joystick = new Linux.LinuxJoystick();
|
||||||
readonly IGamePadDriver gamepad = new MappedGamePadDriver();
|
readonly IGamePadDriver gamepad = new MappedGamePadDriver();
|
||||||
|
|
||||||
internal XI2Input()
|
internal XI2Input()
|
||||||
|
|
Loading…
Reference in a new issue