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 #include #include +#include #include #include #include @@ -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) {