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