diff --git a/cmd/wm/area.c b/cmd/wm/area.c index 8274bd3e..d3362e94 100644 --- a/cmd/wm/area.c +++ b/cmd/wm/area.c @@ -116,11 +116,58 @@ void send2area(Area *to, Area *from, Client *c) { c->revert = from; - detach_fromarea(from, c); + detach_fromarea(from, c, True); attach_toarea(to, c); focus_client(c); } +void +pre_attach(Area *a) +{ + Area *new = nil; + Client *c; + View *v = a->view; + unsigned int i, j; + + if(!a->capacity || (a->nframe < a->capacity)) + return; + i = area2index(a); + for(j = i + 1; j < v->narea; j++) + if(!v->area[j]->capacity + || (v->area[j]->capacity > v->area[j]->nframe)) + { + new = v->area[j]; + break; + } + if(!new) { + new = alloc_area(v); + arrange_view(v, True); + } + c = a->frame[a->sel]->client; + detach_fromarea(a, c, False); + attach_toarea(new, c); + arrange_area(new); +} + +void +post_detach(Area *a) +{ + Client *c; + Area *det; + View *v = a->view; + unsigned int i = area2index(a); + + if(!a->capacity || i + 1 >= v->narea) + return; + det = v->area[i + 1]; + if(!det->nframe) + return; + c = det->frame[det->sel]->client; + detach_fromarea(det, c, True); + attach_toarea(a, c); + arrange_area(a); +} + void attach_toarea(Area *a, Client *c) { @@ -129,6 +176,7 @@ attach_toarea(Area *a, Client *c) if(clientofview(a->view, c)) return; + pre_attach(a); f = cext_emallocz(sizeof(Frame)); f->id = id++; f->area = a; @@ -150,7 +198,7 @@ attach_toarea(Area *a, Client *c) } void -detach_fromarea(Area *a, Client *c) +detach_fromarea(Area *a, Client *c, Bool postarrange) { Frame *f; View *v = a->view; @@ -171,6 +219,12 @@ detach_fromarea(Area *a, Client *c) a->nframe--; if(a->sel > 0) a->sel--; + + if(!postarrange) + return; + + post_detach(a); + i = area2index(a); if(i && a->nframe) arrange_area(a); @@ -180,7 +234,7 @@ detach_fromarea(Area *a, Client *c) destroy_area(a); else if(!a->nframe && v->area[0]->nframe) v->sel = 0; /* focus floating area if it contains something */ - arrange_tag(v, True); + arrange_view(v, True); } else if(!i && !a->nframe) { if(c->trans) { @@ -351,27 +405,6 @@ Fallthrough: relax_area(a); } -void -arrange_tag(View *v, Bool updategeometry) -{ - unsigned int i; - unsigned int width; - - if(v->narea == 1) - return; - - width = rect.width / (v->narea - 1); - for(i = 1; i < v->narea; i++) { - Area *a = v->area[i]; - if(updategeometry) { - a->rect.height = rect.height - brect.height; - a->rect.x = (i - 1) * width; - a->rect.width = width; - } - arrange_area(a); - } -} - static void match_horiz(Area *a, XRectangle *r) { @@ -393,6 +426,7 @@ drop_resize(Frame *f, XRectangle *new) Frame *north = nil, *south = nil; unsigned int i; unsigned int min = 2 * bar_height(); + Bool horiz_resize = False; for(i = 1; (i < v->narea) && (v->area[i] != a); i++); /* first managed area is indexed 1, thus (i > 1) ? ... */ @@ -403,47 +437,36 @@ drop_resize(Frame *f, XRectangle *new) north = i ? a->frame[i - 1] : nil; south = i + 1 < a->nframe ? a->frame[i + 1] : nil; - /* validate (and trim if necessary) horizontal resize */ - if(new->width < MIN_COLWIDTH) { - if(new->x + new->width == f->rect.x + f->rect.width) - new->x = a->rect.x + a->rect.width - MIN_COLWIDTH; - new->width = MIN_COLWIDTH; - } + /* horizontal resize */ if(west && (new->x != f->rect.x)) { + horiz_resize = True; if(new->x < 0 || new->x < (west->rect.x + MIN_COLWIDTH)) { new->width -= (west->rect.x + MIN_COLWIDTH) - new->x; new->x = west->rect.x + MIN_COLWIDTH; + } else if(new->width < MIN_COLWIDTH) { + new->x -= MIN_COLWIDTH - new->width; + new->width = MIN_COLWIDTH; } - } else { - new->width += new->x - a->rect.x; - new->x = a->rect.x; - } - if(east && (new->x + new->width != f->rect.x + f->rect.width)) { - if((new->x + new->width) > (east->rect.x + east->rect.width - MIN_COLWIDTH)) - new->width = (east->rect.x + east->rect.width - MIN_COLWIDTH) - new->x; - } else - new->width = (a->rect.x + a->rect.width) - new->x; - if(new->width < MIN_COLWIDTH) - goto AfterHorizontal; - - /* horizontal resize */ - if(west && (new->x != a->rect.x)) { west->rect.width = new->x - west->rect.x; a->rect.width += a->rect.x - new->x; a->rect.x = new->x; - match_horiz(a, &a->rect); match_horiz(west, &west->rect); relax_area(west); } - if(east && (new->x + new->width != a->rect.x + a->rect.width)) { + if(east && (new->x + new->width != f->rect.x + f->rect.width)) { + horiz_resize = True; + if((new->x + new->width) > (east->rect.x + east->rect.width - MIN_COLWIDTH)) + new->width = (east->rect.x + east->rect.width - MIN_COLWIDTH) - new->x; + else if(new->width < MIN_COLWIDTH) + new->width = MIN_COLWIDTH; east->rect.width -= new->x + new->width - east->rect.x; east->rect.x = new->x + new->width; a->rect.width = (new->x + new->width) - a->rect.x; - match_horiz(a, &a->rect); match_horiz(east, &east->rect); relax_area(east); } -AfterHorizontal: + if(horiz_resize) + match_horiz(a, &a->rect); if(a->mode == Colstack || a->mode == Colmax) goto AfterVertical; diff --git a/cmd/wm/bar.c b/cmd/wm/bar.c index 35bdce81..40ab04d8 100644 --- a/cmd/wm/bar.c +++ b/cmd/wm/bar.c @@ -94,7 +94,7 @@ void draw_bar() { unsigned int i = 0, w = 0; - int exp = 0; + int exp = -1; Draw d = { 0 }; Label *l = nil; diff --git a/cmd/wm/client.c b/cmd/wm/client.c index adc51795..239c6e9e 100644 --- a/cmd/wm/client.c +++ b/cmd/wm/client.c @@ -519,10 +519,10 @@ send2area_client(Client *c, char *arg) if(i == -1) return; if(!strncmp(arg, "new", 4) && i) { - if(a->nframe == 1 || v->narea - 1 >= rect.width / MIN_COLWIDTH) + if(a->nframe == 1 || v->narea - 1 >= rect.width / (2 * MIN_COLWIDTH)) return; to = alloc_area(v); - arrange_tag(v, True); + arrange_view(v, True); } else if(!strncmp(arg, "prev", 5) && i) { if(i == 1) diff --git a/cmd/wm/fs.c b/cmd/wm/fs.c index fd54d8e9..5647f133 100644 --- a/cmd/wm/fs.c +++ b/cmd/wm/fs.c @@ -55,6 +55,7 @@ static char Ebadvalue[] = "bad value"; * /view/1/ FsDarea * /view/1/ctl FsFctl command interface (area) * /view/1/mode FsFmode column mode + * /view/1/capacity FsFcapacity capacity of column * /view/1/sel/ FsDclient * /view/1/1/class FsFclass class:instance of client * /view/1/1/name FsFname name of client @@ -217,6 +218,11 @@ qid2name(Qid *qid) return nil; return "tags"; break; + case FsFcapacity: + if(i1 == -1 || i2 == -1) + return nil; + return "capacity"; + break; case FsFmode: if(i1 == -1 || i2 == -1) return nil; @@ -269,6 +275,8 @@ name2type(char *name, unsigned char dir_type) return FsFrules; if(!strncmp(name, "data", 5)) return FsFdata; + if(!strncmp(name, "capacity", 9)) + return FsFcapacity; if(!strncmp(name, "mode", 5)) return FsFmode; if(!strncmp(name, "tag", 4)) @@ -381,6 +389,7 @@ mkqid(Qid *dir, char *wname, Qid *new) return -1; goto Mkfile; break; + case FsFcapacity: case FsFmode: if(dir_i1 == -1 || dir_i2 == -1 || dir_type != FsDarea) return -1; @@ -536,6 +545,10 @@ type2stat(Stat *stat, char *wname, Qid *dir) case FsFdata: return mkstat(stat, dir, wname, (dir_i1 == nlabel) ? 0 : strlen(label[dir_i1]->data), DMREAD | DMWRITE); break; + case FsFcapacity: + snprintf(buf, sizeof(buf), "%u", view[dir_i1]->area[dir_i2]->capacity); + return mkstat(stat, dir, wname, strlen(buf), DMREAD | DMWRITE); + break; case FsFmode: return mkstat(stat, dir, wname, strlen(mode2str(view[dir_i1]->area[dir_i2]->mode)), DMREAD | DMWRITE); break; @@ -789,8 +802,10 @@ xread(IXPConn *c, Fcall *fcall) case FsDarea: /* jump to offset */ len = type2stat(&stat, "ctl", &m->qid); - if(i2) + if(i2) { len += type2stat(&stat, "mode", &m->qid); + len += type2stat(&stat, "capacity", &m->qid); + } if(view[i1]->area[i2]->nframe) len += type2stat(&stat, "sel", &m->qid); for(i = 0; i < view[i1]->area[i2]->nframe; i++) { @@ -956,6 +971,8 @@ xread(IXPConn *c, Fcall *fcall) if(i2) { fcall->count += type2stat(&stat, "mode", &m->qid); p = ixp_enc_stat(p, &stat); + fcall->count += type2stat(&stat, "capacity", &m->qid); + p = ixp_enc_stat(p, &stat); } if(view[i1]->area[i2]->nframe) { fcall->count += type2stat(&stat, "sel", &m->qid); @@ -1103,6 +1120,13 @@ xread(IXPConn *c, Fcall *fcall) if((fcall->count = strlen(def.font))) memcpy(p, def.font, fcall->count); break; + case FsFcapacity: + if(!i2) + return Enofile; + snprintf(buf, sizeof(buf), "%u", view[i1]->area[i2]->capacity); + fcall->count = strlen(buf); + memcpy(p, buf, fcall->count); + break; case FsFmode: if(!i2) return Enofile; @@ -1319,6 +1343,35 @@ xwrite(IXPConn *c, Fcall *fcall) xfont = blitz_getfont(dpy, def.font); update_bar_geometry(); break; + case FsFcapacity: + if(!i2) + return Enofile; + if(fcall->count > sizeof(buf)) + return Ebadvalue; + memcpy(buf, fcall->data, fcall->count); + buf[fcall->count] = 0; + i = cext_strtonum(buf, 0, 0xffff, &err); + if(err) + return Ebadvalue; + view[i1]->area[i2]->capacity = i; + if(i) { + Area *a = view[i1]->area[i2]; + len = 0; + while(a->nframe > a->capacity) + pre_attach(a); + for(i = 1; i < view[i1]->narea; i++) + len += view[i1]->area[i]->nframe; + if(len > a->capacity) { + while(a->nframe < a->capacity) { + i = a->nframe; + post_detach(a); + if(i == a->nframe) + break; + } + } + arrange_area(a); + } + break; case FsFmode: if(!i2) return Enofile; diff --git a/cmd/wm/view.c b/cmd/wm/view.c index 667b6f03..66e576ca 100644 --- a/cmd/wm/view.c +++ b/cmd/wm/view.c @@ -234,7 +234,7 @@ detach_fromview(View *v, Client *c) Client *cl; for(i = 0; i < v->narea; i++) { if(clientofarea(v->area[i], c)) { - detach_fromarea(v->area[i], c); + detach_fromarea(v->area[i], c, True); XMoveWindow(dpy, c->framewin, 2 * rect.width, 0); } } @@ -297,3 +297,24 @@ restack_view(View *v) if(n) XRestackWindows(dpy, wins, n); } + +void +arrange_view(View *v, Bool updategeometry) +{ + unsigned int i; + unsigned int width; + + if(v->narea == 1) + return; + + width = rect.width / (v->narea - 1); + for(i = 1; i < v->narea; i++) { + Area *a = v->area[i]; + if(updategeometry) { + a->rect.height = rect.height - brect.height; + a->rect.x = (i - 1) * width; + a->rect.width = width; + } + arrange_area(a); + } +} diff --git a/cmd/wm/wm.h b/cmd/wm/wm.h index 0a8e730a..da2c2beb 100644 --- a/cmd/wm/wm.h +++ b/cmd/wm/wm.h @@ -60,13 +60,14 @@ enum { FsFtags, FsFclass, FsFtag, + FsFcapacity, FsFmode }; -#define MAX_TAGS 8 -#define MAX_TAGLEN 32 +#define MAX_TAGS 8 +#define MAX_TAGLEN 32 #define WM_PROTOCOL_DELWIN 1 -#define MIN_COLWIDTH 64 +#define MIN_COLWIDTH 32 typedef struct View View; typedef struct Area Area; @@ -91,6 +92,7 @@ struct Area { unsigned int framesz; unsigned int sel; unsigned int nframe; + unsigned int capacity; int mode; XRectangle rect; }; @@ -205,13 +207,14 @@ int aid2index(View *t, unsigned short id); void select_area(Area *a, char *arg); void send2area(Area *to, Area *from, Client *c); void attach_toarea(Area *a, Client *c); -void detach_fromarea(Area *a, Client *c); -void arrange_tag(View *t, Bool updategeometry); +void detach_fromarea(Area *a, Client *c, Bool postarrange); void arrange_area(Area *a); void resize_area(Client *c, XRectangle *r, XPoint *pt); int str2mode(char *arg); char *mode2str(int mode); Bool clientofarea(Area *a, Client *c); +void pre_attach(Area *a); +void post_detach(Area *a); /* bar.c */ Label *get_label(char *name); @@ -286,6 +289,7 @@ Bool istag(char *t); void update_tags(); /* view.c */ +void arrange_view(View *v, Bool updategeometry); View *alloc_view(char *name); void focus_view(View *v); XRectangle *rectangles(View *v, Bool isfloat, unsigned int *num);