224 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			224 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 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);
 | |
| }
 |