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.c781
1 files changed, 781 insertions, 0 deletions
diff --git a/src/window/wayland.c b/src/window/wayland.c
new file mode 100644
index 0000000..f889126
--- /dev/null
+++ b/src/window/wayland.c
@@ -0,0 +1,781 @@
+#include "../../include/mgl/window/wayland.h"
+#include "../../include/mgl/mgl.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <wayland-client.h>
+#include <wayland-egl.h>
+#include "xdg-shell-client-protocol.h"
+
+static void mgl_window_wayland_deinit(mgl_window *self);
+
+typedef struct {
+ struct wl_egl_window *window;
+ struct wl_registry *registry;
+ struct wl_surface *surface;
+ struct wl_compositor *compositor;
+ struct wl_shell *shell;
+ struct wl_shell_surface *shell_surface;
+ struct wl_seat *seat;
+ struct wl_pointer *pointer;
+ struct wl_keyboard *keyboard;
+
+ struct xdg_wm_base *xdg_wm_base;
+ struct xdg_surface *xdg_surface;
+ struct xdg_toplevel *xdg_toplevel;
+
+ bool mouse_moved;
+ mgl_vec2i mouse_position;
+
+ mgl_graphics graphics;
+} mgl_window_wayland;
+
+static void mgl_window_wayland_on_resize(mgl_window *self, int width, int height) {
+ mgl_window_wayland *impl = self->impl;
+ self->size.x = width;
+ self->size.y = height;
+ wl_egl_window_resize(impl->window, self->size.x, self->size.y, 0, 0);
+
+ mgl_view view;
+ view.position = (mgl_vec2i){ 0, 0 };
+ view.size = self->size;
+ mgl_window_set_view(self, &view);
+ mgl_window_set_scissor(self, &(mgl_scissor){ .position = { 0, 0 }, .size = self->size });
+}
+
+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_interface.name) == 0) {
+ if(impl->compositor)
+ return;
+
+ 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, "mgl warning: wl output interface version is < 4, expected >= 4\n");
+ return;
+ }
+
+ if(self->num_monitors == MGL_MAX_MONITORS) {
+ fprintf(stderr, "mgl 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);
+ } else if(strcmp(interface, wl_shell_interface.name) == 0) {
+ if(impl->shell)
+ return;
+
+ impl->shell = wl_registry_bind(registry, name, &wl_shell_interface, 1);
+ } else if(strcmp(interface, xdg_wm_base_interface.name) == 0) {
+ if(impl->xdg_wm_base)
+ return;
+
+ impl->xdg_wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
+ } else if(strcmp(interface, wl_seat_interface.name) == 0) {
+ if(version < 5) {
+ fprintf(stderr, "mgl warning: wl seat interface version is < 5, expected >= 5\n");
+ return;
+ }
+
+ if(impl->seat)
+ return;
+
+ impl->seat = wl_registry_bind(registry, name, &wl_seat_interface, 5);
+ }
+}
+
+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,
+};
+
+static void shell_surface_ping(void *data, struct wl_shell_surface *shell_surface, uint32_t serial) {
+ wl_shell_surface_pong(shell_surface, serial);
+}
+
+static void shell_surface_configure(void *data, struct wl_shell_surface *shell_surface, uint32_t edges, int32_t width, int32_t height) {
+ mgl_window *self = data;
+ mgl_window_wayland *impl = self->impl;
+ wl_egl_window_resize(impl->window, width, height, 0, 0);
+}
+
+void shell_surface_popup_done(void *data, struct wl_shell_surface *shell_surface) {
+
+}
+
+static struct wl_shell_surface_listener shell_surface_listener = {
+ .ping = shell_surface_ping,
+ .configure = shell_surface_configure,
+ .popup_done = shell_surface_popup_done,
+};
+
+static void xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial) {
+ xdg_wm_base_pong(shell, serial);
+}
+
+static const struct xdg_wm_base_listener wm_base_listener = {
+ .ping = xdg_wm_base_ping,
+};
+
+static void xdg_surface_configure(void *data, struct xdg_surface *surface, uint32_t serial) {
+ xdg_surface_ack_configure(surface, serial);
+ // TODO:
+ //window->wait_for_configure = false;
+}
+
+static const struct xdg_surface_listener xdg_surface_listener = {
+ .configure = xdg_surface_configure,
+};
+
+static void xdg_toplevel_configure(void *data, struct xdg_toplevel *toplevel, int32_t width, int32_t height, struct wl_array *states) {
+ mgl_window *self = data;
+ mgl_window_wayland *impl = self->impl;
+ // TODO:
+ mgl_window_wayland_on_resize(self, width, height);
+ // struct window *window = data;
+ // uint32_t *p;
+
+ // window->fullscreen = 0;
+ // window->maximized = 0;
+ // wl_array_for_each(p, states) {
+ // uint32_t state = *p;
+ // switch (state) {
+ // case XDG_TOPLEVEL_STATE_FULLSCREEN:
+ // window->fullscreen = 1;
+ // break;
+ // case XDG_TOPLEVEL_STATE_MAXIMIZED:
+ // window->maximized = 1;
+ // break;
+ // }
+ // }
+
+ // if (width > 0 && height > 0) {
+ // if (!window->fullscreen && !window->maximized) {
+ // window->window_size.width = width;
+ // window->window_size.height = height;
+ // }
+ // window->geometry.width = width;
+ // window->geometry.height = height;
+ // } else if (!window->fullscreen && !window->maximized) {
+ // window->geometry = window->window_size;
+ // }
+
+ // if (window->native)
+ // wl_egl_window_resize(window->native,
+ // window->geometry.width,
+ // window->geometry.height, 0, 0);
+}
+
+static void xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel) {
+ // TODO:
+ //running = 0;
+}
+
+static const struct xdg_toplevel_listener xdg_toplevel_listener = {
+ .configure = xdg_toplevel_configure,
+ .close = xdg_toplevel_close,
+};
+
+static void
+wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
+ uint32_t serial, struct wl_surface *surface,
+ wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+ // // Set our pointer
+ // wl_pointer_set_cursor(wl_pointer, serial, cursor_surface,
+ // cursor_image->hotspot_x, cursor_image->hotspot_y);
+}
+
+static void
+wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
+ uint32_t serial, struct wl_surface *surface)
+{
+}
+
+static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
+ mgl_window *self = data;
+ mgl_window_wayland *impl = self->impl;
+ impl->mouse_moved = true;
+ impl->mouse_position = (mgl_vec2i){ .x = wl_fixed_to_int(surface_x), .y = wl_fixed_to_int(surface_y) };
+}
+
+static void
+wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
+ uint32_t time, uint32_t button, uint32_t state)
+{
+
+}
+
+static void
+wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time,
+ uint32_t axis, wl_fixed_t value)
+{
+
+}
+
+static void
+wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer,
+ uint32_t axis_source)
+{
+
+}
+
+static void
+wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, uint32_t axis)
+{
+
+}
+
+static void
+wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
+ uint32_t axis, int32_t discrete)
+{
+
+}
+
+static void
+wl_pointer_frame(void *data, struct wl_pointer *wl_pointer)
+{
+ mgl_window *self = data;
+ mgl_window_wayland *impl = self->impl;
+ if(impl->mouse_moved) {
+ impl->mouse_moved = false;
+ self->cursor_position = impl->mouse_position;
+ }
+}
+
+static const struct wl_pointer_listener wl_pointer_listener = {
+ .enter = wl_pointer_enter,
+ .leave = wl_pointer_leave,
+ .motion = wl_pointer_motion,
+ .button = wl_pointer_button,
+ .axis = wl_pointer_axis,
+ .frame = wl_pointer_frame,
+ .axis_source = wl_pointer_axis_source,
+ .axis_stop = wl_pointer_axis_stop,
+ .axis_discrete = wl_pointer_axis_discrete,
+};
+
+static void
+wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
+ uint32_t format, int32_t fd, uint32_t size)
+{
+ // struct client_state *client_state = data;
+ // assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1);
+
+ // char *map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ // assert(map_shm != MAP_FAILED);
+
+ // struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_string(
+ // client_state->xkb_context, map_shm,
+ // XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
+ // munmap(map_shm, size);
+ // close(fd);
+
+ // struct xkb_state *xkb_state = xkb_state_new(xkb_keymap);
+ // xkb_keymap_unref(client_state->xkb_keymap);
+ // xkb_state_unref(client_state->xkb_state);
+ // client_state->xkb_keymap = xkb_keymap;
+ // client_state->xkb_state = xkb_state;
+}
+
+static void
+wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard,
+ uint32_t serial, struct wl_surface *surface,
+ struct wl_array *keys)
+{
+ // struct client_state *client_state = data;
+ // fprintf(stderr, "keyboard enter; keys pressed are:\n");
+ // uint32_t *key;
+ // wl_array_for_each(key, keys) {
+ // char buf[128];
+ // xkb_keysym_t sym = xkb_state_key_get_one_sym(
+ // client_state->xkb_state, *key + 8);
+ // xkb_keysym_get_name(sym, buf, sizeof(buf));
+ // fprintf(stderr, "sym: %-12s (%d), ", buf, sym);
+ // xkb_state_key_get_utf8(client_state->xkb_state,
+ // *key + 8, buf, sizeof(buf));
+ // fprintf(stderr, "utf8: '%s'\n", buf);
+ // }
+}
+
+static void
+wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard,
+ uint32_t serial, struct wl_surface *surface)
+{
+ //fprintf(stderr, "keyboard leave\n");
+}
+
+static void
+wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard,
+ uint32_t serial, uint32_t mods_depressed,
+ uint32_t mods_latched, uint32_t mods_locked,
+ uint32_t group)
+{
+ // struct client_state *client_state = data;
+ // xkb_state_update_mask(client_state->xkb_state,
+ // mods_depressed, mods_latched, mods_locked, 0, 0, group);
+}
+
+static void
+wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
+ int32_t rate, int32_t delay)
+{
+ /* Left as an exercise for the reader */
+}
+
+static void
+wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard,
+ uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
+{
+ // struct client_state *client_state = data;
+ // char buf[128];
+ // uint32_t keycode = key + 8;
+ // xkb_keysym_t sym = xkb_state_key_get_one_sym(
+ // client_state->xkb_state, keycode);
+ // xkb_keysym_get_name(sym, buf, sizeof(buf));
+ // const char *action =
+ // state == WL_KEYBOARD_KEY_STATE_PRESSED ? "press" : "release";
+ // fprintf(stderr, "key %s: sym: %-12s (%d), ", action, buf, sym);
+ // xkb_state_key_get_utf8(client_state->xkb_state, keycode,
+ // buf, sizeof(buf));
+ // fprintf(stderr, "utf8: '%s'\n", buf);
+}
+
+static const struct wl_keyboard_listener wl_keyboard_listener = {
+ .keymap = wl_keyboard_keymap,
+ .enter = wl_keyboard_enter,
+ .leave = wl_keyboard_leave,
+ .key = wl_keyboard_key,
+ .modifiers = wl_keyboard_modifiers,
+ .repeat_info = wl_keyboard_repeat_info,
+};
+
+static void wl_seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) {
+ struct mgl_window *self = data;
+ mgl_window_wayland *impl = self->impl;
+ const bool have_pointer = capabilities & WL_SEAT_CAPABILITY_POINTER;
+ const bool have_keyboard = capabilities & WL_SEAT_CAPABILITY_KEYBOARD;
+
+ if(have_pointer && impl->pointer == NULL) {
+ impl->pointer = wl_seat_get_pointer(impl->seat);
+ wl_pointer_add_listener(impl->pointer, &wl_pointer_listener, self);
+ } else if(!have_pointer && impl->pointer != NULL) {
+ wl_pointer_release(impl->pointer);
+ impl->pointer = NULL;
+ }
+
+ if(have_keyboard && impl->keyboard == NULL) {
+ impl->keyboard = wl_seat_get_keyboard(impl->seat);
+ wl_keyboard_add_listener(impl->keyboard, &wl_keyboard_listener, self);
+ } else if(!have_keyboard && impl->keyboard != NULL) {
+ wl_keyboard_release(impl->keyboard);
+ impl->keyboard = NULL;
+ }
+}
+
+static void wl_seat_name(void *data, struct wl_seat *wl_seat, const char *name) {
+ fprintf(stderr, "seat name: %s\n", name);
+}
+
+static const struct wl_seat_listener wl_seat_listener = {
+ .capabilities = wl_seat_capabilities,
+ .name = wl_seat_name,
+};
+
+// TODO: 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_context *context = mgl_get_context();
+
+ 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->registry = wl_display_get_registry(context->connection); /* TODO: Error checking */
+ wl_registry_add_listener(impl->registry, &registry_listener, self); /* TODO: Error checking */
+
+ /* Fetch globals */
+ wl_display_roundtrip(context->connection);
+
+ /* Fetch wl_output */
+ //wl_display_roundtrip(context->connection);
+
+ if(!impl->compositor) {
+ fprintf(stderr, "mgl error: mgl_wayland_setup_window: failed to find compositor\n");
+ return false;
+ }
+
+ if(!impl->xdg_wm_base && !impl->shell) {
+ fprintf(stderr, "mgl error: mgl_wayland_setup_window: failed to find shell\n");
+ return false;
+ }
+
+ if(!impl->seat) {
+ fprintf(stderr, "mgl error: mgl_wayland_setup_window: failed to find seat\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;
+ }
+
+ wl_seat_add_listener(impl->seat, &wl_seat_listener, self);
+
+ if(impl->xdg_wm_base) {
+ // TODO: Error check, cleanup
+ xdg_wm_base_add_listener(impl->xdg_wm_base, &wm_base_listener, self);
+
+ impl->xdg_surface = xdg_wm_base_get_xdg_surface(impl->xdg_wm_base, impl->surface);
+ xdg_surface_add_listener(impl->xdg_surface, &xdg_surface_listener, self);
+
+ impl->xdg_toplevel = xdg_surface_get_toplevel(impl->xdg_surface);
+ xdg_toplevel_add_listener(impl->xdg_toplevel, &xdg_toplevel_listener, self);
+
+ xdg_toplevel_set_title(impl->xdg_toplevel, title);
+ if(params && params->class_name)
+ xdg_toplevel_set_app_id(impl->xdg_toplevel, params->class_name);
+ } else {
+ // TODO: Error check, cleanup
+ impl->shell_surface = wl_shell_get_shell_surface(impl->shell, impl->surface);
+ wl_shell_surface_add_listener(impl->shell_surface, &shell_surface_listener, self);
+ wl_shell_surface_set_toplevel(impl->shell_surface);
+ wl_shell_surface_set_title(impl->shell_surface, title);
+ if(params && params->class_name)
+ wl_shell_surface_set_class(impl->shell_surface, params->class_name);
+ }
+
+ wl_surface_commit(impl->surface);
+
+ // TODO: Error check
+ struct wl_region *region = wl_compositor_create_region(impl->compositor);
+ wl_region_add(region, 0, 0, self->size.x, self->size.y);
+ wl_surface_set_opaque_region(impl->surface, region);
+ wl_region_destroy(region);
+
+ 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;
+ }
+
+ //mgl_window_x11_on_move(self, window_pos.x, window_pos.y);
+ mgl_window_wayland_on_resize(self, self->size.x, self->size.y);
+
+ self->open = true;
+ self->focused = false;
+ return true;
+}
+
+static mgl_window_handle mgl_window_wayland_get_system_handle(const mgl_window *self) {
+ const mgl_window_wayland *impl = self->impl;
+ return (mgl_window_handle)impl->window;
+}
+
+static void mgl_window_wayland_close(mgl_window *self) {
+ mgl_window_wayland *impl = self->impl;
+
+ if(impl->window) {
+ wl_egl_window_destroy(impl->window);
+ impl->window = NULL;
+ }
+
+ if(impl->surface) {
+ wl_surface_destroy(impl->surface);
+ impl->surface = NULL;
+ }
+
+ self->open = false;
+}
+
+static bool mgl_window_wayland_poll_event(mgl_window *self, mgl_event *event) {
+ mgl_context *context = mgl_get_context();
+ struct wl_display *display = context->connection;
+ const bool events_available = wl_display_dispatch_pending(display) > 0;
+ //wl_display_flush(display);
+ /* TODO: Return event here, pop from circular buffer */
+ return events_available;
+}
+
+static void mgl_window_wayland_swap_buffers(mgl_window *self) {
+ mgl_window_wayland *impl = self->impl;
+ mgl_graphics_swap_buffers(&impl->graphics, (mgl_window_handle)impl->window);
+}
+
+static void mgl_window_wayland_set_visible(mgl_window *self, bool visible) {
+ fprintf(stderr, "TODO: Implement\n");
+}
+
+static bool mgl_window_wayland_is_key_pressed(const mgl_window *self, mgl_key key) {
+ (void)self;
+ if(key < 0 || key >= __MGL_NUM_KEYS__)
+ return false;
+
+ fprintf(stderr, "TODO: Implement\n");
+ return false;
+}
+
+static bool mgl_window_wayland_is_mouse_button_pressed(const mgl_window *self, mgl_mouse_button button) {
+ (void)self;
+ if(button < 0 || button >= __MGL_NUM_MOUSE_BUTTONS__)
+ return false;
+
+ fprintf(stderr, "TODO: Implement\n");
+ return false;
+}
+
+static void mgl_window_wayland_set_title(mgl_window *self, const char *title) {
+ mgl_window_wayland *impl = self->impl;
+ // TODO: Check if wl_display_flush is needed after these calls
+ if(impl->xdg_toplevel)
+ xdg_toplevel_set_title(impl->xdg_toplevel, title);
+ else
+ wl_shell_surface_set_title(impl->shell_surface, title);
+}
+
+static void mgl_window_wayland_set_cursor_visible(mgl_window *self, bool visible) {
+ fprintf(stderr, "TODO: Implement\n");
+}
+
+static void mgl_window_wayland_set_vsync_enabled(mgl_window *self, bool enabled) {
+ mgl_window_wayland *impl = self->impl;
+ self->vsync_enabled = enabled;
+ if(!mgl_graphics_set_swap_interval(&impl->graphics, (mgl_window_handle)impl->window, self->vsync_enabled))
+ fprintf(stderr, "mgl warning: mgl_window_wayland_set_vsync_enabled: failed to enable vsync\n");
+}
+
+static bool mgl_window_wayland_is_vsync_enabled(const mgl_window *self) {
+ return self->vsync_enabled;
+}
+
+static void mgl_window_wayland_set_fullscreen(mgl_window *self, bool fullscreen) {
+ mgl_window_wayland *impl = self->impl;
+ // TODO: The last argument is the monitor we want to fullscreen on. Use this!
+ if(impl->xdg_toplevel) {
+ if(fullscreen)
+ xdg_toplevel_set_fullscreen(impl->xdg_toplevel, NULL);
+ else
+ xdg_toplevel_unset_fullscreen(impl->xdg_toplevel);
+ } else {
+ if(fullscreen)
+ wl_shell_surface_set_fullscreen(impl->shell_surface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, NULL);
+ else
+ fprintf(stderr, "TODO: Implement\n");
+ }
+}
+
+static bool mgl_window_wayland_is_fullscreen(const mgl_window *self) {
+ fprintf(stderr, "TODO: Implement\n");
+ return false;
+}
+
+static void mgl_window_wayland_set_position(mgl_window *self, mgl_vec2i position) {
+ fprintf(stderr, "TODO: Implement\n");
+}
+
+static void mgl_window_wayland_set_size(mgl_window *self, mgl_vec2i size) {
+ fprintf(stderr, "TODO: Implement\n");
+}
+
+static void mgl_window_wayland_set_size_limits(mgl_window *self, mgl_vec2i minimum, mgl_vec2i maximum) {
+ mgl_window_wayland *impl = self->impl;
+ if(impl->xdg_toplevel) {
+ xdg_toplevel_set_min_size(impl->xdg_toplevel, minimum.x, minimum.y);
+ xdg_toplevel_set_max_size(impl->xdg_toplevel, maximum.x, maximum.y);
+ } else {
+ fprintf(stderr, "TODO: Implement\n");
+ }
+}
+
+static void mgl_window_wayland_set_clipboard(mgl_window *self, const char *str, size_t size) {
+ fprintf(stderr, "TODO: Implement\n");
+}
+
+static bool mgl_window_wayland_get_clipboard(mgl_window *self, mgl_clipboard_callback callback, void *userdata, uint32_t clipboard_types) {
+ fprintf(stderr, "TODO: Implement\n");
+ return false;
+}
+
+static void mgl_window_wayland_set_key_repeat_enabled(mgl_window *self, bool enabled) {
+ self->key_repeat_enabled = enabled;
+ // TODO: Implement
+}
+
+static void mgl_window_wayland_flush(mgl_window *self) {
+ (void)self;
+ mgl_context *context = mgl_get_context();
+ struct wl_display *display = context->connection;
+ wl_display_flush(display);
+}
+
+static void* mgl_window_wayland_get_egl_display(mgl_window *self) {
+ mgl_window_wayland *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_window_wayland_get_egl_context(mgl_window *self) {
+ mgl_window_wayland *impl = self->impl;
+ if(impl->graphics.graphics_api == MGL_GRAPHICS_API_EGL)
+ return mgl_graphics_get_context(&impl->graphics);
+ else
+ return NULL;
+}
+
+static void mgl_window_wayland_for_each_active_monitor_output(mgl_window *self, mgl_active_monitor_callback callback, void *userdata) {
+ fprintf(stderr, "TODO: Implement\n");
+}
+
+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_wayland_get_system_handle;
+ self->deinit = mgl_window_wayland_deinit;
+ self->close = mgl_window_wayland_close;
+ self->poll_event = mgl_window_wayland_poll_event;
+ self->swap_buffers = mgl_window_wayland_swap_buffers;
+ self->set_visible = mgl_window_wayland_set_visible;
+ self->is_key_pressed = mgl_window_wayland_is_key_pressed;
+ self->is_mouse_button_pressed = mgl_window_wayland_is_mouse_button_pressed;
+ self->set_title = mgl_window_wayland_set_title;
+ self->set_cursor_visible = mgl_window_wayland_set_cursor_visible;
+ self->set_vsync_enabled = mgl_window_wayland_set_vsync_enabled;
+ self->is_vsync_enabled = mgl_window_wayland_is_vsync_enabled;
+ self->set_fullscreen = mgl_window_wayland_set_fullscreen;
+ self->is_fullscreen = mgl_window_wayland_is_fullscreen;
+ self->set_position = mgl_window_wayland_set_position;
+ self->set_size = mgl_window_wayland_set_size;
+ self->set_size_limits = mgl_window_wayland_set_size_limits;
+ self->set_clipboard = mgl_window_wayland_set_clipboard;
+ self->get_clipboard = mgl_window_wayland_get_clipboard;
+ self->set_key_repeat_enabled = mgl_window_wayland_set_key_repeat_enabled;
+ self->flush = mgl_window_wayland_flush;
+ self->get_egl_display = mgl_window_wayland_get_egl_display;
+ self->get_egl_context = mgl_window_wayland_get_egl_context;
+ self->for_each_active_monitor_output = mgl_window_wayland_for_each_active_monitor_output;
+ 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);
+ mgl_window_wayland_close(self);
+
+ if(impl->xdg_toplevel) {
+ xdg_toplevel_destroy(impl->xdg_toplevel);
+ impl->xdg_toplevel = NULL;
+ }
+
+ if(impl->xdg_surface) {
+ xdg_surface_destroy(impl->xdg_surface);
+ impl->xdg_surface = NULL;
+ }
+
+ if(impl->shell_surface) {
+ wl_shell_surface_destroy(impl->shell_surface);
+ impl->shell_surface = NULL;
+ }
+
+ if(impl->pointer) {
+ wl_pointer_release(impl->pointer);
+ impl->pointer = NULL;
+ }
+
+ if(impl->keyboard) {
+ wl_keyboard_release(impl->keyboard);
+ impl->keyboard = NULL;
+ }
+
+ if(impl->seat) {
+ wl_seat_destroy(impl->seat);
+ impl->seat = NULL;
+ }
+
+ if(impl->shell) {
+ wl_shell_destroy(impl->shell);
+ impl->shell = NULL;
+ }
+
+ if(impl->xdg_wm_base) {
+ xdg_wm_base_destroy(impl->xdg_wm_base);
+ impl->xdg_wm_base = NULL;
+ }
+
+ if(impl->compositor) {
+ wl_compositor_destroy(impl->compositor);
+ impl->compositor = NULL;
+ }
+
+ if(impl->registry) {
+ wl_registry_destroy(impl->registry);
+ impl->registry = NULL;
+ }
+
+ mgl_context *context = mgl_get_context();
+ if(context->current_window == self)
+ context->current_window = NULL;
+
+ free(self->impl);
+ self->impl = NULL;
+}