diff options
author | rsc <devnull@localhost> | 2003-12-11 17:50:28 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2003-12-11 17:50:28 +0000 |
commit | b3994ec5c78e6c18885079b58abb7fb997899c3f (patch) | |
tree | d4ead391f5ebd1554cc5ecfba69130e750de67bb /src/cmd/acme/rows.c | |
parent | 32f69c36e0eec1227934bbd34854bfebd88686f2 (diff) | |
download | plan9port-b3994ec5c78e6c18885079b58abb7fb997899c3f.tar.gz plan9port-b3994ec5c78e6c18885079b58abb7fb997899c3f.tar.bz2 plan9port-b3994ec5c78e6c18885079b58abb7fb997899c3f.zip |
More files related to user-level file servers.
Also add acme!
Diffstat (limited to 'src/cmd/acme/rows.c')
-rw-r--r-- | src/cmd/acme/rows.c | 731 |
1 files changed, 731 insertions, 0 deletions
diff --git a/src/cmd/acme/rows.c b/src/cmd/acme/rows.c new file mode 100644 index 00000000..11014c2c --- /dev/null +++ b/src/cmd/acme/rows.c @@ -0,0 +1,731 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <fcall.h> +#include <bio.h> +#include <plumb.h> +#include "dat.h" +#include "fns.h" + +static Rune Lcolhdr[] = { + 'N', 'e', 'w', 'c', 'o', 'l', ' ', + 'K', 'i', 'l', 'l', ' ', + 'P', 'u', 't', 'a', 'l', 'l', ' ', + 'D', 'u', 'm', 'p', ' ', + 'E', 'x', 'i', 't', ' ', + 0 +}; + +void +rowinit(Row *row, Rectangle r) +{ + Rectangle r1; + Text *t; + + draw(screen, r, display->white, nil, ZP); + row->r = r; + row->col = nil; + row->ncol = 0; + r1 = r; + r1.max.y = r1.min.y + font->height; + t = &row->tag; + textinit(t, fileaddtext(nil, t), r1, rfget(FALSE, FALSE, FALSE, nil), tagcols); + t->what = Rowtag; + t->row = row; + t->w = nil; + t->col = nil; + r1.min.y = r1.max.y; + r1.max.y += Border; + draw(screen, r1, display->black, nil, ZP); + textinsert(t, 0, Lcolhdr, 29, TRUE); + textsetselect(t, t->file->b.nc, t->file->b.nc); +} + +Column* +rowadd(Row *row, Column *c, int x) +{ + Rectangle r, r1; + Column *d; + int i; + + d = nil; + r = row->r; + r.min.y = row->tag.fr.r.max.y+Border; + if(x<r.min.x && row->ncol>0){ /*steal 40% of last column by default */ + d = row->col[row->ncol-1]; + x = d->r.min.x + 3*Dx(d->r)/5; + } + /* look for column we'll land on */ + for(i=0; i<row->ncol; i++){ + d = row->col[i]; + if(x < d->r.max.x) + break; + } + if(row->ncol > 0){ + if(i < row->ncol) + i++; /* new column will go after d */ + r = d->r; + if(Dx(r) < 100) + return nil; + draw(screen, r, display->white, nil, ZP); + r1 = r; + r1.max.x = min(x, r.max.x-50); + if(Dx(r1) < 50) + r1.max.x = r1.min.x+50; + colresize(d, r1); + r1.min.x = r1.max.x; + r1.max.x = r1.min.x+Border; + draw(screen, r1, display->black, nil, ZP); + r.min.x = r1.max.x; + } + if(c == nil){ + c = emalloc(sizeof(Column)); + colinit(c, r); + incref(&reffont.ref); + }else + colresize(c, r); + c->row = row; + c->tag.row = row; + row->col = realloc(row->col, (row->ncol+1)*sizeof(Column*)); + memmove(row->col+i+1, row->col+i, (row->ncol-i)*sizeof(Column*)); + row->col[i] = c; + row->ncol++; + clearmouse(); + return c; +} + +void +rowresize(Row *row, Rectangle r) +{ + int i, dx, odx; + Rectangle r1, r2; + Column *c; + + dx = Dx(r); + odx = Dx(row->r); + row->r = r; + r1 = r; + r1.max.y = r1.min.y + font->height; + textresize(&row->tag, r1); + r1.min.y = r1.max.y; + r1.max.y += Border; + draw(screen, r1, display->black, nil, ZP); + r.min.y = r1.max.y; + r1 = r; + r1.max.x = r1.min.x; + for(i=0; i<row->ncol; i++){ + c = row->col[i]; + r1.min.x = r1.max.x; + if(i == row->ncol-1) + r1.max.x = r.max.x; + else + r1.max.x = r1.min.x+Dx(c->r)*dx/odx; + if(i > 0){ + r2 = r1; + r2.max.x = r2.min.x+Border; + draw(screen, r2, display->black, nil, ZP); + r1.min.x = r2.max.x; + } + colresize(c, r1); + } +} + +void +rowdragcol(Row *row, Column *c, int _0) +{ + Rectangle r; + int i, b, x; + Point p, op; + Column *d; + + USED(_0); + + clearmouse(); + setcursor(mousectl, &boxcursor); + b = mouse->buttons; + op = mouse->xy; + while(mouse->buttons == b) + readmouse(mousectl); + setcursor(mousectl, nil); + if(mouse->buttons){ + while(mouse->buttons) + readmouse(mousectl); + return; + } + + for(i=0; i<row->ncol; i++) + if(row->col[i] == c) + goto Found; + error("can't find column"); + + Found: + if(i == 0) + return; + p = mouse->xy; + if((abs(p.x-op.x)<5 && abs(p.y-op.y)<5)) + return; + if((i>0 && p.x<row->col[i-1]->r.min.x) || (i<row->ncol-1 && p.x>c->r.max.x)){ + /* shuffle */ + x = c->r.min.x; + rowclose(row, c, FALSE); + if(rowadd(row, c, p.x) == nil) /* whoops! */ + if(rowadd(row, c, x) == nil) /* WHOOPS! */ + if(rowadd(row, c, -1)==nil){ /* shit! */ + rowclose(row, c, TRUE); + return; + } + colmousebut(c); + return; + } + d = row->col[i-1]; + if(p.x < d->r.min.x+80+Scrollwid) + p.x = d->r.min.x+80+Scrollwid; + if(p.x > c->r.max.x-80-Scrollwid) + p.x = c->r.max.x-80-Scrollwid; + r = d->r; + r.max.x = c->r.max.x; + draw(screen, r, display->white, nil, ZP); + r.max.x = p.x; + colresize(d, r); + r = c->r; + r.min.x = p.x; + r.max.x = r.min.x; + r.max.x += Border; + draw(screen, r, display->black, nil, ZP); + r.min.x = r.max.x; + r.max.x = c->r.max.x; + colresize(c, r); + colmousebut(c); +} + +void +rowclose(Row *row, Column *c, int dofree) +{ + Rectangle r; + int i; + + for(i=0; i<row->ncol; i++) + if(row->col[i] == c) + goto Found; + error("can't find column"); + Found: + r = c->r; + if(dofree) + colcloseall(c); + memmove(row->col+i, row->col+i+1, (row->ncol-i)*sizeof(Column*)); + row->ncol--; + row->col = realloc(row->col, row->ncol*sizeof(Column*)); + if(row->ncol == 0){ + draw(screen, r, display->white, nil, ZP); + return; + } + if(i == row->ncol){ /* extend last column right */ + c = row->col[i-1]; + r.min.x = c->r.min.x; + r.max.x = row->r.max.x; + }else{ /* extend next window left */ + c = row->col[i]; + r.max.x = c->r.max.x; + } + draw(screen, r, display->white, nil, ZP); + colresize(c, r); +} + +Column* +rowwhichcol(Row *row, Point p) +{ + int i; + Column *c; + + for(i=0; i<row->ncol; i++){ + c = row->col[i]; + if(ptinrect(p, c->r)) + return c; + } + return nil; +} + +Text* +rowwhich(Row *row, Point p) +{ + Column *c; + + if(ptinrect(p, row->tag.all)) + return &row->tag; + c = rowwhichcol(row, p); + if(c) + return colwhich(c, p); + return nil; +} + +Text* +rowtype(Row *row, Rune r, Point p) +{ + Window *w; + Text *t; + + clearmouse(); + qlock(&row->lk); + if(bartflag) + t = barttext; + else + t = rowwhich(row, p); + if(t!=nil && !(t->what==Tag && ptinrect(p, t->scrollr))){ + w = t->w; + if(w == nil) + texttype(t, r); + else{ + winlock(w, 'K'); + wintype(w, t, r); + winunlock(w); + } + } + qunlock(&row->lk); + return t; +} + +int +rowclean(Row *row) +{ + int clean; + int i; + + clean = TRUE; + for(i=0; i<row->ncol; i++) + clean &= colclean(row->col[i]); + return clean; +} + +void +rowdump(Row *row, char *file) +{ + int i, j, fd, m, n, dumped; + uint q0, q1; + Biobuf *b; + char *buf, *a, *fontname; + Rune *r; + Column *c; + Window *w, *w1; + Text *t; + + if(row->ncol == 0) + return; + buf = fbufalloc(); + if(file == nil){ + if(home == nil){ + warning(nil, "can't find file for dump: $home not defined\n"); + goto Rescue; + } + sprint(buf, "%s/acme.dump", home); + file = buf; + } + fd = create(file, OWRITE, 0600); + if(fd < 0){ + warning(nil, "can't open %s: %r\n", file); + goto Rescue; + } + b = emalloc(sizeof(Biobuf)); + Binit(b, fd, OWRITE); + r = fbufalloc(); + Bprint(b, "%s\n", wdir); + Bprint(b, "%s\n", fontnames[0]); + Bprint(b, "%s\n", fontnames[1]); + for(i=0; i<row->ncol; i++){ + c = row->col[i]; + Bprint(b, "%11d", 100*(c->r.min.x-row->r.min.x)/Dx(row->r)); + if(i == row->ncol-1) + Bputc(b, '\n'); + else + Bputc(b, ' '); + } + for(i=0; i<row->ncol; i++){ + c = row->col[i]; + for(j=0; j<c->nw; j++) + c->w[j]->body.file->dumpid = 0; + } + for(i=0; i<row->ncol; i++){ + c = row->col[i]; + for(j=0; j<c->nw; j++){ + w = c->w[j]; + wincommit(w, &w->tag); + t = &w->body; + /* windows owned by others get special treatment */ + if(w->nopen[QWevent] > 0) + if(w->dumpstr == nil) + continue; + /* zeroxes of external windows are tossed */ + if(t->file->ntext > 1) + for(n=0; n<t->file->ntext; n++){ + w1 = t->file->text[n]->w; + if(w == w1) + continue; + if(w1->nopen[QWevent]) + goto Continue2; + } + fontname = ""; + if(t->reffont->f != font) + fontname = t->reffont->f->name; + if(t->file->nname) + a = runetobyte(t->file->name, t->file->nname); + else + a = emalloc(1); + if(t->file->dumpid){ + dumped = FALSE; + Bprint(b, "x%11d %11d %11d %11d %11d %s\n", i, t->file->dumpid, + w->body.q0, w->body.q1, + 100*(w->r.min.y-c->r.min.y)/Dy(c->r), + fontname); + }else if(w->dumpstr){ + dumped = FALSE; + Bprint(b, "e%11d %11d %11d %11d %11d %s\n", i, t->file->dumpid, + 0, 0, + 100*(w->r.min.y-c->r.min.y)/Dy(c->r), + fontname); + }else if((w->dirty==FALSE && access(a, 0)==0) || w->isdir){ + dumped = FALSE; + t->file->dumpid = w->id; + Bprint(b, "f%11d %11d %11d %11d %11d %s\n", i, w->id, + w->body.q0, w->body.q1, + 100*(w->r.min.y-c->r.min.y)/Dy(c->r), + fontname); + }else{ + dumped = TRUE; + t->file->dumpid = w->id; + Bprint(b, "F%11d %11d %11d %11d %11d %11d %s\n", i, j, + w->body.q0, w->body.q1, + 100*(w->r.min.y-c->r.min.y)/Dy(c->r), + w->body.file->b.nc, fontname); + } + free(a); + winctlprint(w, buf, 0); + Bwrite(b, buf, strlen(buf)); + m = min(RBUFSIZE, w->tag.file->b.nc); + bufread(&w->tag.file->b, 0, r, m); + n = 0; + while(n<m && r[n]!='\n') + n++; + r[n++] = '\n'; + Bprint(b, "%.*S", n, r); + if(dumped){ + q0 = 0; + q1 = t->file->b.nc; + while(q0 < q1){ + n = q1 - q0; + if(n > BUFSIZE/UTFmax) + n = BUFSIZE/UTFmax; + bufread(&t->file->b, q0, r, n); + Bprint(b, "%.*S", n, r); + q0 += n; + } + } + if(w->dumpstr){ + if(w->dumpdir) + Bprint(b, "%s\n%s\n", w->dumpdir, w->dumpstr); + else + Bprint(b, "\n%s\n", w->dumpstr); + } + Continue2:; + } + } + Bterm(b); + close(fd); + free(b); + fbuffree(r); + + Rescue: + fbuffree(buf); +} + +static +char* +rdline(Biobuf *b, int *linep) +{ + char *l; + + l = Brdline(b, '\n'); + if(l) + (*linep)++; + return l; +} + +/* + * Get font names from load file so we don't load fonts we won't use + */ +void +rowloadfonts(char *file) +{ + int i; + Biobuf *b; + char *l; + + b = Bopen(file, OREAD); + if(b == nil) + return; + /* current directory */ + l = Brdline(b, '\n'); + if(l == nil) + goto Return; + /* global fonts */ + for(i=0; i<2; i++){ + l = Brdline(b, '\n'); + if(l == nil) + goto Return; + l[Blinelen(b)-1] = 0; + if(*l && strcmp(l, fontnames[i])!=0) + fontnames[i] = estrdup(l); + } + Return: + Bterm(b); +} + +void +rowload(Row *row, char *file, int initing) +{ + int i, j, line, percent, y, nr, nfontr, n, ns, ndumped, dumpid, x, fd; + Biobuf *b, *bout; + char *buf, *l, *t, *fontname; + Rune *r, rune, *fontr; + Column *c, *c1, *c2; + uint q0, q1; + Rectangle r1, r2; + Window *w; + + buf = fbufalloc(); + if(file == nil){ + if(home == nil){ + warning(nil, "can't find file for load: $home not defined\n"); + goto Rescue1; + } + sprint(buf, "%s/acme.dump", home); + file = buf; + } + b = Bopen(file, OREAD); + if(b == nil){ + warning(nil, "can't open load file %s: %r\n", file); + goto Rescue1; + } + /* current directory */ + line = 0; + l = rdline(b, &line); + if(l == nil) + goto Rescue2; + l[Blinelen(b)-1] = 0; + if(chdir(l) < 0){ + warning(nil, "can't chdir %s\n", l); + goto Rescue2; + } + /* global fonts */ + for(i=0; i<2; i++){ + l = rdline(b, &line); + if(l == nil) + goto Rescue2; + l[Blinelen(b)-1] = 0; + if(*l && strcmp(l, fontnames[i])!=0) + rfget(i, TRUE, i==0 && initing, estrdup(l)); + } + if(initing && row->ncol==0) + rowinit(row, screen->clipr); + l = rdline(b, &line); + if(l == nil) + goto Rescue2; + j = Blinelen(b)/12; + if(j<=0 || j>10) + goto Rescue2; + for(i=0; i<j; i++){ + percent = atoi(l+i*12); + if(percent<0 || percent>=100) + goto Rescue2; + x = row->r.min.x+percent*Dx(row->r)/100; + if(i < row->ncol){ + if(i == 0) + continue; + c1 = row->col[i-1]; + c2 = row->col[i]; + r1 = c1->r; + r2 = c2->r; + r1.max.x = x; + r2.min.x = x+Border; + if(Dx(r1) < 50 || Dx(r2) < 50) + continue; + draw(screen, Rpt(r1.min, r2.max), display->white, nil, ZP); + colresize(c1, r1); + colresize(c2, r2); + r2.min.x = x; + r2.max.x = x+Border; + draw(screen, r2, display->black, nil, ZP); + } + if(i >= row->ncol) + rowadd(row, nil, x); + } + for(;;){ + l = rdline(b, &line); + if(l == nil) + break; + dumpid = 0; + switch(l[0]){ + case 'e': + if(Blinelen(b) < 1+5*12+1) + goto Rescue2; + l = rdline(b, &line); /* ctl line; ignored */ + if(l == nil) + goto Rescue2; + l = rdline(b, &line); /* directory */ + if(l == nil) + goto Rescue2; + l[Blinelen(b)-1] = 0; + if(*l == '\0'){ + if(home == nil) + r = bytetorune("./", &nr); + else{ + t = emalloc(strlen(home)+1+1); + sprint(t, "%s/", home); + r = bytetorune(t, &nr); + free(t); + } + }else + r = bytetorune(l, &nr); + l = rdline(b, &line); /* command */ + if(l == nil) + goto Rescue2; + t = emalloc(Blinelen(b)+1); + memmove(t, l, Blinelen(b)); + run(nil, t, r, nr, TRUE, nil, nil, FALSE); + /* r is freed in run() */ + continue; + case 'f': + if(Blinelen(b) < 1+5*12+1) + goto Rescue2; + fontname = l+1+5*12; + ndumped = -1; + break; + case 'F': + if(Blinelen(b) < 1+6*12+1) + goto Rescue2; + fontname = l+1+6*12; + ndumped = atoi(l+1+5*12+1); + break; + case 'x': + if(Blinelen(b) < 1+5*12+1) + goto Rescue2; + fontname = l+1+5*12; + ndumped = -1; + dumpid = atoi(l+1+1*12); + break; + default: + goto Rescue2; + } + l[Blinelen(b)-1] = 0; + fontr = nil; + nfontr = 0; + if(*fontname) + fontr = bytetorune(fontname, &nfontr); + i = atoi(l+1+0*12); + j = atoi(l+1+1*12); + q0 = atoi(l+1+2*12); + q1 = atoi(l+1+3*12); + percent = atoi(l+1+4*12); + if(i<0 || i>10) + goto Rescue2; + if(i > row->ncol) + i = row->ncol; + c = row->col[i]; + y = c->r.min.y+(percent*Dy(c->r))/100; + if(y<c->r.min.y || y>=c->r.max.y) + y = -1; + if(dumpid == 0) + w = coladd(c, nil, nil, y); + else + w = coladd(c, nil, lookid(dumpid, TRUE), y); + if(w == nil) + continue; + w->dumpid = j; + l = rdline(b, &line); + if(l == nil) + goto Rescue2; + l[Blinelen(b)-1] = 0; + r = bytetorune(l+5*12, &nr); + ns = -1; + for(n=0; n<nr; n++){ + if(r[n] == '/') + ns = n; + if(r[n] == ' ') + break; + } + if(dumpid == 0) + winsetname(w, r, n); + for(; n<nr; n++) + if(r[n] == '|') + break; + wincleartag(w); + textinsert(&w->tag, w->tag.file->b.nc, r+n+1, nr-(n+1), TRUE); + free(r); + if(ndumped >= 0){ + /* simplest thing is to put it in a file and load that */ + sprint(buf, "/tmp/d%d.%.4sacme", getpid(), getuser()); + fd = create(buf, OWRITE|ORCLOSE, 0600); + if(fd < 0){ + warning(nil, "can't create temp file: %r\n"); + goto Rescue2; + } + bout = emalloc(sizeof(Biobuf)); + Binit(bout, fd, OWRITE); + for(n=0; n<ndumped; n++){ + rune = Bgetrune(b); + if(rune == '\n') + line++; + if(rune == (Rune)Beof){ + Bterm(bout); + free(bout); + close(fd); + goto Rescue2; + } + Bputrune(bout, rune); + } + Bterm(bout); + free(bout); + textload(&w->body, 0, buf, 1); + close(fd); + w->body.file->mod = TRUE; + for(n=0; n<w->body.file->ntext; n++) + w->body.file->text[n]->w->dirty = TRUE; + winsettag(w); + }else if(dumpid==0 && r[ns+1]!='+' && r[ns+1]!='-') + get(&w->body, nil, nil, FALSE, XXX, nil, 0); + if(fontr){ + fontx(&w->body, nil, nil, 0, 0, fontr, nfontr); + free(fontr); + } + if(q0>w->body.file->b.nc || q1>w->body.file->b.nc || q0>q1) + q0 = q1 = 0; + textshow(&w->body, q0, q1, 1); + w->maxlines = min(w->body.fr.nlines, max(w->maxlines, w->body.fr.maxlines)); + } + Bterm(b); + +Rescue1: + fbuffree(buf); + return; + +Rescue2: + warning(nil, "bad load file %s:%d\n", file, line); + Bterm(b); + goto Rescue1; +} + +void +allwindows(void (*f)(Window*, void*), void *arg) +{ + int i, j; + Column *c; + + for(i=0; i<row.ncol; i++){ + c = row.col[i]; + for(j=0; j<c->nw; j++) + (*f)(c->w[j], arg); + } +} |