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
+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