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