[Flags]
public enum KeyModifiers : byte
{
+ None = 0,
/// <summary>
/// The alt key modifier (option on Mac).
/// </summary>
/// <summary>
/// The shift key modifier.
/// </summary>
- Shift = 1 << 2
+ Shift = 1 << 2,
+
+ /// <summary>
+ /// The shift key modifier.
+ /// </summary>
+ AltGr = 1 << 3
}
}
using (Application drm = new Application ()) {
//drm.CrowInterface.LoadInterface (@"/mnt/data2/devel/crow/Tests/Interfaces/Divers/colorPicker.crow");
- drm.CrowInterface.LoadInterface (@"/mnt/data2/devel/crow/Tests/Interfaces/Divers/0.crow");
- drm.CrowInterface.LoadInterface (@"/mnt/data2/devel/crow/Tests/Interfaces/Divers/0.crow");
- drm.CrowInterface.LoadInterface (@"/mnt/data2/devel/crow/Tests/Interfaces/Divers/0.crow");
+ drm.CrowInterface.LoadInterface ("#testDrm.ui.menu.crow");
drm.CrowInterface.LoadInterface (@"/mnt/data2/devel/crow/Tests/Interfaces/Divers/0.crow");
//drm.CrowInterface.LoadInterface (@"/mnt/data2/devel/crow/Tests/Interfaces/GraphicObject/2.crow");
drm.Run ();
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
-using OpenTK.Platform.Egl;
using System.Runtime.InteropServices;
using System.Threading;
{
public class Application : IDisposable
{
- #region Crow interface
+ DRMContext drm;
public Interface CrowInterface;
public bool mouseIsInInterface = false;
Thread.Sleep (1);
}
}
- void initCrow (){
+
+
+ public Application(){
+ drm = new DRMContext();
CrowInterface = new Interface ();
+ drm.CrowInterface = CrowInterface;
Thread t = new Thread (interfaceThread);
t.IsBackground = true;
t.Start ();
- updateCrowInterfaceBounds ();
- }
- void updateCrowInterfaceBounds () {
- CrowInterface.ProcessResize (new Size (width, height));
- }
- #endregion
-
- volatile bool run = true;
-
- int fd_gpu = 0;
- int major, minor;
-
- IntPtr gbm_device, gbm_surface, egl_display, egl_config, egl_surface, egl_ctx;
-
- int r, g, b, a;
-
- BufferObject cursor_custom;
- BufferObject cursor_default;
- BufferObject cursor_empty;
-
-
- ModeInfo originalMode, currentMode;
- int width, height;
-
- public IntPtr Connector, Crtc, Encoder;
- unsafe ModeCrtc* saved_crtc;
- unsafe ModeConnector* pConnector { get { return (ModeConnector*)Connector; } }
- unsafe ModeCrtc* pCrtc { get { return (ModeCrtc*)Crtc; } }
- unsafe ModeEncoder* pEncoder { get { return (ModeEncoder*)Encoder; } }
-
- Cairo.EGLDevice cairoDev;
- Cairo.GLSurface cairoSurf;
-
- public Application(string gpu_path = "/dev/dri/card0"){
- DestroyFB = HandleDestroyFB;
- DestroyFBPtr = Marshal.GetFunctionPointerForDelegate(DestroyFB);
- PageFlip = HandlePageFlip;
- PageFlipPtr = Marshal.GetFunctionPointerForDelegate(PageFlip);
-
- gbm_device = IntPtr.Zero;
- egl_display = IntPtr.Zero;
-
- fd_gpu = Libc.open(gpu_path, OpenFlags.ReadWrite | OpenFlags.CloseOnExec);
- if (fd_gpu < 0)
- throw new NotSupportedException("[KMS] Failed to open gpu");
- Console.WriteLine("[KMS] GPU '{0}' opened as fd:{1}", gpu_path, fd_gpu);
-
- initDrm ();
-
- initGbm ();
-
- setNewMode ();
-
- initEgl ();
-
- initCairo ();
-
- initInput ();
-
- initCrow ();
- }
-
- #region init
- unsafe void initDrm(){
- ModeRes* resources = (ModeRes*)Drm.ModeGetResources(fd_gpu);
- if (resources == null)
- throw new NotSupportedException("[KMS] Drm.ModeGetResources failed.");
-
- ModeConnector* connector = null;
- for (int i = 0; i < resources->count_connectors; i++) {
- connector = (ModeConnector*)Drm.ModeGetConnector (fd_gpu, *(resources->connectors + i));
- if (connector != null) {
- if (connector->connection == ModeConnection.Connected && connector->count_encoders > 0)
- break;
- Drm.ModeFreeConnector ((IntPtr)connector);
- connector = null;
- }
- }
- if (connector == null)
- throw new NotSupportedException("[KMS] No connected screen found");
-
- Connector = (IntPtr)connector;
- Encoder = Drm.ModeGetEncoder (fd_gpu, connector->encoder_id);
- Crtc = Drm.ModeGetCrtc(fd_gpu, pEncoder->crtc_id);
- saved_crtc = (ModeCrtc*) Drm.ModeGetCrtc (fd_gpu, pEncoder->crtc_id);
-
- originalMode = pCrtc->mode;
- width = 1600;
- height = 900;
-
-// Console.WriteLine ("[DRM]: current mode = {0} X {1} at {2} Hz", width, height, currentMode.vrefresh);
- }
- void initGbm (){
- gbm_device = Gbm.CreateDevice(fd_gpu);
- if (gbm_device == IntPtr.Zero)
- throw new NotSupportedException("[GBM] Failed to create GBM device");
-
- gbm_surface = Gbm.CreateSurface(gbm_device, width, height, SurfaceFormat.ARGB8888, SurfaceFlags.Rendering | SurfaceFlags.Scanout);
- if (gbm_surface == IntPtr.Zero)
- throw new NotSupportedException("[GBM] Failed to create GBM surface for rendering");
- }
-
- void setNewMode (){
- //118.25 1600 1696 1856 2112 900 903 908 934 -hsync +vsync
- //currentMode = pCrtc->mode;
- currentMode.clock = 118250;
- currentMode.hdisplay = 1600;
- currentMode.hsync_start = 1696;
- currentMode.hsync_end = 1856;
- currentMode.htotal = 2112;
- currentMode.vdisplay = 900;
- currentMode.vsync_start = 903;
- currentMode.vsync_end = 908;
- currentMode.vtotal = 934;
- currentMode.flags |= (uint)ModeFlags.NHSYNC;
- currentMode.flags |= (uint)ModeFlags.PVSYNC;
- // byte[] tmp = System.Text.Encoding.ASCII.GetBytes ("1600x900");
- // for (int i = 0; i < tmp.Length; i++) {
- // currentMode.name [i] = (sbyte)tmp [i];
- // }
-
- unsafe
- {
- pCrtc->mode = currentMode;
- ModeInfo* mode = (ModeInfo*)Marshal.AllocHGlobal (sizeof(ModeInfo));// pConnector->modes;
- *mode = currentMode;
- int connector_id = pConnector->connector_id;
- int crtc_id = pEncoder->crtc_id;
- BufferObject bo = Gbm.CreateBuffer(
- gbm_device, width, height, SurfaceFormat.ARGB8888, SurfaceFlags.Scanout);
- int nfb = getFbFromBo (bo);
- int ret = Drm.ModeSetCrtc (fd_gpu, crtc_id, nfb, 0, 0, &connector_id, 1, mode);
-
- if (ret != 0)
- Console.WriteLine("[KMS] Drm.ModeSetCrtc failed. Error: " + ret);
- }
-// width = currentMode.hdisplay;
-// height = currentMode.vdisplay;
- }
-
- unsafe void initEgl () {
- IntPtr[] configs = new IntPtr[1];
- int[] contextAttrib = new int[] {
- Egl.CONTEXT_CLIENT_VERSION, 2,
- Egl.NONE
- };
- int[] attribList = new int[]
- {
- Egl.SURFACE_TYPE, Egl.WINDOW_BIT,
- Egl.RENDERABLE_TYPE, Egl.OPENGL_BIT,
- Egl.RED_SIZE, 1,
- Egl.GREEN_SIZE, 1,
- Egl.BLUE_SIZE, 1,
- Egl.ALPHA_SIZE, 0,
-
- //Egl.DEPTH_SIZE, 24,
- //Egl.STENCIL_SIZE, 0,
-
- //Egl.SAMPLE_BUFFERS, 2,
- //Egl.SAMPLES, 0,
- Egl.NONE
- };
- int num_configs;
-
- egl_display = Egl.GetDisplay(gbm_device);
- if (egl_display == IntPtr.Zero)
- throw new NotSupportedException("[KMS] Failed to create EGL display");
- Console.WriteLine("[EGL] EGL display {0:x} created successfully", egl_display);
-
- if (!Egl.Initialize(egl_display, out major, out minor))
- throw new NotSupportedException("[EGL] Failed to initialize EGL display. Error code: " + Egl.GetError());
-
- if (!Egl.BindAPI (RenderApi.GL))
- throw new NotSupportedException("[EGL] Failed to bind EGL Api: " + Egl.GetError());
-
- Console.WriteLine ("[EGL] Version: " + Marshal.PtrToStringAuto (Egl.QueryString (egl_display, Egl.VERSION)));
- Console.WriteLine ("[EGL] Vendor: " + Marshal.PtrToStringAuto (Egl.QueryString (egl_display, Egl.VENDOR)));
- Console.WriteLine ("[EGL] Extensions: " + Marshal.PtrToStringAuto (Egl.QueryString (egl_display, Egl.EXTENSIONS)));
- Console.WriteLine ("[EGL] Extensions: " + Marshal.PtrToStringAuto (Egl.QueryString(IntPtr.Zero, Egl.EXTENSIONS)));
-
- if (!Egl.ChooseConfig(egl_display, attribList, configs, configs.Length, out num_configs) || num_configs == 0)
- throw new NotSupportedException(String.Format("Failed to retrieve GraphicsMode, error {0}", Egl.GetError()));
-
-
- // See what we really got
- int d, s, sample_buffers, samples;
- IntPtr active_config = configs[0];
- Egl.GetConfigAttrib(egl_display, active_config, Egl.RED_SIZE, out r);
- Egl.GetConfigAttrib(egl_display, active_config, Egl.GREEN_SIZE, out g);
- Egl.GetConfigAttrib(egl_display, active_config, Egl.BLUE_SIZE, out b);
- Egl.GetConfigAttrib(egl_display, active_config, Egl.ALPHA_SIZE, out a);
- //Egl.GetConfigAttrib(egl_display, active_config, Egl.DEPTH_SIZE, out d);
- //Egl.GetConfigAttrib(egl_display, active_config, Egl.STENCIL_SIZE, out s);
- //Egl.GetConfigAttrib(egl_display, active_config, Egl.SAMPLE_BUFFERS, out sample_buffers);
- //Egl.GetConfigAttrib(egl_display, active_config, Egl.SAMPLES, out samples);
-// Console.WriteLine ("EGL context: {0},{1},{2},{3} depth={4} stencil={5} samples={6} sample buffers={7}",
-// r, g, b, a, d, s, samples, sample_buffers);
- egl_config = active_config;
-
- egl_ctx = Egl.CreateContext(egl_display, egl_config, IntPtr.Zero, contextAttrib);
-
- egl_surface = Egl.CreateWindowSurface(egl_display, egl_config, gbm_surface, IntPtr.Zero);
-
- if (egl_surface==IntPtr.Zero)
- throw new NotSupportedException(String.Format("[EGL] Failed to create window surface, error {0}.", Egl.GetError()));
-
- if (!Egl.MakeCurrent(egl_display, egl_surface, egl_surface, egl_ctx))
- throw new NotSupportedException(string.Format("Failed to make context {0} current. Error: {1}", gbm_surface, Egl.GetError()));
-
- cursor_default = CreateCursor(gbm_device, Cursors.Default);
- cursor_empty = CreateCursor(gbm_device, Cursors.Empty);
-
- SetCursor(Cursors.Default);
- unsafe {
- Drm.MoveCursor (fd_gpu, pEncoder->crtc_id, 0, 0);
- }
- }
-
- void initCairo (){
- cairoDev = new Cairo.EGLDevice (egl_display, egl_ctx);
-
- cairoSurf = new Cairo.GLSurface (cairoDev, egl_surface, width, height);
- //cairoSurf = new Cairo.EGLSurface (cairoDev, egl_surface, 1600, 900);
-
- cairoDev.SetThreadAware (false);
-
- if (cairoDev.Acquire () != Cairo.Status.Success)
- Console.WriteLine ("[Cairo]: Failed to acquire egl device.");
- }
- #endregion
-
- #region cursor
-
- 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(gbm_device, 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)
- {
- unsafe {
- Console.WriteLine ("Cursor ({0},{1})", cursor.X, cursor.Y);
- Drm.SetCursor (fd_gpu, pEncoder->crtc_id,
- bo.Handle, bo.Width, bo.Height, cursor.X, cursor.Y);
- }
- }
- }
- #endregion
-
- int getFbFromBo (BufferObject bo){
- int width = bo.Width;
- int height = bo.Height;
- int bpp = 32;
- int depth = 24;
- int stride = bo.Stride;
- int hndBO = bo.Handle;
-
- int fb;
- int ret = Drm.ModeAddFB (fd_gpu, width, height,(byte)depth, (byte)bpp, stride, hndBO, out fb);
- if (ret != 0)
- throw new Exception ("[DRM]: ModeAddFB failed.");
- bo.SetUserData ((IntPtr)fb, DestroyFBPtr);
- return fb;
- }
-
- public void Run(){
- BufferObject bo;
- int fb;
-
- PollFD fds = new PollFD();
- fds.fd = fd_gpu;
- fds.events = PollFlags.In;
-
- EventContext evctx = new EventContext();
- evctx.version = EventContext.Version;
- evctx.page_flip_handler = PageFlipPtr;
-
- int timeout = -1;//block ? -1 : 0;
-
- using (Cairo.Context ctx = new Cairo.Context (cairoSurf)) {
- ctx.Rectangle (0, 0, width, height);
- ctx.SetSourceRGB (0, 0, 0);
- ctx.Fill ();
- }
-
- cairoSurf.SwapBuffers ();
-
- bo = Gbm.LockFrontBuffer (gbm_surface);
- fb = getFbFromBo (bo);
-
- //SetScanoutRegion (fb);
-
- while (run){
- BufferObject next_bo;
- bool update = false;
-
- if (updateMousePos) {
- lock (Sync) {
- updateMousePos = false;
- unsafe {
- Drm.MoveCursor (fd_gpu, pEncoder->crtc_id, MouseX-8, MouseY-4);
- }
- }
- }
-
- if (Monitor.TryEnter (CrowInterface.RenderMutex)) {
- if (CrowInterface.IsDirty) {
- CrowInterface.IsDirty = false;
- update = true;
- using (Cairo.Context ctx = new Cairo.Context (cairoSurf)) {
- using (Cairo.Surface d = new Cairo.ImageSurface (CrowInterface.dirtyBmp, Cairo.Format.Argb32,
- width, height, width * 4)) {
- ctx.SetSourceSurface (d, 0, 0);
- ctx.Operator = Cairo.Operator.Source;
- ctx.Paint ();
- }
- }
- }
- Monitor.Exit (CrowInterface.RenderMutex);
- }
-
- if (!update)
- continue;
- update = false;
-
- cairoSurf.Flush ();
- cairoSurf.SwapBuffers ();
-
- if (Gbm.HasFreeBuffers (gbm_surface) == 0)
- throw new Exception ("[GBM]: Out of free buffers.");
-
- next_bo = Gbm.LockFrontBuffer (gbm_surface);
- if (next_bo == BufferObject.Zero)
- throw new Exception ("[GBM]: Failed to lock front buffer.");
+ CrowInterface.ProcessResize (new Size (drm.width, drm.height));
+ drm.updateCursor (XCursor.Default);
- fb = getFbFromBo (next_bo);
-
- unsafe{
- int is_flip_queued = 1;
-
- while (Drm.ModePageFlip (fd_gpu, pEncoder->crtc_id, fb, PageFlipFlags.FlipEvent, ref is_flip_queued) < 0) {
- //Console.WriteLine ("[DRM] Failed to enqueue framebuffer flip.");
- continue;
- }
-
- while (is_flip_queued != 0)
- {
- 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_gpu, ref evctx);
- else
- break;
- }
- if (is_flip_queued != 0)
- Console.WriteLine ("flip canceled");
-
- Gbm.ReleaseBuffer (gbm_surface, bo);
- //Drm.ModeRmFB(fd_gpu, fb);
-
- bo = next_bo;
- next_bo = BufferObject.Zero;
-
- }
- }
- }
-
- #region rendering
-
-
-
- // 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().
- int swap_interval=0;
-
- readonly IntPtr PageFlipPtr;
- readonly PageFlipCallback PageFlip;
-
- readonly IntPtr DestroyFBPtr;
- readonly DestroyUserDataCallback DestroyFB;
-
- void HandlePageFlip(int fd, int sequence, int tv_sec, int tv_usec, ref int user_data)
- {
- user_data = 0;
+ CrowInterface.MouseCursorChanged += CrowInterface_MouseCursorChanged;
}
-
- void HandleDestroyFB(BufferObject bo, IntPtr data)
+ void CrowInterface_MouseCursorChanged (object sender, MouseCursorChangedEventArgs e)
{
- Console.WriteLine ("DestroyFB");
- IntPtr gbm = bo.Device;
- int fb = data.ToInt32();
-
- if (fb != 0)
- Drm.ModeRmFB(fd_gpu, fb);
+ drm.updateCursor (e.NewCursor);
}
- void SetScanoutRegion(int buffer)
- {
- unsafe
- {
- ModeInfo* mode = pConnector->modes;
- int connector_id = pConnector->connector_id;
- int crtc_id = pEncoder->crtc_id;
-
- int ret = Drm.ModeSetCrtc (fd_gpu, crtc_id, buffer, 0, 0, &connector_id, 1, mode);
-
- if (ret != 0)
- Debug.Print("[KMS] Drm.ModeSetCrtc{0}, {1}, {2} failed. Error: {3}",
- fd_gpu, crtc_id, buffer, ret);
- Console.WriteLine ("scanout region set: {0}x{1}", mode->hdisplay, mode->vdisplay);
- }
+ public void Run (){
+ drm.Run ();
}
- #endregion
#region IDisposable implementation
public void Dispose ()
{
- cairoDev.Release ();
- cairoSurf.Dispose ();
- cairoDev.Dispose ();
-
-// if (fb != 0)
-// Drm.ModeRmFB (fd_gpu, fb);
-// if (bo != BufferObject.Zero)
-// Gbm.ReleaseBuffer (gbm_surface, bo);
-// if (next_fb != 0)
-// Drm.ModeRmFB (fd_gpu, next_fb);
-// if (next_bo != BufferObject.Zero)
-// Gbm.ReleaseBuffer (gbm_surface, next_bo);
-
- if (Egl.GetCurrentContext () == egl_ctx) {
- Console.WriteLine ("destroying context");
- Egl.DestroyContext (egl_display, egl_ctx);
- }else
- Console.WriteLine ("not current");
-
- cairoDev.Dispose ();
-
- unsafe{
- Drm.ModeSetCrtc (fd_gpu, saved_crtc->crtc_id, saved_crtc->buffer_id,
- saved_crtc->x, saved_crtc->y, &pConnector->connector_id, 1, &saved_crtc->mode);
- Drm.ModeFreeCrtc ((IntPtr)saved_crtc);
- }
-
- Drm.ModeFreeCrtc (Crtc);
- Drm.ModeFreeConnector(Connector);
- Drm.ModeFreeEncoder(Encoder);
- Libc.close(fd_gpu);
- }
- #endregion
-
- #region tests
- unsafe void dumpDrmResources(){
- ModeRes* resources = (ModeRes*)Drm.ModeGetResources(fd_gpu);
- if (resources == null)
- throw new NotSupportedException("[KMS] Drm.ModeGetResources failed.");
- Console.WriteLine("[KMS] DRM found {0} connectors", resources->count_connectors);
-
- Console.WriteLine ("[ENCODERS]");
- for (int j = 0; j < resources->count_encoders; j++) {
- ModeEncoder* e = (ModeEncoder*)Drm.ModeGetEncoder(fd_gpu, *(resources->encoders + j));
-
- if (e == null)
- continue;
- Console.WriteLine ("{0}\t{1}\t{2}",e->encoder_id, e->encoder_type, e->crtc_id);
-
- Drm.ModeFreeEncoder((IntPtr)e);
- }
-
- Console.WriteLine ("\n[CONNECTORS]");
- ModeConnector* connector = null;
- for (int i = 0; i < resources->count_connectors; i++)
- {
- connector = (ModeConnector*)Drm.ModeGetConnector(fd_gpu, *(resources->connectors + i));
- if (connector != null)
- {
- Console.WriteLine ("{0}\t{1}\t{2}\t{3}",
- connector->connector_id,
- connector->connector_type,
- connector->connection,
- connector->encoder_id);
-
- for (int j = 0; j < connector->count_modes; j++) {
- ModeInfo* mode = connector->modes + j;
- if (mode == null)
- continue;
- Console.WriteLine ("\t{0,-20}{1,5}{2,5}{3,4} hz",
- new string(mode->name),
- mode->hdisplay,
- mode->vdisplay,
- mode->vrefresh);
- }
- Drm.ModeFreeConnector((IntPtr)connector);
- connector = null;
- }
- }
- }
- #endregion
-
- #region INPUT
- Thread input_thread;
- long exit;
-
- static readonly object Sync = new object();
- static readonly Crow.Key[] KeyMap = Evdev.KeyMap;
- static long DeviceFDCount;
-
- IntPtr udev;
- IntPtr input_context;
-
- int input_fd = 0;
-
- InputInterface input_interface = new InputInterface(
- OpenRestricted, CloseRestricted);
- 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 initInput (){
- Semaphore ready = new Semaphore(0, 1);
- input_thread = new Thread (InputThreadLoop);
- input_thread.IsBackground = true;
- input_thread.Start(ready);
- }
-
- 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 = input_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;
-
- 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 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);
- 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);
-
- string seat_id = "seat0";
- int seat_assignment = LibInput.AssignSeat(input_context, seat_id);
- if (seat_assignment == -1)
- {
- Debug.Print("[Input] LibInput.AssignSeat({0:x}) = {1} failed.", input_context, seat_id);
- Interlocked.Increment(ref exit);
- return;
- }
- Debug.Print("[Input] LibInput.AssignSeat({0:x}) = {1}", input_context, seat_id);
-
- input_fd = LibInput.GetFD(input_context);
- if (input_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, input_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:
- run = false;
- //HandleKeyboard(GetKeyboard(device), LibInput.GetKeyboardEvent(pevent));
- break;
-//
-// case InputEventType.PointerAxis:
-// HandlePointerAxis(GetMouse(device), LibInput.GetPointerEvent(pevent));
-// break;
-//
- case InputEventType.PointerButton:
- handlePointerButton (LibInput.GetPointerEvent(pevent));
- break;
-
- case InputEventType.PointerMotion:
- handlePointerMotion (LibInput.GetPointerEvent(pevent));
- break;
-
-// case InputEventType.PointerMotionAbsolute:
-// HandlePointerMotionAbsolute(GetMouse(device), LibInput.GetPointerEvent(pevent));
-// break;
- }
- }
-
- LibInput.DestroyEvent(pevent);
- }
- }
- int MouseX = 0, MouseY = 0;
- volatile bool updateMousePos = true;
-
- int roundDelta (double d){
- return d > 0 ? (int)Math.Ceiling(d) : (int)Math.Floor (d);
- }
-
- void handlePointerMotion(PointerEvent e)
- {
- MouseX += roundDelta (e.DeltaX);
- MouseY += roundDelta (e.DeltaY);
-
- Rectangle bounds = CrowInterface.ClientRectangle;
- if (MouseX < bounds.Left)
- MouseX = bounds.Left;
- else if (MouseX > bounds.Right)
- MouseX = bounds.Right;
-
- if (MouseY < bounds.Top)
- MouseY = bounds.Top;
- else if (MouseY > bounds.Bottom)
- MouseY = bounds.Bottom;
-
- CrowInterface.ProcessMouseMove (MouseX, MouseY);
-
- updateMousePos = true;
- }
- void handlePointerButton (PointerEvent e)
- {
- int but = 0;
- switch (e.Button) {
- case EvdevButton.LEFT:
- but = 0;
- break;
- case EvdevButton.MIDDLE:
- but = 1;
- break;
- case EvdevButton.RIGHT:
- but = 2;
- break;
- }
- if (e.ButtonState == OpenTK.Platform.Linux.ButtonState.Pressed)
- CrowInterface.ProcessMouseButtonDown (but);
- else
- CrowInterface.ProcessMouseButtonUp (but);
+ drm.Dispose ();
}
#endregion
}
using System.Diagnostics;
using System.Reflection;
-namespace OpenTK
+namespace Crow
{
#region BlittableValueType<T>
--- /dev/null
+//
+// DRMDevice.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// 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.
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading;
+using OpenTK;
+using OpenTK.Platform.Linux;
+using System.IO.Compression;
+
+namespace Crow.Linux
+{
+
+ internal class DRMContext : IDisposable
+ {
+ Stopwatch drmTimeOut;
+
+ public Interface CrowInterface;
+ int fd_gpu = 0;
+
+ IntPtr gbm_device, gbm_surface, egl_display, egl_config, egl_surface, egl_ctx;
+
+ ModeInfo originalMode, currentMode;
+ public int width, height;
+
+ volatile bool run = true;
+
+ public IntPtr Connector, Crtc, Encoder;
+ unsafe ModeCrtc* saved_crtc;
+ unsafe ModeConnector* pConnector { get { return (ModeConnector*)Connector; } }
+ unsafe ModeCrtc* pCrtc { get { return (ModeCrtc*)Crtc; } }
+ unsafe ModeEncoder* pEncoder { get { return (ModeEncoder*)Encoder; } }
+
+ Cairo.EGLDevice cairoDev;
+ Cairo.GLSurface cairoSurf;
+
+ Dictionary<KeyModifiers, string[]> keymap;
+
+ int previousVT = 0, appVT;
+
+ public DRMContext(string gpu_path = "/dev/dri/card0"){
+ drmTimeOut = new Stopwatch();
+
+ DestroyFB = HandleDestroyFB;
+ DestroyFBPtr = Marshal.GetFunctionPointerForDelegate(DestroyFB);
+ PageFlip = HandlePageFlip;
+ PageFlipPtr = Marshal.GetFunctionPointerForDelegate(PageFlip);
+
+ gbm_device = IntPtr.Zero;
+ egl_display = IntPtr.Zero;
+
+ fd_gpu = Libc.open(gpu_path, OpenFlags.ReadWrite | OpenFlags.CloseOnExec);
+ if (fd_gpu < 0)
+ throw new NotSupportedException("[KMS] Failed to open gpu");
+ Console.WriteLine("[KMS] GPU '{0}' opened as fd:{1}", gpu_path, fd_gpu);
+
+ initDrm ();
+
+ initGbm ();
+
+ setNewMode ();
+
+ initEgl ();
+
+ initCairo ();
+
+ initInput ();
+ }
+
+ #region init
+ unsafe void initDrm(){
+ ModeRes* resources = (ModeRes*)Drm.ModeGetResources(fd_gpu);
+ if (resources == null)
+ throw new NotSupportedException("[KMS] Drm.ModeGetResources failed.");
+
+ ModeConnector* connector = null;
+ for (int i = 0; i < resources->count_connectors; i++) {
+ connector = (ModeConnector*)Drm.ModeGetConnector (fd_gpu, *(resources->connectors + i));
+ if (connector != null) {
+ if (connector->connection == ModeConnection.Connected && connector->count_encoders > 0)
+ break;
+ Drm.ModeFreeConnector ((IntPtr)connector);
+ connector = null;
+ }
+ }
+ if (connector == null)
+ throw new NotSupportedException("[KMS] No connected screen found");
+
+ Connector = (IntPtr)connector;
+ Encoder = Drm.ModeGetEncoder (fd_gpu, connector->encoder_id);
+ Crtc = Drm.ModeGetCrtc(fd_gpu, pEncoder->crtc_id);
+ saved_crtc = (ModeCrtc*) Drm.ModeGetCrtc (fd_gpu, pEncoder->crtc_id);
+
+ originalMode = pCrtc->mode;
+ width = 1600;
+ height = 900;
+
+ // Console.WriteLine ("[DRM]: current mode = {0} X {1} at {2} Hz", width, height, currentMode.vrefresh);
+ }
+ void initGbm (){
+ gbm_device = Gbm.CreateDevice(fd_gpu);
+ if (gbm_device == IntPtr.Zero)
+ throw new NotSupportedException("[GBM] Failed to create GBM device");
+
+ gbm_surface = Gbm.CreateSurface(gbm_device, width, height, SurfaceFormat.ARGB8888, SurfaceFlags.Rendering | SurfaceFlags.Scanout);
+ if (gbm_surface == IntPtr.Zero)
+ throw new NotSupportedException("[GBM] Failed to create GBM surface for rendering");
+ }
+
+ void setNewMode (){
+ //118.25 1600 1696 1856 2112 900 903 908 934 -hsync +vsync
+ //currentMode = pCrtc->mode;
+ currentMode.clock = 118250;
+ currentMode.hdisplay = 1600;
+ currentMode.hsync_start = 1696;
+ currentMode.hsync_end = 1856;
+ currentMode.htotal = 2112;
+ currentMode.vdisplay = 900;
+ currentMode.vsync_start = 903;
+ currentMode.vsync_end = 908;
+ currentMode.vtotal = 934;
+ currentMode.flags |= (uint)ModeFlags.NHSYNC;
+ currentMode.flags |= (uint)ModeFlags.PVSYNC;
+ // byte[] tmp = System.Text.Encoding.ASCII.GetBytes ("1600x900");
+ // for (int i = 0; i < tmp.Length; i++) {
+ // currentMode.name [i] = (sbyte)tmp [i];
+ // }
+
+ unsafe
+ {
+ pCrtc->mode = currentMode;
+ ModeInfo* mode = (ModeInfo*)Marshal.AllocHGlobal (sizeof(ModeInfo));// pConnector->modes;
+ *mode = currentMode;
+ int connector_id = pConnector->connector_id;
+ int crtc_id = pEncoder->crtc_id;
+ BufferObject bo = Gbm.CreateBuffer(
+ gbm_device, width, height, SurfaceFormat.ARGB8888, SurfaceFlags.Scanout);
+ int nfb = getFbFromBo (bo);
+ int ret = Drm.ModeSetCrtc (fd_gpu, crtc_id, nfb, 0, 0, &connector_id, 1, mode);
+
+ if (ret != 0)
+ Console.WriteLine("[KMS] Drm.ModeSetCrtc failed. Error: " + ret);
+ }
+ // width = currentMode.hdisplay;
+ // height = currentMode.vdisplay;
+ }
+
+ unsafe void initEgl () {
+ int major, minor;
+ IntPtr[] configs = new IntPtr[1];
+ int[] contextAttrib = new int[] {
+ Egl.CONTEXT_CLIENT_VERSION, 2,
+ Egl.NONE
+ };
+ int[] attribList = new int[]
+ {
+ Egl.SURFACE_TYPE, Egl.WINDOW_BIT,
+ Egl.RENDERABLE_TYPE, Egl.OPENGL_BIT,
+ Egl.RED_SIZE, 1,
+ Egl.GREEN_SIZE, 1,
+ Egl.BLUE_SIZE, 1,
+ Egl.ALPHA_SIZE, 0,
+ //Egl.DEPTH_SIZE, 24,
+ //Egl.STENCIL_SIZE, 0,
+ //Egl.SAMPLE_BUFFERS, 2,
+ //Egl.SAMPLES, 0,
+ Egl.NONE
+ };
+ int num_configs;
+
+ egl_display = Egl.GetDisplay(gbm_device);
+
+ if (egl_display == IntPtr.Zero)
+ throw new NotSupportedException("[KMS] Failed to create EGL display");
+ Console.WriteLine("[EGL] EGL display {0:x} created successfully", egl_display);
+
+ if (!Egl.Initialize(egl_display, out major, out minor))
+ throw new NotSupportedException("[EGL] Failed to initialize EGL display. Error code: " + Egl.GetError());
+
+ if (!Egl.BindAPI (RenderApi.GL))
+ throw new NotSupportedException("[EGL] Failed to bind EGL Api: " + Egl.GetError());
+
+ Console.WriteLine ("[EGL] Version: " + Marshal.PtrToStringAuto (Egl.QueryString (egl_display, Egl.VERSION)));
+ Console.WriteLine ("[EGL] Vendor: " + Marshal.PtrToStringAuto (Egl.QueryString (egl_display, Egl.VENDOR)));
+ Console.WriteLine ("[EGL] Extensions: " + Marshal.PtrToStringAuto (Egl.QueryString (egl_display, Egl.EXTENSIONS)));
+ Console.WriteLine (" " + Marshal.PtrToStringAuto (Egl.QueryString(IntPtr.Zero, Egl.EXTENSIONS)));
+
+ if (!Egl.ChooseConfig(egl_display, attribList, configs, configs.Length, out num_configs) || num_configs == 0)
+ throw new NotSupportedException(String.Format("Failed to retrieve GraphicsMode, error {0}", Egl.GetError()));
+
+ egl_config = configs[0];
+ egl_ctx = Egl.CreateContext(egl_display, egl_config, IntPtr.Zero, contextAttrib);
+ egl_surface = Egl.CreateWindowSurface(egl_display, egl_config, gbm_surface, IntPtr.Zero);
+
+ if (egl_surface==IntPtr.Zero)
+ throw new NotSupportedException(String.Format("[EGL] Failed to create window surface, error {0}.", Egl.GetError()));
+
+ // See what we really got
+ int r, g, b, a, d, s, sample_buffers, samples;
+ IntPtr active_config = configs[0];
+ Egl.GetConfigAttrib(egl_display, active_config, Egl.RED_SIZE, out r);
+ Egl.GetConfigAttrib(egl_display, active_config, Egl.GREEN_SIZE, out g);
+ Egl.GetConfigAttrib(egl_display, active_config, Egl.BLUE_SIZE, out b);
+ Egl.GetConfigAttrib(egl_display, active_config, Egl.ALPHA_SIZE, out a);
+ Egl.GetConfigAttrib(egl_display, active_config, Egl.DEPTH_SIZE, out d);
+ Egl.GetConfigAttrib(egl_display, active_config, Egl.STENCIL_SIZE, out s);
+ Egl.GetConfigAttrib(egl_display, active_config, Egl.SAMPLE_BUFFERS, out sample_buffers);
+ Egl.GetConfigAttrib(egl_display, active_config, Egl.SAMPLES, out samples);
+ Console.WriteLine ("EGL context: {0},{1},{2},{3} depth={4} stencil={5} samples={6} sample buffers={7}",
+ r, g, b, a, d, s, samples, sample_buffers);
+
+
+ if (!Egl.MakeCurrent(egl_display, egl_surface, egl_surface, egl_ctx))
+ throw new NotSupportedException(string.Format("Failed to make context {0} current. Error: {1}", gbm_surface, Egl.GetError()));
+ }
+
+ void initCairo (){
+ cairoDev = new Cairo.EGLDevice (egl_display, egl_ctx);
+
+ cairoSurf = new Cairo.GLSurface (cairoDev, egl_surface, width, height);
+ //cairoSurf = new Cairo.EGLSurface (cairoDev, egl_surface, 1600, 900);
+
+ cairoDev.SetThreadAware (false);
+
+ if (cairoDev.Acquire () != Cairo.Status.Success)
+ Console.WriteLine ("[Cairo]: Failed to acquire egl device.");
+ }
+ #endregion
+
+ #region cursor
+ BufferObject boMouseCursor = BufferObject.Zero;
+
+ internal void updateCursor (XCursor cursor) {
+ uint width = 64, height = 64;
+ if (cursor.Width > width || cursor.Height > height){
+ Debug.Print("[DRM] Cursor size {0}x{1} unsupported. Maximum is 64x64.",
+ cursor.Width, cursor.Height);
+ return;
+ }
+
+ if (boMouseCursor != BufferObject.Zero)
+ Gbm.DestroyBuffer (boMouseCursor);
+
+ boMouseCursor = Gbm.CreateBuffer (gbm_device, (int)width, (int)height,
+ SurfaceFormat.ARGB8888, SurfaceFlags.Cursor64x64 | SurfaceFlags.Write);
+
+ if (boMouseCursor == BufferObject.Zero)
+ {
+ Debug.Print("[DRM] Failed to create buffer for mouse cursor.");
+ return;
+ }
+
+ // Copy cursor.Data into a new buffer of the correct size
+ byte[] cursor_data = new byte[width * height * 4];
+ for (uint y = 0; y < cursor.Height; y++)
+ {
+ uint dst_offset = y * width * 4;
+ uint src_offset = y * cursor.Width * 4;
+ uint src_length = cursor.Width * 4;
+ Array.Copy(
+ cursor.data, src_offset,
+ cursor_data, dst_offset,
+ src_length);
+ }
+
+ boMouseCursor.Write(cursor_data);
+
+ unsafe {
+ Drm.SetCursor (fd_gpu, pEncoder->crtc_id,
+ boMouseCursor.Handle, boMouseCursor.Width, boMouseCursor.Height, (int)cursor.Xhot, (int)cursor.Yhot);
+ }
+ }
+ #endregion
+
+ int getFbFromBo (BufferObject bo){
+ int width = bo.Width;
+ int height = bo.Height;
+ int bpp = 32;
+ int depth = 24;
+ int stride = bo.Stride;
+ int hndBO = bo.Handle;
+
+ int fb;
+ int ret = Drm.ModeAddFB (fd_gpu, width, height,(byte)depth, (byte)bpp, stride, hndBO, out fb);
+ if (ret != 0)
+ throw new Exception ("[DRM]: ModeAddFB failed.");
+ bo.SetUserData ((IntPtr)fb, DestroyFBPtr);
+ return fb;
+ }
+
+ public void Run(){
+ BufferObject bo;
+ int fb;
+
+ PollFD fds = new PollFD();
+ fds.fd = fd_gpu;
+ fds.events = PollFlags.In;
+
+ EventContext evctx = new EventContext();
+ evctx.version = EventContext.Version;
+ evctx.page_flip_handler = PageFlipPtr;
+
+ int timeout = -1;//block ? -1 : 0;
+
+ using (Cairo.Context ctx = new Cairo.Context (cairoSurf)) {
+ ctx.Rectangle (0, 0, width, height);
+ ctx.SetSourceRGB (0, 0, 0);
+ ctx.Fill ();
+ }
+
+ cairoSurf.SwapBuffers ();
+
+ bo = Gbm.LockFrontBuffer (gbm_surface);
+ fb = getFbFromBo (bo);
+
+ SetScanoutRegion (fb);
+ drmTimeOut.Restart();
+
+ while (run && drmTimeOut.ElapsedMilliseconds < 10000){
+ BufferObject next_bo;
+ bool update = false;
+
+ if (updateMousePos) {
+ lock (Sync) {
+ updateMousePos = false;
+ unsafe {
+ Drm.MoveCursor (fd_gpu, pEncoder->crtc_id, MouseX-8, MouseY-4);
+ }
+ }
+ }
+
+ if (Monitor.TryEnter (CrowInterface.RenderMutex)) {
+ if (CrowInterface.IsDirty) {
+ CrowInterface.IsDirty = false;
+ update = true;
+ using (Cairo.Context ctx = new Cairo.Context (cairoSurf)) {
+ using (Cairo.Surface d = new Cairo.ImageSurface (CrowInterface.dirtyBmp, Cairo.Format.Argb32,
+ width, height, width * 4)) {
+ ctx.SetSourceSurface (d, 0, 0);
+ ctx.Operator = Cairo.Operator.Source;
+ ctx.Paint ();
+ }
+ }
+ }
+ Monitor.Exit (CrowInterface.RenderMutex);
+ }
+
+ if (!update)
+ continue;
+ update = false;
+
+ cairoSurf.Flush ();
+ cairoSurf.SwapBuffers ();
+
+ if (Gbm.HasFreeBuffers (gbm_surface) == 0)
+ throw new Exception ("[GBM]: Out of free buffers.");
+
+ next_bo = Gbm.LockFrontBuffer (gbm_surface);
+ if (next_bo == BufferObject.Zero)
+ throw new Exception ("[GBM]: Failed to lock front buffer.");
+
+ fb = getFbFromBo (next_bo);
+
+ unsafe{
+ int is_flip_queued = 1;
+
+ while (Drm.ModePageFlip (fd_gpu, pEncoder->crtc_id, fb, PageFlipFlags.FlipEvent, ref is_flip_queued) < 0) {
+ //Console.WriteLine ("[DRM] Failed to enqueue framebuffer flip.");
+ continue;
+ }
+
+ while (is_flip_queued != 0)
+ {
+ 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_gpu, ref evctx);
+ else
+ break;
+ }
+ if (is_flip_queued != 0)
+ Console.WriteLine ("flip canceled");
+
+ Gbm.ReleaseBuffer (gbm_surface, bo);
+ //Drm.ModeRmFB(fd_gpu, fb);
+
+ bo = next_bo;
+ next_bo = BufferObject.Zero;
+
+ }
+ }
+ }
+
+ #region rendering
+
+
+
+ // 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().
+ int swap_interval=0;
+
+ readonly IntPtr PageFlipPtr;
+ readonly PageFlipCallback PageFlip;
+
+ readonly IntPtr DestroyFBPtr;
+ readonly DestroyUserDataCallback DestroyFB;
+
+ void HandlePageFlip(int fd, int sequence, int tv_sec, int tv_usec, ref int user_data)
+ {
+ user_data = 0;
+ }
+
+
+ void HandleDestroyFB(BufferObject bo, IntPtr data)
+ {
+ Console.WriteLine ("DestroyFB");
+ IntPtr gbm = bo.Device;
+ int fb = data.ToInt32();
+
+ if (fb != 0)
+ Drm.ModeRmFB(fd_gpu, fb);
+ }
+
+ void SetScanoutRegion(int buffer)
+ {
+ unsafe
+ {
+ ModeInfo* mode = pConnector->modes;
+ int connector_id = pConnector->connector_id;
+ int crtc_id = pEncoder->crtc_id;
+
+ int ret = Drm.ModeSetCrtc (fd_gpu, crtc_id, buffer, 0, 0, &connector_id, 1, mode);
+
+ if (ret != 0)
+ Debug.Print("[KMS] Drm.ModeSetCrtc{0}, {1}, {2} failed. Error: {3}",
+ fd_gpu, crtc_id, buffer, ret);
+ Console.WriteLine ("scanout region set: {0}x{1}", mode->hdisplay, mode->vdisplay);
+ }
+ }
+ #endregion
+
+ #region IDisposable implementation
+ public void Dispose ()
+ {
+ cairoDev.Release ();
+ cairoSurf.Dispose ();
+ cairoDev.Dispose ();
+
+ // if (fb != 0)
+ // Drm.ModeRmFB (fd_gpu, fb);
+ // if (bo != BufferObject.Zero)
+ // Gbm.ReleaseBuffer (gbm_surface, bo);
+ // if (next_fb != 0)
+ // Drm.ModeRmFB (fd_gpu, next_fb);
+ // if (next_bo != BufferObject.Zero)
+ // Gbm.ReleaseBuffer (gbm_surface, next_bo);
+
+ if (Egl.GetCurrentContext () == egl_ctx) {
+ Console.WriteLine ("destroying context");
+ Egl.DestroyContext (egl_display, egl_ctx);
+ }else
+ Console.WriteLine ("not current");
+
+ cairoDev.Dispose ();
+
+ unsafe{
+ Drm.ModeSetCrtc (fd_gpu, saved_crtc->crtc_id, saved_crtc->buffer_id,
+ saved_crtc->x, saved_crtc->y, &pConnector->connector_id, 1, &saved_crtc->mode);
+ Drm.ModeFreeCrtc ((IntPtr)saved_crtc);
+ }
+
+ Drm.ModeFreeCrtc (Crtc);
+ Drm.ModeFreeConnector(Connector);
+ Drm.ModeFreeEncoder(Encoder);
+ Libc.close(fd_gpu);
+
+// using(VTControler master = new VTControler()){
+// master.CurrentMode = TTY.Mode.TEXT;
+// if (master.CurrentVT != previousVT) {
+// master.SwitchTo (previousVT);
+// }
+// }
+ }
+ #endregion
+
+ #region INPUT
+ Thread input_thread;
+ long exit;
+
+ static readonly object Sync = new object();
+ static readonly Crow.Key[] KeyMap = Evdev.KeyMap;
+ static long DeviceFDCount;
+
+ IntPtr udev;
+ IntPtr input_context;
+
+ int input_fd = 0;
+
+ InputInterface input_interface = new InputInterface(
+ OpenRestricted, CloseRestricted);
+ 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 initInput (){
+ Semaphore ready = new Semaphore(0, 1);
+ input_thread = new Thread (InputThreadLoop);
+ input_thread.IsBackground = true;
+ input_thread.Start(ready);
+ }
+
+ 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 = input_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)
+ {
+ drmTimeOut.Restart ();
+
+ 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;
+
+ 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 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);
+ 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);
+
+ string seat_id = "seat0";
+ int seat_assignment = LibInput.AssignSeat(input_context, seat_id);
+ if (seat_assignment == -1)
+ {
+ Debug.Print("[Input] LibInput.AssignSeat({0:x}) = {1} failed.", input_context, seat_id);
+ Interlocked.Increment(ref exit);
+ return;
+ }
+ Debug.Print("[Input] LibInput.AssignSeat({0:x}) = {1}", input_context, seat_id);
+
+ input_fd = LibInput.GetFD(input_context);
+ if (input_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, input_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:
+ //run = false;
+ handleKeyboard(LibInput.GetKeyboardEvent(pevent));
+ break;
+ //
+ // case InputEventType.PointerAxis:
+ // HandlePointerAxis(GetMouse(device), LibInput.GetPointerEvent(pevent));
+ // break;
+ //
+ case InputEventType.PointerButton:
+ handlePointerButton (LibInput.GetPointerEvent(pevent));
+ break;
+
+ case InputEventType.PointerMotion:
+ handlePointerMotion (LibInput.GetPointerEvent(pevent));
+ break;
+
+ // case InputEventType.PointerMotionAbsolute:
+ // HandlePointerMotionAbsolute(GetMouse(device), LibInput.GetPointerEvent(pevent));
+ // break;
+ }
+ }
+
+ LibInput.DestroyEvent(pevent);
+ }
+ }
+ int MouseX = 0, MouseY = 0;
+ volatile bool updateMousePos = true;
+
+ int roundDelta (double d){
+ return d > 0 ? (int)Math.Ceiling(d) : (int)Math.Floor (d);
+ }
+
+ void handlePointerMotion(PointerEvent e)
+ {
+ MouseX += roundDelta (e.DeltaX);
+ MouseY += roundDelta (e.DeltaY);
+
+ Rectangle bounds = CrowInterface.ClientRectangle;
+ if (MouseX < bounds.Left)
+ MouseX = bounds.Left;
+ else if (MouseX > bounds.Right)
+ MouseX = bounds.Right;
+
+ if (MouseY < bounds.Top)
+ MouseY = bounds.Top;
+ else if (MouseY > bounds.Bottom)
+ MouseY = bounds.Bottom;
+
+ CrowInterface.ProcessMouseMove (MouseX, MouseY);
+
+ updateMousePos = true;
+ }
+ void handlePointerButton (PointerEvent e)
+ {
+ int but = 0;
+ switch (e.Button) {
+ case EvdevButton.LEFT:
+ but = 0;
+ break;
+ case EvdevButton.MIDDLE:
+ but = 1;
+ break;
+ case EvdevButton.RIGHT:
+ but = 2;
+ break;
+ }
+ if (e.ButtonState == ButtonState.Pressed)
+ CrowInterface.ProcessMouseButtonDown (but);
+ else
+ CrowInterface.ProcessMouseButtonUp (but);
+ }
+
+ KeyModifiers curModifiers = KeyModifiers.None;
+
+ void handleKeyboard(KeyboardEvent e)
+ {
+ return;
+ int key = (int)Evdev.KeyMap [e.Key];
+ Key k = (Key)key;
+ if (e.KeyState == KeyState.Pressed) {
+ CrowInterface.ProcessKeyDown (key);
+ switch (k) {
+ case Key.ShiftLeft:
+ case Key.ShiftRight:
+ curModifiers |= KeyModifiers.Shift;
+ break;
+ case Key.ControlLeft:
+ case Key.ControlRight:
+ curModifiers |= KeyModifiers.Control;
+ break;
+ case Key.AltLeft:
+ curModifiers |= KeyModifiers.Alt;
+ break;
+ case Key.AltRight:
+ curModifiers |= KeyModifiers.AltGr;
+ break;
+ }
+ }else {
+ CrowInterface.ProcessKeyUp (key);
+ switch (k) {
+ case Key.ShiftLeft:
+ case Key.ShiftRight:
+ curModifiers &= ~KeyModifiers.Shift;
+ break;
+ case Key.ControlLeft:
+ case Key.ControlRight:
+ curModifiers &= ~KeyModifiers.Control;
+ break;
+ case Key.AltLeft:
+ curModifiers &= ~KeyModifiers.Alt;
+ break;
+ case Key.AltRight:
+ curModifiers &= ~KeyModifiers.AltGr;
+ break;
+ }
+ if (!keymap.ContainsKey (curModifiers)) {
+ Console.WriteLine ("keymap not found for: " + curModifiers + " " + (int)curModifiers);
+ return;
+ }
+// string tmp = keymap [curModifiers] [e.Key];
+// if (string.IsNullOrEmpty (tmp))
+// return;
+// if (char.IsControl (tmp[0]))
+// return;
+// CrowInterface.ProcessKeyPress (tmp [0]);
+ }
+ }
+
+ #endregion
+ }
+}
+
+
+
+
+++ /dev/null
-#region License
-//
-// The Open Toolkit Library License
-//
-// Copyright (c) 2006 - 2011 the Open Toolkit library.
-//
-// 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.Collections.Generic;
-using System.Text;
-
-
-namespace OpenTK.Platform.Egl
-{
- using EGLNativeDisplayType = IntPtr;
- using EGLNativeWindowType = IntPtr;
- using EGLNativePixmapType = IntPtr;
- using EGLConfig = IntPtr;
- using EGLContext = IntPtr;
- using EGLDisplay = IntPtr;
- using EGLSurface = IntPtr;
- using EGLClientBuffer = IntPtr;
-
- enum RenderApi
- {
- ES = Egl.OPENGL_ES_API,
- GL = Egl.OPENGL_API,
- VG = Egl.OPENVG_API
- }
-
- [Flags]
- enum RenderableFlags
- {
- ES = Egl.OPENGL_ES_BIT,
- ES2 = Egl.OPENGL_ES2_BIT,
- ES3 = Egl.OPENGL_ES3_BIT,
- GL = Egl.OPENGL_BIT,
- VG = Egl.OPENVG_BIT,
- }
-
- public 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,
- CONTEXT_LOST = 12302,
- }
-
- static partial class Egl
- {
- public const int VERSION_1_0 = 1;
- public const int VERSION_1_1 = 1;
- public const int VERSION_1_2 = 1;
- public const int VERSION_1_3 = 1;
- public const int VERSION_1_4 = 1;
- public const int FALSE = 0;
- public const int TRUE = 1;
- public const int DONT_CARE = -1;
- public const int CONTEXT_LOST = 12302;
- public const int BUFFER_SIZE = 12320;
- public const int ALPHA_SIZE = 12321;
- public const int BLUE_SIZE = 12322;
- public const int GREEN_SIZE = 12323;
- public const int RED_SIZE = 12324;
- public const int DEPTH_SIZE = 12325;
- public const int STENCIL_SIZE = 12326;
- public const int CONFIG_CAVEAT = 12327;
- public const int CONFIG_ID = 12328;
- public const int LEVEL = 12329;
- public const int MAX_PBUFFER_HEIGHT = 12330;
- public const int MAX_PBUFFER_PIXELS = 12331;
- public const int MAX_PBUFFER_WIDTH = 12332;
- public const int NATIVE_RENDERABLE = 12333;
- public const int NATIVE_VISUAL_ID = 12334;
- public const int NATIVE_VISUAL_TYPE = 12335;
- public const int PRESERVED_RESOURCES = 12336;
- public const int SAMPLES = 12337;
- public const int SAMPLE_BUFFERS = 12338;
- public const int SURFACE_TYPE = 12339;
- public const int TRANSPARENT_TYPE = 12340;
- public const int TRANSPARENT_BLUE_VALUE = 12341;
- public const int TRANSPARENT_GREEN_VALUE = 12342;
- public const int TRANSPARENT_RED_VALUE = 12343;
- public const int NONE = 12344;
- public const int BIND_TO_TEXTURE_RGB = 12345;
- public const int BIND_TO_TEXTURE_RGBA = 12346;
- public const int MIN_SWAP_INTERVAL = 12347;
- public const int MAX_SWAP_INTERVAL = 12348;
- public const int LUMINANCE_SIZE = 12349;
- public const int ALPHA_MASK_SIZE = 12350;
- public const int COLOR_BUFFER_TYPE = 12351;
- public const int RENDERABLE_TYPE = 12352;
- public const int MATCH_NATIVE_PIXMAP = 12353;
- public const int CONFORMANT = 12354;
- public const int SLOW_CONFIG = 12368;
- public const int NON_CONFORMANT_CONFIG = 12369;
- public const int TRANSPARENT_RGB = 12370;
- public const int RGB_BUFFER = 12430;
- public const int LUMINANCE_BUFFER = 12431;
- public const int NO_TEXTURE = 12380;
- public const int TEXTURE_RGB = 12381;
- public const int TEXTURE_RGBA = 12382;
- public const int TEXTURE_2D = 12383;
- public const int PBUFFER_BIT = 1;
- public const int PIXMAP_BIT = 2;
- public const int WINDOW_BIT = 4;
- public const int VG_COLORSPACE_LINEAR_BIT = 32;
- public const int VG_ALPHA_FORMAT_PRE_BIT = 64;
- public const int MULTISAMPLE_RESOLVE_BOX_BIT = 512;
- public const int SWAP_BEHAVIOR_PRESERVED_BIT = 1024;
- public const int OPENGL_ES_BIT = 1;
- public const int OPENVG_BIT = 2;
- public const int OPENGL_ES2_BIT = 4;
- public const int OPENGL_BIT = 8;
- public const int OPENGL_ES3_BIT = 64;
- public const int VENDOR = 12371;
- public const int VERSION = 12372;
- public const int EXTENSIONS = 12373;
- public const int CLIENT_APIS = 12429;
- public const int HEIGHT = 12374;
- public const int WIDTH = 12375;
- public const int LARGEST_PBUFFER = 12376;
- public const int TEXTURE_FORMAT = 12416;
- public const int TEXTURE_TARGET = 12417;
- public const int MIPMAP_TEXTURE = 12418;
- public const int MIPMAP_LEVEL = 12419;
- public const int RENDER_BUFFER = 12422;
- public const int VG_COLORSPACE = 12423;
- public const int VG_ALPHA_FORMAT = 12424;
- public const int HORIZONTAL_RESOLUTION = 12432;
- public const int VERTICAL_RESOLUTION = 12433;
- public const int PIXEL_ASPECT_RATIO = 12434;
- public const int SWAP_BEHAVIOR = 12435;
- public const int MULTISAMPLE_RESOLVE = 12441;
- public const int BACK_BUFFER = 12420;
- public const int SINGLE_BUFFER = 12421;
- public const int VG_COLORSPACE_sRGB = 12425;
- public const int VG_COLORSPACE_LINEAR = 12426;
- public const int VG_ALPHA_FORMAT_NONPRE = 12427;
- public const int VG_ALPHA_FORMAT_PRE = 12428;
- public const int DISPLAY_SCALING = 10000;
- public const int UNKNOWN = -1;
- public const int BUFFER_PRESERVED = 12436;
- public const int BUFFER_DESTROYED = 12437;
- public const int OPENVG_IMAGE = 12438;
- public const int CONTEXT_CLIENT_TYPE = 12439;
- public const int CONTEXT_CLIENT_VERSION = 12440;
- public const int MULTISAMPLE_RESOLVE_DEFAULT = 12442;
- public const int MULTISAMPLE_RESOLVE_BOX = 12443;
- public const int OPENGL_ES_API = 12448;
- public const int OPENVG_API = 12449;
- public const int OPENGL_API = 12450;
- public const int DRAW = 12377;
- public const int READ = 12378;
- public const int CORE_NATIVE_ENGINE = 12379;
- public const int COLORSPACE = VG_COLORSPACE;
- public const int ALPHA_FORMAT = VG_ALPHA_FORMAT;
- public const int COLORSPACE_sRGB = VG_COLORSPACE_sRGB;
- public const int COLORSPACE_LINEAR = VG_COLORSPACE_LINEAR;
- public const int ALPHA_FORMAT_NONPRE = VG_ALPHA_FORMAT_NONPRE;
- public const int ALPHA_FORMAT_PRE = VG_ALPHA_FORMAT_PRE;
-
- // EGL_ANGLE_d3d_share_handle_client_buffer
- public const int D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200;
- // EGL_ANGLE_window_fixed_size
- public const int FIXED_SIZE_ANGLE = 0x3201;
- // EGL_ANGLE_query_surface_pointer
- [DllImport("libEGL.dll", EntryPoint = "eglQuerySurfacePointerANGLE")]
- public static extern bool QuerySurfacePointerANGLE(EGLDisplay display, EGLSurface surface, int attribute, out IntPtr value);
- // EGL_ANGLE_software_display
- public static readonly EGLNativeDisplayType SOFTWARE_DISPLAY_ANGLE = new EGLNativeDisplayType(-1);
- // EGL_ANGLE_direct3d_display
- public static readonly EGLNativeDisplayType D3D11_ELSE_D3D9_DISPLAY_ANGLE = new EGLNativeDisplayType(-2);
- public static readonly EGLNativeDisplayType D3D11_ONLY_DISPLAY_ANGLE = new EGLNativeDisplayType(-3);
- // EGL_ANGLE_device_d3d
- public const int D3D9_DEVICE_ANGLE = 0x33A0;
- public const int D3D11_DEVICE_ANGLE = 0x33A1;
- // EGL_ANGLE_platform_angle
- public const int PLATFORM_ANGLE_ANGLE = 0x3202;
- public const int PLATFORM_ANGLE_TYPE_ANGLE = 0x3203;
- public const int PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE = 0x3204;
- public const int PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE = 0x3205;
- public const int PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE = 0x3206;
- // EGL_ANGLE_platform_angle_d3d
- public const int PLATFORM_ANGLE_TYPE_D3D9_ANGLE = 0x3207;
- public const int PLATFORM_ANGLE_TYPE_D3D11_ANGLE = 0x3208;
- public const int PLATFORM_ANGLE_DEVICE_TYPE_ANGLE = 0x3209;
- public const int PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE = 0x320A;
- public const int PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE = 0x320B;
- public const int PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE = 0x320C;
- public const int PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE = 0x320F;
- // EGL_ANGLE_platform_angle_opengl
- public const int PLATFORM_ANGLE_TYPE_OPENGL_ANGLE = 0x320D;
- public const int PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE = 0x320E;
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetError")]
- public static extern ErrorCode GetError();
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetDisplay")]
- public static extern EGLDisplay GetDisplay(EGLNativeDisplayType display_id);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglInitialize")]
- //[return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool Initialize(EGLDisplay dpy, out int major, out int minor);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglTerminate")]
- //[return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool Terminate(EGLDisplay dpy);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryString")]
- public static extern IntPtr QueryString(EGLDisplay dpy, int name);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetConfigs")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool GetConfigs(EGLDisplay dpy, EGLConfig[] configs, int config_size, out int num_config);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglChooseConfig")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool ChooseConfig(EGLDisplay dpy, int[] attrib_list, [In, Out] EGLConfig[] configs, int config_size, out int num_config);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetConfigAttrib")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool GetConfigAttrib(EGLDisplay dpy, EGLConfig config, int attribute, out int value);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreateWindowSurface")]
- public static extern EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config, IntPtr win, IntPtr attrib_list);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreatePbufferSurface")]
- public static extern EGLSurface CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, int[] attrib_list);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreatePixmapSurface")]
- public static extern EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, int[] attrib_list);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglDestroySurface")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool DestroySurface(EGLDisplay dpy, EGLSurface surface);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglQuerySurface")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool QuerySurface(EGLDisplay dpy, EGLSurface surface, int attribute, out int value);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglBindAPI")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool BindAPI(RenderApi api);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryAPI")]
- public static extern int QueryAPI();
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglWaitClient")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool WaitClient();
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglReleaseThread")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool ReleaseThread();
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreatePbufferFromClientBuffer")]
- public static extern EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, int buftype, EGLClientBuffer buffer, EGLConfig config, int[] attrib_list);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglSurfaceAttrib")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, int attribute, int value);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglBindTexImage")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool BindTexImage(EGLDisplay dpy, EGLSurface surface, int buffer);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglReleaseTexImage")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, int buffer);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglSwapInterval")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool SwapInterval(EGLDisplay dpy, int interval);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreateContext")]
- static extern IntPtr eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list);
-
- public static EGLContext CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list)
- {
- IntPtr ptr = eglCreateContext(dpy, config, share_context, attrib_list);
- if (ptr == IntPtr.Zero)
- throw new Exception(String.Format("Failed to create EGL context, error: {0}.", Egl.GetError()));
- return ptr;
- }
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglDestroyContext")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool DestroyContext(EGLDisplay dpy, EGLContext ctx);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglMakeCurrent")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetCurrentContext")]
- public static extern EGLContext GetCurrentContext();
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetCurrentSurface")]
- public static extern EGLSurface GetCurrentSurface(int readdraw);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetCurrentDisplay")]
- public static extern EGLDisplay GetCurrentDisplay();
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryContext")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool QueryContext(EGLDisplay dpy, EGLContext ctx, int attribute, out int value);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglWaitGL")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool WaitGL();
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglWaitNative")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool WaitNative(int engine);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglSwapBuffers")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool SwapBuffers(EGLDisplay dpy, EGLSurface surface);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglCopyBuffers")]
- [return: MarshalAsAttribute(UnmanagedType.I1)]
- public static extern bool CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetProcAddress")]
- public static extern IntPtr GetProcAddress(string funcname);
-
- [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetProcAddress")]
- public static extern IntPtr GetProcAddress(IntPtr funcname);
-
- // EGL_EXT_platform_base
- [DllImport("libEGL.dll", EntryPoint = "eglGetPlatformDisplayEXT")]
- public static extern EGLDisplay GetPlatformDisplayEXT(int platform, EGLNativeDisplayType native_display, int[] attrib_list);
-
- [DllImport("libEGL.dll", EntryPoint = "eglCreatePlatformWindowSurfaceEXT")]
- public static extern EGLSurface CreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType native_window, int[] attrib_list);
-
- [DllImport("libEGL.dll", EntryPoint = "eglCreatePlatformPixmapSurfaceEXT")]
- public static extern EGLSurface CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType native_pixmap, int[] attrib_list);
-
- // Returns true if Egl drivers exist on the system.
- public static bool IsSupported
- {
- get
- {
- try { GetCurrentContext(); }
- catch (Exception) { return false; }
- return true;
- }
- }
-
- }
-#pragma warning restore 0169
-}
\ No newline at end of file
--- /dev/null
+#region License
+//
+// The Open Toolkit Library License
+//
+// Copyright (c) 2006 - 2011 the Open Toolkit library.
+//
+// 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.Collections.Generic;
+using System.Text;
+
+
+namespace Crow.Linux
+{
+ using EGLNativeDisplayType = IntPtr;
+ using EGLNativeWindowType = IntPtr;
+ using EGLNativePixmapType = IntPtr;
+ using EGLConfig = IntPtr;
+ using EGLContext = IntPtr;
+ using EGLDisplay = IntPtr;
+ using EGLSurface = IntPtr;
+ using EGLClientBuffer = IntPtr;
+
+ enum RenderApi
+ {
+ ES = Egl.OPENGL_ES_API,
+ GL = Egl.OPENGL_API,
+ VG = Egl.OPENVG_API
+ }
+
+ [Flags]
+ enum RenderableFlags
+ {
+ ES = Egl.OPENGL_ES_BIT,
+ ES2 = Egl.OPENGL_ES2_BIT,
+ ES3 = Egl.OPENGL_ES3_BIT,
+ GL = Egl.OPENGL_BIT,
+ VG = Egl.OPENVG_BIT,
+ }
+
+ public 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,
+ CONTEXT_LOST = 12302,
+ }
+
+ static partial class Egl
+ {
+ public const int VERSION_1_0 = 1;
+ public const int VERSION_1_1 = 1;
+ public const int VERSION_1_2 = 1;
+ public const int VERSION_1_3 = 1;
+ public const int VERSION_1_4 = 1;
+ public const int FALSE = 0;
+ public const int TRUE = 1;
+ public const int DONT_CARE = -1;
+ public const int CONTEXT_LOST = 12302;
+ public const int BUFFER_SIZE = 12320;
+ public const int ALPHA_SIZE = 12321;
+ public const int BLUE_SIZE = 12322;
+ public const int GREEN_SIZE = 12323;
+ public const int RED_SIZE = 12324;
+ public const int DEPTH_SIZE = 12325;
+ public const int STENCIL_SIZE = 12326;
+ public const int CONFIG_CAVEAT = 12327;
+ public const int CONFIG_ID = 12328;
+ public const int LEVEL = 12329;
+ public const int MAX_PBUFFER_HEIGHT = 12330;
+ public const int MAX_PBUFFER_PIXELS = 12331;
+ public const int MAX_PBUFFER_WIDTH = 12332;
+ public const int NATIVE_RENDERABLE = 12333;
+ public const int NATIVE_VISUAL_ID = 12334;
+ public const int NATIVE_VISUAL_TYPE = 12335;
+ public const int PRESERVED_RESOURCES = 12336;
+ public const int SAMPLES = 12337;
+ public const int SAMPLE_BUFFERS = 12338;
+ public const int SURFACE_TYPE = 12339;
+ public const int TRANSPARENT_TYPE = 12340;
+ public const int TRANSPARENT_BLUE_VALUE = 12341;
+ public const int TRANSPARENT_GREEN_VALUE = 12342;
+ public const int TRANSPARENT_RED_VALUE = 12343;
+ public const int NONE = 12344;
+ public const int BIND_TO_TEXTURE_RGB = 12345;
+ public const int BIND_TO_TEXTURE_RGBA = 12346;
+ public const int MIN_SWAP_INTERVAL = 12347;
+ public const int MAX_SWAP_INTERVAL = 12348;
+ public const int LUMINANCE_SIZE = 12349;
+ public const int ALPHA_MASK_SIZE = 12350;
+ public const int COLOR_BUFFER_TYPE = 12351;
+ public const int RENDERABLE_TYPE = 12352;
+ public const int MATCH_NATIVE_PIXMAP = 12353;
+ public const int CONFORMANT = 12354;
+ public const int SLOW_CONFIG = 12368;
+ public const int NON_CONFORMANT_CONFIG = 12369;
+ public const int TRANSPARENT_RGB = 12370;
+ public const int RGB_BUFFER = 12430;
+ public const int LUMINANCE_BUFFER = 12431;
+ public const int NO_TEXTURE = 12380;
+ public const int TEXTURE_RGB = 12381;
+ public const int TEXTURE_RGBA = 12382;
+ public const int TEXTURE_2D = 12383;
+ public const int PBUFFER_BIT = 1;
+ public const int PIXMAP_BIT = 2;
+ public const int WINDOW_BIT = 4;
+ public const int VG_COLORSPACE_LINEAR_BIT = 32;
+ public const int VG_ALPHA_FORMAT_PRE_BIT = 64;
+ public const int MULTISAMPLE_RESOLVE_BOX_BIT = 512;
+ public const int SWAP_BEHAVIOR_PRESERVED_BIT = 1024;
+ public const int OPENGL_ES_BIT = 1;
+ public const int OPENVG_BIT = 2;
+ public const int OPENGL_ES2_BIT = 4;
+ public const int OPENGL_BIT = 8;
+ public const int OPENGL_ES3_BIT = 64;
+ public const int VENDOR = 12371;
+ public const int VERSION = 12372;
+ public const int EXTENSIONS = 12373;
+ public const int CLIENT_APIS = 12429;
+ public const int HEIGHT = 12374;
+ public const int WIDTH = 12375;
+ public const int LARGEST_PBUFFER = 12376;
+ public const int TEXTURE_FORMAT = 12416;
+ public const int TEXTURE_TARGET = 12417;
+ public const int MIPMAP_TEXTURE = 12418;
+ public const int MIPMAP_LEVEL = 12419;
+ public const int RENDER_BUFFER = 12422;
+ public const int VG_COLORSPACE = 12423;
+ public const int VG_ALPHA_FORMAT = 12424;
+ public const int HORIZONTAL_RESOLUTION = 12432;
+ public const int VERTICAL_RESOLUTION = 12433;
+ public const int PIXEL_ASPECT_RATIO = 12434;
+ public const int SWAP_BEHAVIOR = 12435;
+ public const int MULTISAMPLE_RESOLVE = 12441;
+ public const int BACK_BUFFER = 12420;
+ public const int SINGLE_BUFFER = 12421;
+ public const int VG_COLORSPACE_sRGB = 12425;
+ public const int VG_COLORSPACE_LINEAR = 12426;
+ public const int VG_ALPHA_FORMAT_NONPRE = 12427;
+ public const int VG_ALPHA_FORMAT_PRE = 12428;
+ public const int DISPLAY_SCALING = 10000;
+ public const int UNKNOWN = -1;
+ public const int BUFFER_PRESERVED = 12436;
+ public const int BUFFER_DESTROYED = 12437;
+ public const int OPENVG_IMAGE = 12438;
+ public const int CONTEXT_CLIENT_TYPE = 12439;
+ public const int CONTEXT_CLIENT_VERSION = 12440;
+ public const int MULTISAMPLE_RESOLVE_DEFAULT = 12442;
+ public const int MULTISAMPLE_RESOLVE_BOX = 12443;
+ public const int OPENGL_ES_API = 12448;
+ public const int OPENVG_API = 12449;
+ public const int OPENGL_API = 12450;
+ public const int DRAW = 12377;
+ public const int READ = 12378;
+ public const int CORE_NATIVE_ENGINE = 12379;
+ public const int COLORSPACE = VG_COLORSPACE;
+ public const int ALPHA_FORMAT = VG_ALPHA_FORMAT;
+ public const int COLORSPACE_sRGB = VG_COLORSPACE_sRGB;
+ public const int COLORSPACE_LINEAR = VG_COLORSPACE_LINEAR;
+ public const int ALPHA_FORMAT_NONPRE = VG_ALPHA_FORMAT_NONPRE;
+ public const int ALPHA_FORMAT_PRE = VG_ALPHA_FORMAT_PRE;
+
+ // EGL_ANGLE_d3d_share_handle_client_buffer
+ public const int D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200;
+ // EGL_ANGLE_window_fixed_size
+ public const int FIXED_SIZE_ANGLE = 0x3201;
+ // EGL_ANGLE_query_surface_pointer
+ [DllImport("libEGL.dll", EntryPoint = "eglQuerySurfacePointerANGLE")]
+ public static extern bool QuerySurfacePointerANGLE(EGLDisplay display, EGLSurface surface, int attribute, out IntPtr value);
+ // EGL_ANGLE_software_display
+ public static readonly EGLNativeDisplayType SOFTWARE_DISPLAY_ANGLE = new EGLNativeDisplayType(-1);
+ // EGL_ANGLE_direct3d_display
+ public static readonly EGLNativeDisplayType D3D11_ELSE_D3D9_DISPLAY_ANGLE = new EGLNativeDisplayType(-2);
+ public static readonly EGLNativeDisplayType D3D11_ONLY_DISPLAY_ANGLE = new EGLNativeDisplayType(-3);
+ // EGL_ANGLE_device_d3d
+ public const int D3D9_DEVICE_ANGLE = 0x33A0;
+ public const int D3D11_DEVICE_ANGLE = 0x33A1;
+ // EGL_ANGLE_platform_angle
+ public const int PLATFORM_ANGLE_ANGLE = 0x3202;
+ public const int PLATFORM_ANGLE_TYPE_ANGLE = 0x3203;
+ public const int PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE = 0x3204;
+ public const int PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE = 0x3205;
+ public const int PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE = 0x3206;
+ // EGL_ANGLE_platform_angle_d3d
+ public const int PLATFORM_ANGLE_TYPE_D3D9_ANGLE = 0x3207;
+ public const int PLATFORM_ANGLE_TYPE_D3D11_ANGLE = 0x3208;
+ public const int PLATFORM_ANGLE_DEVICE_TYPE_ANGLE = 0x3209;
+ public const int PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE = 0x320A;
+ public const int PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE = 0x320B;
+ public const int PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE = 0x320C;
+ public const int PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE = 0x320F;
+ // EGL_ANGLE_platform_angle_opengl
+ public const int PLATFORM_ANGLE_TYPE_OPENGL_ANGLE = 0x320D;
+ public const int PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE = 0x320E;
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetError")]
+ public static extern ErrorCode GetError();
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetDisplay")]
+ public static extern EGLDisplay GetDisplay(EGLNativeDisplayType display_id);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglInitialize")]
+ //[return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool Initialize(EGLDisplay dpy, out int major, out int minor);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglTerminate")]
+ //[return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool Terminate(EGLDisplay dpy);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryString")]
+ public static extern IntPtr QueryString(EGLDisplay dpy, int name);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetConfigs")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool GetConfigs(EGLDisplay dpy, EGLConfig[] configs, int config_size, out int num_config);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglChooseConfig")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool ChooseConfig(EGLDisplay dpy, int[] attrib_list, [In, Out] EGLConfig[] configs, int config_size, out int num_config);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetConfigAttrib")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool GetConfigAttrib(EGLDisplay dpy, EGLConfig config, int attribute, out int value);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreateWindowSurface")]
+ public static extern EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config, IntPtr win, IntPtr attrib_list);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreatePbufferSurface")]
+ public static extern EGLSurface CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, int[] attrib_list);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreatePixmapSurface")]
+ public static extern EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, int[] attrib_list);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglDestroySurface")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool DestroySurface(EGLDisplay dpy, EGLSurface surface);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglQuerySurface")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool QuerySurface(EGLDisplay dpy, EGLSurface surface, int attribute, out int value);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglBindAPI")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool BindAPI(RenderApi api);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryAPI")]
+ public static extern int QueryAPI();
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglWaitClient")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool WaitClient();
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglReleaseThread")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool ReleaseThread();
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreatePbufferFromClientBuffer")]
+ public static extern EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, int buftype, EGLClientBuffer buffer, EGLConfig config, int[] attrib_list);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglSurfaceAttrib")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, int attribute, int value);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglBindTexImage")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool BindTexImage(EGLDisplay dpy, EGLSurface surface, int buffer);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglReleaseTexImage")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, int buffer);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglSwapInterval")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool SwapInterval(EGLDisplay dpy, int interval);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreateContext")]
+ static extern IntPtr eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list);
+
+ public static EGLContext CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list)
+ {
+ IntPtr ptr = eglCreateContext(dpy, config, share_context, attrib_list);
+ if (ptr == IntPtr.Zero)
+ throw new Exception(String.Format("Failed to create EGL context, error: {0}.", Egl.GetError()));
+ return ptr;
+ }
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglDestroyContext")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool DestroyContext(EGLDisplay dpy, EGLContext ctx);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglMakeCurrent")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetCurrentContext")]
+ public static extern EGLContext GetCurrentContext();
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetCurrentSurface")]
+ public static extern EGLSurface GetCurrentSurface(int readdraw);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetCurrentDisplay")]
+ public static extern EGLDisplay GetCurrentDisplay();
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryContext")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool QueryContext(EGLDisplay dpy, EGLContext ctx, int attribute, out int value);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglWaitGL")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool WaitGL();
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglWaitNative")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool WaitNative(int engine);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglSwapBuffers")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool SwapBuffers(EGLDisplay dpy, EGLSurface surface);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglCopyBuffers")]
+ [return: MarshalAsAttribute(UnmanagedType.I1)]
+ public static extern bool CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetProcAddress")]
+ public static extern IntPtr GetProcAddress(string funcname);
+
+ [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetProcAddress")]
+ public static extern IntPtr GetProcAddress(IntPtr funcname);
+
+ // EGL_EXT_platform_base
+ [DllImport("libEGL.dll", EntryPoint = "eglGetPlatformDisplayEXT")]
+ public static extern EGLDisplay GetPlatformDisplayEXT(int platform, EGLNativeDisplayType native_display, int[] attrib_list);
+
+ [DllImport("libEGL.dll", EntryPoint = "eglCreatePlatformWindowSurfaceEXT")]
+ public static extern EGLSurface CreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType native_window, int[] attrib_list);
+
+ [DllImport("libEGL.dll", EntryPoint = "eglCreatePlatformPixmapSurfaceEXT")]
+ public static extern EGLSurface CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType native_pixmap, int[] attrib_list);
+
+ // Returns true if Egl drivers exist on the system.
+ public static bool IsSupported
+ {
+ get
+ {
+ try { GetCurrentContext(); }
+ catch (Exception) { return false; }
+ return true;
+ }
+ }
+
+ }
+#pragma warning restore 0169
+}
\ No newline at end of file
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
+using OpenTK;
+
+
#endregion
using System;
using System.Runtime.InteropServices;
using Crow;
-namespace OpenTK.Platform.Linux
+namespace Crow.Linux
{
// Bindings for linux/input.h
class Evdev
using System.Diagnostics;
using System.Runtime.InteropServices;
-namespace OpenTK.Platform.Linux
+namespace Crow.Linux
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int OpenRestrictedCallback(IntPtr path, int flags, IntPtr data);
#pragma warning disable 0649 // field is never assigned
-namespace OpenTK.Platform.Linux
+namespace Crow.Linux
{
partial class Libc
{
[DllImport(lib)]
public static extern int open(IntPtr pathname, OpenFlags flags);
+ [DllImport(lib)]
+ public static extern int posix_openpt (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);
+ [DllImport(lib)]
+ unsafe public static extern uint write(int fd, void *buffer, int count);
+
+ public static void write (int fd, byte[] b){
+ unsafe {
+ fixed (byte* pb = b) {
+ write (fd, pb, b.Length);
+ }
+ }
+ }
public static int read(int fd, out byte b)
{
using System;
using System.Runtime.InteropServices;
-namespace OpenTK.Platform.Linux
+namespace Crow.Linux
{
partial class Libc
{
--- /dev/null
+//
+// DRM.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// 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.
+using System;
+using System.Runtime.InteropServices;
+
+namespace Crow.Linux.DRI {
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate void VBlankCallback(int fd, int sequence, int tv_sec, int tv_usec, IntPtr user_data);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate void PageFlipCallback(int fd, int sequence, int tv_sec, int tv_usec, ref int user_data);
+
+ enum ModeConnection
+ {
+ Connected = 1,
+ Disconnected = 2,
+ Unknown = 3
+ }
+ enum ModeConnectorType
+ {
+ Unknown = 0,
+ VGA=1,
+ DVII=2,
+ DVID=3,
+ DVIA=4,
+ Composite=5,
+ SVIDEO=6,
+ LVDS=7,
+ Component=8,
+ PinDIN9 = 9,
+ DisplayPort=10,
+ HDMIA=11,
+ HDMIB=12,
+ TV=13,
+ eDP=14,
+ VIRTUAL=15,
+ DSI=16,
+ DPI=17
+ }
+ enum ModeEncoderType
+ {
+ NONE=0,
+ DAC=1,
+ TMDS=2,
+ LVDS=3,
+ TVDAC=4,
+ VIRTUAL=5,
+ DSI=6,
+ DPMST=7,
+ DPI=8,
+ }
+ enum ModeSubPixel
+ {
+ Unknown = 1,
+ HorizontalRgb = 2,
+ HorizontalBgr = 3,
+ VerticalRgb = 4,
+ VerticalBgr = 5,
+ None = 6
+ }
+
+ [Flags]
+ enum PageFlipFlags
+ {
+ FlipEvent = 0x01,
+ FlipAsync = 0x02,
+ FlipFlags = FlipEvent | FlipAsync
+ }
+
+ [Flags]
+ enum ModeFlags
+ {
+ /* Video mode flags */
+ /* bit compatible with the xorg definitions. */
+ PHSYNC = 0x01,
+ NHSYNC = 0x02,
+ PVSYNC = 0x04,
+ NVSYNC = 0x08,
+ INTERLACE = 0x10,
+ DBLSCAN = 0x20,
+ CSYNC = 0x40,
+ PCSYNC = 0x80,
+ NCSYNC = 0x10,
+ HSKEW = 0x0200,
+ BCAST = 0x0400,
+ PIXMUX = 0x0800,
+ DBLCLK = 0x1000,
+ CLKDIV2 = 0x2000,
+ // FLAG_3D_MASK (0x1f<<14)
+ // FLAG_3D_NONE = 0x0;
+ // FLAG_3D_FRAME_PACKING = 0x4000,
+ // FLAG_3D_FIELD_ALTERNATIVE = 0x8000,
+ // FLAG_3D_LINE_ALTERNATIVE (3<<14)
+ // FLAG_3D_SIDE_BY_SIDE_FULL (4<<14)
+ // FLAG_3D_L_DEPTH (5<<14)
+ // FLAG_3D_L_DEPTH_GFX_GFX_DEPTH (6<<14)
+ // FLAG_3D_TOP_AND_BOTTOM (7<<14)
+ // FLAG_3D_SIDE_BY_SIDE_HALF (8<<14)
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public 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 ModeConnectorType 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;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ 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;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct ModeEncoder
+ {
+ public int encoder_id;
+ public ModeEncoderType 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 uint* fbs;
+ public int count_crtcs;
+ public uint* crtcs;
+ public int count_connectors;
+ public uint* connectors;
+ public int count_encoders;
+ public uint* encoders;
+ public uint min_width, max_width;
+ public uint min_height, max_height;
+ }
+
+
+
+ public class GPUControler : IDisposable {
+ int fd_gpu = -1;
+ ModeRes resources = new ModeRes ();
+
+ public GPUControler(string gpu_path = "/dev/dri/card0"){
+ fd_gpu = Libc.open(gpu_path, OpenFlags.ReadWrite | OpenFlags.CloseOnExec);
+ if (fd_gpu < 0)
+ throw new NotSupportedException("[KMS] Failed to open gpu");
+
+ unsafe {
+ ModeRes* ptrRes = ModeGetResources (fd_gpu);
+ resources = *ptrRes;
+ ModeFreeResources (ptrRes);
+ }
+
+// if (resources == null)
+// throw new NotSupportedException("[KMS] Drm.ModeGetResources failed.");
+ }
+
+ #region IDisposable implementation
+ ~GPUControler(){
+ Dispose (false);
+ }
+ public void Dispose ()
+ {
+ Dispose (true);
+ GC.SuppressFinalize (this);
+ }
+ protected virtual void Dispose (bool disposing){
+ if (fd_gpu > 0)
+ Libc.close (fd_gpu);
+ fd_gpu = -1;
+ }
+ #endregion
+
+ #region ioctl overrides
+ 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 = "drmModeGetResources", CallingConvention = CallingConvention.Cdecl)]
+ unsafe static extern ModeRes* ModeGetResources(int fd);
+ [DllImport(lib, EntryPoint = "drmModeGetCrtc", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr ModeGetCrtc(int fd, int crtcId);
+ [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 = "drmModeFreeResources", CallingConvention = CallingConvention.Cdecl)]
+ unsafe static extern void ModeFreeResources(ModeRes* ptr);
+ [DllImport(lib, EntryPoint = "drmModeFreeCrtc", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void ModeFreeCrtc(IntPtr ptr);
+ [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 = "drmModePageFlip", CallingConvention = CallingConvention.Cdecl)]
+ static extern int ModePageFlip(int fd, int crtc_id, int fb_id,
+ PageFlipFlags flags, ref int user_data);
+
+ [DllImport(lib, EntryPoint = "drmModeSetCrtc", CallingConvention = CallingConvention.Cdecl)]
+ unsafe 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);
+ #endregion
+ }
+}
\ No newline at end of file
+++ /dev/null
-#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;
-#if !MINIMAL
-using System.Drawing;
-#endif
-
-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
- {
- 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());
- }
-
- 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 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 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 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
- }
-}
-
+++ /dev/null
-#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;
- }
- }
-
- public override OpenTK.Input.IGamePadDriver CreateGamePadDriver()
- {
- return new MappedGamePadDriver();
- }
-
- #endregion
- }
-}
-
+++ /dev/null
-#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();
-
- 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;
- }
- }
-
- bo_next = LockSurface();
- int fb = GetFramebuffer(bo_next);
- 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);
- }
- }
-}
-
-
-
+++ /dev/null
-#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;
-#if !MINIMAL
-using System.Drawing;
-#endif
-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);
- 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);
-
- string seat_id = "seat0";
- int seat_assignment = LibInput.AssignSeat(input_context, seat_id);
- if (seat_assignment == -1)
- {
- Debug.Print("[Input] LibInput.AssignSeat({0:x}) = {1} failed.", input_context, seat_id);
- Interlocked.Increment(ref exit);
- return;
- }
- Debug.Print("[Input] LibInput.AssignSeat({0:x}) = {1}", input_context, seat_id);
-
- 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);
-
- if (e.HasAxis(PointerAxis.HorizontalScroll))
- {
- mouse.State.SetScrollRelative((float)e.AxisValue(PointerAxis.HorizontalScroll), 0);
- }
- if (e.HasAxis(PointerAxis.VerticalScroll))
- {
- mouse.State.SetScrollRelative(0, (float)e.AxisValue(PointerAxis.VerticalScroll));
- }
- }
- }
-
- 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.DeltaX, (float)e.DeltaY);
- 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((float)e.X, (float)e.Y);
- }
-
- CursorPosition = new Vector2(
- (float)e.TransformedX(bounds.Width),
- (float)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
- }
-}
-
+++ /dev/null
-#region License
-//
-// The Open Toolkit Library License
-//
-// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted.
-//
-// 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.IO;
-using System.Runtime.InteropServices;
-using System.Text;
-using OpenTK.Input;
-
-namespace OpenTK.Platform.Linux
-{
- struct AxisInfo
- {
- public JoystickAxis Axis;
- public InputAbsInfo Info;
- }
-
- class LinuxJoystickDetails
- {
- public Guid Guid;
- public string Name;
- public int FileDescriptor;
- public int PathIndex; // e.g. "0" for "/dev/input/event0". Used as a hardware id
- public JoystickState State;
- public JoystickCapabilities Caps;
-
- public readonly Dictionary<EvdevAxis, AxisInfo> AxisMap =
- new Dictionary<EvdevAxis, AxisInfo>();
- public readonly Dictionary<EvdevButton, int> ButtonMap =
- new Dictionary<EvdevButton, int>();
- }
-
- sealed class LinuxJoystick : IJoystickDriver2
- {
- #region Fields
-
- static readonly HatPosition[,] HatPositions = new HatPosition[,]
- {
- { HatPosition.UpLeft, HatPosition.Up, HatPosition.UpRight },
- { HatPosition.Left, HatPosition.Centered, HatPosition.Right },
- { HatPosition.DownLeft, HatPosition.Down, HatPosition.DownRight }
- };
-
- readonly object sync = new object();
-
- readonly FileSystemWatcher watcher = new FileSystemWatcher();
-
- readonly DeviceCollection<LinuxJoystickDetails> Sticks =
- new DeviceCollection<LinuxJoystickDetails>();
-
- bool disposed;
-
- #endregion
-
- #region Constructors
-
- public LinuxJoystick()
- {
- string path =
- Directory.Exists(JoystickPath) ? JoystickPath :
- Directory.Exists(JoystickPathLegacy) ? JoystickPathLegacy :
- String.Empty;
-
- if (!String.IsNullOrEmpty(path))
- {
- watcher.Path = path;
-
- watcher.Created += JoystickAdded;
- watcher.Deleted += JoystickRemoved;
- watcher.EnableRaisingEvents = true;
-
- OpenJoysticks(path);
- }
- }
-
- #endregion
-
- #region Private Members
-
- void OpenJoysticks(string path)
- {
- lock (sync)
- {
- foreach (string file in Directory.GetFiles(path))
- {
- LinuxJoystickDetails stick = OpenJoystick(file);
- if (stick != null)
- {
- Sticks.Add(stick.PathIndex, stick);
- }
- }
- }
- }
-
- int GetJoystickNumber(string path)
- {
- const string evdev = "event";
- if (path.StartsWith(evdev))
- {
- int num;
- if (Int32.TryParse(path.Substring(evdev.Length), out num))
- {
- return num;
- }
- }
- return -1;
- }
-
- void JoystickAdded(object sender, FileSystemEventArgs e)
- {
- lock (sync)
- {
- OpenJoystick(e.FullPath);
- }
- }
-
- void JoystickRemoved(object sender, FileSystemEventArgs e)
- {
- lock (sync)
- {
- string file = Path.GetFileName(e.FullPath);
- int number = GetJoystickNumber(file);
- if (number != -1)
- {
- var stick = Sticks.FromHardwareId(number);
- if (stick != null)
- {
- CloseJoystick(stick);
- }
- }
- }
- }
-
- #endregion
-
- #region Private Members
-
- Guid CreateGuid(EvdevInputId id, string name)
- {
- // Note: the first 8bytes of the Guid are byteswapped
- // in three parts when using `new Guid(byte[])`:
- // (int, short, short).
- // We need to take that into account to match the expected
- // Guid in the database. Ugh.
-
- byte[] bytes = new byte[16];
-
- int i = 0;
- byte[] bus = BitConverter.GetBytes((int)id.BusType);
- bytes[i++] = bus[3];
- bytes[i++] = bus[2];
- bytes[i++] = bus[1];
- bytes[i++] = bus[0];
-
- if (id.Vendor != 0 && id.Product != 0 && id.Version != 0)
- {
- byte[] vendor = BitConverter.GetBytes(id.Vendor);
- byte[] product = BitConverter.GetBytes(id.Product);
- byte[] version = BitConverter.GetBytes(id.Version);
- bytes[i++] = vendor[1];
- bytes[i++] = vendor[0];
- bytes[i++] = 0;
- bytes[i++] = 0;
- bytes[i++] = product[0]; // no byteswapping
- bytes[i++] = product[1];
- bytes[i++] = 0;
- bytes[i++] = 0;
- bytes[i++] = version[0]; // no byteswapping
- bytes[i++] = version[1];
- bytes[i++] = 0;
- bytes[i++] = 0;
- }
- else
- {
- for (int j = 0; j < bytes.Length - i; j++)
- {
- bytes[i + j] = (byte)name[j];
- }
- }
-
- return new Guid(bytes);
- }
-
- unsafe static bool TestBit(byte* ptr, int bit)
- {
- int byte_offset = bit / 8;
- int bit_offset = bit % 8;
- return (*(ptr + byte_offset) & (1 << bit_offset)) != 0;
- }
-
- unsafe static void QueryCapabilities(LinuxJoystickDetails stick,
- byte* axisbit, int axisbytes,
- byte* keybit, int keybytes,
- out int axes, out int buttons, out int hats)
- {
- // Note: since we are trying to be compatible with the SDL2 gamepad database,
- // we have to match SDL2 behavior bug-for-bug. This means:
- // HAT0-HAT3 are all reported as hats (even if the docs say that HAT1 and HAT2 can be analogue triggers)
- // DPAD buttons are reported as buttons, not as hats (unlike Windows and Mac OS X)
-
- axes = buttons = hats = 0;
- for (EvdevAxis axis = 0; axis < EvdevAxis.CNT && (int)axis < axisbytes * 8; axis++)
- {
- InputAbsInfo info;
- bool is_valid = true;
- is_valid &= TestBit(axisbit, (int)axis);
- is_valid &= Evdev.GetAbs(stick.FileDescriptor, axis, out info) >= 0;
- if (is_valid)
- {
- if (axis >= EvdevAxis.HAT0X && axis <= EvdevAxis.HAT3Y)
- {
- // Analogue hat
- stick.AxisMap.Add(axis, new AxisInfo
- {
- Axis = (JoystickAxis)(JoystickHat)hats++,
- Info = info
- });
- }
- else
- {
- // Regular axis
- stick.AxisMap.Add(axis, new AxisInfo
- {
- Axis = (JoystickAxis)axes++,
- Info = info
- });
- }
- }
- }
-
- for (EvdevButton button = 0; button < EvdevButton.Last && (int)button < keybytes * 8; button++)
- {
- if (TestBit(keybit, (int)button))
- {
- stick.ButtonMap.Add(button, buttons++);
- }
- }
- }
-
- LinuxJoystickDetails OpenJoystick(string path)
- {
- LinuxJoystickDetails stick = null;
-
- int number = GetJoystickNumber(Path.GetFileName(path));
- if (number >= 0)
- {
- int fd = -1;
- try
- {
- fd = Libc.open(path, OpenFlags.NonBlock);
- if (fd == -1)
- return null;
-
- unsafe
- {
- const int evsize = Evdev.EventCount / 8;
- const int axissize = Evdev.AxisCount / 8;
- const int keysize = Evdev.KeyCount / 8;
- byte* evbit = stackalloc byte[evsize];
- byte* axisbit = stackalloc byte[axissize];
- byte* keybit = stackalloc byte[keysize];
-
- string name;
- EvdevInputId id;
-
- // Ensure this is a joystick device
- bool is_valid = true;
-
- is_valid &= Evdev.GetBit(fd, 0, evsize, new IntPtr(evbit)) >= 0;
- is_valid &= Evdev.GetBit(fd, EvdevType.ABS, axissize, new IntPtr(axisbit)) >= 0;
- is_valid &= Evdev.GetBit(fd, EvdevType.KEY, keysize, new IntPtr(keybit)) >= 0;
-
- is_valid &= TestBit(evbit, (int)EvdevType.KEY);
- is_valid &= TestBit(evbit, (int)EvdevType.ABS);
- is_valid &= TestBit(axisbit, (int)EvdevAxis.X);
- is_valid &= TestBit(axisbit, (int)EvdevAxis.Y);
-
- is_valid &= Evdev.GetName(fd, out name) >= 0;
- is_valid &= Evdev.GetId(fd, out id) >= 0;
-
- if (is_valid)
- {
- stick = new LinuxJoystickDetails
- {
- FileDescriptor = fd,
- PathIndex = number,
- State = new JoystickState(),
- Name = name,
- Guid = CreateGuid(id, name),
- };
-
- int axes, buttons, hats;
- QueryCapabilities(stick, axisbit, axissize, keybit, keysize,
- out axes, out buttons, out hats);
-
- stick.Caps = new JoystickCapabilities(axes, buttons, hats, false);
-
- // Poll the joystick once, to initialize its state
- PollJoystick(stick);
- }
- }
-
- Debug.Print("Found joystick on path {0}", path);
- }
- catch (Exception e)
- {
- Debug.Print("Error opening joystick: {0}", e.ToString());
- }
- finally
- {
- if (stick == null && fd != -1)
- {
- // Not a joystick
- Libc.close(fd);
- }
- }
- }
-
- return stick;
- }
-
- void CloseJoystick(LinuxJoystickDetails js)
- {
- Sticks.Remove(js.FileDescriptor);
-
- Libc.close(js.FileDescriptor);
- js.FileDescriptor = -1;
- js.State = new JoystickState(); // clear joystick state
- js.Caps = new JoystickCapabilities();
- }
-
- JoystickHatState TranslateHat(int x, int y)
- {
- return new JoystickHatState(HatPositions[x, y]);
- }
-
- void PollJoystick(LinuxJoystickDetails js)
- {
- unsafe
- {
- const int EventCount = 32;
- InputEvent* events = stackalloc InputEvent[EventCount];
-
- long length = 0;
- while (true)
- {
- length = (long)Libc.read(js.FileDescriptor, (void*)events, (UIntPtr)(sizeof(InputEvent) * EventCount));
- if (length <= 0)
- break;
-
- // Only mark the joystick as connected when we actually start receiving events.
- // Otherwise, the Xbox wireless receiver will register 4 joysticks even if no
- // actual joystick is connected to the receiver.
- js.Caps.SetIsConnected(true);
- js.State.SetIsConnected(true);
-
- length /= sizeof(InputEvent);
- for (int i = 0; i < length; i++)
- {
- InputEvent *e = events + i;
- switch (e->Type)
- {
- case EvdevType.ABS:
- {
- AxisInfo axis;
- if (js.AxisMap.TryGetValue((EvdevAxis)e->Code, out axis))
- {
- if (axis.Info.Maximum > axis.Info.Minimum)
- {
- if (e->Code >= (int)EvdevAxis.HAT0X && e->Code <= (int)EvdevAxis.HAT3Y)
- {
- // We currently treat analogue hats as digital hats
- // to maintain compatibility with SDL2. We can do
- // better than this, however.
- JoystickHat hat = JoystickHat.Hat0 + (e->Code - (int)EvdevAxis.HAT0X) / 2;
- JoystickHatState pos = js.State.GetHat(hat);
- int xy_axis = (int)axis.Axis & 0x1;
- switch (xy_axis)
- {
- case 0:
- // X-axis
- pos = TranslateHat(
- e->Value.CompareTo(0) + 1,
- pos.IsUp ? 0 : pos.IsDown ? 2 : 1);
- break;
-
- case 1:
- // Y-axis
- pos = TranslateHat(
- pos.IsLeft ? 0 : pos.IsRight ? 2 : 1,
- e->Value.CompareTo(0) + 1);
- break;
- }
-
- js.State.SetHat(hat, pos);
- }
- else
- {
- // This axis represents a regular axis or trigger
- js.State.SetAxis(
- axis.Axis,
- (short)Common.HidHelper.ScaleValue(e->Value,
- axis.Info.Minimum, axis.Info.Maximum,
- short.MinValue, short.MaxValue));
- }
- }
- }
- break;
- }
-
- case EvdevType.KEY:
- {
- int button;
- if (js.ButtonMap.TryGetValue((EvdevButton)e->Code, out button))
- {
- js.State.SetButton(button, e->Value != 0);
- }
- break;
- }
- }
-
- // Create a serial number (total seconds in 24.8 fixed point format)
- int sec = (int)((long)e->Time.Seconds & 0xffffffff);
- int msec = (int)e->Time.MicroSeconds / 1000;
- int packet =
- ((sec & 0x00ffffff) << 24) |
- Common.HidHelper.ScaleValue(msec, 0, 1000, 0, 255);
- js.State.SetPacketNumber(packet);
- }
- }
- }
- }
-
- static readonly string JoystickPath = "/dev/input";
- static readonly string JoystickPathLegacy = "/dev";
-
- #endregion
-
- #region IDisposable Members
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- void Dispose(bool manual)
- {
- if (!disposed)
- {
- if (manual)
- {
- }
-
- watcher.Dispose();
- foreach (LinuxJoystickDetails js in Sticks)
- {
- CloseJoystick(js);
- }
-
- disposed = true;
- }
- }
-
- ~LinuxJoystick()
- {
- Dispose(false);
- }
-
- #endregion
-
- #region IJoystickDriver2 Members
-
- JoystickState IJoystickDriver2.GetState(int index)
- {
- LinuxJoystickDetails js = Sticks.FromIndex(index);
- if (js != null)
- {
- PollJoystick(js);
- return js.State;
- }
- return new JoystickState();
- }
-
- JoystickCapabilities IJoystickDriver2.GetCapabilities(int index)
- {
- LinuxJoystickDetails js = Sticks.FromIndex(index);
- if (js != null)
- {
- return js.Caps;
- }
- return new JoystickCapabilities();
- }
-
- Guid IJoystickDriver2.GetGuid(int index)
- {
- LinuxJoystickDetails js = Sticks.FromIndex(index);
- if (js != null)
- {
- return js.Guid;
- }
- return Guid.Empty;
- }
-
- #endregion
- }
-}
+++ /dev/null
-#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
-}
-
+++ /dev/null
-#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;
-#if !MINIMAL
-using System.Drawing;
-#endif
-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;
-
- 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 client = Location;
- return new Point(point.X - client.X, point.Y - client.Y);
- }
-
- public override Point PointToScreen(Point point)
- {
- var client = Location;
- return new Point(point.X + client.X, point.Y + client.Y);
- }
-
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- Debug.Print("[KMS] Destroying window {0}.", window.Handle);
- Drm.SetCursor(window.FD, window.DisplayDevice.Id, 0, 0, 0, 0, 0);
- 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
- }
-}
-
+++ /dev/null
-#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.
- }
- }
-}
-
--- /dev/null
+//
+// Signals.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// 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.
+using System;
+using System.Runtime.InteropServices;
+
+namespace Linux
+{
+ public enum Signal : int {
+ SIGHUP = 1,
+ SIGINT = 2,
+ SIGQUIT = 3,
+ SIGILL = 4,
+ SIGTRAP = 5,
+ SIGABRT = 6,
+ SIGIOT = 6,
+ SIGBUS = 7,
+ SIGFPE = 8,
+ SIGKILL = 9,
+ SIGUSR1 = 10,
+ SIGSEGV = 11,
+ SIGUSR2 = 12,
+ SIGPIPE = 13,
+ SIGALRM = 14,
+ SIGTERM = 15,
+ SIGSTKFLT = 16,
+ SIGCHLD = 17,
+ SIGCONT = 18,
+ SIGSTOP = 19,
+ SIGTSTP = 20,
+ SIGTTIN = 21,
+ SIGTTOU = 22,
+ SIGURG = 23,
+ SIGXCPU = 24,
+ SIGXFSZ = 25,
+ SIGVTALRM = 26,
+ SIGPROF = 27,
+ SIGWINCH = 28,
+ /// <summary>same as SIGPOLL</summary>
+ SIGIO = 29,
+ SIGPWR = 30,
+ SIGSYS = 31,
+ SIGUNUSED = 31
+ }
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate void SignalHandler(Signal signal);
+
+ public static class Kernel
+ {
+ [DllImport("libc")]
+ public static extern int signal(Signal s, SignalHandler handler);
+ }
+}
+
--- /dev/null
+//
+// TTY.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// 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.
+using System;
+using System.Runtime.InteropServices;
+
+namespace Crow.Linux.VT
+{
+ internal class TTY {
+ [DllImport("libc")]
+ static extern IntPtr ptsname(int fd);
+ [DllImport("libc")]
+ public static extern int unlockpt(int fd);
+
+ public static string GetFreePtsPath (int fd){
+ IntPtr pStr = ptsname (fd);
+ string name = Marshal.PtrToStringAnsi (pStr);
+ return name;
+ }
+ }
+}
+
--- /dev/null
+//
+// VT.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// 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.
+using System;
+using System.Runtime.InteropServices;
+
+namespace Crow.Linux.VT {
+ public enum KDMode : byte {
+ TEXT = 0x00,
+ GRAPHICS= 0x01,
+ TEXT0 = 0x02, /* obsolete */
+ TEXT1 = 0x03 /* obsolete */
+ }
+ public enum SwitchMode : sbyte {
+ AUTO = 0x00, /* auto vt switching */
+ PROCESS = 0x01, /* process controls switching */
+ ACKACQ = 0x02 /* acknowledge switch */
+ }
+ public enum KbdMode{
+ RAW = 0x00,
+ XLATE = 0x01,
+ MEDIUMRAW = 0x02,
+ UNICODE = 0x03,
+ OFF = 0x04,
+ }
+ public struct vt_mode {
+ public SwitchMode mode; /* vt mode */
+ public sbyte waitv; /* if set, hang on writes if not active */
+ public short relsig; /* signal to raise on release req */
+ public short acqsig; /* signal to raise on acquisition */
+ public short frsig; /* unused (set to 0) */
+ }
+ public struct State {
+ public ushort v_active; /* active vt */
+ public ushort v_signal; /* signal to send */
+ public ushort v_state; /* vt bitmask */
+ }
+ public struct Sizes {
+ public ushort v_rows; /* number of rows */
+ public ushort v_cols; /* number of columns */
+ public ushort v_scrollsize; /* number of lines of scrollback */
+ }
+
+ public struct KbEntry {
+ public byte kb_table;
+ public byte kb_index;
+ public ushort kb_value;
+ }
+
+ public class VTControler : IDisposable {
+ public int fd = -1;
+
+ #region ctor
+ public VTControler (string path = "/dev/tty") {
+ fd = Libc.open (path, OpenFlags.ReadWrite);
+ if (fd <= 0)
+ throw new Exception ("VTControler: unable to open " + path);
+ }
+ #endregion
+
+ /// <summary>set Graphic or Text mode for VT. </summary>
+ unsafe public KDMode KDMode {
+ get {
+ KDMode m = 0;
+ if (ioctl (fd, KDGETMODE, ref m) < 0)
+ throw new Exception ("VTControler: failed to get current TTY mode");
+ return m;
+ }
+ set {
+ if (ioctl (fd, KDSETMODE, value) < 0)
+ throw new Exception ("VTControler: failed to set current TTY mode");
+ }
+ }
+ /// <summary>set AUTO or PROCESS mode for VT. </summary>
+ unsafe public vt_mode VTMode {
+ get {
+ vt_mode m = new vt_mode();
+ if (ioctl (fd, VT_GETMODE, ref m) < 0)
+ throw new Exception ("VTControler: failed to get VTMode for current");
+ return m;
+ }
+ set {
+ if (ioctl (fd, VT_SETMODE, ref value) < 0)
+ throw new Exception ("VTControler: failed to set VTMode for current VT");
+ }
+ }
+
+ /// <summary>
+ /// Switchs to V.
+ /// </summary>
+ /// <param name="vt">Virtual Terminal to switch to</param>
+ /// <param name="waitCompleted">If set to <c>true</c> wait until switch is completed.</param>
+ public void SwitchTo (int vt, bool waitCompleted = true){
+ if (ioctl (fd, VT_ACTIVATE, vt) < 0)
+ throw new Exception ("VTControler: failed to activate TTY" + vt);
+ if (waitCompleted) {
+ if (ioctl (fd, VT_WAITACTIVE, vt) < 0)
+ throw new Exception ("VTControler: error waiting for activation of TTY" + vt);
+ }
+ }
+ public State State {
+ get {
+ State vtstats = new State ();
+ if (ioctl (fd, VT_GETSTATE, ref vtstats) < 0)
+ throw new Exception ("VirtualTerminal: unable to get TTY Stats");
+ return vtstats;
+ }
+ }
+ public int FirstAvailableVT {
+ get {
+ long freeVT = 0;
+ ioctl (fd, VT_OPENQRY, ref freeVT);
+ return (int)freeVT;
+ }
+ }
+ public int CurrentVT {
+ get {
+ return (int)State.v_active;
+ }
+ }
+
+ const int ACKACQ = 0x02;
+
+ public void AcknoledgeSwitchRequest (){
+ if (ioctl (fd, VT_RELDISP, ACKACQ)<0)
+ throw new Exception ("VTControler: failed to acknowledge switch with VT_RELDISP");
+ }
+
+ #region IDisposable implementation
+ ~VTControler(){
+ Dispose (false);
+ }
+ public void Dispose ()
+ {
+ Dispose (true);
+ GC.SuppressFinalize (this);
+ }
+ protected virtual void Dispose (bool disposing){
+ if (fd > 0)
+ Libc.close (fd);
+ fd = -1;
+ }
+ #endregion
+
+ #region IOCTLS constants
+ const uint KDSETMODE = 0x4B3A; /* set text/graphics mode */
+ const uint KDGETMODE = 0x4B3B; /* get current mode */
+
+ const uint KDGKBMODE = 0x4B44; /* gets current keyboard mode */
+ const uint KDSKBMODE = 0x4B45; /* sets current keyboard mode */
+ const uint KDGKBENT = 0x4B46; /* gets one entry in translation table */
+ const uint KDSKBENT = 0x4B47; /* sets one entry in translation table */
+
+ const uint VT_OPENQRY = 0x5600; /* find available vt */
+ const uint VT_GETMODE = 0x5601; /* get mode of active vt */
+ const uint VT_SETMODE = 0x5602; /* set mode of active vt */
+
+ const uint VT_GETSTATE = 0x5603; /* get global vt state info */
+ const uint VT_SENDSIG = 0x5604; /* signal to send to bitmask of vts */
+
+ const uint VT_RELDISP = 0x5605; /* release display */
+
+ const uint VT_ACTIVATE = 0x5606; /* make vt active */
+ const uint VT_WAITACTIVE= 0x5607; /* wait for vt active */
+ const uint VT_DISALLOCATE= 0x5608; /* free memory associated to vt */
+
+ const uint VT_RESIZE = 0x5609; /* set kernel's idea of screensize */
+ #endregion
+
+ #region ioctl overrides
+ [DllImport("libc")]
+ static extern int ioctl(int d, uint request, ref KbEntry entry);
+ [DllImport("libc")]
+ static extern int ioctl(int d, uint request, ref KbdMode value);
+ [DllImport("libc")]
+ static extern int ioctl(int d, uint request, ref long value);
+ [DllImport("libc")]
+ static extern int ioctl(int d, uint request, int value);
+ [DllImport("libc")]
+ static extern int ioctl(int d, uint request, ref int value);
+ [DllImport("libc")]
+ static extern int ioctl(int d, uint request, ref State value);
+ [DllImport("libc")]
+ static extern int ioctl(int d, uint request, ref SwitchMode value);
+ [DllImport("libc")]
+ static extern int ioctl(int d, uint request, KDMode value);
+ [DllImport("libc")]
+ static extern int ioctl(int d, uint request, ref KDMode value);
+ [DllImport("libc")]
+ static extern int ioctl(int d, uint request, vt_mode value);
+ [DllImport("libc")]
+ static extern int ioctl(int d, uint request, ref vt_mode value);
+ #endregion
+ }
+}
\ No newline at end of file
<Command type="Execute" command="${TargetName}" workingdir="${SolutionDir}/build/${ProjectConfigName}" />
</CustomCommands>
</CustomCommands>
+ <StartupObject>testDrm.Tests</StartupObject>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<Compile Include="src\DisplayResolution.cs">
<SubType>Code</SubType>
</Compile>
- <Compile Include="src\Egl.cs">
- <SubType>Code</SubType>
- </Compile>
- <Compile Include="src\Linux\DefaultCursor.cs" />
<Compile Include="src\MouseCursor.cs" />
<Compile Include="src\WindowIcon.cs" />
<Compile Include="src\Application.cs" />
- <Compile Include="src\DRMDevice.cs" />
+ <Compile Include="src\DRMContext.cs" />
+ <Compile Include="src\Linux\Bindings\Egl.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="tests.cs" />
+ <Compile Include="src\Linux\TTY.cs" />
+ <Compile Include="src\Linux\Signal.cs" />
+ <Compile Include="src\Linux\VT.cs" />
+ <Compile Include="src\Linux\DRM.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Folder Include="src\" />
- </ItemGroup>
- <ItemGroup>
- <None Include="src\Linux\LinuxFactory.cs" />
- <None Include="src\Linux\LinuxGraphicsContext.cs" />
- <None Include="src\Linux\LinuxInput.cs" />
- <None Include="src\Linux\LinuxJoystick.cs">
- <SubType>Code</SubType>
- </None>
- <None Include="src\Linux\LinuxKeyboardTTY.cs" />
- <None Include="src\Linux\LinuxNativeWindow.cs" />
- <None Include="src\Linux\LinuxWindowInfo.cs" />
- <None Include="src\Linux\LinuxDisplayDriver.cs" />
+ <Folder Include="ui\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Crow.csproj">
<Name>Crow</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="ui\menu.crow" />
+ </ItemGroup>
</Project>
\ No newline at end of file
--- /dev/null
+//
+// tests.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// 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.
+using System;
+using Crow.Linux;
+using System.Threading;
+using Linux;
+using System.Runtime.InteropServices;
+using System.Text;
+
+//using static Crow.Linux.VT.VTControler;
+using VT = Crow.Linux.VT;
+using Crow.Linux.DRI;
+
+namespace testDrm
+{
+ static class Tests
+ {
+ static void signal_handler (Signal s){
+ Console.WriteLine ("signal catched: " + s.ToString());
+ }
+ static void Main ()
+ {
+ using (GPUControler gpu = new GPUControler ()) {
+ }
+ }
+ static void signalTest (){
+ if (Kernel.signal (Signal.SIGINT, signal_handler) < 0)
+ throw new Exception ("signal handler registation failed");
+ Console.WriteLine ("Handler registered for {0}", Signal.SIGINT);
+ while (true)
+ Thread.Sleep (1);
+ }
+// static void pty_tests(){
+// int ret = 0;
+// int fd = -1;
+// fd = Libc.posix_openpt (OpenFlags.ReadWrite);
+// if (fd < 0)
+// return;
+// string newPts = Crow.Linux.VT.TTY.GetFreePtsPath (fd);
+// Console.WriteLine (newPts);
+//
+// Crow.Linux.VT.TTY.unlockpt (fd);
+// int fdPts = -1;
+// fdPts = Libc.open(newPts, OpenFlags.ReadWrite);
+// if (fdPts < 0)
+// return;
+//
+// Libc.close (fdPts);
+// Libc.close (fd);
+//
+// Console.WriteLine ("terminated succeffully");
+// }
+
+ static void tty_switch2(){
+ int previousVT = -1, appVT = -1;
+ using(VT.VTControler master = new VT.VTControler()){
+ VT.vt_mode m = master.VTMode;
+
+ Console.WriteLine ("Startup:");
+ Console.WriteLine ("\tVT{0}\t- KDMode: {1}", master.CurrentVT, master.KDMode);
+ Console.WriteLine ("\t\t- VTMode= {0}", m.mode);
+ Console.WriteLine ("\t\t- RELSIG= {0}", ((Signal)m.relsig).ToString());
+
+ previousVT = master.CurrentVT;
+ appVT = master.FirstAvailableVT;
+
+
+ master.SwitchTo (appVT);
+
+ m = master.VTMode;
+
+ try {
+ master.KDMode = VT.KDMode.GRAPHICS;
+ //m.mode = VT.SwitchMode.AUTO;
+ //master.VTMode = m;
+
+ } catch (Exception ex) {
+ Console.WriteLine (ex.ToString ());
+ }
+
+ Console.WriteLine ("Switch:");
+ Console.WriteLine ("\tVT{0}\t- KDMode: {1}", master.CurrentVT, master.KDMode);
+ Console.WriteLine ("\t\t- VTMode= {0}", m.mode);
+ Console.WriteLine ("\t\t- RELSIG= {0}", m.relsig.ToString());
+
+ if (Kernel.signal (Signal.SIGUSR1, switch_request_handle) < 0)
+ throw new Exception ("signal handler registation failed");
+ Console.WriteLine ("Handler registered for switching tty");
+ if (Kernel.signal (Signal.SIGINT, sigint_handler) < 0)
+ throw new Exception ("SIGINT handler registation failed");
+ Console.WriteLine ("SIGINT Handler registered");
+
+ while (running) {
+ Thread.Sleep (500);
+ Console.Write (".");
+ }
+
+
+ master.SwitchTo (previousVT);
+
+ Console.WriteLine ("Back to master:");
+ Console.WriteLine ("\tVT{0}\t- KDMode: {1}", master.CurrentVT, master.KDMode);
+ Console.WriteLine ("\t\t- VTMode= {0}", master.VTMode.mode);
+
+ }
+
+// using (VTControler vt = new VTControler ("/dev/tty" + appVT)) {
+// vt.CurrentMode = VT.Mode.GRAPHICS;
+// }
+
+
+ Console.WriteLine ("terminated succeffully");
+ //vtc = new VTControler ("/dev/tty" + appVT);
+ //vtc.CurrentMode = VT.Mode.GRAPHICS;
+ }
+ static bool running = true;
+ static void switch_request_handle (Signal s){
+ Console.WriteLine ("switch request catched: " + s.ToString());
+ using (VT.VTControler master = new VT.VTControler ()) {
+ Libc.write (master.fd, Encoding.ASCII.GetBytes ("this is a test string"));
+ master.AcknoledgeSwitchRequest ();
+ }
+ }
+ static void sigint_handler (Signal s){
+ Console.WriteLine ("SIGINT catched");
+ running = false;
+ }
+
+ }
+}
+
--- /dev/null
+<?xml version="1.0"?>
+<Menu>
+ <MenuItem Caption="File" Width="Fit">
+ <MenuItem Caption="New" />
+ <MenuItem Caption="Open"/>
+ <MenuItem Caption="Save"/>
+ <MenuItem Caption="Quit"/>
+ </MenuItem>
+ <MenuItem Caption="Edit" Name="edit" Width="Fit">
+ <MenuItem Caption="Cut"/>
+ <MenuItem Caption="Copy"/>
+ <MenuItem Caption="Paste"/>
+ <MenuItem Caption="Special" Name="special" Width="Fit">
+ <MenuItem Caption="Cut"/>
+ <MenuItem Caption="Copy"/>
+ <MenuItem Caption="Paste"/>
+ </MenuItem>
+ <MenuItem Caption="Special2" Name="special" Width="Fit">
+ <MenuItem Caption="Cut"/>
+ <MenuItem Caption="Copy"/>
+ <MenuItem Caption="Paste"/>
+ </MenuItem>
+ </MenuItem>
+ <MenuItem Caption="Help" Width="Fit">
+ <MenuItem Caption="About"/>
+ <MenuItem Caption="Help"/>
+ </MenuItem>
+</Menu>
\ No newline at end of file