all repos — dwm @ 8fa47ac679cfd91c022a35f2469bea7396e5f7c7

fork of suckless dynamic window manager

view.c (view raw)

  1/*
  2 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
  3 * See LICENSE file for license details.
  4 */
  5#include "dwm.h"
  6
  7/* static */
  8
  9static Client *
 10minclient(void) {
 11	Client *c, *min;
 12
 13	if((clients && clients->isfloat) || arrange == dofloat)
 14		return clients; /* don't touch floating order */
 15	for(min = c = clients; c; c = c->next)
 16		if(c->weight < min->weight)
 17			min = c;
 18	return min;
 19}
 20
 21static Client *
 22nexttiled(Client *c) {
 23	for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
 24	return c;
 25}
 26
 27static void
 28reorder(void) {
 29	Client *c, *newclients, *tail;
 30
 31	newclients = tail = NULL;
 32	while((c = minclient())) {
 33		detach(c);
 34		if(tail) {
 35			c->prev = tail;
 36			tail->next = c;
 37			tail = c;
 38		}
 39		else
 40			tail = newclients = c;
 41	}
 42	clients = newclients;
 43}
 44
 45static void
 46togglemax(Client *c)
 47{
 48	XEvent ev;
 49	if((c->ismax = !c->ismax)) {
 50		c->rx = c->x; c->x = sx;
 51		c->ry = c->y; c->y = bh;
 52		c->rw = c->w; c->w = sw - 2 * BORDERPX;
 53		c->rh = c->h; c->h = sh - bh - 2 * BORDERPX;
 54	}
 55	else {
 56		c->x = c->rx;
 57		c->y = c->ry;
 58		c->w = c->rw;
 59		c->h = c->rh;
 60	}
 61	resize(c, True, TopLeft);
 62	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
 63}
 64
 65/* extern */
 66
 67void (*arrange)(Arg *) = DEFMODE;
 68Bool isvertical = VERTICALSTACK;
 69StackPos stackpos = STACKPOS;
 70
 71void
 72detach(Client *c) {
 73	if(c->prev)
 74		c->prev->next = c->next;
 75	if(c->next)
 76		c->next->prev = c->prev;
 77	if(c == clients)
 78		clients = c->next;
 79	c->next = c->prev = NULL;
 80}
 81
 82void
 83dofloat(Arg *arg) {
 84	Client *c;
 85
 86	for(c = clients; c; c = c->next) {
 87		if(isvisible(c)) {
 88			resize(c, True, TopLeft);
 89		}
 90		else
 91			ban(c);
 92	}
 93	if(!sel || !isvisible(sel)) {
 94		for(c = stack; c && !isvisible(c); c = c->snext);
 95		focus(c);
 96	}
 97	restack();
 98}
 99
