Hook up mouse callbacks

This commit is contained in:
Phireh 2024-11-24 21:01:34 +01:00
commit a3f8043afa
2 changed files with 128 additions and 10 deletions

View file

@ -1,9 +1,9 @@
INTERFACEDIR:=$(shell pkg-config --variable=pkgdatadir wayland-protocols) INTERFACEDIR:=$(shell pkg-config --variable=pkgdatadir wayland-protocols)
CFLAGS=-Wall -Wextra -Og -ggdb3 -Wno-unused-but-set-variable -Wno-unused-parameter CFLAGS=-Wall -Wextra -Og -ggdb3 -Wno-unused-but-set-variable -Wno-unused-parameter
LIBS=-lwayland-client -lwayland-egl -lEGL -lOpenGL LIBS=-lwayland-client -lwayland-egl -lEGL -lOpenGL -lxkbcommon
wayland: wayland.c xdg-shell-protocol.c xdg-shell-client-protocol.h wayland: wayland.c xdg-shell-protocol.c xdg-shell-client-protocol.h
gcc $(CFLAGS) $(LIBS) wayland.c xdg-shell-protocol.c -o wayland gcc $(CFLAGS) $(LIBS) wayland.c xdg-shell-protocol.c -o wayland
xdg-shell-protocol.c: xdg-shell-protocol.c:
wayland-scanner private-code $(INTERFACEDIR)/stable/xdg-shell/xdg-shell.xml xdg-shell-protocol.c wayland-scanner private-code $(INTERFACEDIR)/stable/xdg-shell/xdg-shell.xml xdg-shell-protocol.c
xdg-shell-client-protocol.h: xdg-shell-client-protocol.h:
wayland-scanner client-header $(INTERFACEDIR)/stable/xdg-shell/xdg-shell.xml xdg-shell-client-protocol.h wayland-scanner client-header $(INTERFACEDIR)/stable/xdg-shell/xdg-shell.xml xdg-shell-client-protocol.h

132
wayland.c
View file

