commit e734053

uint  ·  2026-06-09 19:56:55 +0000 UTC
parent 28e217f
Separate Maus and backend impl (MausBackend)
3 files changed,  +160, -147
M maus.h
M maus.h
+26, -5
 1@@ -21,21 +21,22 @@
 2 	#define BACKEND_X11
 3 
 4 	#endif
 5-	#endif /* auto selection */
 6+#endif /* auto selection */
 7 
 8-	#if defined(BACKEND_X11)
 9+#if defined(BACKEND_X11)
10 	#include "maus_x11.h"
11 
12-	#elif defined(BACKEND_WAY)
13+#elif defined(BACKEND_WAY)
14 	/* ... */
15 
16-	#elif defined(BACKEND_WIN)
17+#elif defined(BACKEND_WIN)
18 	/* ... */
19 
20-	#elif defined(BACKEND_MAC)
21+#elif defined(BACKEND_MAC)
22 	/* ... */
23 #endif
24 
25+#define MAUS_KEYCODE_LAST (256)
26 #define MAUS_COL_ARGB(a, r, g, b) (MausColor){a, r, g, b}
27 #define MAUS_COL_RGBA(r, g, b, a) (MausColor){a, r, g, b}
28 #define MAUS_UNPACK_COL(c) \
29@@ -91,6 +92,26 @@ typedef struct {
30 	};
31 } MausEvent;
32 
33+typedef struct {
34+	MausBackend    backend;
35+
36+	uint32_t*      fb;
37+	uint32_t       stride;
38+
39+	const char*    title;
40+	uint32_t       width;
41+	uint32_t       height;
42+	int32_t        x;
43+	int32_t        y;
44+
45+	bool           key_codes[MAUS_KEYCODE_LAST]; /* physical keys */
46+	bool           key_syms[MAUS_KEY_LAST];      /* logical keys */
47+	MausKey        keymap[MAUS_KEYCODE_LAST];    /* X11 keycode->MausKey */
48+
49+	MausCursor     cursor;
50+	bool           mouse_buttons[MAUS_MOUSE_BUTTON_LAST];
51+} Maus;
52+
53 /* close a Maus. returns false on fail */
54 void maus_close(Maus* mw);
55 
+133, -121
  1@@ -11,12 +11,23 @@
  2 
  3 #include "maus.h"
  4 #include "maus_input.h"
  5+#include "maus_x11.h"
  6 
  7 typedef struct {
  8 	KeySym  x11;
  9 	MausKey maus;
 10 } KeyMapEntry;
 11 
 12+static void build_keymap(Maus* mw);
 13+static bool fb_create(Maus* mw);
 14+static bool fb_create_shm(Maus* mw);
 15+/* TODO? static bool fb_create_ximage(Maus* mw); */
 16+static void fb_destroy(Maus* mw);
 17+static bool handle_event(XEvent* xev, MausEvent* ev, Maus* mw);
 18+static MausKey keysym_to_mauskey(KeySym sym);
 19+static MausMouseButton mouse_button_to_maus(int btn);
 20+static int xerr(Display* dpy, XErrorEvent* ev);
 21+
 22 static const KeyMapEntry keymap[] = {
 23 	{ XK_BackSpace,    MAUS_KEY_BACKSPACE }, { XK_Tab,              MAUS_KEY_TAB },
 24 	{ XK_Return,       MAUS_KEY_ENTER },     { XK_Escape,           MAUS_KEY_ESCAPE },
 25@@ -46,18 +57,9 @@ static const KeyMapEntry keymap[] = {
 26 
 27 static int xerrored;
 28 
 29-static void build_keymap(Maus* mw);
 30-static bool fb_create(Maus* mw);
 31-static bool fb_create_shm(Maus* mw);
 32-/* TODO? static bool fb_create_ximage(Maus* mw); */
 33-static void fb_destroy(Maus* mw);
 34-static bool handle_event(XEvent* xev, MausEvent* ev, Maus* mw);
 35-static MausKey keysym_to_mauskey(KeySym sym);
 36-static MausMouseButton mouse_button_to_maus(int btn);
 37-static int xerr(Display* dpy, XErrorEvent* ev);
 38-
 39 static void build_keymap(Maus* mw)
 40 {
 41+	MausBackend* be = &mw->backend;
 42 	int min_code = 0;
 43 	int max_code = 0;
 44 	int syms_per_code = 0;
 45@@ -67,9 +69,9 @@ static void build_keymap(Maus* mw)
 46 	for (int i = 0; i < MAUS_KEYCODE_LAST; i++)
 47 		mw->keymap[i] = MAUS_KEY_NONE;
 48 
 49-	XDisplayKeycodes(mw->display, &min_code, &max_code);
 50+	XDisplayKeycodes(be->display, &min_code, &max_code);
 51 	KeySym* syms = XGetKeyboardMapping(
 52-		mw->display, min_code,
 53+		be->display, min_code,
 54 		max_code - min_code + 1, &syms_per_code
 55 	);
 56 	if (!syms)
 57@@ -93,12 +95,13 @@ static void build_keymap(Maus* mw)
 58 
 59 static bool fb_create(Maus* mw)
 60 {
 61-	mw->image = NULL;
 62+	MausBackend* be = &mw->backend;
 63+	be->image = NULL;
 64+	be->shmat = false;
 65+	be->shm.shmid = -1;
 66+	be->shm.shmaddr = NULL;
 67 	mw->fb = NULL;
 68 	mw->stride = 0;
 69-	mw->shmat = false;
 70-	mw->shm.shmid = -1;
 71-	mw->shm.shmaddr = NULL;
 72 
 73 	return fb_create_shm(mw);
 74 }
 75@@ -106,109 +109,110 @@ static bool fb_create(Maus* mw)
 76 /* allocate and store a new shm for the framebuffer */
 77 static bool fb_create_shm(Maus* mw)
 78 {
 79-
 80-	if (!XShmQueryExtension(mw->display))
 81+	MausBackend* be = &mw->backend;
 82+	if (!XShmQueryExtension(be->display))
 83 		return false;
 84 
 85-	int scr = DefaultScreen(mw->display);
 86-	int depth = DefaultDepth(mw->display, scr);
 87-	Visual* vis = DefaultVisual(mw->display, scr);
 88+	int scr = DefaultScreen(be->display);
 89+	int depth = DefaultDepth(be->display, scr);
 90+	Visual* vis = DefaultVisual(be->display, scr);
 91 	if (!vis) {
 92 		maus_log(stderr, "could not get default visual");
 93 		return false;
 94 	}
 95 
 96-	mw->image = XShmCreateImage(
 97-		mw->display, vis, depth, ZPixmap, NULL,
 98-		&mw->shm, mw->width, mw->height
 99+	be->image = XShmCreateImage(
100+		be->display, vis, depth, ZPixmap, NULL,
101+		&be->shm, mw->width, mw->height
102 	);
103-	if (!mw->image) {
104+	if (!be->image) {
105 		maus_log(stderr, "could not create XImage (shm)");
106 		return false;
107 	}
108 
109-	if (mw->image->bits_per_pixel != 32) {
110-		XDestroyImage(mw->image);
111-		mw->image = NULL;
112+	if (be->image->bits_per_pixel != 32) {
113+		XDestroyImage(be->image);
114+		be->image = NULL;
115 		maus_log(stderr, "XImage not 32bpp");
116 		return false;
117 	}
118 
119-	size_t size = mw->image->bytes_per_line * mw->image->height;
120-	mw->shm.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
121-	if (mw->shm.shmid < 0) {
122-		XDestroyImage(mw->image);
123-		mw->image = NULL;
124+	size_t size = be->image->bytes_per_line * be->image->height;
125+	be->shm.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
126+	if (be->shm.shmid < 0) {
127+		XDestroyImage(be->image);
128+		be->image = NULL;
129 		maus_log(stderr, "shmget() failed");
130 		return false;
131 	}
132 
133-	mw->shm.shmaddr = shmat(mw->shm.shmid, NULL, 0);
134-	if (mw->shm.shmaddr == (char*)-1) {
135-		shmctl(mw->shm.shmid, IPC_RMID, NULL);
136-		XDestroyImage(mw->image);
137-		mw->image = NULL;
138+	be->shm.shmaddr = shmat(be->shm.shmid, NULL, 0);
139+	if (be->shm.shmaddr == (char*)-1) {
140+		shmctl(be->shm.shmid, IPC_RMID, NULL);
141+		XDestroyImage(be->image);
142+		be->image = NULL;
143 		maus_log(stderr, "shmat() failed");
144 		return false;
145 	}
146 
147-	mw->shm.readOnly = False;
148-	mw->image->data = mw->shm.shmaddr;
149+	be->shm.readOnly = False;
150+	be->image->data = be->shm.shmaddr;
151 
152 	xerrored = 0;
153 	int (*old_xerr)(Display*, XErrorEvent*) = XSetErrorHandler(xerr);
154 
155-	if (!XShmAttach(mw->display, &mw->shm))
156+	if (!XShmAttach(be->display, &be->shm))
157 		xerrored = 1;
158 
159-	XSync(mw->display, False);
160+	XSync(be->display, False);
161 	XSetErrorHandler(old_xerr);
162 	if (xerrored) {
163-		shmdt(mw->shm.shmaddr);
164-		shmctl(mw->shm.shmid, IPC_RMID, NULL);
165-		XDestroyImage(mw->image);
166+		shmdt(be->shm.shmaddr);
167+		shmctl(be->shm.shmid, IPC_RMID, NULL);
168+		XDestroyImage(be->image);
169 
170-		mw->image = NULL;
171+		be->image = NULL;
172 		mw->fb = NULL;
173-		mw->shm.shmaddr = NULL;
174-		mw->shm.shmid = -1;
175+		be->shm.shmaddr = NULL;
176+		be->shm.shmid = -1;
177 		maus_log(stderr, "XShmAttach failed");
178 		return false;
179 	}
180 
181-	shmctl(mw->shm.shmid, IPC_RMID, NULL);
182+	shmctl(be->shm.shmid, IPC_RMID, NULL);
183 
184-	mw->shmat = true;
185-	mw->fb = (uint32_t*) mw->image->data;
186-	mw->stride = mw->image->bytes_per_line / sizeof(uint32_t);
187+	be->shmat = true;
188+	mw->fb = (uint32_t*) be->image->data;
189+	mw->stride = be->image->bytes_per_line / sizeof(uint32_t);
190 
191 	return true;
192 }
193 
194 static void fb_destroy(Maus* mw)
195 {
196-	Display* dpy = mw->display;
197-	if (mw->shmat) {
198-		XShmDetach(dpy, &mw->shm);
199+	MausBackend* be = &mw->backend;
200+	Display* dpy = be->display;
201+	if (be->shmat) {
202+		XShmDetach(dpy, &be->shm);
203 		XSync(dpy, False);
204-		mw->shmat = false;
205+		be->shmat = false;
206 	}
207 
208-	if (mw->image) {
209-		XDestroyImage(mw->image);
210-		mw->image = NULL;
211+	if (be->image) {
212+		XDestroyImage(be->image);
213+		be->image = NULL;
214 	}
215 
216-	if (mw->shm.shmaddr && mw->shm.shmaddr != (char*) -1) {
217-		shmdt(mw->shm.shmaddr);
218-		mw->shm.shmaddr = NULL;
219+	if (be->shm.shmaddr && be->shm.shmaddr != (char*) -1) {
220+		shmdt(be->shm.shmaddr);
221+		be->shm.shmaddr = NULL;
222 	}
223 
224 	/* normally already removed after attach but
225 	   can check anyways */
226-	if (mw->shm.shmid >= 0) {
227-		shmctl(mw->shm.shmid, IPC_RMID, NULL);
228-		mw->shm.shmid = -1;
229+	if (be->shm.shmid >= 0) {
230+		shmctl(be->shm.shmid, IPC_RMID, NULL);
231+		be->shm.shmid = -1;
232 	}
233 
234 	mw->fb = NULL;
235@@ -217,6 +221,7 @@ static void fb_destroy(Maus* mw)
236 
237 static bool handle_event(XEvent* xev, MausEvent* ev, Maus* mw)
238 {
239+	MausBackend* be = &mw->backend;
240 	uint32_t code = 0;
241 	unsigned int mb;
242 	MausMouseButton mbtype;
243@@ -224,7 +229,7 @@ static bool handle_event(XEvent* xev, MausEvent* ev, Maus* mw)
244 
245 	switch (xev->type) {
246 		case ClientMessage:
247-			if ((Atom)xev->xclient.data.l[0] == mw->atoms[MAUS_ATOM_WM_DELETE_WINDOW]) {
248+			if ((Atom)xev->xclient.data.l[0] == be->atoms[MAUS_ATOM_WM_DELETE_WINDOW]) {
249 				ev->type = MAUS_EV_CLOSE;
250 				return true;
251 			}
252@@ -316,27 +321,48 @@ static MausKey keysym_to_mauskey(KeySym sym)
253 	return MAUS_KEY_NONE;
254 }
255 
256+static MausMouseButton mouse_button_to_maus(int btn)
257+{
258+	switch (btn) {
259+		case Button1: return MAUS_MOUSE_BUTTON_LEFT;
260+		case Button2: return MAUS_MOUSE_BUTTON_MIDDLE;
261+		case Button3: return MAUS_MOUSE_BUTTON_RIGHT;
262+		case Button4: return MAUS_MOUSE_BUTTON_SCROLL_UP;
263+		case Button5: return MAUS_MOUSE_BUTTON_SCROLL_DOWN;
264+		default:      return MAUS_MOUSE_BUTTON_NONE;
265+	}
266+}
267+
268+static int xerr(Display* dpy, XErrorEvent* ev)
269+{
270+	(void) dpy;
271+	(void) ev;
272+	xerrored = 1;
273+	return 0;
274+}
275 
276 void maus_close(Maus* mw)
277 {
278+	MausBackend* be = &mw->backend;
279 	fb_destroy(mw);
280-	if (mw->win != None) {
281+	if (be->win != None) {
282 		(void) maus_close_window(mw);
283 	}
284-	if (mw->display)
285-		XCloseDisplay(mw->display);
286+	if (be->display)
287+		XCloseDisplay(be->display);
288 }
289 
290 bool maus_close_window(Maus* mw)
291 {
292-	if (mw->gc) {
293-		XFreeGC(mw->display, mw->gc);
294-		mw->gc = 0;
295+	MausBackend* be = &mw->backend;
296+	if (be->gc) {
297+		XFreeGC(be->display, be->gc);
298+		be->gc = 0;
299 	}
300 
301-	if (mw->win != None) {
302-		XUnmapWindow(mw->display, mw->win);
303-		XDestroyWindow(mw->display, mw->win);
304+	if (be->win != None) {
305+		XUnmapWindow(be->display, be->win);
306+		XDestroyWindow(be->display, be->win);
307 	}
308 
309 	return true;
310@@ -344,11 +370,12 @@ bool maus_close_window(Maus* mw)
311 
312 bool maus_create_window(Maus* mw)
313 {
314-	Display* dpy = mw->display;
315-	Window* win = &mw->win;
316+	MausBackend* be = &mw->backend;
317+	Display* dpy = be->display;
318+	Window* win = &be->win;
319 
320 	*win = XCreateSimpleWindow(
321-		dpy, mw->root,
322+		dpy, be->root,
323 		mw->x, mw->y,
324 		mw->width, mw->height,
325 		0u, 0u, 0u
326@@ -363,16 +390,16 @@ bool maus_create_window(Maus* mw)
327 	);
328 
329 	/* atoms */
330-	mw->atoms[MAUS_ATOM_WM_DELETE_WINDOW] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
331+	be->atoms[MAUS_ATOM_WM_DELETE_WINDOW] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
332 
333-	XSetWMProtocols(dpy, *win, &mw->atoms[MAUS_ATOM_WM_DELETE_WINDOW], 1);
334+	XSetWMProtocols(dpy, *win, &be->atoms[MAUS_ATOM_WM_DELETE_WINDOW], 1);
335 	XStoreName(dpy, *win, mw->title);
336 
337 	XMapWindow(dpy, *win);
338 	XFlush(dpy);
339 
340-	mw->gc = XCreateGC(dpy, *win, 0, NULL);
341-	if (!mw->gc) {
342+	be->gc = XCreateGC(dpy, *win, 0, NULL);
343+	if (!be->gc) {
344 		maus_log(stderr, "failed to create window GC");
345 		maus_close_window(mw);
346 		return false;
347@@ -402,9 +429,10 @@ Maus* maus_init(const char* title, int x, int y, int width, int height)
348 	}
349 
350 	Maus* mw = calloc(1, sizeof(Maus));
351-	mw->display = d;
352-	mw->root = DefaultRootWindow(d);
353-	mw->win = None;
354+	MausBackend* be = &mw->backend;
355+	be->display = d;
356+	be->root = DefaultRootWindow(d);
357+	be->win = None;
358 	mw->title = title;
359 	mw->width = width;
360 	mw->height = height;
361@@ -414,12 +442,11 @@ Maus* maus_init(const char* title, int x, int y, int width, int height)
362 
363 	build_keymap(mw);
364 	
365-	mw->gc = 0;
366-	mw->image = NULL;
367-	mw->fb = NULL;
368-	mw->shmat = false;
369-	mw->shm.shmid = -1;
370-	mw->shm.shmaddr = NULL;
371+	be->gc = 0;
372+	be->image = NULL;
373+	be->shmat = false;
374+	be->shm.shmid = -1;
375+	be->shm.shmaddr = NULL;
376 	if (!fb_create(mw)) {
377 		maus_log(stderr, "failed to create framebuffer");
378 		maus_close(mw);
379@@ -432,9 +459,10 @@ Maus* maus_init(const char* title, int x, int y, int width, int height)
380 
381 bool maus_event_poll(Maus* mw, MausEvent* ev)
382 {
383+	MausBackend* be = &mw->backend;
384 	XEvent xev;
385-	while (XPending(mw->display)) {
386-		XNextEvent(mw->display, &xev);
387+	while (XPending(be->display)) {
388+		XNextEvent(be->display, &xev);
389 		ev->type = MAUS_EV_NONE;
390 		if (handle_event(&xev, ev, mw))
391 			return true;
392@@ -444,31 +472,12 @@ bool maus_event_poll(Maus* mw, MausEvent* ev)
393 	return false;
394 }
395 
396-static MausMouseButton mouse_button_to_maus(int btn)
397-{
398-	switch (btn) {
399-		case Button1: return MAUS_MOUSE_BUTTON_LEFT;
400-		case Button2: return MAUS_MOUSE_BUTTON_MIDDLE;
401-		case Button3: return MAUS_MOUSE_BUTTON_RIGHT;
402-		case Button4: return MAUS_MOUSE_BUTTON_SCROLL_UP;
403-		case Button5: return MAUS_MOUSE_BUTTON_SCROLL_DOWN;
404-		default:      return MAUS_MOUSE_BUTTON_NONE;
405-	}
406-}
407-
408-static int xerr(Display* dpy, XErrorEvent* ev)
409-{
410-	(void) dpy;
411-	(void) ev;
412-	xerrored = 1;
413-	return 0;
414-}
415-
416 void maus_event_wait(Maus* mw, MausEvent* ev)
417 {
418+	MausBackend* be = &mw->backend;
419 	XEvent xev;
420 	for (;;) {
421-		XNextEvent(mw->display, &xev);
422+		XNextEvent(be->display, &xev);
423 		ev->type = MAUS_EV_NONE;
424 		if (handle_event(&xev, ev, mw))
425 			return;
426@@ -477,19 +486,21 @@ void maus_event_wait(Maus* mw, MausEvent* ev)
427 
428 void maus_present(Maus* mw)
429 {
430-	if (!mw->image || mw->win == None)
431+	MausBackend* be = &mw->backend;
432+	if (!be->image || be->win == None)
433 		return;
434 
435 	XShmPutImage(
436-		mw->display, mw->win, mw->gc, mw->image,
437+		be->display, be->win, be->gc, be->image,
438 		0, 0, 0, 0, mw->width, mw->height, False
439 	);
440 
441-	XFlush(mw->display);
442+	XFlush(be->display);
443 }
444 
445 bool maus_resize(Maus* mw, uint32_t width, uint32_t height)
446 {
447+	MausBackend* be = &mw->backend;
448 	if (width == 0 || height == 0 ||
449 	    mw->width == width || mw->height == height)
450 		return false;
451@@ -498,15 +509,16 @@ bool maus_resize(Maus* mw, uint32_t width, uint32_t height)
452 	mw->width = width;
453 	mw->height = height;
454 
455-	XSync(mw->display, False);
456-	XFlush(mw->display);
457+	XSync(be->display, False);
458+	XFlush(be->display);
459 	return fb_create(mw);
460 }
461 
462 void maus_cur_set_mode(Maus* mw, MausCursorState state)
463 {
464-	Display* dpy = mw->display;
465-	Window win = mw->win;
466+	MausBackend* be = &mw->backend;
467+	Display* dpy = be->display;
468+	Window win = be->win;
469 
470 	if (!dpy) {
471 		maus_log(stderr, "display is NULL");
+1, -21
 1@@ -2,15 +2,10 @@
 2 #define MAUS_X11_H
 3 
 4 #include <stdbool.h>
 5-#include <stdint.h>
 6 
 7 #include <X11/Xlib.h>
 8 #include <X11/extensions/XShm.h>
 9 
10-#include "maus_input.h"
11-
12-#define MAUS_KEYCODE_LAST 256
13-
14 typedef enum {
15 	MAUS_ATOM_WM_DELETE_WINDOW,
16 	MAUS_ATOM_LAST,
17@@ -26,22 +21,7 @@ typedef struct {
18 	XImage*        image;
19 	XShmSegmentInfo shm;
20 	bool           shmat;
21-	uint32_t*      fb;
22-	uint32_t       stride;
23-
24-	const char*    title;
25-	uint32_t       width;
26-	uint32_t       height;
27-	int32_t        x;
28-	int32_t        y;
29-
30-	bool           key_codes[MAUS_KEYCODE_LAST]; /* physical keys */
31-	bool           key_syms[MAUS_KEY_LAST];      /* logical keys */
32-	MausKey        keymap[MAUS_KEYCODE_LAST];    /* X11 keycode->MausKey */
33-
34-	MausCursor     cursor;
35-	bool           mouse_buttons[MAUS_MOUSE_BUTTON_LAST];
36-} Maus;
37+} MausBackend;
38 
39 #endif /* MAUS_X11_H */
40