commit e847a24

uint  ·  2026-10-03 17:40:28 +0000 UTC
parent 09ec6ba
remove vendored libmaus
26 files changed,  +0, -4161
+0, -16
 1@@ -1,16 +0,0 @@
 2-*.o
 3-*.swp
 4-*.a
 5-*.exe
 6-*.obj
 7-*.lib
 8-
 9-build/
10-compile_flags.txt
11-
12-fenster/
13-
14-examples/basic-window/basic-window
15-
16-config.mk
17-
+0, -16
 1@@ -1,16 +0,0 @@
 2-ISC License
 3-
 4-Copyright 2026 uint
 5-
 6-Permission to use, copy, modify, and/or distribute this software for any
 7-purpose with or without fee is hereby granted, provided that the above
 8-copyright notice and this permission notice appear in all copies.
 9-
10-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
11-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
12-FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
13-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
15-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16-PERFORMANCE OF THIS SOFTWARE.
17-
+0, -83
 1@@ -1,83 +0,0 @@
 2-.POSIX:
 3-
 4-include config.mk
 5-
 6-CC = cc
 7-AR = ar
 8-ARFLAGS = -r -c
 9-CFLAGS = -ansi -pedantic-errors -Wall -Wextra -O2
10-WL_CFLAGS = -std=c99 -Wall -Wextra -O2
11-CPPFLAGS = ${CONF_CPPFLAGS} -Iinclude -Ibuild
12-LDFLAGS = ${CONF_LDFLAGS}
13-
14-LIB_NAME = build/${CONF_LIB_NAME}
15-LIB_SRCS = source/maus.c      \
16-           source/maus_font.c \
17-           source/utils.c     \
18-           ${CONF_SRC}
19-LIB_OBJS = build/maus.o       \
20-           build/maus_font.o  \
21-           build/utils.o      \
22-           ${CONF_OBJS}
23-
24-all: ${LIB_NAME}
25-
26-${LIB_NAME}: ${LIB_OBJS}
27-	${AR} ${ARFLAGS} $@ ${LIB_OBJS}
28-
29-build/maus.o: source/maus.c include/maus.h config.mk
30-	mkdir -p build
31-	${CC} ${CFLAGS} ${CPPFLAGS} -c source/maus.c -o $@
32-build/maus_font.o: source/maus_font.c include/maus.h include/maus_font.h config.mk
33-	mkdir -p build
34-	${CC} ${CFLAGS} ${CPPFLAGS} -c source/maus_font.c -o $@
35-build/utils.o: source/utils.c include/utils.h
36-	mkdir -p build
37-	${CC} ${CFLAGS} ${CPPFLAGS} -c source/utils.c -o $@
38-
39-# X11
40-build/maus_x11.o: source/maus_x11.c include/maus.h include/maus_x11.h config.mk
41-	mkdir -p build
42-	${CC} ${CFLAGS} ${CPPFLAGS} -c source/maus_x11.c -o $@
43-
44-# Wayland
45-build/maus_wayland.o: source/maus_wayland.c include/maus.h include/maus_wayland.h build/xdg-shell-client-protocol.h build/pointer-constraints-unstable-v1-client-protocol.h build/relative-pointer-unstable-v1-client-protocol.h config.mk
46-	mkdir -p build
47-	${CC} ${WL_CFLAGS} ${CPPFLAGS} -c source/maus_wayland.c -o $@
48-build/xdg-shell-client-protocol.h:
49-	mkdir -p build
50-	wayland-scanner client-header ${PROTOS}/stable/xdg-shell/xdg-shell.xml $@
51-build/xdg-shell-protocol.c:
52-	mkdir -p build
53-	wayland-scanner private-code ${PROTOS}/stable/xdg-shell/xdg-shell.xml $@
54-build/xdg-shell-protocol.o: build/xdg-shell-protocol.c build/xdg-shell-client-protocol.h
55-	mkdir -p build
56-	${CC} ${WL_CFLAGS} ${CPPFLAGS} -c build/xdg-shell-protocol.c -o $@
57-build/pointer-constraints-unstable-v1-client-protocol.h:
58-	mkdir -p build
59-	wayland-scanner client-header ${PROTOS}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@
60-build/pointer-constraints-unstable-v1-protocol.c:
61-	mkdir -p build
62-	wayland-scanner private-code ${PROTOS}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@
63-build/pointer-constraints-unstable-v1-protocol.o: build/pointer-constraints-unstable-v1-protocol.c build/pointer-constraints-unstable-v1-client-protocol.h
64-	mkdir -p build
65-	${CC} ${WL_CFLAGS} ${CPPFLAGS} -c build/pointer-constraints-unstable-v1-protocol.c -o $@
66-build/relative-pointer-unstable-v1-client-protocol.h:
67-	mkdir -p build
68-	wayland-scanner client-header ${PROTOS}/unstable/relative-pointer/relative-pointer-unstable-v1.xml $@
69-build/relative-pointer-unstable-v1-protocol.c:
70-	mkdir -p build
71-	wayland-scanner private-code ${PROTOS}/unstable/relative-pointer/relative-pointer-unstable-v1.xml $@
72-build/relative-pointer-unstable-v1-protocol.o: build/relative-pointer-unstable-v1-protocol.c build/relative-pointer-unstable-v1-client-protocol.h
73-	mkdir -p build
74-	${CC} ${WL_CFLAGS} ${CPPFLAGS} -c build/relative-pointer-unstable-v1-protocol.c -o $@
75-
76-clean:
77-	rm -rf build ${LIB_NAME} config.mk compile_flags.txt
78-
79-compile_flags:
80-	rm -f compile_flags.txt
81-	for f in ${CFLAGS} ${CPPFLAGS}; do echo $$f >> compile_flags.txt; done
82-
83-.PHONY: all clean compile_flags
84-
+0, -84
 1@@ -1,84 +0,0 @@
 2-![logo](assets/logo_256x112.png)  
 3-is a small, cross-platform, software windowing library **now in ANSI C**
 4-
 5-### Building
 6-Unix:
 7-```sh
 8-./configure [x11|wayland|mac]
 9-make # That's it!
10-```
11-
12-Windows:
13-```
14-.\build.bat [msvc|gcc|clang]
15-```
16-> If anyone is on Windows, please try to compile past the ANSI conversion.
17-> I pretty much converted it without checking so there may still be C99
18-> artefacts left behind.
19-
20-After building, you have a library which you link _your_ sources with. It is
21-located in `build/`.
22-
23-### Usage
24-#### libmaus
25-Here is an annoted (C99) example for a basic window program which counts the
26-number of frames that have elapsed, draw the text and displays if you've
27-pressed a key (specifically 'A').
28-
29-For the full list of functions and what they do, look at
30-[the header](include/maus.h).
31-
32-```c
33-#include "maus.h"
34-#include "maus_font.h"
35-
36-int main(void)
37-{
38-	int x=50, y=50, width=640, height=480;
39-	Maus* ctx = maus_init("example!", x, y, width, height);
40-	maus_create_window(ctx);
41-	MausFont* font = maus_font_load("assets/fonts/font1.bdf");
42-
43-	int running = true;
44-	long long frames = 0;
45-	int a_pressed = false;
46-
47-	while (running) {
48-		MausEvent ev;
49-		while (maus_event_poll(ctx, &ev)) {
50-			// to see the full list of event types, look at
51-			// the enum `MausEventType` in `maus.h`
52-			if (ev.type == MAUS_EV_CLOSE)  {
53-				running = false;
54-				continue;
55-			}
56-
57-			if (ev.type == MAUS_EV_KEY && ev.key.pressed)  {
58-				if (ctx->key_syms[MAUS_KEY_A])
59-					a_pressed = 1;
60-			}
61-		}
62-
63-		// clear framebuffer with color white
64-		// colors are in format ARGB
65-		maus_clear(ctx, (MausColor){255, 255, 255, 255});
66-
67-		if (a_pressed) {
68-			const char* msg = "how dare you press a!!";
69-			maus_draw_text(ctx, font, 10, 50, msg, (MausColor){255, 255, 0, 0});
70-		}
71-
72-		char frames_text[256];
73-		snprintf(frames_text, sizeof(frames_text), "%lld", frames++);
74-		maus_draw_text(ctx, font, 10, 20, frames_text, (MausColor){255, 255, 0, 0});
75-
76-		maus_target_fps(ctx, 512);
77-		maus_present(ctx);
78-	}
79-
80-	// free resources
81-	maus_font_free(font);
82-	maus_close(ctx);
83-}
84-```
85-
+0, -16
 1@@ -1,16 +0,0 @@
 2-Maus:
 3-[ ] Relative cursor
 4-	[ ] Fill deltas
 5-[ ] Rename mw->ctx internally
 6-[ ] Move framebuffer creation out
 7-    of maus_init on platforms
 8-[?] Cursor warping
 9-[?] Custom cursor
10-
11-MausFont:
12-
13-X11:
14-Wayland:
15-Windows:
16-macOS:
17-
+0, -0
+0, -0
+0, -38
 1@@ -1,38 +0,0 @@
 2-@echo off
 3-
 4-if not exist build mkdir build
 5-
 6-set "COMPILER=%~1"
 7-if "%COMPILER%"=="" set "COMPILER=gcc"
 8-
 9-if /I "%COMPILER%"=="msvc" goto msvc
10-if /I "%COMPILER%"=="gcc" goto gcc
11-if /I "%COMPILER%"=="clang" goto clang
12-
13-echo Usage: build.bat [msvc^|gcc^|clang]
14-exit /b 1
15-
16-:: MSVC
17-:msvc
18-cl /diagnostics:color /nologo /W3 /O2 /Iinclude /DBACKEND_WIN /c ^
19-   source/maus.c source/maus_win.c source/maus_font.c source/utils.c
20-lib /nologo /OUT:build\libmaus_win.lib *.obj
21-move /Y *.obj build\
22-goto :eof
23-
24-:: GCC
25-:gcc
26-cc -std=c99 -Wall -Wextra -O2 -Iinclude -DBACKEND_WIN -c ^
27-   source/maus.c source/maus_win.c source/maus_font.c source/utils.c
28-move *.o build\
29-ar rcs build\libmaus_win.a build\maus.o build\maus_win.o build\maus_font.o build\utils.o
30-goto :eof
31-
32-:: GCC
33-:clang
34-clang -std=c99 -Wall -Wextra -O2 -Iinclude -DBACKEND_WIN -c ^
35-   source/maus.c source/maus_win.c source/maus_font.c source/utils.c
36-move *.o build\
37-ar rcs build\libmaus_win.a build\maus.o build\maus_win.o build\maus_font.o build\utils.o
38-goto :eof
39-
+0, -50
 1@@ -1,50 +0,0 @@
 2-#!/bin/sh
 3-
 4-for arg do
 5-	case "$arg" in
 6-		--help)
 7-			echo "Usage: ./configure [x11|wayland|mac]"
 8-			exit 0
 9-			;;
10-		*)
11-			if [ -n "$backend" ]; then
12-				echo "Usage: ./configure [x11|wayland|mac]"
13-				exit 1
14-			fi
15-			backend="$arg"
16-			;;
17-	esac
18-done
19-
20-cat > config.mk << EOF
21-# Generated by configure script
22-BACKEND = $backend
23-EOF
24-
25-case "$backend" in
26-	x11)
27-		echo "CONF_CPPFLAGS = -DBACKEND_X11" >> config.mk
28-		echo "CONF_LDFLAGS = -lX11 -lXext" >> config.mk
29-		echo "CONF_SRC = source/maus_x11.c" >> config.mk
30-		echo "CONF_OBJS = build/maus_x11.o" >> config.mk
31-		echo "CONF_LIB_NAME = libmaus_x11.a" >> config.mk
32-		;;
33-	wayland)
34-		echo "CONF_CPPFLAGS = -DBACKEND_WAY $(pkg-config --cflags wayland-client wayland-cursor xkbcommon)" >> config.mk
35-		echo "CONF_LDFLAGS = $(pkg-config --libs wayland-client wayland-cursor xkbcommon)" >> config.mk
36-		echo "CONF_SRC = source/maus_wayland.c build/xdg-shell-protocol.c build/pointer-constraints-unstable-v1-protocol.c build/relative-pointer-unstable-v1-protocol.c" >> config.mk
37-		echo "CONF_OBJS = build/maus_wayland.o build/xdg-shell-protocol.o build/pointer-constraints-unstable-v1-protocol.o build/relative-pointer-unstable-v1-protocol.o" >> config.mk
38-		echo "CONF_LIB_NAME = libmaus_wayland.a" >> config.mk
39-		echo "PROTOS = $(pkg-config --variable=pkgdatadir wayland-protocols)" >> config.mk
40-		;;
41-	mac)
42-		# TODO
43-		;;
44-	*)
45-		echo "Unsupported backend '$backend'"
46-		rm -f config.mk
47-		exit 1
48-		;;
49-esac
50-echo "Configuration done"
51-
+0, -12
 1@@ -1,12 +0,0 @@
 2-include ../../config.mk
 3-
 4-CC = cc
 5-CFLAGS = -std=c99 -Wall -Wextra -g
 6-CPPFLAGS = ${CONF_CPPFLAGS} -I../../include -I../../build
 7-LIBS = ${CONF_LDFLAGS}
 8-MAUS_LIB = ../../build/${CONF_LIB_NAME}
 9-
10-SRC = main.c
11-
12-all:
13-	${CC} ${CFLAGS} ${CPPFLAGS} ${SRC} ${MAUS_LIB} ${LIBS} -o basic-window
+0, -27
 1@@ -1,27 +0,0 @@
 2-@echo off
 3-
 4-set "COMPILER=%~1"
 5-if "%COMPILER%"=="" set "COMPILER=gcc"
 6-
 7-if /I "%COMPILER%"=="msvc" goto msvc
 8-if /I "%COMPILER%"=="gcc" goto gcc
 9-if /I "%COMPILER%"=="clang" goto clang
