sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

commit 4519b8b664937938217277f1b25e9d2f935cc8a5
parent f79134fe500f8a1cd192286fb1797e7c495d92bb
Author: lucas-mior <lucas.mior@tutamail.com>
Date:   Mon,  6 Nov 2023 13:47:42 -0300

add alttab2 patch for dwm

It adds alt-tab like functionality to dwm, by cycling through
windows/clients in their recently used order.  Tag `~0` is used to view
all clients while doing so.  One can also click to focus a window.

Diffstat:
Adwm.suckless.org/patches/alttab2/dwm-alttab2+winview-6.4.diff | 217+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/alttab2/dwm-alttab2-6.4.diff | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/alttab2/index.md | 35+++++++++++++++++++++++++++++++++++
3 files changed, 419 insertions(+), 0 deletions(-)

diff --git a/dwm.suckless.org/patches/alttab2/dwm-alttab2+winview-6.4.diff b/dwm.suckless.org/patches/alttab2/dwm-alttab2+winview-6.4.diff @@ -0,0 +1,217 @@ +diff --git a/config.def.h b/config.def.h +index 9efa774..95499bd 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -2,6 +2,8 @@ + + /* appearance */ + static const unsigned int borderpx = 1; /* border pixel of windows */ ++static const unsigned int tabModKey = 0x40; ++static const unsigned int tabCycleKey = 0x17; + 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 */ +@@ -95,6 +97,8 @@ static const Key keys[] = { + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_q, quit, {0} }, ++ { MODKEY, XK_o, winview, {0} }, ++ { Mod1Mask, XK_Tab, alttab, {0} }, + }; + + /* button definitions */ +diff --git a/dwm.1 b/dwm.1 +index ddc8321..f8a809e 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -110,6 +110,9 @@ Increase master area size. + .B Mod1\-h + Decrease master area size. + .TP ++.B Mod1\-o ++Select view of the window in focus. The list of tags to be displayed is matched to the window tag list. ++.TP + .B Mod1\-Return + Zooms/cycles focused window to/from master area (tiled layouts only). + .TP +diff --git a/dwm.c b/dwm.c +index f1d86b2..71d0ebc 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -28,6 +28,7 @@ + #include <stdlib.h> + #include <string.h> + #include <unistd.h> ++#include <time.h> + #include <sys/types.h> + #include <sys/wait.h> + #include <X11/cursorfont.h> +@@ -142,6 +143,7 @@ typedef struct { + } Rule; + + /* function declarations */ ++static void alttab(const Arg *arg); + static void applyrules(Client *c); + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); + static void arrange(Monitor *m); +@@ -168,6 +170,7 @@ static void expose(XEvent *e); + static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); ++static void focusnext(const Arg *arg); + static void focusstack(const Arg *arg); + static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); +@@ -229,6 +232,7 @@ static void updatewmhints(Client *c); + static void view(const Arg *arg); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); ++static void winview(const Arg* arg); + static int xerror(Display *dpy, XErrorEvent *ee); + static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); +@@ -268,6 +272,8 @@ static Drw *drw; + static Monitor *mons, *selmon; + static Window root, wmcheckwin; + ++static int alt_tab_direction = 0; ++ + /* configuration, allows nested code to access above variables */ + #include "config.h" + +@@ -275,6 +281,79 @@ static Window root, wmcheckwin; + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + + /* function implementations */ ++ ++static void ++alttab(const Arg *arg) { ++ ++ view(&(Arg){ .ui = ~0 }); ++ focusnext(&(Arg){ .i = alt_tab_direction }); ++ ++ int grabbed = 1; ++ int grabbed_keyboard = 1000; ++ for (int i = 0; i < 100; i += 1) { ++ struct timespec ts; ++ ts.tv_sec = 0; ++ ts.tv_nsec = 1000000; ++ ++ if (grabbed_keyboard != GrabSuccess) { ++ grabbed_keyboard = XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, ++ GrabModeAsync, GrabModeAsync, CurrentTime); ++ } ++ if (grabbed_keyboard == GrabSuccess) { ++ XGrabButton(dpy, AnyButton, AnyModifier, None, False, ++ BUTTONMASK, GrabModeAsync, GrabModeAsync, ++ None, None); ++ break; ++ } ++ nanosleep(&ts, NULL); ++ if (i == 100 - 1) ++ grabbed = 0; ++ } ++ ++ XEvent event; ++ Client *c; ++ Monitor *m; ++ XButtonPressedEvent *ev; ++ ++ while (grabbed) { ++ XNextEvent(dpy, &event); ++ switch (event.type) { ++ case KeyPress: ++ if (event.xkey.keycode == tabCycleKey) ++ focusnext(&(Arg){ .i = alt_tab_direction }); ++ break; ++ case KeyRelease: ++ if (event.xkey.keycode == tabModKey) { ++ XUngrabKeyboard(dpy, CurrentTime); ++ XUngrabButton(dpy, AnyButton, AnyModifier, None); ++ grabbed = 0; ++ alt_tab_direction = !alt_tab_direction; ++ winview(0); ++ } ++ break; ++ case ButtonPress: ++ ev = &(event.xbutton); ++ if ((m = wintomon(ev->window)) && m != selmon) { ++ unfocus(selmon->sel, 1); ++ selmon = m; ++ focus(NULL); ++ } ++ if ((c = wintoclient(ev->window))) ++ focus(c); ++ XAllowEvents(dpy, AsyncBoth, CurrentTime); ++ break; ++ case ButtonRelease: ++ XUngrabKeyboard(dpy, CurrentTime); ++ XUngrabButton(dpy, AnyButton, AnyModifier, None); ++ grabbed = 0; ++ alt_tab_direction = !alt_tab_direction; ++ winview(0); ++ break; ++ } ++ } ++ return; ++} ++ + void + applyrules(Client *c) + { +@@ -835,6 +914,28 @@ focusmon(const Arg *arg) + focus(NULL); + } + ++static void ++focusnext(const Arg *arg) { ++ Monitor *m; ++ Client *c; ++ m = selmon; ++ c = m->sel; ++ ++ if (arg->i) { ++ if (c->next) ++ c = c->next; ++ else ++ c = m->clients; ++ } else { ++ Client *last = c; ++ if (last == m->clients) ++ last = NULL; ++ for (c = m->clients; c->next != last; c = c->next); ++ } ++ focus(c); ++ return; ++} ++ + void + focusstack(const Arg *arg) + { +@@ -2092,6 +2193,26 @@ wintomon(Window w) + return selmon; + } + ++/* Selects for the view of the focused window. The list of tags */ ++/* to be displayed is matched to the focused window tag list. */ ++void ++winview(const Arg* arg){ ++ Window win, win_r, win_p, *win_c; ++ unsigned nc; ++ int unused; ++ Client* c; ++ Arg a; ++ ++ if (!XGetInputFocus(dpy, &win, &unused)) return; ++ while(XQueryTree(dpy, win, &win_r, &win_p, &win_c, &nc) ++ && win_p != win_r) win = win_p; ++ ++ if (!(c = wintoclient(win))) return; ++ ++ a.ui = c->tags; ++ view(&a); ++} ++ + /* There's no way to check accesses to destroyed windows, thus those cases are + * ignored (especially on UnmapNotify's). Other types of errors call Xlibs + * default error handler, which may call exit. */ diff --git a/dwm.suckless.org/patches/alttab2/dwm-alttab2-6.4.diff b/dwm.suckless.org/patches/alttab2/dwm-alttab2-6.4.diff @@ -0,0 +1,167 @@ +diff --git a/config.def.h b/config.def.h +index 71ec68b..95499bd 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -2,6 +2,8 @@ + + /* appearance */ + static const unsigned int borderpx = 1; /* border pixel of windows */ ++static const unsigned int tabModKey = 0x40; ++static const unsigned int tabCycleKey = 0x17; + 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 */ +@@ -96,6 +98,7 @@ static const Key keys[] = { + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_q, quit, {0} }, + { MODKEY, XK_o, winview, {0} }, ++ { Mod1Mask, XK_Tab, alttab, {0} }, + }; + + /* button definitions */ +diff --git a/dwm.c b/dwm.c +index ec076a8..71d0ebc 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -28,6 +28,7 @@ + #include <stdlib.h> + #include <string.h> + #include <unistd.h> ++#include <time.h> + #include <sys/types.h> + #include <sys/wait.h> + #include <X11/cursorfont.h> +@@ -142,6 +143,7 @@ typedef struct { + } Rule; + + /* function declarations */ ++static void alttab(const Arg *arg); + static void applyrules(Client *c); + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); + static void arrange(Monitor *m); +@@ -168,6 +170,7 @@ static void expose(XEvent *e); + static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); ++static void focusnext(const Arg *arg); + static void focusstack(const Arg *arg); + static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); +@@ -269,6 +272,8 @@ static Drw *drw; + static Monitor *mons, *selmon; + static Window root, wmcheckwin; + ++static int alt_tab_direction = 0; ++ + /* configuration, allows nested code to access above variables */ + #include "config.h" + +@@ -276,6 +281,79 @@ static Window root, wmcheckwin; + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + + /* function implementations */ ++ ++static void ++alttab(const Arg *arg) { ++ ++ view(&(Arg){ .ui = ~0 }); ++ focusnext(&(Arg){ .i = alt_tab_direction }); ++ ++ int grabbed = 1; ++ int grabbed_keyboard = 1000; ++ for (int i = 0; i < 100; i += 1) { ++ struct timespec ts; ++ ts.tv_sec = 0; ++ ts.tv_nsec = 1000000; ++ ++ if (grabbed_keyboard != GrabSuccess) { ++ grabbed_keyboard = XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, ++ GrabModeAsync, GrabModeAsync, CurrentTime); ++ } ++ if (grabbed_keyboard == GrabSuccess) { ++ XGrabButton(dpy, AnyButton, AnyModifier, None, False, ++ BUTTONMASK, GrabModeAsync, GrabModeAsync, ++ None, None); ++ break; ++ } ++ nanosleep(&ts, NULL); ++ if (i == 100 - 1) ++ grabbed = 0; ++ } ++ ++ XEvent event; ++ Client *c; ++ Monitor *m; ++ XButtonPressedEvent *ev; ++ ++ while (grabbed) { ++ XNextEvent(dpy, &event); ++ switch (event.type) { ++ case KeyPress: ++ if (event.xkey.keycode == tabCycleKey) ++ focusnext(&(Arg){ .i = alt_tab_direction }); ++ break; ++ case KeyRelease: ++ if (event.xkey.keycode == tabModKey) { ++ XUngrabKeyboard(dpy, CurrentTime); ++ XUngrabButton(dpy, AnyButton, AnyModifier, None); ++ grabbed = 0; ++ alt_tab_direction = !alt_tab_direction; ++ winview(0); ++ } ++ break; ++ case ButtonPress: ++ ev = &(event.xbutton); ++ if ((m = wintomon(ev->window)) && m != selmon) { ++ unfocus(selmon->sel, 1); ++ selmon = m; ++ focus(NULL); ++ } ++ if ((c = wintoclient(ev->window))) ++ focus(c); ++ XAllowEvents(dpy, AsyncBoth, CurrentTime); ++ break; ++ case ButtonRelease: ++ XUngrabKeyboard(dpy, CurrentTime); ++ XUngrabButton(dpy, AnyButton, AnyModifier, None); ++ grabbed = 0; ++ alt_tab_direction = !alt_tab_direction; ++ winview(0); ++ break; ++ } ++ } ++ return; ++} ++ + void + applyrules(Client *c) + { +@@ -836,6 +914,28 @@ focusmon(const Arg *arg) + focus(NULL); + } + ++static void ++focusnext(const Arg *arg) { ++ Monitor *m; ++ Client *c; ++ m = selmon; ++ c = m->sel; ++ ++ if (arg->i) { ++ if (c->next) ++ c = c->next; ++ else ++ c = m->clients; ++ } else { ++ Client *last = c; ++ if (last == m->clients) ++ last = NULL; ++ for (c = m->clients; c->next != last; c = c->next); ++ } ++ focus(c); ++ return; ++} ++ + void + focusstack(const Arg *arg) + { diff --git a/dwm.suckless.org/patches/alttab2/index.md b/dwm.suckless.org/patches/alttab2/index.md @@ -0,0 +1,35 @@ +Alt-tab2 +======= + +Description +----------- +This patch is based on [alt-tab](../alt-tab/). +It adds alt-tab like functionality to dwm, +by cycling through windows/clients in their recently used order. +Tag `~0` is used to view all clients while doing so. +One can also click to focus a window. +In order to use this patch [winview](../winview/) is also necessary. + +Rationale +--------- +For whatever reason, the original alt-tab patch made dwm crash for me. +Besides, it was a huge patch, this version is simplified to use dwm's +core features + winview patch instead of drawing an alt tab window. + +Configuration +--------------------- +* `tabModKey` - If this key is hold the alt-tab functionality stays active. This key must be the same as key that is used to active function alttab +* `tabCycleKey` - If this key is hit the alt-tab program moves one position forward in clients. This key must be the same as key that is used to active function alttab + +`tabModkey` and `tabCycleKey` are keycodes values. +In case you use to other keys, checkout the instructions in +[alt-tab](../alt-tab/index.md). + +Support +----- +This patch is kept alive on my [github](https://github.com/lucas-mior/dwm). + +Download +-------- +* [dwm-alttab2-6.4.diff](dwm-alttab2-6.4.diff) (patch on top of winview) +* [dwm-alttab2+winview-6.4.diff](dwm-alttab2+winview-6.4.diff) (winview + alttab2 as a single patch)