main uint/cterm / libmaus / source / maus_wayland.c
   1#define _POSIX_C_SOURCE 200809L
   2
   3#include <fcntl.h>
   4#include <poll.h>
   5#include <stdlib.h>
   6#include <string.h>
   7#include <sys/mman.h>
   8#include <unistd.h>
   9
  10#include <wayland-client.h>
  11#include <wayland-cursor.h>
  12#include <xdg-shell-client-protocol.h>
  13#include <pointer-constraints-unstable-v1-client-protocol.h>
  14#include <relative-pointer-unstable-v1-client-protocol.h>
  15#include <xkbcommon/xkbcommon.h>
  16
  17#include "maus.h"
  18#include "maus_wayland.h"
  19
  20static void registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name);
  21static void xdg_surface_configure(void* data, struct xdg_surface* xdg_surface, uint32_t serial);
  22static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, int32_t width, int32_t height, struct wl_array* states);
  23static void xdg_toplevel_close(void* data, struct xdg_toplevel* xdg_toplevel);
  24static void xdg_toplevel_configure_bounds(void* data, struct xdg_toplevel* xdg_toplevel, int32_t width, int32_t height);
  25static void xdg_toplevel_wm_capabilities(void* data, struct xdg_toplevel* xdg_toplevel, struct wl_array* capabilities);
  26static void wm_base_ping(void* data, struct xdg_wm_base* wm_base, uint32_t serial);
  27static void seat_capabilities(void* data, struct wl_seat* seat, uint32_t capabilities);
  28static void seat_name(void* data, struct wl_seat* seat, const char* name);
  29static void pointer_enter(void* data, struct wl_pointer* pointer, uint32_t serial, struct wl_surface* surface, wl_fixed_t sx, wl_fixed_t sy);
  30static void pointer_leave(void* data, struct wl_pointer* pointer, uint32_t serial, struct wl_surface* surface);
  31static void pointer_motion(void* data, struct wl_pointer* pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
  32static void pointer_button(void* data, struct wl_pointer* pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
  33static void pointer_axis(void* data, struct wl_pointer* pointer, uint32_t time, uint32_t axis, wl_fixed_t value);
  34static void pointer_frame(void* data, struct wl_pointer* pointer);
  35static void pointer_axis_source(void* data, struct wl_pointer* pointer, uint32_t axis_source);
  36static void pointer_axis_stop(void* data, struct wl_pointer* pointer, uint32_t time, uint32_t axis);
  37static void pointer_axis_discrete(void* data, struct wl_pointer* pointer, uint32_t axis, int32_t discrete);
  38static void pointer_axis_value120(void* data, struct wl_pointer* pointer, uint32_t axis, int32_t value120);
  39static void pointer_axis_relative_direction(void* data, struct wl_pointer* pointer, uint32_t axis, uint32_t direction);
  40static void relative_pointer_motion(void* data, struct zwp_relative_pointer_v1* relative_pointer, uint32_t utime_hi, uint32_t utime_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel);
  41static void keyboard_keymap(void* data, struct wl_keyboard* keyboard, uint32_t format, int32_t fd, uint32_t size);
  42static void keyboard_enter(void* data, struct wl_keyboard* keyboard, uint32_t serial, struct wl_surface* surface, struct wl_array* keys);
  43static void keyboard_leave(void* data, struct wl_keyboard* keyboard, uint32_t serial, struct wl_surface* surface);
  44static void keyboard_key(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
  45static void keyboard_modifiers(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group);
  46static void keyboard_repeat_info(void* data, struct wl_keyboard* keyboard, int32_t rate, int32_t delay);
  47static void registry_global(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version);
  48
  49static int8_t cursor_init(Maus* mw);
  50static void cursor_destroy(Maus* mw);
  51static void cursor_lock(Maus* mw);
  52static void cursor_unlock(Maus* mw);
  53static void cursor_show(Maus* mw);
  54static void cursor_hide(Maus* mw);
  55static void cursor_relative(Maus* mw);
  56static void cursor_absolute(Maus* mw);
  57static void event_push_pending(Maus* mw);
  58static int8_t event_pop(Maus* mw, MausEventPending* ev);
  59static void event_push_key(Maus* mw, uint32_t code, uint32_t sym, char text, uint8_t pressed);
  60static int8_t repeat_push_due(Maus* mw);
  61static int32_t repeat_timeout_ms(Maus* mw);
  62static int8_t display_read(Maus* mw, int timeout_ms);
  63static MausKey keysym_to_mauskey(xkb_keysym_t sym);
  64static MausMouseButton wl_button_to_maus(uint32_t button);
  65static void wl_buffer_release(void* data, struct wl_buffer* buffer);
  66
  67static struct wl_registry_listener registry_listener = { registry_global, registry_global_remove };
  68static struct xdg_surface_listener xdg_surface_listener = { xdg_surface_configure };
  69static struct xdg_toplevel_listener xdg_toplevel_listener = {
  70	xdg_toplevel_configure, xdg_toplevel_close,
  71	xdg_toplevel_configure_bounds, xdg_toplevel_wm_capabilities
  72};
  73static struct xdg_wm_base_listener xdg_wm_base_listener = { wm_base_ping };
  74static struct wl_seat_listener seat_listener = { seat_capabilities, seat_name };
  75static struct wl_pointer_listener pointer_listener = {
  76	pointer_enter, pointer_leave, pointer_motion, pointer_button,
  77	pointer_axis, pointer_frame, pointer_axis_source, pointer_axis_stop,
  78	pointer_axis_discrete, pointer_axis_value120, pointer_axis_relative_direction
  79};
  80static struct wl_keyboard_listener keyboard_listener = {
  81	keyboard_keymap, keyboard_enter, keyboard_leave, keyboard_key,
  82	keyboard_modifiers, keyboard_repeat_info
  83};
  84static struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
  85	relative_pointer_motion
  86};
  87static struct wl_buffer_listener wl_buffer_listener = { wl_buffer_release };
  88
  89static void wl_buffer_release(void* data, struct wl_buffer* buffer)
  90{
  91	MausWLBuffer* wb = data;
  92
  93	(void)buffer;
  94
  95	wb->busy = 0;
  96}
  97
  98static void event_push_pending(Maus* mw)
  99{
 100	MausBackend* be = &mw->backend;
 101
 102	if (!be->pending.pending)
 103		return;
 104
 105	if (be->evq_count == MAUS_EVQ_MAX) {
 106		be->evq_head = (be->evq_head + 1) % MAUS_EVQ_MAX;
 107		be->evq_count--;
 108	}
 109
 110	be->evq[be->evq_tail] = be->pending;
 111	be->evq_tail = (be->evq_tail + 1) % MAUS_EVQ_MAX;
 112	be->evq_count++;
 113	be->pending.pending = 0;
 114}
 115
 116static int8_t event_pop(Maus* mw, MausEventPending* ev)
 117{
 118	MausBackend* be = &mw->backend;
 119
 120	if (be->evq_count == 0)
 121		return 0;
 122
 123	*ev = be->evq[be->evq_head];
 124	be->evq_head = (be->evq_head + 1) % MAUS_EVQ_MAX;
 125	be->evq_count--;
 126	return 1;
 127}
 128
 129static void event_push_key(Maus* mw, uint32_t code, uint32_t sym, char text, uint8_t pressed)
 130{
 131	MausBackend* be = &mw->backend;
 132
 133	be->pending.pending = 1;
 134	be->pending.type = MAUS_EV_KEY;
 135	be->pending.key_code = code;
 136	be->pending.key_sym = sym;
 137	be->pending.key_text = text;
 138	be->pending.key_pressed = pressed;
 139	event_push_pending(mw);
 140}
 141
 142static void registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name)
 143{
 144	(void)data;
 145	(void)wl_registry;
 146	(void)name;
 147}
 148
 149static void xdg_surface_configure(void* data, struct xdg_surface* xdg_surface, uint32_t serial)
 150{
 151	Maus* mw = data;
 152	xdg_surface_ack_configure(xdg_surface, serial);
 153	mw->backend.configured = 1;
 154	if (!mw->backend.pending.pending) {
 155		mw->backend.pending.pending = 1;
 156		mw->backend.pending.type = MAUS_EV_REDRAW;
 157	}
 158	event_push_pending(mw);
 159}
 160
 161static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel,
 162                                   int32_t width, int32_t height, struct wl_array* states)
 163{
 164	Maus* mw = data;
 165
 166	(void)xdg_toplevel;
 167	(void)states;
 168
 169	if (width <= 0 || height <= 0)
 170		return;
 171
 172	mw->backend.pending.pending = 1;
 173	mw->backend.pending.type = MAUS_EV_RESIZE;
 174	mw->backend.pending.width = width;
 175	mw->backend.pending.height = height;
 176	event_push_pending(mw);
 177}
 178
 179static void xdg_toplevel_close(void* data, struct xdg_toplevel* xdg_toplevel)
 180{
 181	Maus* mw = data;
 182
 183	(void)xdg_toplevel;
 184
 185	mw->backend.pending.pending = 1;
 186	mw->backend.pending.type = MAUS_EV_CLOSE;
 187	event_push_pending(mw);
 188}
 189
 190static void xdg_toplevel_configure_bounds(void* data, struct xdg_toplevel* xdg_toplevel,
 191                                          int32_t width, int32_t height)
 192{
 193	(void)data;
 194	(void)xdg_toplevel;
 195	(void)width;
 196	(void)height;
 197}
 198
 199static void xdg_toplevel_wm_capabilities(void* data, struct xdg_toplevel* xdg_toplevel,
 200                                         struct wl_array* capabilities)
 201{
 202	(void)data;
 203	(void)xdg_toplevel;
 204	(void)capabilities;
 205}
 206
 207static void wm_base_ping(void* data, struct xdg_wm_base* wm_base, uint32_t serial)
 208{
 209	(void)data;
 210	xdg_wm_base_pong(wm_base, serial);
 211}
 212
 213static void registry_global(void* data, struct wl_registry* registry,
 214                            uint32_t name, const char* interface,
 215                            uint32_t version)
 216{
 217	Maus* mw = data;
 218	MausBackend* be = &mw->backend;
 219
 220	(void) version;
 221
 222	if (strcmp(interface, wl_compositor_interface.name) == 0)
 223		be->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 4);
 224	else if (strcmp(interface, wl_shm_interface.name) == 0)
 225		be->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
 226	else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
 227		be->wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
 228		xdg_wm_base_add_listener(be->wm_base, &xdg_wm_base_listener, mw);
 229	}
 230	else if (strcmp(interface, wl_seat_interface.name) == 0) {
 231		be->seat = wl_registry_bind(registry, name, &wl_seat_interface, 5);
 232		wl_seat_add_listener(be->seat, &seat_listener, mw);
 233	}
 234	else if (strcmp(interface, zwp_pointer_constraints_v1_interface.name) == 0)
 235		be->pointer_constraints = wl_registry_bind(registry, name, &zwp_pointer_constraints_v1_interface, 1);
 236	else if (strcmp(interface, zwp_relative_pointer_manager_v1_interface.name) == 0)
 237		be->relative_pointer_manager = wl_registry_bind(registry, name, &zwp_relative_pointer_manager_v1_interface, 1);
 238}
 239
 240static void seat_capabilities(void* data, struct wl_seat* seat, uint32_t capabilities)
 241{
 242	Maus* mw = data;
 243	MausBackend* be = &mw->backend;
 244
 245	if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !be->pointer) {
 246		be->pointer = wl_seat_get_pointer(seat);
 247		wl_pointer_add_listener(be->pointer, &pointer_listener, mw);
 248	}
 249	else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && be->pointer) {
 250		cursor_absolute(mw);
 251		wl_pointer_destroy(be->pointer);
 252		be->pointer = NULL;
 253	}
 254
 255	if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && !be->keyboard) {
 256		be->keyboard = wl_seat_get_keyboard(seat);
 257		wl_keyboard_add_listener(be->keyboard, &keyboard_listener, mw);
 258	}
 259	else if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && be->keyboard) {
 260		wl_keyboard_destroy(be->keyboard);
 261		be->keyboard = NULL;
 262	}
 263}
 264
 265static void seat_name(void* data, struct wl_seat* seat, const char* name)
 266{
 267	(void)data;
 268	(void)seat;
 269	(void)name;
 270}
 271
 272static void pointer_enter(void* data, struct wl_pointer* pointer, uint32_t serial,
 273                          struct wl_surface* surface, wl_fixed_t sx, wl_fixed_t sy)
 274{
 275	Maus* mw = data;
 276
 277	(void)pointer;
 278	(void)surface;
 279	(void)sx;
 280	(void)sy;
 281
 282	mw->backend.pointer_enter_serial = serial;
 283	if (mw->backend.cursor_state == MAUS_CURSOR_STATE_HIDDEN)
 284		cursor_hide(mw);
 285	else
 286		cursor_show(mw);
 287}
 288
 289static void pointer_leave(void* data, struct wl_pointer* pointer, uint32_t serial,
 290                          struct wl_surface* surface)
 291{
 292	(void)data;
 293	(void)pointer;
 294	(void)serial;
 295	(void)surface;
 296}
 297
 298static void pointer_motion(void* data, struct wl_pointer* pointer, uint32_t time,
 299                           wl_fixed_t sx, wl_fixed_t sy)
 300{
 301	Maus* mw = data;
 302	MausBackend* be = &mw->backend;
 303	int32_t x;
 304	int32_t y;
 305
 306	(void)pointer;
 307	(void)time;
 308
 309	if (be->relative_pointer)
 310		return;
 311
 312	x = wl_fixed_to_int(sx);
 313	y = wl_fixed_to_int(sy);
 314
 315	be->pending.pending = 1;
 316	be->pending.type = MAUS_EV_MOUSE_MOTION;
 317	be->pending.mouse_x = x;
 318	be->pending.mouse_y = y;
 319	be->pending.mouse_dx = be->mouse_pos_set ? x - be->mouse_x : 0;
 320	be->pending.mouse_dy = be->mouse_pos_set ? y - be->mouse_y : 0;
 321	be->mouse_x = x;
 322	be->mouse_y = y;
 323	be->mouse_pos_set = 1;
 324	event_push_pending(mw);
 325}
 326
 327static void pointer_button(void* data, struct wl_pointer* pointer, uint32_t serial,
 328                           uint32_t time, uint32_t button, uint32_t state)
 329{
 330	Maus* mw = data;
 331	MausMouseButton mb;
 332
 333	(void)pointer;
 334	(void)serial;
 335	(void)time;
 336
 337	mb = wl_button_to_maus(button);
 338	mw->backend.pending.pending = 1;
 339	mw->backend.pending.type = MAUS_EV_MOUSE_BUTTON;
 340	mw->backend.pending.mouse_button = mb;
 341	mw->backend.pending.mouse_pressed = state == WL_POINTER_BUTTON_STATE_PRESSED;
 342
 343	if (mb != MAUS_MOUSE_BUTTON_NONE)
 344		mw->mouse_buttons[mb] = mw->backend.pending.mouse_pressed;
 345	event_push_pending(mw);
 346}
 347
 348static void pointer_axis(void* data, struct wl_pointer* pointer, uint32_t time,
 349                         uint32_t axis, wl_fixed_t value)
 350{
 351	Maus* mw = data;
 352
 353	(void)pointer;
 354	(void)time;
 355
 356	if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
 357		return;
 358
 359	mw->backend.pending.pending = 1;
 360	mw->backend.pending.type = MAUS_EV_MOUSE_BUTTON;
 361	mw->backend.pending.mouse_button = wl_fixed_to_int(value) > 0
 362		? MAUS_MOUSE_BUTTON_SCROLL_DOWN
 363		: MAUS_MOUSE_BUTTON_SCROLL_UP;
 364	mw->backend.pending.mouse_pressed = 1;
 365	event_push_pending(mw);
 366}
 367
 368static void pointer_frame(void* data, struct wl_pointer* pointer)
 369{
 370	(void)data;
 371	(void)pointer;
 372}
 373
 374static void pointer_axis_source(void* data, struct wl_pointer* pointer, uint32_t axis_source)
 375{
 376	(void)data;
 377	(void)pointer;
 378	(void)axis_source;
 379}
 380
 381static void pointer_axis_stop(void* data, struct wl_pointer* pointer, uint32_t time, uint32_t axis) {
 382	(void)data;
 383	(void)pointer;
 384	(void)time;
 385	(void)axis;
 386}
 387
 388static void pointer_axis_discrete(void* data, struct wl_pointer* pointer, uint32_t axis,
 389                                  int32_t discrete)
 390{
 391	(void)data;
 392	(void)pointer;
 393	(void)axis;
 394	(void)discrete;
 395}
 396
 397static void pointer_axis_value120(void* data, struct wl_pointer* pointer, uint32_t axis,
 398                                  int32_t value120)
 399{
 400	(void)data;
 401	(void)pointer;
 402	(void)axis;
 403	(void)value120;
 404}
 405
 406static void pointer_axis_relative_direction(void* data, struct wl_pointer* pointer,
 407                                            uint32_t axis, uint32_t direction)
 408{
 409	(void)data;
 410	(void)pointer;
 411	(void)axis;
 412	(void)direction;
 413}
 414
 415static void relative_pointer_motion(void* data, struct zwp_relative_pointer_v1* relative_pointer,
 416                                    uint32_t utime_hi, uint32_t utime_lo,
 417                                    wl_fixed_t dx, wl_fixed_t dy,
 418                                    wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel)
 419{
 420	Maus* mw = data;
 421
 422	(void)relative_pointer;
 423	(void)utime_hi;
 424	(void)utime_lo;
 425	(void)dx_unaccel;
 426	(void)dy_unaccel;
 427
 428	mw->backend.pending.pending = 1;
 429	mw->backend.pending.type = MAUS_EV_MOUSE_MOTION;
 430	mw->backend.pending.mouse_x = wl_fixed_to_int(dx);
 431	mw->backend.pending.mouse_y = wl_fixed_to_int(dy);
 432	mw->backend.pending.mouse_dx = wl_fixed_to_int(dx);
 433	mw->backend.pending.mouse_dy = wl_fixed_to_int(dy);
 434	event_push_pending(mw);
 435}
 436
 437static void keyboard_keymap(void* data, struct wl_keyboard* keyboard, uint32_t format,
 438                            int32_t fd, uint32_t size)
 439{
 440	Maus* mw = data;
 441	MausBackend* be = &mw->backend;
 442	char* map;
 443
 444	(void)keyboard;
 445
 446	if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
 447		close(fd);
 448		return;
 449	}
 450
 451	map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 452	if (map == MAP_FAILED) {
 453		close(fd);
 454		return;
 455	}
 456
 457	if (be->xkb_state)
 458		xkb_state_unref(be->xkb_state);
 459	if (be->xkb_keymap)
 460		xkb_keymap_unref(be->xkb_keymap);
 461
 462	be->xkb_keymap = xkb_keymap_new_from_string(
 463		be->xkb_context, map,
 464		XKB_KEYMAP_FORMAT_TEXT_V1,
 465		XKB_KEYMAP_COMPILE_NO_FLAGS
 466	);
 467
 468	munmap(map, size);
 469	close(fd);
 470
 471	if (!be->xkb_keymap)
 472		return;
 473
 474	be->xkb_state = xkb_state_new(be->xkb_keymap);
 475}
 476
 477static void keyboard_enter(void* data, struct wl_keyboard* keyboard, uint32_t serial,
 478                           struct wl_surface* surface, struct wl_array* keys)
 479{
 480	(void)data;
 481	(void)keyboard;
 482	(void)serial;
 483	(void)surface;
 484	(void)keys;
 485}
 486
 487static void keyboard_leave(void* data, struct wl_keyboard* keyboard, uint32_t serial,
 488                           struct wl_surface* surface)
 489{
 490	Maus* mw = data;
 491
 492	(void)keyboard;
 493	(void)serial;
 494	(void)surface;
 495
 496	mw->backend.repeat_key_code = 0;
 497}
 498
 499static void keyboard_key(void* data, struct wl_keyboard* keyboard, uint32_t serial,
 500                         uint32_t time, uint32_t key, uint32_t state)
 501{
 502	Maus* mw = data;
 503	MausBackend* be = &mw->backend;
 504	uint32_t code;
 505	xkb_keysym_t sym;
 506	MausKey maus_key;
 507	char text[8];
 508	int len;
 509	uint8_t pressed;
 510
 511	(void)keyboard;
 512	(void)serial;
 513	(void)time;
 514
 515	code = key + 8;
 516	sym = XKB_KEY_NoSymbol;
 517	text[0] = 0;
 518
 519	if (be->xkb_state) {
 520		sym = xkb_state_key_get_one_sym(be->xkb_state, code);
 521		if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
 522			len = xkb_state_key_get_utf8(be->xkb_state, code, text, sizeof(text));
 523			if (len <= 0)
 524				text[0] = 0;
 525		}
 526	}
 527
 528	maus_key = keysym_to_mauskey(sym);
 529	if (maus_key == MAUS_KEY_ENTER)
 530		text[0] = '\n';
 531	pressed = state == WL_KEYBOARD_KEY_STATE_PRESSED;
 532	event_push_key(mw, code, maus_key, text[0], pressed);
 533
 534	if (code < MAUS_KEYCODE_LAST)
 535		mw->key_codes[code] = pressed;
 536	if (maus_key != MAUS_KEY_NONE)
 537		mw->key_syms[maus_key] = pressed;
 538
 539	if (!pressed) {
 540		if (be->repeat_key_code == code)
 541			be->repeat_key_code = 0;
 542		return;
 543	}
 544
 545	if (be->repeat_rate > 0 && be->xkb_keymap &&
 546	    xkb_keymap_key_repeats(be->xkb_keymap, code)) {
 547		be->repeat_key_code = code;
 548		be->repeat_key_sym = maus_key;
 549		be->repeat_key_text = text[0];
 550		be->repeat_next_ns = maus_get_time_ns() + be->repeat_delay * 1000000;
 551	}
 552	else
 553		be->repeat_key_code = 0;
 554}
 555
 556static void keyboard_modifiers(void* data, struct wl_keyboard* keyboard, uint32_t serial,
 557                               uint32_t mods_depressed, uint32_t mods_latched,
 558                               uint32_t mods_locked, uint32_t group)
 559{
 560	Maus* mw = data;
 561
 562	(void)keyboard;
 563	(void)serial;
 564
 565	if (!mw->backend.xkb_state)
 566		return;
 567
 568	xkb_state_update_mask(
 569		mw->backend.xkb_state, mods_depressed,
 570		mods_latched, mods_locked,
 571		0, 0, group
 572	);
 573}
 574
 575static void keyboard_repeat_info(void* data, struct wl_keyboard* keyboard,
 576                                 int32_t rate, int32_t delay)
 577{
 578	Maus* mw = data;
 579
 580	(void)keyboard;
 581
 582	mw->backend.repeat_rate = rate;
 583	mw->backend.repeat_delay = delay;
 584	if (rate <= 0)
 585		mw->backend.repeat_key_code = 0;
 586}
 587
 588static int8_t repeat_push_due(Maus* mw)
 589{
 590	MausBackend* be = &mw->backend;
 591	uint64_t now;
 592	uint64_t interval;
 593
 594	if (be->repeat_key_code == 0 || be->repeat_rate <= 0)
 595		return 0;
 596
 597	now = maus_get_time_ns();
 598	if (now < be->repeat_next_ns)
 599		return 0;
 600
 601	event_push_key(mw, be->repeat_key_code, be->repeat_key_sym, be->repeat_key_text, 1);
 602	interval = 1000000000 / be->repeat_rate;
 603	do {
 604		be->repeat_next_ns += interval;
 605	} while (be->repeat_next_ns <= now);
 606
 607	return 1;
 608}
 609
 610static int32_t repeat_timeout_ms(Maus* mw)
 611{
 612	MausBackend* be = &mw->backend;
 613	uint64_t now;
 614	uint64_t diff;
 615
 616	if (be->repeat_key_code == 0 || be->repeat_rate <= 0)
 617		return -1;
 618
 619	now = maus_get_time_ns();
 620	if (now >= be->repeat_next_ns)
 621		return 0;
 622
 623	diff = be->repeat_next_ns - now;
 624	/* round xto nearest ms */
 625	return (int32_t)((diff + 999999) / 1000000);
 626}
 627
 628static int8_t display_read(Maus* mw, int timeout_ms)
 629{
 630	MausBackend* be = &mw->backend;
 631	struct pollfd pfd;
 632	int ret;
 633
 634	if (wl_display_prepare_read(be->display) != 0) {
 635		wl_display_dispatch_pending(be->display);
 636		return 1;
 637	}
 638
 639	wl_display_flush(be->display);
 640
 641	pfd.fd = wl_display_get_fd(be->display);
 642	pfd.events = POLLIN;
 643	pfd.revents = 0;
 644
 645	ret = poll(&pfd, 1, timeout_ms);
 646	if (ret > 0 && (pfd.revents & POLLIN)) {
 647		if (wl_display_read_events(be->display) == -1) {
 648			wl_display_cancel_read(be->display);
 649			return -1;
 650		}
 651		wl_display_dispatch_pending(be->display);
 652		return 1;
 653	}
 654
 655	wl_display_cancel_read(be->display);
 656	return 0;
 657}
 658
 659
 660static int8_t cursor_init(Maus* mw)
 661{
 662	MausBackend* be = &mw->backend;
 663
 664	be->cursor_theme = wl_cursor_theme_load(NULL, 24, be->shm);
 665	if (!be->cursor_theme)
 666		return 0;
 667
 668	be->cursor = wl_cursor_theme_get_cursor(be->cursor_theme, "left_ptr");
 669	if (!be->cursor)
 670		return 0;
 671
 672	be->cursor_surface = wl_compositor_create_surface(be->compositor);
 673	if (!be->cursor_surface)
 674		return 0;
 675
 676	return 1;
 677}
 678
 679static void cursor_destroy(Maus* mw)
 680{
 681	MausBackend* be = &mw->backend;
 682
 683	if (be->cursor_surface)
 684		wl_surface_destroy(be->cursor_surface);
 685	if (be->cursor_theme)
 686		wl_cursor_theme_destroy(be->cursor_theme);
 687
 688	be->cursor_surface = NULL;
 689	be->cursor_theme = NULL;
 690	be->cursor = NULL;
 691}
 692
 693static void cursor_hide(Maus* mw)
 694{
 695	MausBackend* be = &mw->backend;
 696
 697	if (!be->pointer)
 698		return;
 699
 700	wl_pointer_set_cursor(be->pointer, be->pointer_enter_serial, NULL, 0, 0);
 701}
 702
 703static void cursor_lock(Maus* mw)
 704{
 705	MausBackend* be = &mw->backend;
 706
 707	if (be->locked_pointer)
 708		return;
 709	if (!be->pointer_constraints || !be->surface || !be->pointer)
 710		return;
 711
 712	be->locked_pointer = zwp_pointer_constraints_v1_confine_pointer(
 713		be->pointer_constraints, be->surface, be->pointer, NULL,
 714		ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT
 715	);
 716}
 717
 718static void cursor_unlock(Maus* mw)
 719{
 720	MausBackend* be = &mw->backend;
 721
 722	if (be->locked_pointer) {
 723		zwp_confined_pointer_v1_destroy(be->locked_pointer);
 724		be->locked_pointer = NULL;
 725	}
 726
 727	if (be->cursor_state == MAUS_CURSOR_STATE_VISIBLE)
 728		cursor_show(mw);
 729}
 730
 731static void cursor_show(Maus* mw)
 732{
 733	MausBackend* be = &mw->backend;
 734	struct wl_cursor_image* image;
 735	struct wl_buffer* buffer;
 736
 737	if (!be->pointer || !be->cursor || !be->cursor_surface)
 738		return;
 739
 740	image = be->cursor->images[0];
 741	buffer = wl_cursor_image_get_buffer(image);
 742	if (!buffer)
 743		return;
 744
 745	wl_pointer_set_cursor(
 746		be->pointer, be->pointer_enter_serial,
 747		be->cursor_surface, image->hotspot_x, image->hotspot_y
 748	);
 749	wl_surface_attach(be->cursor_surface, buffer, 0, 0);
 750	wl_surface_damage_buffer(be->cursor_surface, 0, 0, image->width, image->height);
 751	wl_surface_commit(be->cursor_surface);
 752}
 753
 754static void cursor_relative(Maus* mw)
 755{
 756	MausBackend* be = &mw->backend;
 757	if (be->relative_pointer)
 758		return;
 759	if (!be->relative_pointer_manager || !be->pointer)
 760		return;
 761
 762	cursor_lock(mw);
 763	be->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
 764		be->relative_pointer_manager, be->pointer
 765	);
 766	zwp_relative_pointer_v1_add_listener(
 767		be->relative_pointer, &relative_pointer_listener, mw
 768	);
 769}
 770
 771static void cursor_absolute(Maus* mw)
 772{
 773	MausBackend* be = &mw->backend;
 774
 775	if (be->relative_pointer) {
 776		zwp_relative_pointer_v1_destroy(be->relative_pointer);
 777		be->relative_pointer = NULL;
 778	}
 779
 780	cursor_unlock(mw);
 781}
 782
 783static int8_t fb_create(Maus* mw);
 784static int8_t fb_create_buffer(Maus* mw, MausWLBuffer* wb);
 785static int8_t fb_create_shm(size_t size);
 786static void fb_destroy(Maus* mw);
 787static int8_t handle_event(Maus* mw, MausEvent* ev);
 788
 789static int8_t fb_create(Maus* mw)
 790{
 791	MausBackend* be = &mw->backend;
 792
 793	if (!fb_create_buffer(mw, &be->buffers[0])) {
 794		fb_destroy(mw);
 795		return 0;
 796	}
 797	if (!fb_create_buffer(mw, &be->buffers[1])) {
 798		fb_destroy(mw);
 799		return 0;
 800	}
 801
 802	mw->fb = be->buffers[0].data;
 803	mw->stride = mw->width;
 804	return 1;
 805}
 806
 807static int8_t fb_create_buffer(Maus* mw, MausWLBuffer* wb)
 808{
 809	MausBackend* be = &mw->backend;
 810	struct wl_shm_pool* pool;
 811
 812	int fd;
 813	int stride;
 814	int size;
 815
 816	stride = mw->width * 4;
 817	size = stride * mw->height;
 818
 819	fd = fb_create_shm(size);
 820	if (fd < 0)
 821		return 0;
 822
 823	wb->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
 824	if (wb->data == MAP_FAILED) {
 825		wb->data = NULL;
 826		close(fd);
 827		return 0;
 828	}
 829
 830	pool = wl_shm_create_pool(be->shm, fd, size);
 831	wb->buffer = wl_shm_pool_create_buffer(
 832		pool, 0, mw->width, mw->height,
 833		stride, WL_SHM_FORMAT_XRGB8888
 834	);
 835
 836	wl_shm_pool_destroy(pool);
 837	close(fd);
 838
 839	if (!wb->buffer) {
 840		munmap(wb->data, size);
 841		wb->data = NULL;
 842		return 0;
 843	}
 844
 845	wl_buffer_add_listener(wb->buffer, &wl_buffer_listener, wb);
 846	wb->size = size;
 847	wb->busy = 0;
 848
 849	return 1;
 850}
 851
 852static int8_t fb_create_shm(size_t size)
 853{
 854	char name[64];
 855	int fd;
 856
 857	int i;
 858
 859	for (i = 0; i < 100; i++) {
 860		snprintf(name, sizeof(name), "/maus-%ld-%d", (long)getpid(), i);
 861
 862		fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
 863		if (fd >= 0) {
 864			shm_unlink(name);
 865
 866			if (ftruncate(fd, size) < 0) {
 867				close(fd);
 868				return -1;
 869			}
 870
 871			return fd;
 872		}
 873	}
 874
 875	return -1;
 876}
 877
 878static void fb_destroy(Maus* mw)
 879{
 880	MausBackend* be = &mw->backend;
 881
 882	uint32_t i;
 883
 884	for (i = 0; i < 2; i++) {
 885		if (be->buffers[i].buffer)
 886			wl_buffer_destroy(be->buffers[i].buffer);
 887
 888		if (be->buffers[i].data && be->buffers[i].size > 0)
 889			munmap(be->buffers[i].data, be->buffers[i].size);
 890
 891		be->buffers[i].buffer = NULL;
 892		be->buffers[i].data = NULL;
 893		be->buffers[i].size = 0;
 894		be->buffers[i].busy = 0;
 895	}
 896	mw->fb = NULL;
 897}
 898
 899static int8_t handle_event(Maus* mw, MausEvent* ev)
 900{
 901	MausEventPending pending;
 902
 903	if (!event_pop(mw, &pending))
 904		return 0;
 905
 906	ev->type = pending.type;
 907
 908	switch (ev->type) {
 909	case MAUS_EV_CLOSE:
 910		return 1;
 911
 912	case MAUS_EV_RESIZE:
 913		ev->resize.width = pending.width;
 914		ev->resize.height = pending.height;
 915		return 1;
 916
 917	case MAUS_EV_MOUSE_MOTION:
 918		ev->mouse.motion.x = pending.mouse_x;
 919		ev->mouse.motion.y = pending.mouse_y;
 920		ev->mouse.motion.dx = pending.mouse_dx;
 921		ev->mouse.motion.dy = pending.mouse_dy;
 922		return 1;
 923
 924	case MAUS_EV_MOUSE_BUTTON:
 925		ev->mouse.button.button = pending.mouse_button;
 926		ev->mouse.button.pressed = pending.mouse_pressed;
 927		return 1;
 928
 929	case MAUS_EV_KEY:
 930		ev->key.code = pending.key_code;
 931		ev->key.pressed = pending.key_pressed;
 932		ev->key.key = pending.key_sym;
 933		ev->key.text = pending.key_text;
 934		return 1;
 935
 936	default:
 937		return 1;
 938	}
 939}
 940
 941static MausMouseButton wl_button_to_maus(uint32_t button)
 942{
 943	switch (button) {
 944		case 0x110: return MAUS_MOUSE_BUTTON_LEFT;
 945		case 0x111: return MAUS_MOUSE_BUTTON_RIGHT;
 946		case 0x112: return MAUS_MOUSE_BUTTON_MIDDLE;
 947		default:    return MAUS_MOUSE_BUTTON_NONE;
 948	}
 949}
 950
 951static MausKey keysym_to_mauskey(xkb_keysym_t sym)
 952{
 953	if (sym >= 0x20 && sym <= 0x7E)
 954		return (MausKey)sym;
 955
 956	if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F12)
 957		return MAUS_KEY_F1 + (sym - XKB_KEY_F1);
 958	if (sym >= XKB_KEY_KP_0 && sym <= XKB_KEY_KP_9)
 959		return MAUS_KEY_KP_0 + (sym - XKB_KEY_KP_0);
 960
 961	switch (sym) {
 962		case XKB_KEY_BackSpace:    return MAUS_KEY_BACKSPACE;
 963		case XKB_KEY_Tab:          return MAUS_KEY_TAB;
 964		case XKB_KEY_Return:       return MAUS_KEY_ENTER;
 965		case XKB_KEY_Escape:       return MAUS_KEY_ESCAPE;
 966		case XKB_KEY_Delete:       return MAUS_KEY_DELETE;
 967		case XKB_KEY_Left:         return MAUS_KEY_LEFT;
 968		case XKB_KEY_Right:        return MAUS_KEY_RIGHT;
 969		case XKB_KEY_Up:           return MAUS_KEY_UP;
 970		case XKB_KEY_Down:         return MAUS_KEY_DOWN;
 971		case XKB_KEY_Home:         return MAUS_KEY_HOME;
 972		case XKB_KEY_End:          return MAUS_KEY_END;
 973		case XKB_KEY_Page_Up:      return MAUS_KEY_PAGE_UP;
 974		case XKB_KEY_Page_Down:    return MAUS_KEY_PAGE_DOWN;
 975		case XKB_KEY_Insert:       return MAUS_KEY_INSERT;
 976		case XKB_KEY_Shift_L:      return MAUS_KEY_SHIFT_L;
 977		case XKB_KEY_Shift_R:      return MAUS_KEY_SHIFT_R;
 978		case XKB_KEY_Control_L:    return MAUS_KEY_CONTROL_L;
 979		case XKB_KEY_Control_R:    return MAUS_KEY_CONTROL_R;
 980		case XKB_KEY_Alt_L:        return MAUS_KEY_ALT_L;
 981		case XKB_KEY_Alt_R:        return MAUS_KEY_ALT_R;
 982		case XKB_KEY_Super_L:      return MAUS_KEY_SUPER_L;
 983		case XKB_KEY_Super_R:      return MAUS_KEY_SUPER_R;
 984		case XKB_KEY_Caps_Lock:    return MAUS_KEY_CAPS_LOCK;
 985		case XKB_KEY_Num_Lock:     return MAUS_KEY_NUM_LOCK;
 986		case XKB_KEY_Scroll_Lock:  return MAUS_KEY_SCROLL_LOCK;
 987		case XKB_KEY_Print:        return MAUS_KEY_PRINT_SCREEN;
 988		case XKB_KEY_Pause:        return MAUS_KEY_PAUSE;
 989		case XKB_KEY_Menu:         return MAUS_KEY_MENU;
 990		case XKB_KEY_KP_Decimal:   return MAUS_KEY_KP_DECIMAL;
 991		case XKB_KEY_KP_Divide:    return MAUS_KEY_KP_DIVIDE;
 992		case XKB_KEY_KP_Multiply:  return MAUS_KEY_KP_MULTIPLY;
 993		case XKB_KEY_KP_Subtract:  return MAUS_KEY_KP_SUBTRACT;
 994		case XKB_KEY_KP_Add:       return MAUS_KEY_KP_ADD;
 995		case XKB_KEY_KP_Enter:     return MAUS_KEY_KP_ENTER;
 996		case XKB_KEY_KP_Equal:     return MAUS_KEY_KP_EQUAL;
 997		default:                   return MAUS_KEY_NONE;
 998	}
 999}
