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.c313
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;