sites

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

dwm-alttab-20220709-d3f93c7.diff (10048B)


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