Adding alt-tab patch ref. #303
This commit is contained in:
		| @@ -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 | ||||||
|   | |||||||
							
								
								
									
										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" | #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 | ||||||
|   | |||||||
| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								dwm.c
									
									
									
									
									
								
							| @@ -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
									
								
							
							
						
						
									
										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 | #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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user