15 static void pageload1(Page *, Url *, int);
19 addchild(Page *p, Page *c)
31 for(t=p->child; t->next!=nil; t=t->next)
39 loadchilds(Page *p, Kidinfo *k)
45 addrefresh(p, "loading frames...");
47 for(t=k->kidinfos; t!=nil; t=t->next){
48 c = emalloc(sizeof(Page));
51 c->url = urldup(p->url);
55 /* this check shouldn't be necessary, but... */
57 rs.r = urlcombine(p->url->act.r, t->src);
58 rs.nr = runestrlen(rs.r);
59 pageload1(c, urlalloc(&rs, nil, HGet), FALSE);
70 "image/gif", "gif -t9",
71 "image/jpeg", "jpg -t9",
72 "image/jpg", "jpg -t9",
73 "image/pjpeg", "jpg -t9",
74 "image/png", "png -t9",
75 "image/ppm", "ppm -t9",
80 getfilter(Rune *r, int x, int y)
85 snprint(buf, sizeof(buf), "%S", r);
86 for(i=0; filtertab[i].mime!=nil; i++)
87 if(cistrncmp(buf, filtertab[i].mime, strlen(filtertab[i].mime)) == 0)
90 if(filtertab[i].filter == nil)
94 return smprint("%s", filtertab[i].filter);
96 return smprint("%s | resize -x %d -y %d", filtertab[i].filter, x, y);
98 return smprint("%s | resize -x %d", filtertab[i].filter, x);
100 return smprint("%s | resize -y %d", filtertab[i].filter, y);
103 static Cimage *cimages = nil;
104 static QLock cimagelock;
108 freecimage(Cimage *ci)
117 freememimage(ci->mi);
125 ci1->next = ci->next;
133 qunlock(&cimagelock);
142 for(i=0; i<p->ncimage; i++)
143 freecimage(p->cimage[i]);
151 loadimg(Rune *src, int x , int y)
158 ci = emalloc(sizeof(Cimage));
160 rs.nr = runestrlen(rs.r);
161 ci->url = urlalloc(&rs, nil, HGet);
162 fd = urlopen(ci->url);
167 filter = getfilter(ci->url->ctype.r, x, y);
169 werrstr("%S unsupported: %S", ci->url->ctype.r, ci->url->act.r);
174 fd = pipeline(fd, "%s", filter);
178 ci->mi = readmemimage(fd);
181 werrstr("can't read image");
194 for(ci=cimages; ci!=nil; ci=ci->next)
195 if(runestrcmp(ci->url->src.r, s) == 0)
198 qunlock(&cimagelock);
209 addrefresh(p, "loading images...");
210 reverseimages(&p->doc->images);
211 for(i=p->doc->images; i!=nil; i=i->nextimage){
214 src = urlcombine(getbase(p), i->imsrc);
217 ci = loadimg(src, i->imwidth, i->imheight);
221 qunlock(&cimagelock);
226 p->cimage = erealloc(p->cimage, ++p->ncimage*sizeof(Cimage *));
227 p->cimage[p->ncimage-1] = ci;
233 static char *mimetab[] = {
241 pageloadproc(void *v)
244 char buf[BUFSIZE], cs[32], *s;
248 threadsetname("pageloadproc");
252 addrefresh(p, "opening: %S...", p->url->src.r);
253 fd = urlopen(p->url);
255 addrefresh(p, "%S: %r", p->url->src.r);
260 if(runestrlen(p->url->ctype.r) == 0) /* assume .html when headers don't say anyting */
263 snprint(buf, sizeof(buf), "%S", p->url->ctype.r);
264 for(i=0; mimetab[i]!=nil; i++)
265 if(cistrncmp(buf, mimetab[i], strlen(mimetab[i])) == 0)
271 }else if(cistrncmp(buf, "text/", 5) == 0)
275 addrefresh(p, "%S: unsupported mime type: '%S'", p->url->act.r, p->url->ctype.r);
278 addrefresh(p, "loading: %S...", p->url->src.r);
281 if(p->url->ctype.nr > 0){
282 snprint(buf, sizeof(buf), "%.*S", p->url->ctype.nr, p->url->ctype.r);
283 if(findctype(cs, sizeof(cs), "charset", buf) == 0)
286 if((fd = pipeline(fd, s != nil ? "uhtml -c %q" : "uhtml", s)) < 0)
291 while((n=read(fd, buf, sizeof(buf))) > 0){
299 s = erealloc(s, l+n+1);
300 memmove(s+l, buf, n);
307 p->items = parsehtml((uchar *)s, n, p->url->act.r, ctype, UTF_8, &p->doc);
310 if(ctype==TextHtml && p->aborting==FALSE){
313 if(p->doc->doctitle){
314 p->title.r = erunestrdup(p->doc->doctitle);
315 p->title.nr = runestrlen(p->title.r);
319 loadchilds(p, p->doc->kidinfo);
320 else if(p->doc->images)
331 pageload1(Page *p, Url *u, int dohist)
337 winaddhist(p->w, p->url);
338 proccreate(pageloadproc, p, STACK);
342 pageload(Page *p, Url *u, int dohist)
345 textset(&p->w->url, u->src.r, u->src.nr);
346 draw(p->b, p->all, display->white, nil, ZP);
347 pageload1(p, u, dohist);
351 pageget(Page *p, Runestr *src, Runestr *post, int m, int dohist)
353 pageload(p, urlalloc(src, post, m), dohist);
375 for(c=p->child; c!=nil; c=nc){
381 closerunestr(&p->title);
382 closerunestr(&p->refresh.rs);
387 p->loading = p->aborting = FALSE;
395 for(c=p->child; c!=nil; c=c->next)
415 tmp = eallocimage(display, Rect(0,0,Dx(screen->r),Dy(screen->r)), screen->chan, 0, -1);
420 renderchilds(Page *p)
425 int i, j, x, y, *w, *h;
427 draw(p->b, p->all, display->white, nil, ZP);
432 frdims(k->rows, k->nrows, Dy(r), &h);
433 frdims(k->cols, k->ncols, Dx(r), &w);
434 for(i=0; i<k->nrows; i++){
436 for(j=0; j<k->ncols; j++){
440 c->all = Rect(x,y,x+w[j],y+h[i]);
460 p->hscrollr.min.y = r.max.y-Scrollsize;
462 p->vscrollr.max.x = r.min.x+Scrollsize;
463 r.max.y -= Scrollsize;
464 r.min.x += Scrollsize;
466 p->vscrollr.max.y = r.max.y;
467 p->hscrollr.min.x = r.min.x;
475 if(p->child && p->loading==FALSE)
487 if(Dx(r)==0 || Dy(r)==0){
488 draw(p->b, p->r, display->white, nil, ZP);
494 p->selecting = FALSE;
495 draw(tmp, tmp->r, getbg(p), nil, ZP);
496 laydraw(p, tmp, p->lay);
497 draw(p->b, p->r, tmp, nil, tmp->r.min);
500 r.max.y += Scrollsize;
501 draw(p->b, r, tagcols[HIGH], nil, ZP);
502 draw(p->b, insetrect(r, 1), tagcols[BACK], nil, ZP);
508 pageselect1(Page *p) /* when called, button 1 is down */
510 Point mp, npos, opos;
518 if(mp.x < p->r.min.x)
519 x -= p->r.min.x-mp.x;
520 else if(mp.x > p->r.max.x)
521 x += mp.x-p->r.max.x;
522 if(mp.y < p->r.min.y)
523 y -= (p->r.min.y-mp.y)*Panspeed;
524 else if(mp.y > p->r.max.y)
525 y += (mp.y-p->r.max.y)*Panspeed;
527 scrled = pagescrollxy(p, x, y);
543 }while(mousectl->buttons == b);
546 static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 };
547 static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };
548 static Rune left2[] = { L'\'', L'"', L'`', 0 };
564 pagedoubleclick(Page *p)
570 xy = getpt(p, mouse->xy);
571 l = linewhich(p->lay, xy);
572 if(l==nil || l->hastext==FALSE)
575 if(xy.x<l->boxes->r.min.x && hasbrk(l->state)){ /* beginning of line? */
576 p->top = l->boxes->r.min;
577 if(l->next && !hasbrk(l->next->state)){
578 for(l=l->next; l->next!=nil; l=l->next)
579 if(hasbrk(l->next->state))
582 p->bot = l->lastbox->r.max;;
583 }else if(xy.x>l->lastbox->r.max.x && hasbrk(l->next->state)){ /* end of line? */
584 p->bot = l->lastbox->r.max;
585 if(!hasbrk(l->state) && l->prev!=nil){
586 for(l=l->prev; l->prev!=nil; l=l->prev)
590 p->top = l->boxes->r.min;
593 if(b!=nil && b->i->tag==Itexttag){
603 static uint clickmsec;
613 * To have double-clicking and chording, we double-click
614 * immediately if it might make sense.
617 if(mouse->msec-clickmsec<500){
621 /* stay here until something interesting happens */
624 while(mouse->buttons==b && abs(mouse->xy.x-x)<3 && abs(mouse->xy.y-y)<3);
625 mouse->xy.x = x; /* in case we're calling pageselect1 */
628 if(mousectl->buttons == b)
631 if(eqpt(p->top, p->bot)){
632 if(mouse->msec-clickmsec<500)
635 clickmsec = mouse->msec;
637 while(mouse->buttons){
640 if(b & 2) /* snarf only */
641 cut(nil, nil, TRUE, FALSE, nil, 0);
642 while(mouse->buttons == b)
648 pagewhich(Page *p, Point xy)
655 for(c=p->child; c!=nil; c=c->next)
656 if(ptinrect(xy, c->all))
657 return pagewhich(c, xy);
663 pagemouse(Page *p, Point xy, int but)
667 p = pagewhich(p, xy);
677 if(ptinrect(xy, p->vscrollr)){
678 pagescroll(p, but, FALSE);
681 if(ptinrect(xy, p->hscrollr)){
682 pagescroll(p, but, TRUE);
686 b = boxwhich(p->lay, xy);
694 pagetype(Page *p, Rune r, Point xy)
699 p = pagewhich(p, xy);
711 b = boxwhich(p->lay, xy);
716 /* ^H: same as 'Back' */
718 wingohist(p->w, FALSE);
746 y -= Dy(p->lay->r); /* force p->pos.y = 0 */
749 y = Dy(p->lay->r) - Dy(p->r);
754 if(pagescrollxy(p, x, y))
763 memset(&rs, 0, sizeof(Runestr));
764 laysnarf(p, p->lay, &rs);
770 pagesetrefresh(Page *p)
777 if(!p->doc || !p->doc->refresh)
781 q = runestrchr(s, L'=');
794 t = runesmprint("%.*S", n, q);
795 rs.r = urlcombine(getbase(p), t);
796 rs.nr = runestrlen(rs.r);
797 copyrunestr(&p->refresh.rs, &rs);
802 q = runestrchr(s, L';');
804 v = smprint("%.*S", (int)(q-s), s);
805 p->refresh.t = atoi(v);
810 p->refresh.t += time(0);
821 t = p->refresh.t - time(0);
825 pageget(p, &p->refresh.rs, nil, HGet, FALSE);