aboutsummaryrefslogtreecommitdiff
path: root/src/window/wayland.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/window/wayland.c')
-rw-r--r--src/window/wayland.c214
1 files changed, 214 insertions, 0 deletions
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;
+}