10-
11-echo Usage: build.bat [msvc^|gcc^|clang]
12-exit /b 1
13-
14-:msvc
15-cl /diagnostics:color /nologo /W3 /O2 /I..\..\include main.c ..\..\build\libmaus_win.lib user32.lib gdi32.lib /link /OUT:basic-window.exe
16-echo Build complete
17-goto :eof
18-
19-:gcc
20-cc -std=c99 -Wall -Wextra -g -I../../include main.c ../../build/libmaus_win.a -lgdi32 -luser32 -o basic-window.exe
21-echo Build complete
22-goto :eof
23-
24-:clang
25-clang -std=c99 -Wall -Wextra -g -I../../include main.c ../../build/libmaus_win.a -lgdi32 -luser32 -o basic-window.exe
26-echo Build complete
27-goto :eof
28-
+0, -155
  1@@ -1,155 +0,0 @@
  2-#include <stdbool.h>
  3-#include <stdint.h>
  4-#include <stdlib.h>
  5-
  6-#include "maus.h"
  7-#include "maus_font.h"
  8-
  9-int mx, my;
 10-bool cur_visible = true;
 11-bool cur_locked = false;
 12-bool cur_relative = false;
 13-bool mb1_pressed = false;
 14-char txtbuf[4096] = {'\0'};
 15-int current_char = 0;
 16-bool resize = false;
 17-int rszw;
 18-int rszh;
 19-MausColor white = {255, 255, 255, 255};
 20-
 21-void handle_ev(Maus* mw, MausEvent* ev)
 22-{
 23-	switch (ev->type) {
 24-		case MAUS_EV_CLOSE:
 25-			maus_close(mw);
 26-			exit(EXIT_SUCCESS);
 27-			break;
 28-		case MAUS_EV_KEY: {
 29-			(void)0;
 30-
 31-			int8_t* keys = mw->key_syms;
 32-			if (keys[MAUS_KEY_CONTROL_L] && keys[MAUS_KEY_Q]) {
 33-				maus_close(mw);
 34-				exit(EXIT_SUCCESS);
 35-			};
 36-			if (keys[MAUS_KEY_CONTROL_L] && keys[MAUS_KEY_P]) {
 37-				cur_visible ?
 38-				maus_cur_set_mode(mw, MAUS_CURSOR_STATE_HIDDEN) :
 39-				maus_cur_set_mode(mw, MAUS_CURSOR_STATE_VISIBLE);
 40-
 41-				cur_visible = !cur_visible;
 42-			}
 43-			if (keys[MAUS_KEY_CONTROL_L] && keys[MAUS_KEY_L]) {
 44-				cur_locked ?
 45-				maus_cur_set_mode(mw, MAUS_CURSOR_STATE_FREE) :
 46-				maus_cur_set_mode(mw, MAUS_CURSOR_STATE_LOCKED);
 47-
 48-				cur_locked = !cur_locked;
 49-			}
 50-			if (keys[MAUS_KEY_CONTROL_L] && keys[MAUS_KEY_R]) {
 51-				cur_relative ?
 52-				maus_cur_set_mode(mw, MAUS_CURSOR_STATE_ABSOLUTE) :
 53-				maus_cur_set_mode(mw, MAUS_CURSOR_STATE_RELATIVE);
 54-
 55-				cur_relative = !cur_relative;
 56-			}
 57-
 58-			if (ev->key.pressed == false)
 59-				break;
 60-
 61-			if (!((ev->key.key >= 32 && ev->key.key <= 126) || ev->key.key == '\n'))
 62-				break;
 63-
 64-			if (current_char + 1 < 4095 && current_char >= 0)
 65-				txtbuf[current_char++] = ev->key.text;
 66-			else
 67-				maus_log(stderr, "txtbuf full");
 68-
 69-			break;
 70-		}
 71-		case MAUS_EV_MOUSE_BUTTON: {
 72-			if (ev->mouse.button.button == MAUS_MOUSE_BUTTON_SCROLL_UP) {
 73-				white.r += 5;
 74-				white.g += 5;
 75-				white.b += 5;
 76-			}
 77-			else if (ev->mouse.button.button == MAUS_MOUSE_BUTTON_SCROLL_DOWN) {
 78-				white.r -= 5;
 79-				white.g -= 5;
 80-				white.b -= 5;
 81-			}
 82-			mb1_pressed =
 83-			mw->mouse_buttons[MAUS_MOUSE_BUTTON_LEFT] ?
 84-			true : false;
 85-			break;
 86-		}
 87-		case MAUS_EV_MOUSE_MOTION: {
 88-			mx = ev->mouse.motion.x;
 89-			my = ev->mouse.motion.y;
 90-
 91-		} break;
 92-		case MAUS_EV_RESIZE: {
 93-			resize = true;
 94-			rszw = ev->resize.width;
 95-			rszh = ev->resize.height;
 96-		} break;
 97-		case MAUS_EV_REDRAW:
 98-			break;
 99-		case MAUS_EV_NONE:
100-			break;
101-	}
102-}
103-
104-int main(void)
105-{
106-	Maus* mw = maus_init("basic window", 0, 0, 800, 600);
107-	if (!mw)
108-		return EXIT_FAILURE;
109-	maus_create_window(mw);
110-	MausFont* font = maus_font_load("assets/fonts/font1.bdf");
111-	if (!font)
112-		return EXIT_FAILURE;
113-
114-	MausEvent ev;
115-	MausColor red = { 255, 255, 0, 0 };
116-	/* unsigned long long ticks = 0; */
117-	for (;;) {
118-		while (maus_event_poll(mw, &ev))
119-			(void) handle_ev(mw, &ev);
120-
121-		/* only resize window once per fram */
122-		if (resize) {
123-			maus_resize(mw, rszw, rszh);
124-			resize = false;
125-		}
126-
127-		maus_clear(mw, white);
128-
129-		uint32_t red_unpacked = MAUS_UNPACK_COL(red);
130-		if (mx >= 0 && my >= 0 &&
131-		    mx < (int32_t)mw->width &&
132-		    my < (int32_t)mw->height && mb1_pressed) {
133-			MAUS_PIXEL_AT(mw, mx, my) = red_unpacked;
134-		}
135-
136-		for (uint32_t y = 0; y < mw->height/2; y++) {
137-			for (uint32_t x = 0; x < mw->width/2; x++) {
138-				MAUS_PIXEL_AT(mw, x, y) = red_unpacked;
139-			}
140-		}
141-		red.b++;
142-
143-		/* maus_draw_text(mw, font, 700, 50, "maus font\nloading example", red); */
144-
145-		/* char buf[512] = {0}; */
146-		/* snprintf(buf, 512, "maus' basic-window has been running for %lld ticks!", ticks); */
147-		/* maus_clipboard_set_text(mw, buf); */
148-
149-		maus_draw_text(mw, font, 700, 50, txtbuf, red);
150-
151-		maus_target_fps(mw, 60);
152-		maus_present(mw);
153-	}
154-	maus_font_free(font);
155-	maus_close(mw);
156-}
+0, -181
  1@@ -1,181 +0,0 @@
  2-#ifndef MAUSWIN_H
  3-#define MAUSWIN_H
  4-
  5-#include <stdio.h>
  6-#include <stdint.h>
  7-
  8-#include "maus_input.h"
  9-
 10-/* auto selection */
 11-#if (!defined(BACKEND_WIN) && !defined(BACKEND_MAC) && \
 12-    !defined(BACKEND_X11) && !defined(BACKEND_WAY)) || \
 13-    defined(BACKEND_AUTO)
 14-
 15-#ifdef BACKEND_AUTO
 16-#define MAUS_WARN_BACKEND_AUTO_SEL 0
 17-#else
 18-#define MAUS_WARN_BACKEND_AUTO_SEL 1
 19-#endif /* BACKEND_AUTO */
 20-
 21-	#if defined(_WIN32)
 22-	#define BACKEND_WIN
 23-
 24-	#elif defined(__APPLE__)
 25-	#define BACKEND_MAC
 26-
 27-	#else /* default to X */
 28-	#define BACKEND_X11
 29-
 30-	#endif
 31-#else
 32-#define MAUS_WARN_BACKEND_AUTO_SEL 0
 33-#endif /* auto selection */
 34-
 35-#if defined(BACKEND_X11)
 36-	#include "maus_x11.h"
 37-
 38-#elif defined(BACKEND_WAY)
 39-	#include "maus_wayland.h"
 40-
 41-#elif defined(BACKEND_WIN)
 42-	#include "maus_win.h"
 43-
 44-#elif defined(BACKEND_MAC)
 45-	/* ... */
 46-#endif
 47-
 48-#define MAUS_KEYCODE_LAST (256)
 49-#define MAUS_COL_ARGB(a, r, g, b) (MausColor){a, r, g, b}
 50-#define MAUS_COL_RGBA(r, g, b, a) (MausColor){a, r, g, b}
 51-#define MAUS_UNPACK_COL(c) \
 52-	(((uint32_t)(c).a << 24) | \
 53-	 ((uint32_t)(c).r << 16) | \
 54-	 ((uint32_t)(c).g <<  8) | \
 55-	 ((uint32_t)(c).b))
 56-
 57-#define MAUS_PIXEL_AT(mw, x, y) ((mw)->bfb[(y) * (mw)->stride + (x)])
 58-
 59-typedef enum {
 60-	MAUS_EV_NONE,
 61-	MAUS_EV_CLOSE,
 62-	MAUS_EV_KEY,
 63-	MAUS_EV_MOUSE_BUTTON,
 64-	MAUS_EV_MOUSE_MOTION,
 65-	MAUS_EV_RESIZE,
 66-	MAUS_EV_REDRAW /* TODO: MAUS_EV_REDRAW for windows */
 67-} MausEventType;
 68-
 69-typedef struct {
 70-	uint8_t a;
 71-	uint8_t r;
 72-	uint8_t g;
 73-	uint8_t b;
 74-} MausColor;
 75-
 76-typedef struct {
 77-	MausEventType type;
 78-
 79-	struct {
 80-		uint32_t code; /* raw, backend keycode */
 81-		MausKey  key;  /* logical, mapped key */
 82-		char     text; /* translated text from key */
 83-		int8_t     pressed;
 84-	} key;
 85-
 86-	struct {
 87-		struct {
 88-			MausMouseButton button;
 89-			int8_t            pressed;
 90-		} button;
 91-
 92-		struct {
 93-			int32_t x;
 94-			int32_t y;
 95-			int32_t dx;
 96-			int32_t dy;
 97-		} motion;
 98-	} mouse;
 99-
100-	struct {
101-		uint32_t width;
102-		uint32_t height;
103-	} resize;
104-} MausEvent;
105-
106-typedef struct {
107-	MausBackend backend;
108-	uint64_t    frame_time_last;
109-	char*       clipboard;
110-
111-	uint32_t* fb;  /* front frame buffer */
112-	uint32_t* bfb; /* back frame buffer */
113-	uint32_t  stride;
114-
115-	const char* title;
116-	uint32_t    width;
117-	uint32_t    height;
118-	int32_t     x;
119-	int32_t     y;
120-
121-	int8_t key_codes[MAUS_KEYCODE_LAST]; /* physical keys */
122-	int8_t key_syms[MAUS_KEY_LAST];      /* logical keys */
123-
124-	MausCursor cursor;
125-	int8_t       mouse_buttons[MAUS_MOUSE_BUTTON_LAST];
126-} Maus;
127-
128-/* clear screen with color: `col` */
129-void maus_clear(Maus* mw, MausColor col);
130-
131-/* set text to system clipboard */
132-void maus_clipboard_set_text(Maus* mw, const char* text);
133-
134-/* get text from system clipboard */
135-char* maus_clipboard_get_text(Maus* mw);
136-
137-/* close a Maus. returns 0 on fail
138-   TODO also free mw */
139-void maus_close(Maus* mw);
140-
141-/* close a window without the whole Maus. returns 0 on fail */
142-int8_t maus_close_window(Maus* mw);
143-
144-/* create window from Maus. returns 0 on fail */
145-int8_t maus_create_window(Maus* mw);
146-
147-/* log message to output `fd` and die */
148-void maus_die(const char* fmt, ...);
149-
150-/* get time since arbitrary start point (ns) */
151-uint64_t maus_get_time_ns(void);
152-
153-/* initialise and fills the Maus. returns NULL on fail */
154-Maus* maus_init(const char* title, int x, int y, int width, int height);
155-
156-/* log message to output `fd` */
157-void maus_log(FILE* fd, const char* fmt, ...);
158-
159-/* poll for events then fill `ev` with retrieved events.
160-   returns 1 if event polled, else 0.
161-   note: can burn cpu cycles */
162-int8_t maus_event_poll(Maus* mw, MausEvent* ev);
163-
164-/* poll for events then fill `ev` with retrieved events. returns 1 if event
165-   polled, else 0. note, thread goes to sleep until an event arrives */
166-void maus_event_wait(Maus* mw, MausEvent* ev);
167-
168-/* present the pixelbuffer to the screen */
169-void maus_present(Maus* mw);
170-
171-/* resize window to specified width and height. returns 1 on resize success,
172-   else 0 */
173-int8_t maus_resize(Maus* mw, uint32_t width, uint32_t height);
174-
175-/* cap framerate to targetted fps */
176-void maus_target_fps(Maus* mw, uint32_t fps);
177-
178-/* change behavior of mouse based on state passed */
179-void maus_cur_set_mode(Maus* mw, MausCursorState state);
180-
181-#endif /* MAUSWIN_H */
182-
+0, -40
 1@@ -1,40 +0,0 @@
 2-#ifndef MAUS_FONT_H
 3-#define MAUS_FONT_H
 4-
 5-#include <stdint.h>
 6-
 7-#include "maus.h"
 8-
 9-#define MAUS_BDF_GLYPHS_MAX 256
10-
11-typedef struct {
12-	uint8_t* bmp;
13-	uint16_t w;
14-	uint16_t h;
15-	int16_t  xoff;
16-	int16_t  yoff;
17-	uint16_t adv;
18-	int8_t   valid;
19-} MausGlyph;
20-
21-typedef struct {
22-	MausGlyph glyphs[MAUS_BDF_GLYPHS_MAX];
23-
24-	int32_t asc;
25-	int32_t dsc;
26-	int32_t cellh;
27-	int32_t cellw;
28-} MausFont;
29-
30-/* Loops through text passing parameters to glyph drawer */
31-void maus_draw_text(Maus* mw, MausFont* font, int32_t x, int32_t y,
32-                    const char* text, MausColor col);
33-
34-/* load a bdf font into MausFont. returns NULL on fail */
35-MausFont* maus_font_load(const char* path);
36-
37-/* release all allocations made with a MausFont */
38-void maus_font_free(MausFont* font);
39-
40-#endif /* MAUS_FONT_H */
41-
+0, -92
 1@@ -1,92 +0,0 @@
 2-#ifndef MAUS_INPUT_H
 3-#define MAUS_INPUT_H
 4-
 5-#include <stdint.h>
 6-
 7-typedef enum {
 8-	MAUS_KEY_NONE = 0,
 9-
10-	MAUS_KEY_TAB = '\t',     MAUS_KEY_ENTER = '\n',   MAUS_KEY_SPACE = ' ',
11-	MAUS_KEY_APOSTROPHE = '\'', MAUS_KEY_COMMA = ',',  MAUS_KEY_MINUS = '-',
12-	MAUS_KEY_PERIOD = '.',   MAUS_KEY_SLASH = '/',    MAUS_KEY_SEMICOLON = ';',
13-	MAUS_KEY_EQUAL = '=',    MAUS_KEY_LEFT_BRACKET = '[', MAUS_KEY_BACKSLASH = '\\',
14-	MAUS_KEY_RIGHT_BRACKET = ']', MAUS_KEY_GRAVE = '`',
15-
16-	/* numbers */
17-	MAUS_KEY_0 = '0', MAUS_KEY_1, MAUS_KEY_2, MAUS_KEY_3, MAUS_KEY_4,
18-	MAUS_KEY_5,       MAUS_KEY_6, MAUS_KEY_7, MAUS_KEY_8, MAUS_KEY_9,
19-
20-	/* uppercase */
21-	MAUS_KEY_A_UP = 'A', MAUS_KEY_B_UP, MAUS_KEY_C_UP, MAUS_KEY_D_UP, MAUS_KEY_E_UP,
22-	MAUS_KEY_F_UP,       MAUS_KEY_G_UP, MAUS_KEY_H_UP, MAUS_KEY_I_UP, MAUS_KEY_J_UP,
23-	MAUS_KEY_K_UP,       MAUS_KEY_L_UP, MAUS_KEY_M_UP, MAUS_KEY_N_UP, MAUS_KEY_O_UP,
24-	MAUS_KEY_P_UP,       MAUS_KEY_Q_UP, MAUS_KEY_R_UP, MAUS_KEY_S_UP, MAUS_KEY_T_UP,
25-	MAUS_KEY_U_UP,       MAUS_KEY_V_UP, MAUS_KEY_W_UP, MAUS_KEY_X_UP, MAUS_KEY_Y_UP,
26-	MAUS_KEY_Z_UP,
27-
28-	/* lowercase */
29-	MAUS_KEY_A = 'a', MAUS_KEY_B, MAUS_KEY_C, MAUS_KEY_D, MAUS_KEY_E,
30-	MAUS_KEY_F,       MAUS_KEY_G, MAUS_KEY_H, MAUS_KEY_I, MAUS_KEY_J,
31-	MAUS_KEY_K,       MAUS_KEY_L, MAUS_KEY_M, MAUS_KEY_N, MAUS_KEY_O,
32-	MAUS_KEY_P,       MAUS_KEY_Q, MAUS_KEY_R, MAUS_KEY_S, MAUS_KEY_T,
33-	MAUS_KEY_U,       MAUS_KEY_V, MAUS_KEY_W, MAUS_KEY_X, MAUS_KEY_Y,
34-	MAUS_KEY_Z,
35-
36-	MAUS_KEY_BACKSPACE = 128, MAUS_KEY_ESCAPE,      MAUS_KEY_DELETE,
37-
38-	/* navigation */
39-	MAUS_KEY_LEFT,          MAUS_KEY_RIGHT,     MAUS_KEY_UP,        MAUS_KEY_DOWN,
40-	MAUS_KEY_HOME,          MAUS_KEY_END,       MAUS_KEY_PAGE_UP,   MAUS_KEY_PAGE_DOWN,
41-	MAUS_KEY_INSERT,
42-
43-	/* modifiers */
44-	MAUS_KEY_SHIFT_L,       MAUS_KEY_SHIFT_R,   MAUS_KEY_CONTROL_L, MAUS_KEY_CONTROL_R,
45-	MAUS_KEY_ALT_L,         MAUS_KEY_ALT_R,     MAUS_KEY_SUPER_L,   MAUS_KEY_SUPER_R,
46-	MAUS_KEY_CAPS_LOCK,     MAUS_KEY_NUM_LOCK,  MAUS_KEY_SCROLL_LOCK,
47-
48-	/* function */
49-	MAUS_KEY_F1,            MAUS_KEY_F2,        MAUS_KEY_F3,        MAUS_KEY_F4,
50-	MAUS_KEY_F5,            MAUS_KEY_F6,        MAUS_KEY_F7,        MAUS_KEY_F8,
51-	MAUS_KEY_F9,            MAUS_KEY_F10,       MAUS_KEY_F11,       MAUS_KEY_F12,
52-
53-	MAUS_KEY_PRINT_SCREEN,  MAUS_KEY_PAUSE,     MAUS_KEY_MENU,
54-
55-	/* keypad */
56-	MAUS_KEY_KP_0,          MAUS_KEY_KP_1,      MAUS_KEY_KP_2,      MAUS_KEY_KP_3,
57-	MAUS_KEY_KP_4,          MAUS_KEY_KP_5,      MAUS_KEY_KP_6,      MAUS_KEY_KP_7,
58-	MAUS_KEY_KP_8,          MAUS_KEY_KP_9,
59-
60-	MAUS_KEY_KP_DECIMAL,    MAUS_KEY_KP_DIVIDE, MAUS_KEY_KP_MULTIPLY,
61-	MAUS_KEY_KP_SUBTRACT,   MAUS_KEY_KP_ADD,    MAUS_KEY_KP_ENTER,  MAUS_KEY_KP_EQUAL,
62-
63-	MAUS_KEY_LAST
64-} MausKey;
65-
66-typedef struct {
67-	int32_t x;
68-	int32_t y;
69-} MausCursor;
70-
71-typedef enum {
72-	MAUS_CURSOR_STATE_VISIBLE,
73-	MAUS_CURSOR_STATE_HIDDEN,
74-
75-	MAUS_CURSOR_STATE_FREE,
76-	MAUS_CURSOR_STATE_LOCKED,
77-
78-	MAUS_CURSOR_STATE_ABSOLUTE,
79-	MAUS_CURSOR_STATE_RELATIVE
80-} MausCursorState;
81-
82-typedef enum {
83-	MAUS_MOUSE_BUTTON_NONE = 0,
84-	MAUS_MOUSE_BUTTON_LEFT,
85-	MAUS_MOUSE_BUTTON_MIDDLE,
86-	MAUS_MOUSE_BUTTON_RIGHT,
87-	MAUS_MOUSE_BUTTON_SCROLL_UP,
88-	MAUS_MOUSE_BUTTON_SCROLL_DOWN,
89-	MAUS_MOUSE_BUTTON_LAST
90-} MausMouseButton;
91-
92-#endif /* MAUS_KEYS_H */
93-
+0, -116
  1@@ -1,116 +0,0 @@
  2-#ifndef MAUS_WAYLAND_H
  3-#define MAUS_WAYLAND_H
  4-
  5-#include <stddef.h>
  6-#include <stdint.h>
  7-
  8-#define MAUS_EVQ_MAX 64
  9-
 10-/* must forward declare so that other
 11-   ANSI abiding files arent affected */
 12-struct wl_display;
 13-struct wl_buffer;
 14-struct wl_registry;
 15-struct wl_compositor;
 16-struct wl_surface;
 17-struct wl_shm;
 18-struct wl_seat;
 19-struct wl_pointer;
 20-struct wl_keyboard;
 21-struct wl_cursor_theme;
 22-struct wl_cursor;
 23-
 24-struct xdg_wm_base;
 25-struct xdg_surface;
 26-struct xdg_toplevel;
 27-
 28-struct zwp_pointer_constraints_v1;
 29-struct zwp_confined_pointer_v1;
 30-struct zwp_relative_pointer_manager_v1;
 31-struct zwp_relative_pointer_v1;
 32-
 33-struct xkb_context;
 34-struct xkb_keymap;
 35-struct xkb_state;
 36-
 37-typedef struct {
 38-	int8_t  pending;
 39-	int32_t type;
 40-
 41-	uint32_t width;
 42-	uint32_t height;
 43-
 44-	int32_t  mouse_x;
 45-	int32_t  mouse_y;
 46-	int32_t  mouse_dx;
 47-	int32_t  mouse_dy;
 48-	uint32_t mouse_button;
 49-	uint8_t  mouse_pressed;
 50-
 51-	uint32_t key_code;
 52-	uint32_t key_sym;
 53-	char     key_text;
 54-	uint8_t  key_pressed;
 55-} MausEventPending;
 56-
 57-typedef struct {
 58-	struct wl_buffer* buffer;
 59-	void*             data;
 60-	size_t            size;
 61-	int8_t            busy;
 62-} MausWLBuffer;
 63-
 64-typedef struct {
 65-	struct wl_display*    display;
 66-	struct wl_compositor* compositor;
 67-	struct wl_surface*    surface;
 68-
 69-	struct wl_shm* shm;
 70-	MausWLBuffer   buffers[2];
 71-
 72-	struct wl_seat*     seat;
 73-	struct wl_pointer*  pointer;
 74-	struct wl_keyboard* keyboard;
 75-
 76-	struct wl_cursor_theme* cursor_theme;
 77-	struct wl_cursor*       cursor;
 78-	struct wl_surface*      cursor_surface;
 79-	uint32_t                pointer_enter_serial;
 80-	int32_t                 mouse_x;
 81-	int32_t                 mouse_y;
 82-	int8_t                  mouse_pos_set;
 83-	int8_t                  cursor_state;
 84-
 85-	struct zwp_pointer_constraints_v1*      pointer_constraints;
 86-	struct zwp_confined_pointer_v1*         locked_pointer;
 87-	struct zwp_relative_pointer_manager_v1* relative_pointer_manager;
 88-	struct zwp_relative_pointer_v1*         relative_pointer;
 89-
 90-	struct xkb_context* xkb_context;
 91-	struct xkb_keymap*  xkb_keymap;
 92-	struct xkb_state*   xkb_state;
 93-
 94-
 95-	MausEventPending pending;
 96-	MausEventPending evq[MAUS_EVQ_MAX];
 97-	uint32_t evq_head;
 98-	uint32_t evq_tail;
 99-	uint32_t evq_count;
100-
101-	int32_t  repeat_rate;
102-	int32_t  repeat_delay;
103-	uint32_t repeat_key_code;
104-	uint32_t repeat_key_sym;
105-	char     repeat_key_text;
106-	uint64_t repeat_next_ns;
107-
108-	struct xdg_wm_base*  wm_base;
109-	struct xdg_surface*  xdg_surface;
110-	struct xdg_toplevel* xdg_toplevel;
111-	int8_t               configured;
112-
113-	struct wl_registry*          registry;
114-} MausBackend;
115-
116-#endif /* MAUS_WAYLAND_H */
117-
+0, -20
 1@@ -1,20 +0,0 @@
 2-#ifndef MAUS_WIN_H
 3-#define MAUS_WIN_H
 4-
 5-#include <stdint.h>
 6-
 7-#include <windows.h>
 8-
 9-typedef struct {
10-	HWND      hwnd;
11-	HINSTANCE hInst;
12-	HDC       hdc;
13-	HBITMAP   hbm;
14-	HDC       memdc;
15-	int8_t    resized;
16-	uint32_t  rw;
17-	uint32_t  rh;
18-} MausBackend;
19-
20-#endif /* MAUS_WIN_H */
21-
+0, -33
 1@@ -1,33 +0,0 @@
 2-#ifndef MAUS_X11_H
 3-#define MAUS_X11_H
 4-
 5-#include <stdint.h>
 6-
 7-#include <X11/Xlib.h>
 8-#include <X11/extensions/XShm.h>
 9-
