diff options
Diffstat (limited to 'src/window/wayland.c')
-rw-r--r-- | src/window/wayland.c | 313 |
1 files changed, 289 insertions, 24 deletions
diff --git a/src/window/wayland.c b/src/window/wayland.c index 20c5c7a..c85499c 100644 --- a/src/window/wayland.c +++ b/src/window/wayland.c @@ -19,32 +19,50 @@ typedef struct { 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) { - wl_compositor_destroy(impl->compositor); - impl->compositor = NULL; - } + 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, "gsr warning: wl output interface version is < 4, expected >= 4 to capture a monitor\n"); + fprintf(stderr, "mgl warning: wl output interface version is < 4, expected >= 4\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); + fprintf(stderr, "mgl warning: reached maximum outputs (%d), ignoring output %u\n", MGL_MAX_MONITORS, name); return; } @@ -60,17 +78,25 @@ static void registry_add_object(void *data, struct wl_registry *registry, uint32 // }; // 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; - } + 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) { - xdg_wm_base_destroy(impl->xdg_wm_base); - impl->xdg_wm_base = NULL; - } + 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); } } @@ -128,7 +154,7 @@ static void xdg_toplevel_configure(void *data, struct xdg_toplevel *toplevel, in mgl_window *self = data; mgl_window_wayland *impl = self->impl; // TODO: - wl_egl_window_resize(impl->window, width, height, 0, 0); + mgl_window_wayland_on_resize(self, width, height); // struct window *window = data; // uint32_t *p; @@ -173,6 +199,213 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener = { .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) { @@ -205,12 +438,19 @@ bool mgl_wayland_setup_window(mgl_window *self, const char *title, const mgl_win 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); @@ -222,12 +462,16 @@ bool mgl_wayland_setup_window(mgl_window *self, const char *title, const mgl_win 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); @@ -244,13 +488,8 @@ bool mgl_wayland_setup_window(mgl_window *self, const char *title, const mgl_win 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 }); + mgl_window_wayland_on_resize(self, self->size.x, self->size.y); self->open = true; self->focused = false; @@ -315,7 +554,12 @@ static bool mgl_window_wayland_is_mouse_button_pressed(const mgl_window *self, m } static void mgl_window_wayland_set_title(mgl_window *self, const char *title) { - fprintf(stderr, "TODO: Implement\n"); + 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) { @@ -336,7 +580,7 @@ static bool mgl_window_wayland_is_vsync_enabled(const mgl_window *self) { 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(impl->xdg_toplevel) { if(fullscreen) xdg_toplevel_set_fullscreen(impl->xdg_toplevel, NULL); else @@ -363,7 +607,13 @@ static void mgl_window_wayland_set_size(mgl_window *self, mgl_vec2i size) { } static void mgl_window_wayland_set_size_limits(mgl_window *self, mgl_vec2i minimum, mgl_vec2i maximum) { - fprintf(stderr, "TODO: Implement\n"); + 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) { @@ -487,6 +737,21 @@ void mgl_window_wayland_deinit(mgl_window *self) { 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; |