int alttabn; /* move that many clients forward */ int ntabs; /* number of active clients in tag */ int isalt; Client **altsnext; /* array of all clients in the tag */ Window alttabwin; void alttab() { Monitor *m = selmon; /* move to next window */ if (m->sel && m->sel->snext) { alttabn++; if (alttabn >= ntabs) alttabn = 0; /* reset alttabn */ focus(altsnext[alttabn]); restack(m); } /* redraw tab */ XRaiseWindow(dpy, alttabwin); drawalttab(ntabs, 0, m); } void alttabend() { Monitor *m = selmon; Client *buff; int i; if (!isalt) return; /* Move all clients between first and choosen position, * one down in stack and put choosen client to the first position * so they remain in right order for the next time that alt-tab is used */ if (ntabs > 1) { if (alttabn != 0) { /* if user picked original client do nothing */ buff = altsnext[alttabn]; if (alttabn > 1) for (i = alttabn; i > 0; i--) altsnext[i] = altsnext[i - 1]; else /* swap them if there are just 2 clients */ altsnext[alttabn] = altsnext[0]; altsnext[0] = buff; } /* restack clients */ for (i = ntabs - 1; i >= 0; i--) { focus(altsnext[i]); restack(m); } free(altsnext); /* free list of clients */ } /* destroy the window */ isalt = 0; ntabs = 0; XUnmapWindow(dpy, alttabwin); XDestroyWindow(dpy, alttabwin); } void drawalttab(int nwins, int first, Monitor *m) { Client *c; int i, h; int y = 0; int px = m->mx; int py = m->my; if (first) { XSetWindowAttributes wa = { .override_redirect = True, #if BAR_ALPHA_PATCH .background_pixel = 0, .border_pixel = 0, .colormap = cmap, #else .background_pixmap = ParentRelative, #endif // BAR_ALPHA_PATCH .event_mask = ButtonPressMask|ExposureMask }; /* decide position of tabwin */ if (tabposx == 1) px = m->mx + (m->mw / 2) - (maxwtab / 2); else if (tabposx == 2) px = m->mx + m->mw - maxwtab; if (tabposy == 1) py = m->my + (m->mh / 2) - (maxhtab / 2); else if (tabposy == 2) py = m->my + m->mh - maxhtab; h = maxhtab; #if BAR_ALPHA_PATCH alttabwin = XCreateWindow(dpy, root, px, py, maxwtab, maxhtab, 2, depth, InputOutput, visual, CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa); #else alttabwin = XCreateWindow(dpy, root, px, py, maxwtab, maxhtab, 2, DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); #endif // BAR_ALPHA_PATCH XDefineCursor(dpy, alttabwin, cursor[CurNormal]->cursor); XMapRaised(dpy, alttabwin); } h = maxhtab / ntabs; for (i = 0; i < ntabs; i++) { /* draw all clients into tabwin */ c = altsnext[i]; if (!ISVISIBLE(c)) continue; if (HIDDEN(c)) continue; drw_setscheme(drw, scheme[c == m->sel ? SchemeSel : SchemeNorm]); drw_text(drw, 0, y, maxwtab, h, 0, c->name, 0, 0); y += h; } drw_setscheme(drw, scheme[SchemeNorm]); drw_map(drw, alttabwin, 0, 0, maxwtab, maxhtab); } void alttabstart(const Arg *arg) { Client *c; Monitor *m = selmon; int grabbed; int i; altsnext = NULL; if (alttabwin) alttabend(); if (isalt == 1) { alttabend(); return; } isalt = 1; alttabn = 0; ntabs = 0; for (c = m->clients; c; c = c->next) { if (!ISVISIBLE(c)) continue; if (HIDDEN(c)) continue; ++ntabs; } if (!ntabs) { alttabend(); return; } altsnext = (Client **) malloc(ntabs * sizeof(Client *)); for (i = 0, c = m->stack; c; c = c->snext) { if (!ISVISIBLE(c)) continue; if (HIDDEN(c)) continue; altsnext[i] = c; i++; } drawalttab(ntabs, 1, m); struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 }; /* grab keyboard (take all input from keyboard) */ grabbed = 1; for (i = 0; i < 1000; i++) { if (XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess) break; nanosleep(&ts, NULL); if (i == 1000 - 1) grabbed = 0; } XEvent event; alttab(); if (grabbed == 0) { alttabend(); return; } while (grabbed) { XNextEvent(dpy, &event); if (event.type == KeyPress || event.type == KeyRelease) { if (event.type == KeyRelease && event.xkey.keycode == tabmodkey) /* if mod key is released break cycle */ break; if (event.type == KeyPress) { if (event.xkey.keycode == tabcyclekey) { /* if tab is pressed move to the next window */ alttab(); } } } } c = m->sel; alttabend(); XUngrabKeyboard(dpy, CurrentTime); focus(c); restack(m); }