sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

dwm-alttab-6.4.diff (10136B)


      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,11 @@ 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  	unsigned int seltags;
     69  	unsigned int sellt;
     70  	unsigned int tagset[2];
     71 @@ -127,8 +133,10 @@ struct Monitor {
     72  	Client *clients;
     73  	Client *sel;
     74  	Client *stack;
     75 +	Client ** altsnext; /* array of all clients in the tag */
     76  	Monitor *next;
     77  	Window barwin;
     78 +	Window tabwin;
     79  	const Layout *lt[2];
     80  };
     81  
     82 @@ -234,6 +242,9 @@ static int xerror(Display *dpy, XErrorEvent *ee);
     83  static int xerrordummy(Display *dpy, XErrorEvent *ee);
     84  static int xerrorstart(Display *dpy, XErrorEvent *ee);
     85  static void zoom(const Arg *arg);
     86 +void drawTab(int nwins, int first, Monitor *m);
     87 +void altTabStart(const Arg *arg);
     88 +static void altTabEnd();
     89  
     90  /* variables */
     91  static const char broken[] = "broken";
     92 @@ -477,6 +488,7 @@ cleanup(void)
     93  	Monitor *m;
     94  	size_t i;
     95  
     96 +	altTabEnd();
     97  	view(&a);
     98  	selmon->lt[selmon->sellt] = &foo;
     99  	for (m = mons; m; m = m->next)
    100 @@ -644,6 +656,7 @@ createmon(void)
    101  	m->topbar = topbar;
    102  	m->lt[0] = &layouts[0];
    103  	m->lt[1] = &layouts[1 % LENGTH(layouts)];
    104 +	m->nTabs = 0;
    105  	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
    106  	return m;
    107  }
    108 @@ -1648,6 +1661,211 @@ spawn(const Arg *arg)
    109  	}
    110  }
    111  
    112 +void
    113 +altTab()
    114 +{
    115 +	/* move to next window */
    116 +	if (selmon->sel != NULL && selmon->sel->snext != NULL) {
    117 +		selmon->altTabN++;
    118 +		if (selmon->altTabN >= selmon->nTabs)
    119 +			selmon->altTabN = 0; /* reset altTabN */
    120 +
    121 +		focus(selmon->altsnext[selmon->altTabN]);
    122 +		restack(selmon);
    123 +	}
    124 +
    125 +	/* redraw tab */
    126 +	XRaiseWindow(dpy, selmon->tabwin);
    127 +	drawTab(selmon->nTabs, 0, selmon);
    128 +}
    129 +
    130 +void
    131 +altTabEnd()
    132 +{
    133 +	if (selmon->isAlt == 0)
    134 +		return;
    135 +
    136 +	/*
    137 +	* move all clients between 1st and choosen position,
    138 +	* one down in stack and put choosen client to the first position 
    139 +	* so they remain in right order for the next time that alt-tab is used
    140 +	*/
    141 +	if (selmon->nTabs > 1) {
    142 +		if (selmon->altTabN != 0) { /* if user picked original client do nothing */
    143 +			Client *buff = selmon->altsnext[selmon->altTabN];
    144 +			if (selmon->altTabN > 1)
    145 +				for (int i = selmon->altTabN;i > 0;i--)
    146 +					selmon->altsnext[i] = selmon->altsnext[i - 1];
    147 +			else /* swap them if there are just 2 clients */
    148 +				selmon->altsnext[selmon->altTabN] = selmon->altsnext[0];
    149 +			selmon->altsnext[0] = buff;
    150 +		}
    151 +
    152 +		/* restack clients */
    153 +		for (int i = selmon->nTabs - 1;i >= 0;i--) {
    154 +			focus(selmon->altsnext[i]);
    155 +			restack(selmon);
    156 +		}
    157 +
    158 +		free(selmon->altsnext); /* free list of clients */
    159 +	}
    160 +
    161 +	/* turn off/destroy the window */
    162 +	selmon->isAlt = 0;
    163 +	selmon->nTabs = 0;
    164 +	XUnmapWindow(dpy, selmon->tabwin);
    165 +	XDestroyWindow(dpy, selmon->tabwin);
    166 +}
    167 +
    168 +void
    169 +drawTab(int nwins, int first, Monitor *m)
    170 +{
    171 +	/* little documentation of functions */
    172 +	/* void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); */
    173 +	/* int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); */
    174 +	/* void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); */
    175 +
    176 +	Client *c;
    177 +	int h;
    178 +
    179 +	if (first) {
    180 +		Monitor *m = selmon;
    181 +		XSetWindowAttributes wa = {
    182 +			.override_redirect = True,
    183 +			.background_pixmap = ParentRelative,
    184 +			.event_mask = ButtonPressMask|ExposureMask
    185 +		};
    186 +
    187 +		selmon->maxWTab = maxWTab;
    188 +		selmon->maxHTab = maxHTab;
    189 +
    190 +		/* decide position of tabwin */
    191 +		int posX = selmon->mx;
    192 +		int posY = selmon->my;
    193 +		if (tabPosX == 0)
    194 +			posX += 0;
    195 +		if (tabPosX == 1)
    196 +			posX += (selmon->mw / 2) - (maxWTab / 2);
    197 +		if (tabPosX == 2)
    198 +			posX += selmon->mw - maxWTab;
    199 +
    200 +		if (tabPosY == 0)
    201 +			posY += selmon->mh - maxHTab;
    202 +		if (tabPosY == 1)
    203 +			posY += (selmon->mh / 2) - (maxHTab / 2);
    204 +		if (tabPosY == 2)
    205 +			posY += 0;
    206 +
    207 +		h = selmon->maxHTab;
    208 +		/* XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual, valuemask, attributes); just reference */
    209 +		m->tabwin = XCreateWindow(dpy, root, posX, posY, selmon->maxWTab, selmon->maxHTab, 2, DefaultDepth(dpy, screen),
    210 +								CopyFromParent, DefaultVisual(dpy, screen),
    211 +								CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); /* create tabwin */
    212 +
    213 +		XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor);
    214 +		XMapRaised(dpy, m->tabwin);
    215 +
    216 +	}
    217 +
    218 +	h = selmon->maxHTab  / m->nTabs;
    219 +
    220 +	int y = 0;
    221 +	int n = 0;
    222 +	for (int i = 0;i < m->nTabs;i++) { /* draw all clients into tabwin */
    223 +		c = m->altsnext[i];
    224 +		if(!ISVISIBLE(c)) continue;
    225 +		/* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */
    226 +
    227 +		n++;
    228 +		drw_setscheme(drw, scheme[(c == m->sel) ? SchemeSel : SchemeNorm]);
    229 +		drw_text(drw, 0, y, selmon->maxWTab, h, 0, c->name, 0);
    230 +		y += h;
    231 +	}
    232 +
    233 +	drw_setscheme(drw, scheme[SchemeNorm]);
    234 +	drw_map(drw, m->tabwin, 0, 0, selmon->maxWTab, selmon->maxHTab);
    235 +}
    236 +
    237 +void
    238 +altTabStart(const Arg *arg)
    239 +{
    240 +	selmon->altsnext = NULL;
    241 +	if (selmon->tabwin)
    242 +		altTabEnd();
    243 +
    244 +	if (selmon->isAlt == 1) {
    245 +		altTabEnd();
    246 +	} else {
    247 +		selmon->isAlt = 1;
    248 +		selmon->altTabN = 0;
    249 +
    250 +		Client *c;
    251 +		Monitor *m = selmon;
    252 +
    253 +		m->nTabs = 0;
    254 +		for(c = m->clients; c; c = c->next) { /* count clients */
    255 +			if(!ISVISIBLE(c)) continue;
    256 +			/* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */
    257 +
    258 +			++m->nTabs;
    259 +		}
    260 +
    261 +		if (m->nTabs > 0) {
    262 +			m->altsnext = (Client **) malloc(m->nTabs * sizeof(Client *));
    263 +
    264 +			int listIndex = 0;
    265 +			for(c = m->stack; c; c = c->snext) { /* add clients to the list */
    266 +				if(!ISVISIBLE(c)) continue;
    267 +				/* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */
    268 +
    269 +				m->altsnext[listIndex++] = c;
    270 +			}
    271 +
    272 +			drawTab(m->nTabs, 1, m);
    273 +
    274 +			struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
    275 +
    276 +			/* grab keyboard (take all input from keyboard) */
    277 +			int grabbed = 1;
    278 +			for (int i = 0;i < 1000;i++) {
    279 +				if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess)
    280 +					break;
    281 +				nanosleep(&ts, NULL);
    282 +				if (i == 1000 - 1)
    283 +					grabbed = 0;
    284 +			}
    285 +
    286 +			XEvent event;
    287 +			altTab();
    288 +			if (grabbed == 0) {
    289 +				altTabEnd();
    290 +			} else {
    291 +				while (grabbed) {
    292 +					XNextEvent(dpy, &event);
    293 +					if (event.type == KeyPress || event.type == KeyRelease) {
    294 +						if (event.type == KeyRelease && event.xkey.keycode == tabModKey) { /* if super key is released break cycle */
    295 +							break;
    296 +						} else if (event.type == KeyPress) {
    297 +							if (event.xkey.keycode == tabCycleKey) {/* if XK_s is pressed move to the next window */
    298 +								altTab();
    299 +							}
    300 +						}
    301 +					}
    302 +				}
    303 +
    304 +				c = selmon->sel;
    305 +				altTabEnd(); /* end the alt-tab functionality */
    306 +				/* XUngrabKeyboard(display, time); just a reference */
    307 +				XUngrabKeyboard(dpy, CurrentTime); /* stop taking all input from keyboard */
    308 +				focus(c);
    309 +				restack(selmon);
    310 +			}
    311 +		} else {
    312 +			altTabEnd(); /* end the alt-tab functionality */
    313 +		}
    314 +	}
    315 +}
    316 +
    317  void
    318  tag(const Arg *arg)
    319  {
    320 -- 
    321 2.37.3
    322