From 26c56565cc0573ce23eb8d172a6765bce1f657ce Mon Sep 17 00:00:00 2001 From: dec05eba Date: Fri, 18 Apr 2025 12:55:00 +0200 Subject: Separate glx and egl from window system to prepare for wayland --- src/mgl.c | 208 +++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 151 insertions(+), 57 deletions(-) (limited to 'src/mgl.c') diff --git a/src/mgl.c b/src/mgl.c index 3b5adf2..d0e344f 100644 --- a/src/mgl.c +++ b/src/mgl.c @@ -1,18 +1,21 @@ #include "../include/mgl/mgl.h" -#include -#include -#include -#include #include #include #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 bool connected_to_x_server = false; +static bool connected_to_display_server = false; static int mgl_x_error_handler(Display *display, XErrorEvent *ee) { (void)display; @@ -22,7 +25,8 @@ static int mgl_x_error_handler(Display *display, XErrorEvent *ee) { static int mgl_x_io_error_handler(Display *display) { (void)display; - connected_to_x_server = false; + /* TODO: Do something equivalent for wayland */ + connected_to_display_server = false; return 0; } @@ -54,45 +58,112 @@ static bool xrandr_is_supported(Display *display, int *event_base, int *error_ba 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)); +static bool is_xwayland(Display *dpy) { + int opcode, event, error; + return XQueryExtension(dpy, "XWAYLAND", &opcode, &event, &error); +} +static int mgl_init_x11(void) { + if(!context.connection) context.connection = XOpenDisplay(NULL); - if(!context.connection) { - fprintf(stderr, "mgl error: XOpenDisplay failed\n"); - mgl_deinit(); - return -1; - } - connected_to_x_server = true; - /* If we dont call we will never get a MappingNotify until a key has been pressed */ - XKeysymToKeycode(context.connection, XK_F1); - prev_xerror = XSetErrorHandler(mgl_x_error_handler); - prev_xioerror = XSetIOErrorHandler(mgl_x_io_error_handler); + if(!context.connection) { + fprintf(stderr, "mgl error: mgl_init_x11: failed to connect to the X11 server\n"); + mgl_deinit(); + return -1; + } + connected_to_display_server = true; + /* If we dont call we will never get a MappingNotify until a key has been pressed */ + XKeysymToKeycode(context.connection, XK_F1); - 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; - } + prev_xerror = XSetErrorHandler(mgl_x_error_handler); + prev_xioerror = XSetIOErrorHandler(mgl_x_io_error_handler); - 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; + context.display_server_is_wayland = is_xwayland(context.connection); + + if(!xrender_is_supported(context.connection, &context.render_event_base, &context.render_error_base)) { + fprintf(stderr, "mgl error: mgl_init_x11: 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: mgl_init_x11: 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); + return 0; +} + +static int mgl_init_wayland(void) { + context.connection = wl_display_connect(NULL); + if(!context.connection) { + fprintf(stderr, "mgl error: mgl_init_wayland: failed to connect to the Wayland server\n"); + mgl_deinit(); + return -1; + } + connected_to_display_server = true; + return 0; +} + +static int mgl_init_native(void) { + context.connection = XOpenDisplay(NULL); + if(context.connection) { + context.display_server_is_wayland = is_xwayland(context.connection); + if(context.display_server_is_wayland) { + XCloseDisplay(context.connection); + context.connection = NULL; } + } else { + context.display_server_is_wayland = true; + } - XRRSelectInput(context.connection, DefaultRootWindow(context.connection), RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask | RROutputChangeNotifyMask); + if(context.display_server_is_wayland) { + context.window_system = MGL_WINDOW_SYSTEM_WAYLAND; + if(mgl_init_wayland() != 0) + return -1; + } else { + context.window_system = MGL_WINDOW_SYSTEM_X11; + if(mgl_init_x11() != 0) + return -1; + } - XInitThreads(); - XkbSetDetectableAutoRepeat(context.connection, True, NULL); + return 0; +} - 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); +int mgl_init(mgl_window_system window_system) { + ++init_count; + if(init_count == 1) { + setenv("__GL_MaxFramesAllowed", "1", true); + memset(&context, 0, sizeof(context)); + context.window_system = window_system; + + switch(window_system) { + case MGL_WINDOW_SYSTEM_NATIVE: { + if(mgl_init_native() != 0) + return -1; + break; + } + case MGL_WINDOW_SYSTEM_X11: { + if(mgl_init_x11() != 0) + return -1; + break; + } + case MGL_WINDOW_SYSTEM_WAYLAND: { + if(mgl_init_wayland() != 0) + return -1; + break; + } + } if(mgl_gl_load(&context.gl) != 0) { mgl_deinit(); @@ -102,30 +173,49 @@ int mgl_init(void) { return 0; } -void mgl_deinit(void) { - if(init_count == 1) { - if(context.connection) { - XCloseDisplay(context.connection); - context.connection = NULL; - connected_to_x_server = false; +static void mgl_deinit_x11(void) { + if(context.connection) { + XCloseDisplay(context.connection); + context.connection = NULL; + connected_to_display_server = false; + } - /* - 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(prev_xioerror) { + XSetIOErrorHandler(prev_xioerror); + prev_xioerror = NULL; + } - if(prev_xioerror) { - XSetIOErrorHandler(prev_xioerror); - prev_xioerror = NULL; - } + if(prev_xerror) { + XSetErrorHandler(prev_xerror); + prev_xerror = NULL; + } +} - if(prev_xerror) { - XSetErrorHandler(prev_xerror); - prev_xerror = NULL; +static void mgl_deinit_wayland(void) { + if(context.connection) { + wl_display_disconnect(context.connection); + context.connection = NULL; + connected_to_display_server = false; + } +} + +void mgl_deinit(void) { + if(init_count == 1) { + switch(context.window_system) { + case MGL_WINDOW_SYSTEM_NATIVE: + assert(false); + break; + case MGL_WINDOW_SYSTEM_X11: { + mgl_deinit_x11(); + break; + } + case MGL_WINDOW_SYSTEM_WAYLAND: { + mgl_deinit_wayland(); + break; + } } + mgl_gl_unload(&context.gl); context.current_window = NULL; } @@ -144,11 +234,15 @@ mgl_context* mgl_get_context(void) { } bool mgl_is_connected_to_display_server(void) { - return connected_to_x_server; + return connected_to_display_server; } void mgl_ping_display_server(void) { - if(context.connection) { + if(!context.connection) + return; + + // TODO: Do something equivalent for wayland + if(context.window_system == MGL_WINDOW_SYSTEM_X11) { XNoOp(context.connection); XFlush(context.connection); } -- cgit v1.2.3-70-g09d2