all repos — dwm @ 69408d384d55b69f66ea52f8767eb577a34d9ae2

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;
 68StackPos stackpos = STACKPOS;
 69
 70void
 71detach(Client *c) {
 72	if(c->prev)
 73		c->prev->next = c->next;
 74	if(c->next)
 75		c->next->prev = c->prev;
 76	if(c == clients)
 77		clients = c->next;
 78	c->next = c->prev = NULL;
 79}
 80
 81void
 82dofloat(Arg *arg) {
 83	Client *c;
 84
 85	for(c = clients; c; c = c->next) {
 86		if(isvisible(c)) {
 87			resize(c, True, TopLeft);
 88		}
 89		else
 90			ban(c);
 91	}
 92	if(!sel || !isvisible(sel)) {
 93		for(c = stack; c && !isvisible(c); c = c->snext);
 94		focus(c);
 95	}
 96	restack();
 97}
 98
 99/* This algorithm is based on a (M)aster area and a (S)tacking area.
100 * It supports following arrangements:
101 * 	SSMMM	MMMMM	MMMSS
102 * 	SSMMM	SSSSS	MMMSS
103 */
104void
105dotile(Arg *arg) {
106	unsigned int i, n, md, stackw, stackh, tw, th;
107	Client *c;
108
109	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
110		n++;
111
112	if(stackpos == StackBottom) {
113		md = ((sh - bh) * master) / 100;
114		stackw = sw;
115		stackh = sh - bh - md;
116	}
117	else {
118		md = (sw * master) / 100;
119		stackw = sw - md;
120		stackh = sh - bh;
121	}
122
123	tw = stackw;
124	if(n > 1)
125		th = stackh / (n - 1);
126	else
127		th = stackh;
128
129	for(i = 0, c = clients; c; c = c->next) {
130		if(isvisible(c)) {
131			if(c->isfloat) {
132				resize(c, True, TopLeft);
133				continue;
134			}
135			c->ismax = False;
136			c->x = sx;
137			c->y = sy + bh;
138			if(n == 1) { /* only 1 window */
139				c->w = sw - 2 * BORDERPX;
140				c->h = sh - 2 * BORDERPX - bh;
141			}
142			else if(i == 0) { /* master window */
143				if(stackpos == StackLeft)
144					c->x += stackw;
145				switch(stackpos) {
146				case StackLeft:
147				case StackRight:
148					c->w = md - 2 * BORDERPX;
149					c->h = sh - bh - 2 * BORDERPX;
150					break;
151				case StackBottom:
152					c->w = sw - 2 * BORDERPX;
153					c->h = md - 2 * BORDERPX;
154					break;
155				}
156			}
157			else {  /* tile window */
158				if(stackpos == StackRight)
159					c->x += md;
160				if(th > bh) {
161					switch(stackpos) {
162					case StackLeft:
163					case StackRight:
164						c->y = sy + (i - 1) * th + bh;
165						if(i + 1 == n)
166							c->h = sh - c->y - 2 * BORDERPX;
167						break;
168					case StackBottom:
169						c->y = sy + md + (i - 1) * th + bh;
170						if(i + 1 == n)
171							c->h = sh - c->y - 2 * BORDERPX;
172						break;
173					}
174					c->w = tw - 2 * BORDERPX;
175					c->h = th - 2 * BORDERPX;
176				}
177				else { /* fallback if th < bh */
178					if(stackpos == StackBottom)
179						c->y += md;
180					c->w = stackw - 2 * BORDERPX;
181					c->h = stackh - 2 * BORDERPX;
182				}
183			}
184			resize(c, False, TopLeft);
185			i++;
186		}
187		else
188			ban(c);
189	}
190	if(!sel || !isvisible(sel)) {
191		for(c = stack; c && !isvisible(c); c = c->snext);
192		focus(c);
193	}
194	restack();
195}
196
197void
198focusnext(Arg *arg) {
199	Client *c;
200   
201	if(!sel)
202		return;
203
204	if(!(c = getnext(sel->next)))
205		c = getnext(clients);
206	if(c) {
207		focus(c);
208		restack();
209	}
210}
211
212void
213focusprev(Arg *arg) {
214	Client *c;
215
216	if(!sel)
217		return;
218
219	if(!(c = getprev(sel->prev))) {
220		for(c = clients; c && c->next; c = c->next);
221		c = getprev(c);
222	}
223	if(c) {
224		focus(c);
225		restack();
226	}
227}
228
229Bool
230isvisible(Client *c) {
231	unsigned int i;
232
233	for(i = 0; i < ntags; i++)
234		if(c->tags[i] && seltag[i])
235			return True;
236	return False;
237}
238
239void
240resizecol(Arg *arg) {
241	unsigned int n;
242	Client *c;
243
244	for(n = 0, c = clients; c; c = c->next)
245		if(isvisible(c) && !c->isfloat)
246			n++;
247	if(!sel || sel->isfloat || n < 2 || (arrange == dofloat))
248		return;
249
250	if(sel == getnext(clients)) {
251		if(master + arg->i > 95 || master + arg->i < 5)
252			return;
253		master += arg->i;
254	}
255	else {
256		if(master - arg->i > 95 || master - arg->i < 5)
257			return;
258		master -= arg->i;
259	}
260	arrange(NULL);
261}
262
263void
264restack(void) {
265	Client *c;
266	XEvent ev;
267
268	if(!sel) {
269		drawstatus();
270		return;
271	}
272	if(sel->isfloat || arrange == dofloat) {
273		XRaiseWindow(dpy, sel->win);
274		XRaiseWindow(dpy, sel->twin);
275	}
276	if(arrange != dofloat) {
277		if(!sel->isfloat) {
278			XLowerWindow(dpy, sel->twin);
279			XLowerWindow(dpy, sel->win);
280		}
281		for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
282			if(c == sel)
283				continue;
284			XLowerWindow(dpy, c->twin);
285			XLowerWindow(dpy, c->win);
286		}
287	}
288	drawall();
289	XSync(dpy, False);
290	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
291}
292
293void
294togglemode(Arg *arg) {
295	arrange = (arrange == dofloat) ? dotile : dofloat;
296	if(sel)
297		arrange(NULL);
298	else
299		drawstatus();
300}
301
302void
303toggleview(Arg *arg) {
304	unsigned int i;
305
306	seltag[arg->i] = !seltag[arg->i];
307	for(i = 0; i < ntags && !seltag[i]; i++);
308	if(i == ntags)
309		seltag[arg->i] = True; /* cannot toggle last view */
310	reorder();
311	arrange(NULL);
312}
313
314void
315togglestackpos(Arg *arg) {
316	if(arrange == dofloat)
317		return;
318	if(stackpos == StackBottom)
319		stackpos = STACKPOS;
320	else
321		stackpos = StackBottom;
322	arrange(NULL);
323}
324
325void
326view(Arg *arg) {
327	unsigned int i;
328
329	for(i = 0; i < ntags; i++)
330		seltag[i] = False;
331	seltag[arg->i] = True;
332	reorder();
333	arrange(NULL);
334}
335
336void
337viewall(Arg *arg) {
338	unsigned int i;
339
340	for(i = 0; i < ntags; i++)
341		seltag[i] = True;
342	reorder();
343	arrange(NULL);
344}
345
346
347
348void
349zoom(Arg *arg) {
350	unsigned int n;
351	Client *c;
352
353	if(!sel)
354		return;
355
356	if(sel->isfloat || (arrange == dofloat)) {
357		togglemax(sel);
358		return;
359	}
360
361	for(n = 0, c = clients; c; c = c->next)
362		if(isvisible(c) && !c->isfloat)
363			n++;
364	if(n < 2 || (arrange == dofloat))
365		return;
366
367	if((c = sel) == nexttiled(clients))
368		if(!(c = nexttiled(c->next)))
369			return;
370	detach(c);
371	if(clients)
372		clients->prev = c;
373	c->next = clients;
374	clients = c;
375	focus(c);
376	arrange(NULL);
377}