about summary refs log tree commit diff stats
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
...
* pager: fix incremental search with empty stringbptato2024-03-301-3/+11
| | | | | | | | | | | | | | This is broken in w3m too, so we take nvi behavior instead. Also, we now consistently complain when the user tries to search for an empty string instead of just occasionally spitting out "invalid regex" alerts. (In w3m, /search^M/^M just jumps to the first search result with ISEARCH. In nvi, it jumps to the second one with both searchincr on and off. w3m only produces the latter behavior with regular search, which is I assume why I made it work this way, but it's still inconsistent for no good reason.)
* pager: fix weird halfPage* behaviorbptato2024-03-301-6/+6
| | | | | | | | | For some reason, halfPageDown decremented height instead of incrementing it, which caused some rather weird behavior where halfPageUp + halfPageDown would put the cursor in a different position than it was before. Also, we must increment *before* dividing to mimic vi behavior properly.
* pager: exclude status line from buffer heightbptato2024-03-302-1/+9
|
* layout: add missing min/max heights to absolute sizesbptato2024-03-301-1/+3
|
* layout: fix various table cell sizing bugsbptato2024-03-301-47/+35
| | | | | | | | | | It seems I never properly converted the table cell (pre-)sizing code to use SizeConstraints, so it was still in a half-working state where it broke down e.g. on nested tables. * move auto check to canpx * simplify convoluted and broken table cell size calculation into something that actually works
* pager: edit source fixesbptato2024-03-302-71/+56
| | | | | | | * URI-decode path name for local files in default config * (ab)use mailcap command quoting for passing params to editor command instead of replicating it badly in formatEditorName * rename mailcap enums
* layout: fix float positioning with marginsbptato2024-03-301-1/+1
| | | | | | | | | | | | | | | Here we are restricting the float to the same width constraint as its parent, so we must add offset.x both when the float is larger than this constraint *and* when the float fits into the constraint. An example of what this fixes: <div style="padding-left: 10em; background: green"> <div style="float: right; background: red"> wat ^ previously the float was positioned as if the padding had been on the *right*, because it did not take into account offset.x.
* buffer: fix markURL in plaintextbptato2024-03-291-3/+31
| | | | | | | We must HTML escape data, or the fragment parser will parse plain text as markup. (However, just running htmlEscape() on data is not enough; that would also mark <, ', etc. as &gt, &apos. So we only escape after the regex is executed.)
* term: flush stdout in anyKeybptato2024-03-291-0/+1
|
* pager: fix broken writeToFilebptato2024-03-292-5/+4
|
* ansi2html: support passing titlesbptato2024-03-292-17/+22
| | | | | | | Use content type attributes so e.g. git.cgi can set the title even with a text/x-ansi content type. (This commit also fixes some bugs in content type attribute handling.)
* fflush() before forksbptato2024-03-283-6/+19
| | | | | seems like a good idea, especially because CGI uses stdout as the IPC mechanism
* Add capsicum supportbptato2024-03-2811-38/+169
| | | | | | | | | | | | | It's the sandboxing system of FreeBSD. Quite pleasant to work with. (Just tr
/*
 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
 * See LICENSE file for license details.
 */
#include "dwm.h"

/* static */

static Client *
minclient(void) {
	Client *c, *min;

	if((clients && clients->isfloat) || arrange == dofloat)
		return clients; /* don't touch floating order */
	for(min = c = clients; c; c = c->next)
		if(c->weight < min->weight)
			min = c;
	return min;
}

static Client *
nexttiled(Client *c) {
	for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
	return c;
}

static void
reorder(void) {
	Client *c, *newclients, *tail;

	newclients = tail = NULL;
	while((c = minclient())) {
		detach(c);
		if(tail) {
			c->prev = tail;
			tail->next = c;
			tail = c;
		}
		else
			tail = newclients = c;
	}
	clients = newclients;
}

static void
togglemax(Client *c)
{
	XEvent ev;
	if((c->ismax = !c->ismax)) {
		c->rx = c->x; c->x = sx;
		c->ry = c->y; c->y = bh;
		c->rw = c->w; c->w = sw - 2 * BORDERPX;
		c->rh = c->h; c->h = sh - bh - 2 * BORDERPX;
	}
	else {
		c->x = c->rx;
		c->y = c->ry;
		c->w = c->rw;
		c->h = c->rh;
	}
	resize(c, True, TopLeft);
	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}

/* extern */

void (*arrange)(Arg *) = DEFMODE;
Bool isvertical = VERTICALSTACK;
StackPos stackpos = STACKPOS;

void
detach(Client *c) {
	if(c->prev)
		c->prev->next = c->next;
	if(c->next)
		c->next->prev = c->prev;
	if(c == clients)
		clients = c->next;
	c->next = c->prev = NULL;
}

void
dofloat(Arg *arg) {
	Client *c;

	for(c = clients; c; c = c->next) {
		if(isvisible(c)) {
			resize(c, True, TopLeft);
		}
		else
			ban(c);
	}
	if(!sel || !isvisible(sel)) {
		for(c = stack; c && !isvisible(c); c = c->snext);
		focus(c);
	}
	restack();
}

/* This algorithm is based on a (M)aster area and a (S)tacking area.
 * It supports following arrangements:
 * 	MMMS		MMMM		SMMM
 * 	MMMS		MMMM		SMMM
 * 	MMMS		SSSS		SMMM
 */
void
dotile(Arg *arg) {
	int h, i, n, w;
	Client *c;

	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
		n++;

	if(isvertical) {
		if(stackpos == StackBottom) {
			w = sw;
			if(n > 1)
				h = (sh - bh) / (n - 1);
			else
				h = sh - bh;
		}
		else {
			w = sw - master;
			if(n > 1)
				h = (sh - bh) / (n - 1);
			else
				h = sh - bh;
		}
	}
	else { /* horizontal stack */

	}

	for(i = 0, c = clients; c; c = c->next) {
		if(isvisible(c)) {
			if(c->isfloat) {
				resize(c, True, TopLeft);
				continue;
			}
			c->ismax = False;
			if(n == 1) {
				c->x = sx;
				c->y = sy + bh;
				c->w = sw - 2 * BORDERPX;
				c->h = sh - 2 * BORDERPX - bh;
			}
			else if(i == 0) {
				c->x = sx;
				c->y = sy + bh;
				c->w = master - 2 * BORDERPX;
				c->h = sh - 2 * BORDERPX - bh;
			}
			else if(h > bh) {
				c->x = sx + master;
				c->y = sy + (i - 1) * h + bh;
				c->w = w - 2 * BORDERPX;
				if(i + 1 == n)
					c->h = sh - c->y - 2 * BORDERPX;
				else
					c->h = h - 2 * BORDERPX;
			}
			else { /* fallback if h < bh */
				c->x = sx + master;
				c->y = sy + bh;
				c->w = w - 2 * BORDERPX;
				c->h = sh - 2 * BORDERPX - bh;
			}
			resize(c, False, TopLeft);
			i++;
		}
		else
			ban(c);
	}
	if(!sel || !isvisible(sel)) {
		for(c = stack; c && !isvisible(c); c = c->snext);
		focus(c);
	}
	restack();
}

void
focusnext(Arg *arg) {
	Client *c;
   
	if(!sel)
		return;

	if(!(c = getnext(sel->next)))
		c = getnext(clients);
	if(c) {
		focus(c);
		restack();
	}
}

void
focusprev(Arg *arg) {
	Client *c;

	if(!sel)
		return;

	if(!(c = getprev(sel->prev))) {
		for(c = clients; c && c->next; c = c->next);
		c = getprev(c);
	}
	if(c) {
		focus(c);
		restack();
	}
}

Bool
isvisible(Client *c) {
	unsigned int i;

	for(i = 0; i < ntags; i++)
		if(c->tags[i] && seltag[i])
			return True;
	return False;
}

void
resizecol(Arg *arg) {
	unsigned int n;
	Client *c;

	for(n = 0, c = clients; c; c = c->next)
		if(isvisible(c) && !c->isfloat)
			n++;
	if(!sel || sel->isfloat || n < 2 || (arrange == dofloat))
		return;

	if(sel == getnext(clients)) {
		if(master + arg->i > sw - 100 || master + arg->i < 100)
			return;
		master += arg->i;
	}
	else {
		if(master - arg->i > sw - 100 || master - arg->i < 100)
			return;
		master -= arg->i;
	}
	arrange(NULL);
}

void
restack(void) {
	Client *c;
	XEvent ev;

	if(!sel) {
		drawstatus();
		return;
	}
	if(sel->isfloat || arrange == dofloat) {
		XRaiseWindow(dpy, sel->win);
		XRaiseWindow(dpy, sel->twin);
	}
	if(arrange != dofloat)
		for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
			XLowerWindow(dpy, c->twin);
			XLowerWindow(dpy, c->win);
		}
	drawall();
	XSync(dpy, False);
	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}

void
togglemode(Arg *arg) {
	arrange = (arrange == dofloat) ? dotile : dofloat;
	if(sel)
		arrange(NULL);
	else
		drawstatus();
}

void
toggleview(Arg *arg) {
	unsigned int i;

	seltag[arg->i] = !seltag[arg->i];
	for(i = 0; i < ntags && !seltag[i]; i++);
	if(i == ntags)
		seltag[arg->i] = True; /* cannot toggle last view */
	reorder();
	arrange(NULL);
}

void
view(Arg *arg) {
	unsigned int i;

	for(i = 0; i < ntags; i++)
		seltag[i] = False;
	seltag[arg->i] = True;
	reorder();
	arrange(NULL);
}

void
viewall(Arg *arg) {
	unsigned int i;

	for(i = 0; i < ntags; i++)
		seltag[i] = True;
	reorder();
	arrange(NULL);
}

void
zoom(Arg *arg) {
	unsigned int n;
	Client *c;

	if(!sel)
		return;

	if(sel->isfloat || (arrange == dofloat)) {
		togglemax(sel);
		return;
	}

	for(n = 0, c = clients; c; c = c->next)
		if(isvisible(c) && !c->isfloat)
			n++;
	if(n < 2 || (arrange == dofloat))
		return;

	if((c = sel) == nexttiled(clients))
		if(!(c = nexttiled(c->next)))
			return;
	detach(c);
	if(clients)
		clients->prev = c;
	c->next = clients;
	clients = c;
	focus(c);
	arrange(NULL);
}