From 33081ed8e64001a660a52d57bcfca201f6153d4d Mon Sep 17 00:00:00 2001 From: Elizabeth Hunt Date: Sun, 1 Sep 2024 13:41:17 -0700 Subject: [PATCH] initial commit --- .clang-format | 138 ++++++++++++ .gitignore | 2 + config.def.h | 3 + config.h | 128 +++++++++++ config.mk | 8 +- dwm.c | 123 ++++++++++- patch | 9 + patches/dwm-cursorwarp-20210222-61bb8b2.diff | 33 +++ patches/dwm-gaps-6.0.diff | 53 +++++ patches/dwm-torus-20240901.diff | 218 +++++++++++++++++++ 10 files changed, 712 insertions(+), 3 deletions(-) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 config.h create mode 100755 patch create mode 100644 patches/dwm-cursorwarp-20210222-61bb8b2.diff create mode 100644 patches/dwm-gaps-6.0.diff create mode 100644 patches/dwm-torus-20240901.diff diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..7eb3471 --- /dev/null +++ b/.clang-format @@ -0,0 +1,138 @@ +AccessModifierOffset: 0 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveDeclarations: + Enabled: false +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: true +# Kind: Always +# OverEmptyLines: 1 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: None +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: TopLevelDefinitions +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: [] +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BreakAfterJavaFieldAnnotations: false +#BreakArrays: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: WebKit +BreakBeforeConceptDeclarations: Always +#BreakBeforeInlineASMColon: Always +BreakBeforeTernaryOperators: false +BreakConstructorInitializers: AfterColon +BreakInheritanceList: AfterComma +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: "" +CompactNamespaces: false +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +Cpp11BracedListStyle: false +DeriveLineEnding: false +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: Never +FixNamespaceComments: true +ForEachMacros: [] +IfMacros: [] +IncludeBlocks: Preserve +IncludeIsMainRegex: "" +IncludeIsMainSourceRegex: "" +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: NoIndent +IndentGotoLabels: false +IndentPPDirectives: BeforeHash +IndentRequiresClause: false +IndentWidth: 8 +IndentWrappedFunctionNames: false +InsertBraces: true +InsertTrailingCommas: None +JavaImportGroups: [] +JavaScriptQuotes: Double +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +Language: Cpp +MacroBlockBegin: "" +MacroBlockEnd: "" +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +NamespaceMacros: [] +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 8 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true +PPIndentWidth: 0 +PackConstructorInitializers: Never +PointerAlignment: Right +QualifierAlignment: Left +RawStringFormats: [] +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +#RemoveSemicolon: false +RequiresClausePosition: OwnLine +#RequiresExpressionIndentation: Keyword +SeparateDefinitionBlocks: Always +ShortNamespaceLines: 0 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceAroundPointerQualifiers: Before +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 4 +SpacesInAngles: Never +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: 1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +StatementAttributeLikeMacros: [] +StatementMacros: [] +TabWidth: 8 +TypenameMacros: [] +UseCRLF: false +UseTab: AlignWithSpaces +#WhitespaceSensitiveMacros: [] \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..095e840 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +dwm diff --git a/config.def.h b/config.def.h index 9efa774..8251624 100644 --- a/config.def.h +++ b/config.def.h @@ -114,3 +114,6 @@ static const Button buttons[] = { { ClkTagBar, MODKEY, Button3, toggletag, {0} }, }; +/* torus config */ +static int torusenabled = 1; +static int wormholedelta = 1; // how close to the edge do we get before we take a wormhole to the other side. diff --git a/config.h b/config.h new file mode 100644 index 0000000..25994a7 --- /dev/null +++ b/config.h @@ -0,0 +1,128 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const unsigned int snap = 32; /* snap pixel */ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const char *fonts[] = { "monospace:size=10" }; +static const char dmenufont[] = "monospace:size=10"; +static const char col_gray1[] = "#222222"; +static const char col_gray2[] = "#444444"; +static const char col_gray3[] = "#bbbbbb"; +static const char col_gray4[] = "#eeeeee"; +static const char col_cyan[] = "#005577"; +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +}; + +/* tagging */ +static const char *tags[] = { "1", "2", "3", "4", "5" }; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, +}; + +/* layout(s) */ +static const float mfact = 0.50; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* key definitions */ +#define MODKEY Mod4Mask +#define TAGKEYS(KEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } + +/* commands */ +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +static const char *termcmd[] = { "st", NULL }; +static const char *editorcmd[] = { "emacs", NULL }; +static const char *browsercmd[] = { "chromium", "https://simponic.xyz/dvd-logo" }; +static const char *increasebrightnesscmd[] = { "brightnessctl", "set", "-c", "backlight", "+10%", NULL }; +static const char *decreasebrightnesscmd[] = { "brightnessctl", "set", "-c", "backlight", "10%-", NULL }; + +static const Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY|ShiftMask, XK_b, spawn, {.v = browsercmd } }, + { MODKEY|ShiftMask, XK_e, spawn, {.v = editorcmd } }, + { MODKEY|ShiftMask, XK_w, spawn, {.v = increasebrightnesscmd } }, + { MODKEY|ShiftMask, XK_s, spawn, {.v = decreasebrightnesscmd } }, + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY|ShiftMask, XK_i, incnmaster, {.i = +1 } }, + { MODKEY|ShiftMask, XK_d, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY, XK_Return, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY|ShiftMask, XK_q, killclient, {0} }, + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_c, quit, {0} }, +}; + +/* button definitions */ +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ +static const Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, +}; + + +/* torus config */ +static int torusenabled = 1; +static int wormholedelta = 1; // how close to the edge do we get before we take a wormhole to the other side. diff --git a/config.mk b/config.mk index 8efca9a..5f7634f 100644 --- a/config.mk +++ b/config.mk @@ -14,6 +14,10 @@ X11LIB = /usr/X11R6/lib XINERAMALIBS = -lXinerama XINERAMAFLAGS = -DXINERAMA +# Xinput extensions, comment if you don't want it +XINPUTLIBS = -lXi +XINPUTFLAGS = -DXINPUT + # freetype FREETYPELIBS = -lfontconfig -lXft FREETYPEINC = /usr/include/freetype2 @@ -23,10 +27,10 @@ FREETYPEINC = /usr/include/freetype2 # includes and libs INCS = -I${X11INC} -I${FREETYPEINC} -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XINPUTLIBS} # flags -CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} ${XINPUTFLAGS} #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} LDFLAGS = ${LIBS} diff --git a/dwm.c b/dwm.c index 67c6b2b..08cbb6b 100644 --- a/dwm.c +++ b/dwm.c @@ -39,6 +39,9 @@ #ifdef XINERAMA #include #endif /* XINERAMA */ +#ifdef XINPUT +#include +#endif /* XINPUT */ #include #include "drw.h" @@ -183,12 +186,16 @@ static void mappingnotify(XEvent *e); static void maprequest(XEvent *e); static void monocle(Monitor *m); static void motionnotify(XEvent *e); +static void rawmotionnotify(XEvent *e); +static void genericeventnotify(XEvent *e); static void movemouse(const Arg *arg); static Client *nexttiled(Client *c); static void pop(Client *c); static void propertynotify(XEvent *e); static void quit(const Arg *arg); static Monitor *recttomon(int x, int y, int w, int h); +static Monitor *raycastx(Monitor *src, int y, int dx); +static Monitor *raycasty(Monitor *src, int x, int dy); static void resize(Client *c, int x, int y, int w, int h, int interact); static void resizeclient(Client *c, int x, int y, int w, int h); static void resizemouse(const Arg *arg); @@ -242,6 +249,9 @@ static int sw, sh; /* X display screen geometry width, height */ static int bh; /* bar height */ static int lrpad; /* sum of left and right padding for text */ static int (*xerrorxlib)(Display *, XErrorEvent *); +#ifdef XINPUT +static int xinputextensionop; +#endif /* XINPUT */ static unsigned int numlockmask = 0; static void (*handler[LASTEvent]) (XEvent *) = { [ButtonPress] = buttonpress, @@ -257,7 +267,8 @@ static void (*handler[LASTEvent]) (XEvent *) = { [MapRequest] = maprequest, [MotionNotify] = motionnotify, [PropertyNotify] = propertynotify, - [UnmapNotify] = unmapnotify + [UnmapNotify] = unmapnotify, + [GenericEvent] = genericeventnotify, }; static Atom wmatom[WMLast], netatom[NetLast]; static int running = 1; @@ -833,6 +844,8 @@ focusmon(const Arg *arg) unfocus(selmon->sel, 0); selmon = m; focus(NULL); + if (selmon->sel) + XWarpPointer(dpy, None, selmon->sel->win, 0, 0, 0, 0, selmon->sel->w/2, selmon->sel->h/2); } void @@ -858,6 +871,7 @@ focusstack(const Arg *arg) if (c) { focus(c); restack(selmon); + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2); } } @@ -1142,6 +1156,58 @@ motionnotify(XEvent *e) mon = m; } +void +genericeventnotify(XEvent *e) +{ + if (e->xcookie.extension == xinputextensionop && + e->xcookie.evtype == XI_RawMotion) { + rawmotionnotify(e); + } +} + +void +rawmotionnotify(XEvent *e) +{ + if (torusenabled == 0) return; + + int x, y; + if (!getrootptr(&x, &y)) return; + + int warpx = x; + int warpy = y; + if (BETWEEN(x, selmon->mx, selmon->mx + wormholedelta)) { + /* ensure there's no monitor to the left */ + if (recttomon(selmon->mx - 1, y, 1, 1) != selmon) + return; + /* take the wormhole */ + Monitor *farright = raycastx(selmon, y, 1); + warpx = farright->mx + farright->mw - wormholedelta - 1; + } else if (BETWEEN(x, selmon->mx + selmon->mw - wormholedelta, + selmon->mx + selmon->mw)) { + /* ensure there's no monitor to the right */ + if (recttomon(selmon->mx + selmon->mw + 1, y, 1, 1) != selmon) + return; + Monitor *farleft = raycastx(selmon, y, -1); + warpx = farleft->mx + wormholedelta + 1; + } else if (BETWEEN(y, selmon->my, selmon->my + wormholedelta)) { + /* ensure there's no monitor under us */ + if (recttomon(x, y, selmon->my - 1, 1) != selmon) + return; + Monitor *farup = raycasty(selmon, x, 1); + warpy = farup->my + farup->mh - wormholedelta - 1; + } else if (BETWEEN(y, selmon->my + selmon->mh - wormholedelta, + selmon->my + selmon->mh)) { + /* ensure there's no monitor above us */ + if (recttomon(x, y, selmon->my + selmon->mh + 1, 1) != selmon) + return; + Monitor *fardown = raycasty(selmon, x, -1); + warpy = fardown->my + wormholedelta + 1; + } + + if (warpx != x || warpy != y) + XWarpPointer(dpy, None, root, 0, 0, 0, 0, warpx, warpy); +} + void movemouse(const Arg *arg) { @@ -1275,6 +1341,44 @@ recttomon(int x, int y, int w, int h) return r; } +Monitor * +raycastx(Monitor *src, int y, int dx) +{ + Monitor *farthest = src; + for (Monitor *m = mons; m; m = m->next) { + int scansy = BETWEEN(y, m->my, m->my + m->mh); + if (!scansy) { + continue; + } + if (dx == 1 && (m->mx + m->mw > farthest->mx + farthest->mw)) { + farthest = m; + } + if (dx == -1 && (m->mx < farthest->mx)) { + farthest = m; + } + } + return farthest; +} + +Monitor * +raycasty(Monitor *src, int x, int dy) +{ + Monitor *farthest = src; + for (Monitor *m = mons; m; m = m->next) { + int scansx = BETWEEN(x, m->mx, m->mx + m->mw); + if (!scansx) { + continue; + } + if (dy == 1 && (m->my + m->mh > farthest->my + farthest->mh)) { + farthest = m; + } + if (dy == -1 && (m->my < farthest->my)) { + farthest = m; + } + } + return farthest; +} + void resize(Client *c, int x, int y, int w, int h, int interact) { @@ -1609,6 +1713,23 @@ setup(void) |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); XSelectInput(dpy, root, wa.event_mask); +#ifdef XINPUT + /* select XInput raw motion events; we can't hook into PointerMotionMask since some windows block it. */ + size_t maskbyteslen = XIMaskLen(XI_RawMotion); + unsigned char *maskbytes = calloc(maskbyteslen, sizeof(unsigned char)); + XISetMask(maskbytes, XI_RawMotion); + XIEventMask mask; + int _unused; + if (!XQueryExtension(dpy, "XInputExtension", &xinputextensionop, + &_unused, &_unused)) { + fprintf(stderr, "XInputExtension not found"); + exit(1); + } + mask.deviceid = XIAllMasterDevices; + mask.mask_len = maskbyteslen * sizeof(unsigned char); + mask.mask = maskbytes; + XISelectEvents(dpy, root, &mask, 1); +#endif /* XINPUT */ grabkeys(); focus(NULL); } diff --git a/patch b/patch new file mode 100755 index 0000000..7a7da60 --- /dev/null +++ b/patch @@ -0,0 +1,9 @@ +#!/bin/bash + +order=("dwm-cursorwarp" "dwm-gaps" "dwm-torus") + +for patch in ${order[@]}; do + patch_file=$(ls patches | grep $patch) + echo "applying patch $patch_file..." + git apply "patches/$patch_file" || echo "failed to patch $patch_file. it may've already been applied!" +done diff --git a/patches/dwm-cursorwarp-20210222-61bb8b2.diff b/patches/dwm-cursorwarp-20210222-61bb8b2.diff new file mode 100644 index 0000000..6aa04a5 --- /dev/null +++ b/patches/dwm-cursorwarp-20210222-61bb8b2.diff @@ -0,0 +1,33 @@ +From 1e4936416fa5517fe447e3388e1d44c913e29f56 Mon Sep 17 00:00:00 2001 +From: Markus Dam +Date: Mon, 22 Feb 2021 13:40:13 +0100 +Subject: [PATCH] Add cursor warping + +--- + dwm.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/dwm.c b/dwm.c +index 331a309..c80ef8a 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -882,6 +882,8 @@ focusmon(const Arg *arg) + unfocus(selmon->sel, 0); + selmon = m; + focus(NULL); ++ if (selmon->sel) ++ XWarpPointer(dpy, None, selmon->sel->win, 0, 0, 0, 0, selmon->sel->w/2, selmon->sel->h/2); + } + + void +@@ -906,6 +908,7 @@ focusstack(const Arg *arg) + if (c) { + focus(c); + restack(selmon); ++ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2); + } + } + +-- +2.30.1 + diff --git a/patches/dwm-gaps-6.0.diff b/patches/dwm-gaps-6.0.diff new file mode 100644 index 0000000..80e1c8d --- /dev/null +++ b/patches/dwm-gaps-6.0.diff @@ -0,0 +1,53 @@ +diff --git a/config.def.h b/config.def.h +index 77ff358..a4e496b 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -9,6 +9,7 @@ static const char selbordercolor[] = "#005577"; + static const char selbgcolor[] = "#005577"; + static const char selfgcolor[] = "#eeeeee"; + static const unsigned int borderpx = 1; /* border pixel of windows */ ++static const unsigned int gappx = 1; /* gap pixel between windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const Bool showbar = True; /* False means no bar */ + static const Bool topbar = True; /* False means bottom bar */ +diff --git a/dwm.c b/dwm.c +index 1d78655..6cc96ff 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -1703,7 +1703,7 @@ textnw(const char *text, unsigned int len) { + + void + tile(Monitor *m) { +- unsigned int i, n, h, mw, my, ty; ++ unsigned int i, n, h, r, g = 0, mw, my, ty; + Client *c; + + for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); +@@ -1711,19 +1711,21 @@ tile(Monitor *m) { + return; + + if(n > m->nmaster) +- mw = m->nmaster ? m->ww * m->mfact : 0; ++ mw = m->nmaster ? (m->ww - (g = gappx)) * m->mfact : 0; + else + mw = m->ww; + for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if(i < m->nmaster) { +- h = (m->wh - my) / (MIN(n, m->nmaster) - i); ++ r = MIN(n, m->nmaster) - i; ++ h = (m->wh - my - gappx * (r - 1)) / r; + resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False); +- my += HEIGHT(c); ++ my += HEIGHT(c) + gappx; + } + else { +- h = (m->wh - ty) / (n - i); +- resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), False); +- ty += HEIGHT(c); ++ r = n - i; ++ h = (m->wh - ty - gappx * (r - 1)) / r; ++ resize(c, m->wx + mw + g, m->wy + ty, m->ww - mw - g - (2*c->bw), h - (2*c->bw), False); ++ ty += HEIGHT(c) + gappx; + } + } + diff --git a/patches/dwm-torus-20240901.diff b/patches/dwm-torus-20240901.diff new file mode 100644 index 0000000..bc9ed89 --- /dev/null +++ b/patches/dwm-torus-20240901.diff @@ -0,0 +1,218 @@ +diff --git a/config.def.h b/config.def.h +index 9efa774..8251624 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -114,3 +114,6 @@ static const Button buttons[] = { + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, + }; + ++/* torus config */ ++static int torusenabled = 1; ++static int wormholedelta = 1; // how close to the edge do we get before we take a wormhole to the other side. +diff --git a/config.mk b/config.mk +index 8efca9a..5f7634f 100644 +--- a/config.mk ++++ b/config.mk +@@ -14,6 +14,10 @@ X11LIB = /usr/X11R6/lib + XINERAMALIBS = -lXinerama + XINERAMAFLAGS = -DXINERAMA + ++# Xinput extensions, comment if you don't want it ++XINPUTLIBS = -lXi ++XINPUTFLAGS = -DXINPUT ++ + # freetype + FREETYPELIBS = -lfontconfig -lXft + FREETYPEINC = /usr/include/freetype2 +@@ -23,10 +27,10 @@ FREETYPEINC = /usr/include/freetype2 + + # includes and libs + INCS = -I${X11INC} -I${FREETYPEINC} +-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XINPUTLIBS} + + # flags +-CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} ++CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} ${XINPUTFLAGS} + #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} + CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} + LDFLAGS = ${LIBS} +diff --git a/dwm.c b/dwm.c +index 67c6b2b..392496e 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -39,6 +39,9 @@ + #ifdef XINERAMA + #include + #endif /* XINERAMA */ ++#ifdef XINPUT ++#include ++#endif /* XINPUT */ + #include + + #include "drw.h" +@@ -183,12 +186,16 @@ static void mappingnotify(XEvent *e); + static void maprequest(XEvent *e); + static void monocle(Monitor *m); + static void motionnotify(XEvent *e); ++static void rawmotionnotify(XEvent *e); ++static void genericeventnotify(XEvent *e); + static void movemouse(const Arg *arg); + static Client *nexttiled(Client *c); + static void pop(Client *c); + static void propertynotify(XEvent *e); + static void quit(const Arg *arg); + static Monitor *recttomon(int x, int y, int w, int h); ++static Monitor *raycastx(Monitor *src, int y, int dx); ++static Monitor *raycasty(Monitor *src, int x, int dy); + static void resize(Client *c, int x, int y, int w, int h, int interact); + static void resizeclient(Client *c, int x, int y, int w, int h); + static void resizemouse(const Arg *arg); +@@ -242,6 +249,9 @@ static int sw, sh; /* X display screen geometry width, height */ + static int bh; /* bar height */ + static int lrpad; /* sum of left and right padding for text */ + static int (*xerrorxlib)(Display *, XErrorEvent *); ++#ifdef XINPUT ++static int xinputextensionop; ++#endif /* XINPUT */ + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, +@@ -257,7 +267,8 @@ static void (*handler[LASTEvent]) (XEvent *) = { + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, +- [UnmapNotify] = unmapnotify ++ [UnmapNotify] = unmapnotify, ++ [GenericEvent] = genericeventnotify, + }; + static Atom wmatom[WMLast], netatom[NetLast]; + static int running = 1; +@@ -1142,6 +1153,58 @@ motionnotify(XEvent *e) + mon = m; + } + ++void ++genericeventnotify(XEvent *e) ++{ ++ if (e->xcookie.extension == xinputextensionop && ++ e->xcookie.evtype == XI_RawMotion) { ++ rawmotionnotify(e); ++ } ++} ++ ++void ++rawmotionnotify(XEvent *e) ++{ ++ if (torusenabled == 0) return; ++ ++ int x, y; ++ if (!getrootptr(&x, &y)) return; ++ ++ int warpx = x; ++ int warpy = y; ++ if (BETWEEN(x, selmon->mx, selmon->mx + wormholedelta)) { ++ /* ensure there's no monitor to the left */ ++ if (recttomon(selmon->mx - 1, y, 1, 1) != selmon) ++ return; ++ /* take the wormhole */ ++ Monitor *farright = raycastx(selmon, y, 1); ++ warpx = farright->mx + farright->mw - wormholedelta - 1; ++ } else if (BETWEEN(x, selmon->mx + selmon->mw - wormholedelta, ++ selmon->mx + selmon->mw)) { ++ /* ensure there's no monitor to the right */ ++ if (recttomon(selmon->mx + selmon->mw + 1, y, 1, 1) != selmon) ++ return; ++ Monitor *farleft = raycastx(selmon, y, -1); ++ warpx = farleft->mx + wormholedelta + 1; ++ } else if (BETWEEN(y, selmon->my, selmon->my + wormholedelta)) { ++ /* ensure there's no monitor under us */ ++ if (recttomon(x, y, selmon->my - 1, 1) != selmon) ++ return; ++ Monitor *farup = raycasty(selmon, x, 1); ++ warpy = farup->my + farup->mh - wormholedelta - 1; ++ } else if (BETWEEN(y, selmon->my + selmon->mh - wormholedelta, ++ selmon->my + selmon->mh)) { ++ /* ensure there's no monitor above us */ ++ if (recttomon(x, y, selmon->my + selmon->mh + 1, 1) != selmon) ++ return; ++ Monitor *fardown = raycasty(selmon, x, -1); ++ warpy = fardown->my + wormholedelta + 1; ++ } ++ ++ if (warpx != x || warpy != y) ++ XWarpPointer(dpy, None, root, 0, 0, 0, 0, warpx, warpy); ++} ++ + void + movemouse(const Arg *arg) + { +@@ -1275,6 +1338,44 @@ recttomon(int x, int y, int w, int h) + return r; + } + ++Monitor * ++raycastx(Monitor *src, int y, int dx) ++{ ++ Monitor *farthest = src; ++ for (Monitor *m = mons; m; m = m->next) { ++ int scansy = BETWEEN(y, m->my, m->my + m->mh); ++ if (!scansy) { ++ continue; ++ } ++ if (dx == 1 && (m->mx + m->mw > farthest->mx + farthest->mw)) { ++ farthest = m; ++ } ++ if (dx == -1 && (m->mx < farthest->mx)) { ++ farthest = m; ++ } ++ } ++ return farthest; ++} ++ ++Monitor * ++raycasty(Monitor *src, int x, int dy) ++{ ++ Monitor *farthest = src; ++ for (Monitor *m = mons; m; m = m->next) { ++ int scansx = BETWEEN(x, m->mx, m->mx + m->mw); ++ if (!scansx) { ++ continue; ++ } ++ if (dy == 1 && (m->my + m->mh > farthest->my + farthest->mh)) { ++ farthest = m; ++ } ++ if (dy == -1 && (m->my < farthest->my)) { ++ farthest = m; ++ } ++ } ++ return farthest; ++} ++ + void + resize(Client *c, int x, int y, int w, int h, int interact) + { +@@ -1609,6 +1710,23 @@ setup(void) + |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; + XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); + XSelectInput(dpy, root, wa.event_mask); ++#ifdef XINPUT ++ /* select XInput raw motion events; we can't hook into PointerMotionMask since some windows block it. */ ++ size_t maskbyteslen = XIMaskLen(XI_RawMotion); ++ unsigned char *maskbytes = calloc(maskbyteslen, sizeof(unsigned char)); ++ XISetMask(maskbytes, XI_RawMotion); ++ XIEventMask mask; ++ int _unused; ++ if (!XQueryExtension(dpy, "XInputExtension", &xinputextensionop, ++ &_unused, &_unused)) { ++ fprintf(stderr, "XInputExtension not found"); ++ exit(1); ++ } ++ mask.deviceid = XIAllMasterDevices; ++ mask.mask_len = maskbyteslen * sizeof(unsigned char); ++ mask.mask = maskbytes; ++ XISelectEvents(dpy, root, &mask, 1); ++#endif /* XINPUT */ + grabkeys(); + focus(NULL); + }