summaryrefslogtreecommitdiff
path: root/cmd/wmii/float.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/wmii/float.c')
-rw-r--r--cmd/wmii/float.c245
1 files changed, 245 insertions, 0 deletions
diff --git a/cmd/wmii/float.c b/cmd/wmii/float.c
new file mode 100644
index 0000000..23998d5
--- /dev/null
+++ b/cmd/wmii/float.c
@@ -0,0 +1,245 @@
+/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include "dat.h"
+#include <limits.h>
+#include "fns.h"
+
+static void float_placeframe(Frame*);
+
+void
+float_attach(Area *a, Frame *f) {
+
+ f->client->floating = true;
+
+ f->r = f->floatr;
+ float_placeframe(f);
+ assert(a->sel != f);
+ frame_insert(f, a->sel);
+
+ if(a->sel == nil)
+ area_setsel(a, f);
+}
+
+void
+float_detach(Frame *f) {
+ Frame *pr;
+ Area *a, *sel, *oldsel;
+ View *v;
+
+ v = f->view;
+ a = f->area;
+ sel = view_findarea(v, v->selscreen, v->selcol, false);
+ oldsel = v->oldsel;
+ pr = f->aprev;
+
+ frame_remove(f);
+
+ if(a->sel == f) {
+ if(!pr)
+ pr = a->frame;
+ a->sel = nil;
+ area_setsel(a, pr);
+ }
+ f->area = nil;
+
+ if(oldsel)
+ area_focus(oldsel);
+ else if(!a->frame)
+ if(sel && sel->frame)
+ area_focus(sel);
+}
+
+void
+float_resizeframe(Frame *f, Rectangle r) {
+
+ if(f->area->view == selview)
+ client_resize(f->client, r);
+ else
+ frame_resize(f, r);
+}
+
+void
+float_arrange(Area *a) {
+ Frame *f;
+
+ assert(a->floating);
+
+ switch(a->mode) {
+ case Coldefault:
+ for(f=a->frame; f; f=f->anext)
+ f->collapsed = false;
+ break;
+ case Colstack:
+ for(f=a->frame; f; f=f->anext)
+ f->collapsed = (f != a->sel);
+ break;
+ default:
+ die("not reached");
+ break;
+ }
+ for(f=a->frame; f; f=f->anext)
+ f->r = f->floatr;
+ view_update(a->view);
+}
+
+static void
+rect_push(Vector_rect *vec, Rectangle r) {
+ Rectangle *rp;
+ int i;
+
+ for(i=0; i < vec->n; i++) {
+ rp = &vec->ary[i];
+ if(rect_contains_p(*rp, r))
+ return;
+ if(rect_contains_p(r, *rp)) {
+ *rp = r;
+ return;
+ }
+ }
+ vector_rpush(vec, r);
+}
+
+Vector_rect*
+unique_rects(Vector_rect *vec, Rectangle orig) {
+ static Vector_rect vec1, vec2;
+ Vector_rect *v1, *v2, *v;
+ Rectangle r1, r2;
+ int i, j;
+
+ v1 = &vec1;
+ v2 = &vec2;
+ v1->n = 0;
+ vector_rpush(v1, orig);
+ for(i=0; i < vec->n; i++) {
+ v2->n = 0;
+ r1 = vec->ary[i];
+ for(j=0; j < v1->n; j++) {
+ r2 = v1->ary[j];
+ if(!rect_intersect_p(r1, r2)) {
+ rect_push(v2, r2);
+ continue;
+ }
+ if(r2.min.x < r1.min.x)
+ rect_push(v2, Rect(r2.min.x, r2.min.y, r1.min.x, r2.max.y));
+ if(r2.min.y < r1.min.y)
+ rect_push(v2, Rect(r2.min.x, r2.min.y, r2.max.x, r1.min.y));
+ if(r2.max.x > r1.max.x)
+ rect_push(v2, Rect(r1.max.x, r2.min.y, r2.max.x, r2.max.y));
+ if(r2.max.y > r1.max.y)
+ rect_push(v2, Rect(r2.min.x, r1.max.y, r2.max.x, r2.max.y));
+ }
+ v = v1;
+ v1 = v2;
+ v2 = v;
+ }
+ return v1;
+}
+
+Rectangle
+max_rect(Vector_rect *vec) {
+ Rectangle *r, *rp;
+ int i, a, area;
+
+ area = 0;
+ r = 0;
+ for(i=0; i < vec->n; i++) {
+ rp = &vec->ary[i];
+ a = Dx(*rp) * Dy(*rp);
+ if(a > area) {
+ area = a;
+ r = rp;
+ }
+ }
+ return r ? *r : ZR;
+}
+
+static void
+float_placeframe(Frame *f) {
+ static Vector_rect vec;
+ Vector_rect *vp;
+ Rectangle r;
+ Point dim, p;
+ Client *c;
+ Frame *ff;
+ Area *a, *sel;
+ long area, l;
+ int i, s;
+
+ a = f->area;
+ c = f->client;
+
+ /*
+ if(c->trans)
+ return;
+ */
+
+ if(c->fullscreen >= 0 || c->w.hints->position || starting) {
+ f->r = f->floatr;
+ return;
+ }
+
+ /* Find all rectangles on the floating layer into which
+ * the new frame would fit.
+ */
+ vec.n = 0;
+ for(ff=a->frame; ff; ff=ff->anext)
+ /* TODO: Find out why this check is needed.
+ * The frame hasn't been inserted yet, but somehow,
+ * its old rectangle winds up in the list.
+ */
+ if(ff->client != f->client)
+ vector_rpush(&vec, ff->r);
+
+ /* Decide which screen we want to place this on.
+ * Ideally, it should probably Do the Right Thing
+ * when a screen fills, but what's the right thing?
+ * I think usage will show...
+ */
+ s = -1;
+ ff = client_groupframe(c, f->view);
+ if (f->screen >= 0)
+ s = f->screen;
+ else if (ff)
+ s = ownerscreen(ff->r);
+ else if (selclient())
+ s = ownerscreen(selclient()->sel->r);
+ else {
+ sel = view_findarea(a->view, a->view->selscreen, a->view->selcol, false);
+ if (sel)
+ s = sel->screen;
+ }
+
+ r = s == -1 ? a->r : screens[s]->r;
+ vp = unique_rects(&vec, r);
+
+ area = LONG_MAX;
+ dim.x = Dx(f->r);
+ dim.y = Dy(f->r);
+ p = ZP;
+
+ for(i=0; i < vp->n; i++) {
+ r = vp->ary[i];
+ if(Dx(r) < dim.x || Dy(r) < dim.y)
+ continue;
+ l = Dx(r) * Dy(r);
+ if(l < area) {
+ area = l;
+ p = r.min;
+ }
+ }
+
+ if(area == LONG_MAX) {
+ /* Cascade. */
+ s = max(s, 0);
+ ff = a->sel;
+ if(ff)
+ p = addpt(ff->r.min, Pt(Dy(ff->titlebar), Dy(ff->titlebar)));
+ if(p.x + Dx(f->r) > screens[s]->r.max.x ||
+ p.y + Dy(f->r) > screens[s]->r.max.y)
+ p = screens[s]->r.min;
+ }
+
+ f->floatr = rectsetorigin(f->r, p);
+}
+