100/* This algorithm is based on a (M)aster area and a (S)tacking area.
101 * It supports following arrangements:
102 * 	SSMMM	MMMMM	MMMSS
103 * 	SSMMM	SSSSS	MMMSS
104 */
105void
106dotile(Arg *arg) {
107	int i, n, stackw, stackh, tw, th;
108	Client *c;
109
110	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
111		n++;
112
113	if(stackpos == StackBottom) {
114		stackw = sw;
115		stackh = sh - bh - master;
116	}
117	else {
118		stackw = sw - master;
119		stackh = sh - bh;
120	}
121
122	if(isvertical) {
123		tw = stackw;
124		if(n > 1)
125			th = stackh / (n - 1);
126		else
127			th = stackh;
128	}
129	else {
130		th = stackh;
131		if(n > 1)
132			tw = stackw / (n - 1);
133		else
134			tw = stackw;
135	}
136
137	for(i = 0, c = clients; c; c = c->next) {
138		if(isvisible(c)) {
139			if(c->isfloat) {
140				resize(c, True, TopLeft);
141				continue;
142			}
143			c->ismax = False;
144			if(n == 1) { /* only 1 window */
145				c->x = sx;
146				c->y = sy + bh;
147				c->w = sw - 2 * BORDERPX;
148				c->h = sh - 2 * BORDERPX - bh;
149			}
150			else if(i == 0) { /* master window */
151				c->x = sx;
152				if(stackpos == StackLeft)
153					c->x += master;
154				c->y = sy + bh;
155				if(isvertical) {
156					c->w = master - 2 * BORDERPX;
157					c->h = sh - 2 * BORDERPX - bh;
158				}
159				else {
160					c->w = sw;
161					c->h = master - 2 * BORDERPX;
162				}
163			}
164			else if((isvertical && th > bh) || (!isvertical && tw > MINW)) {
165				/* tile window */
166				c->x = sx;
167				if(isvertical)
168					c->y = sy + (i - 1) * th + bh;
169				else
170					c->y = sy + bh;
171				if(stackpos == StackRight)
172					c->x += master;
173				else if(stackpos == StackBottom)
174					c->y += master;
175				c->w = tw - 2 * BORDERPX;
176				c->h = th - 2 * BORDERPX;
177				if(i + 1 == n) { /* fixes for last tile to take up rest space */
178					if(isvertical)
179						c->h = sh - c->y - 2 * BORDERPX;
180					else {
181						if(stackpos == StackLeft)
182							c->w = master - c->x - 2 * BORDERPX;
183						else
184							c->w = sw - c->x - 2 * BORDERPX;
185					}
186				}
187			}
188			else { /* fallback if th < bh resp. tw < MINW */
189				c->x = sx;
190				c->y = sy + bh;
191				if(stackpos == StackRight)
192					c->x += master;
193				else if(stackpos == StackBottom)
194					c->y += master;
195				c->w = stackw - 2 * BORDERPX;
196				c->h = stackh - 2 * BORDERPX;
197			}
198			resize(c, False, TopLeft);
199			i++;
200		}
201		else
202			ban(c);
203	}
204	if(!sel || !isvisible(sel)) {
205		for(c = stack; c && !isvisible(c); c = c->snext);
206		focus(c);
207	}
208	restack();
209}
210
211void
212focusnext(Arg *arg) {
213	Client *c;
214   
215	if(!sel)
216		return;
217
218	if(!(c = getnext(sel->next)))
219		c = getnext(clients);
220	if(c) {
221		focus(c);
222		restack();
223	}
224}
225
226void
227focusprev(Arg *arg) {
228	Client *c;
229
230	if(!sel)
231		return;
232
233	if(!(c = getprev(sel->prev))) {
234		for(c = clients; c && c->next; c = c->next);
235		c = getprev(c);
236	}
237	if(c) {
238		focus(c);
239		restack();
240	}
241}
242
243Bool
244isvisible(Client *c) {
245	unsigned int i;
246
247	for(i = 0; i < ntags; i++)
248		if(c->tags[i] && seltag[i])
249			return True;
250	return False;
251}
252
253void
254resizecol(Arg *arg) {
255	unsigned int n;
256	Client *c;
257
258	for(n = 0, c = clients; c; c = c->next)
259		if(isvisible(c) && !c->isfloat)
260			n++;
261	if(!sel || sel->isfloat || n < 2 || (arrange == dofloat))
262		return;
263
264	if(sel == getnext(clients)) {
265		if(master + arg->i > sw - MINW || master + arg->i < MINW)
266			return;
267		master += arg->i;
268	}
269	else {
270		if(master - arg->i > sw - MINW || master - arg->i < MINW)
271			return;
272		master -= arg->i;
273	}
274	arrange(NULL);
275}
276
277void
278restack(void) {
279	Client *c;
280	XEvent ev;
281
282	if(!sel) {
283		drawstatus();
284		return;
285	}
286	if(sel->isfloat || arrange == dofloat) {
287		XRaiseWindow(dpy, sel->win);
288		XRaiseWindow(dpy, sel->twin);
289	}
290	if(arrange != dofloat)
291		for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
292			XLowerWindow(dpy, c->twin);
293			XLowerWindow(dpy, c->win);
294		}
295	drawall();
296	XSync(dpy, False);
297	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
298}
299
300void
301togglemode(Arg *arg) {
302	arrange = (arrange == dofloat) ? dotile : dofloat;
303	if(sel)
304		arrange(NULL);
305	else
306		drawstatus();
307}
308
309void
310toggleview(Arg *arg) {
311	unsigned int i;
312
313	seltag[arg->i] = !seltag[arg->i];
314	for(i = 0; i < ntags && !seltag[i]; i++);
315	if(i == ntags)
316		seltag[arg->i] = True; /* cannot toggle last view */
317	reorder();
318	arrange(NULL);
319}
320
321void
322view(Arg *arg) {
323	unsigned int i;
324
325	for(i = 0; i < ntags; i++)
326		seltag[i] = False;
327	seltag[arg->i] = True;
328	reorder();
329	arrange(NULL);
330}
331
332void
333viewall(Arg *arg) {
334	unsigned int i;
335
336	for(i = 0; i < ntags; i++)
337		seltag[i] = True;
338	reorder();
339	arrange(NULL);
340}
341
342void
343zoom(Arg *arg) {
344	unsigned int n;
345	Client *c;
346
347	if(!sel)
348		return;
349
350	if(sel->isfloat || (arrange == dofloat)) {
351		togglemax(sel);
352		return;
353	}
354
355	for(n = 0, c = clients; c; c = c->next)
356		if(isvisible(c) && !c->isfloat)
357			n++;
358	if(n < 2 || (arrange == dofloat))
359		return;
360
361	if((c = sel) == nexttiled(clients))
362		if(!(c = nexttiled(c->next)))
363			return;
364	detach(c);
365	if(clients)
366		clients->prev = c;
367	c->next = clients;
368	clients = c;
369	focus(c);
370	arrange(NULL);
371}