dwm-torus-20240901-5687f46.diff (7358B)
1 From bdd2dcfc0d33b894c4bddb00008f33abcd3478a5 Mon Sep 17 00:00:00 2001 2 From: Elizabeth Hunt <elizabeth@simponic.xyz> 3 Date: Sun, 1 Sep 2024 14:37:36 -0700 4 Subject: [PATCH] wrap the cursor around the monitor(s) like a torus! 5 6 --- 7 config.def.h | 3 ++ 8 config.mk | 8 +++- 9 dwm.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++- 10 3 files changed, 128 insertions(+), 3 deletions(-) 11 12 diff --git a/config.def.h b/config.def.h 13 index 9efa774..8251624 100644 14 --- a/config.def.h 15 +++ b/config.def.h 16 @@ -114,3 +114,6 @@ static const Button buttons[] = { 17 { ClkTagBar, MODKEY, Button3, toggletag, {0} }, 18 }; 19 20 +/* torus config */ 21 +static int torusenabled = 1; 22 +static int wormholedelta = 1; // how close to the edge do we get before we take a wormhole to the other side. 23 diff --git a/config.mk b/config.mk 24 index 8efca9a..5f7634f 100644 25 --- a/config.mk 26 +++ b/config.mk 27 @@ -14,6 +14,10 @@ X11LIB = /usr/X11R6/lib 28 XINERAMALIBS = -lXinerama 29 XINERAMAFLAGS = -DXINERAMA 30 31 +# Xinput extensions, comment if you don't want it 32 +XINPUTLIBS = -lXi 33 +XINPUTFLAGS = -DXINPUT 34 + 35 # freetype 36 FREETYPELIBS = -lfontconfig -lXft 37 FREETYPEINC = /usr/include/freetype2 38 @@ -23,10 +27,10 @@ FREETYPEINC = /usr/include/freetype2 39 40 # includes and libs 41 INCS = -I${X11INC} -I${FREETYPEINC} 42 -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} 43 +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XINPUTLIBS} 44 45 # flags 46 -CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} 47 +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} ${XINPUTFLAGS} 48 #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} 49 CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} 50 LDFLAGS = ${LIBS} 51 diff --git a/dwm.c b/dwm.c 52 index 67c6b2b..392496e 100644 53 --- a/dwm.c 54 +++ b/dwm.c 55 @@ -39,6 +39,9 @@ 56 #ifdef XINERAMA 57 #include <X11/extensions/Xinerama.h> 58 #endif /* XINERAMA */ 59 +#ifdef XINPUT 60 +#include <X11/extensions/XInput2.h> 61 +#endif /* XINPUT */ 62 #include <X11/Xft/Xft.h> 63 64 #include "drw.h" 65 @@ -183,12 +186,16 @@ static void mappingnotify(XEvent *e); 66 static void maprequest(XEvent *e); 67 static void monocle(Monitor *m); 68 static void motionnotify(XEvent *e); 69 +static void rawmotionnotify(XEvent *e); 70 +static void genericeventnotify(XEvent *e); 71 static void movemouse(const Arg *arg); 72 static Client *nexttiled(Client *c); 73 static void pop(Client *c); 74 static void propertynotify(XEvent *e); 75 static void quit(const Arg *arg); 76 static Monitor *recttomon(int x, int y, int w, int h); 77 +static Monitor *raycastx(Monitor *src, int y, int dx); 78 +static Monitor *raycasty(Monitor *src, int x, int dy); 79 static void resize(Client *c, int x, int y, int w, int h, int interact); 80 static void resizeclient(Client *c, int x, int y, int w, int h); 81 static void resizemouse(const Arg *arg); 82 @@ -242,6 +249,9 @@ static int sw, sh; /* X display screen geometry width, height */ 83 static int bh; /* bar height */ 84 static int lrpad; /* sum of left and right padding for text */ 85 static int (*xerrorxlib)(Display *, XErrorEvent *); 86 +#ifdef XINPUT 87 +static int xinputextensionop; 88 +#endif /* XINPUT */ 89 static unsigned int numlockmask = 0; 90 static void (*handler[LASTEvent]) (XEvent *) = { 91 [ButtonPress] = buttonpress, 92 @@ -257,7 +267,8 @@ static void (*handler[LASTEvent]) (XEvent *) = { 93 [MapRequest] = maprequest, 94 [MotionNotify] = motionnotify, 95 [PropertyNotify] = propertynotify, 96 - [UnmapNotify] = unmapnotify 97 + [UnmapNotify] = unmapnotify, 98 + [GenericEvent] = genericeventnotify, 99 }; 100 static Atom wmatom[WMLast], netatom[NetLast]; 101 static int running = 1; 102 @@ -1142,6 +1153,58 @@ motionnotify(XEvent *e) 103 mon = m; 104 } 105 106 +void 107 +genericeventnotify(XEvent *e) 108 +{ 109 + if (e->xcookie.extension == xinputextensionop && 110 + e->xcookie.evtype == XI_RawMotion) { 111 + rawmotionnotify(e); 112 + } 113 +} 114 + 115 +void 116 +rawmotionnotify(XEvent *e) 117 +{ 118 + if (torusenabled == 0) return; 119 + 120 + int x, y; 121 + if (!getrootptr(&x, &y)) return; 122 + 123 + int warpx = x; 124 + int warpy = y; 125 + if (BETWEEN(x, selmon->mx, selmon->mx + wormholedelta)) { 126 + /* ensure there's no monitor to the left */ 127 + if (recttomon(selmon->mx - 1, y, 1, 1) != selmon) 128 + return; 129 + /* take the wormhole */ 130 + Monitor *farright = raycastx(selmon, y, 1); 131 + warpx = farright->mx + farright->mw - wormholedelta - 1; 132 + } else if (BETWEEN(x, selmon->mx + selmon->mw - wormholedelta, 133 + selmon->mx + selmon->mw)) { 134 + /* ensure there's no monitor to the right */ 135 + if (recttomon(selmon->mx + selmon->mw + 1, y, 1, 1) != selmon) 136 + return; 137 + Monitor *farleft = raycastx(selmon, y, -1); 138 + warpx = farleft->mx + wormholedelta + 1; 139 + } else if (BETWEEN(y, selmon->my, selmon->my + wormholedelta)) { 140 + /* ensure there's no monitor under us */ 141 + if (recttomon(x, y, selmon->my - 1, 1) != selmon) 142 + return; 143 + Monitor *farup = raycasty(selmon, x, 1); 144 + warpy = farup->my + farup->mh - wormholedelta - 1; 145 + } else if (BETWEEN(y, selmon->my + selmon->mh - wormholedelta, 146 + selmon->my + selmon->mh)) { 147 + /* ensure there's no monitor above us */ 148 + if (recttomon(x, y, selmon->my + selmon->mh + 1, 1) != selmon) 149 + return; 150 + Monitor *fardown = raycasty(selmon, x, -1); 151 + warpy = fardown->my + wormholedelta + 1; 152 + } 153 + 154 + if (warpx != x || warpy != y) 155 + XWarpPointer(dpy, None, root, 0, 0, 0, 0, warpx, warpy); 156 +} 157 + 158 void 159 movemouse(const Arg *arg) 160 { 161 @@ -1275,6 +1338,44 @@ recttomon(int x, int y, int w, int h) 162 return r; 163 } 164 165 +Monitor * 166 +raycastx(Monitor *src, int y, int dx) 167 +{ 168 + Monitor *farthest = src; 169 + for (Monitor *m = mons; m; m = m->next) { 170 + int scansy = BETWEEN(y, m->my, m->my + m->mh); 171 + if (!scansy) { 172 + continue; 173 + } 174 + if (dx == 1 && (m->mx + m->mw > farthest->mx + farthest->mw)) { 175 + farthest = m; 176 + } 177 + if (dx == -1 && (m->mx < farthest->mx)) { 178 + farthest = m; 179 + } 180 + } 181 + return farthest; 182 +} 183 + 184 +Monitor * 185 +raycasty(Monitor *src, int x, int dy) 186 +{ 187 + Monitor *farthest = src; 188 + for (Monitor *m = mons; m; m = m->next) { 189 + int scansx = BETWEEN(x, m->mx, m->mx + m->mw); 190 + if (!scansx) { 191 + continue; 192 + } 193 + if (dy == 1 && (m->my + m->mh > farthest->my + farthest->mh)) { 194 + farthest = m; 195 + } 196 + if (dy == -1 && (m->my < farthest->my)) { 197 + farthest = m; 198 + } 199 + } 200 + return farthest; 201 +} 202 + 203 void 204 resize(Client *c, int x, int y, int w, int h, int interact) 205 { 206 @@ -1609,6 +1710,23 @@ setup(void) 207 |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; 208 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); 209 XSelectInput(dpy, root, wa.event_mask); 210 +#ifdef XINPUT 211 + /* select XInput raw motion events; we can't hook into PointerMotionMask since some windows block it. */ 212 + size_t maskbyteslen = XIMaskLen(XI_RawMotion); 213 + unsigned char *maskbytes = calloc(maskbyteslen, sizeof(unsigned char)); 214 + XISetMask(maskbytes, XI_RawMotion); 215 + XIEventMask mask; 216 + int _unused; 217 + if (!XQueryExtension(dpy, "XInputExtension", &xinputextensionop, 218 + &_unused, &_unused)) { 219 + fprintf(stderr, "XInputExtension not found"); 220 + exit(1); 221 + } 222 + mask.deviceid = XIAllMasterDevices; 223 + mask.mask_len = maskbyteslen * sizeof(unsigned char); 224 + mask.mask = maskbytes; 225 + XISelectEvents(dpy, root, &mask, 1); 226 +#endif /* XINPUT */ 227 grabkeys(); 228 focus(NULL); 229 } 230 -- 231 2.46.0 232