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; 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* char*
area_name(Area *a) { area_name(Area *a) {
@ -53,6 +65,8 @@ area_create(View *v, Area *pos, uint w) {
for(a=v->area; a; a=a->next) for(a=v->area; a; a=a->next)
areanum++; areanum++;
/* TODO: Need a better sizing/placing algorithm.
*/
colnum = areanum - 1; colnum = areanum - 1;
if(w == 0) { if(w == 0) {
if(colnum >= 0) { if(colnum >= 0) {
@ -241,7 +255,7 @@ area_focus(Area *a) {
client_focus(nil); client_focus(nil);
if(a != old_a) { if(a != old_a) {
event("AreaFocus %s\n", area_name(a)); event("AreaFocus %a\n", a);
/* Deprecated */ /* Deprecated */
if(a->floating) if(a->floating)
event("FocusFloating\n"); event("FocusFloating\n");

View File

@ -68,6 +68,9 @@ column_attach(Area *a, Frame *f) {
f->r = a->r; f->r = a->r;
f->r.max.y = Dy(a->r) / nframe; 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_insert(a, f, a->sel);
column_arrange(a, false); column_arrange(a, false);
@ -136,30 +139,24 @@ column_detach(Frame *f) {
area_destroy(a); 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 static void
column_scale(Area *a) { column_fit(Area *a, uint *ncolp, uint *nuncolp) {
Frame *f, **fp; Frame *f, **fp;
uint minh, yoff, dy; uint minh, dy;
uint ncol, nuncol; uint ncol, nuncol;
uint colh, uncolh; uint colh, uncolh;
int surplus, osurplus, i, j; int surplus, 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;
}
/* The minimum heights of collapsed and uncollpsed frames. /* The minimum heights of collapsed and uncollpsed frames.
*/ */
@ -171,7 +168,7 @@ column_scale(Area *a) {
ncol = 0; ncol = 0;
nuncol = 0; nuncol = 0;
for(f=a->frame; f; f=f->anext) { for(f=a->frame; f; f=f->anext) {
frame_resize(f, f->r); frame_resize(f, f->colr);
if(f->collapsed) if(f->collapsed)
ncol++; ncol++;
else else
@ -239,90 +236,168 @@ column_scale(Area *a) {
fp = &f->anext; fp = &f->anext;
} }
/* Make some adjustments. */ if(ncolp) *ncolp = ncol;
surplus = Dy(a->r); if(nuncolp) *nuncolp = nuncol;
for(f=a->frame; f; f=f->anext) { }
f->r = rectsubpt(f->r, f->r.min);
f->r.max.x = Dx(a->r);
if(f->collapsed) { static void
surplus -= colh; column_settle(Area *a) {
f->dy = 0; Frame *f;
f->r.max.y = colh; uint yoff, yoffcr;
}else { int i, surplus, nuncol, n;
surplus -= Dy(f->r);
f->dy = Dy(f->r) - uncolh; 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. /* Distribute the surplus.
*/ */
osurplus = 0; dy = 0;
/* More on this later. */ surplus = Dy(a->r);
//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;
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)
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;
}
#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) { for(f=a->frame; f; f=f->anext) {
f->r = rectaddpt(f->r, if(f->collapsed)
Pt(a->r.min.x, yoff)); f->colr.max.y = f->colr.min.y + colh;
/* Give each frame an equal portion of the surplus, surplus -= Dy(f->colr);
* whether it wants it or not. if(!f->collapsed)
*/ dy += Dy(f->colr);
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. */ for(f=a->frame; f; f=f->anext) {
a->frame_old = a->frame; WinHints h;
f->dy = Dy(f->r);
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) {
h = frame_gethints(f);
f->r = sizehint(&h, f->r);
}
}
column_squeeze(a);
column_settle(a);
} }
void void
@ -340,12 +415,14 @@ column_arrange(Area *a, bool dirty) {
if(dirty) if(dirty)
for(f=a->frame; f; f=f->anext) for(f=a->frame; f; f=f->anext)
f->r = Rect(0, 0, 100, 100); 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; break;
case Colstack: case Colstack:
for(f=a->frame; f; f=f->anext) { for(f=a->frame; f; f=f->anext)
f->collapsed = (f != a->sel); f->collapsed = (f != a->sel);
f->r = Rect(0, 0, 1, 1);
}
break; break;
case Colmax: case Colmax:
for(f=a->frame; f; f=f->anext) { for(f=a->frame; f; f=f->anext) {
@ -402,7 +479,7 @@ column_resizeframe_h(Frame *f, Rectangle r) {
if(fp) if(fp)
r.min.y = max(r.min.y, fp->r.min.y + minh); 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); r.min.y = max(r.min.y, a->r.min.y);
if(fn) if(fn)

View File

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

View File

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

View File

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

View File

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

View File

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