#include "../include/mgl/mgl.h" #include #include #include #include #include #include #include #include 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 bool xrender_is_supported(Display *display, int *event_base, int *error_base) { *event_base = 0; *error_base = 0; if(!XRenderQueryExtension(display, event_base, error_base)) return false; int major_version = 0; int minor_version = 0; if(!XRenderQueryVersion(display, &major_version, &minor_version)) return false; return major_version > 0 || (major_version == 0 && minor_version >= 7); } static bool xrandr_is_supported(Display *display, int *event_base, int *error_base) { *event_base = 0; *error_base = 0; if(!XRRQueryExtension(display, event_base, error_base)) return false; int major_version = 0; int minor_version = 0; if(!XRRQueryVersion(display, &major_version, &minor_version)) return false; return major_version > 1 || (major_version == 1 && minor_version >= 2); } int mgl_init(void) { ++init_count; if(init_count == 1) { setenv("__GL_MaxFramesAllowed", "1", true); memset(&context, 0, sizeof(context)); context.connection = XOpenDisplay(NULL); if(!context.connection) { fprintf(stderr, "mgl error: XOpenDisplay failed\n"); mgl_deinit(); return -1; } prev_xerror = XSetErrorHandler(ignore_xerror); prev_xioerror = XSetIOErrorHandler(ignore_xioerror); if(!xrender_is_supported(context.connection, &context.render_event_base, &context.render_error_base)) { fprintf(stderr, "mgl error: x11 render extension is not supported by your X server\n"); mgl_deinit(); return -1; } if(!xrandr_is_supported(context.connection, &context.randr_event_base, &context.randr_error_base)) { fprintf(stderr, "mgl error: x11 randr extension is not supported by your X server\n"); mgl_deinit(); return -1; } XRRSelectInput(context.connection, DefaultRootWindow(context.connection), RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask | RROutputChangeNotifyMask); XInitThreads(); XkbSetDetectableAutoRepeat(context.connection, True, NULL); context.wm_delete_window_atom = XInternAtom(context.connection, "WM_DELETE_WINDOW", False); context.net_wm_ping_atom = XInternAtom(context.connection, "_NET_WM_PING", False); context.net_wm_pid_atom = XInternAtom(context.connection, "_NET_WM_PID", False); if(mgl_gl_load(&context.gl) != 0) { mgl_deinit(); return -1; } } return 0; } void mgl_deinit(void) { if(init_count == 1) { if(prev_xioerror) { XSetIOErrorHandler(prev_xioerror); prev_xioerror = NULL; } if(prev_xerror) { XSetErrorHandler(prev_xerror); prev_xerror = NULL; } if(context.connection) { 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. */ 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; }