1000
1001void maus_clear(Maus* mw, MausColor col)
1002{
1003	uint32_t up = MAUS_UNPACK_COL(col);
1004	uint32_t pxs = mw->height * mw->width;
1005
1006	uint32_t i;
1007
1008	for (i = 0; i < pxs; i++)
1009		mw->bfb[i] = up;
1010}
1011
1012/* TODO */
1013void maus_clipboard_set_text(Maus* mw, const char* text)
1014{
1015	(void)mw;
1016	(void)text;
1017}
1018
1019/* TODO */
1020char* maus_clipboard_get_text(Maus* mw)
1021{
1022	(void)mw;
1023	return NULL;
1024}
1025
1026void maus_close(Maus* mw)
1027{
1028	MausBackend* be;
1029
1030	if (!mw)
1031		return;
1032
1033	be = &mw->backend;
1034
1035	fb_destroy(mw);
1036	cursor_absolute(mw);
1037
1038	if (be->xdg_toplevel)
1039		xdg_toplevel_destroy(be->xdg_toplevel);
1040
1041	if (be->xdg_surface)
1042		xdg_surface_destroy(be->xdg_surface);
1043
1044	if (be->surface)
1045		wl_surface_destroy(be->surface);
1046
1047	if (be->keyboard)
1048		wl_keyboard_destroy(be->keyboard);
1049
1050	if (be->pointer)
1051		wl_pointer_destroy(be->pointer);
1052
1053	if (be->seat)
1054		wl_seat_destroy(be->seat);
1055
1056	if (be->pointer_constraints)
1057		zwp_pointer_constraints_v1_destroy(be->pointer_constraints);
1058
1059	if (be->relative_pointer_manager)
1060		zwp_relative_pointer_manager_v1_destroy(be->relative_pointer_manager);
1061
1062	if (be->xkb_state)
1063		xkb_state_unref(be->xkb_state);
1064
1065	if (be->xkb_keymap)
1066		xkb_keymap_unref(be->xkb_keymap);
1067
1068	if (be->xkb_context)
1069		xkb_context_unref(be->xkb_context);
1070
1071	cursor_destroy(mw);
1072
1073	if (be->wm_base)
1074		xdg_wm_base_destroy(be->wm_base);
1075
1076	if (be->shm)
1077		wl_shm_destroy(be->shm);
1078
1079	if (be->compositor)
1080		wl_compositor_destroy(be->compositor);
1081
1082	if (be->registry)
1083		wl_registry_destroy(be->registry);
1084
1085	if (be->display) {
1086		wl_display_flush(be->display);
1087		wl_display_disconnect(be->display);
1088	}
1089
1090	free(mw->bfb);
1091	free(mw);
1092}
1093
1094int8_t maus_close_window(Maus* mw)
1095{
1096	MausBackend* be = &mw->backend;
1097
1098	cursor_unlock(mw);
1099	fb_destroy(mw);
1100
1101	if (be->xdg_toplevel)
1102		xdg_toplevel_destroy(be->xdg_toplevel);
1103	if (be->xdg_surface)
1104		xdg_surface_destroy(be->xdg_surface);
1105	if (be->surface)
1106		wl_surface_destroy(be->surface);
1107
1108	be->xdg_toplevel = NULL;
1109	be->xdg_surface = NULL;
1110	be->surface = NULL;
1111	be->configured = 0;
1112
1113	return 1;
1114}
1115
1116int8_t maus_create_window(Maus* mw)
1117{
1118	MausBackend* be = &mw->backend;
1119
1120	be->surface = wl_compositor_create_surface(be->compositor);
1121	if (!be->surface)
1122		return 0;
1123
1124	be->xdg_surface = xdg_wm_base_get_xdg_surface(be->wm_base, be->surface);
1125	if (!be->xdg_surface)
1126		return 0;
1127
1128	xdg_surface_add_listener(be->xdg_surface, &xdg_surface_listener, mw);
1129
1130	be->xdg_toplevel = xdg_surface_get_toplevel(be->xdg_surface);
1131	if (!be->xdg_toplevel)
1132		return 0;
1133
1134	xdg_toplevel_add_listener(be->xdg_toplevel, &xdg_toplevel_listener, mw);
1135	xdg_toplevel_set_title(be->xdg_toplevel, mw->title);
1136
1137	if (!fb_create(mw))
1138		return 0;
1139
1140	wl_surface_commit(be->surface);
1141
1142	while (!be->configured) {
1143		if (wl_display_dispatch(be->display) == -1)
1144			return 0;
1145	}
1146
1147	return 1;
1148}
1149
1150Maus* maus_init(const char* title, int x, int y, int width, int height)
1151{
1152	Maus* mw = calloc(1, sizeof(Maus));
1153	MausBackend* be = &mw->backend;
1154
1155	if (!mw)
1156		return NULL;
1157
1158	be->display = wl_display_connect(NULL);
1159	if (!be->display) {
1160		free(mw);
1161		return NULL;
1162	}
1163
1164	be->registry = wl_display_get_registry(be->display);
1165	wl_registry_add_listener(be->registry, &registry_listener, mw);
1166	wl_display_roundtrip(be->display);
1167
1168	be->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
1169	if (!be->xkb_context)
1170		goto close;
1171
1172	if (!be->compositor || !be->shm || !be->wm_base) {
1173		maus_close(mw);
1174		free(mw);
1175		return NULL;
1176	}
1177
1178	if (!cursor_init(mw))
1179		goto close;
1180
1181	mw->frame_time_last = maus_get_time_ns();
1182	mw->title = title;
1183	mw->x = x;
1184	mw->y = y;
1185	mw->width = width;
1186	mw->height = height;
1187	mw->stride = width;
1188	be->cursor_state = MAUS_CURSOR_STATE_VISIBLE;
1189
1190	mw->bfb = calloc(mw->stride * mw->height, sizeof(uint32_t));
1191	if (!mw->bfb)
1192		goto close;
1193
1194	return mw;
1195close:
1196	maus_close(mw);
1197	free(mw);
1198	return NULL;
1199}
1200
1201int8_t maus_event_poll(Maus* mw, MausEvent* ev)
1202{
1203	MausBackend* be = &mw->backend;
1204	int8_t read;
1205
1206	ev->type = MAUS_EV_NONE;
1207
1208	if (repeat_push_due(mw) && handle_event(mw, ev))
1209		return 1;
1210
1211	if (handle_event(mw, ev))
1212		return 1;
1213
1214	wl_display_dispatch_pending(be->display);
1215	if (handle_event(mw, ev))
1216		return 1;
1217
1218	read = display_read(mw, 0);
1219	if (read == -1) {
1220		ev->type = MAUS_EV_CLOSE;
1221		return 1;
1222	}
1223	if (read == 0)
1224		return 0;
1225	if (repeat_push_due(mw) && handle_event(mw, ev))
1226		return 1;
1227
1228	return handle_event(mw, ev);
1229}
1230
1231void maus_event_wait(Maus* mw, MausEvent* ev)
1232{
1233	MausBackend* be = &mw->backend;
1234	int32_t timeout;
1235	int8_t read;
1236
1237	ev->type = MAUS_EV_NONE;
1238
1239	for (;;) {
1240		if (repeat_push_due(mw) && handle_event(mw, ev))
1241			return;
1242
1243		if (handle_event(mw, ev))
1244			return;
1245
1246		timeout = repeat_timeout_ms(mw);
1247		if (timeout >= 0) {
1248			read = display_read(mw, timeout);
1249			if (read == -1) {
1250				ev->type = MAUS_EV_CLOSE;
1251				return;
1252			}
1253			continue;
1254		}
1255
1256		if (wl_display_dispatch(be->display) == -1) {
1257			ev->type = MAUS_EV_CLOSE;
1258			return;
1259		}
1260	}
1261}
1262
1263void maus_present(Maus* mw)
1264{
1265	MausBackend* be = &mw->backend;
1266	MausWLBuffer* wb = NULL;
1267	size_t bytes;
1268
1269	uint32_t i;
1270
1271	for (i = 0; i < 2; i++) {
1272		if (be->buffers[i].buffer && !be->buffers[i].busy) {
1273			wb = &be->buffers[i];
1274			break;
1275		}
1276	}
1277
1278	if (!wb)
1279		return;
1280
1281	bytes = mw->stride * mw->height * sizeof(uint32_t);
1282	memcpy(wb->data, mw->bfb, bytes);
1283	mw->fb = wb->data;
1284	wb->busy = 1;
1285
1286	wl_surface_attach(be->surface, wb->buffer, 0, 0);
1287	wl_surface_damage_buffer(be->surface, 0, 0, mw->width, mw->height);
1288	wl_surface_commit(be->surface);
1289	wl_display_flush(be->display);
1290}
1291
1292int8_t maus_resize(Maus* mw, uint32_t width, uint32_t height)
1293{
1294	uint32_t* bfb;
1295
1296	if (width == 0 || height == 0)
1297		return 0;
1298
1299	bfb = calloc(width * height, sizeof(uint32_t));
1300	if (!bfb)
1301		return 0;
1302
1303	fb_destroy(mw);
1304	free(mw->bfb);
1305
1306	mw->width = width;
1307	mw->height = height;
1308	mw->stride = width;
1309	mw->bfb = bfb;
1310
1311	if (!fb_create(mw)) {
1312		free(mw->bfb);
1313		mw->bfb = NULL;
1314		return 0;
1315	}
1316
1317	return 1;
1318}
1319
1320void maus_cur_set_mode(Maus* mw, MausCursorState state)
1321{
1322	switch (state) {
1323	case MAUS_CURSOR_STATE_VISIBLE:
1324		cursor_show(mw);
1325		mw->backend.cursor_state = state;
1326		break;
1327	case MAUS_CURSOR_STATE_HIDDEN:
1328		cursor_hide(mw);
1329		mw->backend.cursor_state = state;
1330		break;
1331	case MAUS_CURSOR_STATE_LOCKED:
1332		mw->backend.cursor_state = state;
1333		cursor_lock(mw);
1334		break;
1335	case MAUS_CURSOR_STATE_FREE:
1336		cursor_unlock(mw);
1337		mw->backend.cursor_state = state;
1338		break;
1339	case MAUS_CURSOR_STATE_RELATIVE:
1340		cursor_relative(mw);
1341		mw->backend.cursor_state = state;
1342		break;
1343	case MAUS_CURSOR_STATE_ABSOLUTE:
1344		cursor_absolute(mw);
1345		mw->backend.cursor_state = state;
1346		break;
1347	default:
1348		break;
1349	}
1350}
1351