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