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: | ||||
|  | ||||
| 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. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user