float.c (4699B)
1 /* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail> 2 * See LICENSE file for license details. 3 */ 4 #include "dat.h" 5 #include <limits.h> 6 #include "fns.h" 7 8 static void float_placeframe(Frame*); 9 10 void 11 float_attach(Area *a, Frame *f) { 12 13 if(f->client->floating == Off) 14 f->client->floating = On; 15 16 f->r = f->floatr; 17 float_placeframe(f); 18 assert(a->sel != f); 19 frame_insert(f, a->sel); 20 21 if(a->sel == nil) 22 area_setsel(a, f); 23 } 24 25 void 26 float_detach(Frame *f) { 27 Frame *pr; 28 Area *a, *sel, *oldsel; 29 View *v; 30 31 v = f->view; 32 a = f->area; 33 sel = view_findarea(v, v->selscreen, v->selcol, false); 34 oldsel = v->oldsel; 35 pr = f->aprev; 36 37 frame_remove(f); 38 39 if(a->sel == f) { 40 while(pr && pr->client->nofocus) 41 pr = pr->aprev; 42 if(!pr) 43 for(pr=a->frame; pr && pr->anext; pr=pr->anext) 44 if(!pr->client->nofocus) break; 45 a->sel = nil; 46 area_setsel(a, pr); 47 } 48 f->area = nil; 49 50 if(oldsel) 51 area_focus(oldsel); 52 else if(!a->frame || pr && pr->client->nofocus) 53 if(sel && sel->frame) 54 area_focus(sel); 55 } 56 57 void 58 float_resizeframe(Frame *f, Rectangle r) { 59 60 if(f->area->view == selview) 61 client_resize(f->client, r); 62 else 63 frame_resize(f, r); 64 } 65 66 void 67 float_arrange(Area *a) { 68 Frame *f; 69 70 assert(a->floating); 71 72 switch(a->mode) { 73 case Coldefault: 74 break; 75 case Colstack: 76 for(f=a->frame; f; f=f->anext) 77 f->collapsed = !(f->client->w.ewmh.type & (TypeDock|TypeMenu|TypeToolbar)) 78 && (f != a->sel); 79 break; 80 default: 81 die("not reached"); 82 break; 83 } 84 for(f=a->frame; f; f=f->anext) 85 f->r = f->floatr; 86 view_update(a->view); 87 } 88 89 static void 90 rect_push(Vector_rect *vec, Rectangle r) { 91 Rectangle *rp; 92 int i; 93 94 for(i=0; i < vec->n; i++) { 95 rp = &vec->ary[i]; 96 if(rect_contains_p(*rp, r)) 97 return; 98 if(rect_contains_p(r, *rp)) { 99 *rp = r; 100 return; 101 } 102 } 103 vector_rpush(vec, r); 104 } 105 106 Vector_rect* 107 unique_rects(Vector_rect *vec, Rectangle orig) { 108 static Vector_rect vec1, vec2; 109 Vector_rect *v1, *v2, *v; 110 Rectangle r1, r2; 111 int i, j; 112 113 v1 = &vec1; 114 v2 = &vec2; 115 v1->n = 0; 116 vector_rpush(v1, orig); 117 for(i=0; i < vec->n; i++) { 118 v2->n = 0; 119 r1 = vec->ary[i]; 120 for(j=0; j < v1->n; j++) { 121 r2 = v1->ary[j]; 122 if(!rect_intersect_p(r1, r2)) { 123 rect_push(v2, r2); 124 continue; 125 } 126 if(r2.min.x < r1.min.x) 127 rect_push(v2, Rect(r2.min.x, r2.min.y, r1.min.x, r2.max.y)); 128 if(r2.min.y < r1.min.y) 129 rect_push(v2, Rect(r2.min.x, r2.min.y, r2.max.x, r1.min.y)); 130 if(r2.max.x > r1.max.x) 131 rect_push(v2, Rect(r1.max.x, r2.min.y, r2.max.x, r2.max.y)); 132 if(r2.max.y > r1.max.y) 133 rect_push(v2, Rect(r2.min.x, r1.max.y, r2.max.x, r2.max.y)); 134 } 135 v = v1; 136 v1 = v2; 137 v2 = v; 138 } 139 return v1; 140 } 141 142 Rectangle 143 max_rect(Vector_rect *vec) { 144 Rectangle *r, *rp; 145 int i, a, area; 146 147 area = 0; 148 r = 0; 149 for(i=0; i < vec->n; i++) { 150 rp = &vec->ary[i]; 151 a = Dx(*rp) * Dy(*rp); 152 if(a > area) { 153 area = a; 154 r = rp; 155 } 156 } 157 return r ? *r : ZR; 158 } 159 160 static void 161 float_placeframe(Frame *f) { 162 static Vector_rect vec; 163 Vector_rect *vp; 164 Rectangle r; 165 Point dim, p; 166 Area *a, *sel; 167 Client *c; 168 Frame *ff; 169 View *v; 170 long area, l; 171 int i, s; 172 173 v = f->view; 174 a = f->area; 175 c = f->client; 176 177 /* 178 if(c->trans) 179 return; 180 */ 181 182 if(c->fullscreen >= 0 || c->w.hints->position || starting) { 183 f->r = f->floatr; 184 return; 185 } 186 187 /* Find all rectangles on the floating layer into which 188 * the new frame would fit. 189 */ 190 vec.n = 0; 191 for(ff=a->frame; ff; ff=ff->anext) 192 /* TODO: Find out why this check is needed. 193 * The frame hasn't been inserted yet, but somehow, 194 * its old rectangle winds up in the list. 195 */ 196 if(ff->client != f->client) 197 vector_rpush(&vec, ff->r); 198 199 /* Decide which screen we want to place this on. 200 * Ideally, it should probably Do the Right Thing 201 * when a screen fills, but what's the right thing? 202 * I think usage will show... 203 */ 204 s = -1; 205 ff = client_groupframe(c, f->view); 206 if(f->screen >= 0) 207 s = f->screen; 208 else if(ff) 209 s = ownerscreen(ff->r); 210 else if(selclient()) 211 s = ownerscreen(selclient()->sel->r); 212 else { 213 sel = view_findarea(a->view, a->view->selscreen, a->view->selcol, false); 214 if(sel) 215 s = sel->screen; 216 } 217 218 if (s == -1) 219 r = a->r; 220 else 221 r = v->r[s]; 222 223 vp = unique_rects(&vec, r); 224 225 area = LONG_MAX; 226 dim.x = Dx(f->r); 227 dim.y = Dy(f->r); 228 p = ZP; 229 230 for(i=0; i < vp->n; i++) { 231 r = vp->ary[i]; 232 if(Dx(r) < dim.x || Dy(r) < dim.y) 233 continue; 234 l = Dx(r) * Dy(r); 235 if(l < area) { 236 area = l; 237 p = r.min; 238 } 239 } 240 241 if(area == LONG_MAX) { 242 /* Cascade. */ 243 s = max(s, 0); 244 ff = a->sel; 245 if(ff) 246 p = addpt(ff->r.min, Pt(Dy(ff->titlebar), Dy(ff->titlebar))); 247 if(p.x + Dx(f->r) > screens[s]->r.max.x || 248 p.y + Dy(f->r) > screens[s]->r.max.y) 249 p = screens[s]->r.min; 250 } 251 252 f->floatr = rectsetorigin(f->r, p); 253 } 254