#region --- License --- /* Copyright (c) 2006, 2007 Stefanos Apostolopoulos * Contributions from Erik Ylvisaker * See license.txt for license info */ #endregion using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using System.Diagnostics; #pragma warning disable 3019 // CLS-compliance checking #pragma warning disable 0649 // struct members not explicitly initialized #pragma warning disable 0169 // field / method is never used. #pragma warning disable 0414 // field assigned but never used. namespace OpenTK.Platform.X11 { #region Types // using XID = System.Int32; using Window = System.IntPtr; using Drawable = System.IntPtr; using Font = System.IntPtr; using Pixmap = System.IntPtr; using Cursor = System.IntPtr; using Colormap = System.IntPtr; using GContext = System.IntPtr; using KeySym = System.IntPtr; using Mask = System.IntPtr; using Atom = System.IntPtr; using VisualID = System.IntPtr; using Time = System.IntPtr; using KeyCode = System.Byte; // Or maybe ushort? using Display = System.IntPtr; using XPointer = System.IntPtr; // Randr and Xrandr using Bool = System.Boolean; using XRRScreenConfiguration = System.IntPtr; // opaque datatype using Rotation = System.UInt16; using Status = System.Int32; using SizeID = System.UInt16; #endregion #region internal static class API internal static class API { #region --- Fields --- private const string _dll_name = "libX11"; private const string _dll_name_vid = "libXxf86vm"; static Display defaultDisplay; static int defaultScreen; static Window rootWindow; static int screenCount; internal static Display DefaultDisplay { get { return defaultDisplay; } } static int DefaultScreen { get { return defaultScreen; } } //internal static Window RootWindow { get { return rootWindow; } } internal static int ScreenCount { get { return screenCount; } } internal static object Lock = new object(); #endregion static API() { Debug.Print("Initializing threaded X11: {0}.", Functions.XInitThreads().ToString()); AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit); // Bad idea - Windows.Forms will steal our events! //Type xplatui = Type.GetType("System.Windows.Forms.XplatUIX11, System.Windows.Forms"); //defaultDisplay = (IntPtr)xplatui.GetField("DisplayHandle", System.Reflection.BindingFlags.Static | // System.Reflection.BindingFlags.NonPublic).GetValue(null); defaultDisplay = Functions.XOpenDisplay(IntPtr.Zero); if (defaultDisplay == IntPtr.Zero) throw new PlatformException("Could not establish connection to the X-Server."); //defaultScreen = Functions.XDefaultScreen(DefaultDisplay); //rootWindow = Functions.XRootWindow(DefaultDisplay, DefaultScreen); screenCount = Functions.XScreenCount(DefaultDisplay); //Debug.Print("Default Display: {0}, Default Screen: {1}, Default Root Window: {2}, Screen Count: {3}", // DefaultDisplay, DefaultScreen, RootWindow, ScreenCount); Debug.Print("Display connection: {0}, Screen count: {1}", DefaultDisplay, ScreenCount); } static void CurrentDomain_ProcessExit(object sender, EventArgs e) { if (defaultDisplay != IntPtr.Zero) { Functions.XCloseDisplay(defaultDisplay); defaultDisplay = IntPtr.Zero; defaultScreen = 0; rootWindow = IntPtr.Zero; } } // Display management //[DllImport(_dll_name, EntryPoint = "XOpenDisplay")] //extern public static IntPtr OpenDisplay([MarshalAs(UnmanagedType.LPTStr)] string display_name); //[DllImport(_dll_name, EntryPoint = "XCloseDisplay")] //extern public static void CloseDisplay(Display display); //[DllImport(_dll_name, EntryPoint = "XCreateColormap")] //extern public static IntPtr CreateColormap(Display display, Window window, IntPtr visual, int alloc); #region Window handling [Obsolete("Use XCreateWindow instead")] [DllImport(_dll_name, EntryPoint = "XCreateWindow")] public extern static Window CreateWindow( Display display, Window parent, int x, int y, //uint width, uint height, int width, int height, //uint border_width, int border_width, int depth, //uint @class, int @class, IntPtr visual, [MarshalAs(UnmanagedType.SysUInt)] CreateWindowMask valuemask, SetWindowAttributes attributes ); [DllImport(_dll_name, EntryPoint = "XCreateSimpleWindow")] public extern static Window CreateSimpleWindow( Display display, Window parent, int x, int y, int width, int height, int border_width, long border, long background ); [DllImport(_dll_name, EntryPoint = "XResizeWindow")] public extern static int XResizeWindow(Display display, Window window, int width, int height); [DllImport(_dll_name, EntryPoint = "XDestroyWindow")] public extern static void DestroyWindow(Display display, Window window); [DllImport(_dll_name, EntryPoint = "XMapWindow")] extern public static void MapWindow(Display display, Window window); [DllImport(_dll_name, EntryPoint = "XMapRaised")] extern public static void MapRaised(Display display, Window window); #endregion [DllImport(_dll_name, EntryPoint = "XDefaultVisual")] extern public static IntPtr DefaultVisual(Display display, int screen_number); #region XFree /// /// Frees the memory used by an X structure. Only use on unmanaged structures! /// /// A pointer to the structure that will be freed. [DllImport(_dll_name, EntryPoint = "XFree")] extern public static void Free(IntPtr buffer); #endregion #region Event queue management [System.Security.SuppressUnmanagedCodeSecurity] [DllImport(_dll_name, EntryPoint = "XEventsQueued")] extern public static int EventsQueued(Display display, int mode); [System.Security.SuppressUnmanagedCodeSecurity] [DllImport(_dll_name, EntryPoint = "XPending")] extern public static int Pending(Display display); //[System.Security.SuppressUnmanagedCodeSecurity] [DllImport(_dll_name, EntryPoint = "XNextEvent")] extern public static void NextEvent( Display display, [MarshalAs(UnmanagedType.AsAny)][In, Out]object e); [DllImport(_dll_name, EntryPoint = "XNextEvent")] extern public static void NextEvent(Display display, [In, Out] IntPtr e); [DllImport(_dll_name, EntryPoint = "XPeekEvent")] extern public static void PeekEvent( Display display, [MarshalAs(UnmanagedType.AsAny)][In, Out]object event_return ); [DllImport(_dll_name, EntryPoint = "XPeekEvent")] extern public static void PeekEvent(Display display, [In, Out]XEvent event_return); [DllImport(_dll_name, EntryPoint = "XSendEvent")] [return: MarshalAs(UnmanagedType.Bool)] extern public static bool SendEvent(Display display, Window window, bool propagate, [MarshalAs(UnmanagedType.SysInt)]EventMask event_mask, ref XEvent event_send); /// /// The XSelectInput() function requests that the X server report the events associated /// with the specified event mask. /// /// Specifies the connection to the X server. /// Specifies the window whose events you are interested in. /// Specifies the event mask. /// /// Initially, X will not report any of these events. /// Events are reported relative to a window. /// If a window is not interested in a device event, /// it usually propagates to the closest ancestor that is interested, /// unless the do_not_propagate mask prohibits it. /// Setting the event-mask attribute of a window overrides any previous call for the same window but not for other clients. Multiple clients can select for the same events on the same window with the following restrictions: /// Multiple clients can select events on the same window because their event masks are disjoint. When the X server generates an event, it reports it to all interested clients. /// Only one client at a time can select CirculateRequest, ConfigureRequest, or MapRequest events, which are associated with the event mask SubstructureRedirectMask. /// Only one client at a time can select a ResizeRequest event, which is associated with the event mask ResizeRedirectMask. /// Only one client at a time can select a ButtonPress event, which is associated with the event mask ButtonPressMask. /// The server reports the event to all interested clients. /// XSelectInput() can generate a BadWindow error. /// [DllImport(_dll_name, EntryPoint = "XSelectInput")] public static extern void SelectInput(Display display, Window w, EventMask event_mask); /// /// When the predicate procedure finds a match, XCheckIfEvent() copies the matched event into the client-supplied XEvent structure and returns True. (This event is removed from the queue.) If the predicate procedure finds no match, XCheckIfEvent() returns False, and the output buffer will have been flushed. All earlier events stored in the queue are not discarded. /// /// Specifies the connection to the X server. /// Returns a copy of the matched event's associated structure. /// Specifies the procedure that is to be called to determine if the next event in the queue matches what you want /// Specifies the user-supplied argument that will be passed to the predicate procedure. /// true if the predicate returns true for some event, false otherwise [DllImport(_dll_name, EntryPoint = "XCheckIfEvent")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CheckIfEvent(Display display, ref XEvent event_return, /*[MarshalAs(UnmanagedType.FunctionPtr)] */ CheckEventPredicate predicate, /*XPointer*/ IntPtr arg); [DllImport(_dll_name, EntryPoint = "XIfEvent")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool IfEvent(Display display, ref XEvent event_return, /*[MarshalAs(UnmanagedType.FunctionPtr)] */ CheckEventPredicate predicate, /*XPointer*/ IntPtr arg); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate bool CheckEventPredicate(Display display, ref XEvent @event, IntPtr arg); [DllImport(_dll_name, EntryPoint = "XCheckMaskEvent")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CheckMaskEvent(Display display, EventMask event_mask, ref XEvent event_return); #endregion #region Pointer and Keyboard functions [DllImport(_dll_name, EntryPoint = "XGrabPointer")] extern public static ErrorCodes GrabPointer(Display display, IntPtr grab_window, bool owner_events, int event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, int time); [DllImport(_dll_name, EntryPoint = "XUngrabPointer")] extern public static ErrorCodes UngrabPointer(Display display, int time); [DllImport(_dll_name, EntryPoint = "XGrabKeyboard")] extern public static ErrorCodes GrabKeyboard(Display display, IntPtr grab_window, bool owner_events, GrabMode pointer_mode, GrabMode keyboard_mode, int time); [DllImport(_dll_name, EntryPoint = "XUngrabKeyboard")] extern public static void UngrabKeyboard(Display display, int time); /// /// The XGetKeyboardMapping() function returns the symbols for the specified number of KeyCodes starting with first_keycode. /// /// Specifies the connection to the X server. /// Specifies the first KeyCode that is to be returned. /// Specifies the number of KeyCodes that are to be returned /// Returns the number of KeySyms per KeyCode. /// /// /// The value specified in first_keycode must be greater than or equal to min_keycode as returned by XDisplayKeycodes(), or a BadValue error results. In addition, the following expression must be less than or equal to max_keycode as returned by XDisplayKeycodes(): /// first_keycode + keycode_count - 1 /// If this is not the case, a BadValue error results. The number of elements in the KeySyms list is: /// keycode_count * keysyms_per_keycode_return /// KeySym number N, counting from zero, for KeyCode K has the following index in the list, counting from zero: /// (K - first_code) * keysyms_per_code_return + N /// The X server arbitrarily chooses the keysyms_per_keycode_return value to be large enough to report all requested symbols. A special KeySym value of NoSymbol is used to fill in unused elements for individual KeyCodes. To free the storage returned by XGetKeyboardMapping(), use XFree(). /// XGetKeyboardMapping() can generate a BadValue error. /// Diagnostics: /// BadValue: Some numeric value falls outside the range of values accepted by the request. Unless a specific range is specified for an argument, the full range defined by the argument's type is accepted. Any argument defined as a set of alternatives can generate this error. /// [DllImport(_dll_name, EntryPoint = "XGetKeyboardMapping")] public static extern KeySym GetKeyboardMapping(Display display, KeyCode first_keycode, int keycode_count, ref int keysyms_per_keycode_return); /// /// The XDisplayKeycodes() function returns the min-keycodes and max-keycodes supported by the specified display. /// /// Specifies the connection to the X server. /// Returns the minimum number of KeyCodes /// Returns the maximum number of KeyCodes. /// The minimum number of KeyCodes returned is never less than 8, and the maximum number of KeyCodes returned is never greater than 255. Not all KeyCodes in this range are required to have corresponding keys. [DllImport(_dll_name, EntryPoint = "XDisplayKeycodes")] public static extern void DisplayKeycodes(Display display, ref int min_keycodes_return, ref int max_keycodes_return); #endregion #region Xf86VidMode internal structures [StructLayout(LayoutKind.Sequential)] internal struct XF86VidModeModeLine { short hdisplay; /* Number of display pixels horizontally */ short hsyncstart; /* Horizontal sync start */ short hsyncend; /* Horizontal sync end */ short htotal; /* Total horizontal pixels */ short vdisplay; /* Number of display pixels vertically */ short vsyncstart; /* Vertical sync start */ short vsyncend; /* Vertical sync start */ short vtotal; /* Total vertical pixels */ int flags; /* Mode flags */ int privsize; /* Size of private */ IntPtr _private; /* Server privates */ } /// /// Specifies an XF86 display mode. /// [StructLayout(LayoutKind.Sequential)] internal struct XF86VidModeModeInfo { /// /// Pixel clock. /// public int dotclock; /// /// Number of display pixels horizontally /// public short hdisplay; /// /// Horizontal sync start /// public short hsyncstart; /// /// Horizontal sync end /// public short hsyncend; /// /// Total horizontal pixel /// public short htotal; /// /// /// public short hskew; /// /// Number of display pixels vertically /// public short vdisplay; /// /// Vertical sync start /// public short vsyncstart; /// /// Vertical sync end /// public short vsyncend; /// /// Total vertical pixels /// public short vtotal; /// /// /// public short vskew; /// /// Mode flags /// public int flags; int privsize; /* Size of private */ IntPtr _private; /* Server privates */ } //Monitor information: [StructLayout(LayoutKind.Sequential)] internal struct XF86VidModeMonitor { [MarshalAs(UnmanagedType.LPStr)] string vendor; /* Name of manufacturer */ [MarshalAs(UnmanagedType.LPStr)] string model; /* Model name */ float EMPTY; /* unused, for backward compatibility */ byte nhsync; /* Number of horiz sync ranges */ /*XF86VidModeSyncRange* */ IntPtr hsync;/* Horizontal sync ranges */ byte nvsync; /* Number of vert sync ranges */ /*XF86VidModeSyncRange* */ IntPtr vsync;/* Vertical sync ranges */ } [StructLayout(LayoutKind.Sequential)] internal struct XF86VidModeSyncRange { float hi; /* Top of range */ float lo; /* Bottom of range */ } [StructLayout(LayoutKind.Sequential)] internal struct XF86VidModeNotifyEvent { int type; /* of event */ ulong serial; /* # of last request processed by server */ bool send_event; /* true if this came from a SendEvent req */ Display display; /* Display the event was read from */ IntPtr root; /* root window of event screen */ int state; /* What happened */ int kind; /* What happened */ bool forced; /* extents of new region */ /* Time */ IntPtr time; /* event timestamp */ } [StructLayout(LayoutKind.Sequential)] internal struct XF86VidModeGamma { float red; /* Red Gamma value */ float green; /* Green Gamma value */ float blue; /* Blue Gamma value */ } #endregion #region libXxf86vm Functions [DllImport(_dll_name_vid)] extern public static bool XF86VidModeQueryExtension( Display display, out int event_base_return, out int error_base_return); /* [DllImport(_dll_name_vid)] extern public static bool XF86VidModeSwitchMode( Display display, int screen, int zoom); */ [DllImport(_dll_name_vid)] extern public static bool XF86VidModeSwitchToMode( Display display, int screen, IntPtr /*XF86VidModeModeInfo* */ modeline); [DllImport(_dll_name_vid)] extern public static bool XF86VidModeQueryVersion( Display display, out int major_version_return, out int minor_version_return); [DllImport(_dll_name_vid)] extern public static bool XF86VidModeGetAllModeLines( Display display, int screen, out int modecount_return, /*XF86VidModeModeInfo*** <-- yes, that's three *'s. */ out IntPtr modesinfo); [DllImport(_dll_name_vid)] extern public static bool XF86VidModeSetViewPort( Display display, int screen, int x, int y); /* Bool XF86VidModeSetClientVersion( Display *display); Bool XF86VidModeGetModeLine( Display *display, int screen, int *dotclock_return, XF86VidModeModeLine *modeline); Bool XF86VidModeDeleteModeLine( Display *display, int screen, XF86VidModeModeInfo *modeline); Bool XF86VidModeModModeLine( Display *display, int screen, XF86VidModeModeLine *modeline); Status XF86VidModeValidateModeLine( Display *display, int screen, XF86VidModeModeLine *modeline); Bool XF86VidModeLockModeSwitch( Display *display, int screen, int lock); Bool XF86VidModeGetMonitor( Display *display, int screen, XF86VidModeMonitor *monitor); Bool XF86VidModeGetViewPort( Display *display, int screen, int *x_return, int *y_return); XF86VidModeGetDotClocks( Display *display, int screen, int *flags return, int *number of clocks return, int *max dot clock return, int **clocks return); XF86VidModeGetGamma( Display *display, int screen, XF86VidModeGamma *Gamma); XF86VidModeSetGamma( Display *display, int screen, XF86VidModeGamma *Gamma); XF86VidModeGetGammaRamp( Display *display, int screen, int size, unsigned short *red array, unsigned short *green array, unsigned short *blue array); XF86VidModeSetGammaRamp( Display *display, int screen, int size, unsigned short *red array, unsigned short *green array, unsigned short *blue array); XF86VidModeGetGammaRampSize( Display *display, int screen, int *size); * */ #endregion [DllImport(_dll_name, EntryPoint = "XLookupKeysym")] public static extern KeySym LookupKeysym(ref XKeyEvent key_event, int index); } #endregion #region X11 Structures #region internal class XVisualInfo [StructLayout(LayoutKind.Sequential)] struct XVisualInfo { public IntPtr Visual; public VisualID VisualID; public int Screen; public int Depth; public XVisualClass Class; public long RedMask; public long GreenMask; public long blueMask; public int ColormapSize; public int BitsPerRgb; public override string ToString() { return String.Format("id ({0}), screen ({1}), depth ({2}), class ({3})", VisualID, Screen, Depth, Class); } } #endregion #region internal class SetWindowAttributes [StructLayout(LayoutKind.Sequential), Obsolete("Use XSetWindowAttributes instead")] internal class SetWindowAttributes { /// /// background, None, or ParentRelative /// public Pixmap background_pixmap; /// /// background pixel /// public long background_pixel; /// /// border of the window or CopyFromParent /// public Pixmap border_pixmap; /// /// border pixel value /// public long border_pixel; /// /// one of bit gravity values /// public int bit_gravity; /// /// one of the window gravity values /// public int win_gravity; /// /// NotUseful, WhenMapped, Always /// public int backing_store; /// /// planes to be preserved if possible /// public long backing_planes; /// /// value to use in restoring planes /// public long backing_pixel; /// /// should bits under be saved? (popups) /// public bool save_under; /// /// set of events that should be saved /// public EventMask event_mask; /// /// set of events that should not propagate /// public long do_not_propagate_mask; /// /// boolean value for override_redirect /// public bool override_redirect; /// /// color map to be associated with window /// public Colormap colormap; /// /// cursor to be displayed (or None) /// public Cursor cursor; } #endregion #region internal struct SizeHints [StructLayout(LayoutKind.Sequential)] internal struct SizeHints { public long flags; /* marks which fields in this structure are defined */ public int x, y; /* Obsolete */ public int width, height; /* Obsolete */ public int min_width, min_height; public int max_width, max_height; public int width_inc, height_inc; public Rectangle min_aspect, max_aspect; public int base_width, base_height; public int win_gravity; internal struct Rectangle { public int x; /* numerator */ public int y; /* denominator */ private void stop_the_compiler_warnings() { x = y = 0; } } /* this structure may be extended in the future */ } #endregion #region internal struct XRRScreenSize internal struct XRRScreenSize { internal int Width, Height; internal int MWidth, MHeight; }; #endregion #region unsafe internal struct Screen unsafe internal struct Screen { XExtData ext_data; /* hook for extension to hang buffer */ IntPtr display; /* back pointer to display structure */ /* _XDisplay */ Window root; /* Root window id. */ int width, height; /* width and height of screen */ int mwidth, mheight; /* width and height of in millimeters */ int ndepths; /* number of depths possible */ //Depth *depths; /* list of allowable depths on the screen */ int root_depth; /* bits per pixel */ //Visual* root_visual; /* root visual */ IntPtr default_gc; /* GC for the root root visual */ // GC Colormap cmap; /* default color map */ UIntPtr white_pixel; // unsigned long UIntPtr black_pixel; /* White and Black pixel values */ // unsigned long int max_maps, min_maps; /* max and min color maps */ int backing_store; /* Never, WhenMapped, Always */ Bool save_unders; long root_input_mask; /* initial root input mask */ } #endregion #region unsafe internal class XExtData unsafe internal class XExtData { int number; /* number returned by XRegisterExtension */ XExtData next; /* next item on list of buffer for structure */ delegate int FreePrivateDelegate(XExtData extension); FreePrivateDelegate FreePrivate; /* called to free private storage */ XPointer private_data; /* buffer private to this extension. */ }; #endregion #region Motif [StructLayout(LayoutKind.Sequential)] internal struct MotifWmHints { internal IntPtr flags; internal IntPtr functions; internal IntPtr decorations; internal IntPtr input_mode; internal IntPtr status; public override string ToString () { return string.Format("MotifWmHints