commit 6578f25
uint
·
2026-08-04 12:53:53 +0000 UTC
parent 9ae8147
update libmaus sources, configure script
20 files changed,
+2209,
-452
+32,
-31
1@@ -2,63 +2,64 @@
2 set -eu
3
4 PLATFORM=$(uname -s)
5+BACKEND=${1:-}
6 CPPFLAGS=
7 LDFLAGS="-Llibmaus/build"
8
9+if [ "$#" -gt 1 ]; then
10+ echo "Usage: ./configure [x11|wayland|mac]" >&2
11+ exit 1
12+fi
13+
14 case "$PLATFORM" in
15 Darwin)
16- BACKEND=mac
17- LDLIBS="-lmaus_mac \
18- -framework Cocoa \
19- -framework CoreVideo \
20- -framework IOKit \
21- -framework CoreGraphics \
22- -framework CoreFoundation \
23- -framework Carbon"
24+ : "${BACKEND:=mac}"
25 ;;
26-
27 Linux|FreeBSD|OpenBSD)
28- if [ -n "${WAYLAND_DISPLAY:-}" ]; then
29- BACKEND=way
30- CPPFLAGS=-DBACKEND_WAY
31- LDLIBS="-lmaus_way -lwayland-client"
32- elif [ -n "${DISPLAY:-}" ]; then
33+ if [ -z "$BACKEND" ] && [ -n "${WAYLAND_DISPLAY:-}" ]; then
34+ BACKEND=wayland
35+ elif [ -z "$BACKEND" ] && [ -n "${DISPLAY:-}" ]; then
36 BACKEND=x11
37- CPPFLAGS=-DBACKEND_X11
38- LDLIBS="-lmaus_x11 -lX11 -lXext"
39- else
40+ elif [ -z "$BACKEND" ]; then
41 echo "No X11 or Wayland display found" >&2
42 exit 1
43 fi
44-
45- case "$PLATFORM" in
46- Linux)
47- CPPFLAGS="-D_XOPEN_SOURCE=700 $CPPFLAGS"
48- ;;
49- OpenBSD)
50- CPPFLAGS="-I/usr/X11R6/include $CPPFLAGS"
51- LDFLAGS="-L/usr/X11R6/lib $LDFLAGS"
52- ;;
53- esac
54 ;;
55-
56 *)
57 echo "Unsupported platform: $PLATFORM" >&2
58 exit 1
59 ;;
60 esac
61
62+case "$PLATFORM" in
63+ Linux)
64+ CPPFLAGS="-D_XOPEN_SOURCE=700"
65+ ;;
66+ OpenBSD)
67+ CPPFLAGS="-I/usr/X11R6/include"
68+ LDFLAGS="-L/usr/X11R6/lib $LDFLAGS"
69+ ;;
70+esac
71+
72 (
73 cd libmaus
74 rm -rf build/
75- ./configure --backend="$BACKEND"
76+ ./configure "$BACKEND"
77 make
78 )
79
80+CONF_CPPFLAGS=$(sed -n 's/^CONF_CPPFLAGS = //p' libmaus/config.mk)
81+CONF_LDFLAGS=$(sed -n 's/^CONF_LDFLAGS = //p' libmaus/config.mk)
82+CONF_LIB_NAME=$(sed -n 's/^CONF_LIB_NAME = //p' libmaus/config.mk)
83+CONF_LIB=${CONF_LIB_NAME#lib}
84+CONF_LIB=${CONF_LIB%.a}
85+
86 cat >platform.mk <<EOF
87-CPPFLAGS += $CPPFLAGS
88+CPPFLAGS += $CPPFLAGS $CONF_CPPFLAGS
89 LDFLAGS += $LDFLAGS
90-LDLIBS += $LDLIBS
91+LDLIBS += -l$CONF_LIB
92+LDLIBS += ${CONF_LDFLAGS}
93 EOF
94
95 echo "Configuration done"
96+
+1,
-0
1@@ -5,6 +5,7 @@
2 *.obj
3 *.lib
4
5+build/
6 compile_flags.txt
7
8 fenster/
+45,
-7
1@@ -1,9 +1,13 @@
2+.POSIX:
3+
4 include config.mk
5
6 CC = cc
7 AR = ar
8-CFLAGS = -std=c99 -Wall -Wextra -O2
9-CPPFLAGS = ${CONF_CPPFLAGS} -Iinclude
10+ARFLAGS = -r -c
11+CFLAGS = -ansi -pedantic-errors -Wall -Wextra -O2
12+WL_CFLAGS = -std=c99 -Wall -Wextra -O2
13+CPPFLAGS = ${CONF_CPPFLAGS} -Iinclude -Ibuild
14 LDFLAGS = ${CONF_LDFLAGS}
15
16 LIB_NAME = build/${CONF_LIB_NAME}
17@@ -19,21 +23,55 @@ LIB_OBJS = build/maus.o \
18 all: ${LIB_NAME}
19
20 ${LIB_NAME}: ${LIB_OBJS}
21- ${AR} -rcs $@ ${LIB_OBJS}
22+ ${AR} ${ARFLAGS} $@ ${LIB_OBJS}
23
24-build/maus.o: source/maus.c
25+build/maus.o: source/maus.c include/maus.h config.mk
26 mkdir -p build
27 ${CC} ${CFLAGS} ${CPPFLAGS} -c source/maus.c -o $@
28-build/maus_font.o: source/maus_font.c
29+build/maus_font.o: source/maus_font.c include/maus.h include/maus_font.h config.mk
30 mkdir -p build
31 ${CC} ${CFLAGS} ${CPPFLAGS} -c source/maus_font.c -o $@
32-build/utils.o: source/utils.c
33+build/utils.o: source/utils.c include/utils.h
34 mkdir -p build
35 ${CC} ${CFLAGS} ${CPPFLAGS} -c source/utils.c -o $@
36-build/maus_x11.o: source/maus_x11.c
37+
38+# X11
39+build/maus_x11.o: source/maus_x11.c include/maus.h include/maus_x11.h config.mk
40 mkdir -p build
41 ${CC} ${CFLAGS} ${CPPFLAGS} -c source/maus_x11.c -o $@
42
43+# Wayland
44+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
45+ mkdir -p build
46+ ${CC} ${WL_CFLAGS} ${CPPFLAGS} -c source/maus_wayland.c -o $@
47+build/xdg-shell-client-protocol.h:
48+ mkdir -p build
49+ wayland-scanner client-header ${PROTOS}/stable/xdg-shell/xdg-shell.xml $@
50+build/xdg-shell-protocol.c:
51+ mkdir -p build
52+ wayland-scanner private-code ${PROTOS}/stable/xdg-shell/xdg-shell.xml $@
53+build/xdg-shell-protocol.o: build/xdg-shell-protocol.c build/xdg-shell-client-protocol.h
54+ mkdir -p build
55+ ${CC} ${WL_CFLAGS} ${CPPFLAGS} -c build/xdg-shell-protocol.c -o $@
56+build/pointer-constraints-unstable-v1-client-protocol.h:
57+ mkdir -p build
58+ wayland-scanner client-header ${PROTOS}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@
59+build/pointer-constraints-unstable-v1-protocol.c:
60+ mkdir -p build
61+ wayland-scanner private-code ${PROTOS}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@
62+build/pointer-constraints-unstable-v1-protocol.o: build/pointer-constraints-unstable-v1-protocol.c build/pointer-constraints-unstable-v1-client-protocol.h
63+ mkdir -p build
64+ ${CC} ${WL_CFLAGS} ${CPPFLAGS} -c build/pointer-constraints-unstable-v1-protocol.c -o $@
65+build/relative-pointer-unstable-v1-client-protocol.h:
66+ mkdir -p build
67+ wayland-scanner client-header ${PROTOS}/unstable/relative-pointer/relative-pointer-unstable-v1.xml $@
68+build/relative-pointer-unstable-v1-protocol.c:
69+ mkdir -p build
70+ wayland-scanner private-code ${PROTOS}/unstable/relative-pointer/relative-pointer-unstable-v1.xml $@
71+build/relative-pointer-unstable-v1-protocol.o: build/relative-pointer-unstable-v1-protocol.c build/relative-pointer-unstable-v1-client-protocol.h
72+ mkdir -p build
73+ ${CC} ${WL_CFLAGS} ${CPPFLAGS} -c build/relative-pointer-unstable-v1-protocol.c -o $@
74+
75 clean:
76 rm -rf build ${LIB_NAME} config.mk compile_flags.txt
77
+8,
-5
1@@ -1,10 +1,10 @@
2 
3-is a small, cross-platform, software windowing library
4+is a small, cross-platform, software windowing library **now in ANSI C**
5
6 ### Building
7 Unix:
8 ```sh
9-./configure --backend=[x11|wayland|mac]
10+./configure [x11|wayland|mac]
11 make # That's it!
12 ```
13
14@@ -12,15 +12,18 @@ Windows:
15 ```
16 .\build.bat [msvc|gcc|clang]
17 ```
18+> If anyone is on Windows, please try to compile past the ANSI conversion.
19+> I pretty much converted it without checking so there may still be C99
20+> artefacts left behind.
21
22 After building, you have a library which you link _your_ sources with. It is
23 located in `build/`.
24
25 ### Usage
26 #### libmaus
27-Here is an annoted example for a basic window program which counts the number of
28-frames that have elapsed, draw the text and displays if you've pressed a key
29-(specifically 'A').
30+Here is an annoted (C99) example for a basic window program which counts the
31+number of frames that have elapsed, draw the text and displays if you've
32+pressed a key (specifically 'A').
33
34 For the full list of functions and what they do, look at
35 [the header](include/maus.h).
+5,
-0
1@@ -1,4 +1,9 @@
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
+12,
-5
1@@ -2,14 +2,16 @@
2
3 for arg do
4 case "$arg" in
5- --backend=*) backend="${arg#*=}" ;;
6 --help)
7- echo "Usage: ./configure [--backend=x11|wayland|mac]"
8+ echo "Usage: ./configure [x11|wayland|mac]"
9 exit 0
10 ;;
11 *)
12- echo "Unknown argument: $arg"
13- exit 1
14+ if [ -n "$backend" ]; then
15+ echo "Usage: ./configure [x11|wayland|mac]"
16+ exit 1
17+ fi
18+ backend="$arg"
19 ;;
20 esac
21 done
22@@ -28,7 +30,12 @@ case "$backend" in
23 echo "CONF_LIB_NAME = libmaus_x11.a" >> config.mk
24 ;;
25 wayland)
26- # TODO
27+ echo "CONF_CPPFLAGS = -DBACKEND_WAY $(pkg-config --cflags wayland-client wayland-cursor xkbcommon)" >> config.mk
28+ echo "CONF_LDFLAGS = $(pkg-config --libs wayland-client wayland-cursor xkbcommon)" >> config.mk
29+ 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
30+ 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
31+ echo "CONF_LIB_NAME = libmaus_wayland.a" >> config.mk
32+ echo "PROTOS = $(pkg-config --variable=pkgdatadir wayland-protocols)" >> config.mk
33 ;;
34 mac)
35 # TODO
1@@ -1,8 +1,10 @@
2+include ../../config.mk
3+
4 CC = cc
5 CFLAGS = -std=c99 -Wall -Wextra -g
6-CPPFLAGS = -DBACKEND_X11 -I../../include
7-LIBS = -lX11 -lXext
8-MAUS_LIB = ../../build/libmaus_x11.a
9+CPPFLAGS = ${CONF_CPPFLAGS} -I../../include -I../../build
10+LIBS = ${CONF_LDFLAGS}
11+MAUS_LIB = ../../build/${CONF_LIB_NAME}
12
13 SRC = main.c
14
+23,
-3
1@@ -8,12 +8,14 @@
2 int mx, my;
3 bool cur_visible = true;
4 bool cur_locked = false;
5+bool cur_relative = false;
6 bool mb1_pressed = false;
7 char txtbuf[4096] = {'\0'};
8 int current_char = 0;
9 bool resize = false;
10 int rszw;
11 int rszh;
12+MausColor white = {255, 255, 255, 255};
13
14 void handle_ev(Maus* mw, MausEvent* ev)
15 {
16@@ -25,7 +27,7 @@ void handle_ev(Maus* mw, MausEvent* ev)
17 case MAUS_EV_KEY: {
18 (void)0;
19
20- bool* keys = mw->key_syms;
21+ int8_t* keys = mw->key_syms;
22 if (keys[MAUS_KEY_CONTROL_L] && keys[MAUS_KEY_Q]) {
23 maus_close(mw);
24 exit(EXIT_SUCCESS);
25@@ -44,6 +46,13 @@ void handle_ev(Maus* mw, MausEvent* ev)
26
27 cur_locked = !cur_locked;
28 }
29+ if (keys[MAUS_KEY_CONTROL_L] && keys[MAUS_KEY_R]) {
30+ cur_relative ?
31+ maus_cur_set_mode(mw, MAUS_CURSOR_STATE_ABSOLUTE) :
32+ maus_cur_set_mode(mw, MAUS_CURSOR_STATE_RELATIVE);
33+
34+ cur_relative = !cur_relative;
35+ }
36
37 if (ev->key.pressed == false)
38 break;
39@@ -59,6 +68,16 @@ void handle_ev(Maus* mw, MausEvent* ev)
40 break;
41 }
42 case MAUS_EV_MOUSE_BUTTON: {
43+ if (ev->mouse.button.button == MAUS_MOUSE_BUTTON_SCROLL_UP) {
44+ white.r += 5;
45+ white.g += 5;
46+ white.b += 5;
47+ }
48+ else if (ev->mouse.button.button == MAUS_MOUSE_BUTTON_SCROLL_DOWN) {
49+ white.r -= 5;
50+ white.g -= 5;
51+ white.b -= 5;
52+ }
53 mb1_pressed =
54 mw->mouse_buttons[MAUS_MOUSE_BUTTON_LEFT] ?
55 true : false;
56@@ -74,6 +93,8 @@ void handle_ev(Maus* mw, MausEvent* ev)
57 rszw = ev->resize.width;
58 rszh = ev->resize.height;
59 } break;
60+ case MAUS_EV_REDRAW:
61+ break;
62 case MAUS_EV_NONE:
63 break;
64 }
65@@ -102,7 +123,7 @@ int main(void)
66 resize = false;
67 }
68
69- maus_clear(mw, MAUS_COL_RGBA(255, 255, 255, 255));
70+ maus_clear(mw, white);
71
72 uint32_t red_unpacked = MAUS_UNPACK_COL(red);
73 if (mx >= 0 && my >= 0 &&
74@@ -132,4 +153,3 @@ int main(void)
75 maus_font_free(font);
76 maus_close(mw);
77 }
78-
+56,
-56
1@@ -1,7 +1,6 @@
2 #ifndef MAUSWIN_H
3 #define MAUSWIN_H
4
5-#include <stdbool.h>
6 #include <stdio.h>
7 #include <stdint.h>
8
9@@ -36,7 +35,7 @@
10 #include "maus_x11.h"
11
12 #elif defined(BACKEND_WAY)
13- /* ... */
14+ #include "maus_wayland.h"
15
16 #elif defined(BACKEND_WIN)
17 #include "maus_win.h"
18@@ -53,7 +52,7 @@
19 ((uint32_t)(c).r << 16) | \
20 ((uint32_t)(c).g << 8) | \
21 ((uint32_t)(c).b))
22-/* ... */
23+
24 #define MAUS_PIXEL_AT(mw, x, y) ((mw)->bfb[(y) * (mw)->stride + (x)])
25
26 typedef enum {
27@@ -63,66 +62,66 @@ typedef enum {
28 MAUS_EV_MOUSE_BUTTON,
29 MAUS_EV_MOUSE_MOTION,
30 MAUS_EV_RESIZE,
31- MAUS_EV_REDRAW, /* TODO: MAUS_EV_REDRAW for windows */
32+ MAUS_EV_REDRAW /* TODO: MAUS_EV_REDRAW for windows */
33 } MausEventType;
34
35 typedef struct {
36- uint8_t a;
37- uint8_t r;
38- uint8_t g;
39- uint8_t b;
40+ uint8_t a;
41+ uint8_t r;
42+ uint8_t g;
43+ uint8_t b;
44 } MausColor;
45
46 typedef struct {
47 MausEventType type;
48
49- union {
50- struct {
51- uint32_t code; /* raw, backend keycode */
52- MausKey key; /* logical, mapped key */
53- char text; /* translated text from key */
54- bool pressed;
55- } key;
56+ struct {
57+ uint32_t code; /* raw, backend keycode */
58+ MausKey key; /* logical, mapped key */
59+ char text; /* translated text from key */
60+ int8_t pressed;
61+ } key;
62
63+ struct {
64 struct {
65- struct {
66- MausMouseButton button;
67- bool pressed;
68- } button;
69-
70- struct {
71- int32_t x;
72- int32_t y;
73- } motion;
74- } mouse;
75+ MausMouseButton button;
76+ int8_t pressed;
77+ } button;
78
79 struct {
80- uint32_t width;
81- uint32_t height;
82- } resize;
83- };
84+ int32_t x;
85+ int32_t y;
86+ int32_t dx;
87+ int32_t dy;
88+ } motion;
89+ } mouse;
90+
91+ struct {
92+ uint32_t width;
93+ uint32_t height;
94+ } resize;
95 } MausEvent;
96
97 typedef struct {
98- MausBackend backend;
99- uint64_t frame_time_last;
100- char* clipboard;
101+ MausBackend backend;
102+ uint64_t frame_time_last;
103+ char* clipboard;
104
105- uint32_t* fb; /* front frame buffer */
106- uint32_t* bfb; /* back frame buffer */
107- uint32_t stride;
108+ uint32_t* fb; /* front frame buffer */
109+ uint32_t* bfb; /* back frame buffer */
110+ uint32_t stride;
111
112- const char* title;
113- uint32_t width;
114- uint32_t height;
115- int32_t x;
116- int32_t y;
117+ const char* title;
118+ uint32_t width;
119+ uint32_t height;
120+ int32_t x;
121+ int32_t y;
122
123- bool key_codes[MAUS_KEYCODE_LAST]; /* physical keys */
124- bool key_syms[MAUS_KEY_LAST]; /* logical keys */
125+ int8_t key_codes[MAUS_KEYCODE_LAST]; /* physical keys */
126+ int8_t key_syms[MAUS_KEY_LAST]; /* logical keys */
127
128- MausCursor cursor;
129- bool mouse_buttons[MAUS_MOUSE_BUTTON_LAST];
130+ MausCursor cursor;
131+ int8_t mouse_buttons[MAUS_MOUSE_BUTTON_LAST];
132 } Maus;
133
134 /* clear screen with color: `col` */
135@@ -134,14 +133,15 @@ void maus_clipboard_set_text(Maus* mw, const char* text);
136 /* get text from system clipboard */
137 char* maus_clipboard_get_text(Maus* mw);
138
139-/* close a Maus. returns false on fail */
140+/* close a Maus. returns 0 on fail
141+ TODO also free mw */
142 void maus_close(Maus* mw);
143
144-/* close a window without the whole Maus. returns false on fail */
145-bool maus_close_window(Maus* mw);
146+/* close a window without the whole Maus. returns 0 on fail */
147+int8_t maus_close_window(Maus* mw);
148
149-/* create window from Maus. returns false on fail */
150-bool maus_create_window(Maus* mw);
151+/* create window from Maus. returns 0 on fail */
152+int8_t maus_create_window(Maus* mw);
153
154 /* log message to output `fd` and die */
155 void maus_die(const char* fmt, ...);
156@@ -156,20 +156,20 @@ Maus* maus_init(const char* title, int x, int y, int width, int height);
157 void maus_log(FILE* fd, const char* fmt, ...);
158
159 /* poll for events then fill `ev` with retrieved events.
160- returns true if event polled, else false.
161+ returns 1 if event polled, else 0.
162 note: can burn cpu cycles */
163-bool maus_event_poll(Maus* mw, MausEvent* ev);
164+int8_t maus_event_poll(Maus* mw, MausEvent* ev);
165
166-/* poll for events then fill `ev` with retrieved events. returns true if event
167- polled, else false. note, thread goes to sleep until an event arrives */
168+/* poll for events then fill `ev` with retrieved events. returns 1 if event
169+ polled, else 0. note, thread goes to sleep until an event arrives */
170 void maus_event_wait(Maus* mw, MausEvent* ev);
171
172 /* present the pixelbuffer to the screen */
173 void maus_present(Maus* mw);
174
175-/* resize window to specified width and height. returns true on resize success,
176- else false */
177-bool maus_resize(Maus* mw, uint32_t width, uint32_t height);
178+/* resize window to specified width and height. returns 1 on resize success,
179+ else 0 */
180+int8_t maus_resize(Maus* mw, uint32_t width, uint32_t height);
181
182 /* cap framerate to targetted fps */
183 void maus_target_fps(Maus* mw, uint32_t fps);
+13,
-13
1@@ -2,28 +2,28 @@
2 #define MAUS_FONT_H
3
4 #include <stdint.h>
5-#include <stdbool.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- bool valid;
19+ uint8_t* bmp;
20+ uint16_t w;
21+ uint16_t h;
22+ int16_t xoff;
23+ int16_t yoff;
24+ uint16_t adv;
25+ int8_t valid;
26 } MausGlyph;
27
28 typedef struct {
29- MausGlyph glyphs[MAUS_BDF_GLYPHS_MAX];
30- int32_t asc;
31- int32_t dsc;
32- int32_t cellh;
33- int32_t cellw;
34+ MausGlyph glyphs[MAUS_BDF_GLYPHS_MAX];
35+
36+ int32_t asc;
37+ int32_t dsc;
38+ int32_t cellh;
39+ int32_t cellw;
40 } MausFont;
41
42 /* Loops through text passing parameters to glyph drawer */
+9,
-5
1@@ -59,19 +59,23 @@ typedef enum {
2 MAUS_KEY_KP_DECIMAL, MAUS_KEY_KP_DIVIDE, MAUS_KEY_KP_MULTIPLY,
3 MAUS_KEY_KP_SUBTRACT, MAUS_KEY_KP_ADD, MAUS_KEY_KP_ENTER, MAUS_KEY_KP_EQUAL,
4
5- MAUS_KEY_LAST,
6+ MAUS_KEY_LAST
7 } MausKey;
8
9 typedef struct {
10- int32_t x;
11- int32_t y;
12+ int32_t x;
13+ int32_t y;
14 } MausCursor;
15
16 typedef enum {
17 MAUS_CURSOR_STATE_VISIBLE,
18 MAUS_CURSOR_STATE_HIDDEN,
19- MAUS_CURSOR_STATE_LOCKED,
20+
21 MAUS_CURSOR_STATE_FREE,
22+ MAUS_CURSOR_STATE_LOCKED,
23+
24+ MAUS_CURSOR_STATE_ABSOLUTE,
25+ MAUS_CURSOR_STATE_RELATIVE
26 } MausCursorState;
27
28 typedef enum {
29@@ -81,7 +85,7 @@ typedef enum {
30 MAUS_MOUSE_BUTTON_RIGHT,
31 MAUS_MOUSE_BUTTON_SCROLL_UP,
32 MAUS_MOUSE_BUTTON_SCROLL_DOWN,
33- MAUS_MOUSE_BUTTON_LAST,
34+ MAUS_MOUSE_BUTTON_LAST
35 } MausMouseButton;
36
37 #endif /* MAUS_KEYS_H */
+116,
-0
1@@ -0,0 +1,116 @@
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+
+8,
-9
1@@ -1,20 +1,19 @@
2 #ifndef MAUS_WIN_H
3 #define MAUS_WIN_H
4
5-#include <stdbool.h>
6 #include <stdint.h>
7
8 #include <windows.h>
9
10 typedef struct {
11- HWND hwnd;
12- HINSTANCE hInst;
13- HDC hdc;
14- HBITMAP hbm;
15- HDC memdc;
16- bool resized;
17- uint32_t rw;
18- uint32_t rh;
19+ HWND hwnd;
20+ HINSTANCE hInst;
21+ HDC hdc;
22+ HBITMAP hbm;
23+ HDC memdc;
24+ int8_t resized;
25+ uint32_t rw;
26+ uint32_t rh;
27 } MausBackend;
28
29 #endif /* MAUS_WIN_H */
+15,
-9
1@@ -1,26 +1,32 @@
2 #ifndef MAUS_X11_H
3 #define MAUS_X11_H
4
5-#include <stdbool.h>
6+#include <stdint.h>
7
8 #include <X11/Xlib.h>
9 #include <X11/extensions/XShm.h>
10
11 typedef enum {
12 MAUS_ATOM_WM_DELETE_WINDOW,
13- MAUS_ATOM_LAST,
14+ MAUS_ATOM_LAST
15 } MausX11Atoms;
16
17 typedef struct {
18- Display* display;
19- Window root;
20- Window win;
21- Atom atoms[MAUS_ATOM_LAST];
22- GC gc;
23+ Display* display;
24+ Window root;
25+ Window win;
26+ Atom atoms[MAUS_ATOM_LAST];
27+ GC gc;
28+
29+ int8_t cur_rel; /* relative cursor */
30+ int8_t ignore_warp;
31+ int32_t mouse_x;
32+ int32_t mouse_y;
33+ int8_t mouse_pos_set;
34
35- XImage* image;
36 XShmSegmentInfo shm;
37- bool shmat;
38+ int8_t shmat;
39+ XImage* image; /* TODO: XImage path */
40 } MausBackend;
41
42 #endif /* MAUS_X11_H */
+28,
-15
1@@ -22,6 +22,7 @@ static void vlog(FILE* fd, const char* fmt, va_list ap)
2 void maus_die(const char* fmt, ...)
3 {
4 va_list ap;
5+
6 va_start(ap, fmt);
7 vlog(stderr, fmt, ap);
8 va_end(ap);
9@@ -34,25 +35,29 @@ uint64_t maus_get_time_ns(void)
10 #if !defined(_WIN32)
11 struct timespec ts;
12 clock_gettime(CLOCK_MONOTONIC, &ts);
13- return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
14+ return ts.tv_sec * 1000000000 + ts.tv_nsec;
15 #else
16 static LARGE_INTEGER frequency = {0};
17+ LARGE_INTEGER counter;
18+ uint64_t sec;
19+ uint64_t rem;
20+
21 if (frequency.QuadPart == 0)
22 QueryPerformanceFrequency(&frequency);
23
24- LARGE_INTEGER counter;
25 QueryPerformanceCounter(&counter);
26
27- uint64_t sec = counter.QuadPart / frequency.QuadPart;
28- uint64_t rem = counter.QuadPart % frequency.QuadPart;
29+ sec = counter.QuadPart / frequency.QuadPart;
30+ rem = counter.QuadPart % frequency.QuadPart;
31
32- return (sec * 1000000000ULL) + ((rem * 1000000000ULL) / frequency.QuadPart);
33+ return (sec * 1000000000) + ((rem * 1000000000) / frequency.QuadPart);
34 #endif
35 }
36
37 void maus_log(FILE* fd, const char* fmt, ...)
38 {
39 va_list ap;
40+
41 va_start(ap, fmt);
42 vlog(fd, fmt, ap);
43 fputc('\n', fd);
44@@ -61,24 +66,32 @@ void maus_log(FILE* fd, const char* fmt, ...)
45
46 void maus_target_fps(Maus* mw, uint32_t fps)
47 {
48+ uint64_t ns_frame;
49+ uint64_t cur_time;
50+ uint64_t elapsed;
51+ uint64_t sleep;
52+
53+ #if !defined(_WIN32)
54+ struct timespec ts;
55+ #endif
56+
57 if (fps == 0)
58 return;
59
60- uint64_t ns_frame = 1000000000ULL / fps; /* max ns a frame can take */
61- uint64_t cur_time = maus_get_time_ns();
62- uint64_t elapsed = cur_time - mw->frame_time_last;
63+ ns_frame = 1000000000 / fps; /* max ns a frame can take */
64+ cur_time = maus_get_time_ns();
65+ elapsed = cur_time - mw->frame_time_last;
66
67 /* if early finish, sleep for the remaining time balance */
68 if (elapsed < ns_frame) {
69- uint64_t sleep = ns_frame - elapsed;
70+ sleep = ns_frame - elapsed;
71 #if !defined(_WIN32)
72- struct timespec ts;
73- ts.tv_sec = sleep / 1000000000ULL;
74- ts.tv_nsec = sleep % 1000000000ULL;
75+ ts.tv_sec = sleep / 1000000000;
76+ ts.tv_nsec = sleep % 1000000000;
77 nanosleep(&ts, NULL);
78- #else /* unix */
79- Sleep((DWORD)((sleep + 999999ULL) / 1000000ULL));
80- #endif /* platform */
81+ #else
82+ Sleep((DWORD)((sleep + 999999) / 1000000));
83+ #endif
84 }
85
86 mw->frame_time_last = maus_get_time_ns();
+177,
-122
1@@ -5,17 +5,152 @@
2 #include "maus.h"
3 #include "maus_font.h"
4
5+static void glyph_to_buf(int32_t sgx, int32_t egx, int32_t sgy, int32_t egy,
6+ int32_t gox, int32_t goy, MausGlyph* g, uint32_t col_up,
7+ uint32_t* buf, uint32_t stride);
8+
9+/* "blit" a glpyh to some buffer */
10+static void glyph_to_buf(int32_t sgx, int32_t egx, int32_t sgy, int32_t egy,
11+ int32_t gox, int32_t goy, MausGlyph* g, uint32_t col_up,
12+ uint32_t* buf, uint32_t stride)
13+{
14+ int gy;
15+ int gx;
16+ int32_t dstx;
17+
18+ uint32_t* row;
19+ int32_t offset;
20+
21+ for (gy = sgy; gy < egy; gy++) {
22+ int dsty = goy + gy;
23+
24+ /* calculate row pointer once per scanline */
25+ row = buf + (dsty * stride);
26+ offset = gy * g->w;
27+
28+ for (gx = sgx; gx < egx; gx++) {
29+ if (g->bmp[offset + gx] > 0) {
30+ dstx = gox + gx;
31+ row[dstx] = col_up;
32+ }
33+ }
34+ }
35+}
36+
37+static int8_t parse_glyphs(FILE* f, MausFont* font, char* line, size_t line_size,
38+ int32_t* encoding, int32_t* advance, int32_t* bw, int32_t* bh,
39+ int32_t* xoff, int32_t* yoff, int8_t* seen)
40+{
41+ int32_t rowbits;
42+
43+ int32_t x;
44+ int32_t y;
45+ uint64_t bits;
46+
47+ MausGlyph* g;
48+
49+ while (fgets(line, line_size, f)) {
50+ if (sscanf(line, "ENCODING %d", encoding) == 1)
51+ continue;
52+ if (sscanf(line, "DWIDTH %d", advance) == 1)
53+ continue;
54+ if (sscanf(line, "BBX %d %d %d %d", bw, bh, xoff, yoff) == 4)
55+ continue;
56+
57+ if (strncmp(line, "BITMAP", 6) == 0) {
58+ /* invalid character code
59+ TODO: just skip it */
60+ if (*encoding < 0 || *encoding >= MAUS_BDF_GLYPHS_MAX)
61+ break;
62+
63+ /* empty/invalid size */
64+ if (*bw <= 0 || *bh <= 0)
65+ break;
66+
67+ g = &font->glyphs[*encoding];
68+ free(g->bmp); /* prevent leak on hot reload */
69+ memset(g, 0, sizeof(*g));
70+
71+ g->w = *bw;
72+ g->h = *bh;
73+ g->xoff = *xoff;
74+ g->yoff = *yoff;
75+ g->adv = *advance;
76+
77+ g->bmp = calloc((size_t)(*bw) * (*bh), 1);
78+ if (!g->bmp) {
79+ fclose(f);
80+ maus_font_free(font);
81+ return 0;
82+ }
83+
84+ /* each bmp row in BDF is padded as a multiple
85+ of 8 bits. this rounds width up to the next
86+ multiple of 8 */
87+ rowbits = (*bw + 7) & ~7;
88+
89+ for (y = 0; y < *bh; y++) {
90+ /* missing row */
91+ if (!fgets(line, line_size, f)) {
92+ fclose(f);
93+ maus_font_free(font);
94+ return 0;
95+ }
96+
97+ bits = strtoull(line, NULL, 16); /* hex to bits */
98+ for (x = 0; x < *bw; x++) {
99+ int bit = rowbits - 1 - x;
100+
101+ if ((bits >> bit) & 1)
102+ g->bmp[y * (*bw) + x] = 255; /* solid */
103+ }
104+ }
105+
106+ g->valid = 1;
107+ if (*advance > font->cellw)
108+ font->cellw = *advance;
109+ *seen = 1;
110+
111+ continue;
112+ }
113+
114+ if (strncmp(line, "ENDCHAR", 7) == 0)
115+ break;
116+ }
117+
118+ return 1;
119+}
120+
121 void maus_draw_text(Maus* mw, MausFont* font, int32_t x, int32_t y,
122 const char* text, MausColor col)
123 {
124+ uint32_t col_up = MAUS_UNPACK_COL(col);
125+
126+ size_t i;
127+
128+ /* current coordinates */
129+ int32_t cx = x;
130+ int32_t cy = y;
131+
132+ /* origins to start drawing glyph from */
133+ int32_t gox;
134+ int32_t goy;
135+
136+ /* starting glyph coordinates */
137+ int32_t sgx;
138+ int32_t sgy;
139+
140+ /* ending glyph coordinates */
141+ int32_t egx;
142+ int32_t egy;
143+
144+ /* current glyph pointer */
145+ MausGlyph* g;
146+
147 if (!mw || !mw->bfb || !font || !text)
148 return;
149
150- uint32_t col_up = MAUS_UNPACK_COL(col);
151- int32_t cx = x; /* current x */
152- int32_t cy = y; /* current y */
153-
154- for (size_t i = 0; text[i] != '\0'; i++) {
155+ for (i = 0; text[i] != '\0'; i++) {
156 char c = text[i];
157
158 if (c == '\n') {
159@@ -24,7 +159,7 @@ void maus_draw_text(Maus* mw, MausFont* font, int32_t x, int32_t y,
160 continue;
161 }
162
163- MausGlyph* g = &font->glyphs[(uint8_t)c];
164+ g = &font->glyphs[(uint8_t)c];
165 if (!g->valid) {
166 /* still advance cx if character invalid */
167 cx += (font->cellw > 0 ? font->cellw : 8);
168@@ -32,70 +167,57 @@ void maus_draw_text(Maus* mw, MausFont* font, int32_t x, int32_t y,
169 }
170
171 /* origins to start drawing glyph from */
172- int32_t gox = cx + g->xoff;
173- int32_t goy = cy + font->asc - g->h - g->yoff;
174+ gox = cx + g->xoff;
175+ goy = cy + font->asc - g->h - g->yoff;
176
177 /* starting coordinates */
178- int sgx = (-gox > 0) ? -gox : 0;
179- int sgy = (-goy > 0) ? -goy : 0;
180+ sgx = (-gox > 0) ? -gox : 0;
181+ sgy = (-goy > 0) ? -goy : 0;
182
183- /* ending coordinates. if glyph runs over right/bottom, clamp it */
184- int end_gx = (mw->width - gox < g->w) ? (mw->width - gox) : g->w;
185- int end_gy = (mw->height - goy < g->h) ?(mw->height - goy) : g->h;
186+ egx = (mw->width - gox < g->w) ? (mw->width - gox) : g->w;
187+ egy = (mw->height - goy < g->h) ?(mw->height - goy) : g->h;
188
189 /* cull glyphs which start off screen */
190- if (sgx >= end_gx || sgy >= end_gy) {
191+ if (sgx >= egx || sgy >= egy) {
192 cx += g->adv;
193 continue;
194 }
195
196- /* "blit" font to framebuffer */
197- for (int gy = sgy; gy < end_gy; gy++) {
198- int dsty = goy + gy;
199-
200- /* calculate row pointer once per scanline */
201- uint32_t* row = mw->bfb + (dsty * mw->stride);
202- int offset = gy * g->w;
203-
204- for (int gx = sgx; gx < end_gx; gx++) {
205- if (g->bmp[offset + gx] > 0) {
206- int dstx = gox + gx;
207- row[dstx] = col_up;
208- }
209- }
210- }
211-
212+ glyph_to_buf(sgx, egx, sgy, egy, gox, goy, g, col_up, mw->bfb, mw->stride);
213 cx += g->adv;
214 }
215 }
216
217 MausFont* maus_font_load(const char* path)
218 {
219- FILE* fp = fopen(path, "r");
220- if (!fp) {
221+ FILE* f = fopen(path, "r");
222+ MausFont* font = calloc(1, sizeof(MausFont));
223+ char line[1024];
224+
225+ int32_t asc = -1;
226+ int32_t dsc = -1;
227+ int32_t encoding = -1;
228+ int32_t advance = 0;
229+ int32_t bw = 0; /* bmp width */
230+ int32_t bh = 0; /* bmp height */
231+ int32_t xoff = 0;
232+ int32_t yoff = 0;
233+ int8_t seen = 0;
234+
235+ int i;
236+
237+ if (!f) {
238 maus_log(stderr, "failed to load font \"%s\"", path);
239 return NULL;
240 }
241
242- MausFont* font = calloc(1, sizeof(MausFont));
243 if (!font) {
244 maus_log(stderr, "failed to calloc font");
245- fclose(fp);
246+ fclose(f);
247 return NULL;
248 }
249
250- char line[1024];
251- int asc = -1;
252- int dsc = -1;
253- int encoding = -1;
254- int advance = 0;
255- int bw = 0; /* bmp width */
256- int bh = 0; /* bmp height */
257- int xoff = 0;
258- int yoff = 0;
259- bool seen_any_glyph = 0;
260-
261- while (fgets(line, sizeof(line), fp)) {
262+ while (fgets(line, sizeof(line), f)) {
263 if (sscanf(line, "FONT_ASCENT %d", &asc) == 1)
264 continue;
265 if (sscanf(line, "FONT_DESCENT %d", &dsc) == 1)
266@@ -113,83 +235,14 @@ MausFont* maus_font_load(const char* path)
267 xoff = 0;
268 yoff = 0;
269
270- while (fgets(line, sizeof(line), fp)) {
271- if (sscanf(line, "ENCODING %d", &encoding) == 1)
272- continue;
273- if (sscanf(line, "DWIDTH %d", &advance) == 1)
274- continue;
275- if (sscanf(line, "BBX %d %d %d %d", &bw, &bh, &xoff, &yoff) == 4)
276- continue;
277-
278- if (strncmp(line, "BITMAP", 6) == 0) {
279- int rowbits;
280-
281- /* invalid character code
282- TODO: just skip it */
283- if (encoding < 0 || encoding >= MAUS_BDF_GLYPHS_MAX)
284- break;
285-
286- /* empty/invalid size */
287- if (bw <= 0 || bh <= 0)
288- break;
289-
290- MausGlyph* g = &font->glyphs[encoding];
291- free(g->bmp); /* prevent leak on hot reload */
292- memset(g, 0, sizeof(*g));
293-
294- g->w = bw;
295- g->h = bh;
296- g->xoff = xoff;
297- g->yoff = yoff;
298- g->adv = advance;
299-
300- g->bmp = calloc((size_t)bw * bh, 1);
301- if (!g->bmp) {
302- fclose(fp);
303- maus_font_free(font);
304- return NULL;
305- }
306-
307- /* each bmp row in BDF is padded as a multiple
308- of 8 bits. this rounds width up to the next
309- multiple of 8 */
310- rowbits = (bw + 7) & ~7;
311-
312- for (int y = 0; y < bh; y++) {
313- uint64_t bits;
314-
315- /* missing row */
316- if (!fgets(line, sizeof(line), fp)) {
317- fclose(fp);
318- maus_font_free(font);
319- return NULL;
320- }
321-
322- bits = strtoull(line, NULL, 16); /* hex to bits */
323- for (int x = 0; x < bw; x++) {
324- int bit = rowbits - 1 - x;
325-
326- if ((bits >> bit) & 1)
327- g->bmp[y * bw + x] = 255; /* solid */
328- }
329- }
330-
331- g->valid = true;
332- if (advance > font->cellw)
333- font->cellw = advance;
334- seen_any_glyph = true;
335-
336- continue;
337- }
338-
339- if (strncmp(line, "ENDCHAR", 7) == 0)
340- break;
341- }
342+ if (!parse_glyphs(f, font, line, sizeof(line), &encoding, &advance, &bw, &bh, &xoff, &yoff, &seen))
343+ return NULL;
344 }
345
346- fclose(fp);
347
348- if (!seen_any_glyph) {
349+ fclose(f);
350+
351+ if (!seen) {
352 free(font);
353 return NULL;
354 }
355@@ -199,7 +252,7 @@ MausFont* maus_font_load(const char* path)
356 asc = 0;
357 dsc = 0;
358
359- for (int i = 0; i < MAUS_BDF_GLYPHS_MAX; i++) {
360+ for (i = 0; i < MAUS_BDF_GLYPHS_MAX; i++) {
361 MausGlyph* g = &font->glyphs[i];
362
363 /* unloaded glpyh */
364@@ -230,10 +283,12 @@ MausFont* maus_font_load(const char* path)
365
366 void maus_font_free(MausFont* font)
367 {
368+ int i;
369+
370 if (!font)
371 return;
372
373- for (int i = 0; i < MAUS_BDF_GLYPHS_MAX; i++)
374+ for (i = 0; i < MAUS_BDF_GLYPHS_MAX; i++)
375 free(font->glyphs[i].bmp);
376
377 free(font);
+1351,
-0
1@@ -0,0 +1,1351 @@
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, ®istry_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+
+106,
-77
1@@ -10,9 +10,9 @@ typedef struct {
2 MausKey maus;
3 } KeyMapEntry;
4
5-static bool fb_create(Maus* mw);
6+static int8_t fb_create(Maus* mw);
7 static void fb_destroy(Maus* mw);
8-static bool handle_event(const MSG* msg, MausEvent* ev, Maus* mw);
9+static int8_t handle_event(const MSG* msg, MausEvent* ev, Maus* mw);
10 static MausKey vk_to_mauskey(UINT vk);
11 static UINT resolve_lr(UINT vk, LPARAM lparam);
12 static char translate_text(UINT vk, UINT scan);
13@@ -38,14 +38,16 @@ static const KeyMapEntry keymap[] = {
14 { VK_DIVIDE, MAUS_KEY_KP_DIVIDE }, { VK_DECIMAL, MAUS_KEY_KP_DECIMAL },
15 };
16
17-static bool fb_create(Maus* mw)
18+static int8_t fb_create(Maus* mw)
19 {
20 MausBackend* be = &mw->backend;
21+ BITMAPINFO bmi = {0};
22+ HDC dc = GetDC(NULL);
23+
24 be->hbm = NULL;
25 mw->fb = NULL;
26 mw->stride = 0;
27
28- BITMAPINFO bmi = {0};
29 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
30 bmi.bmiHeader.biWidth = mw->width;
31 bmi.bmiHeader.biHeight = -mw->height;
32@@ -53,7 +55,6 @@ static bool fb_create(Maus* mw)
33 bmi.bmiHeader.biBitCount = 32;
34 bmi.bmiHeader.biCompression = BI_RGB;
35
36- HDC dc = GetDC(NULL);
37 be->memdc = CreateCompatibleDC(dc);
38 be->hbm = CreateDIBSection(dc, &bmi, DIB_RGB_COLORS, (void**)&mw->fb, NULL, 0);
39 ReleaseDC(NULL, dc);
40@@ -62,13 +63,13 @@ static bool fb_create(Maus* mw)
41 if (be->memdc)
42 DeleteDC(be->memdc);
43 maus_log(stderr, "CreateDIBSection failed");
44- return false;
45+ return 0;
46 }
47
48 SelectObject(be->memdc, be->hbm);
49
50 mw->stride = mw->width;
51- return true;
52+ return 1;
53 }
54
55 static void fb_destroy(Maus* mw)
56@@ -88,7 +89,7 @@ static void fb_destroy(Maus* mw)
57 mw->stride = 0;
58 }
59
60-static bool handle_event(const MSG* msg, MausEvent* ev, Maus* mw)
61+static int8_t handle_event(const MSG* msg, MausEvent* ev, Maus* mw)
62 {
63 UINT scan;
64 UINT vk;
65@@ -98,52 +99,52 @@ static bool handle_event(const MSG* msg, MausEvent* ev, Maus* mw)
66 switch (msg->message) {
67 case WM_QUIT:
68 ev->type = MAUS_EV_CLOSE;
69- return true;
70+ return 1;
71
72 case WM_MOUSEMOVE:
73 ev->type = MAUS_EV_MOUSE_MOTION;
74 ev->mouse.motion.x = GET_X_LPARAM(msg->lParam);
75 ev->mouse.motion.y = GET_Y_LPARAM(msg->lParam);
76- return true;
77+ return 1;
78
79 case WM_LBUTTONDOWN:
80 ev->type = MAUS_EV_MOUSE_BUTTON;
81 ev->mouse.button.button = MAUS_MOUSE_BUTTON_LEFT;
82- ev->mouse.button.pressed = true;
83- mw->mouse_buttons[MAUS_MOUSE_BUTTON_LEFT] = true;
84- return true;
85+ ev->mouse.button.pressed = 1;
86+ mw->mouse_buttons[MAUS_MOUSE_BUTTON_LEFT] = 1;
87+ return 1;
88 case WM_LBUTTONUP:
89 ev->type = MAUS_EV_MOUSE_BUTTON;
90 ev->mouse.button.button = MAUS_MOUSE_BUTTON_LEFT;
91- ev->mouse.button.pressed = false;
92- mw->mouse_buttons[MAUS_MOUSE_BUTTON_LEFT] = false;
93- return true;
94+ ev->mouse.button.pressed = 0;
95+ mw->mouse_buttons[MAUS_MOUSE_BUTTON_LEFT] = 0;
96+ return 1;
97
98 case WM_RBUTTONDOWN:
99 ev->type = MAUS_EV_MOUSE_BUTTON;
100 ev->mouse.button.button = MAUS_MOUSE_BUTTON_RIGHT;
101- ev->mouse.button.pressed = true;
102- mw->mouse_buttons[MAUS_MOUSE_BUTTON_RIGHT] = true;
103- return true;
104+ ev->mouse.button.pressed = 1;
105+ mw->mouse_buttons[MAUS_MOUSE_BUTTON_RIGHT] = 1;
106+ return 1;
107 case WM_RBUTTONUP:
108 ev->type = MAUS_EV_MOUSE_BUTTON;
109 ev->mouse.button.button = MAUS_MOUSE_BUTTON_RIGHT;
110- ev->mouse.button.pressed = false;
111- mw->mouse_buttons[MAUS_MOUSE_BUTTON_RIGHT] = false;
112- return true;
113+ ev->mouse.button.pressed = 0;
114+ mw->mouse_buttons[MAUS_MOUSE_BUTTON_RIGHT] = 0;
115+ return 1;
116
117 case WM_MBUTTONDOWN:
118 ev->type = MAUS_EV_MOUSE_BUTTON;
119 ev->mouse.button.button = MAUS_MOUSE_BUTTON_MIDDLE;
120- ev->mouse.button.pressed = true;
121- mw->mouse_buttons[MAUS_MOUSE_BUTTON_MIDDLE] = true;
122- return true;
123+ ev->mouse.button.pressed = 1;
124+ mw->mouse_buttons[MAUS_MOUSE_BUTTON_MIDDLE] = 1;
125+ return 1;
126 case WM_MBUTTONUP:
127 ev->type = MAUS_EV_MOUSE_BUTTON;
128 ev->mouse.button.button = MAUS_MOUSE_BUTTON_MIDDLE;
129- ev->mouse.button.pressed = false;
130- mw->mouse_buttons[MAUS_MOUSE_BUTTON_MIDDLE] = false;
131- return true;
132+ ev->mouse.button.pressed = 0;
133+ mw->mouse_buttons[MAUS_MOUSE_BUTTON_MIDDLE] = 0;
134+ return 1;
135
136 case WM_MOUSEWHEEL:
137 delta = GET_WHEEL_DELTA_WPARAM(msg->wParam);
138@@ -151,8 +152,8 @@ static bool handle_event(const MSG* msg, MausEvent* ev, Maus* mw)
139 : MAUS_MOUSE_BUTTON_SCROLL_DOWN;
140 ev->type = MAUS_EV_MOUSE_BUTTON;
141 ev->mouse.button.button = mbtype;
142- ev->mouse.button.pressed = true;
143- return true;
144+ ev->mouse.button.pressed = 1;
145+ return 1;
146
147 case WM_KEYDOWN:
148 case WM_SYSKEYDOWN:
149@@ -161,15 +162,15 @@ static bool handle_event(const MSG* msg, MausEvent* ev, Maus* mw)
150
151 ev->type = MAUS_EV_KEY;
152 ev->key.code = (uint32_t)msg->wParam;
153- ev->key.pressed = true;
154+ ev->key.pressed = 1;
155 ev->key.key = vk_to_mauskey(vk);
156 ev->key.text = translate_text((UINT)msg->wParam, scan);
157
158 if (ev->key.code < MAUS_KEYCODE_LAST)
159- mw->key_codes[ev->key.code] = true;
160+ mw->key_codes[ev->key.code] = 1;
161 if (ev->key.key != MAUS_KEY_NONE)
162- mw->key_syms[ev->key.key] = true;
163- return true;
164+ mw->key_syms[ev->key.key] = 1;
165+ return 1;
166
167 case WM_KEYUP:
168 case WM_SYSKEYUP:
169@@ -177,18 +178,18 @@ static bool handle_event(const MSG* msg, MausEvent* ev, Maus* mw)
170
171 ev->type = MAUS_EV_KEY;
172 ev->key.code = (uint32_t)msg->wParam;
173- ev->key.pressed = false;
174+ ev->key.pressed = 0;
175 ev->key.key = vk_to_mauskey(vk);
176 ev->key.text = 0;
177
178 if (ev->key.code < MAUS_KEYCODE_LAST)
179- mw->key_codes[ev->key.code] = false;
180+ mw->key_codes[ev->key.code] = 0;
181 if (ev->key.key != MAUS_KEY_NONE)
182- mw->key_syms[ev->key.key] = false;
183- return true;
184+ mw->key_syms[ev->key.key] = 0;
185+ return 1;
186 }
187
188- return false;
189+ return 0;
190 }
191
192 static MausKey vk_to_mauskey(UINT vk)
193@@ -228,11 +229,13 @@ static UINT resolve_lr(UINT vk, LPARAM lparam)
194 static char translate_text(UINT vk, UINT scan)
195 {
196 BYTE state[256];
197+ WCHAR buf[4];
198+ int n;
199+
200+ n = ToUnicode(vk, scan, state, buf, 4, 0);
201+
202 if (!GetKeyboardState(state))
203 return 0;
204-
205- WCHAR buf[4];
206- int n = ToUnicode(vk, scan, state, buf, 4, 0);
207 if (n == 1 && buf[0] < 0x80)
208 return (buf[0] == '\r') ? '\n' : (char)buf[0];
209
210@@ -241,16 +244,19 @@ static char translate_text(UINT vk, UINT scan)
211
212 static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
213 {
214+ Maus* mw;
215+ MausBackend* be;
216+
217 if (msg == WM_DESTROY) {
218 PostQuitMessage(EXIT_SUCCESS);
219 return 0;
220 }
221
222 if (msg == WM_SIZE) {
223- Maus* mw = (Maus*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
224+ mw = (Maus*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
225 if (mw) {
226- MausBackend* be = &mw->backend;
227- be->resized = true;
228+ be = &mw->backend;
229+ be->resized = 1;
230 be->rw = LOWORD(lp);
231 be->rh = HIWORD(lp);
232 }
233@@ -264,20 +270,27 @@ void maus_clear(Maus* mw, MausColor col)
234 {
235 uint32_t col_up = MAUS_UNPACK_COL(col);
236 uint32_t pxs = mw->height * mw->width;
237- for (uint32_t i = 0; i < pxs; i++)
238+ uint32_t i;
239+
240+ for (i = 0; i < pxs; i++)
241 mw->bfb[i] = col_up;
242 }
243
244 void maus_clipboard_set_text(Maus* mw, const char* text)
245 {
246 MausBackend* be = &mw->backend;
247+ size_t len = strlen(text) + 1;
248+ HGLOBAL hmem;
249+
250+ void* ptr;
251+
252 if (!text || !OpenClipboard(be->hwnd))
253 return;
254+
255 EmptyClipboard();
256- size_t len = strlen(text) + 1;
257- HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE, len);
258+ hmem = GlobalAlloc(GMEM_MOVEABLE, len);
259 if (hmem) {
260- void* ptr = GlobalLock(hmem);
261+ ptr = GlobalLock(hmem);
262 if (ptr) {
263 memcpy(ptr, text, len);
264 GlobalUnlock(hmem);
265@@ -296,23 +309,28 @@ void maus_clipboard_set_text(Maus* mw, const char* text)
266 char* maus_clipboard_get_text(Maus* mw)
267 {
268 MausBackend* be = &mw->backend;
269+ HANDLE hmem;
270+
271+ const char* text;
272+ size_t len;
273+
274 if (!OpenClipboard(be->hwnd))
275 return NULL;
276
277- HANDLE hmem = GetClipboardData(CF_TEXT);
278+ hmem = GetClipboardData(CF_TEXT);
279 if (!hmem) {
280 CloseClipboard();
281 return NULL;
282 }
283
284- const char* text = GlobalLock(hmem);
285+ text = GlobalLock(hmem);
286 if (text) {
287 if (mw->clipboard) {
288 free(mw->clipboard);
289 mw->clipboard = NULL;
290 }
291
292- size_t len = strlen(text) + 1;
293+ len = strlen(text) + 1;
294 mw->clipboard = malloc(len);
295 if (mw->clipboard)
296 memcpy(mw->clipboard, text, len);
297@@ -327,6 +345,7 @@ char* maus_clipboard_get_text(Maus* mw)
298 void maus_close(Maus* mw)
299 {
300 MausBackend* be = &mw->backend;
301+
302 fb_destroy(mw);
303 if (mw->bfb) {
304 free(mw->bfb);
305@@ -340,34 +359,35 @@ void maus_close(Maus* mw)
306 (void) maus_close_window(mw);
307 }
308
309-bool maus_close_window(Maus* mw)
310+int8_t maus_close_window(Maus* mw)
311 {
312 MausBackend* be = &mw->backend;
313
314 if (be->hwnd) {
315 DestroyWindow(be->hwnd);
316 be->hwnd = NULL;
317- return true;
318+ return 1;
319 }
320
321- return false;
322+ return 0;
323 }
324
325
326-bool maus_create_window(Maus* mw)
327+int8_t maus_create_window(Maus* mw)
328 {
329 MausBackend* be = &mw->backend;
330 be->hInst = GetModuleHandle(NULL);
331-
332 WNDCLASS wc = {0};
333+
334+ RECT r = { 0, 0, mw->width, mw->height };
335+
336 wc.lpfnWndProc = WndProc;
337 wc.hInstance = be->hInst;
338 wc.lpszClassName = "MausWindow";
339 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
340 if (!RegisterClass(&wc))
341- return false;
342+ return 0;
343
344- RECT r = { 0, 0, mw->width, mw->height };
345 AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE);
346
347 be->hwnd = CreateWindowEx(
348@@ -378,12 +398,12 @@ bool maus_create_window(Maus* mw)
349 );
350
351 if (!be->hwnd)
352- return false;
353+ return 0;
354
355 SetWindowLongPtr(be->hwnd, GWLP_USERDATA, (LONG_PTR)mw);
356 ShowWindow(be->hwnd, SW_SHOW);
357 UpdateWindow(be->hwnd);
358- return true;
359+ return 1;
360 }
361
362 Maus* maus_init(const char* title, int x, int y, int width, int height)
363@@ -418,29 +438,30 @@ Maus* maus_init(const char* title, int x, int y, int width, int height)
364 return mw;
365 }
366
367-bool maus_event_poll(Maus* mw, MausEvent* ev)
368+int8_t maus_event_poll(Maus* mw, MausEvent* ev)
369 {
370 MausBackend* be = &mw->backend;
371 MSG msg;
372+
373 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
374 TranslateMessage(&msg);
375 DispatchMessage(&msg);
376 ev->type = MAUS_EV_NONE;
377
378 if (handle_event(&msg, ev, mw))
379- return true;
380+ return 1;
381 }
382
383 /* WM_SIZE doesnt is handled separately */
384 if (be->resized) {
385- be->resized = false;
386+ be->resized = 0;
387 ev->type = MAUS_EV_RESIZE;
388 ev->resize.width = be->rw;
389 ev->resize.height = be->rh;
390- return true;
391+ return 1;
392 }
393
394- return false;
395+ return 0;
396 }
397
398 void maus_event_wait(Maus* mw, MausEvent* ev)
399@@ -448,8 +469,10 @@ void maus_event_wait(Maus* mw, MausEvent* ev)
400 MausBackend* be = &mw->backend;
401 MSG msg;
402
403+ int r;
404+
405 for (;;) {
406- int r = GetMessage(&msg, NULL, 0, 0);
407+ r = GetMessage(&msg, NULL, 0, 0);
408 if (r <= 0) {
409 ev->type = MAUS_EV_CLOSE;
410 return;
411@@ -461,7 +484,7 @@ void maus_event_wait(Maus* mw, MausEvent* ev)
412
413 /* WM_SIZE doesnt is handled separately */
414 if (be->resized) {
415- be->resized = false;
416+ be->resized = 0;
417 ev->type = MAUS_EV_RESIZE;
418 ev->resize.width = be->rw;
419 ev->resize.height = be->rh;
420@@ -476,22 +499,27 @@ void maus_event_wait(Maus* mw, MausEvent* ev)
421 void maus_present(Maus* mw)
422 {
423 MausBackend* be = &mw->backend;
424+ HDC wdc;
425+
426+ uint32_t bytes;
427+
428 if (!be->hwnd || !be->memdc)
429 return;
430- HDC wdc = GetDC(be->hwnd);
431
432- uint32_t bytes = mw->stride * mw->height * sizeof(uint32_t);
433+ wdc = GetDC(be->hwnd);
434+
435+ bytes = mw->stride * mw->height * sizeof(uint32_t);
436 memcpy(mw->fb, mw->bfb, bytes);
437
438 BitBlt(wdc, 0, 0, mw->width, mw->height, be->memdc, 0, 0, SRCCOPY);
439 ReleaseDC(be->hwnd, wdc);
440 }
441
442-bool maus_resize(Maus* mw, uint32_t width, uint32_t height)
443+int8_t maus_resize(Maus* mw, uint32_t width, uint32_t height)
444 {
445 if (width == 0 || height == 0 ||
446- (mw->width == width && mw->height == height))
447- return false;
448+ (mw->width == width && mw->height == height))
449+ return 0;
450
451 fb_destroy(mw);
452 if (mw->bfb) {
453@@ -503,13 +531,13 @@ bool maus_resize(Maus* mw, uint32_t width, uint32_t height)
454 mw->height = height;
455
456 if (!fb_create(mw))
457- return false;
458+ return 0;
459
460 mw->bfb = calloc(mw->stride * mw->height, sizeof(uint32_t));
461 if (!mw->bfb)
462- return false;
463+ return 0;
464
465- return true;
466+ return 1;
467 }
468
469 void maus_cur_set_mode(Maus* mw, MausCursorState state)
470@@ -517,6 +545,8 @@ void maus_cur_set_mode(Maus* mw, MausCursorState state)
471 MausBackend* be = &mw->backend;
472 HWND hwnd = be->hwnd;
473
474+ RECT r;
475+
476 if (!hwnd) {
477 maus_log(stderr, "hwnd is NULL");
478 return;
479@@ -537,7 +567,6 @@ void maus_cur_set_mode(Maus* mw, MausCursorState state)
480
481 /* lock cursor */
482 if (state == MAUS_CURSOR_STATE_LOCKED) {
483- RECT r;
484 GetClientRect(hwnd, &r);
485 MapWindowPoints(hwnd, NULL, (POINT*)&r, 2);
486
+195,
-90
1@@ -1,5 +1,4 @@
2 #include <limits.h>
3-#include <stdbool.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/shm.h>
7@@ -21,11 +20,11 @@ typedef struct {
8 MausKey maus;
9 } KeyMapEntry;
10
11-static bool fb_create(Maus* mw);
12-static bool fb_create_shm(Maus* mw);
13-/* TODO? static bool fb_create_ximage(Maus* mw); */
14+static int8_t fb_create(Maus* mw);
15+static int8_t fb_create_shm(Maus* mw);
16+/* TODO static int8_t fb_create_ximage(Maus* mw); */
17 static void fb_destroy(Maus* mw);
18-static bool handle_event(XEvent* xev, MausEvent* ev, Maus* mw);
19+static int8_t handle_event(XEvent* xev, MausEvent* ev, Maus* mw);
20 static MausKey keysym_to_mauskey(KeySym sym);
21 static MausMouseButton mouse_button_to_maus(int btn);
22 static int xerr(Display* dpy, XErrorEvent* ev);
23@@ -59,11 +58,12 @@ static const KeyMapEntry keymap[] = {
24
25 static int xerrored;
26
27-static bool fb_create(Maus* mw)
28+static int8_t fb_create(Maus* mw)
29 {
30 MausBackend* be = &mw->backend;
31+
32 be->image = NULL;
33- be->shmat = false;
34+ be->shmat = 0;
35 be->shm.shmid = -1;
36 be->shm.shmaddr = NULL;
37 mw->fb = NULL;
38@@ -73,43 +73,48 @@ static bool fb_create(Maus* mw)
39 }
40
41 /* allocate and store a new shm for the framebuffer */
42-static bool fb_create_shm(Maus* mw)
43+static int8_t fb_create_shm(Maus* mw)
44 {
45 MausBackend* be = &mw->backend;
46- if (!XShmQueryExtension(be->display))
47- return false;
48-
49 int scr = DefaultScreen(be->display);
50 int depth = DefaultDepth(be->display, scr);
51 Visual* vis = DefaultVisual(be->display, scr);
52+
53+ size_t size;
54+ int (*old_xerr)(Display*, XErrorEvent*);
55+
56+ if (!XShmQueryExtension(be->display))
57+ return 0;
58+
59 if (!vis) {
60 maus_log(stderr, "could not get default visual");
61- return false;
62+ return 0;
63 }
64
65 be->image = XShmCreateImage(
66 be->display, vis, depth, ZPixmap, NULL,
67 &be->shm, mw->width, mw->height
68 );
69+
70 if (!be->image) {
71 maus_log(stderr, "could not create XImage (shm)");
72- return false;
73+ return 0;
74 }
75
76 if (be->image->bits_per_pixel != 32) {
77 XDestroyImage(be->image);
78 be->image = NULL;
79 maus_log(stderr, "XImage not 32bpp");
80- return false;
81+ return 0;
82 }
83
84- size_t size = be->image->bytes_per_line * be->image->height;
85+ size = be->image->bytes_per_line * be->image->height;
86 be->shm.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
87 if (be->shm.shmid < 0) {
88 XDestroyImage(be->image);
89 be->image = NULL;
90 maus_log(stderr, "shmget() failed");
91- return false;
92+ return 0;
93 }
94
95 be->shm.shmaddr = shmat(be->shm.shmid, NULL, 0);
96@@ -118,14 +123,14 @@ static bool fb_create_shm(Maus* mw)
97 XDestroyImage(be->image);
98 be->image = NULL;
99 maus_log(stderr, "shmat() failed");
100- return false;
101+ return 0;
102 }
103
104 be->shm.readOnly = False;
105 be->image->data = be->shm.shmaddr;
106
107 xerrored = 0;
108- int (*old_xerr)(Display*, XErrorEvent*) = XSetErrorHandler(xerr);
109+ old_xerr = XSetErrorHandler(xerr);
110
111 if (!XShmAttach(be->display, &be->shm))
112 xerrored = 1;
113@@ -142,26 +147,27 @@ static bool fb_create_shm(Maus* mw)
114 be->shm.shmaddr = NULL;
115 be->shm.shmid = -1;
116 maus_log(stderr, "XShmAttach failed");
117- return false;
118+ return 0;
119 }
120
121 shmctl(be->shm.shmid, IPC_RMID, NULL);
122
123- be->shmat = true;
124+ be->shmat = 1;
125 mw->fb = (uint32_t*) be->image->data;
126 mw->stride = be->image->bytes_per_line / sizeof(uint32_t);
127
128- return true;
129+ return 1;
130 }
131
132 static void fb_destroy(Maus* mw)
133 {
134 MausBackend* be = &mw->backend;
135 Display* dpy = be->display;
136+
137 if (be->shmat) {
138 XShmDetach(dpy, &be->shm);
139 XSync(dpy, False);
140- be->shmat = false;
141+ be->shmat = 0;
142 }
143
144 if (be->image) {
145@@ -185,73 +191,85 @@ static void fb_destroy(Maus* mw)
146 mw->stride = 0;
147 }
148
149-static bool handle_event(XEvent* xev, MausEvent* ev, Maus* mw)
150+static int8_t handle_event(XEvent* xev, MausEvent* ev, Maus* mw)
151 {
152 MausBackend* be = &mw->backend;
153 uint32_t code = 0;
154 unsigned int mb;
155 MausMouseButton mbtype;
156
157+ char buf[8] = {0};
158+ int len;
159+
160+ KeySym sym;
161+
162+ XSelectionRequestEvent* req;
163+ XEvent rsp; /* response */
164+ Atom utf8_string;
165+ Atom clipboard;
166+
167+ int cx;
168+ int cy;
169+
170 switch (xev->type) {
171 case Expose:
172 if (xev->xexpose.count != 0)
173- return false;
174+ return 0;
175 ev->type = MAUS_EV_REDRAW;
176- return true;
177+ return 1;
178
179 case ClientMessage:
180 if ((Atom)xev->xclient.data.l[0] == be->atoms[MAUS_ATOM_WM_DELETE_WINDOW]) {
181 ev->type = MAUS_EV_CLOSE;
182- return true;
183+ return 1;
184 }
185 break;
186
187 case MappingNotify:
188 XRefreshKeyboardMapping(&xev->xmapping);
189- return true;
190+ return 1;
191 break;
192
193 case KeyPress: {
194 ev->type = MAUS_EV_KEY;
195 code = xev->xkey.keycode;
196 ev->key.code = code;
197- ev->key.pressed = true;
198+ ev->key.pressed = 1;
199 if (code < MAUS_KEYCODE_LAST)
200- mw->key_codes[code] = true;
201+ mw->key_codes[code] = 1;
202
203 /* grab the raw, base sym */
204- KeySym sym = XLookupKeysym(&xev->xkey, 0);
205+ sym = XLookupKeysym(&xev->xkey, 0);
206 ev->key.key = keysym_to_mauskey(sym);
207 if (ev->key.key != MAUS_KEY_NONE)
208- mw->key_syms[ev->key.key] = true;
209+ mw->key_syms[ev->key.key] = 1;
210
211- char buf[8] = {0};
212- int len = XLookupString(&xev->xkey, buf, sizeof(buf), NULL, NULL);
213+ len = XLookupString(&xev->xkey, buf, sizeof(buf), NULL, NULL);
214 if (len > 0)
215- ev->key.text = (buf[0] == '\r') ? '\n' : buf[0];
216+ ev->key.text = (buf[0] == '\r') ? '\n' : buf[0];
217 else
218- ev->key.text = 0;
219+ ev->key.text = 0;
220
221- return true;
222+ return 1;
223 }
224
225 case KeyRelease: {
226 ev->type = MAUS_EV_KEY;
227 code = xev->xkey.keycode;
228 ev->key.code = code;
229- ev->key.pressed = false;
230+ ev->key.pressed = 0;
231 ev->key.text = 0;
232
233 if (code < MAUS_KEYCODE_LAST)
234- mw->key_codes[code] = false;
235+ mw->key_codes[code] = 0;
236
237 /* unset base sym set on `KeyPress` */
238- KeySym sym = XLookupKeysym(&xev->xkey, 0);
239+ sym = XLookupKeysym(&xev->xkey, 0);
240 ev->key.key = keysym_to_mauskey(sym);
241 if (ev->key.key != MAUS_KEY_NONE)
242- mw->key_syms[ev->key.key] = false;
243+ mw->key_syms[ev->key.key] = 0;
244
245- return true;
246+ return 1;
247 }
248
249 case ButtonPress:
250@@ -259,37 +277,67 @@ static bool handle_event(XEvent* xev, MausEvent* ev, Maus* mw)
251 mb = xev->xbutton.button;
252 mbtype = mouse_button_to_maus(mb);
253 ev->mouse.button.button = mbtype;
254- ev->mouse.button.pressed = true;
255- mw->mouse_buttons[mbtype] = true;
256- return true;
257+ ev->mouse.button.pressed = 1;
258+ mw->mouse_buttons[mbtype] = 1;
259+ return 1;
260
261 case ButtonRelease:
262 ev->type = MAUS_EV_MOUSE_BUTTON;
263 mb = xev->xbutton.button;
264 mbtype = mouse_button_to_maus(mb);
265 ev->mouse.button.button = mbtype;
266- ev->mouse.button.pressed = false;
267- mw->mouse_buttons[mbtype] = false;
268- return true;
269+ ev->mouse.button.pressed = 0;
270+ mw->mouse_buttons[mbtype] = 0;
271+ return 1;
272
273 case MotionNotify:
274+ if (be->cur_rel) {
275+ cx = mw->width / 2;
276+ cy = mw->height / 2;
277+
278+ if (be->ignore_warp && xev->xmotion.x == cx && xev->xmotion.y == cy) {
279+ be->ignore_warp = 0;
280+ return 0;
281+ }
282+
283+ ev->type = MAUS_EV_MOUSE_MOTION;
284+ ev->mouse.motion.x = xev->xmotion.x - cx;
285+ ev->mouse.motion.y = xev->xmotion.y - cy;
286+ ev->mouse.motion.dx = ev->mouse.motion.x;
287+ ev->mouse.motion.dy = ev->mouse.motion.y;
288+
289+ if (ev->mouse.motion.x != 0 || ev->mouse.motion.y != 0) {
290+ be->ignore_warp = 1;
291+ XWarpPointer(
292+ be->display, None, be->win,
293+ 0, 0, 0, 0, cx, cy
294+ );
295+ XFlush(be->display);
296+ }
297+
298+ return ev->mouse.motion.x != 0 || ev->mouse.motion.y != 0;
299+ }
300 ev->type = MAUS_EV_MOUSE_MOTION;
301 ev->mouse.motion.x = xev->xmotion.x;
302 ev->mouse.motion.y = xev->xmotion.y;
303- return true;
304+ ev->mouse.motion.dx = be->mouse_pos_set ? xev->xmotion.x - be->mouse_x : 0;
305+ ev->mouse.motion.dy = be->mouse_pos_set ? xev->xmotion.y - be->mouse_y : 0;
306+ be->mouse_x = xev->xmotion.x;
307+ be->mouse_y = xev->xmotion.y;
308+ be->mouse_pos_set = 1;
309+ return 1;
310
311 case ConfigureNotify:
312 ev->type = MAUS_EV_RESIZE;
313 ev->resize.width = xev->xconfigure.width;
314 ev->resize.height = xev->xconfigure.height;
315- return true;
316+ return 1;
317
318 case SelectionRequest: {
319- XSelectionRequestEvent* req = &xev->xselectionrequest;
320- XEvent rsp; /* response */
321+ req = &xev->xselectionrequest;
322
323- Atom utf8_string = XInternAtom(be->display, "UTF8_STRING", False);
324- Atom clipboard = XInternAtom(be->display, "CLIPBOARD", False);
325+ utf8_string = XInternAtom(be->display, "UTF8_STRING", False);
326+ clipboard = XInternAtom(be->display, "CLIPBOARD", False);
327
328 rsp.type = SelectionNotify;
329 rsp.xselection.display = req->display;
330@@ -317,15 +365,17 @@ static bool handle_event(XEvent* xev, MausEvent* ev, Maus* mw)
331 XSendEvent(req->display, req->requestor, False, 0, &rsp);
332 XFlush(be->display);
333
334- return false; /* skip maus polling it */
335+ return 0; /* skip maus polling it */
336 }
337 }
338
339- return false;
340+ return 0;
341 }
342
343 static MausKey keysym_to_mauskey(KeySym sym)
344 {
345+ size_t i;
346+
347 if (sym >= 0x20 && sym <= 0x7E)
348 return (MausKey)sym;
349
350@@ -334,7 +384,7 @@ static MausKey keysym_to_mauskey(KeySym sym)
351 if (sym >= XK_KP_0 && sym <= XK_KP_9)
352 return MAUS_KEY_KP_0 + (sym - XK_KP_0);
353
354- for (size_t i = 0; i < sizeof(keymap)/ sizeof(keymap[0]); i++) {
355+ for (i = 0; i < sizeof(keymap)/ sizeof(keymap[0]); i++) {
356 if (keymap[i].x11 == sym)
357 return keymap[i].maus;
358 }
359@@ -365,6 +415,8 @@ static int xerr(Display* dpy, XErrorEvent* ev)
360 void maus_clipboard_set_text(Maus* mw, const char* text)
361 {
362 MausBackend* be = &mw->backend;
363+ Atom clipboard;
364+
365 if (!be->display || be->win == None)
366 return;
367
368@@ -377,7 +429,7 @@ void maus_clipboard_set_text(Maus* mw, const char* text)
369 if (text)
370 mw->clipboard = maus_strdup(text);
371
372- Atom clipboard = XInternAtom(be->display, "CLIPBOARD", False);
373+ clipboard = XInternAtom(be->display, "CLIPBOARD", False);
374 XSetSelectionOwner(be->display, clipboard, be->win, CurrentTime);
375 XFlush(be->display);
376 }
377@@ -389,6 +441,19 @@ char* maus_clipboard_get_text(Maus* mw)
378 Atom utf8_string = XInternAtom(be->display, "UTF8_STRING", False);
379 Atom maus_clipboard_prop = XInternAtom(be->display, "MAUS_CLIPBOARD_PROP", False);
380
381+ XEvent xev;
382+ int8_t ok = 0;
383+
384+ int timeout;
385+
386+ Atom actual_type;
387+ int actual_fmt;
388+ unsigned long nitems;
389+ unsigned long bytes_after;
390+ unsigned char* prop_data = NULL;
391+
392+ char* res = NULL;
393+
394 /* fetch clipboard data to `maus_clipboard_prop`
395 window property */
396 XConvertSelection(
397@@ -398,12 +463,10 @@ char* maus_clipboard_get_text(Maus* mw)
398 XFlush(be->display);
399
400 /* check for selection response */
401- XEvent xev;
402- bool ok = false;
403- for (int timeout = 0; timeout < 10000; timeout++) {
404+ for (timeout = 0; timeout < 10000; timeout++) {
405 if (XCheckTypedWindowEvent(be->display, be->win, SelectionNotify, &xev)) {
406 if (xev.xselection.property != None)
407- ok = true;
408+ ok = 1;
409 break;
410 }
411 }
412@@ -411,18 +474,12 @@ char* maus_clipboard_get_text(Maus* mw)
413 return NULL;
414
415 /* read string off property */
416- Atom actual_type;
417- int actual_fmt;
418- unsigned long nitems;
419- unsigned long bytes_after;
420- unsigned char* prop_data = NULL;
421 XGetWindowProperty(
422 be->display, be->win, maus_clipboard_prop, 0,LONG_MAX,
423 True, utf8_string, &actual_type, &actual_fmt, &nitems,
424 &bytes_after, &prop_data
425 );
426
427- char* res = NULL;
428 if (prop_data) {
429 res = maus_strdup((char*)prop_data);
430 XFree(prop_data);
431@@ -434,6 +491,7 @@ char* maus_clipboard_get_text(Maus* mw)
432 void maus_close(Maus* mw)
433 {
434 MausBackend* be = &mw->backend;
435+
436 fb_destroy(mw);
437 if (mw->bfb) {
438 free(mw->bfb);
439@@ -450,9 +508,10 @@ void maus_close(Maus* mw)
440 XCloseDisplay(be->display);
441 }
442
443-bool maus_close_window(Maus* mw)
444+int8_t maus_close_window(Maus* mw)
445 {
446 MausBackend* be = &mw->backend;
447+
448 if (be->gc) {
449 XFreeGC(be->display, be->gc);
450 be->gc = 0;
451@@ -463,10 +522,10 @@ bool maus_close_window(Maus* mw)
452 XDestroyWindow(be->display, be->win);
453 }
454
455- return true;
456+ return 1;
457 }
458
459-bool maus_create_window(Maus* mw)
460+int8_t maus_create_window(Maus* mw)
461 {
462 MausBackend* be = &mw->backend;
463 Display* dpy = be->display;
464@@ -480,12 +539,13 @@ bool maus_create_window(Maus* mw)
465 );
466
467 if (*win == None)
468- return false;
469+ return 0;
470
471 XSelectInput(dpy, *win,
472 ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask |
473 ButtonReleaseMask | PointerMotionMask | StructureNotifyMask
474 );
475+
476 /* no black flashing when resizing */
477 XSetWindowBackgroundPixmap(dpy, *win, None);
478
479@@ -502,36 +562,44 @@ bool maus_create_window(Maus* mw)
480 if (!be->gc) {
481 maus_log(stderr, "failed to create window GC");
482 maus_close_window(mw);
483- return false;
484+ return 0;
485 }
486
487- return true;
488+ return 1;
489 }
490
491 void maus_clear(Maus* mw, MausColor col)
492 {
493 uint32_t col_up = MAUS_UNPACK_COL(col);
494 uint32_t pxs = mw->height * mw->width;
495- for (uint32_t i = 0; i < pxs; i++)
496+ uint32_t i;
497+ for (i = 0; i < pxs; i++)
498 mw->bfb[i] = col_up;
499 }
500
501 Maus* maus_init(const char* title, int x, int y, int width, int height)
502 {
503+ Display* d = XOpenDisplay(NULL);
504+ Maus* mw = calloc(1, sizeof(Maus));
505+ MausBackend* be = &mw->backend;
506+
507 if (MAUS_WARN_BACKEND_AUTO_SEL)
508 maus_log(stderr, "backend auto-selected: X11");
509
510- Display* d = XOpenDisplay(NULL);
511 if (!d) {
512 maus_die("failed to open X11 display");
513 return NULL;
514 }
515
516- Maus* mw = calloc(1, sizeof(Maus));
517- MausBackend* be = &mw->backend;
518 be->display = d;
519 be->root = DefaultRootWindow(d);
520 be->win = None;
521+ be->cur_rel = 0;
522+ be->ignore_warp = 0;
523+ be->mouse_x = 0;
524+ be->mouse_y = 0;
525+ be->mouse_pos_set = 0;
526+
527 mw->frame_time_last = maus_get_time_ns();
528 mw->title = title;
529 mw->width = width;
530@@ -542,7 +610,7 @@ Maus* maus_init(const char* title, int x, int y, int width, int height)
531
532 be->gc = 0;
533 be->image = NULL;
534- be->shmat = false;
535+ be->shmat = 0;
536 be->shm.shmid = -1;
537 be->shm.shmaddr = NULL;
538 if (!fb_create(mw)) {
539@@ -562,25 +630,27 @@ Maus* maus_init(const char* title, int x, int y, int width, int height)
540 return mw;
541 }
542
543-bool maus_event_poll(Maus* mw, MausEvent* ev)
544+int8_t maus_event_poll(Maus* mw, MausEvent* ev)
545 {
546 MausBackend* be = &mw->backend;
547 XEvent xev;
548+
549 while (XPending(be->display)) {
550 XNextEvent(be->display, &xev);
551 ev->type = MAUS_EV_NONE;
552 if (handle_event(&xev, ev, mw))
553- return true;
554+ return 1;
555
556 }
557
558- return false;
559+ return 0;
560 }
561
562 void maus_event_wait(Maus* mw, MausEvent* ev)
563 {
564 MausBackend* be = &mw->backend;
565 XEvent xev;
566+
567 for (;;) {
568 XNextEvent(be->display, &xev);
569 ev->type = MAUS_EV_NONE;
570@@ -592,10 +662,12 @@ void maus_event_wait(Maus* mw, MausEvent* ev)
571 void maus_present(Maus* mw)
572 {
573 MausBackend* be = &mw->backend;
574+ uint32_t bytes;
575+
576 if (!be->image || be->win == None)
577 return;
578
579- uint32_t bytes = mw->stride * mw->height * sizeof(uint32_t);
580+ bytes = mw->stride * mw->height * sizeof(uint32_t);
581 memcpy(mw->fb, mw->bfb, bytes);
582
583 XShmPutImage(
584@@ -606,12 +678,13 @@ void maus_present(Maus* mw)
585 XFlush(be->display);
586 }
587
588-bool maus_resize(Maus* mw, uint32_t width, uint32_t height)
589+int8_t maus_resize(Maus* mw, uint32_t width, uint32_t height)
590 {
591 MausBackend* be = &mw->backend;
592+
593 if (width == 0 || height == 0 ||
594 (mw->width == width && mw->height == height))
595- return false;
596+ return 0;
597
598 fb_destroy(mw);
599 if (mw->bfb) {
600@@ -626,13 +699,13 @@ bool maus_resize(Maus* mw, uint32_t width, uint32_t height)
601 XFlush(be->display);
602
603 if (!fb_create(mw))
604- return false;
605+ return 0;
606
607 mw->bfb = calloc(mw->stride * mw->height, sizeof(uint32_t));
608 if (!mw->bfb)
609- return false;
610+ return 0;
611
612- return true;
613+ return 1;
614 }
615
616 void maus_cur_set_mode(Maus* mw, MausCursorState state)
617@@ -641,6 +714,9 @@ void maus_cur_set_mode(Maus* mw, MausCursorState state)
618 Display* dpy = be->display;
619 Window win = be->win;
620
621+ Mask mask;
622+ int grab;
623+
624 if (!dpy) {
625 maus_log(stderr, "display is NULL");
626 return;
627@@ -660,7 +736,7 @@ void maus_cur_set_mode(Maus* mw, MausCursorState state)
628 /* hide cursor */
629 if (state == MAUS_CURSOR_STATE_HIDDEN) {
630 Pixmap blank_pm = XCreatePixmap(dpy, win, 1, 1, 1);
631- XColor black = {.red=0, .green=0, .blue=0};
632+ XColor black = {0, 0, 0, 0, 0, 0};
633 Cursor blank_cur = XCreatePixmapCursor(
634 dpy, blank_pm, blank_pm, &black, &black, 0, 0
635 );
636@@ -674,8 +750,8 @@ void maus_cur_set_mode(Maus* mw, MausCursorState state)
637
638 /* lock cursor */
639 if (state == MAUS_CURSOR_STATE_LOCKED) {
640- Mask mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
641- int grab = XGrabPointer(
642+ mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
643+ grab = XGrabPointer(
644 dpy, win, True, mask, GrabModeAsync,
645 GrabModeAsync, win, None, CurrentTime
646 );
647@@ -697,5 +773,34 @@ void maus_cur_set_mode(Maus* mw, MausCursorState state)
648 XFlush(dpy);
649 return;
650 }
651+
652+ /* relative cursor */
653+ if (state == MAUS_CURSOR_STATE_RELATIVE) {
654+ mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
655+ grab = XGrabPointer(
656+ dpy, win, True, mask, GrabModeAsync,
657+ GrabModeAsync, win, None, CurrentTime
658+ );
659+
660+ if (grab != GrabSuccess) {
661+ maus_log(stderr, "failed to grab mouse pointer");
662+ return;
663+ }
664+
665+ be->cur_rel = 1;
666+ be->ignore_warp = 1;
667+ XWarpPointer(dpy, None, win, 0, 0, 0, 0, mw->width/2, mw->height/2);
668+ XFlush(dpy);
669+ return;
670+ }
671+
672+ /* absolute cursor */
673+ if (state == MAUS_CURSOR_STATE_ABSOLUTE) {
674+ be->cur_rel = 0;
675+ be->ignore_warp = 0;
676+ XUngrabPointer(dpy, CurrentTime);
677+ XFlush(dpy);
678+ return;
679+ }
680 }
681
+4,
-2
1@@ -5,11 +5,13 @@
2
3 char* maus_strdup(const char* src)
4 {
5+ size_t len;
6+ char* dst;
7 if (src == NULL)
8 return NULL;
9
10- size_t len = strlen(src);
11- char* dst = malloc(len + 1);
12+ len = strlen(src);
13+ dst = malloc(len + 1);
14 if (dst == NULL)
15 return NULL;
16