alttab.c (4652B)
1 int alttabn; /* move that many clients forward */ 2 int ntabs; /* number of active clients in tag */ 3 int isalt; 4 Client **altsnext; /* array of all clients in the tag */ 5 Window alttabwin; 6 7 void 8 alttab() 9 { 10 Monitor *m = selmon; 11 12 /* move to next window */ 13 if (m->sel && m->sel->snext) { 14 alttabn++; 15 if (alttabn >= ntabs) 16 alttabn = 0; /* reset alttabn */ 17 18 focus(altsnext[alttabn]); 19 restack(m); 20 } 21 22 /* redraw tab */ 23 XRaiseWindow(dpy, alttabwin); 24 drawalttab(ntabs, 0, m); 25 } 26 27 void 28 alttabend() 29 { 30 Monitor *m = selmon; 31 Client *buff; 32 int i; 33 34 if (!isalt) 35 return; 36 37 /* Move all clients between first and choosen position, 38 * one down in stack and put choosen client to the first position 39 * so they remain in right order for the next time that alt-tab is used 40 */ 41 if (ntabs > 1) { 42 if (alttabn != 0) { /* if user picked original client do nothing */ 43 buff = altsnext[alttabn]; 44 if (alttabn > 1) 45 for (i = alttabn; i > 0; i--) 46 altsnext[i] = altsnext[i - 1]; 47 else /* swap them if there are just 2 clients */ 48 altsnext[alttabn] = altsnext[0]; 49 altsnext[0] = buff; 50 } 51 52 /* restack clients */ 53 for (i = ntabs - 1; i >= 0; i--) { 54 focus(altsnext[i]); 55 restack(m); 56 } 57 58 free(altsnext); /* free list of clients */ 59 } 60 61 /* destroy the window */ 62 isalt = 0; 63 ntabs = 0; 64 XUnmapWindow(dpy, alttabwin); 65 XDestroyWindow(dpy, alttabwin); 66 } 67 68 void 69 drawalttab(int nwins, int first, Monitor *m) 70 { 71 Client *c; 72 int i, h; 73 int y = 0; 74 int px = m->mx; 75 int py = m->my; 76 77 if (first) { 78 XSetWindowAttributes wa = { 79 .override_redirect = True, 80 #if BAR_ALPHA_PATCH 81 .background_pixel = 0, 82 .border_pixel = 0, 83 .colormap = cmap, 84 #else 85 .background_pixmap = ParentRelative, 86 #endif // BAR_ALPHA_PATCH 87 .event_mask = ButtonPressMask|ExposureMask 88 }; 89 90 /* decide position of tabwin */ 91 if (tabposx == 1) 92 px = m->mx + (m->mw / 2) - (maxwtab / 2); 93 else if (tabposx == 2) 94 px = m->mx + m->mw - maxwtab; 95 96 if (tabposy == 1) 97 py = m->my + (m->mh / 2) - (maxhtab / 2); 98 else if (tabposy == 2) 99 py = m->my + m->mh - maxhtab; 100 101 h = maxhtab; 102 103 #if BAR_ALPHA_PATCH 104 alttabwin = XCreateWindow(dpy, root, px, py, maxwtab, maxhtab, 2, depth, 105 InputOutput, visual, 106 CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa); 107 #else 108 alttabwin = XCreateWindow(dpy, root, px, py, maxwtab, maxhtab, 2, DefaultDepth(dpy, screen), 109 CopyFromParent, DefaultVisual(dpy, screen), 110 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); 111 #endif // BAR_ALPHA_PATCH 112 113 XDefineCursor(dpy, alttabwin, cursor[CurNormal]->cursor); 114 XMapRaised(dpy, alttabwin); 115 } 116 117 h = maxhtab / ntabs; 118 for (i = 0; i < ntabs; i++) { /* draw all clients into tabwin */ 119 c = altsnext[i]; 120 if (!ISVISIBLE(c)) 121 continue; 122 if (HIDDEN(c)) 123 continue; 124 125 drw_setscheme(drw, scheme[c == m->sel ? SchemeSel : SchemeNorm]); 126 drw_text(drw, 0, y, maxwtab, h, 0, c->name, 0, 0); 127 y += h; 128 } 129 130 drw_setscheme(drw, scheme[SchemeNorm]); 131 drw_map(drw, alttabwin, 0, 0, maxwtab, maxhtab); 132 } 133 134 void 135 alttabstart(const Arg *arg) 136 { 137 Client *c; 138 Monitor *m = selmon; 139 int grabbed; 140 int i; 141 142 altsnext = NULL; 143 if (alttabwin) 144 alttabend(); 145 146 if (isalt == 1) { 147 alttabend(); 148 return; 149 } 150 151 isalt = 1; 152 alttabn = 0; 153 ntabs = 0; 154 155 for (c = m->clients; c; c = c->next) { 156 if (!ISVISIBLE(c)) 157 continue; 158 if (HIDDEN(c)) 159 continue; 160 161 ++ntabs; 162 } 163 164 if (!ntabs) { 165 alttabend(); 166 return; 167 } 168 169 altsnext = (Client **) malloc(ntabs * sizeof(Client *)); 170 171 for (i = 0, c = m->stack; c; c = c->snext) { 172 if (!ISVISIBLE(c)) 173 continue; 174 if (HIDDEN(c)) 175 continue; 176 177 altsnext[i] = c; 178 i++; 179 } 180 181 drawalttab(ntabs, 1, m); 182 183 struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 }; 184 185 /* grab keyboard (take all input from keyboard) */ 186 grabbed = 1; 187 for (i = 0; i < 1000; i++) { 188 if (XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess) 189 break; 190 nanosleep(&ts, NULL); 191 if (i == 1000 - 1) 192 grabbed = 0; 193 } 194 195 XEvent event; 196 alttab(); 197 198 if (grabbed == 0) { 199 alttabend(); 200 return; 201 } 202 203 while (grabbed) { 204 XNextEvent(dpy, &event); 205 if (event.type == KeyPress || event.type == KeyRelease) { 206 if (event.type == KeyRelease && event.xkey.keycode == tabmodkey) /* if mod key is released break cycle */ 207 break; 208 209 if (event.type == KeyPress) { 210 if (event.xkey.keycode == tabcyclekey) { /* if tab is pressed move to the next window */ 211 alttab(); 212 } 213 } 214 } 215 } 216 217 c = m->sel; 218 alttabend(); 219 220 XUngrabKeyboard(dpy, CurrentTime); 221 focus(c); 222 restack(m); 223 }