commit fea897c
uint
·
2026-08-03 16:42:08 +0000 UTC
parent 09086f8
Refactor to ANSI C
15 files changed,
+542,
-386
M
Makefile
+26,
-7
1@@ -1,9 +1,12 @@
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+CPPFLAGS = ${CONF_CPPFLAGS} -Iinclude -Ibuild
13 LDFLAGS = ${CONF_LDFLAGS}
14
15 LIB_NAME = build/${CONF_LIB_NAME}
16@@ -19,21 +22,37 @@ LIB_OBJS = build/maus.o \
17 all: ${LIB_NAME}
18
19 ${LIB_NAME}: ${LIB_OBJS}
20- ${AR} -rcs $@ ${LIB_OBJS}
21+ ${AR} ${ARFLAGS} $@ ${LIB_OBJS}
22
23-build/maus.o: source/maus.c
24+build/maus.o: source/maus.c include/maus.h config.mk
25 mkdir -p build
26 ${CC} ${CFLAGS} ${CPPFLAGS} -c source/maus.c -o $@
27-build/maus_font.o: source/maus_font.c
28+build/maus_font.o: source/maus_font.c include/maus.h include/maus_font.h config.mk
29 mkdir -p build
30 ${CC} ${CFLAGS} ${CPPFLAGS} -c source/maus_font.c -o $@
31-build/utils.o: source/utils.c
32+build/utils.o: source/utils.c include/utils.h
33 mkdir -p build
34 ${CC} ${CFLAGS} ${CPPFLAGS} -c source/utils.c -o $@
35-build/maus_x11.o: source/maus_x11.c
36+
37+# X11
38+build/maus_x11.o: source/maus_x11.c include/maus.h include/maus_x11.h config.mk
39 mkdir -p build
40 ${CC} ${CFLAGS} ${CPPFLAGS} -c source/maus_x11.c -o $@
41
42+# Wayland
43+build/maus_wayland.o: source/maus_wayland.c include/maus.h include/maus_wayland.h build/xdg-shell-client-protocol.h config.mk
44+ mkdir -p build
45+ ${CC} ${CFLAGS} ${CPPFLAGS} -c source/maus_wayland.c -o $@
46+build/xdg-shell-client-protocol.h:
47+ mkdir -p build
48+ wayland-scanner client-header ${PROTOS}/stable/xdg-shell/xdg-shell.xml $@
49+build/xdg-shell-protocol.c:
50+ mkdir -p build
51+ wayland-scanner private-code ${PROTOS}/stable/xdg-shell/xdg-shell.xml $@
52+build/xdg-shell-protocol.o: build/xdg-shell-protocol.c build/xdg-shell-client-protocol.h
53+ mkdir -p build
54+ ${CC} ${CFLAGS} ${CPPFLAGS} -c build/xdg-shell-protocol.c -o $@
55+
56 clean:
57 rm -rf build ${LIB_NAME} config.mk compile_flags.txt
58
+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).
+6,
-4
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
+5,
-3
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
+1,
-1
1@@ -25,7 +25,7 @@ void handle_ev(Maus* mw, MausEvent* ev)
2 case MAUS_EV_KEY: {
3 (void)0;
4
5- bool* keys = mw->key_syms;
6+ int8_t* keys = mw->key_syms;
7 if (keys[MAUS_KEY_CONTROL_L] && keys[MAUS_KEY_Q]) {
8 maus_close(mw);
9 exit(EXIT_SUCCESS);
+36,
-39
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@@ -53,7 +52,7 @@
10 ((uint32_t)(c).r << 16) | \
11 ((uint32_t)(c).g << 8) | \
12 ((uint32_t)(c).b))
13-/* ... */
14+
15 #define MAUS_PIXEL_AT(mw, x, y) ((mw)->bfb[(y) * (mw)->stride + (x)])
16
17 typedef enum {
18@@ -63,7 +62,7 @@ typedef enum {
19 MAUS_EV_MOUSE_BUTTON,
20 MAUS_EV_MOUSE_MOTION,
21 MAUS_EV_RESIZE,
22- MAUS_EV_REDRAW, /* TODO: MAUS_EV_REDRAW for windows */
23+ MAUS_EV_REDRAW /* TODO: MAUS_EV_REDRAW for windows */
24 } MausEventType;
25
26 typedef struct {
27@@ -76,31 +75,29 @@ typedef struct {
28 typedef struct {
29 MausEventType type;
30
31- union {
32- struct {
33- uint32_t code; /* raw, backend keycode */
34- MausKey key; /* logical, mapped key */
35- char text; /* translated text from key */
36- bool pressed;
37- } key;
38+ struct {
39+ uint32_t code; /* raw, backend keycode */
40+ MausKey key; /* logical, mapped key */
41+ char text; /* translated text from key */
42+ int8_t pressed;
43+ } key;
44
45+ struct {
46 struct {
47- struct {
48- MausMouseButton button;
49- bool pressed;
50- } button;
51-
52- struct {
53- int32_t x;
54- int32_t y;
55- } motion;
56- } mouse;
57+ MausMouseButton button;
58+ int8_t pressed;
59+ } button;
60
61 struct {
62- uint32_t width;
63- uint32_t height;
64- } resize;
65- };
66+ int32_t x;
67+ int32_t y;
68+ } motion;
69+ } mouse;
70+
71+ struct {
72+ uint32_t width;
73+ uint32_t height;
74+ } resize;
75 } MausEvent;
76
77 typedef struct {
78@@ -118,11 +115,11 @@ typedef struct {
79 int32_t x;
80 int32_t y;
81
82- bool key_codes[MAUS_KEYCODE_LAST]; /* physical keys */
83- bool key_syms[MAUS_KEY_LAST]; /* logical keys */
84+ int8_t key_codes[MAUS_KEYCODE_LAST]; /* physical keys */
85+ int8_t key_syms[MAUS_KEY_LAST]; /* logical keys */
86
87 MausCursor cursor;
88- bool mouse_buttons[MAUS_MOUSE_BUTTON_LAST];
89+ int8_t mouse_buttons[MAUS_MOUSE_BUTTON_LAST];
90 } Maus;
91
92 /* clear screen with color: `col` */
93@@ -134,14 +131,14 @@ void maus_clipboard_set_text(Maus* mw, const char* text);
94 /* get text from system clipboard */
95 char* maus_clipboard_get_text(Maus* mw);
96
97-/* close a Maus. returns false on fail */
98+/* close a Maus. returns 0 on fail */
99 void maus_close(Maus* mw);
100
101-/* close a window without the whole Maus. returns false on fail */
102-bool maus_close_window(Maus* mw);
103+/* close a window without the whole Maus. returns 0 on fail */
104+int8_t maus_close_window(Maus* mw);
105
106-/* create window from Maus. returns false on fail */
107-bool maus_create_window(Maus* mw);
108+/* create window from Maus. returns 0 on fail */
109+int8_t maus_create_window(Maus* mw);
110
111 /* log message to output `fd` and die */
112 void maus_die(const char* fmt, ...);
113@@ -156,20 +153,20 @@ Maus* maus_init(const char* title, int x, int y, int width, int height);
114 void maus_log(FILE* fd, const char* fmt, ...);
115
116 /* poll for events then fill `ev` with retrieved events.
117- returns true if event polled, else false.
118+ returns 1 if event polled, else 0.
119 note: can burn cpu cycles */
120-bool maus_event_poll(Maus* mw, MausEvent* ev);
121+int8_t maus_event_poll(Maus* mw, MausEvent* ev);
122
123-/* poll for events then fill `ev` with retrieved events. returns true if event
124- polled, else false. note, thread goes to sleep until an event arrives */
125+/* poll for events then fill `ev` with retrieved events. returns 1 if event
126+ polled, else 0. note, thread goes to sleep until an event arrives */
127 void maus_event_wait(Maus* mw, MausEvent* ev);
128
129 /* present the pixelbuffer to the screen */
130 void maus_present(Maus* mw);
131
132-/* resize window to specified width and height. returns true on resize success,
133- else false */
134-bool maus_resize(Maus* mw, uint32_t width, uint32_t height);
135+/* resize window to specified width and height. returns 1 on resize success,
136+ else 0 */
137+int8_t maus_resize(Maus* mw, uint32_t width, uint32_t height);
138
139 /* cap framerate to targetted fps */
140 void maus_target_fps(Maus* mw, uint32_t fps);
+12,
-13
1@@ -2,29 +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+ MausGlyph glyphs[MAUS_BDF_GLYPHS_MAX];
31
32- int32_t asc;
33- int32_t dsc;
34- int32_t cellh;
35- int32_t cellw;
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 */
+3,
-3
1@@ -59,7 +59,7 @@ 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@@ -71,7 +71,7 @@ typedef enum {
11 MAUS_CURSOR_STATE_VISIBLE,
12 MAUS_CURSOR_STATE_HIDDEN,
13 MAUS_CURSOR_STATE_LOCKED,
14- MAUS_CURSOR_STATE_FREE,
15+ MAUS_CURSOR_STATE_FREE
16 } MausCursorState;
17
18 typedef enum {
19@@ -81,7 +81,7 @@ typedef enum {
20 MAUS_MOUSE_BUTTON_RIGHT,
21 MAUS_MOUSE_BUTTON_SCROLL_UP,
22 MAUS_MOUSE_BUTTON_SCROLL_DOWN,
23- MAUS_MOUSE_BUTTON_LAST,
24+ MAUS_MOUSE_BUTTON_LAST
25 } MausMouseButton;
26
27 #endif /* MAUS_KEYS_H */
+1,
-2
1@@ -1,7 +1,6 @@
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@@ -12,7 +11,7 @@ typedef struct {
10 HDC hdc;
11 HBITMAP hbm;
12 HDC memdc;
13- bool resized;
14+ int8_t resized;
15 uint32_t rw;
16 uint32_t rh;
17 } MausBackend;
+3,
-3
1@@ -1,14 +1,14 @@
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@@ -19,7 +19,7 @@ typedef struct {
19 GC gc;
20
21 XShmSegmentInfo shm;
22- bool shmat;
23+ int8_t shmat;
24 XImage* image; /* TODO: XImage path */
25 } MausBackend;
26
+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);
+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
+126,
-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,82 @@ 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 switch (xev->type) {
168 case Expose:
169 if (xev->xexpose.count != 0)
170- return false;
171+ return 0;
172 ev->type = MAUS_EV_REDRAW;
173- return true;
174+ return 1;
175
176 case ClientMessage:
177 if ((Atom)xev->xclient.data.l[0] == be->atoms[MAUS_ATOM_WM_DELETE_WINDOW]) {
178 ev->type = MAUS_EV_CLOSE;
179- return true;
180+ return 1;
181 }
182 break;
183
184 case MappingNotify:
185 XRefreshKeyboardMapping(&xev->xmapping);
186- return true;
187+ return 1;
188 break;
189
190 case KeyPress: {
191 ev->type = MAUS_EV_KEY;
192 code = xev->xkey.keycode;
193 ev->key.code = code;
194- ev->key.pressed = true;
195+ ev->key.pressed = 1;
196 if (code < MAUS_KEYCODE_LAST)
197- mw->key_codes[code] = true;
198+ mw->key_codes[code] = 1;
199
200 /* grab the raw, base sym */
201- KeySym sym = XLookupKeysym(&xev->xkey, 0);
202+ sym = XLookupKeysym(&xev->xkey, 0);
203 ev->key.key = keysym_to_mauskey(sym);
204 if (ev->key.key != MAUS_KEY_NONE)
205- mw->key_syms[ev->key.key] = true;
206+ mw->key_syms[ev->key.key] = 1;
207
208- char buf[8] = {0};
209- int len = XLookupString(&xev->xkey, buf, sizeof(buf), NULL, NULL);
210+ len = XLookupString(&xev->xkey, buf, sizeof(buf), NULL, NULL);
211 if (len > 0)
212- ev->key.text = (buf[0] == '\r') ? '\n' : buf[0];
213+ ev->key.text = (buf[0] == '\r') ? '\n' : buf[0];
214 else
215- ev->key.text = 0;
216+ ev->key.text = 0;
217
218- return true;
219+ return 1;
220 }
221
222 case KeyRelease: {
223 ev->type = MAUS_EV_KEY;
224 code = xev->xkey.keycode;
225 ev->key.code = code;
226- ev->key.pressed = false;
227+ ev->key.pressed = 0;
228 ev->key.text = 0;
229
230 if (code < MAUS_KEYCODE_LAST)
231- mw->key_codes[code] = false;
232+ mw->key_codes[code] = 0;
233
234 /* unset base sym set on `KeyPress` */
235- KeySym sym = XLookupKeysym(&xev->xkey, 0);
236+ sym = XLookupKeysym(&xev->xkey, 0);
237 ev->key.key = keysym_to_mauskey(sym);
238 if (ev->key.key != MAUS_KEY_NONE)
239- mw->key_syms[ev->key.key] = false;
240+ mw->key_syms[ev->key.key] = 0;
241
242- return true;
243+ return 1;
244 }
245
246 case ButtonPress:
247@@ -259,37 +274,36 @@ static bool handle_event(XEvent* xev, MausEvent* ev, Maus* mw)
248 mb = xev->xbutton.button;
249 mbtype = mouse_button_to_maus(mb);
250 ev->mouse.button.button = mbtype;
251- ev->mouse.button.pressed = true;
252- mw->mouse_buttons[mbtype] = true;
253- return true;
254+ ev->mouse.button.pressed = 1;
255+ mw->mouse_buttons[mbtype] = 1;
256+ return 1;
257
258 case ButtonRelease:
259 ev->type = MAUS_EV_MOUSE_BUTTON;
260 mb = xev->xbutton.button;
261 mbtype = mouse_button_to_maus(mb);
262 ev->mouse.button.button = mbtype;
263- ev->mouse.button.pressed = false;
264- mw->mouse_buttons[mbtype] = false;
265- return true;
266+ ev->mouse.button.pressed = 0;
267+ mw->mouse_buttons[mbtype] = 0;
268+ return 1;
269
270 case MotionNotify:
271 ev->type = MAUS_EV_MOUSE_MOTION;
272 ev->mouse.motion.x = xev->xmotion.x;
273 ev->mouse.motion.y = xev->xmotion.y;
274- return true;
275+ return 1;
276
277 case ConfigureNotify:
278 ev->type = MAUS_EV_RESIZE;
279 ev->resize.width = xev->xconfigure.width;
280 ev->resize.height = xev->xconfigure.height;
281- return true;
282+ return 1;
283
284 case SelectionRequest: {
285- XSelectionRequestEvent* req = &xev->xselectionrequest;
286- XEvent rsp; /* response */
287+ req = &xev->xselectionrequest;
288
289- Atom utf8_string = XInternAtom(be->display, "UTF8_STRING", False);
290- Atom clipboard = XInternAtom(be->display, "CLIPBOARD", False);
291+ utf8_string = XInternAtom(be->display, "UTF8_STRING", False);
292+ clipboard = XInternAtom(be->display, "CLIPBOARD", False);
293
294 rsp.type = SelectionNotify;
295 rsp.xselection.display = req->display;
296@@ -317,15 +331,17 @@ static bool handle_event(XEvent* xev, MausEvent* ev, Maus* mw)
297 XSendEvent(req->display, req->requestor, False, 0, &rsp);
298 XFlush(be->display);
299
300- return false; /* skip maus polling it */
301+ return 0; /* skip maus polling it */
302 }
303 }
304
305- return false;
306+ return 0;
307 }
308
309 static MausKey keysym_to_mauskey(KeySym sym)
310 {
311+ size_t i;
312+
313 if (sym >= 0x20 && sym <= 0x7E)
314 return (MausKey)sym;
315
316@@ -334,7 +350,7 @@ static MausKey keysym_to_mauskey(KeySym sym)
317 if (sym >= XK_KP_0 && sym <= XK_KP_9)
318 return MAUS_KEY_KP_0 + (sym - XK_KP_0);
319
320- for (size_t i = 0; i < sizeof(keymap)/ sizeof(keymap[0]); i++) {
321+ for (i = 0; i < sizeof(keymap)/ sizeof(keymap[0]); i++) {
322 if (keymap[i].x11 == sym)
323 return keymap[i].maus;
324 }
325@@ -365,6 +381,8 @@ static int xerr(Display* dpy, XErrorEvent* ev)
326 void maus_clipboard_set_text(Maus* mw, const char* text)
327 {
328 MausBackend* be = &mw->backend;
329+ Atom clipboard;
330+
331 if (!be->display || be->win == None)
332 return;
333
334@@ -377,7 +395,7 @@ void maus_clipboard_set_text(Maus* mw, const char* text)
335 if (text)
336 mw->clipboard = maus_strdup(text);
337
338- Atom clipboard = XInternAtom(be->display, "CLIPBOARD", False);
339+ clipboard = XInternAtom(be->display, "CLIPBOARD", False);
340 XSetSelectionOwner(be->display, clipboard, be->win, CurrentTime);
341 XFlush(be->display);
342 }
343@@ -389,6 +407,19 @@ char* maus_clipboard_get_text(Maus* mw)
344 Atom utf8_string = XInternAtom(be->display, "UTF8_STRING", False);
345 Atom maus_clipboard_prop = XInternAtom(be->display, "MAUS_CLIPBOARD_PROP", False);
346
347+ XEvent xev;
348+ int8_t ok = 0;
349+
350+ int timeout;
351+
352+ Atom actual_type;
353+ int actual_fmt;
354+ unsigned long nitems;
355+ unsigned long bytes_after;
356+ unsigned char* prop_data = NULL;
357+
358+ char* res = NULL;
359+
360 /* fetch clipboard data to `maus_clipboard_prop`
361 window property */
362 XConvertSelection(
363@@ -398,12 +429,10 @@ char* maus_clipboard_get_text(Maus* mw)
364 XFlush(be->display);
365
366 /* check for selection response */
367- XEvent xev;
368- bool ok = false;
369- for (int timeout = 0; timeout < 10000; timeout++) {
370+ for (timeout = 0; timeout < 10000; timeout++) {
371 if (XCheckTypedWindowEvent(be->display, be->win, SelectionNotify, &xev)) {
372 if (xev.xselection.property != None)
373- ok = true;
374+ ok = 1;
375 break;
376 }
377 }
378@@ -411,18 +440,12 @@ char* maus_clipboard_get_text(Maus* mw)
379 return NULL;
380
381 /* read string off property */
382- Atom actual_type;
383- int actual_fmt;
384- unsigned long nitems;
385- unsigned long bytes_after;
386- unsigned char* prop_data = NULL;
387 XGetWindowProperty(
388 be->display, be->win, maus_clipboard_prop, 0,LONG_MAX,
389 True, utf8_string, &actual_type, &actual_fmt, &nitems,
390 &bytes_after, &prop_data
391 );
392
393- char* res = NULL;
394 if (prop_data) {
395 res = maus_strdup((char*)prop_data);
396 XFree(prop_data);
397@@ -434,6 +457,7 @@ char* maus_clipboard_get_text(Maus* mw)
398 void maus_close(Maus* mw)
399 {
400 MausBackend* be = &mw->backend;
401+
402 fb_destroy(mw);
403 if (mw->bfb) {
404 free(mw->bfb);
405@@ -450,9 +474,10 @@ void maus_close(Maus* mw)
406 XCloseDisplay(be->display);
407 }
408
409-bool maus_close_window(Maus* mw)
410+int8_t maus_close_window(Maus* mw)
411 {
412 MausBackend* be = &mw->backend;
413+
414 if (be->gc) {
415 XFreeGC(be->display, be->gc);
416 be->gc = 0;
417@@ -463,10 +488,10 @@ bool maus_close_window(Maus* mw)
418 XDestroyWindow(be->display, be->win);
419 }
420
421- return true;
422+ return 1;
423 }
424
425-bool maus_create_window(Maus* mw)
426+int8_t maus_create_window(Maus* mw)
427 {
428 MausBackend* be = &mw->backend;
429 Display* dpy = be->display;
430@@ -480,12 +505,13 @@ bool maus_create_window(Maus* mw)
431 );
432
433 if (*win == None)
434- return false;
435+ return 0;
436
437 XSelectInput(dpy, *win,
438 ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask |
439 ButtonReleaseMask | PointerMotionMask | StructureNotifyMask
440 );
441+
442 /* no black flashing when resizing */
443 XSetWindowBackgroundPixmap(dpy, *win, None);
444
445@@ -502,33 +528,35 @@ bool maus_create_window(Maus* mw)
446 if (!be->gc) {
447 maus_log(stderr, "failed to create window GC");
448 maus_close_window(mw);
449- return false;
450+ return 0;
451 }
452
453- return true;
454+ return 1;
455 }
456
457 void maus_clear(Maus* mw, MausColor col)
458 {
459 uint32_t col_up = MAUS_UNPACK_COL(col);
460 uint32_t pxs = mw->height * mw->width;
461- for (uint32_t i = 0; i < pxs; i++)
462+ uint32_t i;
463+ for (i = 0; i < pxs; i++)
464 mw->bfb[i] = col_up;
465 }
466
467 Maus* maus_init(const char* title, int x, int y, int width, int height)
468 {
469+ Display* d = XOpenDisplay(NULL);
470+ Maus* mw = calloc(1, sizeof(Maus));
471+ MausBackend* be = &mw->backend;
472+
473 if (MAUS_WARN_BACKEND_AUTO_SEL)
474 maus_log(stderr, "backend auto-selected: X11");
475
476- Display* d = XOpenDisplay(NULL);
477 if (!d) {
478 maus_die("failed to open X11 display");
479 return NULL;
480 }
481
482- Maus* mw = calloc(1, sizeof(Maus));
483- MausBackend* be = &mw->backend;
484 be->display = d;
485 be->root = DefaultRootWindow(d);
486 be->win = None;
487@@ -542,7 +570,7 @@ Maus* maus_init(const char* title, int x, int y, int width, int height)
488
489 be->gc = 0;
490 be->image = NULL;
491- be->shmat = false;
492+ be->shmat = 0;
493 be->shm.shmid = -1;
494 be->shm.shmaddr = NULL;
495 if (!fb_create(mw)) {
496@@ -562,25 +590,27 @@ Maus* maus_init(const char* title, int x, int y, int width, int height)
497 return mw;
498 }
499
500-bool maus_event_poll(Maus* mw, MausEvent* ev)
501+int8_t maus_event_poll(Maus* mw, MausEvent* ev)
502 {
503 MausBackend* be = &mw->backend;
504 XEvent xev;
505+
506 while (XPending(be->display)) {
507 XNextEvent(be->display, &xev);
508 ev->type = MAUS_EV_NONE;
509 if (handle_event(&xev, ev, mw))
510- return true;
511+ return 1;
512
513 }
514
515- return false;
516+ return 0;
517 }
518
519 void maus_event_wait(Maus* mw, MausEvent* ev)
520 {
521 MausBackend* be = &mw->backend;
522 XEvent xev;
523+
524 for (;;) {
525 XNextEvent(be->display, &xev);
526 ev->type = MAUS_EV_NONE;
527@@ -592,10 +622,12 @@ void maus_event_wait(Maus* mw, MausEvent* ev)
528 void maus_present(Maus* mw)
529 {
530 MausBackend* be = &mw->backend;
531+ uint32_t bytes;
532+
533 if (!be->image || be->win == None)
534 return;
535
536- uint32_t bytes = mw->stride * mw->height * sizeof(uint32_t);
537+ bytes = mw->stride * mw->height * sizeof(uint32_t);
538 memcpy(mw->fb, mw->bfb, bytes);
539
540 XShmPutImage(
541@@ -606,12 +638,13 @@ void maus_present(Maus* mw)
542 XFlush(be->display);
543 }
544
545-bool maus_resize(Maus* mw, uint32_t width, uint32_t height)
546+int8_t maus_resize(Maus* mw, uint32_t width, uint32_t height)
547 {
548 MausBackend* be = &mw->backend;
549+
550 if (width == 0 || height == 0 ||
551 (mw->width == width && mw->height == height))
552- return false;
553+ return 0;
554
555 fb_destroy(mw);
556 if (mw->bfb) {
557@@ -626,13 +659,13 @@ bool maus_resize(Maus* mw, uint32_t width, uint32_t height)
558 XFlush(be->display);
559
560 if (!fb_create(mw))
561- return false;
562+ return 0;
563
564 mw->bfb = calloc(mw->stride * mw->height, sizeof(uint32_t));
565 if (!mw->bfb)
566- return false;
567+ return 0;
568
569- return true;
570+ return 1;
571 }
572
573 void maus_cur_set_mode(Maus* mw, MausCursorState state)
574@@ -641,6 +674,9 @@ void maus_cur_set_mode(Maus* mw, MausCursorState state)
575 Display* dpy = be->display;
576 Window win = be->win;
577
578+ Mask mask;
579+ int grab;
580+
581 if (!dpy) {
582 maus_log(stderr, "display is NULL");
583 return;
584@@ -660,7 +696,7 @@ void maus_cur_set_mode(Maus* mw, MausCursorState state)
585 /* hide cursor */
586 if (state == MAUS_CURSOR_STATE_HIDDEN) {
587 Pixmap blank_pm = XCreatePixmap(dpy, win, 1, 1, 1);
588- XColor black = {.red=0, .green=0, .blue=0};
589+ XColor black = {0, 0, 0, 0, 0, 0};
590 Cursor blank_cur = XCreatePixmapCursor(
591 dpy, blank_pm, blank_pm, &black, &black, 0, 0
592 );
593@@ -674,8 +710,8 @@ void maus_cur_set_mode(Maus* mw, MausCursorState state)
594
595 /* lock cursor */
596 if (state == MAUS_CURSOR_STATE_LOCKED) {
597- Mask mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
598- int grab = XGrabPointer(
599+ mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
600+ grab = XGrabPointer(
601 dpy, win, True, mask, GrabModeAsync,
602 GrabModeAsync, win, None, CurrentTime
603 );
+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