#include "../../../include/mgl/window/wayland.h" #include "../../../include/mgl/mgl.h" #include #include #include #include #include #include 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; }