10-typedef enum {
11-	MAUS_ATOM_WM_DELETE_WINDOW,
12-	MAUS_ATOM_LAST
13-} MausX11Atoms;
14-
15-typedef struct {
16-	Display* display;
17-	Window   root;
18-	Window   win;
19-	Atom     atoms[MAUS_ATOM_LAST];
20-	GC       gc;
21-
22-	int8_t cur_rel; /* relative cursor */
23-	int8_t ignore_warp;
24-	int32_t mouse_x;
25-	int32_t mouse_y;
26-	int8_t  mouse_pos_set;
27-
28-	XShmSegmentInfo shm;
29-	int8_t          shmat;
30-	XImage*         image; /* TODO: XImage path */
31-} MausBackend;
32-
33-#endif /* MAUS_X11_H */
34-
+0, -11
 1@@ -1,11 +0,0 @@
 2-#ifndef UTIL_H
 3-#define UTIL_H
 4-
 5-/* duplicate a string. returns pointer to address of
 6-   newly allocated string buffer. if NULL, allocation
 7-   failed or src is NULL
 8-   note: you must free this newly allocated string */
 9-char* maus_strdup(const char* src);
10-
11-#endif /* UTIL_H */
12-
+0, -99
  1@@ -1,99 +0,0 @@
  2-#if !defined(BACKEND_WIN)
  3-#define _POSIX_C_SOURCE 199309L
  4-#else
  5-#include <windows.h>
  6-#endif
  7-
  8-#include <stdarg.h>
  9-#include <stdio.h>
 10-#include <stdlib.h>
 11-#include <time.h>
 12-
 13-#include "maus.h"
 14-
 15-static void vlog(FILE* fd, const char* fmt, va_list ap);
 16-
 17-static void vlog(FILE* fd, const char* fmt, va_list ap)
 18-{
 19-	fprintf(fd, "maus: ");
 20-	vfprintf(fd, fmt, ap);
 21-}
 22-
 23-void maus_die(const char* fmt, ...)
 24-{
 25-	va_list ap;
 26-
 27-	va_start(ap, fmt);
 28-	vlog(stderr, fmt, ap);
 29-	va_end(ap);
 30-
 31-	exit(EXIT_FAILURE);
 32-}
 33-
 34-uint64_t maus_get_time_ns(void)
 35-{
 36-#if !defined(_WIN32)
 37-	struct timespec ts;
 38-	clock_gettime(CLOCK_MONOTONIC, &ts);
 39-	return ts.tv_sec * 1000000000 + ts.tv_nsec;
 40-#else
 41-	static LARGE_INTEGER frequency = {0};
 42-	LARGE_INTEGER counter;
 43-	uint64_t sec;
 44-	uint64_t rem;
 45-
 46-	if (frequency.QuadPart == 0)
 47-		QueryPerformanceFrequency(&frequency);
 48-
 49-	QueryPerformanceCounter(&counter);
 50-
 51-	sec = counter.QuadPart / frequency.QuadPart;
 52-	rem = counter.QuadPart % frequency.QuadPart;
 53-
 54-	return (sec * 1000000000) + ((rem * 1000000000) / frequency.QuadPart);
 55-#endif
 56-}
 57-
 58-void maus_log(FILE* fd, const char* fmt, ...)
 59-{
 60-	va_list ap;
 61-
 62-	va_start(ap, fmt);
 63-	vlog(fd, fmt, ap);
 64-	fputc('\n', fd);
 65-	va_end(ap);
 66-}
 67-
 68-void maus_target_fps(Maus* mw, uint32_t fps)
 69-{
 70-	uint64_t ns_frame;
 71-	uint64_t cur_time;
 72-	uint64_t elapsed;
 73-	uint64_t sleep;
 74-
 75-	#if !defined(_WIN32)
 76-	struct timespec ts;
 77-	#endif
 78-
 79-	if (fps == 0)
 80-		return;
 81-
 82-	ns_frame = 1000000000 / fps; /* max ns a frame can take */
 83-	cur_time = maus_get_time_ns();
 84-	elapsed = cur_time - mw->frame_time_last;
 85-
 86-	/* if early finish, sleep for the remaining time balance */
 87-	if (elapsed < ns_frame) {
 88-		sleep = ns_frame - elapsed;
 89-	#if !defined(_WIN32)
 90-		ts.tv_sec = sleep / 1000000000;
 91-		ts.tv_nsec = sleep % 1000000000;
 92-		nanosleep(&ts, NULL);
 93-	#else
 94-		Sleep((DWORD)((sleep + 999999) / 1000000));
 95-	#endif
 96-	}
 97-
 98-	mw->frame_time_last = maus_get_time_ns();
 99-}
