dotfiles

My collection of dotfiles
git clone git://git.stellar-nexus.ru/dotfiles
Log | Files | Refs

06-dwm-alttab-6.4.diff (10206B)


      1 From 8b1d33db9cbc03bf12df398bb14e62389efc70a3 Mon Sep 17 00:00:00 2001
      2 From: ViliamKovac1223 <viliamkovac1223@gmail.com>
      3 Date: Sun, 9 Oct 2022 16:29:28 -0400
      4 Subject: [PATCH] add alt-tab functionality
      5 
      6 Co-authored-by: Daniel Gerblick <daniel.gerblick@gmail.com>
      7 ---
      8  config.def.h |  11 ++-
      9  dwm.c        | 218 +++++++++++++++++++++++++++++++++++++++++++++++++++
     10  2 files changed, 228 insertions(+), 1 deletion(-)
     11 
     12 diff --git a/config.def.h b/config.def.h
     13 index 061ad66..7a9e3b1 100644
     14 --- a/config.def.h
     15 +++ b/config.def.h
     16 @@ -1,5 +1,13 @@
     17  /* See LICENSE file for copyright and license details. */
     18  
     19 +/* alt-tab configuration */
     20 +static const unsigned int tabModKey 		= 0x40;	/* if this key is hold the alt-tab functionality stays acitve. This key must be the same as key that is used to active functin altTabStart `*/
     21 +static const unsigned int tabCycleKey 		= 0x17;	/* if this key is hit the alt-tab program moves one position forward in clients stack. This key must be the same as key that is used to active functin altTabStart */
     22 +static const unsigned int tabPosY 			= 1;	/* tab position on Y axis, 0 = bottom, 1 = center, 2 = top */
     23 +static const unsigned int tabPosX 			= 1;	/* tab position on X axis, 0 = left, 1 = center, 2 = right */
     24 +static const unsigned int maxWTab 			= 600;	/* tab menu width */
     25 +static const unsigned int maxHTab 			= 200;	/* tab menu height */
     26 +
     27  /* appearance */
     28  static const unsigned int borderpx  = 1;        /* border pixel of windows */
     29  static const unsigned int snap      = 32;       /* snap pixel */
     30 @@ -71,7 +79,7 @@ static const Key keys[] = {
     31  	{ MODKEY,                       XK_h,      setmfact,       {.f = -0.05} },
     32  	{ MODKEY,                       XK_l,      setmfact,       {.f = +0.05} },
     33  	{ MODKEY,                       XK_Return, zoom,           {0} },
     34 -	{ MODKEY,                       XK_Tab,    view,           {0} },
     35 +	{ MODKEY,                       XK_q,	   view,           {0} },
     36  	{ MODKEY|ShiftMask,             XK_c,      killclient,     {0} },
     37  	{ MODKEY,                       XK_t,      setlayout,      {.v = &layouts[0]} },
     38  	{ MODKEY,                       XK_f,      setlayout,      {.v = &layouts[1]} },
     39 @@ -84,6 +92,7 @@ static const Key keys[] = {
     40  	{ MODKEY,                       XK_period, focusmon,       {.i = +1 } },
     41  	{ MODKEY|ShiftMask,             XK_comma,  tagmon,         {.i = -1 } },
     42  	{ MODKEY|ShiftMask,             XK_period, tagmon,         {.i = +1 } },
     43 +	{ Mod1Mask,             		XK_Tab,    altTabStart,	   {0} },
     44  	TAGKEYS(                        XK_1,                      0)
     45  	TAGKEYS(                        XK_2,                      1)
     46  	TAGKEYS(                        XK_3,                      2)
     47 diff --git a/dwm.c b/dwm.c
     48 index e5efb6a..f606311 100644
     49 --- a/dwm.c
     50 +++ b/dwm.c
     51 @@ -40,6 +40,7 @@
     52  #include <X11/extensions/Xinerama.h>
     53  #endif /* XINERAMA */
     54  #include <X11/Xft/Xft.h>
     55 +#include <time.h>
     56  
     57  #include "drw.h"
     58  #include "util.h"
     59 @@ -119,6 +120,12 @@ struct Monitor {
     60  	int by;               /* bar geometry */
     61  	int mx, my, mw, mh;   /* screen size */
     62  	int wx, wy, ww, wh;   /* window area  */
     63 +	int altTabN;		  /* move that many clients forward */
     64 +	int nTabs;			  /* number of active clients in tag */
     65 +	int isAlt; 			  /* 1,0 */
     66 +	int maxWTab;
     67 +	int maxHTab;
     68 +	int gappx;           /* gaps between windows */
     69  	unsigned int seltags;
     70  	unsigned int sellt;
     71  	unsigned int tagset[2];
     72 @@ -127,8 +133,10 @@ struct Monitor {
     73  	Client *clients;
     74  	Client *sel;
     75  	Client *stack;
     76 +	Client ** altsnext; /* array of all clients in the tag */
     77  	Monitor *next;
     78  	Window barwin;
     79 +	Window tabwin;
     80  	const Layout *lt[2];
     81  };
     82  
     83 @@ -234,6 +242,9 @@ static int xerror(Display *dpy, XErrorEvent *ee);
     84  static int xerrordummy(Display *dpy, XErrorEvent *ee);
     85  static int xerrorstart(Display *dpy, XErrorEvent *ee);
     86  static void zoom(const Arg *arg);
     87 +void drawTab(int nwins, int first, Monitor *m);
     88 +void altTabStart(const Arg *arg);
     89 +static void altTabEnd();
     90  
     91  /* variables */
     92  static const char broken[] = "broken";
     93 @@ -477,6 +488,7 @@ cleanup(void)
     94  	Monitor *m;
     95  	size_t i;
     96  
     97 +	altTabEnd();
     98  	view(&a);
     99  	selmon->lt[selmon->sellt] = &foo;
    100  	for (m = mons; m; m = m->next)
    101 @@ -644,6 +656,8 @@ createmon(void)
    102  	m->topbar = topbar;
    103 +	m->gappx = gappx;
    104  	m->lt[0] = &layouts[0];
    105  	m->lt[1] = &layouts[1 % LENGTH(layouts)];
    106 +	m->nTabs = 0;
    107  	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
    108  	return m;
    109  }
    110 @@ -1649,6 +1662,211 @@ spawn(const Arg *arg)
    111  	}
    112  }
    113  
    114 +void
    115 +altTab()
    116 +{
    117 +	/* move to next window */
    118 +	if (selmon->sel != NULL && selmon->sel->snext != NULL) {
    119 +		selmon->altTabN++;
    120 +		if (selmon->altTabN >= selmon->nTabs)
    121 +			selmon->altTabN = 0; /* reset altTabN */
    122 +
    123 +		focus(selmon->altsnext[selmon->altTabN]);
    124 +		restack(selmon);
    125 +	}
    126 +
    127 +	/* redraw tab */
    128 +	XRaiseWindow(dpy, selmon->tabwin);
    129 +	drawTab(selmon->nTabs, 0, selmon);
    130 +}
    131 +
    132 +void
    133 +altTabEnd()
    134 +{
    135 +	if (selmon->isAlt == 0)
    136 +		return;
    137 +
    138 +	/*
    139 +	* move all clients between 1st and choosen position,
    140 +	* one down in stack and put choosen client to the first position 
    141 +	* so they remain in right order for the next time that alt-tab is used
    142 +	*/
    143 +	if (selmon->nTabs > 1) {
    144 +		if (selmon->altTabN != 0) { /* if user picked original client do nothing */
    145 +			Client *buff = selmon->altsnext[selmon->altTabN];
    146 +			if (selmon->altTabN > 1)
    147 +				for (int i = selmon->altTabN;i > 0;i--)
    148 +					selmon->altsnext[i] = selmon->altsnext[i - 1];
    149 +			else /* swap them if there are just 2 clients */
    150 +				selmon->altsnext[selmon->altTabN] = selmon->altsnext[0];
    151 +			selmon->altsnext[0] = buff;
    152 +		}
    153 +
    154 +		/* restack clients */
    155 +		for (int i = selmon->nTabs - 1;i >= 0;i--) {
    156 +			focus(selmon->altsnext[i]);
    157 +			restack(selmon);
    158 +		}
    159 +
    160 +		free(selmon->altsnext); /* free list of clients */
    161 +	}
    162 +
    163 +	/* turn off/destroy the window */
    164 +	selmon->isAlt = 0;
    165 +	selmon->nTabs = 0;
    166 +	XUnmapWindow(dpy, selmon->tabwin);
    167 +	XDestroyWindow(dpy, selmon->tabwin);
    168 +}
    169 +
    170 +void
    171 +drawTab(int nwins, int first, Monitor *m)
    172 +{
    173 +	/* little documentation of functions */
    174 +	/* void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); */
    175 +	/* int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); */
    176 +	/* void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); */
    177 +
    178 +	Client *c;
    179 +	int h;
    180 +
    181 +	if (first) {
    182 +		Monitor *m = selmon;
    183 +		XSetWindowAttributes wa = {
    184 +			.override_redirect = True,
    185 +			.background_pixmap = ParentRelative,
    186 +			.event_mask = ButtonPressMask|ExposureMask
    187 +		};
    188 +
    189 +		selmon->maxWTab = maxWTab;
    190 +		selmon->maxHTab = maxHTab;
    191 +
    192 +		/* decide position of tabwin */
    193 +		int posX = selmon->mx;
    194 +		int posY = selmon->my;
    195 +		if (tabPosX == 0)
    196 +			posX += 0;
    197 +		if (tabPosX == 1)
    198 +			posX += (selmon->mw / 2) - (maxWTab / 2);
    199 +		if (tabPosX == 2)
    200 +			posX += selmon->mw - maxWTab;
    201 +
    202 +		if (tabPosY == 0)
    203 +			posY += selmon->mh - maxHTab;
    204 +		if (tabPosY == 1)
    205 +			posY += (selmon->mh / 2) - (maxHTab / 2);
    206 +		if (tabPosY == 2)
    207 +			posY += 0;
    208 +
    209 +		h = selmon->maxHTab;
    210 +		/* XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual, valuemask, attributes); just reference */
    211 +		m->tabwin = XCreateWindow(dpy, root, posX, posY, selmon->maxWTab, selmon->maxHTab, 2, DefaultDepth(dpy, screen),
    212 +								CopyFromParent, DefaultVisual(dpy, screen),
    213 +								CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); /* create tabwin */
    214 +
    215 +		XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor);
    216 +		XMapRaised(dpy, m->tabwin);
    217 +
    218 +	}
    219 +
    220 +	h = selmon->maxHTab  / m->nTabs;
    221 +
    222 +	int y = 0;
    223 +	int n = 0;
    224 +	for (int i = 0;i < m->nTabs;i++) { /* draw all clients into tabwin */
    225 +		c = m->altsnext[i];
    226 +		if(!ISVISIBLE(c)) continue;
    227 +		/* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */
    228 +
    229 +		n++;
    230 +		drw_setscheme(drw, scheme[(c == m->sel) ? SchemeSel : SchemeNorm]);
    231 +		drw_text(drw, 0, y, selmon->maxWTab, h, 0, c->name, 0);
    232 +		y += h;
    233 +	}
    234 +
    235 +	drw_setscheme(drw, scheme[SchemeNorm]);
    236 +	drw_map(drw, m->tabwin, 0, 0, selmon->maxWTab, selmon->maxHTab);
    237 +}
    238 +
    239 +void
    240 +altTabStart(const Arg *arg)
    241 +{
    242 +	selmon->altsnext = NULL;
    243 +	if (selmon->tabwin)
    244 +		altTabEnd();
    245 +
    246 +	if (selmon->isAlt == 1) {
    247 +		altTabEnd();
    248 +	} else {
    249 +		selmon->isAlt = 1;
    250 +		selmon->altTabN = 0;
    251 +
    252 +		Client *c;
    253 +		Monitor *m = selmon;
    254 +
    255 +		m->nTabs = 0;
    256 +		for(c = m->clients; c; c = c->next) { /* count clients */
    257 +			if(!ISVISIBLE(c)) continue;
    258 +			/* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */
    259 +
    260 +			++m->nTabs;
    261 +		}
    262 +
    263 +		if (m->nTabs > 0) {
    264 +			m->altsnext = (Client **) malloc(m->nTabs * sizeof(Client *));
    265 +
    266 +			int listIndex = 0;
    267 +			for(c = m->stack; c; c = c->snext) { /* add clients to the list */
    268 +				if(!ISVISIBLE(c)) continue;
    269 +				/* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */
    270 +
    271 +				m->altsnext[listIndex++] = c;
    272 +			}
    273 +
    274 +			drawTab(m->nTabs, 1, m);
    275 +
    276 +			struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
    277 +
    278 +			/* grab keyboard (take all input from keyboard) */
    279 +			int grabbed = 1;
    280 +			for (int i = 0;i < 1000;i++) {
    281 +				if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess)
    282 +					break;
    283 +				nanosleep(&ts, NULL);
    284 +				if (i == 1000 - 1)
    285 +					grabbed = 0;
    286 +			}
    287 +
    288 +			XEvent event;
    289 +			altTab();
    290 +			if (grabbed == 0) {
    291 +				altTabEnd();
    292 +			} else {
    293 +				while (grabbed) {
    294 +					XNextEvent(dpy, &event);
    295 +					if (event.type == KeyPress || event.type == KeyRelease) {
    296 +						if (event.type == KeyRelease && event.xkey.keycode == tabModKey) { /* if super key is released break cycle */
    297 +							break;
    298 +						} else if (event.type == KeyPress) {
    299 +							if (event.xkey.keycode == tabCycleKey) {/* if XK_s is pressed move to the next window */
    300 +								altTab();
    301 +							}
    302 +						}
    303 +					}
    304 +				}
    305 +
    306 +				c = selmon->sel;
    307 +				altTabEnd(); /* end the alt-tab functionality */
    308 +				/* XUngrabKeyboard(display, time); just a reference */
    309 +				XUngrabKeyboard(dpy, CurrentTime); /* stop taking all input from keyboard */
    310 +				focus(c);
    311 +				restack(selmon);
    312 +			}
    313 +		} else {
    314 +			altTabEnd(); /* end the alt-tab functionality */
    315 +		}
    316 +	}
    317 +}
    318 +
    319  void
    320  tag(const Arg *arg)
    321  {
    322 -- 
    323 2.37.3
    324