dwm-alttabclass-6.4.diff (9326B)
1 diff -up a/config.def.h b/config.def.h 2 --- a/config.def.h 2023-08-17 17:35:28.333393605 +0400 3 +++ b/config.def.h 2023-08-17 17:24:46.724435876 +0400 4 @@ -3,6 +3,7 @@ 5 /* alt-tab configuration */ 6 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 `*/ 7 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 */ 8 +static const unsigned int tabCycleKey2 = 0x31; /* grave key */ 9 static const unsigned int tabPosY = 1; /* tab position on Y axis, 0 = bottom, 1 = center, 2 = top */ 10 static const unsigned int tabPosX = 1; /* tab position on X axis, 0 = left, 1 = center, 2 = right */ 11 static const unsigned int maxWTab = 600; /* tab menu width */ 12 @@ -93,7 +94,8 @@ static const Key keys[] = { 13 { MODKEY, XK_period, focusmon, {.i = +1 } }, 14 { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, 15 { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, 16 - { Mod1Mask, XK_Tab, altTabStart, {0} }, 17 + { Mod1Mask, XK_Tab, altTabStart, {.i = 1} }, 18 + { Mod1Mask, XK_grave, altTabStart, {.i = 0} }, 19 TAGKEYS( XK_1, 0) 20 TAGKEYS( XK_2, 1) 21 TAGKEYS( XK_3, 2) 22 diff -up a/dwm.c b/dwm.c 23 --- a/dwm.c 2023-08-17 17:24:19.753640383 +0400 24 +++ b/dwm.c 2023-08-18 09:41:00.834187121 +0400 25 @@ -87,6 +87,7 @@ typedef struct Monitor Monitor; 26 typedef struct Client Client; 27 struct Client { 28 char name[256]; 29 + char class[256]; 30 float mina, maxa; 31 int x, y, w, h; 32 int oldx, oldy, oldw, oldh; 33 @@ -121,7 +122,9 @@ struct Monitor { 34 int mx, my, mw, mh; /* screen size */ 35 int wx, wy, ww, wh; /* window area */ 36 int altTabN; /* move that many clients forward */ 37 + int altTabNc; /* move that many clients forward when using tab for same class */ 38 int nTabs; /* number of active clients in tag */ 39 + int ncTabs; /* number of active clients under same class in tag */ 40 int isAlt; /* 1,0 */ 41 int maxWTab; 42 int maxHTab; 43 @@ -134,6 +137,7 @@ struct Monitor { 44 Client *sel; 45 Client *stack; 46 Client ** altsnext; /* array of all clients in the tag */ 47 + Client ** altsnextclass; /* array of all clients under same class in the tag */ 48 Monitor *next; 49 Window barwin; 50 Window tabwin; 51 @@ -245,6 +249,7 @@ static void zoom(const Arg *arg); 52 void drawTab(int nwins, int first, Monitor *m); 53 void altTabStart(const Arg *arg); 54 static void altTabEnd(); 55 +static void getclassname(Client *c); 56 57 /* variables */ 58 static const char broken[] = "broken"; 59 @@ -657,6 +662,7 @@ createmon(void) 60 m->lt[0] = &layouts[0]; 61 m->lt[1] = &layouts[1 % LENGTH(layouts)]; 62 m->nTabs = 0; 63 + m->ncTabs = 0; 64 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); 65 return m; 66 } 67 @@ -1059,6 +1065,7 @@ manage(Window w, XWindowAttributes *wa) 68 c->oldbw = wa->border_width; 69 70 updatetitle(c); 71 + getclassname(c); 72 if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { 73 c->mon = t->mon; 74 c->tags = t->tags; 75 @@ -1683,7 +1690,7 @@ altTab() 76 selmon->altTabN = 0; /* reset altTabN */ 77 78 focus(selmon->altsnext[selmon->altTabN]); 79 - restack(selmon); 80 + /* restack(selmon); */ 81 } 82 83 /* redraw tab */ 84 @@ -1692,8 +1699,64 @@ altTab() 85 } 86 87 void 88 +altTabClass() 89 +{ 90 + /* move to next window */ 91 + if (selmon->sel != NULL) { 92 + selmon->altTabNc++; 93 + if (selmon->altTabNc >= selmon->ncTabs) 94 + selmon->altTabNc = 0; /* reset altTabNc */ 95 + 96 + focus(selmon->altsnextclass[selmon->altTabNc]); 97 + } 98 + 99 + /* redraw tab */ 100 + XRaiseWindow(dpy, selmon->tabwin); 101 + drawTab(selmon->ncTabs, 0, selmon); 102 +} 103 + 104 +void 105 +altTabShift() 106 +{ 107 + /* move to prev window */ 108 + if (selmon->sel != NULL) { 109 + selmon->altTabN--; 110 + if (selmon->altTabN < 0) 111 + selmon->altTabN = selmon->nTabs - 1; /* reset altTabN */ 112 + 113 + if (selmon->altsnext[selmon->altTabN]) { 114 + focus(selmon->altsnext[selmon->altTabN]); 115 + } 116 + } 117 + 118 + /* redraw tab */ 119 + XRaiseWindow(dpy, selmon->tabwin); 120 + drawTab(selmon->nTabs, 0, selmon); 121 +} 122 + 123 +void 124 +altTabShiftClass() 125 +{ 126 + /* move to prev window */ 127 + if (selmon->sel != NULL) { 128 + selmon->altTabNc--; 129 + if (selmon->altTabNc < 0) 130 + selmon->altTabNc = selmon->ncTabs - 1; /* reset altTabNc */ 131 + 132 + if (selmon->altsnextclass[selmon->altTabNc]) { 133 + focus(selmon->altsnextclass[selmon->altTabNc]); 134 + } 135 + } 136 + 137 + /* redraw tab */ 138 + XRaiseWindow(dpy, selmon->tabwin); 139 + drawTab(selmon->ncTabs, 0, selmon); 140 +} 141 + 142 +void 143 altTabEnd() 144 { 145 + Client *buff = NULL; 146 if (selmon->isAlt == 0) 147 return; 148 149 @@ -1703,8 +1766,15 @@ altTabEnd() 150 * so they remain in right order for the next time that alt-tab is used 151 */ 152 if (selmon->nTabs > 1) { 153 - if (selmon->altTabN != 0) { /* if user picked original client do nothing */ 154 - Client *buff = selmon->altsnext[selmon->altTabN]; 155 + if (selmon->altTabN != 0) 156 + buff = selmon->altsnext[selmon->altTabN]; 157 + else if (selmon->altTabNc != 0) { 158 + buff = selmon->altsnextclass[selmon->altTabNc]; 159 + for (; selmon->altTabN < selmon->nTabs; selmon->altTabN++) 160 + if (selmon->altsnext[selmon->altTabN] == selmon->altsnextclass[selmon->altTabNc]) 161 + break; 162 + } 163 + if (buff) { /* if user picked original client do nothing */ 164 if (selmon->altTabN > 1) 165 for (int i = selmon->altTabN;i > 0;i--) 166 selmon->altsnext[i] = selmon->altsnext[i - 1]; 167 @@ -1720,6 +1790,7 @@ altTabEnd() 168 } 169 170 free(selmon->altsnext); /* free list of clients */ 171 + free(selmon->altsnextclass); /* free list of clients */ 172 } 173 174 /* turn off/destroy the window */ 175 @@ -1779,16 +1850,17 @@ drawTab(int nwins, int first, Monitor *m 176 177 } 178 179 - h = selmon->maxHTab / m->nTabs; 180 + h = selmon->maxHTab / nwins; 181 182 int y = 0; 183 - int n = 0; 184 - for (int i = 0;i < m->nTabs;i++) { /* draw all clients into tabwin */ 185 - c = m->altsnext[i]; 186 + for (int i = 0; i < nwins; i++) { /* draw all clients into tabwin */ 187 + if (nwins == m->nTabs) 188 + c = m->altsnext[i]; 189 + else 190 + c = m->altsnextclass[i]; 191 if(!ISVISIBLE(c)) continue; 192 /* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */ 193 194 - n++; 195 drw_setscheme(drw, scheme[(c == m->sel) ? SchemeSel : SchemeNorm]); 196 drw_text(drw, 0, y, selmon->maxWTab, h, 0, c->name, 0); 197 y += h; 198 @@ -1801,7 +1873,6 @@ drawTab(int nwins, int first, Monitor *m 199 void 200 altTabStart(const Arg *arg) 201 { 202 - selmon->altsnext = NULL; 203 if (selmon->tabwin) 204 altTabEnd(); 205 206 @@ -1810,30 +1881,47 @@ altTabStart(const Arg *arg) 207 } else { 208 selmon->isAlt = 1; 209 selmon->altTabN = 0; 210 + selmon->altTabNc = 0; 211 212 Client *c; 213 Monitor *m = selmon; 214 215 + char tempclass[256] = {'\0'}; 216 + if (selmon->sel) 217 + strncpy(tempclass, selmon->sel->class, 256); 218 + 219 m->nTabs = 0; 220 + m->ncTabs = 0; 221 for(c = m->clients; c; c = c->next) { /* count clients */ 222 if(!ISVISIBLE(c)) continue; 223 /* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */ 224 225 ++m->nTabs; 226 + 227 + if (!strcmp(c->class, tempclass)) 228 + ++m->ncTabs; 229 } 230 231 if (m->nTabs > 0) { 232 m->altsnext = (Client **) malloc(m->nTabs * sizeof(Client *)); 233 + m->altsnextclass = (Client **) malloc(m->ncTabs * sizeof(Client *)); 234 235 int listIndex = 0; 236 + int listIndexc = 0; 237 for(c = m->stack; c; c = c->snext) { /* add clients to the list */ 238 if(!ISVISIBLE(c)) continue; 239 /* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */ 240 241 m->altsnext[listIndex++] = c; 242 + 243 + if (!strcmp(c->class, tempclass)) 244 + m->altsnextclass[listIndexc++] = c; 245 } 246 247 - drawTab(m->nTabs, 1, m); 248 + if (arg->i) 249 + drawTab(m->nTabs, 1, m); 250 + else 251 + drawTab(m->ncTabs, 1, m); 252 253 struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 }; 254 255 @@ -1848,7 +1936,10 @@ altTabStart(const Arg *arg) 256 } 257 258 XEvent event; 259 - altTab(); 260 + if (arg->i) 261 + altTab(); 262 + else 263 + altTabClass(); 264 if (grabbed == 0) { 265 altTabEnd(); 266 } else { 267 @@ -1858,8 +1949,19 @@ altTabStart(const Arg *arg) 268 if (event.type == KeyRelease && event.xkey.keycode == tabModKey) { /* if super key is released break cycle */ 269 break; 270 } else if (event.type == KeyPress) { 271 - if (event.xkey.keycode == tabCycleKey) {/* if XK_s is pressed move to the next window */ 272 - altTab(); 273 + if (event.xkey.keycode == tabCycleKey || event.xkey.keycode == tabCycleKey2 ) { /* if XK_s is pressed move to the next window */ 274 + if (arg->i) { 275 + if (CLEANMASK((Mod1Mask|ShiftMask)) == CLEANMASK(event.xkey.state)) 276 + altTabShift(); 277 + else 278 + altTab(); 279 + } else { 280 + if (CLEANMASK((Mod1Mask|ShiftMask)) == CLEANMASK(event.xkey.state)) 281 + altTabShiftClass(); 282 + else 283 + altTabClass(); 284 + } 285 + 286 } 287 } 288 } 289 @@ -2231,6 +2333,15 @@ updatetitle(Client *c) 290 strcpy(c->name, broken); 291 } 292 293 +void 294 +getclassname(Client *c) 295 +{ 296 + gettextprop(c->win, XA_WM_CLASS, c->class, sizeof c->class); 297 + 298 + if (c->class[0] == '\0') /* hack to mark broken clients */ 299 + strcpy(c->name, broken); 300 +} 301 + 302 void 303 updatewindowtype(Client *c) 304 {