#include "../include/mgl/mgl.h" #include #include #include #include #ifndef NDEBUG #include #endif static mgl_context context; static int init_count = 0; static XErrorHandler prev_xerror = NULL; static XIOErrorHandler prev_xioerror = NULL; static int ignore_xerror(Display *display, XErrorEvent *ee) { (void)display; (void)ee; return 0; } static int ignore_xioerror(Display *display) { (void)display; return 0; } static int glx_context_init() { const int attr[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_DOUBLEBUFFER, True, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 0, None }; context.visual_info = NULL; context.fbconfig = NULL; int numfbconfigs = 0; GLXFBConfig *fbconfigs = context.gl.glXChooseFBConfig(context.connection, DefaultScreen(context.connection), attr, &numfbconfigs); for(int i = 0; i < numfbconfigs; i++) { context.visual_info = context.gl.glXGetVisualFromFBConfig(context.connection, fbconfigs[i]); if(!context.visual_info) continue; XRenderPictFormat *pict_format = XRenderFindVisualFormat(context.connection, ((XVisualInfo*)context.visual_info)->visual); if(!pict_format) { XFree(context.visual_info); context.visual_info = NULL; continue; } context.fbconfig = fbconfigs[i]; if(pict_format->direct.alphaMask > 0) break; XFree(context.visual_info); context.visual_info = NULL; } if(fbconfigs) XFree(fbconfigs); if(!context.visual_info) { fprintf(stderr, "mgl error: no appropriate visual found\n"); return -1; } return 0; } static void glx_context_deinit() { if(context.visual_info) { XFree(context.visual_info); context.visual_info = NULL; } } int mgl_init(void) { ++init_count; if(init_count == 1) { context.connection = XOpenDisplay(NULL); if(!context.connection) { fprintf(stderr, "mgl error:XOpenDisplay(NULL) failed\n"); mgl_deinit(); return -1; } prev_xerror = XSetErrorHandler(ignore_xerror); prev_xioerror = XSetIOErrorHandler(ignore_xioerror); XkbSetDetectableAutoRepeat(context.connection, True, NULL); context.wm_delete_window_atom = XInternAtom(context.connection, "WM_DELETE_WINDOW", False); if(!context.wm_delete_window_atom) { mgl_deinit(); return -1; } context.net_wm_ping_atom = XInternAtom(context.connection, "_NET_WM_PING", True); context.net_wm_pid_atom = XInternAtom(context.connection, "_NET_WM_PID", True); if(mgl_gl_load(&context.gl) != 0) { mgl_deinit(); return -1; } if(glx_context_init() != 0) { mgl_deinit(); return -1; } } return 0; } void mgl_deinit(void) { if(init_count == 1) { if(context.connection) { XSetIOErrorHandler(prev_xioerror); prev_xioerror = NULL; XSetErrorHandler(prev_xerror); prev_xerror = NULL; XCloseDisplay(context.connection); context.connection = NULL; /* GLX needs to be unloaded after closing the display on nvidia because nvidia registers cleanup callbacks on exit, that uses the x11 display. */ glx_context_deinit(); mgl_gl_unload(&context.gl); } } if(init_count > 0) --init_count; } mgl_context* mgl_get_context(void) { #ifndef NDEBUG if(init_count == 0) { fprintf(stderr, "mgl error: mgl_get_context was called before mgl_init\n"); abort(); } #endif return &context; }