100-
+0, -296
  1@@ -1,296 +0,0 @@
  2-#include <stdio.h>
  3-#include <stdlib.h>
  4-#include <string.h>
  5-
  6-#include "maus.h"
  7-#include "maus_font.h"
  8-
  9-static void glyph_to_buf(int32_t sgx, int32_t egx, int32_t sgy, int32_t egy,
 10-                         int32_t gox, int32_t goy, MausGlyph* g, uint32_t col_up,
 11-                         uint32_t* buf, uint32_t stride);
 12-
 13-/* "blit" a glpyh to some buffer */
 14-static void glyph_to_buf(int32_t sgx, int32_t egx, int32_t sgy, int32_t egy,
 15-                         int32_t gox, int32_t goy, MausGlyph* g, uint32_t col_up,
 16-                         uint32_t* buf, uint32_t stride)
 17-{
 18-	int gy;
 19-	int gx;
 20-	int32_t dstx;
 21-
 22-	uint32_t* row;
 23-	int32_t offset;
 24-
 25-	for (gy = sgy; gy < egy; gy++) {
 26-		int dsty = goy + gy;
 27-
 28-		/* calculate row pointer once per scanline */
 29-		row = buf + (dsty * stride);
 30-		offset = gy * g->w;
 31-
 32-		for (gx = sgx; gx < egx; gx++) {
 33-			if (g->bmp[offset + gx] > 0) {
 34-				dstx = gox + gx;
 35-				row[dstx] = col_up;
 36-			}
 37-		}
 38-	}
 39-}
 40-
 41-static int8_t parse_glyphs(FILE* f, MausFont* font, char* line, size_t line_size,
 42-                           int32_t* encoding, int32_t* advance, int32_t* bw, int32_t* bh,
 43-                           int32_t* xoff, int32_t* yoff, int8_t* seen)
 44-{
 45-	int32_t rowbits;
 46-
 47-	int32_t x;
 48-	int32_t y;
 49-	uint64_t bits;
 50-
 51-	MausGlyph* g;
 52-
 53-	while (fgets(line, line_size, f)) {
 54-		if (sscanf(line, "ENCODING %d", encoding) == 1)
 55-			continue;
 56-		if (sscanf(line, "DWIDTH %d", advance) == 1)
 57-			continue;
 58-		if (sscanf(line, "BBX %d %d %d %d", bw, bh, xoff, yoff) == 4)
 59-			continue;
 60-
 61-		if (strncmp(line, "BITMAP", 6) == 0) {
 62-			/* invalid character code
 63-			   TODO: just skip it */
 64-			if (*encoding < 0 || *encoding >= MAUS_BDF_GLYPHS_MAX)
 65-				break;
 66-
 67-			/* empty/invalid size */
 68-			if (*bw <= 0 || *bh <= 0)
 69-				break;
 70-
 71-			g = &font->glyphs[*encoding];
 72-			free(g->bmp); /* prevent leak on hot reload */
 73-			memset(g, 0, sizeof(*g));
 74-
 75-			g->w = *bw;
 76-			g->h = *bh;
 77-			g->xoff = *xoff;
 78-			g->yoff = *yoff;
 79-			g->adv = *advance;
 80-
 81-			g->bmp = calloc((size_t)(*bw) * (*bh), 1);
 82-			if (!g->bmp) {
 83-				fclose(f);
 84-				maus_font_free(font);
 85-				return 0;
 86-			}
 87-
 88-			/* each bmp row in BDF is padded as a multiple
 89-			   of 8 bits. this rounds width up to the next
 90-			   multiple of 8 */
 91-			rowbits = (*bw + 7) & ~7;
 92-
 93-			for (y = 0; y < *bh; y++) {
 94-				/* missing row */
 95-				if (!fgets(line, line_size, f)) {
 96-					fclose(f);
 97-					maus_font_free(font);
 98-					return 0;
 99-				}
100-
101-				bits = strtoull(line, NULL, 16); /* hex to bits */
102-				for (x = 0; x < *bw; x++) {
103-					int bit = rowbits - 1 - x;
104-
105-					if ((bits >> bit) & 1)
106-						g->bmp[y * (*bw) + x] = 255; /* solid */
107-				}
108-			}
109-
110-			g->valid = 1;
111-			if (*advance > font->cellw)
112-				font->cellw = *advance;
113-			*seen = 1;
114-
115-			continue;
116-		}
117-
118-		if (strncmp(line, "ENDCHAR", 7) == 0)
119-			break;
120-	}
121-
122-	return 1;
123-}
124-
125-void maus_draw_text(Maus* mw, MausFont* font, int32_t x, int32_t y,
126-                    const char* text, MausColor col)
127-{
128-	uint32_t col_up = MAUS_UNPACK_COL(col);
129-
130-	size_t i;
131-
132-	/* current coordinates */
133-	int32_t cx = x;
134-	int32_t cy = y;
135-
136-	/* origins to start drawing glyph from */
137-	int32_t gox;
138-	int32_t goy;
139-
140-	/* starting glyph coordinates */
141-	int32_t sgx;
142-	int32_t sgy;
143-
144-	/* ending glyph coordinates */
145-	int32_t egx;
146-	int32_t egy;
147-
148-	/* current glyph pointer */
149-	MausGlyph* g;
150-
151-	if (!mw || !mw->bfb || !font || !text)
152-		return;
153-
154-	for (i = 0; text[i] != '\0'; i++) {
155-		char c = text[i];
156-
157-		if (c == '\n') {
158-			cx = x;
159-			cy += font->cellh;
160-			continue;
161-		}
162-
163-		g = &font->glyphs[(uint8_t)c];
164-		if (!g->valid) {
165-			/* still advance cx if character invalid */
166-			cx += (font->cellw > 0 ? font->cellw : 8);
167-			continue;
168-		}
169-
170-		/* origins to start drawing glyph from */
171-		gox = cx + g->xoff;
172-		goy = cy + font->asc - g->h - g->yoff;
173-
174-		/* starting coordinates */
175-		sgx = (-gox > 0) ? -gox : 0;
176-		sgy = (-goy > 0) ? -goy : 0;
177-
178-		egx = (mw->width - gox < g->w) ? (mw->width - gox) : g->w;
179-		egy = (mw->height - goy < g->h) ?(mw->height - goy) : g->h;
180-
181-		/* cull glyphs which start off screen */
182-		if (sgx >= egx || sgy >= egy) {
183-			cx += g->adv;
184-			continue;
185-		}
186-
187-		glyph_to_buf(sgx, egx, sgy, egy, gox, goy, g, col_up, mw->bfb, mw->stride);
188-		cx += g->adv;
189-	}
190-}
191-
192-MausFont* maus_font_load(const char* path)
193-{
194-	FILE* f = fopen(path, "r");
195-	MausFont* font = calloc(1, sizeof(MausFont));
196-	char line[1024];
197-
198-	int32_t asc = -1;
199-	int32_t dsc = -1;
200-	int32_t encoding = -1;
201-	int32_t advance = 0;
202-	int32_t bw = 0; /* bmp width */
203-	int32_t bh = 0; /* bmp height */
204-	int32_t xoff = 0;
205-	int32_t yoff = 0;
206-	int8_t seen = 0;
207-
208-	int i;
209-
210-	if (!f) {
211-		maus_log(stderr, "failed to load font \"%s\"", path);
212-		return NULL;
213-	}
214-
215-	if (!font) {
216-		maus_log(stderr, "failed to calloc font");
217-		fclose(f);
218-		return NULL;
219-	}
220-
221-	while (fgets(line, sizeof(line), f)) {
222-		if (sscanf(line, "FONT_ASCENT %d", &asc) == 1)
223-			continue;
224-		if (sscanf(line, "FONT_DESCENT %d", &dsc) == 1)
225-			continue;
226-
227-		/* ignore everything until glyphs start */
228-		if (strncmp(line, "STARTCHAR", 9) != 0)
229-			continue;
230-
231-		/* reset vaules for new glyph */
232-		encoding = -1;
233-		advance = 0;
234-		bw = 0;
235-		bh = 0;
236-		xoff = 0;
237-		yoff = 0;
238-
239-		if (!parse_glyphs(f, font, line, sizeof(line), &encoding, &advance, &bw, &bh, &xoff, &yoff, &seen))
240-			return NULL;
241-	}
242-
243-
244-	fclose(f);
245-
246-	if (!seen) {
247-		free(font);
248-		return NULL;
249-	}
250-
251-	/* estimate asc/dsc if they werent provided */
252-	if (asc < 0 || dsc < 0) {
253-		asc = 0;
254-		dsc = 0;
255-
256-		for (i = 0; i < MAUS_BDF_GLYPHS_MAX; i++) {
257-			MausGlyph* g = &font->glyphs[i];
258-
259-			/* unloaded glpyh */
260-			if (!g->valid)
261-				continue;
262-
263-			/* highest point above baseline */
264-			if (g->h + g->yoff > asc)
265-				asc = g->h + g->yoff;
266-
267-			/* lowest point below baseline */
268-			if (-g->yoff > dsc)
269-				dsc = -g->yoff;
270-		}
271-	}
272-
273-	font->asc = asc;
274-	font->dsc = -dsc;
275-	font->cellh = asc + dsc;
276-
277-	if (font->cellw <= 0 || font->cellh <= 0) {
278-		maus_font_free(font);
279-		return NULL;
280-	}
281-
282-	return font;
283-}
284-
285-void maus_font_free(MausFont* font)
286-{
287-	int i;
288-
289-	if (!font)
290-		return;
291-
292-	for (i = 0; i < MAUS_BDF_GLYPHS_MAX; i++)
293-		free(font->glyphs[i].bmp);
294-
295-	free(font);
296-}
297-
+0, -1351
   1@@ -1,1351 +0,0 @@
   2-#define _POSIX_C_SOURCE 200809L
   3-
   4-#include <fcntl.h>
   5-#include <poll.h>
   6-#include <stdlib.h>
   7-#include <string.h>
   8-#include <sys/mman.h>
   9-#include <unistd.h>
  10-
  11-#include <wayland-client.h>
  12-#include <wayland-cursor.h>
  13-#include <xdg-shell-client-protocol.h>
  14-#include <pointer-constraints-unstable-v1-client-protocol.h>
  15-#include <relative-pointer-unstable-v1-client-protocol.h>
  16-#include <xkbcommon/xkbcommon.h>
  17-
  18-#include "maus.h"
  19-#include "maus_wayland.h"
  20-
  21-static void registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name);
  22-static void xdg_surface_configure(void* data, struct xdg_surface* xdg_surface, uint32_t serial);
  23-static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, int32_t width, int32_t height, struct wl_array* states);
  24-static void xdg_toplevel_close(void* data, struct xdg_toplevel* xdg_toplevel);
  25-static void xdg_toplevel_configure_bounds(void* data, struct xdg_toplevel* xdg_toplevel, int32_t width, int32_t height);
  26-static void xdg_toplevel_wm_capabilities(void* data, struct xdg_toplevel* xdg_toplevel, struct wl_array* capabilities);
  27-static void wm_base_ping(void* data, struct xdg_wm_base* wm_base, uint32_t serial);
  28-static void seat_capabilities(void* data, struct wl_seat* seat, uint32_t capabilities);
  29-static void seat_name(void* data, struct wl_seat* seat, const char* name);
  30-static void pointer_enter(void* data, struct wl_pointer* pointer, uint32_t serial, struct wl_surface* surface, wl_fixed_t sx, wl_fixed_t sy);
  31-static void pointer_leave(void* data, struct wl_pointer* pointer, uint32_t serial, struct wl_surface* surface);
  32-static void pointer_motion(void* data, struct wl_pointer* pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
  33-static void pointer_button(void* data, struct wl_pointer* pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
  34-static void pointer_axis(void* data, struct wl_pointer* pointer, uint32_t time, uint32_t axis, wl_fixed_t value);
  35-static void pointer_frame(void* data, struct wl_pointer* pointer);
  36-static void pointer_axis_source(void* data, struct wl_pointer* pointer, uint32_t axis_source);
  37-static void pointer_axis_stop(void* data, struct wl_pointer* pointer, uint32_t time, uint32_t axis);
  38-static void pointer_axis_discrete(void* data, struct wl_pointer* pointer, uint32_t axis, int32_t discrete);
  39-static void pointer_axis_value120(void* data, struct wl_pointer* pointer, uint32_t axis, int32_t value120);
  40-static void pointer_axis_relative_direction(void* data, struct wl_pointer* pointer, uint32_t axis, uint32_t direction);
  41-static 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);
  42-static void keyboard_keymap(void* data, struct wl_keyboard* keyboard, uint32_t format, int32_t fd, uint32_t size);
  43-static void keyboard_enter(void* data, struct wl_keyboard* keyboard, uint32_t serial, struct wl_surface* surface, struct wl_array* keys);
  44-static void keyboard_leave(void* data, struct wl_keyboard* keyboard, uint32_t serial, struct wl_surface* surface);
  45-static void keyboard_key(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
  46-static 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);
  47-static void keyboard_repeat_info(void* data, struct wl_keyboard* keyboard, int32_t rate, int32_t delay);
  48-static void registry_global(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version);
  49-
  50-static int8_t cursor_init(Maus* mw);
  51-static void cursor_destroy(Maus* mw);
  52-static void cursor_lock(Maus* mw);
  53-static void cursor_unlock(Maus* mw);
  54-static void cursor_show(Maus* mw);
  55-static void cursor_hide(Maus* mw);
  56-static void cursor_relative(Maus* mw);
  57-static void cursor_absolute(Maus* mw);
  58-static void event_push_pending(Maus* mw);
  59-static int8_t event_pop(Maus* mw, MausEventPending* ev);
  60-static void event_push_key(Maus* mw, uint32_t code, uint32_t sym, char text, uint8_t pressed);
  61-static int8_t repeat_push_due(Maus* mw);
  62-static int32_t repeat_timeout_ms(Maus* mw);
  63-static int8_t display_read(Maus* mw, int timeout_ms);
  64-static MausKey keysym_to_mauskey(xkb_keysym_t sym);
  65-static MausMouseButton wl_button_to_maus(uint32_t button);
  66-static void wl_buffer_release(void* data, struct wl_buffer* buffer);
  67-
  68-static struct wl_registry_listener registry_listener = { registry_global, registry_global_remove };
  69-static struct xdg_surface_listener xdg_surface_listener = { xdg_surface_configure };
  70-static struct xdg_toplevel_listener xdg_toplevel_listener = {
  71-	xdg_toplevel_configure, xdg_toplevel_close,
  72-	xdg_toplevel_configure_bounds, xdg_toplevel_wm_capabilities
  73-};
  74-static struct xdg_wm_base_listener xdg_wm_base_listener = { wm_base_ping };
  75-static struct wl_seat_listener seat_listener = { seat_capabilities, seat_name };
  76-static struct wl_pointer_listener pointer_listener = {
  77-	pointer_enter, pointer_leave, pointer_motion, pointer_button,
  78-	pointer_axis, pointer_frame, pointer_axis_source, pointer_axis_stop,
  79-	pointer_axis_discrete, pointer_axis_value120, pointer_axis_relative_direction
  80-};
  81-static struct wl_keyboard_listener keyboard_listener = {
  82-	keyboard_keymap, keyboard_enter, keyboard_leave, keyboard_key,
  83-	keyboard_modifiers, keyboard_repeat_info
  84-};
  85-static struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
  86-	relative_pointer_motion
  87-};
  88-static struct wl_buffer_listener wl_buffer_listener = { wl_buffer_release };
  89-
  90-static void wl_buffer_release(void* data, struct wl_buffer* buffer)
  91-{
  92-	MausWLBuffer* wb = data;
  93-
  94-	(void)buffer;
  95-
  96-	wb->busy = 0;
  97-}
  98-
  99-static void event_push_pending(Maus* mw)
 100-{
 101-	MausBackend* be = &mw->backend;
 102-
 103-	if (!be->pending.pending)
 104-		return;
 105-
 106-	if (be->evq_count == MAUS_EVQ_MAX) {
 107-		be->evq_head = (be->evq_head + 1) % MAUS_EVQ_MAX;
 108-		be->evq_count--;
 109-	}
 110-
 111-	be->evq[be->evq_tail] = be->pending;
 112-	be->evq_tail = (be->evq_tail + 1) % MAUS_EVQ_MAX;
 113-	be->evq_count++;
 114-	be->pending.pending = 0;
 115-}
 116-
 117-static int8_t event_pop(Maus* mw, MausEventPending* ev)
 118-{
 119-	MausBackend* be = &mw->backend;
 120-
 121-	if (be->evq_count == 0)
 122-		return 0;
 123-
 124-	*ev = be->evq[be->evq_head];
 125-	be->evq_head = (be->evq_head + 1) % MAUS_EVQ_MAX;
 126-	be->evq_count--;
 127-	return 1;
 128-}
 129-
 130-static void event_push_key(Maus* mw, uint32_t code, uint32_t sym, char text, uint8_t pressed)
 131-{
 132-	MausBackend* be = &mw->backend;
 133-
 134-	be->pending.pending = 1;
 135-	be->pending.type = MAUS_EV_KEY;
 136-	be->pending.key_code = code;
 137-	be->pending.key_sym = sym;
 138-	be->pending.key_text = text;
 139-	be->pending.key_pressed = pressed;
 140-	event_push_pending(mw);
 141-}
 142-
 143-static void registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name)
 144-{
 145-	(void)data;
 146-	(void)wl_registry;
 147-	(void)name;
 148-}
 149-
 150-static void xdg_surface_configure(void* data, struct xdg_surface* xdg_surface, uint32_t serial)
 151-{
 152-	Maus* mw = data;
 153-	xdg_surface_ack_configure(xdg_surface, serial);
 154-	mw->backend.configured = 1;
 155-	if (!mw->backend.pending.pending) {
 156-		mw->backend.pending.pending = 1;
 157-		mw->backend.pending.type = MAUS_EV_REDRAW;
 158-	}
 159-	event_push_pending(mw);
 160-}
 161-
 162-static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel,
 163-                                   int32_t width, int32_t height, struct wl_array* states)
 164-{
 165-	Maus* mw = data;
 166-
 167-	(void)xdg_toplevel;
 168-	(void)states;
 169-
 170-	if (width <= 0 || height <= 0)
 171-		return;
 172-
 173-	mw->backend.pending.pending = 1;
 174-	mw->backend.pending.type = MAUS_EV_RESIZE;
 175-	mw->backend.pending.width = width;
 176-	mw->backend.pending.height = height;
 177-	event_push_pending(mw);
 178-}
 179-
 180-static void xdg_toplevel_close(void* data, struct xdg_toplevel* xdg_toplevel)
 181-{
 182-	Maus* mw = data;
 183-
 184-	(void)xdg_toplevel;
 185-
 186-	mw->backend.pending.pending = 1;
 187-	mw->backend.pending.type = MAUS_EV_CLOSE;
 188-	event_push_pending(mw);
 189-}
 190-
 191-static void xdg_toplevel_configure_bounds(void* data, struct xdg_toplevel* xdg_toplevel,
 192-                                          int32_t width, int32_t height)
 193-{
 194-	(void)data;
 195-	(void)xdg_toplevel;
 196-	(void)width;
 197-	(void)height;
 198-}
 199-
 200-static void xdg_toplevel_wm_capabilities(void* data, struct xdg_toplevel* xdg_toplevel,
 201-                                         struct wl_array* capabilities)
 202-{
 203-	(void)data;
 204-	(void)xdg_toplevel;
 205-	(void)capabilities;
 206-}
 207-
 208-static void wm_base_ping(void* data, struct xdg_wm_base* wm_base, uint32_t serial)
 209-{
 210-	(void)data;
 211-	xdg_wm_base_pong(wm_base, serial);
 212-}
 213-
 214-static void registry_global(void* data, struct wl_registry* registry,
 215-                            uint32_t name, const char* interface,
 216-                            uint32_t version)
 217-{
 218-	Maus* mw = data;
 219-	MausBackend* be = &mw->backend;
 220-
 221-	(void) version;
 222-
 223-	if (strcmp(interface, wl_compositor_interface.name) == 0)
 224-		be->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 4);
 225-	else if (strcmp(interface, wl_shm_interface.name) == 0)
 226-		be->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
 227-	else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
 228-		be->wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
 229-		xdg_wm_base_add_listener(be->wm_base, &xdg_wm_base_listener, mw);
 230-	}
 231-	else if (strcmp(interface, wl_seat_interface.name) == 0) {
 232-		be->seat = wl_registry_bind(registry, name, &wl_seat_interface, 5);
 233-		wl_seat_add_listener(be->seat, &seat_listener, mw);
 234-	}
 235-	else if (strcmp(interface, zwp_pointer_constraints_v1_interface.name) == 0)
 236-		be->pointer_constraints = wl_registry_bind(registry, name, &zwp_pointer_constraints_v1_interface, 1);
 237-	else if (strcmp(interface, zwp_relative_pointer_manager_v1_interface.name) == 0)
 238-		be->relative_pointer_manager = wl_registry_bind(registry, name, &zwp_relative_pointer_manager_v1_interface, 1);
 239-}
 240-
 241-static void seat_capabilities(void* data, struct wl_seat* seat, uint32_t capabilities)
 242-{
 243-	Maus* mw = data;
 244-	MausBackend* be = &mw->backend;
 245-
 246-	if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !be->pointer) {
 247-		be->pointer = wl_seat_get_pointer(seat);
 248-		wl_pointer_add_listener(be->pointer, &pointer_listener, mw);
 249-	}
 250-	else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && be->pointer) {
 251-		cursor_absolute(mw);
 252-		wl_pointer_destroy(be->pointer);
 253-		be->pointer = NULL;
 254-	}
 255-
 256-	if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && !be->keyboard) {
 257-		be->keyboard = wl_seat_get_keyboard(seat);
 258-		wl_keyboard_add_listener(be->keyboard, &keyboard_listener, mw);
 259-	}
 260-	else if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && be->keyboard) {
 261-		wl_keyboard_destroy(be->keyboard);
 262-		be->keyboard = NULL;
 263-	}
 264-}
 265-
 266-static void seat_name(void* data, struct wl_seat* seat, const char* name)
 267-{
 268-	(void)data;
 269-	(void)seat;
 270-	(void)name;
 271-}
 272-
 273-static void pointer_enter(void* data, struct wl_pointer* pointer, uint32_t serial,
 274-                          struct wl_surface* surface, wl_fixed_t sx, wl_fixed_t sy)
 275-{
 276-	Maus* mw = data;
 277-
 278-	(void)pointer;
 279-	(void)surface;
 280-	(void)sx;
 281-	(void)sy;
 282-
 283-	mw->backend.pointer_enter_serial = serial;
 284-	if (mw->backend.cursor_state == MAUS_CURSOR_STATE_HIDDEN)
 285-		cursor_hide(mw);
 286-	else
 287-		cursor_show(mw);
 288-}
 289-
 290-static void pointer_leave(void* data, struct wl_pointer* pointer, uint32_t serial,
 291-                          struct wl_surface* surface)
 292-{
 293-	(void)data;
 294-	(void)pointer;
 295-	(void)serial;
 296-	(void)surface;
 297-}
 298-
 299-static void pointer_motion(void* data, struct wl_pointer* pointer, uint32_t time,
 300-                           wl_fixed_t sx, wl_fixed_t sy)
 301-{
 302-	Maus* mw = data;
 303-	MausBackend* be = &mw->backend;
 304-	int32_t x;
 305-	int32_t y;
 306-
 307-	(void)pointer;
 308-	(void)time;
 309-
 310-	if (be->relative_pointer)
 311-		return;
 312-
 313-	x = wl_fixed_to_int(sx);
 314-	y = wl_fixed_to_int(sy);
 315-
 316-	be->pending.pending = 1;
 317-	be->pending.type = MAUS_EV_MOUSE_MOTION;
 318-	be->pending.mouse_x = x;
 319-	be->pending.mouse_y = y;
 320-	be->pending.mouse_dx = be->mouse_pos_set ? x - be->mouse_x : 0;
 321-	be->pending.mouse_dy = be->mouse_pos_set ? y - be->mouse_y : 0;
 322-	be->mouse_x = x;
 323-	be->mouse_y = y;
 324-	be->mouse_pos_set = 1;
 325-	event_push_pending(mw);
 326-}
 327-
 328-static void pointer_button(void* data, struct wl_pointer* pointer, uint32_t serial,
 329-                           uint32_t time, uint32_t button, uint32_t state)
 330-{
 331-	Maus* mw = data;
 332-	MausMouseButton mb;
 333-
 334-	(void)pointer;
 335-	(void)serial;
 336-	(void)time;
 337-
 338-	mb = wl_button_to_maus(button);
 339-	mw->backend.pending.pending = 1;
 340-	mw->backend.pending.type = MAUS_EV_MOUSE_BUTTON;
 341-	mw->backend.pending.mouse_button = mb;
 342-	mw->backend.pending.mouse_pressed = state == WL_POINTER_BUTTON_STATE_PRESSED;
 343-
 344-	if (mb != MAUS_MOUSE_BUTTON_NONE)
 345-		mw->mouse_buttons[mb] = mw->backend.pending.mouse_pressed;
 346-	event_push_pending(mw);
 347-}
 348-
 349-static void pointer_axis(void* data, struct wl_pointer* pointer, uint32_t time,
 350-                         uint32_t axis, wl_fixed_t value)
 351-{
 352-	Maus* mw = data;
 353-
 354-	(void)pointer;
 355-	(void)time;
 356-
 357-	if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
 358-		return;
 359-
 360-	mw->backend.pending.pending = 1;
 361-	mw->backend.pending.type = MAUS_EV_MOUSE_BUTTON;
 362-	mw->backend.pending.mouse_button = wl_fixed_to_int(value) > 0
 363-		? MAUS_MOUSE_BUTTON_SCROLL_DOWN
 364-		: MAUS_MOUSE_BUTTON_SCROLL_UP;
 365-	mw->backend.pending.mouse_pressed = 1;
 366-	event_push_pending(mw);
 367-}
 368-
 369-static void pointer_frame(void* data, struct wl_pointer* pointer)
 370-{
 371-	(void)data;
 372-	(void)pointer;
 373-}
 374-
 375-static void pointer_axis_source(void* data, struct wl_pointer* pointer, uint32_t axis_source)
 376-{
 377-	(void)data;
 378-	(void)pointer;
 379-	(void)axis_source;
 380-}
 381-
 382-static void pointer_axis_stop(void* data, struct wl_pointer* pointer, uint32_t time, uint32_t axis) {
 383-	(void)data;
 384-	(void)pointer;
 385-	(void)time;
 386-	(void)axis;
 387-}
 388-
 389-static void pointer_axis_discrete(void* data, struct wl_pointer* pointer, uint32_t axis,
 390-                                  int32_t discrete)
 391-{
 392-	(void)data;
 393-	(void)pointer;
 394-	(void)axis;
 395-	(void)discrete;
 396-}
 397-
 398-static void pointer_axis_value120(void* data, struct wl_pointer* pointer, uint32_t axis,
 399-                                  int32_t value120)
 400-{
 401-	(void)data;
 402-	(void)pointer;
 403-	(void)axis;
 404-	(void)value120;
 405-}
 406-
 407-static void pointer_axis_relative_direction(void* data, struct wl_pointer* pointer,
 408-                                            uint32_t axis, uint32_t direction)
 409-{
 410-	(void)data;
 411-	(void)pointer;
 412-	(void)axis;
 413-	(void)direction;
 414-}
 415-
 416-static void relative_pointer_motion(void* data, struct zwp_relative_pointer_v1* relative_pointer,
 417-                                    uint32_t utime_hi, uint32_t utime_lo,
 418-                                    wl_fixed_t dx, wl_fixed_t dy,
 419-                                    wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel)
 420-{
 421-	Maus* mw = data;
 422-
 423-	(void)relative_pointer;
 424-	(void)utime_hi;
 425-	(void)utime_lo;
 426-	(void)dx_unaccel;
 427-	(void)dy_unaccel;
 428-
 429-	mw->backend.pending.pending = 1;
 430-	mw->backend.pending.type = MAUS_EV_MOUSE_MOTION;
 431-	mw->backend.pending.mouse_x = wl_fixed_to_int(dx);
 432-	mw->backend.pending.mouse_y = wl_fixed_to_int(dy);
 433-	mw->backend.pending.mouse_dx = wl_fixed_to_int(dx);
 434-	mw->backend.pending.mouse_dy = wl_fixed_to_int(dy);
 435-	event_push_pending(mw);
 436-}
 437-
 438-static void keyboard_keymap(void* data, struct wl_keyboard* keyboard, uint32_t format,
 439-                            int32_t fd, uint32_t size)
 440-{
 441-	Maus* mw = data;
 442-	MausBackend* be = &mw->backend;
 443-	char* map;
 444-
 445-	(void)keyboard;
 446-
 447-	if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
 448-		close(fd);
 449-		return;
 450-	}
 451-
 452-	map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 453-	if (map == MAP_FAILED) {
 454-		close(fd);
 455-		return;
 456-	}
 457-
 458-	if (be->xkb_state)
 459-		xkb_state_unref(be->xkb_state);
 460-	if (be->xkb_keymap)
 461-		xkb_keymap_unref(be->xkb_keymap);
 462-
 463-	be->xkb_keymap = xkb_keymap_new_from_string(
 464-		be->xkb_context, map,
 465-		XKB_KEYMAP_FORMAT_TEXT_V1,
 466-		XKB_KEYMAP_COMPILE_NO_FLAGS
 467-	);
 468-
 469-	munmap(map, size);
 470-	close(fd);
 471-
 472-	if (!be->xkb_keymap)
 473-		return;
 474-
 475-	be->xkb_state = xkb_state_new(be->xkb_keymap);
 476-}
 477-
 478-static void keyboard_enter(void* data, struct wl_keyboard* keyboard, uint32_t serial,
 479-                           struct wl_surface* surface, struct wl_array* keys)
 480-{
 481-	(void)data;
 482-	(void)keyboard;
 483-	(void)serial;
 484-	(void)surface;
 485-	(void)keys;
 486-}
 487-
 488-static void keyboard_leave(void* data, struct wl_keyboard* keyboard, uint32_t serial,
 489-                           struct wl_surface* surface)
 490-{
 491-	Maus* mw = data;
 492-
 493-	(void)keyboard;
 494-	(void)serial;
 495-	(void)surface;
 496-
 497-	mw->backend.repeat_key_code = 0;
 498-}
 499-
 500-static void keyboard_key(void* data, struct wl_keyboard* keyboard, uint32_t serial,
 501-                         uint32_t time, uint32_t key, uint32_t state)
 502-{
 503-	Maus* mw = data;
 504-	MausBackend* be = &mw->backend;
 505-	uint32_t code;
 506-	xkb_keysym_t sym;
 507-	MausKey maus_key;
 508-	char text[8];
 509-	int len;
 510-	uint8_t pressed;
 511-
 512-	(void)keyboard;
 513-	(void)serial;
 514-	(void)time;
 515-
 516-	code = key + 8;
 517-	sym = XKB_KEY_NoSymbol;
 518-	text[0] = 0;
 519-
 520-	if (be->xkb_state) {
 521-		sym = xkb_state_key_get_one_sym(be->xkb_state, code);
 522-		if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
 523-			len = xkb_state_key_get_utf8(be->xkb_state, code, text, sizeof(text));
 524-			if (len <= 0)
 525-				text[0] = 0;
 526-		}
 527-	}
 528-
 529-	maus_key = keysym_to_mauskey(sym);
 530-	if (maus_key == MAUS_KEY_ENTER)
 531-		text[0] = '\n';
 532-	pressed = state == WL_KEYBOARD_KEY_STATE_PRESSED;
 533-	event_push_key(mw, code, maus_key, text[0], pressed);
 534-
 535-	if (code < MAUS_KEYCODE_LAST)
 536-		mw->key_codes[code] = pressed;
 537-	if (maus_key != MAUS_KEY_NONE)
 538-		mw->key_syms[maus_key] = pressed;
 539-
 540-	if (!pressed) {
 541-		if (be->repeat_key_code == code)
 542-			be->repeat_key_code = 0;
 543-		return;
 544-	}
 545-
 546-	if (be->repeat_rate > 0 && be->xkb_keymap &&
 547-	    xkb_keymap_key_repeats(be->xkb_keymap, code)) {
 548-		be->repeat_key_code = code;
 549-		be->repeat_key_sym = maus_key;
 550-		be->repeat_key_text = text[0];
 551-		be->repeat_next_ns = maus_get_time_ns() + be->repeat_delay * 1000000;
 552-	}
 553-	else
 554-		be->repeat_key_code = 0;
 555-}
 556-
 557-static void keyboard_modifiers(void* data, struct wl_keyboard* keyboard, uint32_t serial,
 558-                               uint32_t mods_depressed, uint32_t mods_latched,
 559-                               uint32_t mods_locked, uint32_t group)
 560-{
 561-	Maus* mw = data;
 562-
 563-	(void)keyboard;
 564-	(void)serial;
 565-
 566-	if (!mw->backend.xkb_state)
 567-		return;
 568-
 569-	xkb_state_update_mask(
 570-		mw->backend.xkb_state, mods_depressed,
 571-		mods_latched, mods_locked,
 572-		0, 0, group
 573-	);
 574-}
 575-
 576-static void keyboard_repeat_info(void* data, struct wl_keyboard* keyboard,
 577-                                 int32_t rate, int32_t delay)
 578-{
 579-	Maus* mw = data;
 580-
 581-	(void)keyboard;
 582-
 583-	mw->backend.repeat_rate = rate;
 584-	mw->backend.repeat_delay = delay;
 585-	if (rate <= 0)
 586-		mw->backend.repeat_key_code = 0;
 587-}
 588-
 589-static int8_t repeat_push_due(Maus* mw)
 590-{
 591-	MausBackend* be = &mw->backend;
 592-	uint64_t now;
 593-	uint64_t interval;
 594-
 595-	if (be->repeat_key_code == 0 || be->repeat_rate <= 0)
 596-		return 0;
 597-
 598-	now = maus_get_time_ns();
 599-	if (now < be->repeat_next_ns)
 600-		return 0;
 601-
 602-	event_push_key(mw, be->repeat_key_code, be->repeat_key_sym, be->repeat_key_text, 1);
 603-	interval = 1000000000 / be->repeat_rate;
 604-	do {
 605-		be->repeat_next_ns += interval;
 606-	} while (be->repeat_next_ns <= now);
 607-
 608-	return 1;
 609-}
 610-
 611-static int32_t repeat_timeout_ms(Maus* mw)
 612-{
 613-	MausBackend* be = &mw->backend;
 614-	uint64_t now;
 615-	uint64_t diff;
 616-
 617-	if (be->repeat_key_code == 0 || be->repeat_rate <= 0)
 618-		return -1;
 619-
 620-	now = maus_get_time_ns();
 621-	if (now >= be->repeat_next_ns)
 622-		return 0;
 623-
 624-	diff = be->repeat_next_ns - now;
 625-	/* round xto nearest ms */
 626-	return (int32_t)((diff + 999999) / 1000000);
 627-}
 628-
 629-static int8_t display_read(Maus* mw, int timeout_ms)
 630-{
 631-	MausBackend* be = &mw->backend;
 632-	struct pollfd pfd;
 633-	int ret;
 634-
 635-	if (wl_display_prepare_read(be->display) != 0) {
 636-		wl_display_dispatch_pending(be->display);
 637-		return 1;
 638-	}
 639-
 640-	wl_display_flush(be->display);
 641-
 642-	pfd.fd = wl_display_get_fd(be->display);
 643-	pfd.events = POLLIN;
 644-	pfd.revents = 0;
 645-
 646-	ret = poll(&pfd, 1, timeout_ms);
 647-	if (ret > 0 && (pfd.revents & POLLIN)) {
 648-		if (wl_display_read_events(be->display) == -1) {
 649-			wl_display_cancel_read(be->display);
 650-			return -1;
 651-		}
 652-		wl_display_dispatch_pending(be->display);
 653-		return 1;
 654-	}
 655-
 656-	wl_display_cancel_read(be->display);
 657-	return 0;
 658-}
 659-
 660-
 661-static int8_t cursor_init(Maus* mw)
 662-{
 663-	MausBackend* be = &mw->backend;
 664-
 665-	be->cursor_theme = wl_cursor_theme_load(NULL, 24, be->shm);
 666-	if (!be->cursor_theme)
 667-		return 0;
 668-
 669-	be->cursor = wl_cursor_theme_get_cursor(be->cursor_theme, "left_ptr");
 670-	if (!be->cursor)
 671-		return 0;
 672-
 673-	be->cursor_surface = wl_compositor_create_surface(be->compositor);
 674-	if (!be->cursor_surface)
 675-		return 0;
 676-
 677-	return 1;
 678-}
 679-
 680-static void cursor_destroy(Maus* mw)
 681-{
 682-	MausBackend* be = &mw->backend;
 683-
 684-	if (be->cursor_surface)
 685-		wl_surface_destroy(be->cursor_surface);
 686-	if (be->cursor_theme)
 687-		wl_cursor_theme_destroy(be->cursor_theme);
 688-
 689-	be->cursor_surface = NULL;
 690-	be->cursor_theme = NULL;
 691-	be->cursor = NULL;
 692-}
 693-
 694-static void cursor_hide(Maus* mw)
 695-{
 696-	MausBackend* be = &mw->backend;
 697-
 698-	if (!be->pointer)
 699-		return;
 700-
 701-	wl_pointer_set_cursor(be->pointer, be->pointer_enter_serial, NULL, 0, 0);
 702-}
 703-
 704-static void cursor_lock(Maus* mw)
 705-{
 706-	MausBackend* be = &mw->backend;
 707-
 708-	if (be->locked_pointer)
 709-		return;
 710-	if (!be->pointer_constraints || !be->surface || !be->pointer)
 711-		return;
 712-
 713-	be->locked_pointer = zwp_pointer_constraints_v1_confine_pointer(
 714-		be->pointer_constraints, be->surface, be->pointer, NULL,
 715-		ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT
 716-	);
 717-}
 718-
 719-static void cursor_unlock(Maus* mw)
 720-{
 721-	MausBackend* be = &mw->backend;
 722-
 723-	if (be->locked_pointer) {
 724-		zwp_confined_pointer_v1_destroy(be->locked_pointer);
 725-		be->locked_pointer = NULL;
 726-	}
 727-
 728-	if (be->cursor_state == MAUS_CURSOR_STATE_VISIBLE)
 729-		cursor_show(mw);
 730-}
 731-
 732-static void cursor_show(Maus* mw)
 733-{
 734-	MausBackend* be = &mw->backend;
 735-	struct wl_cursor_image* image;
 736-	struct wl_buffer* buffer;
 737-
 738-	if (!be->pointer || !be->cursor || !be->cursor_surface)
 739-		return;
 740-
 741-	image = be->cursor->images[0];
 742-	buffer = wl_cursor_image_get_buffer(image);
 743-	if (!buffer)
 744-		return;
 745-
 746-	wl_pointer_set_cursor(
 747-		be->pointer, be->pointer_enter_serial,
 748-		be->cursor_surface, image->hotspot_x, image->hotspot_y
 749-	);
 750-	wl_surface_attach(be->cursor_surface, buffer, 0, 0);
 751-	wl_surface_damage_buffer(be->cursor_surface, 0, 0, image->width, image->height);
 752-	wl_surface_commit(be->cursor_surface);
 753-}
 754-
 755-static void cursor_relative(Maus* mw)
 756-{
 757-	MausBackend* be = &mw->backend;
 758-	if (be->relative_pointer)
 759-		return;
 760-	if (!be->relative_pointer_manager || !be->pointer)
 761-		return;
 762-
 763-	cursor_lock(mw);
 764-	be->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
 765-		be->relative_pointer_manager, be->pointer
 766-	);
 767-	zwp_relative_pointer_v1_add_listener(
 768-		be->relative_pointer, &relative_pointer_listener, mw
 769-	);
 770-}
 771-
 772-static void cursor_absolute(Maus* mw)
 773-{
 774-	MausBackend* be = &mw->backend;
 775-
 776-	if (be->relative_pointer) {
 777-		zwp_relative_pointer_v1_destroy(be->relative_pointer);
 778-		be->relative_pointer = NULL;
 779-	}
 780-
 781-	cursor_unlock(mw);
 782-}
 783-
 784-static int8_t fb_create(Maus* mw);
 785-static int8_t fb_create_buffer(Maus* mw, MausWLBuffer* wb);
 786-static int8_t fb_create_shm(size_t size);
 787-static void fb_destroy(Maus* mw);
 788-static int8_t handle_event(Maus* mw, MausEvent* ev);
 789-
 790-static int8_t fb_create(Maus* mw)
 791-{
 792-	MausBackend* be = &mw->backend;
 793-
 794-	if (!fb_create_buffer(mw, &be->buffers[0])) {
 795-		fb_destroy(mw);
 796-		return 0;
 797-	}
 798-	if (!fb_create_buffer(mw, &be->buffers[1])) {
 799-		fb_destroy(mw);
 800-		return 0;
 801-	}
 802-
 803-	mw->fb = be->buffers[0].data;
 804-	mw->stride = mw->width;
 805-	return 1;
 806-}
 807-
 808-static int8_t fb_create_buffer(Maus* mw, MausWLBuffer* wb)
 809-{
 810-	MausBackend* be = &mw->backend;
 811-	struct wl_shm_pool* pool;
 812-
 813-	int fd;
 814-	int stride;
 815-	int size;
 816-
 817-	stride = mw->width * 4;
 818-	size = stride * mw->height;
 819-
 820-	fd = fb_create_shm(size);
 821-	if (fd < 0)
 822-		return 0;
 823-
 824-	wb->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
 825-	if (wb->data == MAP_FAILED) {
 826-		wb->data = NULL;
 827-		close(fd);
 828-		return 0;
 829-	}
 830-
 831-	pool = wl_shm_create_pool(be->shm, fd, size);
 832-	wb->buffer = wl_shm_pool_create_buffer(
 833-		pool, 0, mw->width, mw->height,
 834-		stride, WL_SHM_FORMAT_XRGB8888
 835-	);
 836-
 837-	wl_shm_pool_destroy(pool);
 838-	close(fd);
 839-
 840-	if (!wb->buffer) {
 841-		munmap(wb->data, size);
 842-		wb->data = NULL;
 843-		return 0;
 844-	}
 845-
 846-	wl_buffer_add_listener(wb->buffer, &wl_buffer_listener, wb);
 847-	wb->size = size;
 848-	wb->busy = 0;
 849-
 850-	return 1;
 851-}
 852-
 853-static int8_t fb_create_shm(size_t size)
 854-{
 855-	char name[64];
 856-	int fd;
 857-
 858-	int i;
 859-
 860-	for (i = 0; i < 100; i++) {
 861-		snprintf(name, sizeof(name), "/maus-%ld-%d", (long)getpid(), i);
 862-
 863-		fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
 864-		if (fd >= 0) {
 865-			shm_unlink(name);
 866-
 867-			if (ftruncate(fd, size) < 0) {
 868-				close(fd);
 869-				return -1;
 870-			}
 871-
 872-			return fd;
 873-		}
 874-	}
 875-
 876-	return -1;
 877-}
 878-
 879-static void fb_destroy(Maus* mw)
 880-{
 881-	MausBackend* be = &mw->backend;
 882-
 883-	uint32_t i;
 884-
 885-	for (i = 0; i < 2; i++) {
 886-		if (be->buffers[i].buffer)
 887-			wl_buffer_destroy(be->buffers[i].buffer);
 888-
 889-		if (be->buffers[i].data && be->buffers[i].size > 0)
 890-			munmap(be->buffers[i].data, be->buffers[i].size);
 891-
 892-		be->buffers[i].buffer = NULL;
 893-		be->buffers[i].data = NULL;
 894-		be->buffers[i].size = 0;
 895-		be->buffers[i].busy = 0;
 896-	}
 897-	mw->fb = NULL;
 898-}
 899-
 900-static int8_t handle_event(Maus* mw, MausEvent* ev)
 901-{
 902-	MausEventPending pending;
 903-
 904-	if (!event_pop(mw, &pending))
 905-		return 0;
 906-
 907-	ev->type = pending.type;
 908-
 909-	switch (ev->type) {
 910-	case MAUS_EV_CLOSE:
 911-		return 1;
 912-
 913-	case MAUS_EV_RESIZE:
 914-		ev->resize.width = pending.width;
 915-		ev->resize.height = pending.height;
 916-		return 1;
 917-
 918-	case MAUS_EV_MOUSE_MOTION:
 919-		ev->mouse.motion.x = pending.mouse_x;
 920-		ev->mouse.motion.y = pending.mouse_y;
 921-		ev->mouse.motion.dx = pending.mouse_dx;
 922-		ev->mouse.motion.dy = pending.mouse_dy;
 923-		return 1;
 924-
 925-	case MAUS_EV_MOUSE_BUTTON:
 926-		ev->mouse.button.button = pending.mouse_button;
 927-		ev->mouse.button.pressed = pending.mouse_pressed;
 928-		return 1;
 929-
 930-	case MAUS_EV_KEY:
 931-		ev->key.code = pending.key_code;
 932-		ev->key.pressed = pending.key_pressed;
 933-		ev->key.key = pending.key_sym;
 934-		ev->key.text = pending.key_text;
 935-		return 1;
 936-
 937-	default:
 938-		return 1;
 939-	}
 940-}
 941-
 942-static MausMouseButton wl_button_to_maus(uint32_t button)
 943-{
 944-	switch (button) {
 945-		case 0x110: return MAUS_MOUSE_BUTTON_LEFT;
 946-		case 0x111: return MAUS_MOUSE_BUTTON_RIGHT;
 947-		case 0x112: return MAUS_MOUSE_BUTTON_MIDDLE;
 948-		default:    return MAUS_MOUSE_BUTTON_NONE;
 949-	}
 950-}
 951-
 952-static MausKey keysym_to_mauskey(xkb_keysym_t sym)
 953-{
 954-	if (sym >= 0x20 && sym <= 0x7E)
 955-		return (MausKey)sym;
 956-
 957-	if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F12)
 958-		return MAUS_KEY_F1 + (sym - XKB_KEY_F1);
 959-	if (sym >= XKB_KEY_KP_0 && sym <= XKB_KEY_KP_9)
 960-		return MAUS_KEY_KP_0 + (sym - XKB_KEY_KP_0);
 961-
 962-	switch (sym) {
 963-		case XKB_KEY_BackSpace:    return MAUS_KEY_BACKSPACE;
 964-		case XKB_KEY_Tab:          return MAUS_KEY_TAB;
 965-		case XKB_KEY_Return:       return MAUS_KEY_ENTER;
 966-		case XKB_KEY_Escape:       return MAUS_KEY_ESCAPE;
 967-		case XKB_KEY_Delete:       return MAUS_KEY_DELETE;
 968-		case XKB_KEY_Left:         return MAUS_KEY_LEFT;
 969-		case XKB_KEY_Right:        return MAUS_KEY_RIGHT;
 970-		case XKB_KEY_Up:           return MAUS_KEY_UP;
 971-		case XKB_KEY_Down:         return MAUS_KEY_DOWN;
 972-		case XKB_KEY_Home:         return MAUS_KEY_HOME;
 973-		case XKB_KEY_End:          return MAUS_KEY_END;
 974-		case XKB_KEY_Page_Up:      return MAUS_KEY_PAGE_UP;
 975-		case XKB_KEY_Page_Down:    return MAUS_KEY_PAGE_DOWN;
 976-		case XKB_KEY_Insert:       return MAUS_KEY_INSERT;
 977-		case XKB_KEY_Shift_L:      return MAUS_KEY_SHIFT_L;
 978-		case XKB_KEY_Shift_R:      return MAUS_KEY_SHIFT_R;
 979-		case XKB_KEY_Control_L:    return MAUS_KEY_CONTROL_L;
 980-		case XKB_KEY_Control_R:    return MAUS_KEY_CONTROL_R;
 981-		case XKB_KEY_Alt_L:        return MAUS_KEY_ALT_L;
 982-		case XKB_KEY_Alt_R:        return MAUS_KEY_ALT_R;
 983-		case XKB_KEY_Super_L:      return MAUS_KEY_SUPER_L;
 984-		case XKB_KEY_Super_R:      return MAUS_KEY_SUPER_R;
 985-		case XKB_KEY_Caps_Lock:    return MAUS_KEY_CAPS_LOCK;
 986-		case XKB_KEY_Num_Lock:     return MAUS_KEY_NUM_LOCK;
 987-		case XKB_KEY_Scroll_Lock:  return MAUS_KEY_SCROLL_LOCK;
 988-		case XKB_KEY_Print:        return MAUS_KEY_PRINT_SCREEN;
 989-		case XKB_KEY_Pause:        return MAUS_KEY_PAUSE;
 990-		case XKB_KEY_Menu:         return MAUS_KEY_MENU;
 991-		case XKB_KEY_KP_Decimal:   return MAUS_KEY_KP_DECIMAL;
 992-		case XKB_KEY_KP_Divide:    return MAUS_KEY_KP_DIVIDE;
 993-		case XKB_KEY_KP_Multiply:  return MAUS_KEY_KP_MULTIPLY;
 994-		case XKB_KEY_KP_Subtract:  return MAUS_KEY_KP_SUBTRACT;
 995-		case XKB_KEY_KP_Add:       return MAUS_KEY_KP_ADD;
 996-		case XKB_KEY_KP_Enter:     return MAUS_KEY_KP_ENTER;
 997-		case XKB_KEY_KP_Equal:     return MAUS_KEY_KP_EQUAL;
 998-		default:                   return MAUS_KEY_NONE;
 999-	}
