1 /* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
2  * See LICENSE file for license details.
3  */
4 #include "dat.h"
5 #include <math.h>
6 #include <limits.h>
7 #include "fns.h"
8 
9 Client*
area_selclient(Area * a)10 area_selclient(Area *a) {
11 	if(a && a->sel)
12 		return a->sel->client;
13 	return nil;
14 }
15 
16 int
area_idx(Area * a)17 area_idx(Area *a) {
18 	View *v;
19 	Area *ap;
20 	uint i;
21 
22 	v = a->view;
23 	if(a->floating)
24 		return -1;
25 	i = 1;
26 	for(ap=v->areas[a->screen]; a != ap; ap=ap->next)
27 		i++;
28 	return i;
29 }
30 
31 static Rectangle
area_rect(void * v)32 area_rect(void *v) {
33 	Area *a;
34 
35 	a = v;
36 	return a->r;
37 }
38 
39 Area*
area_find(View * v,Rectangle r,int dir,bool wrap)40 area_find(View *v, Rectangle r, int dir, bool wrap) {
41 	static Vector_ptr vec;
42 	Area *a;
43 	int s;
44 
45 	vec.n = 0;
46 	foreach_column(v, s, a)
47 		vector_ppush(&vec, a);
48 
49 	return findthing(r, dir, &vec, area_rect, wrap);
50 }
51 
52 int
afmt(Fmt * f)53 afmt(Fmt *f) {
54 	Area *a;
55 
56 	a = va_arg(f->args, Area*);
57 	if(a == nil)
58 		return fmtstrcpy(f, "<nil>");
59 	if(a->floating)
60 		return fmtstrcpy(f, "~");
61 	if(a->screen > 0 || (f->flags & FmtSharp))
62 		return fmtprint(f, "%d:%d", a->screen, area_idx(a));
63 	return fmtprint(f, "%d", area_idx(a));
64 }
65 
66 char*
area_name(Area * a)67 area_name(Area *a) {
68 
69 	if(a == nil)
70 		return "<nil>";
71 	if(a->floating)
72 		return "~";
73 	return sxprint("%d", area_idx(a));
74 }
75 
76 Area*
area_create(View * v,Area * pos,int scrn,uint width)77 area_create(View *v, Area *pos, int scrn, uint width) {
78 	static ushort id = 1;
79 	int i, j;
80 	uint minwidth, index;
81 	int numcols;
82 	Area *a;
83 
84 	assert(!pos || pos->screen == scrn);
85 	SET(index);
86 	if(v->areas) { /* Creating a column. */
87 		minwidth = column_minwidth();
88 		index = pos ? area_idx(pos) : 1;
89 		numcols = 0;
90 		for(a=v->areas[scrn]; a; a=a->next)
91 			numcols++;
92 
93 		/* TODO: Need a better sizing/placing algorithm.
94 		 */
95 		if(width == 0) {
96 			if(numcols >= 0) {
97 				width = view_newcolwidth(v, index);
98 				if (width == 0)
99 					width = Dx(v->r[scrn]) / (numcols + 1);
100 			}
101 			else
102 				width = Dx(v->r[scrn]);
103 		}
104 
105 		if(width < minwidth)
106 			width = minwidth;
107 		minwidth = numcols * minwidth + minwidth;
108 		if(minwidth > Dx(v->r[scrn]))
109 			return nil;
110 
111 		i = minwidth - Dx(v->pad[scrn]) - Dx(v->r[scrn]);
112 		if(i > 0 && Dx(v->pad[scrn])) {
113 			j = min(i/2, v->pad[scrn].min.x);
114 			v->pad[scrn].min.x -= j;
115 			v->pad[scrn].max.x += i - j;
116 		}
117 
118 		view_scale(v, scrn, Dx(v->r[scrn]) - width);
119 	}
120 
121 	a = emallocz(sizeof *a);
122 	a->view = v;
123 	a->screen = scrn;
124 	a->id = id++;
125 	a->floating = !v->floating;
126 	if(a->floating)
127 		a->mode = Coldefault;
128 	else
129 		a->mode = def.colmode;
130 	a->frame = nil;
131 	a->sel = nil;
132 
133 	a->r = v->r[scrn];
134 	a->r.min.x = 0;
135 	a->r.max.x = width;
136 
137 	if(a->floating) {
138 		v->floating = a;
139 		a->screen = -1;
140 	}
141 	else if(pos) {
142 		a->next = pos->next;
143 		a->prev = pos;
144 	}
145 	else {
146 		a->next = v->areas[scrn];
147 		v->areas[scrn] = a;
148 	}
149 	if(a->prev)
150 		a->prev->next = a;
151 	if(a->next)
152 		a->next->prev = a;
153 
154 	if(v->sel == nil && !a->floating)
155 		area_focus(a);
156 
157 	if(!a->floating)
158 		event("CreateColumn %ud\n", index);
159 	return a;
160 }
161 
162 void
area_destroy(Area * a)163 area_destroy(Area *a) {
164 	Area *newfocus;
165 	View *v;
166 	int idx;
167 
168 	v = a->view;
169 
170 	if(a->frame)
171 		die("destroying non-empty area");
172 
173 	if(v->revert == a)
174 		v->revert = nil;
175 	if(v->oldsel == a)
176 		v->oldsel = nil;
177 
178 	idx = area_idx(a);
179 
180 	if(a->prev && !a->prev->floating)
181 		newfocus = a->prev;
182 	else
183 		newfocus = a->next;
184 
185 	/* Can only destroy the floating area when destroying a
186 	 * view---after destroying all columns.
187 	 */
188 	assert(!a->floating || !v->areas[0]);
189 	if(a->prev)
190 		a->prev->next = a->next;
191 	else if(!a->floating)
192 		v->areas[a->screen] = a->next;
193 	else
194 		v->floating = nil;
195 	if(a->next)
196 		a->next->prev = a->prev;
197 
198 	if(newfocus && v->sel == a)
199 		area_focus(newfocus);
200 
201 	view_arrange(v);
202 	event("DestroyArea %d\n", idx);
203 
204 	free(a);
205 }
206 
207 void
area_moveto(Area * to,Frame * f)208 area_moveto(Area *to, Frame *f) {
209 	Area *from;
210 
211 	assert(to->view == f->view);
212 
213 	if(f->client->fullscreen >= 0 && !to->floating)
214 		return;
215 
216 	from = f->area;
217 	if (from == to)
218 		return;
219 
220 	area_detach(f);
221 
222 	/* Temporary kludge. */
223 	if(!to->floating
224 	&& to->floating != from->floating
225 	&& !eqrect(f->colr, ZR))
226 		column_attachrect(to, f, f->colr);
227 	else
228 		area_attach(to, f);
229 }
230 
231 void
area_setsel(Area * a,Frame * f)232 area_setsel(Area *a, Frame *f) {
233 	View *v;
234 
235 	v = a->view;
236 	/* XXX: Stack. */
237 	for(; f && f->collapsed && f->anext; f=f->anext)
238 		;
239 	for(; f && f->collapsed && f->aprev; f=f->aprev)
240 		;
241 
242 	if(a == v->sel && f)
243 		frame_focus(f);
244 	else
245 		a->sel = f;
246 }
247 
248 void
area_attach(Area * a,Frame * f)249 area_attach(Area *a, Frame *f) {
250 
251 	f->area = a;
252 	if(a->floating)
253 		float_attach(a, f);
254 	else
255 		column_attach(a, f);
256 
257 	view_arrange(a->view);
258 
259 	if(btassert("4 full", a->frame && a->sel == nil))
260 		a->sel = a->frame;
261 }
262 
263 void
area_detach(Frame * f)264 area_detach(Frame *f) {
265 	View *v;
266 	Area *a;
267 
268 	a = f->area;
269 	v = a->view;
270 
271 	if(a->floating)
272 		float_detach(f);
273 	else
274 		column_detach(f);
275 
276 	if(v->sel->sel == nil && v->floating->sel)
277 		v->sel = v->floating;
278 
279 	view_arrange(v);
280 }
281 
282 void
area_focus(Area * a)283 area_focus(Area *a) {
284 	Frame *f;
285 	View *v;
286 	Area *old_a;
287 
288 	v = a->view;
289 	f = a->sel;
290 	old_a = v->sel;
291 
292 	if(!a->floating && view_fullscreen_p(v, a->screen))
293 		return;
294 
295 	v->sel = a;
296 	if(!a->floating) {
297 		v->selcol = area_idx(a);
298 		v->selscreen = a->screen;
299 	}
300 	if(a != old_a)
301 		v->oldsel = nil;
302 
303 	if((old_a) && (a->floating != old_a->floating)) {
304 		v->revert = old_a;
305 		if(v->floating->max)
306 			view_update(v);
307 	}
308 
309 	if(v != selview)
310 		return;
311 
312 	move_focus(old_a->sel, f);
313 
314 	if(f)
315 		client_focus(f->client);
316 	else
317 		client_focus(nil);
318 
319 	if(a != old_a) {
320 		event("AreaFocus %a\n", a);
321 		/* Deprecated */
322 		if(a->floating)
323 			event("FocusFloating\n");
324 		else
325 			event("ColumnFocus %d\n", area_idx(a));
326 	}
327 }
328 
329