17 static Point prevmouse;
18 static Window *mousew;
37 cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls)
44 * Always guaranteed that n bytes may be interpreted
45 * without worrying about partial runes. This may mean
46 * reading up to UTFmax-1 more bytes than n; the caller
47 * knows this. If n is a firm limit, the caller should
57 w = chartorune(s, (char*)q);
70 bytetorunestr(char *s, Runestr *rs)
77 cvttorunes(s, nb, r, &nb, &nr, nil);
86 fprint(2, "abaco: %s: %r\n", s);
98 error("malloc failed");
99 setmalloctag(p, getcallerpc(&n));
105 erealloc(void *p, ulong n)
109 error("realloc failed");
110 setmalloctag(p, getcallerpc(&n));
123 error("runestrdup failed");
124 setmalloctag(p, getcallerpc(&r));
135 error("strdup failed");
136 setmalloctag(t, getcallerpc(&s));
141 runestreq(Runestr a, Runestr b)
143 return runeeq(a.r, a.nr, b.r, b.nr);
147 runeeq(Rune *s1, uint n1, Rune *s2, uint n2)
151 return memcmp(s1, s2, n1*sizeof(Rune)) == 0;
155 closerunestr(Runestr *rs)
165 copyrunestr(Runestr *a, Runestr *b)
168 a->r = runemalloc(b->nr+1);
169 runemove(a->r, b->r, b->nr);
178 * Hard to get absolutely right. Use what we know about ASCII
179 * and assume anything above the Latin control characters is
180 * potentially an alphanumeric.
184 if(0x7F<=c && c<=0xA0)
186 if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
192 skipbl(Rune *r, int n, int *np)
194 while(n>0 && (*r==' ' || *r=='\t' || *r=='\n')){
203 findbl(Rune *r, int n, int *np)
205 while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){
218 ff = ((Iformfield *)i)->formfield;
219 if(ff->ftype==Ftext || ff->ftype==Ftextarea || ff->ftype==Fpassword)
228 if(i->state&IFwrap && i->tag!=Iruletag && i->tag!=Itabletag)
235 dimwidth(Dimen d, int w)
245 else if(k==Dpercent && s<100)
252 frdims(Dimen *d, int n, int t, int **ret)
254 int totpix, totpcnt, totrel;
255 double spix, spcnt, relu, vd;
256 int tt, trest, totpixrel, minrelu, i;
257 int *x, *spec, *kind;
260 *ret = x = emalloc(sizeof(int));
264 totpix = totpcnt = totrel = 0;
265 spec = emalloc(n*sizeof(int));
266 kind = emalloc(n*sizeof(int));
268 spec[i] = dimenspec(d[i]);
271 kind[i] = dimenkind(d[i]);
290 minrelu = Scrollsize+Scrollgap;
291 relu = (double)minrelu;
292 tt = totpix + t*totpcnt/100 + totrel*minrelu;
296 spcnt = (double)((t-totpix)*100)/(double)(t*totpcnt);
298 spix = (double)t/(double)totpix;
300 relu += (double)(t-tt)/(double)totrel;
302 totpixrel = totpix + totrel*minrelu;
304 spcnt = (double)((t-totpixrel)*100)/(double)(t*totpcnt);
306 trest = t - totrel*minrelu;
308 spcnt = (double)trest/(double)(totpix + (t*totpcnt/100));
310 spcnt = (double)t/(double)tt;
316 x = emalloc(n * sizeof(int));
318 for(i=0; i<n-1; i++){
319 vd = (double)spec[i];
325 vd = vd*(double)t*spcnt/100.0;
351 if(d->backgrounditem){
352 if(d->backgrounditem->aux){
353 ci = d->backgrounditem->aux;
355 getimage(ci, d->backgrounditem->altrep);
360 bg = getcolor(d->background.color);
371 return p->url->act.r;
372 return p->url->src.r;
376 eallocimage(Display *d, Rectangle r, ulong chan, int repl, int col)
380 i = allocimage(d, r, chan, repl, col);
382 error("allocimage failed");
387 rect3d(Image *im, Rectangle r, int i, Image **c, Point sp)
393 sp = addpt(sp, Pt(i,i));
396 draw(im, Rect(r.min.x+i, r.min.y+i, r.max.x-i, r.max.y-i), c[2], nil, sp);
398 p[1] = Pt(r.min.x, r.max.y);
399 p[2] = Pt(r.min.x+i, r.max.y-i);
400 p[3] = Pt(r.min.x+i, r.min.y+i);
401 p[4] = Pt(r.max.x-i, r.min.y+i);
402 p[5] = Pt(r.max.x, r.min.y);
403 fillpoly(im, p, 6, 0, c[0], sp);
405 p[1] = Pt(r.min.x, r.max.y);
406 p[2] = Pt(r.min.x+i, r.max.y-i);
407 p[3] = Pt(r.max.x-i, r.max.y-i);
408 p[4] = Pt(r.max.x-i, r.min.y+i);
409 p[5] = Pt(r.max.x, r.min.y);
410 fillpoly(im, p, 6, 0, c[1], sp);
414 ellipse3d(Image *im, Point p, int rad, int i, Image **c, Point sp)
416 fillarc(im, p, rad, rad, c[0], sp, 45, 180);
417 fillarc(im, p, rad, rad, c[1], sp, 45, -180);
418 fillellipse(im, p, rad-i, rad-i, c[2], sp);
422 colarray(Image **c, Image *c0, Image *c1, Image *c2, int checked)
434 static char *deffontpaths[] = {
438 static char *fontpaths[NumFnt];
439 static Font *fonts[NumFnt];
449 /* we don't care if getenv(2) fails */
451 snprint(buf, sizeof(buf)-1, "%s/lib/abaco.fonts", s);
453 if((bp=Bopen(buf, OREAD)) == nil)
456 for(i=0; i<NumFnt; i++)
457 if((fontpaths[i]=Brdstr(bp, '\n', 1)) == nil)
463 fprint(2, "abaco: not enough fontpaths in '%s'\n", buf);
468 for(i=0; i<NumFnt; i++)
469 fontpaths[i] = deffontpaths[i];
476 fonts[i] = openfont(display, fontpaths[i]);
478 error("can't open font file");
483 typedef struct Color Color;
495 static Color *colortab[NHASH];
504 return display->white;
505 else if(rgb == 0x000000)
506 return display->black;
509 for(c=colortab[h]; c!=nil; c=c->next)
511 flushimage(display, 0); /* BUG? */
514 c = emalloc(sizeof(Color));
515 c->i = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, (rgb<<8)|0xFF);
517 c->next = colortab[h];
524 plumbrunestr(Runestr *rs, char *attr)
530 if(plumbsendfd >= 0){
531 m = emalloc(sizeof(Plumbmsg));
532 m->src = estrdup("abaco");
534 m->wdir = estrdup("/tmp");
535 m->type = estrdup("text");
537 m->attr = plumbunpackattr(attr);
540 m->data = smprint("%.*S", rs->nr, rs->r);
542 i = plumbsend(plumbsendfd, m);
558 inclass(char c, Rune* cl)
560 int n, ans, negate, i;
573 if(cl[i]=='-' && i>0 && i<n-1){
574 if(c>=cl[i - 1] && c<=cl[i+1]){
597 t = smprint("%S", s);
602 if(inclass(c, L"- /$_@.!*'(),a-zA-Z0-9"))
607 u = runemalloc(len+1);
612 if(inclass(c, L"-/$_@.!*'(),a-zA-Z0-9"))
618 u[j++] = hexdigit((c >> 4)&15);
619 u[j++] = hexdigit(c&15);
628 reverseimages(Iimage **head)
633 for(c=*head; c!=nil; c=n){
641 char urlexpr[] = "^(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|"
651 urlprog = regcomp(urlexpr);
655 memset(rs, 0, sizeof(rs));
656 if(rregexec(urlprog, r, rs, nelem(rs)) == 0)
666 threadsetname("execproc");
679 procexecl(e->sync, "/bin/rc", "rc", "-c", e->cmd, nil);
684 pipeline(int fd, char *cmd, ...)
689 e = emalloc(sizeof(Exec));
690 if(pipe(e->p)<0 || pipe(e->q)<0)
691 error("can't create pipe");
695 e->cmd = vsmprint(cmd, a);
697 e->sync = chancreate(sizeof(ulong), 0);
699 error("can't create channel");
700 proccreate(execproc, e, STACK);
716 return c==' ' || c== '\t' || c=='\r' || c=='\n';
720 findctype(char *b, int l, char *keyword, char *s)
725 p = cistrstr(s, keyword);
728 p += strlen(keyword);
729 while(*p && isspace(*p))
734 while(*p && isspace(*p))
747 for(e = p; *e < 127 && *e > ' ' ; e++)
750 i = utfnlen(p, e - p);
753 snprint(b, l, "%.*s", i, p);
758 xtofchar(Rune *s, Font *f, long p)
767 for(r=s; *r!=L'\0'; r++){
768 p -= runestringnwidth(f, r, 1);
777 istextsel(Page *p, Rectangle r, int *q0, int *q1, Rune *s, Font *f)
782 topinr= ptinrect(p->top, r);
783 if(topinr || (r.min.y>p->top.y && r.max.y<p->bot.y))
785 botinr = ptinrect(p->bot, r);
786 if(botinr || r.min.y>p->bot.y)
787 p->selecting = FALSE;
789 if(topinr || botinr){
791 *q0 = xtofchar(s, f, p->top.x-r.min.x);
793 *q1 = xtofchar(s, f, p->bot.x-r.min.x);
801 getpt(Page *p, Point xy)
803 xy.x = xy.x-p->r.min.x+p->pos.x;
804 xy.y = xy.y-p->r.min.y+p->pos.y;
810 getimage(Cimage *ci, Rune *altr)
821 snprint(buf, sizeof(buf), "[%S]", altr ? altr : L"IMG");
823 r.max.x = 2*Space + stringwidth(font, buf);
824 r.max.y = 2*Space + font->height;
825 ci->i = eallocimage(display, r, GREY1, 1, DBlack);
828 string(ci->i, r.min, display->white, ZP, font, buf);
831 nbits = bytesperline(mi->r, mi->depth)*Dy(mi->r);
832 bits = emalloc(nbits);
833 unloadmemimage(mi, mi->r, bits, nbits);
835 /* get rid of alpha channel from transparent gif * /
838 for(y=1; y<nbits; y+=2)
839 bits[y>>1] = bits[y];
842 i = eallocimage(display, mi->r, mi->chan, 0, DNofill);
843 loadimage(i, i->r, bits, nbits);
844 i2 = eallocimage(display, i->r, RGB24, 1, DNofill);
845 draw(i2, i2->r, display->black, nil, ZP);
846 draw(i2, i2->r, i, nil, i->r.min);
856 fixtext1(Item **list)
867 for(it=*list; it!=nil; it=prev->next){
868 if(it->tag!=Itexttag || forceitem(it))
873 while(*s && isspacerune(*s))
877 prev = *list = it->next;
879 prev->next = it->next;
888 while(s[n] && !isspacerune(s[n]))
894 s1 = runemalloc(n+1);
895 s1 = runemove(s1, s, n);
899 while(*s && isspacerune(*s))
904 s2 = runemalloc(n+1);
907 ntext = emalloc(sizeof(Itext));
909 ntext->ascent = text->ascent;
910 ntext->anchorid = text->anchorid;
911 ntext->state = text->state&~(IFbrk|IFbrksp|IFnobrk|IFcleft|IFcright);
912 ntext->tag = text->tag;
913 ntext->fnt = text->fnt;
914 ntext->fg = text->fg;
915 ntext->ul = text->ul;
916 ntext->next = (Item *)text->next;
917 text->next = (Item *)ntext;
933 for(t=p->doc->tables; t!=nil; t=t->next)
934 for(c=t->cells; c!=nil; c=c->next)
935 fixtext1(&c->content);
938 typedef struct Refresh Refresh;
946 static Refresh *refreshs = nil;
947 static QLock refreshlock;
950 addrefresh(Page *p, char *fmt, ...)
960 s = runevsmprint(fmt, arg);
963 error("runevsmprint failed");
971 for(r=refreshs; r!=nil; r=r->next)
975 incref(p->w); /* flushrefresh will decref */
976 r = emalloc(sizeof(Refresh));
982 nbsendp(crefresh, nil);
983 qunlock(&refreshlock);
986 /* called while row is locked */
994 for(r=refreshs; r!=nil; r=next){
996 if(p->changed==TRUE && p->aborting==FALSE){
998 if(p->parent==nil || p->loading==FALSE)
1004 winsetstatus(p->w, p->status);
1015 qunlock(&refreshlock);
1019 savemouse(Window *w)
1021 prevmouse = mouse->xy;
1026 restoremouse(Window *w)
1028 if(mousew!=nil && mousew==w)
1029 moveto(mousectl, prevmouse);
1043 makenewwindow(Page *p)
1046 Window *w, *bigw, *emptyw;
1052 else if(selpage && selpage->col)
1054 else if(p && p->col)
1057 if(row.ncol==0 && rowadd(&row, nil, -1)==nil)
1058 error("can't make column");
1059 c = row.col[row.ncol-1];
1062 if(p==nil || p->w==nil || c->nw==0)
1063 return coladd(c, nil, nil, -1);
1065 /* find biggest window and biggest blank spot */
1068 for(i=1; i<c->nw; i++){
1070 /* use >= to choose one near bottom of screen */
1071 if(Dy(w->page.all) >= Dy(bigw->page.all))
1073 if(w->page.lay==nil && Dy(w->page.all) >= Dy(emptyw->page.all))
1076 emptyp = &emptyw->page;
1077 el = Dy(emptyp->all);
1078 /* if empty space is big, use it */
1079 if(el>15 || (el>3 && el>(Dy(bigw->page.all)-1)/2))
1080 y = emptyp->all.max.y;
1082 /* if this window is in column and isn't much smaller, split it */
1083 if(p->col==c && Dy(p->w->r)>2*Dy(bigw->r)/3)
1085 y = (bigw->r.min.y + bigw->r.max.y)/2;
1087 w = coladd(c, nil, nil, y);
1088 colgrow(w->col, w, 1);