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