@ -3,9 +3,12 @@
#include <wayland-egl.h> #include <wayland-egl.h>
#include <EGL/egl.h> #include <EGL/egl.h>
#include <GL/gl.h> #include <GL/gl.h>
#include <xkbcommon/xkbcommon.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <sys/mman.h>
#include <unistd.h>
// Generated header using wayland-scanner // Generated header using wayland-scanner
#include "xdg-shell-client-protocol.h" #include "xdg-shell-client-protocol.h"
@ -16,13 +19,19 @@ struct xdg_wm_base *wm_base = NULL;
struct xdg_surface *xdg_surface = NULL; struct xdg_surface *xdg_surface = NULL;
struct xdg_toplevel *xdg_toplevel = NULL; struct xdg_toplevel *xdg_toplevel = NULL;
struct wl_egl_window *window = NULL; struct wl_egl_window *window = NULL;
/* Input API */ /* Input API */
struct wl_seat *wl_seat = NULL; struct wl_seat *wl_seat = NULL;
struct wl_keyboard *wl_keyboard = NULL; struct wl_keyboard *wl_keyboard = NULL;
struct wl_pointer *wl_pointer = NULL; struct wl_pointer *wl_pointer = NULL;
EGLBoolean errcode = 0;
/* XKB library */
struct xkb_context *xkb_context = NULL;
struct xkb_state *xkb_state = NULL;
struct xkb_keymap *xkb_keymap = NULL;
/* Misc. global state */ /* Misc. global state */
EGLBoolean errcode = 0;
bool running = true; bool running = true;
char *egl_s(int code) char *egl_s(int code)
@ -60,14 +69,15 @@ void registry_handle_global( void *data, struct wl_registry *registry,
fprintf(stdout, "Registering XDG WM base interface...\n"); fprintf(stdout, "Registering XDG WM base interface...\n");
wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
} }
/* NOTE: Since wl_seat v5, pointer events are grouped into "frames", which do not appear to be useful for non-touch applications and
also create more events which are more complicated to dispatch. */
if (!strcmp(interface, wl_seat_interface.name)) if (!strcmp(interface, wl_seat_interface.name))
{ {
fprintf(stdout, "Registering WL seat interface...\n"); fprintf(stdout, "Registering WL seat interface...\n");
wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 1); wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 9);
} }
} }
void registry_handle_global_remove(void *data, struct wl_registry *registry, void registry_handle_global_remove(void *data, struct wl_registry *registry,
uint32_t name) uint32_t name)
{ {
@ -103,10 +113,24 @@ void wayland_ping(void *data, struct xdg_wm_base *base, uint32_t serial)
xdg_wm_base_pong(base, serial); xdg_wm_base_pong(base, serial);
} }
void wl_seat_capabilities_callback(void *data, struct wl_seat *wl_seat, uint capabilities)
{
fprintf(stdout, "Capabilities changed for WL seat\n");
}
void keymap_callback(void *data, struct wl_keyboard *kb, uint format, int fd, uint size) void keymap_callback(void *data, struct wl_keyboard *kb, uint format, int fd, uint size)
{ {
// TODO: Check for XKB compatibility and use xkbcommon to extract // TODO: Check for XKB compatibility and use xkbcommon to extract
fprintf(stdout, "KBMAP of size %d detected\n", size); fprintf(stdout, "KBMAP of size %d detected\n", size);
char *mem = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
fprintf(stdout, "XKBMAP desc:\n\t%s\n", mem);
xkb_keymap = xkb_keymap_new_from_string(xkb_context, mem, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
munmap(mem, size);
close(fd);
if (!(xkb_state = xkb_state_new(xkb_keymap)))
fprintf(stderr, "Could not initialize XKB state machine\n");
} }
void enter_callback(void *data, struct wl_keyboard* kb, uint serial, struct wl_surface* surface, struct wl_array *keys) void enter_callback(void *data, struct wl_keyboard* kb, uint serial, struct wl_surface* surface, struct wl_array *keys)
@ -121,12 +145,27 @@ void leave_callback(void *data, struct wl_keyboard* kb, uint serial, struct wl_s
void key_callback(void *data, struct wl_keyboard *kb, uint serial, uint time, uint key, uint state) void key_callback(void *data, struct wl_keyboard *kb, uint serial, uint time, uint key, uint state)
{ {
fprintf(stdout, "Pressed key %d\n", key); /* TODO: This does *not* respect the system's language defaults. At least not in KDE.
* Wayland's own (terrible) documentation does not go into detail about languages:
* https://wayland-book.com/seat/xkb.html
*/
key += 8;
uint32_t layout = xkb_state_key_get_layout(xkb_state, key);
if (layout >= xkb_keymap_num_layouts_for_key(xkb_keymap, key))
fprintf(stderr, "Layout %d exceeds number of available key layouts\n", layout);
xkb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, key);
char keyname[128];
xkb_keysym_get_name(sym, keyname, sizeof(keyname));
char keyutf8[128];
xkb_state_key_get_utf8(xkb_state, key, keyutf8, sizeof(keyutf8));
fprintf(stdout, "%s key %d layout %d (KEYSYM %s) (UTF8 %s)\n", (state == WL_KEYBOARD_KEY_STATE_PRESSED ? "Pressed" : "Released"), key, layout, keyname, keyutf8);
} }
void modifier_callback(void *data, struct wl_keyboard *kb, uint serial, uint mods_depressed, uint mods_latched, uint mods_locked, uint group) void modifier_callback(void *data, struct wl_keyboard *kb, uint serial, uint mods_depressed, uint mods_latched, uint mods_locked, uint group)
{ {
fprintf(stdout, "Keyboard modifier keys changed\n"); fprintf(stdout, "Keyboard modifier keys changed\n");
xkb_state_update_mask(xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
} }
void repeat_info_callback(void *data, struct wl_keyboard *kb, int rate, int delay) void repeat_info_callback(void *data, struct wl_keyboard *kb, int rate, int delay)
@ -134,6 +173,56 @@ void repeat_info_callback(void *data, struct wl_keyboard *kb, int rate, int dela
fprintf(stdout, "Keyboard repeat/delay rate changed\n"); fprintf(stdout, "Keyboard repeat/delay rate changed\n");
} }
void pointer_enter_callback(void *data, struct wl_pointer *pointer, uint serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
{
fprintf(stdout, "Pointer entered WL surface on coordinates %d %d\n", x, y);
}
void pointer_leave_callback(void *data, struct wl_pointer *pointer, uint serial, struct wl_surface *surface)
{
fprintf(stdout, "Pointer left WL surface\n");
}
void pointer_motion_callback(void *data, struct wl_pointer *pointer, uint time, wl_fixed_t x, wl_fixed_t y)
{
fprintf(stdout, "Pointer moved to %d %d\n", x, y);
}
void pointer_button_callback(void *data, struct wl_pointer *pointer, uint serial, uint time, uint button, uint state)
{
fprintf(stdout, "Pointer button %d changed state\n", button);
}
void pointer_axis_callback(void *data, struct wl_pointer *pointer, uint time, uint axis, wl_fixed_t value)
{
fprintf(stdout, "Pointer scroll on axis %d value %d\n", axis, value);
}
/* NOTE: *some* events are logically grouped together. The frame event marks the boundary between groups of them. More info: https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_pointer */
void pointer_frame_callback(void *data, struct wl_pointer *frame)
{
fprintf(stdout, "Pointer frame ended\n");
}
/* NOTE: This event is also used to group pointer events together. It specifies info about all events in its frame */
void pointer_axis_source_callback(void *data, struct wl_pointer *pointer, uint axis_source)
{
fprintf(stdout, "Pointer axis source: %d\n", axis_source);
}
/* Optional event to implement kinetic scrolling */
void pointer_axis_stop_callback(void *data, struct wl_pointer *pointer, uint time, uint axis)
{
fprintf(stdout, "Pointer axis stopped: %d\n", axis);
}
/* Optional event. Carries discrete scroll info after an 'axis' event */
void pointer_axis_discrete_callback(void *data, struct wl_pointer *pointer, uint axis, int discrete)
{
fprintf(stdout, "Pointer axis discrete step: %d\n", discrete);
}
int main() int main()
{ {
fprintf(stdout, "Starting platform layer...\n"); fprintf(stdout, "Starting platform layer...\n");
@ -165,13 +254,19 @@ int main()
xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
xdg_toplevel_set_title(xdg_toplevel, "Hi"); xdg_toplevel_set_title(xdg_toplevel, "Hi");
/* XKB library initialization */
xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
const struct xdg_toplevel_listener xdg_toplevel_listener = { const struct xdg_toplevel_listener xdg_toplevel_listener = {
.configure = xdg_toplevel_configure, .configure = xdg_toplevel_configure,
.close = xdg_toplevel_close .close = xdg_toplevel_close
}; };
const struct xdg_wm_base_listener xdg_wm_base_listener = { const struct xdg_wm_base_listener xdg_wm_base_listener = {
.ping = wayland_ping .ping = wayland_ping
}; };
if (xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL)) if (xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL))
fprintf(stderr, "Could not set XDG toplevel listener\n"); fprintf(stderr, "Could not set XDG toplevel listener\n");
if (xdg_wm_base_add_listener(wm_base, &xdg_wm_base_listener, NULL)) if (xdg_wm_base_add_listener(wm_base, &xdg_wm_base_listener, NULL))
@ -181,6 +276,13 @@ int main()
if (!(wl_pointer = wl_seat_get_pointer(wl_seat))) if (!(wl_pointer = wl_seat_get_pointer(wl_seat)))
fprintf(stderr, "Could not get WL pointer\n"); fprintf(stderr, "Could not get WL pointer\n");
const struct wl_seat_listener wl_seat_listener = {
.capabilities = wl_seat_capabilities_callback
};
if (wl_seat_add_listener(wl_seat, &wl_seat_listener, NULL))
fprintf(stderr, "Could not set WL seat listener\n");
/* NOTE: We have to define all available callbacks for the keyboard listener even if we are not interested in them: /* NOTE: We have to define all available callbacks for the keyboard listener even if we are not interested in them:
https://gitlab.freedesktop.org/wayland/wayland/-/issues/160 */ https://gitlab.freedesktop.org/wayland/wayland/-/issues/160 */
const struct wl_keyboard_listener wl_keyboard_listener = { const struct wl_keyboard_listener wl_keyboard_listener = {
@ -191,8 +293,24 @@ int main()
.modifiers = modifier_callback, .modifiers = modifier_callback,
.repeat_info = repeat_info_callback, .repeat_info = repeat_info_callback,
}; };
wl_keyboard_add_listener(wl_keyboard, &wl_keyboard_listener, NULL); if (wl_keyboard_add_listener(wl_keyboard, &wl_keyboard_listener, NULL))
fprintf(stderr, "Could not set XKB keyboard listener\n");
// TODO: Apparently we are not setting opcode 10's callback?
const struct wl_pointer_listener wl_pointer_listener = {
.enter = pointer_enter_callback,
.leave = pointer_leave_callback,
.motion = pointer_motion_callback,
.button = pointer_button_callback,
.axis = pointer_axis_callback,
.frame = pointer_frame_callback,
.axis_source = pointer_axis_source_callback,
.axis_stop = pointer_axis_stop_callback,
.axis_discrete = pointer_axis_discrete_callback
};
if (wl_pointer_add_listener(wl_pointer, &wl_pointer_listener, NULL))
fprintf(stderr, "Could not set WL pointer listener\n");
/* WL EGL initialization */ /* WL EGL initialization */
window = wl_egl_window_create(surface, 480, 460); window = wl_egl_window_create(surface, 480, 460);
@ -339,7 +457,7 @@ int main()
// necessary before our first eglSwapBuffers // necessary before our first eglSwapBuffers
wl_surface_commit(surface); wl_surface_commit(surface);
// Main event loop // Main event loop
int framecount = 0; int framecount = 0;
while (running) while (running)