aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mgl/graphics/backend/egl.h8
-rw-r--r--include/mgl/graphics/backend/glx.h8
-rw-r--r--include/mgl/graphics/backend/graphics.h48
-rw-r--r--include/mgl/mgl.h10
-rw-r--r--include/mgl/window/wayland.h8
-rw-r--r--include/mgl/window/window.h19
-rw-r--r--include/mgl/window/x11.h8
-rw-r--r--include/mgl/window/x11/window.h9
-rw-r--r--meson.build9
-rw-r--r--project.conf4
-rw-r--r--src/graphics/backend/egl.c246
-rw-r--r--src/graphics/backend/glx.c174
-rw-r--r--src/graphics/backend/graphics.c54
-rw-r--r--src/mgl.c208
-rw-r--r--src/window/wayland.c214
-rw-r--r--src/window/window.c21
-rw-r--r--src/window/x11.c (renamed from src/window/x11/window.c)723
-rw-r--r--tests/main.c2
18 files changed, 1122 insertions, 651 deletions
diff --git a/include/mgl/graphics/backend/egl.h b/include/mgl/graphics/backend/egl.h
new file mode 100644
index 0000000..5dede61
--- /dev/null
+++ b/include/mgl/graphics/backend/egl.h
@@ -0,0 +1,8 @@
+#ifndef MGL_GRAPHICS_EGL
+#define MGL_GRAPHICS_EGL
+
+#include "graphics.h"
+
+bool mgl_graphics_egl_init(mgl_graphics *self);
+
+#endif /* MGL_GRAPHICS_EGL */
diff --git a/include/mgl/graphics/backend/glx.h b/include/mgl/graphics/backend/glx.h
new file mode 100644
index 0000000..e2a5758
--- /dev/null
+++ b/include/mgl/graphics/backend/glx.h
@@ -0,0 +1,8 @@
+#ifndef MGL_GRAPHICS_GLX
+#define MGL_GRAPHICS_GLX
+
+#include "graphics.h"
+
+bool mgl_graphics_glx_init(mgl_graphics *self);
+
+#endif /* MGL_GRAPHICS_GLX */
diff --git a/include/mgl/graphics/backend/graphics.h b/include/mgl/graphics/backend/graphics.h
new file mode 100644
index 0000000..59f4a0d
--- /dev/null
+++ b/include/mgl/graphics/backend/graphics.h
@@ -0,0 +1,48 @@
+#ifndef MGL_GRAPHICS_H
+#define MGL_GRAPHICS_H
+
+#include <stdbool.h>
+
+/* Each window should have its own mgl_graphics */
+
+typedef struct mgl_graphics mgl_graphics;
+typedef void* mgl_window_handle;
+
+typedef enum {
+ MGL_GRAPHICS_API_GLX, /* Only available when using X11 (or XWayland) */
+ MGL_GRAPHICS_API_EGL
+} mgl_graphics_api;
+
+struct mgl_graphics {
+ void (*deinit)(mgl_graphics *self);
+ bool (*make_context_current)(mgl_graphics *self, mgl_window_handle window);
+ void (*swap_buffers)(mgl_graphics *self, mgl_window_handle window);
+ bool (*set_swap_interval)(mgl_graphics *self, mgl_window_handle window, bool enabled);
+ void* (*get_xvisual_info)(mgl_graphics *self);
+
+ /* Optional */
+ void* (*get_display)(mgl_graphics *self);
+ void* (*get_context)(mgl_graphics *self);
+
+ void *impl;
+
+ mgl_graphics_api graphics_api;
+ bool alpha;
+};
+
+typedef struct {
+ mgl_graphics_api graphics_api; /* The graphics api to use. MGL_GRAPHICS_API_EGL by default */
+ bool alpha; /* Support window alpha transparency. False by default */
+} mgl_graphics_create_params;
+
+bool mgl_graphics_init(mgl_graphics *self, const mgl_graphics_create_params *params);
+void mgl_graphics_deinit(mgl_graphics *self);
+
+bool mgl_graphics_make_context_current(mgl_graphics *self, mgl_window_handle window);
+void mgl_graphics_swap_buffers(mgl_graphics *self, mgl_window_handle window);
+bool mgl_graphics_set_swap_interval(mgl_graphics *self, mgl_window_handle window, bool enabled);
+void* mgl_graphics_get_xvisual_info(mgl_graphics *self);
+void* mgl_graphics_get_display(mgl_graphics *self);
+void* mgl_graphics_get_context(mgl_graphics *self);
+
+#endif /* MGL_GRAPHICS_H */
diff --git a/include/mgl/mgl.h b/include/mgl/mgl.h
index c5d1f2d..fd3367e 100644
--- a/include/mgl/mgl.h
+++ b/include/mgl/mgl.h
@@ -9,7 +9,15 @@ typedef void* mgl_connection;
typedef struct mgl_context mgl_context;
typedef struct mgl_window mgl_window;
+typedef enum {
+ MGL_WINDOW_SYSTEM_NATIVE, /* Use X11 on X11 and Wayland on Wayland */
+ MGL_WINDOW_SYSTEM_X11, /* Use X11 on X11 and XWayland on Wayland */
+ MGL_WINDOW_SYSTEM_WAYLAND, /* Use Wayland. If user runs on X11 then it fails to connect */
+} mgl_window_system;
+
struct mgl_context {
+ bool display_server_is_wayland;
+ mgl_window_system window_system; /* Window system requested with mgl_init */
mgl_connection connection;
mgl_gl gl;
mgl_window *current_window;
@@ -30,7 +38,7 @@ struct mgl_context {
Returns non-0 value on failure.
Note: not thread safe.
*/
-int mgl_init(void);
+int mgl_init(mgl_window_system window_system);
/*
Safe to call multiple times, but will only be deinitialized the last time called.
diff --git a/include/mgl/window/wayland.h b/include/mgl/window/wayland.h
new file mode 100644
index 0000000..081f87c
--- /dev/null
+++ b/include/mgl/window/wayland.h
@@ -0,0 +1,8 @@
+#ifndef MGL_WINDOW_WAYLAND_H
+#define MGL_WINDOW_WAYLAND_H
+
+#include "window.h"
+
+bool mgl_window_wayland_init(mgl_window *self, const char *title, const mgl_window_create_params *params, mgl_window_handle existing_window);
+
+#endif /* MGL_WINDOW_WAYLAND_H */
diff --git a/include/mgl/window/window.h b/include/mgl/window/window.h
index 07c19ca..c788e9f 100644
--- a/include/mgl/window/window.h
+++ b/include/mgl/window/window.h
@@ -2,6 +2,7 @@
#define MGL_WINDOW_H
#include "../graphics/color.h"
+#include "../graphics/backend/graphics.h"
#include "../system/vec.h"
#include "../system/clock.h"
#include "key.h"
@@ -15,8 +16,8 @@
typedef union _XEvent XEvent;
typedef struct mgl_event mgl_event;
-/* x11 window handle. TODO: Add others when wayland, etc is added */
-typedef unsigned long mgl_window_handle;
+/* x11/wayland window handle */
+typedef void* mgl_window_handle;
typedef void* mgl_connection;
typedef struct mgl_window mgl_window;
@@ -41,16 +42,6 @@ typedef struct {
} mgl_monitor;
typedef enum {
- MGL_WINDOW_SYSTEM_NATIVE, /* Use X11 on X11 and Wayland on Wayland */
- MGL_WINDOW_SYSTEM_X11 /* Use X11 on X11 and XWayland on Wayland */
-} mgl_window_system;
-
-typedef enum {
- MGL_RENDER_API_GLX, /* Only available when using X11 (or XWayland) */
- MGL_RENDER_API_EGL
-} mgl_render_api;
-
-typedef enum {
MGL_WINDOW_TYPE_NORMAL,
MGL_WINDOW_TYPE_DIALOG, /* Also sets the window as always on top */
MGL_WINDOW_TYPE_NOTIFICATION /* Also sets the window as always on top */
@@ -75,6 +66,7 @@ typedef void (*mgl_active_monitor_callback)(const mgl_monitor *monitor, void *us
struct mgl_window {
mgl_window_handle (*get_system_handle)(const mgl_window *self);
+ void (*deinit)(mgl_window *self);
void (*close)(mgl_window *self);
bool (*poll_event)(mgl_window *self, mgl_event *event);
bool (*inject_x11_event)(mgl_window *self, XEvent *xev, mgl_event *event); /* Optional */
@@ -136,8 +128,7 @@ typedef struct {
const char *class_name;
mgl_window_type window_type; /* default: normal */
mgl_window_handle transient_for_window; /* 0 = none */
- mgl_render_api render_api; /* default: MGL_RENDER_API_GLX on X11 and MGL_RENDER_API_EGL on Wayland */
- mgl_window_system window_system; /* default: MGL_WINDOW_SYSTEM_NATIVE */
+ mgl_graphics_api graphics_api; /* Can only be MGL_GRAPHICS_API_GLX in an X11 window. default: MGL_GRAPHICS_API_EGL */
} mgl_window_create_params;
/* |params| can be NULL. Note: vsync is enabled by default */
diff --git a/include/mgl/window/x11.h b/include/mgl/window/x11.h
new file mode 100644
index 0000000..6c4aa93
--- /dev/null
+++ b/include/mgl/window/x11.h
@@ -0,0 +1,8 @@
+#ifndef MGL_WINDOW_X11_H
+#define MGL_WINDOW_X11_H
+
+#include "window.h"
+
+bool mgl_window_x11_init(mgl_window *self, const char *title, const mgl_window_create_params *params, mgl_window_handle existing_window);
+
+#endif /* MGL_WINDOW_X11_H */
diff --git a/include/mgl/window/x11/window.h b/include/mgl/window/x11/window.h
deleted file mode 100644
index 9ffc968..0000000
--- a/include/mgl/window/x11/window.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef MGL_X11_WINDOW_H
-#define MGL_X11_WINDOW_H
-
-#include "../window.h"
-
-bool mgl_x11_window_init(mgl_window *self, const char *title, const mgl_window_create_params *params, mgl_window_handle existing_window);
-void mgl_x11_window_deinit(mgl_window *self);
-
-#endif /* MGL_X11_WINDOW_H */
diff --git a/meson.build b/meson.build
index 5f20c58..88ebbd8 100644
--- a/meson.build
+++ b/meson.build
@@ -28,6 +28,10 @@ src = [
'src/gl.c',
]
+src += [
+ 'src/window/wayland.c',
+]
+
project_headers = [
'include/mgl/graphics/rectangle.h',
'include/mgl/graphics/sprite.h',
@@ -64,6 +68,11 @@ dep = [
cc.find_library('m'),
]
+dep += [
+ dependency('wayland-client'),
+ dependency('wayland-egl'),
+]
+
public_headers = include_directories('include')
project_target = static_library(
diff --git a/project.conf b/project.conf
index 8977367..e4ea76a 100644
--- a/project.conf
+++ b/project.conf
@@ -11,4 +11,6 @@ expose_include_dirs = ["include"]
[dependencies]
x11 = ">=0.5"
xrender = ">=0.5"
-xrandr = ">=0.5" \ No newline at end of file
+xrandr = ">=0.5"
+wayland-client = ">=1"
+wayland-egl = ">=15" \ No newline at end of file
diff --git a/src/graphics/backend/egl.c b/src/graphics/backend/egl.c
new file mode 100644
index 0000000..f92e2fc
--- /dev/null
+++ b/src/graphics/backend/egl.c
@@ -0,0 +1,246 @@
+#include "../../../include/mgl/graphics/backend/egl.h"
+#include "../../../include/mgl/mgl.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <X11/Xutil.h>
+#include <X11/extensions/Xrender.h>
+
+static void mgl_graphics_egl_deinit(mgl_graphics *self);
+
+typedef struct {
+ EGLDisplay display;
+ EGLSurface surface;
+ EGLContext context;
+ EGLConfig *configs;
+ EGLConfig ecfg;
+ XVisualInfo *visual_info;
+} mgl_graphics_egl;
+
+static int32_t mgl_graphics_egl_get_config_attrib(mgl_graphics_egl *self, EGLConfig ecfg, int32_t attribute_name) {
+ mgl_context *context = mgl_get_context();
+ int32_t value = 0;
+ context->gl.eglGetConfigAttrib(self->display, ecfg, attribute_name, &value);
+ return value;
+}
+
+static bool xvisual_match_alpha(Display *dpy, XVisualInfo *visual_info, bool alpha) {
+ XRenderPictFormat *pict_format = XRenderFindVisualFormat(dpy, visual_info->visual);
+ if(!pict_format)
+ return false;
+ return (alpha && pict_format->direct.alphaMask > 0) || (!alpha && pict_format->direct.alphaMask == 0);
+}
+
+static bool mgl_graphics_context_choose(mgl_graphics_egl *self, mgl_context *context, bool alpha) {
+ self->configs = NULL;
+ self->ecfg = NULL;
+ self->visual_info = NULL;
+
+ int32_t num_configs = 0;
+ context->gl.eglGetConfigs(self->display, NULL, 0, &num_configs);
+ if(num_configs == 0) {
+ fprintf(stderr, "mgl error: no configs found\n");
+ return false;
+ }
+
+ self->configs = (EGLConfig*)calloc(num_configs, sizeof(EGLConfig));
+ if(!self->configs) {
+ fprintf(stderr, "mgl error: failed to allocate %d configs\n", (int)num_configs);
+ return false;
+ }
+
+ context->gl.eglGetConfigs(self->display, self->configs, num_configs, &num_configs);
+ for(int i = 0; i < num_configs; i++) {
+ self->ecfg = self->configs[i];
+
+ if(mgl_graphics_egl_get_config_attrib(self, self->ecfg, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER)
+ continue;
+
+ if(!(mgl_graphics_egl_get_config_attrib(self, self->ecfg, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
+ continue;
+
+ if(mgl_graphics_egl_get_config_attrib(self, self->ecfg, EGL_RED_SIZE) != 8)
+ continue;
+
+ if(mgl_graphics_egl_get_config_attrib(self, self->ecfg, EGL_GREEN_SIZE) != 8)
+ continue;
+
+ if(mgl_graphics_egl_get_config_attrib(self, self->ecfg, EGL_BLUE_SIZE) != 8)
+ continue;
+
+ if(mgl_graphics_egl_get_config_attrib(self, self->ecfg, EGL_ALPHA_SIZE) != (alpha ? 8 : 0))
+ continue;
+
+ if(context->window_system == MGL_WINDOW_SYSTEM_WAYLAND)
+ break;
+
+ XVisualInfo vi = {0};
+ vi.visualid = mgl_graphics_egl_get_config_attrib(self, self->ecfg, EGL_NATIVE_VISUAL_ID);
+ if(!vi.visualid)
+ continue;
+
+ int vis_count = 0;
+ self->visual_info = XGetVisualInfo(context->connection, VisualIDMask, &vi, &vis_count);
+ if(!self->visual_info)
+ continue;
+
+ if(xvisual_match_alpha(context->connection, self->visual_info, alpha)) {
+ break;
+ } else {
+ XFree(self->visual_info);
+ self->visual_info = NULL;
+ self->ecfg = NULL;
+ }
+ }
+
+ if(context->window_system == MGL_WINDOW_SYSTEM_X11 && !self->visual_info) {
+ if(self->configs) {
+ free(self->configs);
+ self->configs = NULL;
+ }
+ self->ecfg = NULL;
+
+ fprintf(stderr, "mgl error: mgl_graphics_context_choose: no appropriate visual found\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool mgl_graphics_egl_make_context_current(mgl_graphics *self, mgl_window_handle window) {
+ (void)window;
+ mgl_graphics_egl *impl = self->impl;
+ mgl_context *context = mgl_get_context();
+
+ if(!impl->surface) {
+ impl->surface = context->gl.eglCreateWindowSurface(impl->display, impl->ecfg, (EGLNativeWindowType)window, NULL);
+ if(!impl->surface) {
+ fprintf(stderr, "mgl error: mgl_graphics_egl_make_context_current: failed to create window surface\n");
+ return false;
+ }
+ }
+
+ return context->gl.eglMakeCurrent(impl->display, impl->surface, impl->surface, impl->context) != 0;
+}
+
+static void mgl_graphics_egl_swap_buffers(mgl_graphics *self, mgl_window_handle window) {
+ (void)window;
+ mgl_graphics_egl *impl = self->impl;
+ mgl_context *context = mgl_get_context();
+ context->gl.eglSwapBuffers(impl->display, impl->surface);
+}
+
+static bool mgl_graphics_egl_set_swap_interval(mgl_graphics *self, mgl_window_handle window, bool enabled) {
+ (void)window;
+ mgl_graphics_egl *impl = self->impl;
+ mgl_context *context = mgl_get_context();
+ return context->gl.eglSwapInterval(impl->display, (int32_t)enabled) == 1;
+}
+
+static void* mgl_graphics_egl_get_xvisual_info(mgl_graphics *self) {
+ mgl_graphics_egl *impl = self->impl;
+ return impl->visual_info;
+}
+
+static void* mgl_graphics_egl_get_display(mgl_graphics *self) {
+ mgl_graphics_egl *impl = self->impl;
+ return impl->display;
+}
+
+static void* mgl_graphics_egl_get_context(mgl_graphics *self) {
+ mgl_graphics_egl *impl = self->impl;
+ return impl->context;
+}
+
+bool mgl_graphics_egl_init(mgl_graphics *self) {
+ mgl_graphics_egl *impl = calloc(1, sizeof(mgl_graphics_egl));
+ if(!impl)
+ return false;
+
+ self->deinit = mgl_graphics_egl_deinit;
+ self->make_context_current = mgl_graphics_egl_make_context_current;
+ self->swap_buffers = mgl_graphics_egl_swap_buffers;
+ self->set_swap_interval = mgl_graphics_egl_set_swap_interval;
+ self->get_xvisual_info = mgl_graphics_egl_get_xvisual_info;
+ self->get_display = mgl_graphics_egl_get_display;
+ self->get_context = mgl_graphics_egl_get_context;
+ self->impl = impl;
+
+ const int32_t ctxattr[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE, EGL_NONE
+ };
+
+ mgl_context *context = mgl_get_context();
+ context->gl.eglBindAPI(EGL_OPENGL_API);
+
+ impl->display = context->gl.eglGetDisplay((EGLNativeDisplayType)context->connection);
+ if(!impl->display) {
+ fprintf(stderr, "mgl error: mgl_graphics_egl_init: eglGetDisplay failed\n");
+ mgl_graphics_egl_deinit(self);
+ return false;
+ }
+
+ if(!context->gl.eglInitialize(impl->display, NULL, NULL)) {
+ fprintf(stderr, "mgl error: mgl_graphics_egl_init: eglInitialize failed\n");
+ mgl_graphics_egl_deinit(self);
+ return false;
+ }
+
+ if(!mgl_graphics_context_choose(impl, context, self->alpha)) {
+ mgl_graphics_egl_deinit(self);
+ return false;
+ }
+
+ impl->context = context->gl.eglCreateContext(impl->display, impl->ecfg, NULL, ctxattr);
+ if(!impl->context) {
+ fprintf(stderr, "mgl error: mgl_graphics_egl_init: failed to create egl context\n");
+ mgl_graphics_egl_deinit(self);
+ return false;
+ }
+
+ return true;
+}
+
+void mgl_graphics_egl_deinit(mgl_graphics *self) {
+ mgl_graphics_egl *impl = self->impl;
+ if(!impl)
+ return;
+
+ mgl_context *context = mgl_get_context();
+
+ if(impl->visual_info) {
+ XFree(impl->visual_info);
+ impl->visual_info = NULL;
+ }
+
+ if(impl->configs) {
+ free(impl->configs);
+ impl->configs = NULL;
+ }
+
+ if(impl->context) {
+ context->gl.eglMakeCurrent(impl->display, NULL, NULL, NULL);
+ context->gl.eglDestroyContext(impl->display, impl->context);
+ impl->context = NULL;
+ }
+
+ if(impl->surface) {
+ context->gl.eglDestroySurface(impl->display, impl->surface);
+ impl->surface = NULL;
+ }
+
+ if(impl->display) {
+ context->gl.eglTerminate(impl->display);
+ impl->display = NULL;
+ }
+
+ if(impl->visual_info) {
+ XFree(impl->visual_info);
+ impl->visual_info = NULL;
+ }
+
+ free(self->impl);
+ self->impl = NULL;
+}
diff --git a/src/graphics/backend/glx.c b/src/graphics/backend/glx.c
new file mode 100644
index 0000000..548b0a0
--- /dev/null
+++ b/src/graphics/backend/glx.c
@@ -0,0 +1,174 @@
+#include "../../../include/mgl/graphics/backend/glx.h"
+#include "../../../include/mgl/mgl.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <X11/Xutil.h>
+#include <X11/extensions/Xrender.h>
+
+static void mgl_graphics_glx_deinit(mgl_graphics *self);
+
+typedef struct {
+ GLXContext glx_context;
+ GLXFBConfig *fbconfigs;
+ GLXFBConfig fbconfig;
+ XVisualInfo *visual_info;
+} mgl_graphics_glx;
+
+static bool xvisual_match_alpha(Display *dpy, XVisualInfo *visual_info, bool alpha) {
+ XRenderPictFormat *pict_format = XRenderFindVisualFormat(dpy, visual_info->visual);
+ if(!pict_format)
+ return false;
+ return (alpha && pict_format->direct.alphaMask > 0) || (!alpha && pict_format->direct.alphaMask == 0);
+}
+
+static bool mgl_graphics_glx_context_choose(mgl_graphics_glx *self, mgl_context *context, bool alpha) {
+ 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, alpha ? 8 : 0,
+ // TODO:
+ //GLX_DEPTH_SIZE, 0,
+ None
+ };
+
+ self->fbconfigs = NULL;
+ self->visual_info = NULL;
+ self->fbconfig = NULL;
+
+ int numfbconfigs = 0;
+ self->fbconfigs = context->gl.glXChooseFBConfig(context->connection, DefaultScreen(context->connection), attr, &numfbconfigs);
+ for(int i = 0; i < numfbconfigs; i++) {
+ self->visual_info = (XVisualInfo*)context->gl.glXGetVisualFromFBConfig(context->connection, self->fbconfigs[i]);
+ if(!self->visual_info)
+ continue;
+
+ if(xvisual_match_alpha(context->connection, self->visual_info, alpha)) {
+ self->fbconfig = self->fbconfigs[i];
+ break;
+ } else {
+ XFree(self->visual_info);
+ self->visual_info = NULL;
+ self->fbconfig = NULL;
+ }
+ }
+
+ if(!self->visual_info) {
+ if(self->fbconfigs) {
+ XFree(self->fbconfigs);
+ self->fbconfigs = NULL;
+ }
+ self->fbconfig = NULL;
+
+ fprintf(stderr, "mgl error: no appropriate visual found\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool mgl_graphics_glx_make_context_current(mgl_graphics *self, mgl_window_handle window) {
+ mgl_graphics_glx *impl = self->impl;
+ mgl_context *context = mgl_get_context();
+ return context->gl.glXMakeContextCurrent(context->connection, (GLXDrawable)window, (GLXDrawable)window, impl->glx_context) != 0;
+}
+
+static void mgl_graphics_glx_swap_buffers(mgl_graphics *self, mgl_window_handle window) {
+ (void)self;
+ mgl_context *context = mgl_get_context();
+ context->gl.glXSwapBuffers(context->connection, (GLXDrawable)window);
+}
+
+/* TODO: Use gl OML present for other platforms than nvidia? nvidia doesn't support present yet */
+/* TODO: check for glx swap control extension string (GLX_EXT_swap_control, etc) */
+static bool mgl_graphics_glx_set_swap_interval(mgl_graphics *self, mgl_window_handle window, bool enabled) {
+ (void)self;
+ mgl_context *context = mgl_get_context();
+
+ int result = 0;
+ if(context->gl.glXSwapIntervalEXT) {
+ context->gl.glXSwapIntervalEXT(context->connection, (GLXDrawable)window, enabled);
+ } else if(context->gl.glXSwapIntervalMESA) {
+ result = context->gl.glXSwapIntervalMESA(enabled);
+ } else if(context->gl.glXSwapIntervalSGI) {
+ result = context->gl.glXSwapIntervalSGI(enabled);
+ } else {
+ static int warned = 0;
+ if (!warned) {
+ warned = 1;
+ fprintf(stderr, "mgl warning: setting vertical sync not supported\n");
+ }
+ }
+
+ if(result != 0)
+ fprintf(stderr, "mgl warning: setting vertical sync failed\n");
+
+ return result == 0;
+}
+
+static void* mgl_graphics_glx_get_xvisual_info(mgl_graphics *self) {
+ mgl_graphics_glx *impl = self->impl;
+ return impl->visual_info;
+}
+
+bool mgl_graphics_glx_init(mgl_graphics *self) {
+ mgl_graphics_glx *impl = calloc(1, sizeof(mgl_graphics_glx));
+ if(!impl)
+ return false;
+
+ self->deinit = mgl_graphics_glx_deinit;
+ self->make_context_current = mgl_graphics_glx_make_context_current;
+ self->swap_buffers = mgl_graphics_glx_swap_buffers;
+ self->set_swap_interval = mgl_graphics_glx_set_swap_interval;
+ self->get_xvisual_info = mgl_graphics_glx_get_xvisual_info;
+ self->impl = impl;
+
+ mgl_context *context = mgl_get_context();
+ if(!mgl_graphics_glx_context_choose(impl, context, self->alpha)) {
+ mgl_graphics_glx_deinit(self);
+ return false;
+ }
+
+ impl->glx_context = context->gl.glXCreateNewContext(context->connection, impl->fbconfig, GLX_RGBA_TYPE, 0, True);
+ if(!impl->glx_context) {
+ fprintf(stderr, "mgl error: mgl_graphics_glx_init: glXCreateContext failed\n");
+ mgl_graphics_glx_deinit(self);
+ return false;
+ }
+
+ return true;
+}
+
+void mgl_graphics_glx_deinit(mgl_graphics *self) {
+ mgl_graphics_glx *impl = self->impl;
+ if(!impl)
+ return;
+
+ mgl_context *context = mgl_get_context();
+
+ if(impl->glx_context) {
+ context->gl.glXMakeContextCurrent(context->connection, None, None, NULL);
+ context->gl.glXDestroyContext(context->connection, impl->glx_context);
+ impl->glx_context = NULL;
+ }
+
+ if(impl->visual_info) {
+ XFree(impl->visual_info);
+ impl->visual_info = NULL;
+ }
+
+ if(impl->fbconfigs) {
+ XFree(impl->fbconfigs);
+ impl->fbconfigs = NULL;
+ }
+
+ impl->fbconfig = NULL;
+
+ free(self->impl);
+ self->impl = NULL;
+}
diff --git a/src/graphics/backend/graphics.c b/src/graphics/backend/graphics.c
new file mode 100644
index 0000000..792894e
--- /dev/null
+++ b/src/graphics/backend/graphics.c
@@ -0,0 +1,54 @@
+#include "../../../include/mgl/graphics/backend/graphics.h"
+#include "../../../include/mgl/graphics/backend/glx.h"
+#include "../../../include/mgl/graphics/backend/egl.h"
+
+#include <string.h>
+
+bool mgl_graphics_init(mgl_graphics *self, const mgl_graphics_create_params *params) {
+ memset(self, 0, sizeof(*self));
+ self->graphics_api = params ? params->graphics_api : MGL_GRAPHICS_API_EGL;
+ self->alpha = params && params->alpha;
+
+ switch(self->graphics_api) {
+ case MGL_GRAPHICS_API_GLX:
+ return mgl_graphics_glx_init(self);
+ case MGL_GRAPHICS_API_EGL:
+ return mgl_graphics_egl_init(self);
+ }
+ return false;
+}
+
+void mgl_graphics_deinit(mgl_graphics *self) {
+ if(self->deinit)
+ self->deinit(self);
+}
+
+bool mgl_graphics_make_context_current(mgl_graphics *self, mgl_window_handle window) {
+ return self->make_context_current(self, window);
+}
+
+void mgl_graphics_swap_buffers(mgl_graphics *self, mgl_window_handle window) {
+ self->swap_buffers(self, window);
+}
+
+bool mgl_graphics_set_swap_interval(mgl_graphics *self, mgl_window_handle window, bool enabled) {
+ return self->set_swap_interval(self, window, enabled);
+}
+
+void* mgl_graphics_get_xvisual_info(mgl_graphics *self) {
+ return self->get_xvisual_info(self);
+}
+
+void* mgl_graphics_get_display(mgl_graphics *self) {
+ if(self->get_display)
+ return self->get_display(self);
+ else
+ return NULL;
+}
+
+void* mgl_graphics_get_context(mgl_graphics *self) {
+ if(self->get_context)
+ return self->get_context(self);
+ else
+ return NULL;
+}
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);
}
diff --git a/src/window/wayland.c b/src/window/wayland.c
new file mode 100644
index 0000000..2671e53
--- /dev/null
+++ b/src/window/wayland.c
@@ -0,0 +1,214 @@
+#include "../../../include/mgl/window/wayland.h"
+#include "../../../include/mgl/mgl.h"
+
+#include <wayland-client.h>
+#include <wayland-egl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+static void mgl_window_wayland_deinit(mgl_window *self);
+
+typedef struct {
+ struct wl_display *display;
+ struct wl_egl_window *window;
+ struct wl_registry *registry;
+ struct wl_surface *surface;
+ struct wl_compositor *compositor;
+
+ mgl_graphics graphics;
+} mgl_window_wayland;
+
+static void registry_add_object(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) {
+ (void)version;
+ mgl_window *self = data;
+ mgl_window_wayland *impl = self->impl;
+ if(strcmp(interface, "wl_compositor") == 0) {
+ if(impl->compositor) {
+ wl_compositor_destroy(impl->compositor);
+ impl->compositor = NULL;
+ }
+ impl->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
+ } else if(strcmp(interface, wl_output_interface.name) == 0) {
+ if(version < 4) {
+ fprintf(stderr, "gsr warning: wl output interface version is < 4, expected >= 4 to capture a monitor\n");
+ return;
+ }
+
+ if(self->num_monitors == MGL_MAX_MONITORS) {
+ fprintf(stderr, "gsr warning: reached maximum outputs (%d), ignoring output %u\n", MGL_MAX_MONITORS, name);
+ return;
+ }
+
+ // gsr_wayland_output *gsr_output = &window_wayland->outputs[window_wayland->num_outputs];
+ // ++self->num_monitors;
+ // *gsr_output = (gsr_wayland_output) {
+ // .wl_name = name,
+ // .output = wl_registry_bind(registry, name, &wl_output_interface, 4),
+ // .pos = { .x = 0, .y = 0 },
+ // .size = { .x = 0, .y = 0 },
+ // .transform = 0,
+ // .name = NULL,
+ // };
+ // wl_output_add_listener(gsr_output->output, &output_listener, gsr_output);
+ }
+}
+
+static void registry_remove_object(void *data, struct wl_registry *registry, uint32_t name) {
+ (void)data;
+ (void)registry;
+ (void)name;
+ // TODO: Remove output
+}
+
+static struct wl_registry_listener registry_listener = {
+ .global = registry_add_object,
+ .global_remove = registry_remove_object,
+};
+
+// TODO: Use title, params and existing_window
+bool mgl_wayland_setup_window(mgl_window *self, const char *title, const mgl_window_create_params *params, mgl_window_handle existing_window) {
+ mgl_window_wayland *impl = self->impl;
+
+ mgl_vec2i window_size = params ? params->size : (mgl_vec2i){ 0, 0 };
+ if(window_size.x <= 0 || window_size.y <= 0) {
+ window_size.x = 640;
+ window_size.y = 480;
+ }
+ self->size = window_size;
+
+ impl->display = wl_display_connect(NULL);
+ if(!impl->display) {
+ fprintf(stderr, "mgl error: mgl_wayland_setup_window: failed to connect to the Wayland server\n");
+ return false;
+ }
+
+ impl->registry = wl_display_get_registry(impl->display); /* TODO: Error checking */
+ wl_registry_add_listener(impl->registry, &registry_listener, self); /* TODO: Error checking */
+
+ /* Fetch globals */
+ wl_display_roundtrip(impl->display);
+
+ /* Fetch wl_output */
+ //wl_display_roundtrip(impl->display);
+
+ if(!impl->compositor) {
+ fprintf(stderr, "mgl error: mgl_wayland_setup_window: failed to find compositor\n");
+ return false;
+ }
+
+ impl->surface = wl_compositor_create_surface(impl->compositor);
+ if(!impl->surface) {
+ fprintf(stderr, "mgl error: mgl_wayland_setup_window: failed to create surface\n");
+ return false;
+ }
+
+ impl->window = wl_egl_window_create(impl->surface, self->size.x, self->size.y);
+ if(!impl->window) {
+ fprintf(stderr, "mgl error: mgl_wayland_setup_window: failed to create the Wayland window\n");
+ return false;
+ }
+
+ return true;
+}
+
+bool mgl_window_wayland_init(mgl_window *self, const char *title, const mgl_window_create_params *params, mgl_window_handle existing_window) {
+ mgl_window_wayland *impl = calloc(1, sizeof(mgl_window_wayland));
+ if(!impl)
+ return false;
+
+ // self->get_system_handle = mgl_window_x11_get_system_handle;
+ // self->close = mgl_window_x11_close;
+ // self->inject_x11_event = mgl_window_x11_inject_x11_event;
+ // self->poll_event = mgl_window_x11_poll_event;
+ // self->swap_buffers = mgl_window_x11_swap_buffers;
+ // self->set_visible = mgl_window_x11_set_visible;
+ // self->is_key_pressed = mgl_window_x11_is_key_pressed;
+ // self->is_mouse_button_pressed = mgl_window_x11_is_mouse_button_pressed;
+ // self->set_title = mgl_window_x11_set_title;
+ // self->set_cursor_visible = mgl_window_x11_set_cursor_visible;
+ // self->set_vsync_enabled = mgl_window_x11_set_vsync_enabled;
+ // self->is_vsync_enabled = mgl_window_x11_is_vsync_enabled;
+ // self->set_fullscreen = mgl_window_x11_set_fullscreen;
+ // self->is_fullscreen = mgl_window_x11_is_fullscreen;
+ // self->set_position = mgl_window_x11_set_position;
+ // self->set_size = mgl_window_x11_set_size;
+ // self->set_size_limits = mgl_window_x11_set_size_limits;
+ // self->set_clipboard = mgl_window_x11_set_clipboard;
+ // self->get_clipboard = mgl_window_x11_get_clipboard;
+ // self->get_clipboard_string = mgl_window_x11_get_clipboard_string;
+ // self->set_key_repeat_enabled = mgl_window_x11_set_key_repeat_enabled;
+ // self->flush = mgl_window_x11_flush;
+ // self->get_egl_display = mgl_window_x11_get_egl_display;
+ // self->get_egl_context = mgl_window_x11_get_egl_context;
+ // self->for_each_active_monitor_output = mgl_window_x11_for_each_active_monitor_output;
+
+ self->deinit = mgl_window_wayland_deinit;
+ self->impl = impl;
+
+ if(!mgl_wayland_setup_window(self, title, params, existing_window)) {
+ mgl_window_wayland_deinit(self);
+ return false;
+ }
+
+ assert(!params || params->graphics_api == MGL_GRAPHICS_API_EGL);
+ const bool alpha = params && params->support_alpha;
+ if(!mgl_graphics_init(&impl->graphics, &(mgl_graphics_create_params){ .graphics_api = MGL_GRAPHICS_API_EGL, .alpha = alpha })) {
+ mgl_window_wayland_deinit(self);
+ return false;
+ }
+
+ if(!mgl_graphics_make_context_current(&impl->graphics, impl->window)) {
+ fprintf(stderr, "mgl error: mgl_window_wayland_init: failed to make window context current\n");
+ mgl_window_wayland_deinit(self);
+ return false;
+ }
+
+ self->vsync_enabled = true;
+ mgl_graphics_set_swap_interval(&impl->graphics, (mgl_window_handle)impl->window, self->vsync_enabled);
+
+ mgl_context *context = mgl_get_context();
+ context->current_window = self;
+ return true;
+}
+
+void mgl_window_wayland_deinit(mgl_window *self) {
+ mgl_window_wayland *impl = self->impl;
+ if(!impl)
+ return;
+
+ mgl_graphics_deinit(&impl->graphics);
+
+ if(impl->window) {
+ wl_egl_window_destroy(impl->window);
+ impl->window = NULL;
+ }
+
+ if(impl->surface) {
+ wl_surface_destroy(impl->surface);
+ impl->surface = NULL;
+ }
+
+ if(impl->compositor) {
+ wl_compositor_destroy(impl->compositor);
+ impl->compositor = NULL;
+ }
+
+ if(impl->registry) {
+ wl_registry_destroy(impl->registry);
+ impl->registry = NULL;
+ }
+
+ if(impl->display) {
+ wl_display_disconnect(impl->display);
+ impl->display = NULL;
+ }
+
+ mgl_context *context = mgl_get_context();
+ if(context->current_window == self)
+ context->current_window = NULL;
+
+ free(self->impl);
+ self->impl = NULL;
+}
diff --git a/src/window/window.c b/src/window/window.c
index 56df01a..a11bc15 100644
--- a/src/window/window.c
+++ b/src/window/window.c
@@ -1,5 +1,6 @@
#include "../../include/mgl/window/window.h"
-#include "../../include/mgl/window/x11/window.h"
+#include "../../include/mgl/window/x11.h"
+#include "../../include/mgl/window/wayland.h"
#include "../../include/mgl/mgl.h"
#include <stdlib.h>
@@ -8,12 +9,22 @@
#include <string.h>
int mgl_window_init(mgl_window *self, const char *title, const mgl_window_create_params *params, mgl_window_handle existing_window) {
- // TODO: Handle |params->window_system|
memset(self, 0, sizeof(*self));
self->vsync_enabled = true;
self->key_repeat_enabled = true;
mgl_clock_init(&self->frame_timer);
- return mgl_x11_window_init(self, title, params, 0) ? 0 : -1;
+
+ mgl_context *context = mgl_get_context();
+ switch(context->window_system) {
+ case MGL_WINDOW_SYSTEM_NATIVE:
+ assert(false);
+ break;
+ case MGL_WINDOW_SYSTEM_X11:
+ return mgl_window_x11_init(self, title, params, existing_window) ? 0 : -1;
+ case MGL_WINDOW_SYSTEM_WAYLAND:
+ return mgl_window_wayland_init(self, title, params, existing_window) ? 0 : -1;
+ }
+ return -1;
}
int mgl_window_create(mgl_window *self, const char *title, const mgl_window_create_params *params) {
@@ -25,10 +36,12 @@ int mgl_window_init_from_existing_window(mgl_window *self, mgl_window_handle exi
}
void mgl_window_deinit(mgl_window *self) {
- mgl_x11_window_deinit(self);
+ if(self->deinit)
+ self->deinit(self);
}
void mgl_window_clear(mgl_window *self, mgl_color color) {
+ (void)self;
mgl_context *context = mgl_get_context();
context->gl.glClearColor((float)color.r / 255.0f, (float)color.g / 255.0f, (float)color.b / 255.0f, (float)color.a / 255.0f);
context->gl.glClear(GL_COLOR_BUFFER_BIT);
diff --git a/src/window/x11/window.c b/src/window/x11.c
index 59df3bc..113fc1a 100644
--- a/src/window/x11/window.c
+++ b/src/window/x11.c
@@ -1,14 +1,16 @@
-#include "../../../include/mgl/window/x11/window.h"
+#include "../../../include/mgl/window/x11.h"
#include "../../../include/mgl/window/event.h"
#include "../../../include/mgl/mgl.h"
#include "../../../include/mgl/system/utf8.h"
#include "../../../include/mgl/system/clock.h"
+
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xrender.h>
#include <X11/extensions/Xrandr.h>
#include <X11/XF86keysym.h>
+
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -16,6 +18,8 @@
#include <assert.h>
#include <unistd.h>
+static void mgl_window_x11_deinit(mgl_window *self);
+
/* TODO: Handle XIM better. Set XIM position to text position on screen (for text input) and reset input when selecting a new text input, etc */
/* TODO: Separate events from windows. Especially when it comes to monitor events */
@@ -30,30 +34,12 @@ typedef struct {
} x11_events_circular_buffer;
typedef struct {
- GLXContext glx_context;
- GLXFBConfig *fbconfigs;
- GLXFBConfig fbconfig;
- XVisualInfo *visual_info;
-} mgl_x11_window_glx;
-
-typedef struct {
- EGLDisplay egl_display;
- EGLSurface egl_surface;
- EGLContext egl_context;
- EGLConfig *configs;
- EGLConfig ecfg;
- XVisualInfo *visual_info;
-} mgl_x11_window_egl;
-
-typedef struct {
void *dpy;
Window window;
char *clipboard_string;
size_t clipboard_size;
- mgl_x11_window_glx glx;
- mgl_x11_window_egl egl;
- mgl_render_api render_api;
+ mgl_graphics graphics;
Colormap color_map;
XIM xim;
XIC xic;
@@ -91,7 +77,7 @@ typedef struct {
an event for all of them.
*/
x11_events_circular_buffer events;
-} mgl_x11_window;
+} mgl_window_x11;
static void x11_events_circular_buffer_init(x11_events_circular_buffer *self) {
self->start = 0;
@@ -119,329 +105,7 @@ static bool x11_events_circular_buffer_pop(x11_events_circular_buffer *self, mgl
return true;
}
-static bool xvisual_match_alpha(Display *dpy, XVisualInfo *visual_info, bool alpha) {
- XRenderPictFormat *pict_format = XRenderFindVisualFormat(dpy, visual_info->visual);
- if(!pict_format)
- return false;
- return (alpha && pict_format->direct.alphaMask > 0) || (!alpha && pict_format->direct.alphaMask == 0);
-}
-
-static bool glx_context_choose(mgl_context *context, mgl_x11_window_glx *glx, bool alpha) {
- 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, alpha ? 8 : 0,
- // TODO:
- //GLX_DEPTH_SIZE, 0,
- None
- };
-
- glx->fbconfigs = NULL;
- glx->visual_info = NULL;
- glx->fbconfig = NULL;
-
- int numfbconfigs = 0;
- glx->fbconfigs = context->gl.glXChooseFBConfig(context->connection, DefaultScreen(context->connection), attr, &numfbconfigs);
- for(int i = 0; i < numfbconfigs; i++) {
- glx->visual_info = (XVisualInfo*)context->gl.glXGetVisualFromFBConfig(context->connection, glx->fbconfigs[i]);
- if(!glx->visual_info)
- continue;
-
- if(xvisual_match_alpha(context->connection, glx->visual_info, alpha)) {
- glx->fbconfig = glx->fbconfigs[i];
- break;
- } else {
- XFree(glx->visual_info);
- glx->visual_info = NULL;
- glx->fbconfig = NULL;
- }
- }
-
- if(!glx->visual_info) {
- if(glx->fbconfigs) {
- XFree(glx->fbconfigs);
- glx->fbconfigs = NULL;
- }
- glx->fbconfig = NULL;
-
- fprintf(stderr, "mgl error: no appropriate visual found\n");
- return false;
- }
-
- return true;
-}
-
-static void mgl_x11_window_glx_deinit(mgl_x11_window_glx *self) {
- mgl_context *context = mgl_get_context();
-
- if(self->glx_context) {
- context->gl.glXMakeContextCurrent(context->connection, None, None, NULL);
- context->gl.glXDestroyContext(context->connection, self->glx_context);
- self->glx_context = NULL;
- }
-
- if(self->visual_info) {
- XFree(self->visual_info);
- self->visual_info = NULL;
- }
-
- if(self->fbconfigs) {
- XFree(self->fbconfigs);
- self->fbconfigs = NULL;
- }
-
- self->fbconfig = NULL;
-}
-
-static bool mgl_x11_window_glx_init(mgl_x11_window_glx *self, bool alpha) {
- mgl_context *context = mgl_get_context();
- memset(self, 0, sizeof(*self));
-
- if(!glx_context_choose(context, self, alpha)) {
- mgl_x11_window_glx_deinit(self);
- return false;
- }
-
- self->glx_context = context->gl.glXCreateNewContext(context->connection, self->fbconfig, GLX_RGBA_TYPE, 0, True);
- if(!self->glx_context) {
- fprintf(stderr, "mgl error: mgl_x11_window_glx_init: glXCreateContext failed\n");
- mgl_x11_window_glx_deinit(self);
- return false;
- }
-
- return true;
-}
-
-static bool mgl_x11_window_glx_make_context_current(mgl_x11_window_glx *self, Window window) {
- mgl_context *context = mgl_get_context();
- return context->gl.glXMakeContextCurrent(context->connection, window, window, self->glx_context) != 0;
-}
-
-static void mgl_x11_window_glx_swap_buffers(mgl_x11_window_glx *self, Window window) {
- (void)self;
- mgl_context *context = mgl_get_context();
- context->gl.glXSwapBuffers(context->connection, window);
-}
-
-static XVisualInfo* mgl_x11_window_glx_get_xvisual_info(mgl_x11_window_glx *self) {
- return self->visual_info;
-}
-
-static bool mgl_x11_window_glx_set_swap_interval(mgl_x11_window_glx *self, Window window, int enabled) {
- (void)self;
- mgl_context *context = mgl_get_context();
-
- int result = 0;
- if(context->gl.glXSwapIntervalEXT) {
- context->gl.glXSwapIntervalEXT(context->connection, window, enabled ? 1 : 0);
- } else if(context->gl.glXSwapIntervalMESA) {
- result = context->gl.glXSwapIntervalMESA(enabled ? 1 : 0);
- } else if(context->gl.glXSwapIntervalSGI) {
- result = context->gl.glXSwapIntervalSGI(enabled ? 1 : 0);
- } else {
- static int warned = 0;
- if (!warned) {
- warned = 1;
- fprintf(stderr, "mgl warning: setting vertical sync not supported\n");
- }
- }
-
- if(result != 0)
- fprintf(stderr, "mgl warning: setting vertical sync failed\n");
-
- return result == 0;
-}
-
-static int32_t egl_get_config_attrib(mgl_x11_window_egl *egl, EGLConfig ecfg, int32_t attribute_name) {
- mgl_context *context = mgl_get_context();
- int32_t value = 0;
- context->gl.eglGetConfigAttrib(egl->egl_display, ecfg, attribute_name, &value);
- return value;
-}
-
-static bool egl_context_choose(mgl_context *context, mgl_x11_window_egl *egl, bool alpha) {
- egl->configs = NULL;
- egl->ecfg = NULL;
- egl->visual_info = NULL;
-
- int32_t num_configs = 0;
- context->gl.eglGetConfigs(egl->egl_display, NULL, 0, &num_configs);
- if(num_configs == 0) {
- fprintf(stderr, "mgl error: no configs found\n");
- return false;
- }
-
- egl->configs = (EGLConfig*)calloc(num_configs, sizeof(EGLConfig));
- if(!egl->configs) {
- fprintf(stderr, "mgl error: failed to allocate %d configs\n", (int)num_configs);
- return false;
- }
-
- context->gl.eglGetConfigs(egl->egl_display, egl->configs, num_configs, &num_configs);
- for(int i = 0; i < num_configs; i++) {
- egl->ecfg = egl->configs[i];
-
- if(egl_get_config_attrib(egl, egl->ecfg, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER)
- continue;
-
- if(!(egl_get_config_attrib(egl, egl->ecfg, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
- continue;
-
- if(egl_get_config_attrib(egl, egl->ecfg, EGL_RED_SIZE) != 8)
- continue;
-
- if(egl_get_config_attrib(egl, egl->ecfg, EGL_GREEN_SIZE) != 8)
- continue;
-
- if(egl_get_config_attrib(egl, egl->ecfg, EGL_BLUE_SIZE) != 8)
- continue;
-
- if(egl_get_config_attrib(egl, egl->ecfg, EGL_ALPHA_SIZE) != (alpha ? 8 : 0))
- continue;
-
- XVisualInfo vi = {0};
- vi.visualid = egl_get_config_attrib(egl, egl->ecfg, EGL_NATIVE_VISUAL_ID);
- if(!vi.visualid)
- continue;
-
- int vis_count = 0;
- egl->visual_info = XGetVisualInfo(context->connection, VisualIDMask, &vi, &vis_count);
- if(!egl->visual_info)
- continue;
-
- if(xvisual_match_alpha(context->connection, egl->visual_info, alpha)) {
- break;
- } else {
- XFree(egl->visual_info);
- egl->visual_info = NULL;
- egl->ecfg = NULL;
- }
- }
-
- if(!egl->visual_info) {
- if(egl->configs) {
- free(egl->configs);
- egl->configs = NULL;
- }
- egl->ecfg = NULL;
-
- fprintf(stderr, "mgl error: no appropriate visual found\n");
- return false;
- }
-
- return true;
-}
-
-static void mgl_x11_window_egl_deinit(mgl_x11_window_egl *self) {
- mgl_context *context = mgl_get_context();
-
- if(self->visual_info) {
- XFree(self->visual_info);
- self->visual_info = NULL;
- }
-
- if(self->configs) {
- free(self->configs);
- self->configs = NULL;
- }
-
- if(self->egl_context) {
- context->gl.eglMakeCurrent(self->egl_display, NULL, NULL, NULL);
- context->gl.eglDestroyContext(self->egl_display, self->egl_context);
- self->egl_context = NULL;
- }
-
- if(self->egl_surface) {
- context->gl.eglDestroySurface(self->egl_display, self->egl_surface);
- self->egl_surface = NULL;
- }
-
- if(self->egl_display) {
- context->gl.eglTerminate(self->egl_display);
- self->egl_display = NULL;
- }
-
- if(self->visual_info) {
- XFree(self->visual_info);
- self->visual_info = NULL;
- }
-}
-
-static bool mgl_x11_window_egl_init(mgl_x11_window_egl *self, bool alpha) {
- mgl_context *context = mgl_get_context();
- memset(self, 0, sizeof(*self));
-
- const int32_t ctxattr[] = {
- EGL_CONTEXT_CLIENT_VERSION, 2,
- EGL_NONE, EGL_NONE
- };
-
- context->gl.eglBindAPI(EGL_OPENGL_API);
-
- self->egl_display = context->gl.eglGetDisplay((EGLNativeDisplayType)context->connection);
- if(!self->egl_display) {
- fprintf(stderr, "mgl error: mgl_x11_window_egl_init failed: eglGetDisplay failed\n");
- mgl_x11_window_egl_deinit(self);
- return false;
- }
-
- if(!context->gl.eglInitialize(self->egl_display, NULL, NULL)) {
- fprintf(stderr, "mgl error: mgl_x11_window_egl_init failed: eglInitialize failed\n");
- mgl_x11_window_egl_deinit(self);
- return false;
- }
-
- if(!egl_context_choose(context, self, alpha)) {
- mgl_x11_window_egl_deinit(self);
- return false;
- }
-
- self->egl_context = context->gl.eglCreateContext(self->egl_display, self->ecfg, NULL, ctxattr);
- if(!self->egl_context) {
- fprintf(stderr, "mgl error: mgl_x11_window_egl_init failed: failed to create egl context\n");
- mgl_x11_window_egl_deinit(self);
- return false;
- }
-
- return true;
-}
-
-static bool mgl_x11_window_egl_make_context_current(mgl_x11_window_egl *self, Window window) {
- (void)window;
- mgl_context *context = mgl_get_context();
-
- if(!self->egl_surface) {
- self->egl_surface = context->gl.eglCreateWindowSurface(self->egl_display, self->ecfg, (EGLNativeWindowType)window, NULL);
- if(!self->egl_surface) {
- fprintf(stderr, "mgl error: mgl_x11_window_egl_make_context_current: failed to create window surface\n");
- return false;
- }
- }
-
- return context->gl.eglMakeCurrent(self->egl_display, self->egl_surface, self->egl_surface, self->egl_context) != 0;
-}
-
-static void mgl_x11_window_egl_swap_buffers(mgl_x11_window_egl *self, Window window) {
- (void)window;
- mgl_context *context = mgl_get_context();
- context->gl.eglSwapBuffers(self->egl_display, self->egl_surface);
-}
-
-static XVisualInfo* mgl_x11_window_egl_get_xvisual_info(mgl_x11_window_egl *self) {
- return self->visual_info;
-}
-
-static bool mgl_x11_window_egl_set_swap_interval(mgl_x11_window_egl *self, Window window, int enabled) {
- (void)window;
- mgl_context *context = mgl_get_context();
- return context->gl.eglSwapInterval(self->egl_display, enabled) == 1;
-}
-
-static void mgl_x11_window_clear_monitors(mgl_window *self) {
+static void mgl_window_x11_clear_monitors(mgl_window *self) {
for(int i = 0; i < self->num_monitors; ++i) {
mgl_monitor *monitor = &self->monitors[i];
if(monitor->name) {
@@ -452,45 +116,15 @@ static void mgl_x11_window_clear_monitors(mgl_window *self) {
self->num_monitors = 0;
}
-static bool mgl_x11_window_make_gl_context_current(mgl_x11_window *self, Window window) {
- switch(self->render_api) {
- case MGL_RENDER_API_GLX:
- return mgl_x11_window_glx_make_context_current(&self->glx, window);
- case MGL_RENDER_API_EGL:
- return mgl_x11_window_egl_make_context_current(&self->egl, window);
- }
- return false;
-}
-
-static XVisualInfo* mgl_x11_window_get_xvisual_info(mgl_x11_window *self) {
- switch(self->render_api) {
- case MGL_RENDER_API_GLX:
- return mgl_x11_window_glx_get_xvisual_info(&self->glx);
- case MGL_RENDER_API_EGL:
- return mgl_x11_window_egl_get_xvisual_info(&self->egl);
- }
- return NULL;
-}
-
-static bool mgl_x11_window_set_swap_interval(mgl_x11_window *self, Window window, int enabled) {
- switch(self->render_api) {
- case MGL_RENDER_API_GLX:
- return mgl_x11_window_glx_set_swap_interval(&self->glx, window, enabled);
- case MGL_RENDER_API_EGL:
- return mgl_x11_window_egl_set_swap_interval(&self->egl, window, enabled);
- }
- return false;
-}
-
-static bool mgl_x11_window_append_event(mgl_x11_window *self, const mgl_event *event) {
+static bool mgl_window_x11_append_event(mgl_window_x11 *self, const mgl_event *event) {
return x11_events_circular_buffer_append(&self->events, event);
}
-static bool mgl_x11_window_pop_event(mgl_x11_window *self, mgl_event *event) {
+static bool mgl_window_x11_pop_event(mgl_window_x11 *self, mgl_event *event) {
return x11_events_circular_buffer_pop(&self->events, event);
}
-static mgl_monitor* mgl_x11_window_add_monitor(mgl_window *self, RROutput output_id, RRCrtc crtc_id, const char *name, mgl_vec2i pos, mgl_vec2i size, int refresh_rate) {
+static mgl_monitor* mgl_window_x11_add_monitor(mgl_window *self, RROutput output_id, RRCrtc crtc_id, const char *name, mgl_vec2i pos, mgl_vec2i size, int refresh_rate) {
if(self->num_monitors == MGL_MAX_MONITORS)
return NULL;
@@ -508,7 +142,7 @@ static mgl_monitor* mgl_x11_window_add_monitor(mgl_window *self, RROutput output
return monitor;
}
-static mgl_monitor* mgl_x11_window_get_monitor_by_id(mgl_window *self, RROutput output_id) {
+static mgl_monitor* mgl_window_x11_get_monitor_by_id(mgl_window *self, RROutput output_id) {
for(int i = 0; i < self->num_monitors; ++i) {
mgl_monitor *monitor = &self->monitors[i];
if(monitor->id == (int)output_id)
@@ -517,7 +151,7 @@ static mgl_monitor* mgl_x11_window_get_monitor_by_id(mgl_window *self, RROutput
return NULL;
}
-static mgl_monitor* mgl_x11_window_get_monitor_by_crtc_id(mgl_window *self, RRCrtc crtc_id) {
+static mgl_monitor* mgl_window_x11_get_monitor_by_crtc_id(mgl_window *self, RRCrtc crtc_id) {
for(int i = 0; i < self->num_monitors; ++i) {
mgl_monitor *monitor = &self->monitors[i];
if(monitor->crtc_id == (int)crtc_id)
@@ -526,7 +160,7 @@ static mgl_monitor* mgl_x11_window_get_monitor_by_crtc_id(mgl_window *self, RRCr
return NULL;
}
-static bool mgl_x11_window_remove_monitor(mgl_window *self, RROutput output_id, mgl_event *event) {
+static bool mgl_window_x11_remove_monitor(mgl_window *self, RROutput output_id, mgl_event *event) {
int index_to_remove = -1;
for(int i = 0; i < self->num_monitors; ++i) {
mgl_monitor *monitor = &self->monitors[i];
@@ -582,7 +216,7 @@ static const XRRModeInfo* get_mode_info(const XRRScreenResources *sr, RRMode id)
return NULL;
}
-static void mgl_x11_window_for_each_active_monitor_output(mgl_window *self, mgl_active_monitor_callback callback, void *userdata) {
+static void mgl_window_x11_for_each_active_monitor_output(mgl_window *self, mgl_active_monitor_callback callback, void *userdata) {
(void)self;
mgl_context *context = mgl_get_context();
XRRScreenResources *screen_res = XRRGetScreenResources(context->connection, DefaultRootWindow(context->connection));
@@ -619,19 +253,12 @@ static void mgl_x11_window_for_each_active_monitor_output(mgl_window *self, mgl_
XRRFreeScreenResources(screen_res);
}
-static void monitor_callback_add_to_mgl_x11_window(const mgl_monitor *monitor, void *userdata) {
+static void monitor_callback_add_to_mgl_window_x11(const mgl_monitor *monitor, void *userdata) {
mgl_window *mgl_window = userdata;
- mgl_x11_window_add_monitor(mgl_window, monitor->id, monitor->crtc_id, monitor->name, monitor->pos, monitor->size, monitor->refresh_rate);
+ mgl_window_x11_add_monitor(mgl_window, monitor->id, monitor->crtc_id, monitor->name, monitor->pos, monitor->size, monitor->refresh_rate);
}
-/* TODO: Use gl OML present for other platforms than nvidia? nvidia doesn't support present yet */
-
-/* TODO: check for glx swap control extension string (GLX_EXT_swap_control, etc) */
-static void set_vertical_sync_enabled(mgl_x11_window *self, int enabled) {
- mgl_x11_window_set_swap_interval(self, self->window, enabled);
-}
-
-static void mgl_x11_window_set_frame_time_limit_monitor(mgl_window *self) {
+static void mgl_window_x11_set_frame_time_limit_monitor(mgl_window *self) {
int monitor_refresh_rate = 0;
mgl_vec2i window_center = (mgl_vec2i) { self->pos.x + self->size.x / 2, self->pos.y + self->size.y / 2 };
for(int i = 0; i < self->num_monitors; ++i) {
@@ -653,13 +280,13 @@ static void mgl_x11_window_set_frame_time_limit_monitor(mgl_window *self) {
self->frame_time_limit_monitor = 1.0 / (double)monitor_refresh_rate;
}
-static void mgl_x11_window_on_move(mgl_window *self, int x, int y) {
+static void mgl_window_x11_on_move(mgl_window *self, int x, int y) {
self->pos.x = x;
self->pos.y = y;
- mgl_x11_window_set_frame_time_limit_monitor(self);
+ mgl_window_x11_set_frame_time_limit_monitor(self);
}
-static void mgl_x11_window_on_resize(mgl_window *self, int width, int height) {
+static void mgl_window_x11_on_resize(mgl_window *self, int width, int height) {
self->size.x = width;
self->size.y = height;
@@ -677,7 +304,7 @@ static unsigned long mgl_color_to_x11_pixel(mgl_color color) {
}
static void mgl_set_window_type(mgl_window *self, mgl_window_type window_type) {
- mgl_x11_window *impl = self->impl;
+ mgl_window_x11 *impl = self->impl;
mgl_context *context = mgl_get_context();
switch(window_type) {
case MGL_WINDOW_TYPE_NORMAL: {
@@ -714,8 +341,8 @@ typedef struct {
#define MWM_DECOR_NONE 0
#define MWM_DECOR_ALL 1
-static void mgl_x11_window_set_decorations_visible(mgl_window *self, bool visible) {
- mgl_x11_window *impl = self->impl;
+static void mgl_window_x11_set_decorations_visible(mgl_window *self, bool visible) {
+ mgl_window_x11 *impl = self->impl;
mgl_context *context = mgl_get_context();
MotifHints motif_hints = {0};
@@ -725,8 +352,8 @@ static void mgl_x11_window_set_decorations_visible(mgl_window *self, bool visibl
XChangeProperty(context->connection, impl->window, impl->motif_wm_hints_atom, impl->motif_wm_hints_atom, 32, PropModeReplace, (unsigned char*)&motif_hints, sizeof(motif_hints) / sizeof(long));
}
-static void mgl_x11_window_set_title(mgl_window *self, const char *title) {
- mgl_x11_window *impl = self->impl;
+static void mgl_window_x11_set_title(mgl_window *self, const char *title) {
+ mgl_window_x11 *impl = self->impl;
mgl_context *context = mgl_get_context();
XStoreName(context->connection, impl->window, title);
@@ -734,8 +361,8 @@ static void mgl_x11_window_set_title(mgl_window *self, const char *title) {
XFlush(context->connection);
}
-static void mgl_x11_window_set_size_limits(mgl_window *self, mgl_vec2i minimum, mgl_vec2i maximum) {
- mgl_x11_window *impl = self->impl;
+static void mgl_window_x11_set_size_limits(mgl_window *self, mgl_vec2i minimum, mgl_vec2i maximum) {
+ mgl_window_x11 *impl = self->impl;
XSizeHints *size_hints = XAllocSizeHints();
if(size_hints) {
size_hints->width = self->size.x;
@@ -762,7 +389,7 @@ static void mgl_x11_window_set_size_limits(mgl_window *self, mgl_vec2i minimum,
}
static bool mgl_x11_setup_window(mgl_window *self, const char *title, const mgl_window_create_params *params, Window existing_window) {
- mgl_x11_window *impl = self->impl;
+ mgl_window_x11 *impl = self->impl;
impl->window = 0;
impl->clipboard_string = NULL;
impl->clipboard_size = 0;
@@ -777,14 +404,14 @@ static bool mgl_x11_setup_window(mgl_window *self, const char *title, const mgl_
mgl_vec2i window_pos = params ? params->position : (mgl_vec2i){ 0, 0 };
mgl_context *context = mgl_get_context();
- Window parent_window = params ? params->parent_window : None;
+ Window parent_window = params ? (Window)params->parent_window : None;
if(parent_window == 0)
parent_window = DefaultRootWindow(context->connection);
- XVisualInfo *visual_info = mgl_x11_window_get_xvisual_info(impl);
+ XVisualInfo *visual_info = mgl_graphics_get_xvisual_info(&impl->graphics);
impl->color_map = XCreateColormap(context->connection, DefaultRootWindow(context->connection), visual_info->visual, AllocNone);
if(!impl->color_map) {
- fprintf(stderr, "mgl error: XCreateColormap failed\n");
+ fprintf(stderr, "mgl error: mgl_x11_setup_window: XCreateColormap failed\n");
return false;
}
@@ -804,7 +431,7 @@ static bool mgl_x11_setup_window(mgl_window *self, const char *title, const mgl_
if(existing_window) {
if(!XChangeWindowAttributes(context->connection, existing_window, CWColormap | CWEventMask | CWOverrideRedirect | CWBorderPixel | CWBackPixel | CWBitGravity, &window_attr)) {
- fprintf(stderr, "mgl error: XChangeWindowAttributes failed\n");
+ fprintf(stderr, "mgl error: mgl_x11_setup_window: XChangeWindowAttributes failed\n");
return false;
}
@@ -815,7 +442,7 @@ static bool mgl_x11_setup_window(mgl_window *self, const char *title, const mgl_
impl->window = existing_window;
if(params && params->hide_decorations) {
- mgl_x11_window_set_decorations_visible(self, false);
+ mgl_window_x11_set_decorations_visible(self, false);
}
if(hide_window)
@@ -826,21 +453,21 @@ static bool mgl_x11_setup_window(mgl_window *self, const char *title, const mgl_
visual_info->depth, InputOutput, visual_info->visual,
CWColormap | CWEventMask | CWOverrideRedirect | CWBorderPixel | CWBackPixel | CWBitGravity, &window_attr);
if(!impl->window) {
- fprintf(stderr, "mgl error: XCreateWindow failed\n");
+ fprintf(stderr, "mgl error: mgl_x11_setup_window: XCreateWindow failed\n");
return false;
}
if(params && params->hide_decorations) {
- mgl_x11_window_set_decorations_visible(self, false);
+ mgl_window_x11_set_decorations_visible(self, false);
}
- mgl_x11_window_set_title(self, title);
+ mgl_window_x11_set_title(self, title);
if(!hide_window)
XMapWindow(context->connection, impl->window);
}
if(params)
- mgl_x11_window_set_size_limits(self, params->min_size, params->max_size);
+ mgl_window_x11_set_size_limits(self, params->min_size, params->max_size);
/* TODO: Call XGetWMProtocols and add wm_delete_window_atom on top, to not overwrite existing wm protocol atoms */
Atom wm_protocol_atoms[2] = {
@@ -871,7 +498,7 @@ static bool mgl_x11_setup_window(mgl_window *self, const char *title, const mgl_
}
if(params && params->transient_for_window) {
- XSetTransientForHint(context->connection, impl->window, params->transient_for_window);
+ XSetTransientForHint(context->connection, impl->window, (Window)params->transient_for_window);
}
/* TODO: Move this to above XMapWindow? */
@@ -880,13 +507,13 @@ static bool mgl_x11_setup_window(mgl_window *self, const char *title, const mgl_
XFlush(context->connection);
- if(!mgl_x11_window_make_gl_context_current(impl, impl->window)) {
- fprintf(stderr, "mgl error: failed to make opengl context current!\n");
+ if(!mgl_graphics_make_context_current(&impl->graphics, (mgl_window_handle)impl->window)) {
+ fprintf(stderr, "mgl error: mgl_x11_setup_window: failed to make window context current\n");
return false;
}
self->vsync_enabled = true;
- set_vertical_sync_enabled(impl, self->vsync_enabled ? 1 : 0);
+ mgl_graphics_set_swap_interval(&impl->graphics, (mgl_window_handle)impl->window, self->vsync_enabled);
context->gl.glEnable(GL_TEXTURE_2D);
context->gl.glEnable(GL_BLEND);
@@ -905,22 +532,22 @@ static bool mgl_x11_setup_window(mgl_window *self, const char *title, const mgl_
impl->xim = XOpenIM(context->connection, NULL, NULL, NULL);
if(!impl->xim) {
- fprintf(stderr, "mgl error: XOpenIM failed\n");
+ fprintf(stderr, "mgl error: mgl_x11_setup_window: XOpenIM failed\n");
return false;
}
impl->xic = XCreateIC(impl->xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, impl->window, NULL);
if(!impl->xic) {
- fprintf(stderr, "mgl error: XCreateIC failed\n");
+ fprintf(stderr, "mgl error: mgl_x11_setup_window: XCreateIC failed\n");
return false;
}
// TODO: This should be done once and monitor events should be done once, no matter how many windows you have
- mgl_x11_window_clear_monitors(self);
- mgl_x11_window_for_each_active_monitor_output(self, monitor_callback_add_to_mgl_x11_window, self);
+ mgl_window_x11_clear_monitors(self);
+ mgl_window_x11_for_each_active_monitor_output(self, monitor_callback_add_to_mgl_window_x11, self);
- mgl_x11_window_on_resize(self, self->size.x, self->size.y);
- mgl_x11_window_on_move(self, window_pos.x, window_pos.y);
+ mgl_window_x11_on_resize(self, self->size.x, self->size.y);
+ mgl_window_x11_on_move(self, window_pos.x, window_pos.y);
self->open = true;
self->focused = false; /* TODO: Check if we need to call XGetInputFocus for this, or just wait for focus event */
@@ -1036,7 +663,7 @@ static void mgl_window_handle_key_event(XKeyEvent *xkey, mgl_event *event, mgl_c
event->key.system = ((xkey->state & Mod4Mask) != 0);
}
-static void mgl_window_handle_text_event(mgl_x11_window *self, XEvent *xev) {
+static void mgl_window_handle_text_event(mgl_window_x11 *self, XEvent *xev) {
/* Ignore silent keys */
if(XFilterEvent(xev, None))
return;
@@ -1068,7 +695,7 @@ static void mgl_window_handle_text_event(mgl_x11_window *self, XEvent *xev) {
memcpy(text_event.text.str, &buf[i], clen);
text_event.text.str[clen] = '\0';
/* Text may contain multiple codepoints so they need to separated into multiple events */
- if(!mgl_x11_window_append_event(self, &text_event))
+ if(!mgl_window_x11_append_event(self, &text_event))
break;
i += clen;
@@ -1084,7 +711,7 @@ static bool mgl_on_monitor_added(Display *display, mgl_window *mgl_window, XRROu
if(!rr_output_change_event->mode)
return false;
- if(mgl_x11_window_get_monitor_by_id(mgl_window, output_id))
+ if(mgl_window_x11_get_monitor_by_id(mgl_window, output_id))
return false;
if(out_info->nameLen >= (int)sizeof(display_name))
@@ -1101,7 +728,7 @@ static bool mgl_on_monitor_added(Display *display, mgl_window *mgl_window, XRROu
memcpy(display_name, out_info->name, out_info->nameLen);
display_name[out_info->nameLen] = '\0';
- monitor = mgl_x11_window_add_monitor(mgl_window, output_id, out_info->crtc, display_name,
+ monitor = mgl_window_x11_add_monitor(mgl_window, output_id, out_info->crtc, display_name,
(mgl_vec2i){ .x = crt_info->x, .y = crt_info->y },
(mgl_vec2i){ .x = (int)crt_info->width, .y = (int)crt_info->height },
monitor_info_get_framerate(mode_info));
@@ -1139,7 +766,7 @@ static bool mgl_on_monitor_state_changed(Display *display, mgl_window *mgl_windo
if(out_info && out_info->crtc && out_info->connection == RR_Connected) {
state_changed = mgl_on_monitor_added(display, mgl_window, rr_output_change_event, screen_res, rr_output_change_event->output, out_info, event);
} else {
- state_changed = mgl_x11_window_remove_monitor(mgl_window, rr_output_change_event->output, event);
+ state_changed = mgl_window_x11_remove_monitor(mgl_window, rr_output_change_event->output, event);
}
if(out_info)
@@ -1153,7 +780,7 @@ static bool mgl_on_monitor_property_changed(Display *display, mgl_window *mgl_wi
if(!rr_crtc_change_event->crtc)
return false;
- mgl_monitor *monitor = mgl_x11_window_get_monitor_by_crtc_id(mgl_window, rr_crtc_change_event->crtc);
+ mgl_monitor *monitor = mgl_window_x11_get_monitor_by_crtc_id(mgl_window, rr_crtc_change_event->crtc);
if(!monitor)
return false;
@@ -1195,8 +822,8 @@ static bool mgl_on_rr_notify(mgl_context *context, mgl_window *mgl_window, XEven
return false;
}
-static void mgl_x11_window_on_receive_event(mgl_window *self, XEvent *xev, mgl_event *event, mgl_context *context, bool injected) {
- mgl_x11_window *impl = self->impl;
+static void mgl_window_x11_on_receive_event(mgl_window *self, XEvent *xev, mgl_event *event, mgl_context *context, bool injected) {
+ mgl_window_x11 *impl = self->impl;
switch(xev->type - context->randr_event_base) {
case RRScreenChangeNotify: {
XRRUpdateConfiguration(xev);
@@ -1207,7 +834,7 @@ static void mgl_x11_window_on_receive_event(mgl_window *self, XEvent *xev, mgl_e
XRRNotifyEvent *rr_event = (XRRNotifyEvent*)xev;
if(mgl_on_rr_notify(context, self, xev, rr_event->subtype, event)) {
// TODO:
- //impl->num_monitors = mgl_x11_window->num_monitors;
+ //impl->num_monitors = mgl_window_x11->num_monitors;
return;
}
@@ -1292,11 +919,11 @@ static void mgl_x11_window_on_receive_event(mgl_window *self, XEvent *xev, mgl_e
while(XCheckTypedWindowEvent(context->connection, impl->window, ConfigureNotify, xev)) {}
if(xev->xconfigure.x != self->pos.x || xev->xconfigure.y != self->pos.y) {
- mgl_x11_window_on_move(self, xev->xconfigure.x, xev->xconfigure.y);
+ mgl_window_x11_on_move(self, xev->xconfigure.x, xev->xconfigure.y);
}
if(xev->xconfigure.width != self->size.x || xev->xconfigure.height != self->size.y) {
- mgl_x11_window_on_resize(self, xev->xconfigure.width, xev->xconfigure.height);
+ mgl_window_x11_on_resize(self, xev->xconfigure.width, xev->xconfigure.height);
event->type = MGL_EVENT_RESIZED;
event->size.width = self->size.x;
@@ -1415,18 +1042,18 @@ static void mgl_x11_window_on_receive_event(mgl_window *self, XEvent *xev, mgl_e
}
}
-static bool mgl_x11_window_poll_event(mgl_window *self, mgl_event *event) {
- mgl_x11_window *impl = self->impl;
+static bool mgl_window_x11_poll_event(mgl_window *self, mgl_event *event) {
+ mgl_window_x11 *impl = self->impl;
mgl_context *context = mgl_get_context();
Display *display = context->connection;
- if(mgl_x11_window_pop_event(impl, event))
+ if(mgl_window_x11_pop_event(impl, event))
return true;
if(XPending(display)) {
XNextEvent(display, &impl->xev);
if(impl->xev.xany.window == impl->window || impl->xev.type == ClientMessage || impl->xev.type == MappingNotify || impl->xev.type - context->randr_event_base >= 0)
- mgl_x11_window_on_receive_event(self, &impl->xev, event, context, false);
+ mgl_window_x11_on_receive_event(self, &impl->xev, event, context, false);
else
event->type = MGL_EVENT_UNKNOWN;
return true;
@@ -1435,29 +1062,20 @@ static bool mgl_x11_window_poll_event(mgl_window *self, mgl_event *event) {
}
}
-static bool mgl_x11_window_inject_x11_event(mgl_window *self, XEvent *xev, mgl_event *event) {
+static bool mgl_window_x11_inject_x11_event(mgl_window *self, XEvent *xev, mgl_event *event) {
mgl_context *context = mgl_get_context();
event->type = MGL_EVENT_UNKNOWN;
- mgl_x11_window_on_receive_event(self, xev, event, context, true);
+ mgl_window_x11_on_receive_event(self, xev, event, context, true);
return event->type != MGL_EVENT_UNKNOWN;
}
-static void mgl_x11_window_swap_buffers(mgl_window *self) {
- mgl_x11_window *impl = self->impl;
- switch(impl->render_api) {
- case MGL_RENDER_API_GLX: {
- mgl_x11_window_glx_swap_buffers(&impl->glx, impl->window);
- break;
- }
- case MGL_RENDER_API_EGL: {
- mgl_x11_window_egl_swap_buffers(&impl->egl, impl->window);
- break;
- }
- }
+static void mgl_window_x11_swap_buffers(mgl_window *self) {
+ mgl_window_x11 *impl = self->impl;
+ mgl_graphics_swap_buffers(&impl->graphics, (mgl_window_handle)impl->window);
}
-static void mgl_x11_window_set_visible(mgl_window *self, bool visible) {
- mgl_x11_window *impl = self->impl;
+static void mgl_window_x11_set_visible(mgl_window *self, bool visible) {
+ mgl_window_x11 *impl = self->impl;
mgl_context *context = mgl_get_context();
if(visible)
XMapWindow(context->connection, impl->window);
@@ -1467,7 +1085,7 @@ static void mgl_x11_window_set_visible(mgl_window *self, bool visible) {
}
/* TODO: Track keys with events instead, but somehow handle window focus lost */
-static bool mgl_x11_window_is_key_pressed(const mgl_window *self, mgl_key key) {
+static bool mgl_window_x11_is_key_pressed(const mgl_window *self, mgl_key key) {
(void)self;
if(key < 0 || key >= __MGL_NUM_KEYS__)
return false;
@@ -1488,7 +1106,7 @@ static bool mgl_x11_window_is_key_pressed(const mgl_window *self, mgl_key key) {
}
/* TODO: Track keys with events instead, but somehow handle window focus lost */
-static bool mgl_x11_window_is_mouse_button_pressed(const mgl_window *self, mgl_mouse_button button) {
+static bool mgl_window_x11_is_mouse_button_pressed(const mgl_window *self, mgl_mouse_button button) {
(void)self;
if(button < 0 || button >= __MGL_NUM_MOUSE_BUTTONS__)
return false;
@@ -1512,13 +1130,13 @@ static bool mgl_x11_window_is_mouse_button_pressed(const mgl_window *self, mgl_m
return false;
}
-static mgl_window_handle mgl_x11_window_get_system_handle(const mgl_window *self) {
- const mgl_x11_window *impl = self->impl;
- return impl->window;
+static mgl_window_handle mgl_window_x11_get_system_handle(const mgl_window *self) {
+ const mgl_window_x11 *impl = self->impl;
+ return (mgl_window_handle)impl->window;
}
-static void mgl_x11_window_close(mgl_window *self) {
- mgl_x11_window *impl = self->impl;
+static void mgl_window_x11_close(mgl_window *self) {
+ mgl_window_x11 *impl = self->impl;
mgl_context *context = mgl_get_context();
if(impl->window) {
XDestroyWindow(context->connection, impl->window);
@@ -1528,24 +1146,24 @@ static void mgl_x11_window_close(mgl_window *self) {
self->open = false;
}
-static void mgl_x11_window_set_cursor_visible(mgl_window *self, bool visible) {
- mgl_x11_window *impl = self->impl;
+static void mgl_window_x11_set_cursor_visible(mgl_window *self, bool visible) {
+ mgl_window_x11 *impl = self->impl;
mgl_context *context = mgl_get_context();
XDefineCursor(context->connection, impl->window, visible ? impl->default_cursor : impl->invisible_cursor);
}
-static void mgl_x11_window_set_vsync_enabled(mgl_window *self, bool enabled) {
- mgl_x11_window *impl = self->impl;
+static void mgl_window_x11_set_vsync_enabled(mgl_window *self, bool enabled) {
+ mgl_window_x11 *impl = self->impl;
self->vsync_enabled = enabled;
- set_vertical_sync_enabled(impl, self->vsync_enabled ? 1 : 0);
+ mgl_graphics_set_swap_interval(&impl->graphics, (mgl_window_handle)impl->window, self->vsync_enabled);
}
-static bool mgl_x11_window_is_vsync_enabled(const mgl_window *self) {
+static bool mgl_window_x11_is_vsync_enabled(const mgl_window *self) {
return self->vsync_enabled;
}
-static void mgl_x11_window_set_fullscreen(mgl_window *self, bool fullscreen) {
- mgl_x11_window *impl = self->impl;
+static void mgl_window_x11_set_fullscreen(mgl_window *self, bool fullscreen) {
+ mgl_window_x11 *impl = self->impl;
mgl_context *context = mgl_get_context();
XEvent xev;
@@ -1567,8 +1185,8 @@ static void mgl_x11_window_set_fullscreen(mgl_window *self, bool fullscreen) {
XFlush(context->connection);
}
-static bool mgl_x11_window_is_fullscreen(const mgl_window *self) {
- mgl_x11_window *impl = self->impl;
+static bool mgl_window_x11_is_fullscreen(const mgl_window *self) {
+ mgl_window_x11 *impl = self->impl;
mgl_context *context = mgl_get_context();
bool is_fullscreen = false;
@@ -1584,14 +1202,14 @@ static bool mgl_x11_window_is_fullscreen(const mgl_window *self) {
return is_fullscreen;
}
-static void mgl_x11_window_set_position(mgl_window *self, mgl_vec2i position) {
- mgl_x11_window *impl = self->impl;
+static void mgl_window_x11_set_position(mgl_window *self, mgl_vec2i position) {
+ mgl_window_x11 *impl = self->impl;
XMoveWindow(mgl_get_context()->connection, impl->window, position.x, position.y);
XFlush(mgl_get_context()->connection);
}
-static void mgl_x11_window_set_size(mgl_window *self, mgl_vec2i size) {
- mgl_x11_window *impl = self->impl;
+static void mgl_window_x11_set_size(mgl_window *self, mgl_vec2i size) {
+ mgl_window_x11 *impl = self->impl;
if(size.x < 0)
size.x = 0;
if(size.y < 0)
@@ -1600,8 +1218,8 @@ static void mgl_x11_window_set_size(mgl_window *self, mgl_vec2i size) {
XFlush(mgl_get_context()->connection);
}
-static void mgl_x11_window_set_clipboard(mgl_window *self, const char *str, size_t size) {
- mgl_x11_window *impl = self->impl;
+static void mgl_window_x11_set_clipboard(mgl_window *self, const char *str, size_t size) {
+ mgl_window_x11 *impl = self->impl;
mgl_context *context = mgl_get_context();
if(impl->clipboard_string) {
@@ -1615,7 +1233,7 @@ static void mgl_x11_window_set_clipboard(mgl_window *self, const char *str, size
/* Check if setting the selection owner was successful */
if(XGetSelectionOwner(context->connection, impl->clipboard_atom) != impl->window) {
- fprintf(stderr, "mgl error: mgl_x11_window_set_clipboard failed\n");
+ fprintf(stderr, "mgl error: mgl_window_x11_set_clipboard failed\n");
return;
}
@@ -1639,22 +1257,22 @@ static Atom find_matching_atom(const Atom *supported_atoms, size_t num_supported
return None;
}
-static mgl_clipboard_type atom_type_to_supported_clipboard_type(mgl_x11_window *mgl_x11_window, Atom type, int format) {
- if((type == mgl_x11_window->utf8_string_atom || type == XA_STRING || type == mgl_x11_window->text_atom) && format == 8) {
+static mgl_clipboard_type atom_type_to_supported_clipboard_type(mgl_window_x11 *mgl_window_x11, Atom type, int format) {
+ if((type == mgl_window_x11->utf8_string_atom || type == XA_STRING || type == mgl_window_x11->text_atom) && format == 8) {
return MGL_CLIPBOARD_TYPE_STRING;
- } else if(type == mgl_x11_window->image_png_atom && format == 8){
+ } else if(type == mgl_window_x11->image_png_atom && format == 8){
return MGL_CLIPBOARD_TYPE_IMAGE_PNG;
- } else if((type == mgl_x11_window->image_jpg_atom || type == mgl_x11_window->image_jpeg_atom) && format == 8){
+ } else if((type == mgl_window_x11->image_jpg_atom || type == mgl_window_x11->image_jpeg_atom) && format == 8){
return MGL_CLIPBOARD_TYPE_IMAGE_JPG;
- } else if(type == mgl_x11_window->image_gif_atom && format == 8){
+ } else if(type == mgl_window_x11->image_gif_atom && format == 8){
return MGL_CLIPBOARD_TYPE_IMAGE_GIF;
} else {
return -1;
}
}
-static bool mgl_x11_window_get_clipboard(mgl_window *self, mgl_clipboard_callback callback, void *userdata, uint32_t clipboard_types) {
- mgl_x11_window *impl = self->impl;
+static bool mgl_window_x11_get_clipboard(mgl_window *self, mgl_clipboard_callback callback, void *userdata, uint32_t clipboard_types) {
+ mgl_window_x11 *impl = self->impl;
assert(callback);
mgl_context *context = mgl_get_context();
@@ -1746,7 +1364,7 @@ static bool mgl_x11_window_get_clipboard(mgl_window *self, mgl_clipboard_callbac
bool got_data = false;
long chunk_size = 65536;
- //XDeleteProperty(context->connection, self->window, mgl_x11_window->incr_atom);
+ //XDeleteProperty(context->connection, self->window, mgl_window_x11->incr_atom);
//XFlush(context->connection);
while(mgl_clock_get_elapsed_time_seconds(&timeout_timer) < timeout_seconds) {
@@ -1847,7 +1465,7 @@ static bool clipboard_copy_string_callback(const unsigned char *data, size_t siz
return true;
}
-static bool mgl_x11_window_get_clipboard_string(mgl_window *self, char **str, size_t *size) {
+static bool mgl_window_x11_get_clipboard_string(mgl_window *self, char **str, size_t *size) {
assert(str);
assert(size);
@@ -1857,7 +1475,7 @@ static bool mgl_x11_window_get_clipboard_string(mgl_window *self, char **str, si
ClipboardStringCallbackData callback_data;
callback_data.str = str;
callback_data.size = size;
- const bool success = mgl_x11_window_get_clipboard(self, clipboard_copy_string_callback, &callback_data, MGL_CLIPBOARD_TYPE_STRING);
+ const bool success = mgl_window_x11_get_clipboard(self, clipboard_copy_string_callback, &callback_data, MGL_CLIPBOARD_TYPE_STRING);
if(!success) {
free(*str);
*str = NULL;
@@ -1866,68 +1484,65 @@ static bool mgl_x11_window_get_clipboard_string(mgl_window *self, char **str, si
return success;
}
-static void mgl_x11_window_set_key_repeat_enabled(mgl_window *self, bool enabled) {
+static void mgl_window_x11_set_key_repeat_enabled(mgl_window *self, bool enabled) {
self->key_repeat_enabled = enabled;
}
-static void mgl_x11_window_flush(mgl_window *self) {
+static void mgl_window_x11_flush(mgl_window *self) {
(void)self;
mgl_context *context = mgl_get_context();
XFlush(context->connection);
}
-static void* mgl_x11_window_get_egl_display(mgl_window *self) {
- mgl_x11_window *impl = self->impl;
- if(impl->render_api == MGL_RENDER_API_EGL)
- return impl->egl.egl_display;
+static void* mgl_window_x11_get_egl_display(mgl_window *self) {
+ mgl_window_x11 *impl = self->impl;
+ if(impl->graphics.graphics_api == MGL_GRAPHICS_API_EGL)
+ return mgl_graphics_get_display(&impl->graphics);
else
return NULL;
}
-static void* mgl_x11_window_get_egl_context(mgl_window *self) {
- mgl_x11_window *impl = self->impl;
- if(impl->render_api == MGL_RENDER_API_EGL)
- return impl->egl.egl_context;
+static void* mgl_window_x11_get_egl_context(mgl_window *self) {
+ mgl_window_x11 *impl = self->impl;
+ if(impl->graphics.graphics_api == MGL_GRAPHICS_API_EGL)
+ return mgl_graphics_get_context(&impl->graphics);
else
return NULL;
}
-bool mgl_x11_window_init(mgl_window *self, const char *title, const mgl_window_create_params *params, mgl_window_handle existing_window) {
- mgl_x11_window *impl = calloc(1, sizeof(mgl_x11_window));
+bool mgl_window_x11_init(mgl_window *self, const char *title, const mgl_window_create_params *params, mgl_window_handle existing_window) {
+ mgl_window_x11 *impl = calloc(1, sizeof(mgl_window_x11));
if(!impl)
return false;
- *self = (mgl_window) {
- .get_system_handle = mgl_x11_window_get_system_handle,
- .close = mgl_x11_window_close,
- .inject_x11_event = mgl_x11_window_inject_x11_event,
- .poll_event = mgl_x11_window_poll_event,
- .swap_buffers = mgl_x11_window_swap_buffers,
- .set_visible = mgl_x11_window_set_visible,
- .is_key_pressed = mgl_x11_window_is_key_pressed,
- .is_mouse_button_pressed = mgl_x11_window_is_mouse_button_pressed,
- .set_title = mgl_x11_window_set_title,
- .set_cursor_visible = mgl_x11_window_set_cursor_visible,
- .set_vsync_enabled = mgl_x11_window_set_vsync_enabled,
- .is_vsync_enabled = mgl_x11_window_is_vsync_enabled,
- .set_fullscreen = mgl_x11_window_set_fullscreen,
- .is_fullscreen = mgl_x11_window_is_fullscreen,
- .set_position = mgl_x11_window_set_position,
- .set_size = mgl_x11_window_set_size,
- .set_size_limits = mgl_x11_window_set_size_limits,
- .set_clipboard = mgl_x11_window_set_clipboard,
- .get_clipboard = mgl_x11_window_get_clipboard,
- .get_clipboard_string = mgl_x11_window_get_clipboard_string,
- .set_key_repeat_enabled = mgl_x11_window_set_key_repeat_enabled,
- .flush = mgl_x11_window_flush,
- .get_egl_display = mgl_x11_window_get_egl_display,
- .get_egl_context = mgl_x11_window_get_egl_context,
- .for_each_active_monitor_output = mgl_x11_window_for_each_active_monitor_output,
-
- .impl = impl,
- };
-
- impl->render_api = params ? params->render_api : MGL_RENDER_API_GLX;
+ self->get_system_handle = mgl_window_x11_get_system_handle;
+ self->deinit = mgl_window_x11_deinit;
+ self->close = mgl_window_x11_close;
+ self->inject_x11_event = mgl_window_x11_inject_x11_event;
+ self->poll_event = mgl_window_x11_poll_event;
+ self->swap_buffers = mgl_window_x11_swap_buffers;
+ self->set_visible = mgl_window_x11_set_visible;
+ self->is_key_pressed = mgl_window_x11_is_key_pressed;
+ self->is_mouse_button_pressed = mgl_window_x11_is_mouse_button_pressed;
+ self->set_title = mgl_window_x11_set_title;
+ self->set_cursor_visible = mgl_window_x11_set_cursor_visible;
+ self->set_vsync_enabled = mgl_window_x11_set_vsync_enabled;
+ self->is_vsync_enabled = mgl_window_x11_is_vsync_enabled;
+ self->set_fullscreen = mgl_window_x11_set_fullscreen;
+ self->is_fullscreen = mgl_window_x11_is_fullscreen;
+ self->set_position = mgl_window_x11_set_position;
+ self->set_size = mgl_window_x11_set_size;
+ self->set_size_limits = mgl_window_x11_set_size_limits;
+ self->set_clipboard = mgl_window_x11_set_clipboard;
+ self->get_clipboard = mgl_window_x11_get_clipboard;
+ self->get_clipboard_string = mgl_window_x11_get_clipboard_string;
+ self->set_key_repeat_enabled = mgl_window_x11_set_key_repeat_enabled;
+ self->flush = mgl_window_x11_flush;
+ self->get_egl_display = mgl_window_x11_get_egl_display;
+ self->get_egl_context = mgl_window_x11_get_egl_context;
+ self->for_each_active_monitor_output = mgl_window_x11_for_each_active_monitor_output;
+
+ self->impl = impl;
/* TODO: Use CLIPBOARD_MANAGER and SAVE_TARGETS to save clipboard in clipboard manager on exit */
@@ -1955,33 +1570,23 @@ bool mgl_x11_window_init(mgl_window *self, const char *title, const mgl_window_c
impl->support_alpha = params && params->support_alpha;
- switch(impl->render_api) {
- case MGL_RENDER_API_GLX: {
- if(!mgl_x11_window_glx_init(&impl->glx, impl->support_alpha)) {
- mgl_x11_window_deinit(self);
- return false;
- }
- break;
- }
- case MGL_RENDER_API_EGL: {
- if(!mgl_x11_window_egl_init(&impl->egl, impl->support_alpha)) {
- mgl_x11_window_deinit(self);
- return false;
- }
- break;
- }
+ const mgl_graphics_api graphics_api = params ? params->graphics_api : MGL_GRAPHICS_API_EGL;
+ const bool alpha = params && params->support_alpha;
+ if(!mgl_graphics_init(&impl->graphics, &(mgl_graphics_create_params){ .graphics_api = graphics_api, .alpha = alpha })) {
+ mgl_window_x11_deinit(self);
+ return false;
}
impl->default_cursor = XCreateFontCursor(context->connection, XC_arrow);
if(!impl->default_cursor) {
- mgl_x11_window_deinit(self);
+ mgl_window_x11_deinit(self);
return false;
}
const char data[1] = {0};
Pixmap blank_bitmap = XCreateBitmapFromData(context->connection, DefaultRootWindow(context->connection), data, 1, 1);
if(!blank_bitmap) {
- mgl_x11_window_deinit(self);
+ mgl_window_x11_deinit(self);
return false;
}
@@ -1989,14 +1594,14 @@ bool mgl_x11_window_init(mgl_window *self, const char *title, const mgl_window_c
impl->invisible_cursor = XCreatePixmapCursor(context->connection, blank_bitmap, blank_bitmap, &dummy, &dummy, 0, 0);
XFreePixmap(context->connection, blank_bitmap);
if(!impl->invisible_cursor) {
- mgl_x11_window_deinit(self);
+ mgl_window_x11_deinit(self);
return false;
}
x11_events_circular_buffer_init(&impl->events);
- if(!mgl_x11_setup_window(self, title, params, existing_window)) {
- mgl_x11_window_deinit(self);
+ if(!mgl_x11_setup_window(self, title, params, (Window)existing_window)) {
+ mgl_window_x11_deinit(self);
return false;
}
@@ -2004,13 +1609,13 @@ bool mgl_x11_window_init(mgl_window *self, const char *title, const mgl_window_c
return true;
}
-void mgl_x11_window_deinit(mgl_window *self) {
- mgl_x11_window *impl = self->impl;
+void mgl_window_x11_deinit(mgl_window *self) {
+ mgl_window_x11 *impl = self->impl;
mgl_context *context = mgl_get_context();
if(!impl)
return;
- mgl_x11_window_clear_monitors(self);
+ mgl_window_x11_clear_monitors(self);
if(impl->color_map) {
XFreeColormap(context->connection, impl->color_map);
@@ -2037,18 +1642,8 @@ void mgl_x11_window_deinit(mgl_window *self) {
impl->xim = NULL;
}
- switch(impl->render_api) {
- case MGL_RENDER_API_GLX: {
- mgl_x11_window_glx_deinit(&impl->glx);
- break;
- }
- case MGL_RENDER_API_EGL: {
- mgl_x11_window_egl_deinit(&impl->egl);
- break;
- }
- }
-
- mgl_x11_window_close(self);
+ mgl_graphics_deinit(&impl->graphics);
+ mgl_window_x11_close(self);
if(impl->clipboard_string) {
free(impl->clipboard_string);
diff --git a/tests/main.c b/tests/main.c
index 44e3a27..9e6aaa5 100644
--- a/tests/main.c
+++ b/tests/main.c
@@ -234,7 +234,7 @@ int main(void) {
test_hash_map();
test_utf8();
- if(mgl_init() != 0)
+ if(mgl_init(MGL_WINDOW_SYSTEM_NATIVE) != 0)
return 1;
mgl_texture texture;