mirror of
https://github.com/mintycube/dwm.git
synced 2024-10-22 14:05:45 +02:00
Adding alt-tab patch ref. #303
This commit is contained in:
parent
4912e3129a
commit
cc58ad2ef4
@ -19,6 +19,8 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/X9IiSSM6
|
||||
|
||||
### Changelog:
|
||||
|
||||
2022-10-08 - Added the alt-tab patch
|
||||
|
||||
2022-08-12 - Added the nametag 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/)
|
||||
- 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/)
|
||||
- adds alternative tags which can be toggled on the fly for the sole purpose of providing
|
||||
visual aid
|
||||
|
14
config.def.h
14
config.def.h
@ -122,6 +122,16 @@ static const int ulineall = 0; /* 1 to show underline on all ta
|
||||
#define NAMETAG_COMMAND "dmenu < /dev/null"
|
||||
#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 */
|
||||
static int tagindicatortype = INDICATOR_TOP_LEFT_SQUARE;
|
||||
static int tiledindicatortype = INDICATOR_NONE;
|
||||
@ -996,7 +1006,11 @@ static const Key keys[] = {
|
||||
{ MODKEY|Mod4Mask, XK_0, togglegaps, {0} },
|
||||
{ MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} },
|
||||
#endif // VANITYGAPS_PATCH
|
||||
#if ALT_TAB_PATCH
|
||||
{ Mod1Mask, XK_Tab, alttabstart, {0} },
|
||||
#else
|
||||
{ MODKEY, XK_Tab, view, {0} },
|
||||
#endif // ALT_TAB_PATCH
|
||||
#if SHIFTTAG_PATCH
|
||||
{ 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
|
||||
|
@ -29,7 +29,7 @@ FREETYPEINC = /usr/include/freetype2
|
||||
#KVMLIB = -lkvm
|
||||
|
||||
# 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
|
||||
#MPDCLIENT = -lmpdclient
|
||||
|
4
dwm.c
4
dwm.c
@ -1245,6 +1245,10 @@ cleanup(void)
|
||||
Layout foo = { "", NULL };
|
||||
size_t i;
|
||||
|
||||
#if ALT_TAB_PATCH
|
||||
alttabend();
|
||||
#endif // ALT_TAB_PATCH
|
||||
|
||||
#if SEAMLESS_RESTART_PATCH
|
||||
for (m = mons; m; m = m->next)
|
||||
persistmonitorstate(m);
|
||||
|
222
patch/alttab.c
Normal file
222
patch/alttab.c
Normal 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
5
patch/alttab.h
Normal 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();
|
@ -98,6 +98,9 @@
|
||||
#endif
|
||||
|
||||
/* Other patches */
|
||||
#if ALT_TAB_PATCH
|
||||
#include "alttab.c"
|
||||
#endif
|
||||
#if ASPECTRESIZE_PATCH
|
||||
#include "aspectresize.c"
|
||||
#endif
|
||||
|
@ -98,6 +98,9 @@
|
||||
#endif
|
||||
|
||||
/* Other patches */
|
||||
#if ALT_TAB_PATCH
|
||||
#include "alttab.h"
|
||||
#endif
|
||||
#if ASPECTRESIZE_PATCH
|
||||
#include "aspectresize.h"
|
||||
#endif
|
||||
|
@ -438,6 +438,11 @@
|
||||
* 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.
|
||||
* The center patch takes precedence over this patch.
|
||||
* This patch interferes with the center transient windows patches.
|
||||
|
Loading…
Reference in New Issue
Block a user