commit 4519b8b664937938217277f1b25e9d2f935cc8a5
Author: lucas-mior <[email protected]>
Date:   Mon Nov 6 13:47:42 2023 -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.

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
new file mode 100644
index 00000000..38cb4821
--- /dev/null
+++ 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
new file mode 100644
index 00000000..d6ffc3d7
--- /dev/null
+++ 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
new file mode 100644
index 00000000..acfaf73b
--- /dev/null
+++ 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)


Reply via email to