Adding alt-tab patch ref. #303

This commit is contained in:
bakkeby 2022-10-08 22:12:03 +02:00
parent 4912e3129a
commit cc58ad2ef4
9 changed files with 262 additions and 1 deletions

View File

@ -19,6 +19,8 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/X9IiSSM6
### Changelog: ### Changelog:
2022-10-08 - Added the alt-tab patch
2022-08-12 - Added the nametag patch 2022-08-12 - Added the nametag patch
2022-08-02 - Added the bidi patch 2022-08-02 - Added the bidi patch
@ -230,6 +232,9 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/X9IiSSM6
- [alpha](https://dwm.suckless.org/patches/alpha/) - [alpha](https://dwm.suckless.org/patches/alpha/)
- adds transparency for the status bar - adds transparency for the status bar
- [alt-tab](https://dwm.suckless.org/patches/alt-tab/)
- adds a window task switcher toggled using alt-tab
- [alternativetags](https://dwm.suckless.org/patches/alternativetags/) - [alternativetags](https://dwm.suckless.org/patches/alternativetags/)
- adds alternative tags which can be toggled on the fly for the sole purpose of providing - adds alternative tags which can be toggled on the fly for the sole purpose of providing
visual aid visual aid

View File

@ -122,6 +122,16 @@ static const int ulineall = 0; /* 1 to show underline on all ta
#define NAMETAG_COMMAND "dmenu < /dev/null" #define NAMETAG_COMMAND "dmenu < /dev/null"
#endif // NAMETAG_PATCH #endif // NAMETAG_PATCH
#if ALT_TAB_PATCH
/* alt-tab configuration */
static const unsigned int tabmodkey = 0x40; /* (Alt) when this key is held down the alt-tab functionality stays active. Must be the same modifier as used to run alttabstart */
static const unsigned int tabcyclekey = 0x17; /* (Tab) when this key is hit the menu moves one position forward in client stack. Must be the same key as used to run alttabstart */
static const unsigned int tabposy = 1; /* tab position on Y axis, 0 = top, 1 = center, 2 = bottom */
static const unsigned int tabposx = 1; /* tab position on X axis, 0 = left, 1 = center, 2 = right */
static const unsigned int maxwtab = 600; /* tab menu width */
static const unsigned int maxhtab = 200; /* tab menu height */
#endif // ALT_TAB_PATCH
/* Indicators: see patch/bar_indicators.h for options */ /* Indicators: see patch/bar_indicators.h for options */
static int tagindicatortype = INDICATOR_TOP_LEFT_SQUARE; static int tagindicatortype = INDICATOR_TOP_LEFT_SQUARE;
static int tiledindicatortype = INDICATOR_NONE; static int tiledindicatortype = INDICATOR_NONE;
@ -996,7 +1006,11 @@ static const Key keys[] = {
{ MODKEY|Mod4Mask, XK_0, togglegaps, {0} }, { MODKEY|Mod4Mask, XK_0, togglegaps, {0} },
{ MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} }, { MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} },
#endif // VANITYGAPS_PATCH #endif // VANITYGAPS_PATCH
#if ALT_TAB_PATCH
{ Mod1Mask, XK_Tab, alttabstart, {0} },
#else
{ MODKEY, XK_Tab, view, {0} }, { MODKEY, XK_Tab, view, {0} },
#endif // ALT_TAB_PATCH
#if SHIFTTAG_PATCH #if SHIFTTAG_PATCH
{ MODKEY|ShiftMask, XK_Left, shifttag, { .i = -1 } }, // note keybinding conflict with focusadjacenttag tagtoleft { MODKEY|ShiftMask, XK_Left, shifttag, { .i = -1 } }, // note keybinding conflict with focusadjacenttag tagtoleft
{ MODKEY|ShiftMask, XK_Right, shifttag, { .i = +1 } }, // note keybinding conflict with focusadjacenttag tagtoright { MODKEY|ShiftMask, XK_Right, shifttag, { .i = +1 } }, // note keybinding conflict with focusadjacenttag tagtoright

View File

@ -29,7 +29,7 @@ FREETYPEINC = /usr/include/freetype2
#KVMLIB = -lkvm #KVMLIB = -lkvm
# Uncomment this for the alpha patch and the winicon patch (BAR_ALPHA_PATCH, BAR_WINICON_PATCH) # Uncomment this for the alpha patch and the winicon patch (BAR_ALPHA_PATCH, BAR_WINICON_PATCH)
#XRENDER = -lXrender XRENDER = -lXrender
# Uncomment this for the mdpcontrol patch / MDPCONTROL_PATCH # Uncomment this for the mdpcontrol patch / MDPCONTROL_PATCH
#MPDCLIENT = -lmpdclient #MPDCLIENT = -lmpdclient

4
dwm.c
View File

@ -1245,6 +1245,10 @@ cleanup(void)
Layout foo = { "", NULL }; Layout foo = { "", NULL };
size_t i; size_t i;
#if ALT_TAB_PATCH
alttabend();
#endif // ALT_TAB_PATCH
#if SEAMLESS_RESTART_PATCH #if SEAMLESS_RESTART_PATCH
for (m = mons; m; m = m->next) for (m = mons; m; m = m->next)
persistmonitorstate(m); persistmonitorstate(m);

222
patch/alttab.c Normal file
View File

@ -0,0 +1,222 @@
int alttabn; /* move that many clients forward */
int ntabs; /* number of active clients in tag */
int isalt;
Client **altsnext; /* array of all clients in the tag */
Window alttabwin;
void
alttab()
{
Monitor *m = selmon;
/* move to next window */
if (m->sel && m->sel->snext) {
alttabn++;
if (alttabn >= ntabs)
alttabn = 0; /* reset alttabn */
focus(altsnext[alttabn]);
restack(m);
}
/* redraw tab */
XRaiseWindow(dpy, alttabwin);
drawtab(ntabs, 0, m);
}
void
alttabend()
{
Monitor *m = selmon;
Client *buff;
int i;
if (!isalt)
return;
/* Move all clients between first and choosen position,
* one down in stack and put choosen client to the first position
* so they remain in right order for the next time that alt-tab is used
*/
if (ntabs > 1) {
if (alttabn != 0) { /* if user picked original client do nothing */
buff = altsnext[alttabn];
if (alttabn > 1)
for (i = alttabn; i > 0; i--)
altsnext[i] = altsnext[i - 1];
else /* swap them if there are just 2 clients */
altsnext[alttabn] = altsnext[0];
altsnext[0] = buff;
}
/* restack clients */
for (i = ntabs - 1; i >= 0; i--) {
focus(altsnext[i]);
restack(m);
}
free(altsnext); /* free list of clients */
}
/* destroy the window */
isalt = 0;
ntabs = 0;
XUnmapWindow(dpy, alttabwin);
XDestroyWindow(dpy, alttabwin);
}
void
drawtab(int nwins, int first, Monitor *m)
{
Client *c;
int i, h;
int y = 0;
int px = m->mx;
int py = m->my;
if (first) {
XSetWindowAttributes wa = {
.override_redirect = True,
#if BAR_ALPHA_PATCH
.background_pixel = 0,
.border_pixel = 0,
.colormap = cmap,
#else
.background_pixmap = ParentRelative,
#endif // BAR_ALPHA_PATCH
.event_mask = ButtonPressMask|ExposureMask
};
/* decide position of tabwin */
if (tabposx == 1)
px = m->mx + (m->mw / 2) - (maxwtab / 2);
else if (tabposx == 2)
px = m->mx + m->mw - maxwtab;
if (tabposy == 1)
py = m->my + (m->mh / 2) - (maxhtab / 2);
else if (tabposy == 2)
py = m->my + m->mh - maxhtab;
h = maxhtab;
#if BAR_ALPHA_PATCH
alttabwin = XCreateWindow(dpy, root, px, py, maxwtab, maxhtab, 2, depth,
InputOutput, visual,
CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
#else
alttabwin = XCreateWindow(dpy, root, px, py, maxwtab, maxhtab, 2, DefaultDepth(dpy, screen),
CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
#endif // BAR_ALPHA_PATCH
XDefineCursor(dpy, alttabwin, cursor[CurNormal]->cursor);
XMapRaised(dpy, alttabwin);
}
h = maxhtab / ntabs;
for (i = 0; i < ntabs; i++) { /* draw all clients into tabwin */
c = altsnext[i];
if (!ISVISIBLE(c))
continue;
if (HIDDEN(c))
continue;
drw_setscheme(drw, scheme[c == m->sel ? SchemeSel : SchemeNorm]);
drw_text(drw, 0, y, maxwtab, h, 0, c->name, 0, 0);
y += h;
}
drw_setscheme(drw, scheme[SchemeNorm]);
drw_map(drw, alttabwin, 0, 0, maxwtab, maxhtab);
}
void
alttabstart(const Arg *arg)
{
Client *c;
Monitor *m = selmon;
int grabbed;
int i;
altsnext = NULL;
if (alttabwin)
alttabend();
if (isalt == 1) {
alttabend();
return;
}
isalt = 1;
alttabn = 0;
ntabs = 0;
for (c = m->clients; c; c = c->next) {
if (!ISVISIBLE(c))
continue;
if (HIDDEN(c))
continue;
++ntabs;
}
if (!ntabs) {
alttabend();
return;
}
altsnext = (Client **) malloc(ntabs * sizeof(Client *));
for (i = 0, c = m->stack; c; c = c->snext, i++) {
if (!ISVISIBLE(c))
continue;
if (HIDDEN(c))
continue;
altsnext[i] = c;
}
drawtab(ntabs, 1, m);
struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
/* grab keyboard (take all input from keyboard) */
grabbed = 1;
for (i = 0; i < 1000; i++) {
if (XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess)
break;
nanosleep(&ts, NULL);
if (i == 1000 - 1)
grabbed = 0;
}
XEvent event;
alttab();
if (grabbed == 0) {
alttabend();
return;
}
while (grabbed) {
XNextEvent(dpy, &event);
if (event.type == KeyPress || event.type == KeyRelease) {
if (event.type == KeyRelease && event.xkey.keycode == tabmodkey) /* if mod key is released break cycle */
break;
if (event.type == KeyPress) {
if (event.xkey.keycode == tabcyclekey) { /* if tab is pressed move to the next window */
alttab();
}
}
}
}
c = m->sel;
alttabend();
XUngrabKeyboard(dpy, CurrentTime);
focus(c);
restack(m);
}

5
patch/alttab.h Normal file
View File

@ -0,0 +1,5 @@
#include <time.h>
static void drawtab(int nwins, int first, Monitor *m);
static void alttabstart(const Arg *arg);
static void alttabend();

View File

@ -98,6 +98,9 @@
#endif #endif
/* Other patches */ /* Other patches */
#if ALT_TAB_PATCH
#include "alttab.c"
#endif
#if ASPECTRESIZE_PATCH #if ASPECTRESIZE_PATCH
#include "aspectresize.c" #include "aspectresize.c"
#endif #endif

View File

@ -98,6 +98,9 @@
#endif #endif
/* Other patches */ /* Other patches */
#if ALT_TAB_PATCH
#include "alttab.h"
#endif
#if ASPECTRESIZE_PATCH #if ASPECTRESIZE_PATCH
#include "aspectresize.h" #include "aspectresize.h"
#endif #endif

View File

@ -438,6 +438,11 @@
* Other patches * Other patches
*/ */
/* Adds a window task switcher toggled using alt-tab.
* https://dwm.suckless.org/patches/alt-tab/
*/
#define ALT_TAB_PATCH 0
/* All floating windows are centered, like the center patch, but without a rule. /* All floating windows are centered, like the center patch, but without a rule.
* The center patch takes precedence over this patch. * The center patch takes precedence over this patch.
* This patch interferes with the center transient windows patches. * This patch interferes with the center transient windows patches.