Skip to content

Instantly share code, notes, and snippets.

@DeafMan1983
Created January 10, 2021 21:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DeafMan1983/7d9cdc0eb0c3bc7e4526113a1e4c8e69 to your computer and use it in GitHub Desktop.
Save DeafMan1983/7d9cdc0eb0c3bc7e4526113a1e4c8e69 to your computer and use it in GitHub Desktop.
That is simple Xlib/X11 GLArea for GtkSharp 2.x with Idle.Add(); Sorry it works only Linux / FreeBSD.
using System;
using System.Runtime.InteropServices;
/*
* Improved version for GLWidget as GLArea for GtkSharp 2.x
* with Idle Mode version
* Works fine:
* - Display and resize = OK!
* - Clickable in glx_context = hm, hmm, hmmm???
* - Other events with X11's glx_context with Gdk.Event???
* - Drawing triangle = OK
* -> glBegin and glEnd = OK!
* -> VAO and VBO = OK!
*
* - Other unknown???
*
* - Xlib/X11's Vulkan's Surface will come soon.
*/
namespace Gtk2SDL
{
unsafe class MainClass : Gtk.Window
{
private Gtk.DrawingArea area;
private IntPtr display, window, visualinfo, glx_context;
private const string libgdkx112 = "libgdk-x11-2.0.so.0";
private const string libx11 = "libX11.so.6";
private const string libGLX = "libGLX.so.0";
private const string libGL = "libGL.so.1";
[DllImport(libgdkx112)]
private extern static IntPtr gdk_x11_display_get_xdisplay(IntPtr gdk_display);
[DllImport(libx11)]
private extern static IntPtr gdk_x11_drawable_get_display(IntPtr gdk_window);
[DllImport(libgdkx112)]
private extern static IntPtr gdk_x11_drawable_get_xid(IntPtr gdk_window);
[DllImport(libgdkx112)]
private extern static IntPtr gdk_x11_get_default_root_xwindow();
[DllImport(libx11)]
private extern static IntPtr gdk_x11_colormap_get_xcolormap(IntPtr gdk_colormap);
[DllImport(libgdkx112)]
private extern static IntPtr gdk_x11_visual_get_xvisual(IntPtr gdk_visual);
[DllImport(libx11)]
private extern static bool XPending(IntPtr x_display);
[DllImport(libx11)]
private extern static void XReparentWindow(IntPtr x_display, IntPtr x_window, IntPtr x_window_parent, int x, int y);
[DllImport(libx11)]
private extern static void XQueryTree(IntPtr x_display, IntPtr x_window, out IntPtr x_window_root, out IntPtr x_window_parent, out IntPtr x_window_child, out uint number_children);
[DllImport(libx11)]
private extern static void XFree(IntPtr data);
[DllImport(libx11)]
private extern static void XFlush(IntPtr x_display);
[DllImport(libx11)]
private extern static void XDrawRectangle(IntPtr x_display, IntPtr x_drawable, IntPtr x_gc, int x, int y, uint w, uint h);
[DllImport(libx11)]
private extern static IntPtr XDefaultGC(IntPtr x_display, int screen_number);
[DllImport(libx11)]
private extern static IntPtr XCreateSimpleWindow(IntPtr x_display, IntPtr x_window_parent, int x, int y, uint w, uint h, uint border_width, uint border, uint background);
[DllImport(libx11)]
private extern static int XMapWindow(IntPtr x_display, IntPtr x_window);
[DllImport(libx11)]
private extern static int XUnmapWindow(IntPtr x_display, IntPtr x_window);
[DllImport(libx11)]
private extern static void XDestroyWindow(IntPtr x_display, IntPtr x_window);
[DllImport(libx11)]
private extern static void XClearWindow(IntPtr x_display, IntPtr x_window);
[DllImport(libx11)]
private extern static void XSelectInput(IntPtr x_display, IntPtr x_window, IntPtr x_event_mask);
[DllImport(libx11)]
private static extern void XNextEvent(IntPtr display, out XEvent xev);
[DllImport(libx11)]
private static extern void XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
[StructLayout(LayoutKind.Explicit)]
internal struct XEvent
{
[FieldOffset(0)]
public XEventName type;
}
public enum XEventName
{
KeyPress = 2,
KeyRelease = 3,
ButtonPress = 4,
ButtonRelease = 5,
MotionNotify = 6,
EnterNotify = 7,
LeaveNotify = 8,
FocusIn = 9,
FocusOut = 10,
KeymapNotify = 11,
Expose = 12,
GraphicsExpose = 13,
NoExpose = 14,
VisibilityNotify = 15,
CreateNotify = 16,
DestroyNotify = 17,
UnmapNotify = 18,
MapNotify = 19,
MapRequest = 20,
ReparentNotify = 21,
ConfigureNotify = 22,
ConfigureRequest = 23,
GravityNotify = 24,
ResizeRequest = 25,
CirculateNotify = 26,
CirculateRequest = 27,
PropertyNotify = 28,
SelectionClear = 29,
SelectionRequest = 30,
SelectionNotify = 31,
ColormapNotify = 32,
ClientMessage = 33,
MappingNotify = 34,
GenericEvent = 35,
LASTEvent
}
public enum XGravity
{
ForgetGravity = 0,
NorthWestGravity = 1,
NorthGravity = 2,
NorthEastGravity = 3,
WestGravity = 4,
CenterGravity = 5,
EastGravity = 6,
SouthWestGravity = 7,
SouthGravity = 8,
SouthEastGravity = 9,
StaticGravity = 10
}
[Flags]
public enum EventMask
{
NoEventMask = 0,
KeyPressMask = 1 << 0,
KeyReleaseMask = 1 << 1,
ButtonPressMask = 1 << 2,
ButtonReleaseMask = 1 << 3,
EnterWindowMask = 1 << 4,
LeaveWindowMask = 1 << 5,
PointerMotionMask = 1 << 6,
PointerMotionHintMask = 1 << 7,
Button1MotionMask = 1 << 8,
Button2MotionMask = 1 << 9,
Button3MotionMask = 1 << 10,
Button4MotionMask = 1 << 11,
Button5MotionMask = 1 << 12,
ButtonMotionMask = 1 << 13,
KeymapStateMask = 1 << 14,
ExposureMask = 1 << 15,
VisibilityChangeMask = 1 << 16,
StructureNotifyMask = 1 << 17,
ResizeRedirectMask = 1 << 18,
SubstructureNotifyMask = 1 << 19,
SubstructureRedirectMask = 1 << 20,
FocusChangeMask = 1 << 21,
PropertyChangeMask = 1 << 22,
ColormapChangeMask = 1 << 23,
OwnerGrabButtonMask = 1 << 24
}
[StructLayout(LayoutKind.Sequential)]
internal struct XWindowAttributes
{
public int x;
public int y;
public int width;
public int height;
public int border_width;
public int depth;
public IntPtr visual;
public IntPtr root;
public int c_class;
public XGravity bit_gravity;
public XGravity win_gravity;
public int backing_store;
public IntPtr backing_planes;
public IntPtr backing_pixel;
public bool save_under;
public IntPtr colormap;
public bool map_installed;
// public MapState map_state;
public IntPtr all_event_masks;
public IntPtr your_event_mask;
public IntPtr do_not_propagate_mask;
public bool override_direct;
public IntPtr screen;
}
[DllImport(libGLX)]
private extern static IntPtr glXChooseVisual(IntPtr display, int screen_numberm, ref int[] attrilists);
[DllImport(libGLX)]
private extern static IntPtr glXCreateContext(IntPtr x_display, IntPtr x_visualinfo, IntPtr share, bool direct);
[DllImport(libGLX)]
private extern static bool glXIsDirect(IntPtr display, IntPtr context);
[DllImport(libGLX)]
private extern static bool glXMakeCurrent(IntPtr x_display, IntPtr x_window, IntPtr glx_context);
[DllImport(libGLX)]
private extern static void glXSwapBuffers(IntPtr display, IntPtr drawable);
[DllImport(libGLX)]
private extern static void glXDestroyContext(IntPtr display, IntPtr glx_context);
[Flags]
public enum GLXAttribute : int
{
TRANSPARENT_BLUE_VALUE_EXT = 0x27,
GRAY_SCALE = 0x8006,
RGBA_TYPE = 0x8014,
TRANSPARENT_RGB_EXT = 0x8008,
ACCUM_BLUE_SIZE = 16,
SHARE_CONTEXT_EXT = 0x800A,
STEREO = 6,
ALPHA_SIZE = 11,
FLOAT_COMPONENTS_NV = 0x20B0,
NONE = 0x8000,
DEPTH_SIZE = 12,
TRANSPARENT_INDEX_VALUE_EXT = 0x24,
MAX_PBUFFER_WIDTH_SGIX = 0x8016,
GREEN_SIZE = 9,
X_RENDERABLE_SGIX = 0x8012,
LARGEST_PBUFFER = 0x801C,
DONT_CARE = unchecked((int)0xFFFFFFFF),
TRANSPARENT_ALPHA_VALUE_EXT = 0x28,
PSEUDO_COLOR_EXT = 0x8004,
USE_GL = 1,
SAMPLE_BUFFERS_SGIS = 100000,
TRANSPARENT_GREEN_VALUE_EXT = 0x26,
HYPERPIPE_ID_SGIX = 0x8030,
COLOR_INDEX_TYPE_SGIX = 0x8015,
SLOW_CONFIG = 0x8001,
PRESERVED_CONTENTS = 0x801B,
ACCUM_RED_SIZE = 14,
EVENT_MASK = 0x801F,
VISUAL_ID_EXT = 0x800B,
EVENT_MASK_SGIX = 0x801F,
SLOW_VISUAL_EXT = 0x8001,
TRANSPARENT_GREEN_VALUE = 0x26,
MAX_PBUFFER_WIDTH = 0x8016,
DIRECT_COLOR_EXT = 0x8003,
VISUAL_ID = 0x800B,
ACCUM_GREEN_SIZE = 15,
DRAWABLE_TYPE_SGIX = 0x8010,
SCREEN_EXT = 0x800C,
SAMPLES = 100001,
HEIGHT = 0x801E,
TRANSPARENT_INDEX_VALUE = 0x24,
SAMPLE_BUFFERS_ARB = 100000,
PBUFFER = 0x8023,
RGBA_TYPE_SGIX = 0x8014,
MAX_PBUFFER_HEIGHT = 0x8017,
FBCONFIG_ID_SGIX = 0x8013,
DRAWABLE_TYPE = 0x8010,
SCREEN = 0x800C,
RED_SIZE = 8,
VISUAL_SELECT_GROUP_SGIX = 0x8028,
VISUAL_CAVEAT_EXT = 0x20,
PSEUDO_COLOR = 0x8004,
PBUFFER_HEIGHT = 0x8040,
STATIC_GRAY = 0x8007,
PRESERVED_CONTENTS_SGIX = 0x801B,
RGBA_FLOAT_TYPE_ARB = 0x20B9,
TRANSPARENT_RED_VALUE = 0x25,
TRANSPARENT_ALPHA_VALUE = 0x28,
WINDOW = 0x8022,
X_RENDERABLE = 0x8012,
STENCIL_SIZE = 13,
TRANSPARENT_RGB = 0x8008,
LARGEST_PBUFFER_SGIX = 0x801C,
STATIC_GRAY_EXT = 0x8007,
TRANSPARENT_BLUE_VALUE = 0x27,
DIGITAL_MEDIA_PBUFFER_SGIX = 0x8024,
BLENDED_RGBA_SGIS = 0x8025,
NON_CONFORMANT_VISUAL_EXT = 0x800D,
COLOR_INDEX_TYPE = 0x8015,
TRANSPARENT_RED_VALUE_EXT = 0x25,
GRAY_SCALE_EXT = 0x8006,
WINDOW_SGIX = 0x8022,
X_VISUAL_TYPE = 0x22,
MAX_PBUFFER_HEIGHT_SGIX = 0x8017,
DOUBLEBUFFER = 5,
OPTIMAL_PBUFFER_WIDTH_SGIX = 0x8019,
X_VISUAL_TYPE_EXT = 0x22,
WIDTH_SGIX = 0x801D,
STATIC_COLOR_EXT = 0x8005,
BUFFER_SIZE = 2,
DIRECT_COLOR = 0x8003,
MAX_PBUFFER_PIXELS = 0x8018,
NONE_EXT = 0x8000,
HEIGHT_SGIX = 0x801E,
RENDER_TYPE = 0x8011,
FBCONFIG_ID = 0x8013,
TRANSPARENT_INDEX_EXT = 0x8009,
TRANSPARENT_INDEX = 0x8009,
TRANSPARENT_TYPE_EXT = 0x23,
ACCUM_ALPHA_SIZE = 17,
PBUFFER_SGIX = 0x8023,
MAX_PBUFFER_PIXELS_SGIX = 0x8018,
OPTIMAL_PBUFFER_HEIGHT_SGIX = 0x801A,
DAMAGED = 0x8020,
SAVED_SGIX = 0x8021,
TRANSPARENT_TYPE = 0x23,
MULTISAMPLE_SUB_RECT_WIDTH_SGIS = 0x8026,
NON_CONFORMANT_CONFIG = 0x800D,
BLUE_SIZE = 10,
TRUE_COLOR_EXT = 0x8002,
SAMPLES_SGIS = 100001,
SAMPLES_ARB = 100001,
TRUE_COLOR = 0x8002,
RGBA = 4,
AUX_BUFFERS = 7,
SAMPLE_BUFFERS = 100000,
SAVED = 0x8021,
MULTISAMPLE_SUB_RECT_HEIGHT_SGIS = 0x8027,
DAMAGED_SGIX = 0x8020,
STATIC_COLOR = 0x8005,
PBUFFER_WIDTH = 0x8041,
WIDTH = 0x801D,
LEVEL = 3,
CONFIG_CAVEAT = 0x20,
RENDER_TYPE_SGIX = 0x8011,
SWAP_INTERVAL_EXT = 0x20F1,
MAX_SWAP_INTERVAL_EXT = 0x20F2,
}
[DllImport(libGL)]
private extern static void glEnable(uint enable_flag);
[DllImport(libGL)]
private extern static void glViewport(int x, int y, int width, int height);
[DllImport(libGL)]
private extern static void glClearColor(float r, float g, float b, float a);
[DllImport(libGL)]
private extern static void glClear(uint clear_mask);
[DllImport(libGL)]
private extern static void glBegin(uint primitive_mode);
[DllImport(libGL)]
private extern static void glEnd();
[DllImport(libGL)]
private extern static void glColor3f(float r, float g, float b);
[DllImport(libGL)]
private extern static void glVertex3f(float x, float y, float z);
// Modern OpenGL
[DllImport(libGL)]
private extern static void glGenVertexArrays(int size, uint* vaos);
[DllImport(libGL)]
private extern static void glGenBuffers(int size, uint* vbos);
[DllImport(libGL)]
private extern static void glBindVertexArray(uint array);
[DllImport(libGL)]
private extern static void glBufferData(uint target, int size, void* data, uint usage);
[DllImport(libGL)]
private extern static void glVertexAttribPointer(uint index, int size, uint type, bool normalized, int stride, void* pointer);
[DllImport(libGL)]
private extern static void glEnableVertexAttribArray(uint obj);
[DllImport(libGL)]
private extern static void glBindBuffer(uint target, uint vbo);
[DllImport(libGL)]
private extern static uint glCreateProgram();
[DllImport(libGL)]
private extern static uint glCreateShader(uint shader_type);
[DllImport(libGL)]
private extern static void glShaderSource(uint shader_source, int count, IntPtr shader_string, int* length);
[DllImport(libGL)]
private extern static void glCompileShader(uint shader_source);
[DllImport(libGL)]
private extern static void glAttachShader(uint program, uint shader);
[DllImport(libGL)]
private extern static void glLinkProgram(uint program_source);
[DllImport(libGL)]
private extern static void glUseProgram(uint program_source);
[DllImport(libGL)]
private extern static void glDeleteShader(uint shader_source);
[DllImport(libGL)]
private extern static void glDrawArrays(uint primitive_mode, int first, int count);
private void LegacyOpenGL()
{
glBegin(0x0004);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0f, 0.5f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.5f, -0.5f, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(-0.5f, -0.5f, 0.0f);
glEnd();
}
const string vertexShaderSource = @"#version 300 es
precision highp float;
layout (location = 0) in vec4 Position0;
layout (location = 1) in vec4 Color0;
out vec4 color;
void main()
{
gl_Position = Position0;
color = Color0;
}";
const string fragmentShaderSource = @"#version 300 es
precision highp float;
in vec4 color;
out vec4 fragColor;
void main()
{
fragColor = color;
}";
private void ModernOpenGL()
{
// Shader
uint vertexshader = glCreateShader(0x8B31);
IntPtr* textPtr = stackalloc IntPtr[1];
int* lengthArray = stackalloc int[1];
lengthArray[0] = vertexShaderSource.Length;
textPtr[0] = Marshal.StringToHGlobalAnsi(vertexShaderSource);
glShaderSource(vertexshader, 1, (IntPtr)textPtr, lengthArray);
glCompileShader(vertexshader);
uint fragmentshader = glCreateShader(0x8B30);
lengthArray[0] = fragmentShaderSource.Length;
textPtr[0] = Marshal.StringToHGlobalAnsi(fragmentShaderSource);
glShaderSource(fragmentshader, 1, (IntPtr)textPtr, lengthArray);
glCompileShader(fragmentshader);
uint shaderprogram = glCreateProgram();
glAttachShader(shaderprogram, vertexshader);
glAttachShader(shaderprogram, fragmentshader);
glLinkProgram(shaderprogram);
glDeleteShader(vertexshader);
glDeleteShader(fragmentshader);
float[] vertices = new float[]
{
// vertices colors
0f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f
};
// VertexArrayObject
uint vao = 0;
uint vbo = 0;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindVertexArray(vao);
glBindBuffer(0x8892, vao);
fixed (float* verticesPtr = &vertices[0])
{
glBufferData(0x8892, vertices.Length * sizeof(float), verticesPtr, 0x88E4);
}
int stride = 8 * sizeof(float);
glVertexAttribPointer(0, 4, 0x1406, false, stride, (void*)null);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, 0x1406, false, stride, (void*)16);
glEnableVertexAttribArray(1);
glBindBuffer(0x8892, 0);
glBindVertexArray(vao);
glUseProgram(shaderprogram);
glBindVertexArray(vao);
glDrawArrays(0x0004, 0, 3);
}
private Random random = new Random();
private bool idlehandle()
{
if (display == IntPtr.Zero && window == IntPtr.Zero || glx_context == IntPtr.Zero)
{
display = gdk_x11_display_get_xdisplay(area.Display.Handle);
window = gdk_x11_drawable_get_xid(area.GdkWindow.Handle);
int[] attrlist = {
(int)GLXAttribute.RGBA_TYPE,
(int)GLXAttribute.DOUBLEBUFFER,
24,
(int)GLXAttribute.NONE
};
visualinfo = glXChooseVisual(display, area.Screen.Number, ref attrlist);
glx_context = glXCreateContext(display, visualinfo, IntPtr.Zero, true);
if (glXIsDirect(display, glx_context))
{
Console.WriteLine("GLX Context is direct = Yes!");
}
}
else
{
glXMakeCurrent(display, window, glx_context);
glEnable(0x0B71);
glViewport(0, 0, area.Allocation.Width, area.Allocation.Height);
glClear(0x00004000);
glClearColor(1f, .33f, 0f, 1.0f);
//LegacyOpenGL();
ModernOpenGL();
glXSwapBuffers(display, window);
area.Display.Sync();
}
return true;
}
public MainClass() : base(Gtk.WindowType.Toplevel)
{
Title = "X11/Xlib + GLX in GtkSharp 2";
SetDefaultSize(500, 400);
SetPosition(Gtk.WindowPosition.Center);
Gtk.VBox container = new Gtk.VBox(false, 0);
Add(container);
area = new Gtk.DrawingArea
{
AppPaintable = true
};
container.PackStart(area, true, true, 0);
area.ButtonPressEvent += buttlepresshandler;
DeleteEvent += delegate {
glXDestroyContext(display, glx_context);
Gtk.Application.Quit();
};
ShowAll();
GLib.Idle.Add(idlehandle);
}
private void buttlepresshandler(object o, Gtk.ButtonPressEventArgs args)
{
GLib.Idle.Add(delegate
{
glClearColor((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), 1.0f);
return true;
});
}
static void Main(string[] args)
{
Console.WriteLine("Hello World - X11/Xlib + GLX in GtkSharp 2");
Gtk.Application.Init();
new MainClass().Show();
Gtk.Application.Run();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment