diff options
Diffstat (limited to 'src/window/wayland.c')
-rw-r--r-- | src/window/wayland.c | 214 |
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, ®istry_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; +} |