wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

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