aboutsummaryrefslogtreecommitdiff
path: root/src/mgl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mgl.c')
-rw-r--r--src/mgl.c208
1 files changed, 151 insertions, 57 deletions
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 <X11/Xutil.h>
-#include <X11/XKBlib.h>
-#include <X11/extensions/Xrender.h>
-#include <X11/extensions/Xrandr.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include <assert.h>
+
+#include <X11/Xutil.h>
+#include <X11/XKBlib.h>
+#include <X11/extensions/Xrender.h>
+#include <X11/extensions/Xrandr.h>
+#include <wayland-client.h>
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);
}