Squeeze increment gaps, again.

This commit is contained in:
Kris Maglione 2008-05-23 10:37:36 -04:00
parent 00701a72b8
commit 33b0d89da3
7 changed files with 255 additions and 160 deletions

View File

@ -26,6 +26,18 @@ area_idx(Area *a) {
return i;
}
int
afmt(Fmt *f) {
Area *a;
a = va_arg(f->args, Area*);
if(a == nil)
return fmtstrcpy(f, "<nil>");
if(a->floating)
return fmtstrcpy(f, "~");
return fmtprint(f, "%d", area_idx(a));
}
char*
area_name(Area *a) {
@ -53,6 +65,8 @@ area_create(View *v, Area *pos, uint w) {
for(a=v->area; a; a=a->next)
areanum++;
/* TODO: Need a better sizing/placing algorithm.
*/
colnum = areanum - 1;
if(w == 0) {
if(colnum >= 0) {
@ -241,7 +255,7 @@ area_focus(Area *a) {
client_focus(nil);
if(a != old_a) {
event("AreaFocus %s\n", area_name(a));
event("AreaFocus %a\n", a);
/* Deprecated */
if(a->floating)
event("FocusFloating\n");

View File

@ -68,6 +68,9 @@ column_attach(Area *a, Frame *f) {
f->r = a->r;
f->r.max.y = Dy(a->r) / nframe;
/* COLR */
f->colr = a->r;
f->colr.max.y = Dy(a->r) / nframe;
column_insert(a, f, a->sel);
column_arrange(a, false);
@ -136,30 +139,24 @@ column_detach(Frame *f) {
area_destroy(a);
}
/* This is impossibly long and tortuous. We can do better.
*/
static int
column_surplus(Area *a) {
Frame *f;
int surplus;
surplus = Dy(a->r);
for(f=a->frame; f; f=f->anext)
surplus -= Dy(f->r);
return surplus;
}
static void
column_scale(Area *a) {
column_fit(Area *a, uint *ncolp, uint *nuncolp) {
Frame *f, **fp;
uint minh, yoff, dy;
uint minh, dy;
uint ncol, nuncol;
uint colh, uncolh;
int surplus, osurplus, i, j;
if(!a->frame)
return;
/* Kludge. This should be idempotent, but the algorithm is
* flawed, so it's not. This is far from perfect.
*/
if(eqrect(a->r, a->r_old) && a->frame == a->frame_old) {
for(f=a->frame; f; f=f->anext)
if(!eqrect(f->r, f->colr_old)
|| f->anext != f->anext_old)
break;
if(f == nil)
return;
}
int surplus, i, j;
/* The minimum heights of collapsed and uncollpsed frames.
*/
@ -171,7 +168,7 @@ column_scale(Area *a) {
ncol = 0;
nuncol = 0;
for(f=a->frame; f; f=f->anext) {
frame_resize(f, f->r);
frame_resize(f, f->colr);
if(f->collapsed)
ncol++;
else
@ -239,90 +236,168 @@ column_scale(Area *a) {
fp = &f->anext;
}
/* Make some adjustments. */
surplus = Dy(a->r);
for(f=a->frame; f; f=f->anext) {
f->r = rectsubpt(f->r, f->r.min);
f->r.max.x = Dx(a->r);
if(ncolp) *ncolp = ncol;
if(nuncolp) *nuncolp = nuncol;
}
if(f->collapsed) {
surplus -= colh;
f->dy = 0;
f->r.max.y = colh;
}else {
surplus -= Dy(f->r);
f->dy = Dy(f->r) - uncolh;
static void
column_settle(Area *a) {
Frame *f;
uint yoff, yoffcr;
int i, surplus, nuncol, n;
nuncol = 0;
surplus = column_surplus(a);
for(f=a->frame; f; f=f->anext)
if(!f->collapsed) nuncol++;
yoff = a->r.min.y;
yoffcr = yoff;
i = nuncol;
n = 0;
if(surplus / nuncol == 0)
n = surplus;
for(f=a->frame; f; f=f->anext) {
f->r = rectsetorigin(f->r, Pt(a->r.min.x, yoff));
f->colr = rectsetorigin(f->colr, Pt(a->r.min.x, yoffcr));
f->r.min.x = a->r.min.x;
f->r.max.x = a->r.max.x;
if(!f->collapsed) {
if(n == 0)
f->r.max.y += surplus / nuncol;
else if(n-- > 0)
f->r.max.y++;
if(--i == 0)
f->r.max.y = a->r.max.y;
}
yoff = f->r.max.y;
yoffcr = f->colr.max.y;
}
}
static int
foo(Frame *f) {
WinHints h;
int maxh;
h = frame_gethints(f);
maxh = 0;
if(h.aspect.max.x)
maxh = h.baspect.y +
(Dx(f->r) - h.baspect.x) *
h.aspect.max.y / h.aspect.max.x;
maxh = max(maxh, h.max.y);
if(Dy(f->r) > maxh)
return 0;
return h.inc.y - (Dy(f->r) - h.base.y) % h.inc.y;
}
static int
comp_frame(const void *a, const void *b) {
Frame *fa, *fb;
int ia, ib;
fa = *(Frame**)a;
fb = *(Frame**)b;
ia = foo(fa);
ib = foo(fb);
return ia < ib ? -1 :
ia > ib ? 1 :
/* Favor the selected client. */
fa == fa->area->sel ? -1 :
fb == fa->area->sel ? 1 :
0;
}
static void
column_squeeze(Area *a) {
static Vector_ptr fvec;
WinHints h;
Frame **fp;
Frame *f;
int surplus, osurplus, dy;
fvec.n = 0;
for(f=a->frame; f; f=f->anext) {
h = frame_gethints(f);
f->r = sizehint(&h, f->r);
vector_ppush(&fvec, f);
}
fp = (Frame**)fvec.ary;
/* I would prefer an unstable sort. Unfortunately, the GNU people
* provide a stable one, so, this works better on BSD.
*/
qsort(fp, fvec.n, sizeof *fp, comp_frame);
surplus = column_surplus(a);
for(osurplus=0; surplus != osurplus;) {
osurplus = surplus;
for(; f=*fp; fp++) {
dy = foo(f);
if(dy > surplus)
break;
surplus -= dy;
f->r.max.y += dy;
}
}
}
void
column_frob(Area *a) {
Frame *f;
for(f=a->frame; f; f=f->anext)
f->r = f->colr;
column_settle(a);
if(a->view == screen->sel)
for(f=a->frame; f; f=f->anext)
client_resize(f->client, f->r);
}
static void
column_scale(Area *a) {
Frame *f;
uint dy;
uint ncol, nuncol;
uint colh;
int surplus;
if(!a->frame)
return;
column_fit(a, &ncol, &nuncol);
colh = labelh(def.font);
surplus = Dy(a->r);
/* Distribute the surplus.
*/
osurplus = 0;
/* More on this later. */
//while(surplus != osurplus) {
osurplus = surplus;
dy = 0;
for(f=a->frame; f; f=f->anext)
if(f->dy)
dy += f->dy;
for(f=a->frame; f; f=f->anext)
if(f->dy) {
i = Dy(f->r);
f->r.max.y += ((float)f->dy / dy) * osurplus;
frame_resize(f, f->r);
f->r.max.y = Dy(f->crect) + colh + 1;
surplus = Dy(a->r);
for(f=a->frame; f; f=f->anext) {
if(f->collapsed)
f->colr.max.y = f->colr.min.y + colh;
surplus -= Dy(f->colr);
if(!f->collapsed)
dy += Dy(f->colr);
}
for(f=a->frame; f; f=f->anext) {
WinHints h;
f->dy = Dy(f->r);
surplus -= f->dy - i;
if(f->dy == i)
f->dy = 0;
}
//}
/* Now, try to give each frame, in turn, the entirety of the
* surplus that we have left. A single frame might be able
* to fill its increment gap with all of what's left, but
* not with its fair share.
*/
#if 0
No, don''t. Causes too much trouble, the way things are now.
for(f=a->frame; f && surplus > 0; f=f->anext)
f->colr.min.x = a->r.min.x;
f->colr.max.x = a->r.max.x;
if(!f->collapsed)
f->colr.max.y += ((float)f->dy / dy) * surplus;
frame_resize(f, f->colr);
if(!f->collapsed) {
dy = Dy(f->r);
f->r.max.y += surplus;
frame_resize(f, f->r);
f->r.max.y = Dy(f->crect) + colh + 1;
surplus -= Dy(f->r) - dy;
h = frame_gethints(f);
f->r = sizehint(&h, f->r);
}
#endif
if(surplus < 0) {
print("Badness: surplus = %d\n", surplus);
surplus = 0;
}
/* Adjust the y coordnates of each frame. */
yoff = a->r.min.y;
i = nuncol;
for(f=a->frame; f; f=f->anext) {
f->r = rectaddpt(f->r,
Pt(a->r.min.x, yoff));
/* Give each frame an equal portion of the surplus,
* whether it wants it or not.
*/
if(!f->collapsed) {
i--;
f->r.max.y += surplus / nuncol;
if(!i)
f->r.max.y += surplus % nuncol;
f->colr_old = f->r; /* Kludge. */
f->anext_old = f->anext;
}
yoff = f->r.max.y;
}
a->r_old = a->r; /* Kludge. */
a->frame_old = a->frame;
column_squeeze(a);
column_settle(a);
}
void
@ -340,12 +415,14 @@ column_arrange(Area *a, bool dirty) {
if(dirty)
for(f=a->frame; f; f=f->anext)
f->r = Rect(0, 0, 100, 100);
/* COLR */
if(dirty)
for(f=a->frame; f; f=f->anext)
f->colr = Rect(0, 0, 100, 100);
break;
case Colstack:
for(f=a->frame; f; f=f->anext) {
for(f=a->frame; f; f=f->anext)
f->collapsed = (f != a->sel);
f->r = Rect(0, 0, 1, 1);
}
break;
case Colmax:
for(f=a->frame; f; f=f->anext) {
@ -402,7 +479,7 @@ column_resizeframe_h(Frame *f, Rectangle r) {
if(fp)
r.min.y = max(r.min.y, fp->r.min.y + minh);
else
else /* XXX. */
r.min.y = max(r.min.y, a->r.min.y);
if(fn)

View File

@ -8,6 +8,7 @@
# pragma varargck argpos event 1
# pragma varargck argpos warning 1
#
# pragma varargck type "a" Area*
# pragma varargck type "C" Client*
# pragma varargck type "r" void
#endif
@ -16,6 +17,7 @@
(cond ? fprint(1, __FILE__":%d: failed assertion: " #cond "\n", __LINE__), backtrace(arg), true : false)
/* area.c */
int afmt(Fmt*);
void area_attach(Area*, Frame*);
Area* area_create(View*, Area *pos, uint w);
void area_destroy(Area*);
@ -75,6 +77,7 @@ void column_arrange(Area*, bool dirty);
void column_attach(Area*, Frame*);
void column_attachrect(Area*, Frame*, Rectangle);
void column_detach(Frame*);
void column_frob(Area*);
void column_insert(Area*, Frame*, Frame*);
Area* column_new(View*, Area *, uint);
void column_remove(Frame*);

View File

@ -366,6 +366,7 @@ frame_resize(Frame *f, Rectangle r) {
fr = constrain(fr);
/* Collapse managed frames which are too small */
/* XXX. */
collapsed = f->collapsed;
if(!f->area->floating && f->area->mode == Coldefault) {
f->collapsed = false;
@ -393,8 +394,6 @@ frame_resize(Frame *f, Rectangle r) {
if(f->area->floating)
f->floatr = f->r;
else
f->colr = f->r;
}
void

View File

@ -298,6 +298,7 @@ main(int argc, char *argv[]) {
int i;
fmtinstall('r', errfmt);
fmtinstall('a', afmt);
fmtinstall('C', Cfmt);
wmiirc = "wmiistartrc";

View File

@ -652,6 +652,7 @@ msg_grow(View *v, IxpMsg *m) {
if(!getamt(m, &amount))
return Ebadvalue;
/* COLR */
r = f->r;
switch(dir) {
case LLEFT: r.min.x -= amount.x; break;
@ -689,6 +690,7 @@ msg_nudge(View *v, IxpMsg *m) {
if(!getamt(m, &amount))
return Ebadvalue;
/* COLR */
r = f->r;
switch(dir) {
case LLEFT: r = rectaddpt(r, Pt(-amount.x, 0)); break;
@ -1021,7 +1023,7 @@ readctl_view(View *v) {
bufprint("%s\n", v->name);
/* select <area>[ <frame>] */
bufprint("select %s", area_name(v->sel));
bufprint("select %a", v->sel);
if(v->sel->sel)
bufprint(" %d", frame_idx(v->sel->sel));
bufprint("\n");

View File

@ -360,7 +360,7 @@ grabboxcenter(Frame *f) {
p.x += Dx(f->grabbox)/2;
p.y += Dy(f->grabbox)/2;
return p;
/* Pretty, but not concise.
/* Pretty, but not clear.
pt = addpt(pt, divpt(subpt(f->grabbox.max,
f->grabbox.min),
Pt(2, 2)))
@ -428,40 +428,29 @@ mouse_resizecolframe(Frame *f, Align align) {
min.x = Dx(v->r)/NCOL;
min.y = /*frame_delta_h() +*/ labelh(def.font);
if(align&North) {
if(f->aprev) {
r.min.y = f->aprev->r.min.y + min.y;
r.max.y = f->r.max.y - min.y;
}else {
r.min.y = a->r.min.y;
r.max.y = r.min.y + 1;
}
}else {
if(f->anext) {
r.max.y = f->anext->r.max.y - min.y;
r.min.y = f->r.min.y + min.y;
}else {
r.max.y = a->r.max.y;
r.min.y = r.max.y - 1;
}
}
if(align&West) {
if(a->prev != v->area) {
r.min.x = a->prev->r.min.x + min.x;
r.max.x = a->r.max.x - min.x;
}else {
r.min.x = a->r.min.x;
r.max.x = r.min.x + 1;
}
}else {
if(a->next) {
r.max.x = a->next->r.max.x - min.x;
r.min.x = a->r.min.x + min.x;
}else {
r.max.x = a->r.max.x;
r.min.x = r.max.x - 1;
}
}
/* This would be so simple in lisp... */
/* This must be evil. But, I hate to repeat myself. */
/* And I hate to see patterns. */
/* At any rate, set the limits of where this box may be
* dragged.
*/
#define frob(pred, rmin, rmax, plus, minus, xy) BLOCK( \
if(pred) { \
r.rmin.xy = f->aprev->r.rmin.xy plus min.xy; \
r.rmax.xy = f->r.rmax.xy minus min.xy; \
}else { \
r.rmin.xy = a->r.rmin.xy; \
r.rmax.xy = r.rmin.xy plus 1; \
})
if(align&North)
frob(f->aprev, min, max, +, -, y);
else
frob(f->anext, max, min, -, +, y);
if(align&West)
frob(a->prev != v->area, min, max, +, -, x);
else
frob(a->next, max, min, -, +, x);
#undef frob
cwin = createwindow(&scr.root, r, 0, InputOnly, &wa, 0);
mapwin(cwin);
@ -688,6 +677,10 @@ static int (*tramp[])(Frame*) = {
tfloat,
};
/* Trampoline to allow properly tail recursive move/resize routines.
* We could probably get away with plain tail calls, but I don't
* like the idea.
*/
static void
trampoline(int fn, Frame *f) {
@ -706,6 +699,8 @@ mouse_movegrabbox(Client *c) {
Frame *f;
f = c->sel;
for(Area *a=f->view->area->next; a; a=a->next)
column_frob(a);
if(f->area->floating)
trampoline(TFloat, f);
else
@ -745,11 +740,11 @@ thcol(Frame *f) {
if(button != 1)
continue;
/* TODO: Fix... I think that this should be
* simpler, and should be elsewhere. But the
* expected behavior turns out to be more
* complex than one would suspect. The
* simpler algorithms tend not to do what
* you want.
* simpler, at least clearer, and should be
* elsewhere. But the expected behavior
* turns out to be more complex than one
* would suspect. The simpler algorithms
* tend not to do what you want.
*/
a = f->area;
if(a->floating)
@ -761,16 +756,16 @@ thcol(Frame *f) {
if(fnext
&& (!fprev || (fw->fprev != fprev)
&& (fw->fprev != fprev->aprev))) {
fnext->r.min.y = f->r.min.y;
frame_resize(fnext, fnext->r);
fnext->colr.min.y = f->colr.min.y;
frame_resize(fnext, fnext->colr);
}
else if(fprev) {
if(fw->fprev == fprev->aprev) {
fw->fprev = fprev->aprev;
fprev->r = f->r;
fprev->colr = f->r;
}else
fprev->r.max.y = f->r.max.y;
frame_resize(fprev, fprev->r);
fprev->colr.max.y = f->r.max.y;
frame_resize(fprev, fprev->colr);
}
}
@ -778,8 +773,8 @@ thcol(Frame *f) {
r = fw->fprev_r;
if(f->aprev) {
f->aprev->r.max.y = r.min.y;
frame_resize(f->aprev, f->aprev->r);
f->aprev->colr.max.y = r.min.y;
frame_resize(f->aprev, f->aprev->colr);
}else
r.min.y = f->area->r.min.y;
@ -791,7 +786,8 @@ thcol(Frame *f) {
Dprint(DGeneric, "fw->fprev: %C fprev: %C f: %C f->r: %R fprev_r: %R\n",
(fw->fprev?fw->fprev->client:nil), (fprev?fprev->client:nil),
f->client, f->r, fw->fprev_r);
frame_resize(f, fw->fprev_r);
f->colr = fw->fprev_r;
frame_resize(f, f->colr);
if(!a->frame && !a->floating)
area_destroy(a);
@ -931,16 +927,19 @@ done:
#endif
static void
_grab(XWindow w, uint button, ulong mod) {
XGrabButton(display, button, mod, w, false, ButtonMask,
GrabModeSync, GrabModeAsync, None, None);
}
/* Doesn't belong here */
void
grab_button(XWindow w, uint button, ulong mod) {
XGrabButton(display, button, mod, w, false, ButtonMask,
GrabModeSync, GrabModeAsync, None, None);
if((mod != AnyModifier) && (numlock_mask != 0)) {
XGrabButton(display, button, mod | numlock_mask, w, false, ButtonMask,
GrabModeSync, GrabModeAsync, None, None);
XGrabButton(display, button, mod | numlock_mask | LockMask, w, false,
ButtonMask, GrabModeSync, GrabModeAsync, None, None);
_grab(w, button, mod);
if((mod != AnyModifier) && numlock_mask) {
_grab(w, button, mod | numlock_mask);
_grab(w, button, mod | numlock_mask | LockMask);
}
}