diff options
Diffstat (limited to 'src/window')
-rw-r--r-- | src/window/wayland.c | 404 | ||||
-rw-r--r-- | src/window/x11.c | 75 |
2 files changed, 360 insertions, 119 deletions
diff --git a/src/window/wayland.c b/src/window/wayland.c index 2671e53..20c5c7a 100644 --- a/src/window/wayland.c +++ b/src/window/wayland.c @@ -1,21 +1,28 @@ #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> +#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_display *display; 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 xdg_wm_base *xdg_wm_base; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *xdg_toplevel; mgl_graphics graphics; } mgl_window_wayland; @@ -24,7 +31,7 @@ static void registry_add_object(void *data, struct wl_registry *registry, uint32 (void)version; mgl_window *self = data; mgl_window_wayland *impl = self->impl; - if(strcmp(interface, "wl_compositor") == 0) { + if(strcmp(interface, wl_compositor_interface.name) == 0) { if(impl->compositor) { wl_compositor_destroy(impl->compositor); impl->compositor = NULL; @@ -52,6 +59,18 @@ static void registry_add_object(void *data, struct wl_registry *registry, uint32 // .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) { + wl_shell_destroy(impl->shell); + impl->shell = NULL; + } + 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) { + xdg_wm_base_destroy(impl->xdg_wm_base); + impl->xdg_wm_base = NULL; + } + impl->xdg_wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); } } @@ -67,9 +86,98 @@ static struct wl_registry_listener registry_listener = { .global_remove = registry_remove_object, }; -// TODO: Use title, params and existing_window +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: + wl_egl_window_resize(impl->window, width, height, 0, 0); + // 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, +}; + + +// 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) { @@ -78,73 +186,256 @@ bool mgl_wayland_setup_window(mgl_window *self, const char *title, const mgl_win } 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 */ + impl->registry = wl_display_get_registry(context->connection); /* TODO: Error checking */ wl_registry_add_listener(impl->registry, ®istry_listener, self); /* TODO: Error checking */ /* Fetch globals */ - wl_display_roundtrip(impl->display); + wl_display_roundtrip(context->connection); /* Fetch wl_output */ - //wl_display_roundtrip(impl->display); + //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; + } + 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; } + 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); + } 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); + } + + 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_resize(self, self->size.x, self->size.y); + //mgl_window_x11_on_move(self, window_pos.x, window_pos.y); + 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 }); + + 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) { + fprintf(stderr, "TODO: Implement\n"); +} + +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_wm_base) { + 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) { + 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_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->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)) { @@ -179,15 +470,31 @@ void mgl_window_wayland_deinit(mgl_window *self) { return; mgl_graphics_deinit(&impl->graphics); + mgl_window_wayland_close(self); - if(impl->window) { - wl_egl_window_destroy(impl->window); - impl->window = NULL; + if(impl->xdg_toplevel) { + xdg_toplevel_destroy(impl->xdg_toplevel); + impl->xdg_toplevel = NULL; } - if(impl->surface) { - wl_surface_destroy(impl->surface); - impl->surface = 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->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) { @@ -200,11 +507,6 @@ void mgl_window_wayland_deinit(mgl_window *self) { 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; diff --git a/src/window/x11.c b/src/window/x11.c index 113fc1a..cf44ac2 100644 --- a/src/window/x11.c +++ b/src/window/x11.c @@ -4,13 +4,6 @@ #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> @@ -18,6 +11,13 @@ #include <assert.h> #include <unistd.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> + 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 */ @@ -34,7 +34,6 @@ typedef struct { } x11_events_circular_buffer; typedef struct { - void *dpy; Window window; char *clipboard_string; size_t clipboard_size; @@ -515,16 +514,6 @@ static bool mgl_x11_setup_window(mgl_window *self, const char *title, const mgl_ self->vsync_enabled = true; 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); - context->gl.glEnable(GL_SCISSOR_TEST); - context->gl.glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - context->gl.glEnableClientState(GL_VERTEX_ARRAY); - context->gl.glEnableClientState(GL_TEXTURE_COORD_ARRAY); - context->gl.glEnableClientState(GL_COLOR_ARRAY); - context->gl.glPixelStorei(GL_PACK_ALIGNMENT, 1); - context->gl.glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - Window dummy_w; int dummy_i; unsigned int dummy_u; @@ -1436,54 +1425,6 @@ static bool mgl_window_x11_get_clipboard(mgl_window *self, mgl_clipboard_callbac return success; } -typedef struct { - char **str; - size_t *size; -} ClipboardStringCallbackData; - -static bool clipboard_copy_string_callback(const unsigned char *data, size_t size, mgl_clipboard_type clipboard_type, void *userdata) { - ClipboardStringCallbackData *callback_data = userdata; - if(clipboard_type != MGL_CLIPBOARD_TYPE_STRING) { - free(*callback_data->str); - *callback_data->str = NULL; - *callback_data->size = 0; - return false; - } - - char *new_data = realloc(*callback_data->str, *callback_data->size + size); - if(!new_data) { - free(*callback_data->str); - *callback_data->str = NULL; - *callback_data->size = 0; - return false; - } - - memcpy(new_data + *callback_data->size, data, size); - - *callback_data->str = new_data; - *callback_data->size += size; - return true; -} - -static bool mgl_window_x11_get_clipboard_string(mgl_window *self, char **str, size_t *size) { - assert(str); - assert(size); - - *str = NULL; - *size = 0; - - ClipboardStringCallbackData callback_data; - callback_data.str = str; - callback_data.size = size; - 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; - *size = 0; - } - return success; -} - static void mgl_window_x11_set_key_repeat_enabled(mgl_window *self, bool enabled) { self->key_repeat_enabled = enabled; } @@ -1535,13 +1476,11 @@ bool mgl_window_x11_init(mgl_window *self, const char *title, const mgl_window_c 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 */ |