1000-}
1001-
1002-void maus_clear(Maus* mw, MausColor col)
1003-{
1004-	uint32_t up = MAUS_UNPACK_COL(col);
1005-	uint32_t pxs = mw->height * mw->width;
1006-
1007-	uint32_t i;
1008-
1009-	for (i = 0; i < pxs; i++)
1010-		mw->bfb[i] = up;
1011-}
1012-
1013-/* TODO */
1014-void maus_clipboard_set_text(Maus* mw, const char* text)
1015-{
1016-	(void)mw;
1017-	(void)text;
1018-}
1019-
1020-/* TODO */
1021-char* maus_clipboard_get_text(Maus* mw)
1022-{
1023-	(void)mw;
1024-	return NULL;
1025-}
1026-
1027-void maus_close(Maus* mw)
1028-{
1029-	MausBackend* be;
1030-
1031-	if (!mw)
1032-		return;
1033-
1034-	be = &mw->backend;
1035-
1036-	fb_destroy(mw);
1037-	cursor_absolute(mw);
1038-
1039-	if (be->xdg_toplevel)
1040-		xdg_toplevel_destroy(be->xdg_toplevel);
1041-
1042-	if (be->xdg_surface)
1043-		xdg_surface_destroy(be->xdg_surface);
1044-
1045-	if (be->surface)
1046-		wl_surface_destroy(be->surface);
1047-
1048-	if (be->keyboard)
1049-		wl_keyboard_destroy(be->keyboard);
1050-
1051-	if (be->pointer)
1052-		wl_pointer_destroy(be->pointer);
1053-
1054-	if (be->seat)
1055-		wl_seat_destroy(be->seat);
1056-
1057-	if (be->pointer_constraints)
1058-		zwp_pointer_constraints_v1_destroy(be->pointer_constraints);
1059-
1060-	if (be->relative_pointer_manager)
1061-		zwp_relative_pointer_manager_v1_destroy(be->relative_pointer_manager);
1062-
1063-	if (be->xkb_state)
1064-		xkb_state_unref(be->xkb_state);
1065-
1066-	if (be->xkb_keymap)
1067-		xkb_keymap_unref(be->xkb_keymap);
1068-
1069-	if (be->xkb_context)
1070-		xkb_context_unref(be->xkb_context);
1071-
1072-	cursor_destroy(mw);
1073-
1074-	if (be->wm_base)
1075-		xdg_wm_base_destroy(be->wm_base);
1076-
1077-	if (be->shm)
1078-		wl_shm_destroy(be->shm);
1079-
1080-	if (be->compositor)
1081-		wl_compositor_destroy(be->compositor);
1082-
1083-	if (be->registry)
1084-		wl_registry_destroy(be->registry);
1085-
1086-	if (be->display) {
1087-		wl_display_flush(be->display);
1088-		wl_display_disconnect(be->display);
1089-	}
1090-
1091-	free(mw->bfb);
1092-	free(mw);
1093-}
1094-
1095-int8_t maus_close_window(Maus* mw)
1096-{
1097-	MausBackend* be = &mw->backend;
1098-
1099-	cursor_unlock(mw);
1100-	fb_destroy(mw);
1101-
1102-	if (be->xdg_toplevel)
1103-		xdg_toplevel_destroy(be->xdg_toplevel);
1104-	if (be->xdg_surface)
1105-		xdg_surface_destroy(be->xdg_surface);
1106-	if (be->surface)
1107-		wl_surface_destroy(be->surface);
1108-
1109-	be->xdg_toplevel = NULL;
1110-	be->xdg_surface = NULL;
1111-	be->surface = NULL;
1112-	be->configured = 0;
1113-
1114-	return 1;
1115-}
1116-
1117-int8_t maus_create_window(Maus* mw)
1118-{
1119-	MausBackend* be = &mw->backend;
1120-
1121-	be->surface = wl_compositor_create_surface(be->compositor);
1122-	if (!be->surface)
1123-		return 0;
1124-
1125-	be->xdg_surface = xdg_wm_base_get_xdg_surface(be->wm_base, be->surface);
1126-	if (!be->xdg_surface)
1127-		return 0;
1128-
1129-	xdg_surface_add_listener(be->xdg_surface, &xdg_surface_listener, mw);
1130-
1131-	be->xdg_toplevel = xdg_surface_get_toplevel(be->xdg_surface);
1132-	if (!be->xdg_toplevel)
1133-		return 0;
1134-
1135-	xdg_toplevel_add_listener(be->xdg_toplevel, &xdg_toplevel_listener, mw);
1136-	xdg_toplevel_set_title(be->xdg_toplevel, mw->title);
1137-
1138-	if (!fb_create(mw))
1139-		return 0;
1140-
1141-	wl_surface_commit(be->surface);
1142-
1143-	while (!be->configured) {
1144-		if (wl_display_dispatch(be->display) == -1)
1145-			return 0;
1146-	}
1147-
1148-	return 1;
1149-}
1150-
1151-Maus* maus_init(const char* title, int x, int y, int width, int height)
1152-{
1153-	Maus* mw = calloc(1, sizeof(Maus));
1154-	MausBackend* be = &mw->backend;
1155-
1156-	if (!mw)
1157-		return NULL;
1158-
1159-	be->display = wl_display_connect(NULL);
1160-	if (!be->display) {
1161-		free(mw);
1162-		return NULL;
1163-	}
1164-
1165-	be->registry = wl_display_get_registry(be->display);
1166-	wl_registry_add_listener(be->registry, &registry_listener, mw);
1167-	wl_display_roundtrip(be->display);
1168-
1169-	be->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
1170-	if (!be->xkb_context)
1171-		goto close;
1172-
1173-	if (!be->compositor || !be->shm || !be->wm_base) {
1174-		maus_close(mw);
1175-		free(mw);
1176-		return NULL;
1177-	}
1178-
1179-	if (!cursor_init(mw))
1180-		goto close;
1181-
1182-	mw->frame_time_last = maus_get_time_ns();
1183-	mw->title = title;
1184-	mw->x = x;
1185-	mw->y = y;
1186-	mw->width = width;
1187-	mw->height = height;
1188-	mw->stride = width;
1189-	be->cursor_state = MAUS_CURSOR_STATE_VISIBLE;
1190-
1191-	mw->bfb = calloc(mw->stride * mw->height, sizeof(uint32_t));
1192-	if (!mw->bfb)
1193-		goto close;
1194-
1195-	return mw;
1196-close:
1197-	maus_close(mw);
1198-	free(mw);
1199-	return NULL;
1200-}
1201-
1202-int8_t maus_event_poll(Maus* mw, MausEvent* ev)
1203-{
1204-	MausBackend* be = &mw->backend;
1205-	int8_t read;
1206-
1207-	ev->type = MAUS_EV_NONE;
1208-
1209-	if (repeat_push_due(mw) && handle_event(mw, ev))
1210-		return 1;
1211-
1212-	if (handle_event(mw, ev))
1213-		return 1;
1214-
1215-	wl_display_dispatch_pending(be->display);
1216-	if (handle_event(mw, ev))
1217-		return 1;
1218-
1219-	read = display_read(mw, 0);
1220-	if (read == -1) {
1221-		ev->type = MAUS_EV_CLOSE;
1222-		return 1;
1223-	}
1224-	if (read == 0)
1225-		return 0;
1226-	if (repeat_push_due(mw) && handle_event(mw, ev))
1227-		return 1;
1228-
1229-	return handle_event(mw, ev);
1230-}
1231-
1232-void maus_event_wait(Maus* mw, MausEvent* ev)
1233-{
1234-	MausBackend* be = &mw->backend;
1235-	int32_t timeout;
1236-	int8_t read;
1237-
1238-	ev->type = MAUS_EV_NONE;
1239-
1240-	for (;;) {
1241-		if (repeat_push_due(mw) && handle_event(mw, ev))
1242-			return;
1243-
1244-		if (handle_event(mw, ev))
1245-			return;
1246-
1247-		timeout = repeat_timeout_ms(mw);
1248-		if (timeout >= 0) {
1249-			read = display_read(mw, timeout);
1250-			if (read == -1) {
1251-				ev->type = MAUS_EV_CLOSE;
1252-				return;
1253-			}
1254-			continue;
1255-		}
1256-
1257-		if (wl_display_dispatch(be->display) == -1) {
1258-			ev->type = MAUS_EV_CLOSE;
1259-			return;
1260-		}
1261-	}
1262-}
1263-
1264-void maus_present(Maus* mw)
1265-{
1266-	MausBackend* be = &mw->backend;
1267-	MausWLBuffer* wb = NULL;
1268-	size_t bytes;
1269-
1270-	uint32_t i;
1271-
1272-	for (i = 0; i < 2; i++) {
1273-		if (be->buffers[i].buffer && !be->buffers[i].busy) {
1274-			wb = &be->buffers[i];
1275-			break;
1276-		}
1277-	}
1278-
1279-	if (!wb)
1280-		return;
1281-
1282-	bytes = mw->stride * mw->height * sizeof(uint32_t);
1283-	memcpy(wb->data, mw->bfb, bytes);
1284-	mw->fb = wb->data;
1285-	wb->busy = 1;
1286-
1287-	wl_surface_attach(be->surface, wb->buffer, 0, 0);
1288-	wl_surface_damage_buffer(be->surface, 0, 0, mw->width, mw->height);
1289-	wl_surface_commit(be->surface);
1290-	wl_display_flush(be->display);
1291-}
1292-
1293-int8_t maus_resize(Maus* mw, uint32_t width, uint32_t height)
1294-{
1295-	uint32_t* bfb;
1296-
1297-	if (width == 0 || height == 0)
1298-		return 0;
1299-
1300-	bfb = calloc(width * height, sizeof(uint32_t));
1301-	if (!bfb)
1302-		return 0;
1303-
1304-	fb_destroy(mw);
1305-	free(mw->bfb);
1306-
1307-	mw->width = width;
1308-	mw->height = height;
1309-	mw->stride = width;
1310-	mw->bfb = bfb;
1311-
1312-	if (!fb_create(mw)) {
1313-		free(mw->bfb);
1314-		mw->bfb = NULL;
1315-		return 0;
1316-	}
1317-
1318-	return 1;
1319-}
1320-
1321-void maus_cur_set_mode(Maus* mw, MausCursorState state)
1322-{
1323-	switch (state) {
1324-	case MAUS_CURSOR_STATE_VISIBLE:
1325-		cursor_show(mw);
1326-		mw->backend.cursor_state = state;
1327-		break;
1328-	case MAUS_CURSOR_STATE_HIDDEN:
1329-		cursor_hide(mw);
1330-		mw->backend.cursor_state = state;
1331-		break;
1332-	case MAUS_CURSOR_STATE_LOCKED:
1333-		mw->backend.cursor_state = state;
1334-		cursor_lock(mw);
1335-		break;
1336-	case MAUS_CURSOR_STATE_FREE:
1337-		cursor_unlock(mw);
1338-		mw->backend.cursor_state = state;
1339-		break;
1340-	case MAUS_CURSOR_STATE_RELATIVE:
1341-		cursor_relative(mw);
1342-		mw->backend.cursor_state = state;
1343-		break;
1344-	case MAUS_CURSOR_STATE_ABSOLUTE:
1345-		cursor_absolute(mw);
1346-		mw->backend.cursor_state = state;
1347-		break;
1348-	default:
1349-		break;
1350-	}
1351-}
1352-
+0, -587
  1@@ -1,587 +0,0 @@
  2-#include <windows.h>
  3-#include <windowsx.h>
  4-
  5-#include "maus.h"
  6-#include "maus_input.h"
  7-#include "maus_win.h"
  8-
  9-typedef struct {
 10-	UINT    vk;
 11-	MausKey maus;
 12-} KeyMapEntry;
 13-
 14-static int8_t fb_create(Maus* mw);
 15-static void fb_destroy(Maus* mw);
 16-static int8_t handle_event(const MSG* msg, MausEvent* ev, Maus* mw);
 17-static MausKey vk_to_mauskey(UINT vk);
 18-static UINT resolve_lr(UINT vk, LPARAM lparam);
 19-static char translate_text(UINT vk, UINT scan);
 20-static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
 21-
 22-static const KeyMapEntry keymap[] = {
 23-	{ VK_BACK,     MAUS_KEY_BACKSPACE }, { VK_TAB,      MAUS_KEY_TAB },
 24-	{ VK_RETURN,   MAUS_KEY_ENTER },     { VK_ESCAPE,   MAUS_KEY_ESCAPE },
 25-	{ VK_SPACE,    MAUS_KEY_SPACE },     { VK_DELETE,   MAUS_KEY_DELETE },
 26-	{ VK_LEFT,     MAUS_KEY_LEFT },      { VK_RIGHT,    MAUS_KEY_RIGHT },
 27-	{ VK_UP,       MAUS_KEY_UP },        { VK_DOWN,     MAUS_KEY_DOWN },
 28-	{ VK_HOME,     MAUS_KEY_HOME },      { VK_END,      MAUS_KEY_END },
 29-	{ VK_PRIOR,    MAUS_KEY_PAGE_UP },   { VK_NEXT,     MAUS_KEY_PAGE_DOWN },
 30-	{ VK_INSERT,   MAUS_KEY_INSERT },    { VK_CAPITAL,  MAUS_KEY_CAPS_LOCK },
 31-	{ VK_NUMLOCK,  MAUS_KEY_NUM_LOCK },  { VK_SCROLL,   MAUS_KEY_SCROLL_LOCK },
 32-	{ VK_PAUSE,    MAUS_KEY_PAUSE },     { VK_SNAPSHOT, MAUS_KEY_PRINT_SCREEN },
 33-	{ VK_APPS,     MAUS_KEY_MENU },      { VK_LSHIFT,   MAUS_KEY_SHIFT_L },
 34-	{ VK_RSHIFT,   MAUS_KEY_SHIFT_R },   { VK_LCONTROL, MAUS_KEY_CONTROL_L },
 35-	{ VK_RCONTROL, MAUS_KEY_CONTROL_R }, { VK_LMENU,    MAUS_KEY_ALT_L },
 36-	{ VK_RMENU,    MAUS_KEY_ALT_R },     { VK_LWIN,     MAUS_KEY_SUPER_L },
 37-	{ VK_RWIN,     MAUS_KEY_SUPER_R },   { VK_ADD,      MAUS_KEY_KP_ADD },
 38-	{ VK_SUBTRACT, MAUS_KEY_KP_SUBTRACT },{ VK_MULTIPLY, MAUS_KEY_KP_MULTIPLY },
 39-	{ VK_DIVIDE,   MAUS_KEY_KP_DIVIDE }, { VK_DECIMAL,  MAUS_KEY_KP_DECIMAL },
 40-};
 41-
 42-static int8_t fb_create(Maus* mw)
 43-{
 44-	MausBackend* be = &mw->backend;
 45-	BITMAPINFO bmi = {0};
 46-	HDC dc = GetDC(NULL);
 47-
 48-	be->hbm = NULL;
 49-	mw->fb = NULL;
 50-	mw->stride = 0;
 51-
 52-	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 53-	bmi.bmiHeader.biWidth = mw->width;
 54-	bmi.bmiHeader.biHeight = -mw->height;
 55-	bmi.bmiHeader.biPlanes = 1;
 56-	bmi.bmiHeader.biBitCount = 32;
 57-	bmi.bmiHeader.biCompression = BI_RGB;
 58-
 59-	be->memdc = CreateCompatibleDC(dc);
 60-	be->hbm = CreateDIBSection(dc, &bmi, DIB_RGB_COLORS, (void**)&mw->fb, NULL, 0);
 61-	ReleaseDC(NULL, dc);
 62-
 63-	if (!be->hbm || !mw->fb) {
 64-		if (be->memdc)
 65-			DeleteDC(be->memdc);
 66-		maus_log(stderr, "CreateDIBSection failed");
 67-		return 0;
 68-	}
 69-
 70-	SelectObject(be->memdc, be->hbm);
 71-
 72-	mw->stride = mw->width;
 73-	return 1;
 74-}
 75-
 76-static void fb_destroy(Maus* mw)
 77-{
 78-	MausBackend* be = &mw->backend;
 79-
 80-	if (be->memdc) {
 81-		DeleteDC(be->memdc);
 82-		be->memdc = NULL;
 83-	}
 84-	if (be->hbm) {
 85-		DeleteObject(be->hbm);
 86-		be->hbm = NULL;
 87-	}
 88-
 89-	mw->fb = NULL;
 90-	mw->stride = 0;
 91-}
 92-
 93-static int8_t handle_event(const MSG* msg, MausEvent* ev, Maus* mw)
 94-{
 95-	UINT scan;
 96-	UINT vk;
 97-	int delta;
 98-	MausMouseButton mbtype;
 99-
100-	switch (msg->message) {
101-		case WM_QUIT:
102-			ev->type = MAUS_EV_CLOSE;
103-			return 1;
104-
105-		case WM_MOUSEMOVE:
106-			ev->type = MAUS_EV_MOUSE_MOTION;
107-			ev->mouse.motion.x = GET_X_LPARAM(msg->lParam);
108-			ev->mouse.motion.y = GET_Y_LPARAM(msg->lParam);
109-			return 1;
110-
111-		case WM_LBUTTONDOWN:
112-			ev->type = MAUS_EV_MOUSE_BUTTON;
113-			ev->mouse.button.button = MAUS_MOUSE_BUTTON_LEFT;
114-			ev->mouse.button.pressed = 1;
115-			mw->mouse_buttons[MAUS_MOUSE_BUTTON_LEFT] = 1;
116-			return 1;
117-		case WM_LBUTTONUP:
118-			ev->type = MAUS_EV_MOUSE_BUTTON;
119-			ev->mouse.button.button = MAUS_MOUSE_BUTTON_LEFT;
120-			ev->mouse.button.pressed = 0;
121-			mw->mouse_buttons[MAUS_MOUSE_BUTTON_LEFT] = 0;
122-			return 1;
123-
124-		case WM_RBUTTONDOWN:
125-			ev->type = MAUS_EV_MOUSE_BUTTON;
126-			ev->mouse.button.button = MAUS_MOUSE_BUTTON_RIGHT;
127-			ev->mouse.button.pressed = 1;
128-			mw->mouse_buttons[MAUS_MOUSE_BUTTON_RIGHT] = 1;
129-			return 1;
130-		case WM_RBUTTONUP:
131-			ev->type = MAUS_EV_MOUSE_BUTTON;
132-			ev->mouse.button.button = MAUS_MOUSE_BUTTON_RIGHT;
133-			ev->mouse.button.pressed = 0;
134-			mw->mouse_buttons[MAUS_MOUSE_BUTTON_RIGHT] = 0;
135-			return 1;
136-
137-		case WM_MBUTTONDOWN:
138-			ev->type = MAUS_EV_MOUSE_BUTTON;
139-			ev->mouse.button.button = MAUS_MOUSE_BUTTON_MIDDLE;
140-			ev->mouse.button.pressed = 1;
141-			mw->mouse_buttons[MAUS_MOUSE_BUTTON_MIDDLE] = 1;
142-			return 1;
143-		case WM_MBUTTONUP:
144-			ev->type = MAUS_EV_MOUSE_BUTTON;
145-			ev->mouse.button.button = MAUS_MOUSE_BUTTON_MIDDLE;
146-			ev->mouse.button.pressed = 0;
147-			mw->mouse_buttons[MAUS_MOUSE_BUTTON_MIDDLE] = 0;
148-			return 1;
149-
150-		case WM_MOUSEWHEEL:
151-			delta = GET_WHEEL_DELTA_WPARAM(msg->wParam);
152-			mbtype = (delta > 0) ? MAUS_MOUSE_BUTTON_SCROLL_UP
153-			                     : MAUS_MOUSE_BUTTON_SCROLL_DOWN;
154-			ev->type = MAUS_EV_MOUSE_BUTTON;
155-			ev->mouse.button.button = mbtype;
156-			ev->mouse.button.pressed = 1;
157-			return 1;
158-
159-		case WM_KEYDOWN:
160-		case WM_SYSKEYDOWN:
161-			scan = (UINT)((msg->lParam >> 16) & 0xFF);
162-			vk = resolve_lr((UINT)msg->wParam, msg->lParam);
163-
164-			ev->type = MAUS_EV_KEY;
165-			ev->key.code = (uint32_t)msg->wParam;
166-			ev->key.pressed = 1;
167-			ev->key.key = vk_to_mauskey(vk);
168-			ev->key.text = translate_text((UINT)msg->wParam, scan);
169-
170-			if (ev->key.code < MAUS_KEYCODE_LAST)
171-				mw->key_codes[ev->key.code] = 1;
172-			if (ev->key.key != MAUS_KEY_NONE)
173-				mw->key_syms[ev->key.key] = 1;
174-			return 1;
175-
176-		case WM_KEYUP:
177-		case WM_SYSKEYUP:
178-			vk = resolve_lr((UINT)msg->wParam, msg->lParam);
179-
180-			ev->type = MAUS_EV_KEY;
181-			ev->key.code = (uint32_t)msg->wParam;
182-			ev->key.pressed = 0;
183-			ev->key.key = vk_to_mauskey(vk);
184-			ev->key.text = 0;
185-
186-			if (ev->key.code < MAUS_KEYCODE_LAST)
187-				mw->key_codes[ev->key.code] = 0;
188-			if (ev->key.key != MAUS_KEY_NONE)
189-				mw->key_syms[ev->key.key] = 0;
190-			return 1;
191-	}
192-
193-	return 0;
194-}
195-
196-static MausKey vk_to_mauskey(UINT vk)
197-{
198-	if (vk >= 'A' && vk <= 'Z')
199-		return (MausKey)(MAUS_KEY_A + (vk - 'A'));
200-	if (vk >= '0' && vk <= '9')
201-		return (MausKey)(MAUS_KEY_0 + (vk - '0'));
202-	if (vk >= VK_F1 && vk <= VK_F12)
203-		return (MausKey)(MAUS_KEY_F1 + (vk - VK_F1));
204-	if (vk >= VK_NUMPAD0 && vk <= VK_NUMPAD9)
205-		return (MausKey)(MAUS_KEY_KP_0 + (vk - VK_NUMPAD0));
206-
207-	for (size_t i = 0; i < sizeof(keymap) / sizeof(keymap[0]); i++) {
208-		if (keymap[i].vk == vk)
209-			return keymap[i].maus;
210-	}
211-
212-	return MAUS_KEY_NONE;
213-}
214-
215-static UINT resolve_lr(UINT vk, LPARAM lparam)
216-{
217-	UINT scan = (UINT)((lparam >> 16) & 0xFF);
218-	int  ext  = (lparam & (1 << 24)) != 0;
219-
220-	if (vk == VK_SHIFT)
221-		return MapVirtualKey(scan, MAPVK_VSC_TO_VK_EX);
222-	if (vk == VK_CONTROL)
223-		return ext ? VK_RCONTROL : VK_LCONTROL;
224-	if (vk == VK_MENU)
225-		return ext ? VK_RMENU : VK_LMENU;
226-
227-	return vk;
228-}
229-
230-static char translate_text(UINT vk, UINT scan)
231-{
232-	BYTE state[256];
233-	WCHAR buf[4];
234-	int n;
235-
236-	n = ToUnicode(vk, scan, state, buf, 4, 0);
237-
238-	if (!GetKeyboardState(state))
239-		return 0;
240-	if (n == 1 && buf[0] < 0x80)
241-		return (buf[0] == '\r') ? '\n' : (char)buf[0];
242-
243-	return 0;
244-}
245-
246-static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
247-{
248-	Maus* mw;
249-	MausBackend* be;
250-
251-	if (msg == WM_DESTROY) {
252-		PostQuitMessage(EXIT_SUCCESS);
253-		return 0;
254-	}
255-
256-	if (msg == WM_SIZE) {
257-		mw = (Maus*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
258-		if (mw) {
259-			be = &mw->backend;
260-			be->resized = 1;
261-			be->rw = LOWORD(lp);
262-			be->rh = HIWORD(lp);
263-		}
264-		return 0;
265-	}
266-
267-	return DefWindowProc(hwnd, msg, wp, lp);
268-}
269-
270-void maus_clear(Maus* mw, MausColor col)
271-{
272-	uint32_t col_up = MAUS_UNPACK_COL(col);
273-	uint32_t pxs = mw->height * mw->width;
274-	uint32_t i;
275-
276-	for (i = 0; i < pxs; i++)
277-		mw->bfb[i] = col_up;
278-}
279-
280-void maus_clipboard_set_text(Maus* mw, const char* text)
281-{
282-	MausBackend* be = &mw->backend;
283-	size_t len = strlen(text) + 1;
284-	HGLOBAL hmem;
285-
286-	void* ptr;
287-
288-	if (!text || !OpenClipboard(be->hwnd))
289-		return;
290-
291-	EmptyClipboard();
292-	hmem = GlobalAlloc(GMEM_MOVEABLE, len);
293-	if (hmem) {
294-		ptr = GlobalLock(hmem);
295-		if (ptr) {
296-			memcpy(ptr, text, len);
297-			GlobalUnlock(hmem);
298-
299-			if (!SetClipboardData(CF_TEXT, hmem))
300-				GlobalFree(hmem); /* failed */
301-		}
302-		else {
303-			GlobalFree(hmem);
304-		}
305-	}
306-
307-	CloseClipboard();
308-}
309-
310-char* maus_clipboard_get_text(Maus* mw)
311-{
312-	MausBackend* be = &mw->backend;
313-	HANDLE hmem;
314-
315-	const char* text;
316-	size_t len;
317-
318-	if (!OpenClipboard(be->hwnd))
319-		return NULL;
320-
321-	hmem = GetClipboardData(CF_TEXT);
322-	if (!hmem) {
323-		CloseClipboard();
324-		return NULL;
325-	}
326-
327-	text = GlobalLock(hmem);
328-	if (text) {
329-		if (mw->clipboard) {
330-			free(mw->clipboard);
331-			mw->clipboard = NULL;
332-		}
333-
334-		len = strlen(text) + 1;
335-		mw->clipboard = malloc(len);
336-		if (mw->clipboard)
337-			memcpy(mw->clipboard, text, len);
338-
339-		GlobalUnlock(hmem);
340-	}
341-
342-	CloseClipboard();
343-	return mw->clipboard;
344-}
345-
346-void maus_close(Maus* mw)
347-{
348-	MausBackend* be = &mw->backend;
349-
350-	fb_destroy(mw);
351-	if (mw->bfb) {
352-		free(mw->bfb);
353-		mw->bfb = NULL;
354-	}
355-	if (mw->clipboard) {
356-		free(mw->clipboard);
357-		mw->clipboard = NULL;
358-	}
359-	if (be->hwnd)
360-		(void) maus_close_window(mw);
361-}
362-
363-int8_t maus_close_window(Maus* mw)
364-{
365-	MausBackend* be = &mw->backend;
366-
367-	if (be->hwnd) {
368-		DestroyWindow(be->hwnd);
369-		be->hwnd = NULL;
370-		return 1;
371-	}
372-
373-	return 0;
374-}
375-
376-
377-int8_t maus_create_window(Maus* mw)
378-{
379-	MausBackend* be = &mw->backend;
380-	be->hInst = GetModuleHandle(NULL);
381-	WNDCLASS wc = {0};
382-
383-	RECT r = { 0, 0, mw->width, mw->height };
384-
385-	wc.lpfnWndProc = WndProc;
386-	wc.hInstance = be->hInst;
387-	wc.lpszClassName = "MausWindow";
388-	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
389-	if (!RegisterClass(&wc))
390-		return 0;
391-
392-	AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE);
393-
394-	be->hwnd = CreateWindowEx(
395-		0, "MausWindow", mw->title,
396-		WS_OVERLAPPEDWINDOW, mw->x, mw->y,
397-		r.right - r.left, r.bottom - r.top,
398-		NULL, NULL, be->hInst, NULL
399-	);
400-
401-	if (!be->hwnd)
402-		return 0;
403-
404-	SetWindowLongPtr(be->hwnd, GWLP_USERDATA, (LONG_PTR)mw);
405-	ShowWindow(be->hwnd, SW_SHOW);
406-	UpdateWindow(be->hwnd);
407-	return 1;
408-}
409-
410-Maus* maus_init(const char* title, int x, int y, int width, int height)
411-{
412-	Maus* mw = calloc(1, sizeof(Maus));
413-	MausBackend* be = &mw->backend;
414-
415-	mw->frame_time_last = maus_get_time_ns();
416-	mw->title = title;
417-	mw->width = width;
418-	mw->height = height;
419-	mw->x = x;
420-	mw->y = y;
421-	be->hInst = GetModuleHandle(NULL);
422-	be->hwnd = NULL;
423-	be->hbm = NULL;
424-
425-	if (!fb_create(mw)) {
426-		maus_log(stderr, "failed to create framebuffer");
427-		free(mw);
428-		return NULL;
429-	}
430-
431-	mw->bfb = calloc(mw->stride * mw->height, sizeof(uint32_t));
432-	if (!mw->bfb) {
433-		maus_log(stderr, "failed to allocate back buffer");
434-		maus_close(mw);
435-		free(mw);
436-		return NULL;
437-	}
438-
439-	return mw;
440-}
441-
442-int8_t maus_event_poll(Maus* mw, MausEvent* ev)
443-{
444-	MausBackend* be = &mw->backend;
445-	MSG msg;
446-
447-	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
448-		TranslateMessage(&msg);
449-		DispatchMessage(&msg);
450-		ev->type = MAUS_EV_NONE;
451-
452-		if (handle_event(&msg, ev, mw))
453-			return 1;
454-	}
455-
456-	/* WM_SIZE doesnt is handled separately */
457-	if (be->resized) {
458-		be->resized = 0;
459-		ev->type = MAUS_EV_RESIZE;
460-		ev->resize.width = be->rw;
461-		ev->resize.height = be->rh;
462-		return 1;
463-	}
464-
465-	return 0;
466-}
467-
468-void maus_event_wait(Maus* mw, MausEvent* ev)
469-{
470-	MausBackend* be = &mw->backend;
471-	MSG msg;
472-
473-	int r;
474-
475-	for (;;) {
476-		r = GetMessage(&msg, NULL, 0, 0);
477-		if (r <= 0) {
478-			ev->type = MAUS_EV_CLOSE;
479-			return;
480-		}
481-
482-		TranslateMessage(&msg);
483-		DispatchMessage(&msg);
484-		ev->type = MAUS_EV_NONE;
485-
486-		/* WM_SIZE doesnt is handled separately */
487-                if (be->resized) {
488-			be->resized = 0;
489-			ev->type = MAUS_EV_RESIZE;
490-			ev->resize.width = be->rw;
491-			ev->resize.height = be->rh;
492-			return;
493-		}
494-
495-		if (handle_event(&msg, ev, mw))
496-			return;
497-	}
498-}
499-
500-void maus_present(Maus* mw)
501-{
502-	MausBackend* be = &mw->backend;
503-	HDC wdc;
504-
505-	uint32_t bytes;
506-
507-	if (!be->hwnd || !be->memdc)
508-		return;
509-
510-	wdc = GetDC(be->hwnd);
511-
512-	bytes = mw->stride * mw->height * sizeof(uint32_t);
513-	memcpy(mw->fb, mw->bfb, bytes);
514-
515-	BitBlt(wdc, 0, 0, mw->width, mw->height, be->memdc, 0, 0, SRCCOPY);
516-	ReleaseDC(be->hwnd, wdc);
517-}
518-
519-int8_t maus_resize(Maus* mw, uint32_t width, uint32_t height)
520-{
521-	if (width == 0 || height == 0 ||
522-	   (mw->width == width && mw->height == height))
523-		return 0;
524-
525-	fb_destroy(mw);
526-	if (mw->bfb) {
527-		free(mw->bfb);
528-		mw->bfb = NULL;
529-	}
530-
531-	mw->width = width;
532-	mw->height = height;
533-
534-	if (!fb_create(mw))
535-		return 0;
536-
537-	mw->bfb = calloc(mw->stride * mw->height, sizeof(uint32_t));
538-	if (!mw->bfb)
539-		return 0;
540-
541-	return 1;
542-}
543-
544-void maus_cur_set_mode(Maus* mw, MausCursorState state)
545-{
546-	MausBackend* be = &mw->backend;
547-	HWND hwnd = be->hwnd;
548-
549-	RECT r;
550-
551-	if (!hwnd) {
552-		maus_log(stderr, "hwnd is NULL");
553-		return;
554-	}
555-
556-	/* show cursor */
557-	if (state == MAUS_CURSOR_STATE_VISIBLE) {
558-		while (ShowCursor(TRUE) < 0);
559-		return;
560-	}
561-
562-	/* hide cursor */
563-	if (state == MAUS_CURSOR_STATE_HIDDEN) {
564-		while (ShowCursor(FALSE) >= 0);
565-		return;
566-	}
567-
568-
569-	/* lock cursor */
570-	if (state == MAUS_CURSOR_STATE_LOCKED) {
571-		GetClientRect(hwnd, &r);
572-		MapWindowPoints(hwnd, NULL, (POINT*)&r, 2);
573-
574-		if (!ClipCursor(&r)) {
575-			maus_log(stderr, "failed to grab mouse pointer");
576-			return;
577-		}
578-
579-		return;
580-	}
581-
582-	/* unlock cursor */
583-	if (state == MAUS_CURSOR_STATE_FREE) {
584-		ClipCursor(NULL);
585-		return;
586-	}
587-}
588-
+0, -806
  1@@ -1,806 +0,0 @@
  2-#include <limits.h>
  3-#include <stdlib.h>
  4-#include <string.h>
  5-#include <sys/shm.h>
  6-#include <sys/ipc.h>
  7-
  8-#include <X11/Xlib.h>
  9-#include <X11/Xutil.h>
 10-#include <X11/keysym.h>
 11-#include <X11/cursorfont.h>
 12-#include <X11/extensions/XShm.h>
 13-
 14-#include "maus.h"
 15-#include "maus_input.h"
 16-#include "maus_x11.h"
 17-#include "utils.h"
 18-
 19-typedef struct {
 20-	KeySym  x11;
 21-	MausKey maus;
 22-} KeyMapEntry;
 23-
 24-static int8_t fb_create(Maus* mw);
 25-static int8_t fb_create_shm(Maus* mw);
 26-/* TODO static int8_t fb_create_ximage(Maus* mw); */
 27-static void fb_destroy(Maus* mw);
 28-static int8_t handle_event(XEvent* xev, MausEvent* ev, Maus* mw);
 29-static MausKey keysym_to_mauskey(KeySym sym);
 30-static MausMouseButton mouse_button_to_maus(int btn);
 31-static int xerr(Display* dpy, XErrorEvent* ev);
 32-
 33-static const KeyMapEntry keymap[] = {
 34-	{ XK_BackSpace,    MAUS_KEY_BACKSPACE }, { XK_Tab,              MAUS_KEY_TAB },
 35-	{ XK_Return,       MAUS_KEY_ENTER },     { XK_Escape,           MAUS_KEY_ESCAPE },
 36-	{ XK_apostrophe,   MAUS_KEY_APOSTROPHE },{ XK_comma,            MAUS_KEY_COMMA },
 37-	{ XK_space,        MAUS_KEY_SPACE },     { XK_minus,            MAUS_KEY_MINUS },
 38-	{ XK_period,       MAUS_KEY_PERIOD },    { XK_slash,            MAUS_KEY_SLASH },
 39-	{ XK_semicolon,    MAUS_KEY_SEMICOLON }, { XK_equal,            MAUS_KEY_EQUAL },
 40-	{ XK_Delete,       MAUS_KEY_DELETE },    { XK_Left,             MAUS_KEY_LEFT },
 41-	{ XK_Right,        MAUS_KEY_RIGHT },     { XK_Up,               MAUS_KEY_UP },
 42-	{ XK_Down,         MAUS_KEY_DOWN },      { XK_Home,             MAUS_KEY_HOME },
 43-	{ XK_End,          MAUS_KEY_END },       { XK_Page_Up,          MAUS_KEY_PAGE_UP },
 44-	{ XK_Page_Down,    MAUS_KEY_PAGE_DOWN }, { XK_Insert,           MAUS_KEY_INSERT },
 45-	{ XK_Shift_L,      MAUS_KEY_SHIFT_L },   { XK_Shift_R,          MAUS_KEY_SHIFT_R },
 46-	{ XK_Control_L,    MAUS_KEY_CONTROL_L }, { XK_Control_R,        MAUS_KEY_CONTROL_R },
 47-	{ XK_Alt_L,        MAUS_KEY_ALT_L },     { XK_Alt_R,            MAUS_KEY_ALT_R },
 48-	{ XK_Super_L,      MAUS_KEY_SUPER_L },   { XK_Super_R,          MAUS_KEY_SUPER_R },
 49-	{ XK_Caps_Lock,    MAUS_KEY_CAPS_LOCK }, { XK_Num_Lock,         MAUS_KEY_NUM_LOCK },
 50-	{ XK_Pause,        MAUS_KEY_PAUSE },     { XK_Menu,             MAUS_KEY_MENU },
 51-	{ XK_KP_Add,       MAUS_KEY_KP_ADD },    { XK_KP_Enter,         MAUS_KEY_KP_ENTER },
 52-	{ XK_bracketright, MAUS_KEY_RIGHT_BRACKET }, { XK_grave,        MAUS_KEY_GRAVE },
 53-	{ XK_Scroll_Lock,  MAUS_KEY_SCROLL_LOCK },   { XK_Print,        MAUS_KEY_PRINT_SCREEN },
 54-	{ XK_KP_Decimal,   MAUS_KEY_KP_DECIMAL },    { XK_KP_Divide,    MAUS_KEY_KP_DIVIDE },
 55-	{ XK_KP_Multiply,  MAUS_KEY_KP_MULTIPLY },   { XK_KP_Subtract,  MAUS_KEY_KP_SUBTRACT },
 56-	{ XK_bracketleft,  MAUS_KEY_LEFT_BRACKET },  { XK_backslash,    MAUS_KEY_BACKSLASH },
 57-	{ XK_KP_Equal,     MAUS_KEY_KP_EQUAL },
 58-};
 59-
 60-static int xerrored;
 61-
 62-static int8_t fb_create(Maus* mw)
 63-{
 64-	MausBackend* be = &mw->backend;
 65-
 66-	be->image = NULL;
 67-	be->shmat = 0;
 68-	be->shm.shmid = -1;
 69-	be->shm.shmaddr = NULL;
 70-	mw->fb = NULL;
 71-	mw->stride = 0;
 72-
 73-	return fb_create_shm(mw);
 74-}
 75-
 76-/* allocate and store a new shm for the framebuffer */
 77-static int8_t fb_create_shm(Maus* mw)
 78-{
 79-	MausBackend* be = &mw->backend;
 80-	int scr = DefaultScreen(be->display);
 81-	int depth = DefaultDepth(be->display, scr);
 82-	Visual* vis = DefaultVisual(be->display, scr);
 83-
 84-	size_t size;
 85-	int (*old_xerr)(Display*, XErrorEvent*);
 86-
 87-	if (!XShmQueryExtension(be->display))
 88-		return 0;
 89-
 90-	if (!vis) {
 91-		maus_log(stderr, "could not get default visual");
 92-		return 0;
 93-	}
 94-
 95-	be->image = XShmCreateImage(
 96-		be->display, vis, depth, ZPixmap, NULL,
 97-		&be->shm, mw->width, mw->height
 98-	);
 99-
100-	if (!be->image) {
101-		maus_log(stderr, "could not create XImage (shm)");
102-		return 0;
103-	}
104-
105-	if (be->image->bits_per_pixel != 32) {
106-		XDestroyImage(be->image);
107-		be->image = NULL;
108-		maus_log(stderr, "XImage not 32bpp");
109-		return 0;
110-	}
111-
112-	size = be->image->bytes_per_line * be->image->height;
113-	be->shm.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
114-	if (be->shm.shmid < 0) {
115-		XDestroyImage(be->image);
116-		be->image = NULL;
117-		maus_log(stderr, "shmget() failed");
118-		return 0;
119-	}
120-
121-	be->shm.shmaddr = shmat(be->shm.shmid, NULL, 0);
122-	if (be->shm.shmaddr == (char*)-1) {
123-		shmctl(be->shm.shmid, IPC_RMID, NULL);
124-		XDestroyImage(be->image);
125-		be->image = NULL;
126-		maus_log(stderr, "shmat() failed");
127-		return 0;
128-	}
129-
130-	be->shm.readOnly = False;
131-	be->image->data = be->shm.shmaddr;
132-
133-	xerrored = 0;
134-	old_xerr = XSetErrorHandler(xerr);
135-
136-	if (!XShmAttach(be->display, &be->shm))
137-		xerrored = 1;
138-
139-	XSync(be->display, False);
140-	XSetErrorHandler(old_xerr);
141-	if (xerrored) {
142-		shmdt(be->shm.shmaddr);
143-		shmctl(be->shm.shmid, IPC_RMID, NULL);
144-		XDestroyImage(be->image);
145-
146-		be->image = NULL;
147-		mw->fb = NULL;
148-		be->shm.shmaddr = NULL;
149-		be->shm.shmid = -1;
150-		maus_log(stderr, "XShmAttach failed");
151-		return 0;
152-	}
153-
154-	shmctl(be->shm.shmid, IPC_RMID, NULL);
155-
156-	be->shmat = 1;
157-	mw->fb = (uint32_t*) be->image->data;
158-	mw->stride = be->image->bytes_per_line / sizeof(uint32_t);
159-
160-	return 1;
161-}
162-
163-static void fb_destroy(Maus* mw)
164-{
165-	MausBackend* be = &mw->backend;
166-	Display* dpy = be->display;
167-
168-	if (be->shmat) {
169-		XShmDetach(dpy, &be->shm);
170-		XSync(dpy, False);
171-		be->shmat = 0;
172-	}
173-
174-	if (be->image) {
175-		XDestroyImage(be->image);
176-		be->image = NULL;
177-	}
178-
179-	if (be->shm.shmaddr && be->shm.shmaddr != (char*) -1) {
180-		shmdt(be->shm.shmaddr);
181-		be->shm.shmaddr = NULL;
182-	}
183-
184-	/* normally already removed after attach but
185-	   can check anyways */
186-	if (be->shm.shmid >= 0) {
187-		shmctl(be->shm.shmid, IPC_RMID, NULL);
188-		be->shm.shmid = -1;
189-	}
190-
191-	mw->fb = NULL;
192-	mw->stride = 0;
193-}
194-
195-static int8_t handle_event(XEvent* xev, MausEvent* ev, Maus* mw)
196-{
197-	MausBackend* be = &mw->backend;
198-	uint32_t code = 0;
199-	unsigned int mb;
200-	MausMouseButton mbtype;
201-
202-	char buf[8] = {0};
203-	int len;
204-
205-	KeySym sym;
206-
207-	XSelectionRequestEvent* req;
208-	XEvent rsp; /* response */
209-	Atom utf8_string;
210-	Atom clipboard;
211-
212-	int cx;
213-	int cy;
214-
215-	switch (xev->type) {
216-		case Expose:
217-			if (xev->xexpose.count != 0)
218-				return 0;
219-			ev->type = MAUS_EV_REDRAW;
220-			return 1;
221-
222-		case ClientMessage:
223-			if ((Atom)xev->xclient.data.l[0] == be->atoms[MAUS_ATOM_WM_DELETE_WINDOW]) {
224-				ev->type = MAUS_EV_CLOSE;
225-				return 1;
226-			}
227-			break;
228-
229-		case MappingNotify:
230-			XRefreshKeyboardMapping(&xev->xmapping);
231-			return 1;
232-			break;
233-
234-		case KeyPress: {
235-			ev->type = MAUS_EV_KEY;
236-			code = xev->xkey.keycode;
237-			ev->key.code = code;
238-			ev->key.pressed = 1;
239-			if (code < MAUS_KEYCODE_LAST)
240-			        mw->key_codes[code] = 1;
241-
242-			/* grab the raw, base sym */
243-			sym = XLookupKeysym(&xev->xkey, 0);
244-			ev->key.key = keysym_to_mauskey(sym);
245-			if (ev->key.key != MAUS_KEY_NONE)
246-			        mw->key_syms[ev->key.key] = 1;
247-
248-			len = XLookupString(&xev->xkey, buf, sizeof(buf), NULL, NULL);
249-			if (len > 0)
250-				ev->key.text = (buf[0] == '\r') ? '\n' : buf[0];
251-			else
252-				ev->key.text = 0;
253-
254-			return 1;
255-		}
256-
257-		case KeyRelease: {
258-			ev->type = MAUS_EV_KEY;
259-			code = xev->xkey.keycode;
260-			ev->key.code = code;
261-			ev->key.pressed = 0;
262-			ev->key.text = 0;
263-
264-			if (code < MAUS_KEYCODE_LAST)
265-			        mw->key_codes[code] = 0;
266-
267-			/* unset base sym set on `KeyPress` */
268-			sym = XLookupKeysym(&xev->xkey, 0);
269-			ev->key.key = keysym_to_mauskey(sym);
270-			if (ev->key.key != MAUS_KEY_NONE)
271-			        mw->key_syms[ev->key.key] = 0;
272-
273-			return 1;
274-		}
275-
276-		case ButtonPress:
277-			ev->type = MAUS_EV_MOUSE_BUTTON;
278-			mb = xev->xbutton.button;
279-			mbtype = mouse_button_to_maus(mb);
280-			ev->mouse.button.button = mbtype;
281-			ev->mouse.button.pressed = 1;
282-			mw->mouse_buttons[mbtype] = 1;
283-			return 1;
284-
285-		case ButtonRelease:
286-			ev->type = MAUS_EV_MOUSE_BUTTON;
287-			mb = xev->xbutton.button;
288-			mbtype = mouse_button_to_maus(mb);
289-			ev->mouse.button.button = mbtype;
290-			ev->mouse.button.pressed = 0;
291-			mw->mouse_buttons[mbtype] = 0;
292-			return 1;
293-
294-		case MotionNotify:
295-			if (be->cur_rel) {
296-				cx = mw->width / 2;
297-				cy = mw->height / 2;
298-
299-				if (be->ignore_warp && xev->xmotion.x == cx && xev->xmotion.y == cy) {
300-					be->ignore_warp = 0;
301-					return 0;
302-				}
303-
304-				ev->type = MAUS_EV_MOUSE_MOTION;
305-				ev->mouse.motion.x = xev->xmotion.x - cx;
306-				ev->mouse.motion.y = xev->xmotion.y - cy;
307-				ev->mouse.motion.dx = ev->mouse.motion.x;
308-				ev->mouse.motion.dy = ev->mouse.motion.y;
309-
310-				if (ev->mouse.motion.x != 0 || ev->mouse.motion.y != 0) {
311-					be->ignore_warp = 1;
312-					XWarpPointer(
313-						be->display, None, be->win,
314-						0, 0, 0, 0, cx, cy
315-					);
316-					XFlush(be->display);
317-				}
318-
319-				return ev->mouse.motion.x != 0 || ev->mouse.motion.y != 0;
320-			}
321-			ev->type = MAUS_EV_MOUSE_MOTION;
322-			ev->mouse.motion.x = xev->xmotion.x;
323-			ev->mouse.motion.y = xev->xmotion.y;
324-			ev->mouse.motion.dx = be->mouse_pos_set ? xev->xmotion.x - be->mouse_x : 0;
325-			ev->mouse.motion.dy = be->mouse_pos_set ? xev->xmotion.y - be->mouse_y : 0;
326-			be->mouse_x = xev->xmotion.x;
327-			be->mouse_y = xev->xmotion.y;
328-			be->mouse_pos_set = 1;
329-			return 1;
330-
331-		case ConfigureNotify:
332-			ev->type = MAUS_EV_RESIZE;
333-			ev->resize.width = xev->xconfigure.width;
334-			ev->resize.height = xev->xconfigure.height;
335-			return 1;
336-
337-		case SelectionRequest: {
338-			req = &xev->xselectionrequest;
339-
340-			utf8_string = XInternAtom(be->display, "UTF8_STRING", False);
341-			clipboard = XInternAtom(be->display, "CLIPBOARD", False);
342-
343-			rsp.type = SelectionNotify;
344-			rsp.xselection.display = req->display;
345-			rsp.xselection.requestor = req->requestor;
346-			rsp.xselection.selection = req->selection;
347-			rsp.xselection.target = req->target;
348-			rsp.xselection.property = None; 
349-			rsp.xselection.time = req->time;
350-
351-			/* assign clipboard text to requesting programs
352-			   window property */
353-			if (req->selection == clipboard &&
354-			    req->target == utf8_string &&
355-			    mw->clipboard) {
356-			        XChangeProperty(
357-					req->display, req->requestor,
358-					req->property, utf8_string, 8,
359-					PropModeReplace, (unsigned char*)mw->clipboard, 
360-					strlen(mw->clipboard)
361-			 	);
362-				rsp.xselection.property = req->property; 
363-			}
364-
365-			/* send reply back to the prog requesting paste */
366-			XSendEvent(req->display, req->requestor, False, 0, &rsp);
367-			XFlush(be->display);
368-
369-			return 0; /* skip maus polling it */
370-		}
371-	}
372-
373-	return 0;
374-}
375-
376-static MausKey keysym_to_mauskey(KeySym sym)
377-{
378-	size_t i;
379-
380-	if (sym >= 0x20 && sym <= 0x7E)
381-		return (MausKey)sym;
382-
383-	if (sym >= XK_F1 && sym <= XK_F12)
384-		return MAUS_KEY_F1 + (sym - XK_F1);
385-	if (sym >= XK_KP_0 && sym <= XK_KP_9)
386-		return MAUS_KEY_KP_0 + (sym - XK_KP_0);
387-
388-	for (i = 0; i < sizeof(keymap)/ sizeof(keymap[0]); i++) {
389-		if (keymap[i].x11 == sym)
390-			return keymap[i].maus;
391-	}
392-
393-	return MAUS_KEY_NONE;
394-}
395-
396-static MausMouseButton mouse_button_to_maus(int btn)
397-{
398-	switch (btn) {
399-		case Button1: return MAUS_MOUSE_BUTTON_LEFT;
400-		case Button2: return MAUS_MOUSE_BUTTON_MIDDLE;
401-		case Button3: return MAUS_MOUSE_BUTTON_RIGHT;
402-		case Button4: return MAUS_MOUSE_BUTTON_SCROLL_UP;
403-		case Button5: return MAUS_MOUSE_BUTTON_SCROLL_DOWN;
404-		default:      return MAUS_MOUSE_BUTTON_NONE;
405-	}
406-}
407-
408-static int xerr(Display* dpy, XErrorEvent* ev)
409-{
410-	(void) dpy;
411-	(void) ev;
412-	xerrored = 1;
413-	return 0;
414-}
415-
416-void maus_clipboard_set_text(Maus* mw, const char* text)
417-{
418-	MausBackend* be = &mw->backend;
419-	Atom clipboard;
420-
421-	if (!be->display || be->win == None)
422-		return;
423-
424-	/* clear old entry */
425-	if (mw->clipboard) {
426-		free(mw->clipboard);
427-		mw->clipboard = NULL;
428-	}
429-
430-	if (text)
431-		mw->clipboard = maus_strdup(text);
432-
433-	clipboard = XInternAtom(be->display, "CLIPBOARD", False);
434-	XSetSelectionOwner(be->display, clipboard, be->win, CurrentTime);
435-	XFlush(be->display);
436-}
437-
438-char* maus_clipboard_get_text(Maus* mw)
439-{
440-	MausBackend* be = &mw->backend;
441-	Atom clipboard = XInternAtom(be->display, "CLIPBOARD", False);
442-	Atom utf8_string = XInternAtom(be->display, "UTF8_STRING", False);
443-	Atom maus_clipboard_prop = XInternAtom(be->display, "MAUS_CLIPBOARD_PROP", False);
444-
445-	XEvent xev;
446-	int8_t ok = 0;
447-
448-	int timeout;
449-
450-	Atom actual_type;
451-	int actual_fmt;
452-	unsigned long nitems;
453-	unsigned long bytes_after;
454-	unsigned char* prop_data = NULL;
455-
456-	char* res = NULL;
457-
458-	/* fetch clipboard data to `maus_clipboard_prop`
459-	   window property */
460-	XConvertSelection(
461-		be->display, clipboard, utf8_string,
462-		maus_clipboard_prop, be->win, CurrentTime
463-	);
464-	XFlush(be->display);
465-
466-	/* check for selection response */
467-	for (timeout = 0; timeout < 10000; timeout++) { 
468-		if (XCheckTypedWindowEvent(be->display, be->win, SelectionNotify, &xev)) {
469-			if (xev.xselection.property != None)
470-				ok = 1;
471-			break;
472-		}
473-	}
474-	if (!ok)
475-		return NULL;
476-
477-	/* read string off property */
478-	XGetWindowProperty(
479-		be->display, be->win, maus_clipboard_prop, 0,LONG_MAX,
480-		True, utf8_string, &actual_type, &actual_fmt, &nitems,
481-		&bytes_after, &prop_data
482-	);
483-
484-	if (prop_data) {
485-		res = maus_strdup((char*)prop_data);
486-		XFree(prop_data);
487-	}
488-
489-	return res;
490-}
491-
492-void maus_close(Maus* mw)
493-{
494-	MausBackend* be = &mw->backend;
495-
496-	fb_destroy(mw);
497-	if (mw->bfb) {
498-		free(mw->bfb);
499-		mw->bfb = NULL;
500-	}
501-	if (mw->clipboard) {
502-		free(mw->clipboard);
503-		mw->clipboard = NULL;
504-	}
505-	if (be->win != None) {
506-		(void) maus_close_window(mw);
507-	}
508-	if (be->display)
509-		XCloseDisplay(be->display);
510-}
511-
512-int8_t maus_close_window(Maus* mw)
513-{
514-	MausBackend* be = &mw->backend;
515-
516-	if (be->gc) {
517-		XFreeGC(be->display, be->gc);
518-		be->gc = 0;
519-	}
520-
521-	if (be->win != None) {
522-		XUnmapWindow(be->display, be->win);
523-		XDestroyWindow(be->display, be->win);
524-	}
525-
526-	return 1;
527-}
528-
529-int8_t maus_create_window(Maus* mw)
530-{
531-	MausBackend* be = &mw->backend;
532-	Display* dpy = be->display;
533-	Window* win = &be->win;
534-
535-	*win = XCreateSimpleWindow(
536-		dpy, be->root,
537-		mw->x, mw->y,
538-		mw->width, mw->height,
539-		0u, 0u, 0u
540-	);
541-
542-	if (*win == None)
543-		return 0;
544-
545-	XSelectInput(dpy, *win,
546-		ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask |
547-		ButtonReleaseMask | PointerMotionMask | StructureNotifyMask
548-	);
549-
550-	/* no black flashing when resizing */
551-	XSetWindowBackgroundPixmap(dpy, *win, None);
552-
553-	/* atoms */
554-	be->atoms[MAUS_ATOM_WM_DELETE_WINDOW] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
555-
556-	XSetWMProtocols(dpy, *win, &be->atoms[MAUS_ATOM_WM_DELETE_WINDOW], 1);
557-	XStoreName(dpy, *win, mw->title);
558-
559-	XMapWindow(dpy, *win);
560-	XFlush(dpy);
561-
562-	be->gc = XCreateGC(dpy, *win, 0, NULL);
563-	if (!be->gc) {
564-		maus_log(stderr, "failed to create window GC");
565-		maus_close_window(mw);
566-		return 0;
567-	}
568-
569-	return 1;
570-}
571-
572-void maus_clear(Maus* mw, MausColor col)
573-{
574-	uint32_t col_up = MAUS_UNPACK_COL(col);
575-	uint32_t pxs = mw->height * mw->width;
576-	uint32_t i;
577-	for (i = 0; i < pxs; i++)
578-		mw->bfb[i] = col_up;
579-}
580-
581-Maus* maus_init(const char* title, int x, int y, int width, int height)
582-{
583-	Display* d = XOpenDisplay(NULL);
584-	Maus* mw = calloc(1, sizeof(Maus));
585-	MausBackend* be = &mw->backend;
586-
587-	if (MAUS_WARN_BACKEND_AUTO_SEL)
588-		maus_log(stderr, "backend auto-selected: X11");
589-
590-	if (!d) {
591-		maus_die("failed to open X11 display");
592-		return NULL;
593-	}
594-
595-	be->display = d;
596-	be->root = DefaultRootWindow(d);
597-	be->win = None;
598-	be->cur_rel = 0;
599-	be->ignore_warp = 0;
600-	be->mouse_x = 0;
601-	be->mouse_y = 0;
602-	be->mouse_pos_set = 0;
603-
604-	mw->frame_time_last = maus_get_time_ns();
605-	mw->title = title;
606-	mw->width = width;
607-	mw->height = height;
608-	mw->x = x;
609-	mw->y = y;
610-	mw->fb = NULL;
611-
612-	be->gc = 0;
613-	be->image = NULL;
614-	be->shmat = 0;
615-	be->shm.shmid = -1;
616-	be->shm.shmaddr = NULL;
617-	if (!fb_create(mw)) {
618-		maus_log(stderr, "failed to create framebuffer");
619-		maus_close(mw);
620-		free(mw);
621-		return NULL;
622-	}
623-	mw->bfb = calloc(mw->stride * mw->height, sizeof(uint32_t));
624-	if (!mw->bfb) {
625-		maus_log(stderr, "failed to allocate back buffer");
626-		maus_close(mw);
627-		free(mw);
628-		return NULL;
629-	}
630-
631-	return mw;
632-}
633-
634-int8_t maus_event_poll(Maus* mw, MausEvent* ev)
635-{
636-	MausBackend* be = &mw->backend;
637-	XEvent xev;
638-
639-	while (XPending(be->display)) {
640-		XNextEvent(be->display, &xev);
641-		ev->type = MAUS_EV_NONE;
642-		if (handle_event(&xev, ev, mw))
643-			return 1;
644-
645-	}
646-
647-	return 0;
648-}
649-
650-void maus_event_wait(Maus* mw, MausEvent* ev)
651-{
652-	MausBackend* be = &mw->backend;
653-	XEvent xev;
654-
655-	for (;;) {
656-		XNextEvent(be->display, &xev);
657-		ev->type = MAUS_EV_NONE;
658-		if (handle_event(&xev, ev, mw))
659-			return;
660-	}
661-}
662-
663-void maus_present(Maus* mw)
664-{
665-	MausBackend* be = &mw->backend;
666-	uint32_t bytes;
667-
668-	if (!be->image || be->win == None)
669-		return;
670-
671-	bytes = mw->stride * mw->height * sizeof(uint32_t);
672-	memcpy(mw->fb, mw->bfb, bytes);
673-
674-	XShmPutImage(
675-		be->display, be->win, be->gc, be->image,
676-		0, 0, 0, 0, mw->width, mw->height, False
677-	);
678-
679-	XFlush(be->display);
680-}
681-
682-int8_t maus_resize(Maus* mw, uint32_t width, uint32_t height)
683-{
684-	MausBackend* be = &mw->backend;
685-
686-	if (width == 0 || height == 0 ||
687-	    (mw->width == width && mw->height == height))
688-		return 0;
689-
690-	fb_destroy(mw);
691-	if (mw->bfb) {
692-		free(mw->bfb);
693-		mw->bfb = NULL;
694-	}
695-
696-	mw->width = width;
697-	mw->height = height;
698-
699-	XSync(be->display, False);
700-	XFlush(be->display);
701-
702-	if (!fb_create(mw))
703-		return 0;
704-
705-	mw->bfb = calloc(mw->stride * mw->height, sizeof(uint32_t));
706-	if (!mw->bfb)
707-		return 0;
708-
709-	return 1;
710-}
711-
712-void maus_cur_set_mode(Maus* mw, MausCursorState state)
713-{
714-	MausBackend* be = &mw->backend;
715-	Display* dpy = be->display;
716-	Window win = be->win;
717-
718-	Mask mask;
719-	int grab;
720-
721-	if (!dpy) {
722-		maus_log(stderr, "display is NULL");
723-		return;
724-	}
725-	if (win == None) {
726-		maus_log(stderr, "win is None");
727-		return;
728-	}
729-
730-	/* show cursor */
731-	if (state == MAUS_CURSOR_STATE_VISIBLE) {
732-		XUndefineCursor(dpy, win);
733-		XFlush(dpy);
734-		return;
735-	}
736-
737-	/* hide cursor */
738-	if (state == MAUS_CURSOR_STATE_HIDDEN) {
739-		Pixmap blank_pm = XCreatePixmap(dpy, win, 1, 1, 1);
740-		XColor black = {0, 0, 0, 0, 0, 0};
741-		Cursor blank_cur = XCreatePixmapCursor(
742-			dpy, blank_pm, blank_pm, &black, &black, 0, 0
743-		);
744-		XFreePixmap(dpy, blank_pm);
745-
746-		XDefineCursor(dpy, win, blank_cur);
747-		XFreeCursor(dpy, blank_cur);
748-		XFlush(dpy);
749-		return;
750-	}
751-
752-	/* lock cursor */
753-	if (state == MAUS_CURSOR_STATE_LOCKED) {
754-		mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
755-		grab = XGrabPointer(
756-			dpy, win, True, mask, GrabModeAsync,
757-			GrabModeAsync, win, None, CurrentTime
758-		);
759-
760-		if (grab != GrabSuccess) {
761-			maus_log(stderr, "failed to grab mouse pointer");
762-			return;
763-		}
764-
765-		/* TODO keep position just snap to window dimensions */
766-		XWarpPointer(dpy, None, win, 0, 0, 0, 0, mw->width/2, mw->height/2);
767-		XFlush(dpy);
768-		return;
769-	}
770-
771-	/* unlock cursor */
772-	if (state == MAUS_CURSOR_STATE_FREE) {
773-		XUngrabPointer(dpy, CurrentTime);
774-		XFlush(dpy);
775-		return;
776-	}
777-
778-	/* relative cursor */
779-	if (state == MAUS_CURSOR_STATE_RELATIVE) {
780-		mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
781-		grab = XGrabPointer(
782-			dpy, win, True, mask, GrabModeAsync,
783-			GrabModeAsync, win, None, CurrentTime
784-		);
785-
786-		if (grab != GrabSuccess) {
787-			maus_log(stderr, "failed to grab mouse pointer");
788-			return;
789-		}
790-
791-		be->cur_rel = 1;
792-		be->ignore_warp = 1;
793-		XWarpPointer(dpy, None, win, 0, 0, 0, 0, mw->width/2, mw->height/2);
794-		XFlush(dpy);
795-		return;
796-	}
797-
798-	/* absolute cursor */
799-	if (state == MAUS_CURSOR_STATE_ABSOLUTE) {
800-		be->cur_rel = 0;
801-		be->ignore_warp = 0;
802-		XUngrabPointer(dpy, CurrentTime);
803-		XFlush(dpy);
804-		return;
805-	}
806-}
807-
+0, -21
 1@@ -1,21 +0,0 @@
 2-#include <stdlib.h>
 3-#include <string.h>
 4-
 5-#include "utils.h"
 6-
 7-char* maus_strdup(const char* src)
 8-{
 9-	size_t len;
10-	char* dst;
11-	if (src == NULL)
12-		return NULL;
13-
14-	len = strlen(src);
15-	dst = malloc(len + 1);
16-	if (dst == NULL)
17-		return NULL;
18-
19-	memcpy(dst, src, len + 1);
20-	return dst;
21-}
22-
+0, -11
 1@@ -1,11 +0,0 @@
 2-#ifndef UTIL_H
 3-#define UTIL_H
 4-
 5-/* duplicate a string. returns pointer to address of
 6-   newly allocated string buffer. if NULL, allocation
 7-   failed or src is NULL
 8-   note: you must free this newly allocated string */
 9-char* maus_strdup(const char* src);
10-
11-#endif /* UTIL_H */
12-