diff --git a/config.def.h.rej b/config.def.h.rej index 36b8c7c..668347e 100644 --- a/config.def.h.rej +++ b/config.def.h.rej @@ -1,15 +1,19 @@ --- config.def.h +++ config.def.h -@@ -26,9 +26,11 @@ static const Rule rules[] = { - * WM_CLASS(STRING) = instance, class - * WM_NAME(STRING) = title - */ -- /* class instance title tags mask isfloating monitor */ -+ /* class instance title tags mask isfloating monitor isgame */ - { "Gimp", NULL, NULL, 0, 1, -1 }, - { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, -+ { "Steam", NULL, NULL, 0, 0, -1, 1 }, -+ { "steam_app",NULL, NULL, 0, 0, -1, 1 }, +@@ -42,6 +42,7 @@ static const Layout layouts[] = { + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { NULL, NULL }, }; - /* layout(s) */ + /* key definitions */ +@@ -85,6 +86,8 @@ static Key keys[] = { + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, ++ { MODKEY|ControlMask, XK_comma, cyclelayout, {.i = -1 } }, ++ { MODKEY|ControlMask, XK_period, cyclelayout, {.i = +1 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) diff --git a/config.h b/config.h index 8bbe040..abbd557 100644 --- a/config.h +++ b/config.h @@ -126,6 +126,7 @@ static const Key keys[] = { { MODKEY, XK_i, incnmaster, {.i = +1 } }, { MODKEY, XK_p, incnmaster, {.i = -1 } }, + /* vim like window management / nav */ { MODKEY, XK_h, focusdir, {.i = 0 } }, { MODKEY, XK_l, focusdir, {.i = 1 } }, { MODKEY, XK_k, focusdir, {.i = 2 } }, @@ -135,6 +136,9 @@ static const Key keys[] = { { MODKEY|ShiftMask, XK_k, placedir, {.i = 2 } }, { MODKEY|ShiftMask, XK_j, placedir, {.i = 3 } }, + /* cycle layouts */ + { MODKEY, XK_n, cyclelayout, {.i = +1 } }, + { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} }, { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, @@ -152,13 +156,17 @@ static const Key keys[] = { { MODKEY|Mod1Mask|ShiftMask, XK_8, incrohgaps, {.i = -1 } }, { MODKEY|Mod1Mask, XK_9, incrovgaps, {.i = +1 } }, { MODKEY|Mod1Mask|ShiftMask, XK_9, incrovgaps, {.i = -1 } }, - { MODKEY|Mod1Mask, XK_0, togglegaps, {0} }, - { MODKEY|Mod1Mask|ShiftMask, XK_0, defaultgaps, {0} }, + + { MODKEY, XK_a, togglegaps, {0} }, + { MODKEY|Mod1Mask|ShiftMask, XK_a, defaultgaps, {0} }, + { MODKEY, XK_Tab, view, {0} }, { MODKEY, 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_v, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_c, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_space, setlayout, {0} }, { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, { MODKEY, XK_0, view, {.ui = ~0 } }, diff --git a/dwm b/dwm index cc63b4e..29787f5 100755 Binary files a/dwm and b/dwm differ diff --git a/dwm.1 b/dwm.1 index 7b6cadb..63271c1 100644 --- a/dwm.1 +++ b/dwm.1 @@ -92,6 +92,12 @@ Sets monocle layout. .B Mod1\-space Toggles between current and previous layout. .TP +.B Mod1\-Control\-, +Cycles backwards in layout list. +.TP +.B Mod1\-Control\-. +Cycles forwards in layout list. +.TP .B Mod1\-j Focus next window. .TP diff --git a/dwm.c b/dwm.c index b3d821f..433f2a0 100644 --- a/dwm.c +++ b/dwm.c @@ -200,6 +200,7 @@ static void configure(Client *c); static void configurenotify(XEvent *e); static void configurerequest(XEvent *e); static Monitor *createmon(void); +static void cyclelayout(const Arg *arg); static void destroynotify(XEvent *e); static void detach(Client *c); static void detachstack(Client *c); @@ -888,6 +889,23 @@ createmon(void) return m; } +void +cyclelayout(const Arg *arg) { + Layout *l; + for(l = (Layout *)layouts; l != selmon->lt[selmon->sellt]; l++); + if(arg->i > 0) { + if(l->symbol && (l + 1)->symbol) + setlayout(&((Arg) { .v = (l + 1) })); + else + setlayout(&((Arg) { .v = layouts })); + } else { + if(l != layouts && (l - 1)->symbol) + setlayout(&((Arg) { .v = (l - 1) })); + else + setlayout(&((Arg) { .v = &layouts[LENGTH(layouts) - 2] })); + } +} + void destroynotify(XEvent *e) { diff --git a/dwm.c.orig b/dwm.c.orig index 938ba3e..b3d821f 100644 --- a/dwm.c.orig +++ b/dwm.c.orig @@ -57,6 +57,7 @@ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) #define ISVISIBLEONTAG(C, T) ((C->tags & T)) #define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) +#define MINIMIZED(C) ((getstate(C->win) == IconicState)) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) #define HEIGHT(X) ((X)->h + 2 * (X)->bw) @@ -118,6 +119,7 @@ struct Client { int bw, oldbw; unsigned int tags; int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; + int isgame; pid_t pid; Client *next; Client *snext; @@ -172,6 +174,7 @@ typedef struct { int isterminal; int noswallow; int monitor; + int isgame; } Rule; typedef struct Systray Systray; @@ -223,6 +226,7 @@ static void killclient(const Arg *arg); static void manage(Window w, XWindowAttributes *wa); static void mappingnotify(XEvent *e); static void maprequest(XEvent *e); +static void minimize(Client *c); static void monocle(Monitor *m); static void motionnotify(XEvent *e); static void movemouse(const Arg *arg); @@ -268,6 +272,7 @@ static void toggleview(const Arg *arg); static void unfocus(Client *c, int setfocus); static void unmanage(Client *c, int destroyed); static void unmapnotify(XEvent *e); +static void unminimize(Client *c); static void updatebarpos(Monitor *m); static void updatebars(void); static void updateclientlist(void); @@ -411,6 +416,7 @@ applyrules(Client *c) c->noswallow = r->noswallow; c->isfloating = r->isfloating; c->tags |= r->tags; + c->isgame = r->isgame; if ((r->tags & SPTAGMASK) && r->isfloating) { c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); @@ -1469,6 +1475,29 @@ maprequest(XEvent *e) manage(ev->window, &wa); } +void +minimize(Client *c) +{ + if (!c || MINIMIZED(c)) + return; + + Window w = c->win; + static XWindowAttributes ra, ca; + + // more or less taken directly from blackbox's hide() function + XGrabServer(dpy); + XGetWindowAttributes(dpy, root, &ra); + XGetWindowAttributes(dpy, w, &ca); + // prevent UnmapNotify events + XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); + XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); + XUnmapWindow(dpy, w); + setclientstate(c, IconicState); + XSelectInput(dpy, root, ra.your_event_mask); + XSelectInput(dpy, w, ca.your_event_mask); + XUngrabServer(dpy); +} + void monocle(Monitor *m) { @@ -1997,6 +2026,10 @@ setfocus(Client *c) XA_WINDOW, 32, PropModeReplace, (unsigned char *) &(c->win), 1); } + + if (c->isgame && c->isfullscreen) + unminimize(c); + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); } @@ -2359,6 +2392,10 @@ unfocus(Client *c, int setfocus) { if (!c) return; + + if (c->isgame && c->isfullscreen) + minimize(c); + grabbuttons(c, 0); XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); if (setfocus) { @@ -2430,6 +2467,16 @@ unmapnotify(XEvent *e) } } +void +unminimize(Client *c) +{ + if (!c || !MINIMIZED(c)) + return; + + XMapWindow(dpy, c->win); + setclientstate(c, NormalState); +} + void updatebars(void) { diff --git a/dwm.o b/dwm.o index c81d12f..1cb4105 100644 Binary files a/dwm.o and b/dwm.o differ diff --git a/patches/dwm-cyclelayouts-6.3.diff b/patches/dwm-cyclelayouts-6.3.diff new file mode 100644 index 0000000..39c134f --- /dev/null +++ b/patches/dwm-cyclelayouts-6.3.diff @@ -0,0 +1,95 @@ +From d54f931d007a32ddc1fd9d8084258d92378597a5 Mon Sep 17 00:00:00 2001 +From: Bakkeby +Date: Wed, 26 Jun 2024 09:45:28 +0200 +Subject: [PATCH] cyclelayout, function to cycle through available layouts. + +MOD-CTRL-, and MOD-CTRL-. +cycle backwards and forwards through available layouts. +Probably only useful if you have a lot of additional layouts. +The NULL, NULL layout should always be the last layout in your list, +in order to guarantee consistent behavior. + +Refer to https://dwm.suckless.org/patches/cyclelayouts/ +--- + config.def.h | 3 +++ + dwm.1 | 6 ++++++ + dwm.c | 18 ++++++++++++++++++ + 3 files changed, 27 insertions(+) + +diff --git a/config.def.h b/config.def.h +index a2ac963..938fd60 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -42,6 +42,7 @@ static const Layout layouts[] = { + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { NULL, NULL }, + }; + + /* key definitions */ +@@ -85,6 +86,8 @@ static Key keys[] = { + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, ++ { MODKEY|ControlMask, XK_comma, cyclelayout, {.i = -1 } }, ++ { MODKEY|ControlMask, XK_period, cyclelayout, {.i = +1 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) +diff --git a/dwm.1 b/dwm.1 +index ddc8321..829047b 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -92,6 +92,12 @@ Sets monocle layout. + .B Mod1\-space + Toggles between current and previous layout. + .TP ++.B Mod1\-Control\-, ++Cycles backwards in layout list. ++.TP ++.B Mod1\-Control\-. ++Cycles forwards in layout list. ++.TP + .B Mod1\-j + Focus next window. + .TP +diff --git a/dwm.c b/dwm.c +index a96f33c..2d98c2b 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -157,6 +157,7 @@ static void configure(Client *c); + static void configurenotify(XEvent *e); + static void configurerequest(XEvent *e); + static Monitor *createmon(void); ++static void cyclelayout(const Arg *arg); + static void destroynotify(XEvent *e); + static void detach(Client *c); + static void detachstack(Client *c); +@@ -645,6 +646,23 @@ createmon(void) + return m; + } + ++void ++cyclelayout(const Arg *arg) { ++ Layout *l; ++ for(l = (Layout *)layouts; l != selmon->lt[selmon->sellt]; l++); ++ if(arg->i > 0) { ++ if(l->symbol && (l + 1)->symbol) ++ setlayout(&((Arg) { .v = (l + 1) })); ++ else ++ setlayout(&((Arg) { .v = layouts })); ++ } else { ++ if(l != layouts && (l - 1)->symbol) ++ setlayout(&((Arg) { .v = (l - 1) })); ++ else ++ setlayout(&((Arg) { .v = &layouts[LENGTH(layouts) - 2] })); ++ } ++} ++ + void + destroynotify(XEvent *e) + { +-- +2.45.2 + diff --git a/patches/dwm-focusborder-6.3.diff b/patches/dwm-focusborder-6.3.diff new file mode 100644 index 0000000..2a6343e --- /dev/null +++ b/patches/dwm-focusborder-6.3.diff @@ -0,0 +1,200 @@ +From 6d049ac4a34cb2f3a9e774cf7e13886a9da349a8 Mon Sep 17 00:00:00 2001 +From: Bakkeby +Date: Wed, 26 Jun 2024 10:01:41 +0200 +Subject: [PATCH] Adding focusborder patch + +--- + config.def.h | 1 + + dwm.c | 57 +++++++++++++++++++++++++++++++++++++++++++--------- + 2 files changed, 48 insertions(+), 10 deletions(-) + +diff --git a/config.def.h b/config.def.h +index a2ac963..17d326b 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -5,6 +5,7 @@ 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 unsigned int fh = 5; /* focus window height */ + static const char *fonts[] = { "monospace:size=10" }; + static const char dmenufont[] = "monospace:size=10"; + static const char col_gray1[] = "#222222"; +diff --git a/dwm.c b/dwm.c +index a96f33c..5f93b7e 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -267,7 +267,7 @@ static Clr **scheme; + static Display *dpy; + static Drw *drw; + static Monitor *mons, *selmon; +-static Window root, wmcheckwin; ++static Window root, wmcheckwin, focuswin; + + /* configuration, allows nested code to access above variables */ + #include "config.h" +@@ -487,6 +487,7 @@ cleanup(void) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < LENGTH(colors); i++) + free(scheme[i]); ++ XDestroyWindow(dpy, focuswin); + XDestroyWindow(dpy, wmcheckwin); + drw_free(drw); + XSync(dpy, False); +@@ -787,6 +788,8 @@ expose(XEvent *e) + void + focus(Client *c) + { ++ XWindowChanges wc; ++ + if (!c || !ISVISIBLE(c)) + for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); + if (selmon->sel && selmon->sel != c) +@@ -800,10 +803,16 @@ focus(Client *c) + attachstack(c); + grabbuttons(c, 1); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); ++ XMoveResizeWindow(dpy, focuswin, c->x, c->y, c->w + 2 * c->bw, fh); ++ XMoveResizeWindow(dpy, c->win, c->x, c->y + fh, c->w, c->h - fh); ++ wc.stack_mode = Above; ++ wc.sibling = c->win; ++ XConfigureWindow(dpy, focuswin, CWSibling|CWStackMode, &wc); + setfocus(c); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); ++ XMoveWindow(dpy, focuswin, 0, -fh); + } + selmon->sel = c; + drawbars(); +@@ -1150,8 +1159,8 @@ movemouse(const Arg *arg) + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ + return; + restack(selmon); +- ocx = c->x; +- ocy = c->y; ++ nx = ocx = c->x; ++ ny = ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; +@@ -1183,16 +1192,23 @@ movemouse(const Arg *arg) + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) + togglefloating(NULL); +- if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) +- resize(c, nx, ny, c->w, c->h, 1); ++ if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) { ++ XMoveWindow(dpy, focuswin, nx, ny); ++ XMoveWindow(dpy, c->win, nx, ny + fh); ++ } + break; + } + } while (ev.type != ButtonRelease); ++ + XUngrabPointer(dpy, CurrentTime); ++ resize(c, nx, ny, c->w, c->h, 1); ++ + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); ++ } else { ++ focus(c); + } + } + +@@ -1306,7 +1322,9 @@ resizemouse(const Arg *arg) + return; + restack(selmon); + ocx = c->x; +- ocy = c->y; ++ ocy = c->y + fh; ++ nh = c->h; ++ nw = c->w; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) + return; +@@ -1333,18 +1351,25 @@ resizemouse(const Arg *arg) + && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) + togglefloating(NULL); + } +- if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) +- resize(c, c->x, c->y, nw, nh, 1); ++ if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) { ++ XMoveResizeWindow(dpy, focuswin, c->x, c->y, nw + 2 * c->bw, fh); ++ XMoveResizeWindow(dpy, c->win, c->x, c->y + fh, nw, nh - fh); ++ } + break; + } + } while (ev.type != ButtonRelease); ++ + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + XUngrabPointer(dpy, CurrentTime); ++ resize(c, c->x, c->y, nw, nh, 1); ++ + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); ++ } else { ++ focus(c); + } + } + +@@ -1358,8 +1383,10 @@ restack(Monitor *m) + drawbar(m); + if (!m->sel) + return; +- if (m->sel->isfloating || !m->lt[m->sellt]->arrange) ++ if (m->sel->isfloating || !m->lt[m->sellt]->arrange) { + XRaiseWindow(dpy, m->sel->win); ++ XRaiseWindow(dpy, focuswin); ++ } + if (m->lt[m->sellt]->arrange) { + wc.stack_mode = Below; + wc.sibling = m->barwin; +@@ -1534,7 +1561,7 @@ void + setup(void) + { + int i; +- XSetWindowAttributes wa; ++ XSetWindowAttributes wa, fwa; + Atom utf8string; + + /* clean up any zombies immediately */ +@@ -1585,6 +1612,14 @@ setup(void) + PropModeReplace, (unsigned char *) "dwm", 3); + XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); ++ /* focus window */ ++ fwa.override_redirect = 1; ++ fwa.background_pixel = scheme[SchemeSel][ColBorder].pixel; ++ focuswin = XCreateWindow(dpy, root, -1, -1, 1, 1, 0, DefaultDepth(dpy, screen), ++ InputOutput, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixel, &fwa ++ ); ++ XMapWindow(dpy, focuswin); + /* EWMH support per view */ + XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) netatom, NetLast); +@@ -1723,6 +1758,7 @@ togglefloating(const Arg *arg) + resize(selmon->sel, selmon->sel->x, selmon->sel->y, + selmon->sel->w, selmon->sel->h, 0); + arrange(selmon); ++ focus(NULL); + } + + void +@@ -1759,6 +1795,7 @@ unfocus(Client *c, int setfocus) + return; + grabbuttons(c, 0); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); ++ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); +-- +2.45.2 +