commit d433c89

uint  ·  2026-08-04 02:25:26 +0000 UTC
parent 1797ef5
X11: relative cursors
4 files changed,  +75, -2
+8, -1
 1@@ -8,6 +8,7 @@
 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@@ -45,6 +46,13 @@ void handle_ev(Maus* mw, MausEvent* ev)
10 
11 				cur_locked = !cur_locked;
12 			}
13+			if (keys[MAUS_KEY_CONTROL_L] && keys[MAUS_KEY_R]) {
14+				cur_relative ?
15+				maus_cur_set_mode(mw, MAUS_CURSOR_STATE_RELATIVE) :
16+				maus_cur_set_mode(mw, MAUS_CURSOR_STATE_ABSOLUTE);
17+
18+				cur_relative = !cur_relative;
19+			}
20 
21 			if (ev->key.pressed == false)
22 				break;
23@@ -145,4 +153,3 @@ int main(void)
24 	maus_font_free(font);
25 	maus_close(mw);
26 }
27-
+5, -1
 1@@ -70,8 +70,12 @@ typedef struct {
 2 typedef enum {
 3 	MAUS_CURSOR_STATE_VISIBLE,
 4 	MAUS_CURSOR_STATE_HIDDEN,
 5+
 6+	MAUS_CURSOR_STATE_FREE,
 7 	MAUS_CURSOR_STATE_LOCKED,
 8-	MAUS_CURSOR_STATE_FREE
 9+
10+	MAUS_CURSOR_STATE_ABSOLUTE,
11+	MAUS_CURSOR_STATE_RELATIVE
12 } MausCursorState;
13 
14 typedef enum {
+3, -0
 1@@ -18,6 +18,9 @@ typedef struct {
 2 	Atom     atoms[MAUS_ATOM_LAST];
 3 	GC       gc;
 4 
 5+	int8_t cur_rel; /* relative cursor */
 6+	int8_t ignore_warp;
 7+
 8 	XShmSegmentInfo shm;
 9 	int8_t          shmat;
10 	XImage*         image; /* TODO: XImage path */
+59, -0
 1@@ -208,6 +208,9 @@ static int8_t handle_event(XEvent* xev, MausEvent* ev, Maus* mw)
 2 	Atom utf8_string;
 3 	Atom clipboard;
 4 
 5+	int cx;
 6+	int cy;
 7+
 8 	switch (xev->type) {
 9 		case Expose:
10 			if (xev->xexpose.count != 0)
11@@ -288,6 +291,30 @@ static int8_t handle_event(XEvent* xev, MausEvent* ev, Maus* mw)
12 			return 1;
13 
14 		case MotionNotify:
15+			if (be->cur_rel) {
16+				cx = mw->width / 2;
17+				cy = mw->height / 2;
18+
19+				if (be->ignore_warp && xev->xmotion.x == cx && xev->xmotion.y == cy) {
20+					be->ignore_warp = 0;
21+					return 0;
22+				}
23+
24+				ev->type = MAUS_EV_MOUSE_MOTION;
25+				ev->mouse.motion.x = xev->xmotion.x - cx;
26+				ev->mouse.motion.y = xev->xmotion.y - cy;
27+
28+				if (ev->mouse.motion.x != 0 || ev->mouse.motion.y != 0) {
29+					be->ignore_warp = 1;
30+					XWarpPointer(
31+						be->display, None, be->win,
32+						0, 0, 0, 0, cx, cy
33+					);
34+					XFlush(be->display);
35+				}
36+
37+				return ev->mouse.motion.x != 0 || ev->mouse.motion.y != 0;
38+			}
39 			ev->type = MAUS_EV_MOUSE_MOTION;
40 			ev->mouse.motion.x = xev->xmotion.x;
41 			ev->mouse.motion.y = xev->xmotion.y;
42@@ -560,6 +587,9 @@ Maus* maus_init(const char* title, int x, int y, int width, int height)
43 	be->display = d;
44 	be->root = DefaultRootWindow(d);
45 	be->win = None;
46+	be->cur_rel = 0;
47+	be->ignore_warp = 0;
48+
49 	mw->frame_time_last = maus_get_time_ns();
50 	mw->title = title;
51 	mw->width = width;
52@@ -733,5 +763,34 @@ void maus_cur_set_mode(Maus* mw, MausCursorState state)
53 		XFlush(dpy);
54 		return;
55 	}
56+
57+	/* relative cursor */
58+	if (state == MAUS_CURSOR_STATE_RELATIVE) {
59+		mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
60+		grab = XGrabPointer(
61+			dpy, win, True, mask, GrabModeAsync,
62+			GrabModeAsync, win, None, CurrentTime
63+		);
64+
65+		if (grab != GrabSuccess) {
66+			maus_log(stderr, "failed to grab mouse pointer");
67+			return;
68+		}
69+
70+		be->cur_rel = 1;
71+		be->ignore_warp = 1;
72+		XWarpPointer(dpy, None, win, 0, 0, 0, 0, mw->width/2, mw->height/2);
73+		XFlush(dpy);
74+		return;
75+	}
76+
77+	/* absolute cursor */
78+	if (state == MAUS_CURSOR_STATE_ABSOLUTE) {
79+		be->cur_rel = 0;
80+		be->ignore_warp = 0;
81+		XUngrabPointer(dpy, CurrentTime);
82+		XFlush(dpy);
83+		return;
84+	}
85 }
86