xref: /plan9/sys/src/cmd/abaco/page.c (revision 7ab27030036b6c877a6f81728daeda263d1ca3cf)
1*7ab27030SDavid du Colombier #include <u.h>
2*7ab27030SDavid du Colombier #include <libc.h>
3*7ab27030SDavid du Colombier #include <draw.h>
4*7ab27030SDavid du Colombier #include <memdraw.h>
5*7ab27030SDavid du Colombier #include <thread.h>
6*7ab27030SDavid du Colombier #include <cursor.h>
7*7ab27030SDavid du Colombier #include <mouse.h>
8*7ab27030SDavid du Colombier #include <keyboard.h>
9*7ab27030SDavid du Colombier #include <frame.h>
10*7ab27030SDavid du Colombier #include <plumb.h>
11*7ab27030SDavid du Colombier #include <html.h>
12*7ab27030SDavid du Colombier #include "dat.h"
13*7ab27030SDavid du Colombier #include "fns.h"
14*7ab27030SDavid du Colombier 
15*7ab27030SDavid du Colombier static void pageload1(Page *, Url *, int);
16*7ab27030SDavid du Colombier 
17*7ab27030SDavid du Colombier static
18*7ab27030SDavid du Colombier void
addchild(Page * p,Page * c)19*7ab27030SDavid du Colombier addchild(Page *p, Page *c)
20*7ab27030SDavid du Colombier {
21*7ab27030SDavid du Colombier 	Page *t;
22*7ab27030SDavid du Colombier 
23*7ab27030SDavid du Colombier 	c->parent = p;
24*7ab27030SDavid du Colombier 	c->w = p->w;
25*7ab27030SDavid du Colombier 	c->b = p->b;
26*7ab27030SDavid du Colombier 	c->col = p->col;
27*7ab27030SDavid du Colombier 	c->row = p->row;
28*7ab27030SDavid du Colombier 	if(p->child == nil)
29*7ab27030SDavid du Colombier 		p->child = c;
30*7ab27030SDavid du Colombier 	else{
31*7ab27030SDavid du Colombier 		for(t=p->child; t->next!=nil; t=t->next)
32*7ab27030SDavid du Colombier 			;
33*7ab27030SDavid du Colombier 		t->next = c;
34*7ab27030SDavid du Colombier 	}
35*7ab27030SDavid du Colombier }
36*7ab27030SDavid du Colombier 
37*7ab27030SDavid du Colombier static
38*7ab27030SDavid du Colombier void
loadchilds(Page * p,Kidinfo * k)39*7ab27030SDavid du Colombier loadchilds(Page *p, Kidinfo *k)
40*7ab27030SDavid du Colombier {
41*7ab27030SDavid du Colombier 	Runestr rs;
42*7ab27030SDavid du Colombier 	Kidinfo *t;
43*7ab27030SDavid du Colombier 	Page *c;
44*7ab27030SDavid du Colombier 
45*7ab27030SDavid du Colombier 	addrefresh(p, "loading frames...");
46*7ab27030SDavid du Colombier 	p->kidinfo = k;
47*7ab27030SDavid du Colombier 	for(t=k->kidinfos; t!=nil; t=t->next){
48*7ab27030SDavid du Colombier 		c = emalloc(sizeof(Page));
49*7ab27030SDavid du Colombier 		addchild(p, c);
50*7ab27030SDavid du Colombier 		if(t->isframeset){
51*7ab27030SDavid du Colombier 			c->url = urldup(p->url);
52*7ab27030SDavid du Colombier 			loadchilds(c, t);
53*7ab27030SDavid du Colombier 		}else{
54*7ab27030SDavid du Colombier 			c->kidinfo = t;
55*7ab27030SDavid du Colombier 			/* this check shouldn't be necessary, but... */
56*7ab27030SDavid du Colombier 			if(t->src){
57*7ab27030SDavid du Colombier 				rs.r = urlcombine(p->url->act.r, t->src);
58*7ab27030SDavid du Colombier 				rs.nr = runestrlen(rs.r);
59*7ab27030SDavid du Colombier 				pageload1(c, urlalloc(&rs, nil, HGet), FALSE);
60*7ab27030SDavid du Colombier 				closerunestr(&rs);
61*7ab27030SDavid du Colombier 			}
62*7ab27030SDavid du Colombier 		}
63*7ab27030SDavid du Colombier 	}
64*7ab27030SDavid du Colombier }
65*7ab27030SDavid du Colombier 
66*7ab27030SDavid du Colombier static struct {
67*7ab27030SDavid du Colombier 	char *mime;
68*7ab27030SDavid du Colombier 	char *filter;
69*7ab27030SDavid du Colombier }filtertab[] = {
70*7ab27030SDavid du Colombier 	"image/gif",	"gif -t9",
71*7ab27030SDavid du Colombier 	"image/jpeg",	"jpg -t9",
72*7ab27030SDavid du Colombier 	"image/jpg",	"jpg -t9",
73*7ab27030SDavid du Colombier 	"image/pjpeg",	"jpg -t9",
74*7ab27030SDavid du Colombier 	"image/png",	"png -t9",
75*7ab27030SDavid du Colombier 	"image/ppm",	"ppm -t9",
76*7ab27030SDavid du Colombier 	nil,	nil,
77*7ab27030SDavid du Colombier };
78*7ab27030SDavid du Colombier 
79*7ab27030SDavid du Colombier char *
getfilter(Rune * r,int x,int y)80*7ab27030SDavid du Colombier getfilter(Rune *r, int x, int y)
81*7ab27030SDavid du Colombier {
82*7ab27030SDavid du Colombier 	char buf[128];
83*7ab27030SDavid du Colombier 	int i;
84*7ab27030SDavid du Colombier 
85*7ab27030SDavid du Colombier 	snprint(buf, sizeof(buf), "%S", r);
86*7ab27030SDavid du Colombier 	for(i=0; filtertab[i].mime!=nil; i++)
87*7ab27030SDavid du Colombier 		if(cistrncmp(buf, filtertab[i].mime, strlen(filtertab[i].mime)) == 0)
88*7ab27030SDavid du Colombier 			break;
89*7ab27030SDavid du Colombier 
90*7ab27030SDavid du Colombier 	if(filtertab[i].filter == nil)
91*7ab27030SDavid du Colombier 		return nil;
92*7ab27030SDavid du Colombier 
93*7ab27030SDavid du Colombier 	if(x==0 && y==0)
94*7ab27030SDavid du Colombier 		return smprint("%s", filtertab[i].filter);
95*7ab27030SDavid du Colombier 	if(x!=0 && y!=0)
96*7ab27030SDavid du Colombier 		return smprint("%s | resample -x %d -y %d", filtertab[i].filter, x, y);
97*7ab27030SDavid du Colombier 	if(x != 0)
98*7ab27030SDavid du Colombier 		return smprint("%s | resample -x %d", filtertab[i].filter, x);
99*7ab27030SDavid du Colombier 	/* y != 0 */
100*7ab27030SDavid du Colombier 	return smprint("%s | resample -y %d", filtertab[i].filter, y);
101*7ab27030SDavid du Colombier }
102*7ab27030SDavid du Colombier 
103*7ab27030SDavid du Colombier static Cimage *cimages = nil;
104*7ab27030SDavid du Colombier static QLock cimagelock;
105*7ab27030SDavid du Colombier 
106*7ab27030SDavid du Colombier static
107*7ab27030SDavid du Colombier void
freecimage(Cimage * ci)108*7ab27030SDavid du Colombier freecimage(Cimage *ci)
109*7ab27030SDavid du Colombier {
110*7ab27030SDavid du Colombier 	Cimage *ci1;
111*7ab27030SDavid du Colombier 
112*7ab27030SDavid du Colombier 	qlock(&cimagelock);
113*7ab27030SDavid du Colombier 	if(decref(ci) == 0){
114*7ab27030SDavid du Colombier 		if(ci->i)
115*7ab27030SDavid du Colombier 			freeimage(ci->i);
116*7ab27030SDavid du Colombier 		else if(ci->mi)
117*7ab27030SDavid du Colombier 			freememimage(ci->mi);
118*7ab27030SDavid du Colombier 		urlfree(ci->url);
119*7ab27030SDavid du Colombier 		ci1 = cimages;
120*7ab27030SDavid du Colombier 		if(ci1 == ci)
121*7ab27030SDavid du Colombier 			cimages = ci->next;
122*7ab27030SDavid du Colombier 		else{
123*7ab27030SDavid du Colombier 			while(ci1){
124*7ab27030SDavid du Colombier 				if(ci1->next == ci){
125*7ab27030SDavid du Colombier 					ci1->next = ci->next;
126*7ab27030SDavid du Colombier 					break;
127*7ab27030SDavid du Colombier 				}
128*7ab27030SDavid du Colombier 				ci1 = ci1->next;
129*7ab27030SDavid du Colombier 			}
130*7ab27030SDavid du Colombier 		}
131*7ab27030SDavid du Colombier 		free(ci);
132*7ab27030SDavid du Colombier 	}
133*7ab27030SDavid du Colombier 	qunlock(&cimagelock);
134*7ab27030SDavid du Colombier }
135*7ab27030SDavid du Colombier 
136*7ab27030SDavid du Colombier static
137*7ab27030SDavid du Colombier void
closeimages(Page * p)138*7ab27030SDavid du Colombier closeimages(Page *p)
139*7ab27030SDavid du Colombier {
140*7ab27030SDavid du Colombier 	int i;
141*7ab27030SDavid du Colombier 
142*7ab27030SDavid du Colombier 	for(i=0; i<p->ncimage; i++)
143*7ab27030SDavid du Colombier 		freecimage(p->cimage[i]);
144*7ab27030SDavid du Colombier 	free(p->cimage);
145*7ab27030SDavid du Colombier 	p->cimage =nil;
146*7ab27030SDavid du Colombier 	p->ncimage = 0;
147*7ab27030SDavid du Colombier }
148*7ab27030SDavid du Colombier 
149*7ab27030SDavid du Colombier static
150*7ab27030SDavid du Colombier Cimage *
loadimg(Rune * src,int x,int y)151*7ab27030SDavid du Colombier loadimg(Rune *src, int x , int y)
152*7ab27030SDavid du Colombier {
153*7ab27030SDavid du Colombier 	Channel *sync;
154*7ab27030SDavid du Colombier 	Cimage *ci;
155*7ab27030SDavid du Colombier 	Runestr rs;
156*7ab27030SDavid du Colombier 	Exec *e;
157*7ab27030SDavid du Colombier 	char *filter;
158*7ab27030SDavid du Colombier 	int fd, p[2], q[2];
159*7ab27030SDavid du Colombier 
160*7ab27030SDavid du Colombier 	ci = emalloc(sizeof(Cimage));
161*7ab27030SDavid du Colombier 	rs. r = src;
162*7ab27030SDavid du Colombier 	rs.nr = runestrlen(rs.r);
163*7ab27030SDavid du Colombier 	ci->url = urlalloc(&rs, nil, HGet);
164*7ab27030SDavid du Colombier 	fd = urlopen(ci->url);
165*7ab27030SDavid du Colombier 	if(fd < 0){
166*7ab27030SDavid du Colombier     Err1:
167*7ab27030SDavid du Colombier 		return ci;
168*7ab27030SDavid du Colombier 	}
169*7ab27030SDavid du Colombier 	filter = getfilter(ci->url->ctype.r, x, y);
170*7ab27030SDavid du Colombier 	if(filter == nil){
171*7ab27030SDavid du Colombier 		werrstr("%S unsupported: %S", ci->url->ctype.r, ci->url->act.r);
172*7ab27030SDavid du Colombier     Err2:
173*7ab27030SDavid du Colombier 		close(fd);
174*7ab27030SDavid du Colombier 		goto Err1;
175*7ab27030SDavid du Colombier 	}
176*7ab27030SDavid du Colombier 
177*7ab27030SDavid du Colombier 	if(pipe(p)<0 || pipe(q)<0)
178*7ab27030SDavid du Colombier 		error("can't create pipe");
179*7ab27030SDavid du Colombier 	close(p[0]);
180*7ab27030SDavid du Colombier 	p[0] = fd;
181*7ab27030SDavid du Colombier 	sync = chancreate(sizeof(ulong), 0);
182*7ab27030SDavid du Colombier 	if(sync == nil)
183*7ab27030SDavid du Colombier 		error("can't create channel");
184*7ab27030SDavid du Colombier 	e = emalloc(sizeof(Exec));
185*7ab27030SDavid du Colombier 	e->p[0] = p[0];
186*7ab27030SDavid du Colombier 	e->p[1] = p[1];
187*7ab27030SDavid du Colombier 	e->q[0] = q[0];
188*7ab27030SDavid du Colombier 	e->q[1] = q[1];
189*7ab27030SDavid du Colombier 	e->cmd = filter;
190*7ab27030SDavid du Colombier 	e->sync = sync;
191*7ab27030SDavid du Colombier 	proccreate(execproc, e, STACK);
192*7ab27030SDavid du Colombier 	recvul(sync);
193*7ab27030SDavid du Colombier 	chanfree(sync);
194*7ab27030SDavid du Colombier 	close(p[0]);
195*7ab27030SDavid du Colombier 	close(p[1]);
196*7ab27030SDavid du Colombier 	close(q[1]);
197*7ab27030SDavid du Colombier 
198*7ab27030SDavid du Colombier 	ci->mi = readmemimage(q[0]);
199*7ab27030SDavid du Colombier 	close(q[0]);
200*7ab27030SDavid du Colombier 	if(ci->mi == nil){
201*7ab27030SDavid du Colombier 		werrstr("can't read image");
202*7ab27030SDavid du Colombier 		goto Err2;
203*7ab27030SDavid du Colombier 	}
204*7ab27030SDavid du Colombier 	free(filter);
205*7ab27030SDavid du Colombier 	return ci;
206*7ab27030SDavid du Colombier }
207*7ab27030SDavid du Colombier 
208*7ab27030SDavid du Colombier static
209*7ab27030SDavid du Colombier Cimage *
findimg(Rune * s)210*7ab27030SDavid du Colombier findimg(Rune *s)
211*7ab27030SDavid du Colombier {
212*7ab27030SDavid du Colombier 	Cimage *ci;
213*7ab27030SDavid du Colombier 
214*7ab27030SDavid du Colombier 	qlock(&cimagelock);
215*7ab27030SDavid du Colombier 	for(ci=cimages; ci!=nil; ci=ci->next)
216*7ab27030SDavid du Colombier 		if(runestrcmp(ci->url->src.r, s) == 0)
217*7ab27030SDavid du Colombier 			break;
218*7ab27030SDavid du Colombier 
219*7ab27030SDavid du Colombier 	qunlock(&cimagelock);
220*7ab27030SDavid du Colombier 	return ci;
221*7ab27030SDavid du Colombier }
222*7ab27030SDavid du Colombier 
223*7ab27030SDavid du Colombier void
loadimages(Page * p)224*7ab27030SDavid du Colombier loadimages(Page *p)
225*7ab27030SDavid du Colombier {
226*7ab27030SDavid du Colombier 	Cimage *ci;
227*7ab27030SDavid du Colombier 	Iimage *i;
228*7ab27030SDavid du Colombier 	Rune *src;
229*7ab27030SDavid du Colombier 
230*7ab27030SDavid du Colombier 	addrefresh(p, "loading images...");
231*7ab27030SDavid du Colombier 	reverseimages(&p->doc->images);
232*7ab27030SDavid du Colombier 	for(i=p->doc->images; i!=nil; i=i->nextimage){
233*7ab27030SDavid du Colombier 		if(p->aborting)
234*7ab27030SDavid du Colombier 			break;
235*7ab27030SDavid du Colombier 		src = urlcombine(getbase(p), i->imsrc);
236*7ab27030SDavid du Colombier 		ci = findimg(src);
237*7ab27030SDavid du Colombier 		if(ci == nil){
238*7ab27030SDavid du Colombier 			ci = loadimg(src, i->imwidth, i->imheight);
239*7ab27030SDavid du Colombier 			qlock(&cimagelock);
240*7ab27030SDavid du Colombier 			ci->next = cimages;
241*7ab27030SDavid du Colombier 			cimages = ci;
242*7ab27030SDavid du Colombier 			qunlock(&cimagelock);
243*7ab27030SDavid du Colombier 		}
244*7ab27030SDavid du Colombier 		free(src);
245*7ab27030SDavid du Colombier 		incref(ci);
246*7ab27030SDavid du Colombier 		i->aux = ci;
247*7ab27030SDavid du Colombier 		p->cimage = erealloc(p->cimage, ++p->ncimage*sizeof(Cimage *));
248*7ab27030SDavid du Colombier 		p->cimage[p->ncimage-1] = ci;
249*7ab27030SDavid du Colombier 		p->changed = TRUE;
250*7ab27030SDavid du Colombier 		addrefresh(p, "");
251*7ab27030SDavid du Colombier 	}
252*7ab27030SDavid du Colombier }
253*7ab27030SDavid du Colombier 
254*7ab27030SDavid du Colombier static char *mimetab[] = {
255*7ab27030SDavid du Colombier 	"text/html",
256*7ab27030SDavid du Colombier 	"application/xhtml",
257*7ab27030SDavid du Colombier 	nil,
258*7ab27030SDavid du Colombier };
259*7ab27030SDavid du Colombier 
260*7ab27030SDavid du Colombier static
261*7ab27030SDavid du Colombier void
pageloadproc(void * v)262*7ab27030SDavid du Colombier pageloadproc(void *v)
263*7ab27030SDavid du Colombier {
264*7ab27030SDavid du Colombier 	Page *p;
265*7ab27030SDavid du Colombier 	char buf[BUFSIZE], *s;
266*7ab27030SDavid du Colombier 	long n, l;
267*7ab27030SDavid du Colombier 	int fd, i, ctype;
268*7ab27030SDavid du Colombier 
269*7ab27030SDavid du Colombier 	threadsetname("pageloadproc");
270*7ab27030SDavid du Colombier 	rfork(RFFDG);
271*7ab27030SDavid du Colombier 
272*7ab27030SDavid du Colombier 	p = v;
273*7ab27030SDavid du Colombier 	addrefresh(p, "opening: %S...", p->url->src.r);
274*7ab27030SDavid du Colombier 	fd = urlopen(p->url);
275*7ab27030SDavid du Colombier 	if(fd < 0){
276*7ab27030SDavid du Colombier 		addrefresh(p, "%S: %r", p->url->src.r);
277*7ab27030SDavid du Colombier     Err:
278*7ab27030SDavid du Colombier 		p->loading = FALSE;
279*7ab27030SDavid du Colombier 		return;
280*7ab27030SDavid du Colombier 	}
281*7ab27030SDavid du Colombier 	if(runestrlen(p->url->ctype.r) == 0) /* assume .html when headers don't say anyting */
282*7ab27030SDavid du Colombier 		goto Html;
283*7ab27030SDavid du Colombier 
284*7ab27030SDavid du Colombier 	snprint(buf, sizeof(buf), "%S", p->url->ctype.r);
285*7ab27030SDavid du Colombier 	for(i=0; mimetab[i]!=nil; i++)
286*7ab27030SDavid du Colombier 		if(cistrncmp(buf, mimetab[i], strlen(mimetab[i])) == 0)
287*7ab27030SDavid du Colombier 			break;
288*7ab27030SDavid du Colombier 
289*7ab27030SDavid du Colombier 	if(mimetab[i]){
290*7ab27030SDavid du Colombier     Html:
291*7ab27030SDavid du Colombier 		ctype = TextHtml;
292*7ab27030SDavid du Colombier 	}else if(cistrncmp(buf, "text/", 5) == 0)
293*7ab27030SDavid du Colombier 		ctype = TextPlain;
294*7ab27030SDavid du Colombier 	else{
295*7ab27030SDavid du Colombier 		close(fd);
296*7ab27030SDavid du Colombier 		addrefresh(p, "%S: unsupported mime type: '%S'", p->url->act.r, p->url->ctype.r);
297*7ab27030SDavid du Colombier 		goto Err;
298*7ab27030SDavid du Colombier 	}
299*7ab27030SDavid du Colombier 	addrefresh(p, "loading: %S...", p->url->src.r);
300*7ab27030SDavid du Colombier 	s = nil;
301*7ab27030SDavid du Colombier 	l = 0;
302*7ab27030SDavid du Colombier 	while((n=read(fd, buf, sizeof(buf))) > 0){
303*7ab27030SDavid du Colombier 		if(p->aborting){
304*7ab27030SDavid du Colombier 			if(s){
305*7ab27030SDavid du Colombier 				free(s);
306*7ab27030SDavid du Colombier 				s = nil;
307*7ab27030SDavid du Colombier 			}
308*7ab27030SDavid du Colombier 			break;
309*7ab27030SDavid du Colombier 		}
310*7ab27030SDavid du Colombier 		s = erealloc(s, l+n+1);
311*7ab27030SDavid du Colombier 		memmove(s+l, buf, n);
312*7ab27030SDavid du Colombier 		l += n;
313*7ab27030SDavid du Colombier 		s[l] = '\0';
314*7ab27030SDavid du Colombier 	}
315*7ab27030SDavid du Colombier 	close(fd);
316*7ab27030SDavid du Colombier 	n = l;
317*7ab27030SDavid du Colombier 	if(s){
318*7ab27030SDavid du Colombier 		s = convert(p->url->ctype, s, &n);
319*7ab27030SDavid du Colombier 		p->items = parsehtml((uchar *)s, n, p->url->act.r, ctype, UTF_8, &p->doc);
320*7ab27030SDavid du Colombier 		free(s);
321*7ab27030SDavid du Colombier 		fixtext(p);
322*7ab27030SDavid du Colombier 		if(ctype==TextHtml && p->aborting==FALSE){
323*7ab27030SDavid du Colombier 			p->changed = TRUE;
324*7ab27030SDavid du Colombier 			addrefresh(p, "");
325*7ab27030SDavid du Colombier 			if(p->doc->doctitle){
326*7ab27030SDavid du Colombier 				p->title.r = erunestrdup(p->doc->doctitle);
327*7ab27030SDavid du Colombier 				p->title.nr = runestrlen(p->title.r);
328*7ab27030SDavid du Colombier 			}
329*7ab27030SDavid du Colombier 			p->loading = XXX;
330*7ab27030SDavid du Colombier 			if(p->doc->kidinfo)
331*7ab27030SDavid du Colombier 				loadchilds(p, p->doc->kidinfo);
332*7ab27030SDavid du Colombier 			else if(p->doc->images)
333*7ab27030SDavid du Colombier 				loadimages(p);
334*7ab27030SDavid du Colombier 		}
335*7ab27030SDavid du Colombier 	}
336*7ab27030SDavid du Colombier 	p->changed = TRUE;
337*7ab27030SDavid du Colombier 	p->loading = FALSE;
338*7ab27030SDavid du Colombier 	addrefresh(p, "");
339*7ab27030SDavid du Colombier }
340*7ab27030SDavid du Colombier 
341*7ab27030SDavid du Colombier static
342*7ab27030SDavid du Colombier void
pageload1(Page * p,Url * u,int dohist)343*7ab27030SDavid du Colombier pageload1(Page *p, Url *u, int dohist)
344*7ab27030SDavid du Colombier {
345*7ab27030SDavid du Colombier 	pageclose(p);
346*7ab27030SDavid du Colombier 	p->loading = TRUE;
347*7ab27030SDavid du Colombier 	p->url = u;
348*7ab27030SDavid du Colombier 	if(dohist)
349*7ab27030SDavid du Colombier 		winaddhist(p->w, p->url);
350*7ab27030SDavid du Colombier 	proccreate(pageloadproc, p, STACK);
351*7ab27030SDavid du Colombier }
352*7ab27030SDavid du Colombier 
353*7ab27030SDavid du Colombier void
pageload(Page * p,Url * u,int dohist)354*7ab27030SDavid du Colombier pageload(Page *p, Url *u, int dohist)
355*7ab27030SDavid du Colombier {
356*7ab27030SDavid du Colombier 	if(p->parent == nil)
357*7ab27030SDavid du Colombier 		textset(&p->w->url, u->src.r, u->src.nr);
358*7ab27030SDavid du Colombier 	draw(p->b, p->all, display->white, nil, ZP);
359*7ab27030SDavid du Colombier 	pageload1(p, u, dohist);
360*7ab27030SDavid du Colombier }
361*7ab27030SDavid du Colombier 
362*7ab27030SDavid du Colombier void
pageget(Page * p,Runestr * src,Runestr * post,int m,int dohist)363*7ab27030SDavid du Colombier pageget(Page *p, Runestr *src, Runestr *post,  int m, int dohist)
364*7ab27030SDavid du Colombier {
365*7ab27030SDavid du Colombier 	pageload(p, urlalloc(src, post, m), dohist);
366*7ab27030SDavid du Colombier }
367*7ab27030SDavid du Colombier 
368*7ab27030SDavid du Colombier void
pageclose(Page * p)369*7ab27030SDavid du Colombier pageclose(Page *p)
370*7ab27030SDavid du Colombier {
371*7ab27030SDavid du Colombier 	Page *c, *nc;
372*7ab27030SDavid du Colombier 
373*7ab27030SDavid du Colombier 	if(p == selpage)
374*7ab27030SDavid du Colombier 		selpage = nil;
375*7ab27030SDavid du Colombier 	pageabort(p);
376*7ab27030SDavid du Colombier 	closeimages(p);
377*7ab27030SDavid du Colombier 	urlfree(p->url);
378*7ab27030SDavid du Colombier 	p->url = nil;
379*7ab27030SDavid du Colombier 	if(p->doc){
380*7ab27030SDavid du Colombier 		freedocinfo(p->doc);
381*7ab27030SDavid du Colombier 		p->doc = nil;
382*7ab27030SDavid du Colombier 	}
383*7ab27030SDavid du Colombier 	layfree(p->lay);
384*7ab27030SDavid du Colombier 	p->lay = nil;
385*7ab27030SDavid du Colombier 	freeitems(p->items);
386*7ab27030SDavid du Colombier 	p->items = nil;
387*7ab27030SDavid du Colombier 	for(c=p->child; c!=nil; c=nc){
388*7ab27030SDavid du Colombier 		nc = c->next;
389*7ab27030SDavid du Colombier 		pageclose(c);
390*7ab27030SDavid du Colombier 		free(c);
391*7ab27030SDavid du Colombier 	}
392*7ab27030SDavid du Colombier 	p->child = nil;
393*7ab27030SDavid du Colombier 	closerunestr(&p->title);
394*7ab27030SDavid du Colombier 	closerunestr(&p->refresh.rs);
395*7ab27030SDavid du Colombier 	p->refresh.t = 0;
396*7ab27030SDavid du Colombier 	p->pos = ZP;
397*7ab27030SDavid du Colombier 	p->top = ZP;
398*7ab27030SDavid du Colombier 	p->bot = ZP;
399*7ab27030SDavid du Colombier 	p->loading = p->aborting = FALSE;
400*7ab27030SDavid du Colombier }
401*7ab27030SDavid du Colombier 
402*7ab27030SDavid du Colombier int
pageabort(Page * p)403*7ab27030SDavid du Colombier pageabort(Page *p)
404*7ab27030SDavid du Colombier {
405*7ab27030SDavid du Colombier 	Page *c;
406*7ab27030SDavid du Colombier 
407*7ab27030SDavid du Colombier 	for(c=p->child; c!=nil; c=c->next)
408*7ab27030SDavid du Colombier 		pageabort(c);
409*7ab27030SDavid du Colombier 
410*7ab27030SDavid du Colombier 	p->aborting = TRUE;
411*7ab27030SDavid du Colombier 	while(p->loading)
412*7ab27030SDavid du Colombier 		sleep(100);
413*7ab27030SDavid du Colombier 
414*7ab27030SDavid du Colombier 	p->aborting = FALSE;
415*7ab27030SDavid du Colombier 	return TRUE;
416*7ab27030SDavid du Colombier }
417*7ab27030SDavid du Colombier 
418*7ab27030SDavid du Colombier 
419*7ab27030SDavid du Colombier static Image *tmp;
420*7ab27030SDavid du Colombier 
421*7ab27030SDavid du Colombier void
tmpresize(void)422*7ab27030SDavid du Colombier tmpresize(void)
423*7ab27030SDavid du Colombier {
424*7ab27030SDavid du Colombier 	if(tmp)
425*7ab27030SDavid du Colombier 		freeimage(tmp);
426*7ab27030SDavid du Colombier 
427*7ab27030SDavid du Colombier 	tmp = eallocimage(display, Rect(0,0,Dx(screen->r),Dy(screen->r)), screen->chan, 0, -1);
428*7ab27030SDavid du Colombier }
429*7ab27030SDavid du Colombier 
430*7ab27030SDavid du Colombier static
431*7ab27030SDavid du Colombier void
renderchilds(Page * p)432*7ab27030SDavid du Colombier renderchilds(Page *p)
433*7ab27030SDavid du Colombier {
434*7ab27030SDavid du Colombier 	Rectangle r;
435*7ab27030SDavid du Colombier 	Kidinfo *k;
436*7ab27030SDavid du Colombier 	Page *c;
437*7ab27030SDavid du Colombier 	int i, j, x, y, *w, *h;
438*7ab27030SDavid du Colombier 
439*7ab27030SDavid du Colombier 	draw(p->b, p->all, display->white, nil, ZP);
440*7ab27030SDavid du Colombier 	r = p->all;
441*7ab27030SDavid du Colombier 	y = r.min.y;
442*7ab27030SDavid du Colombier 	c = p->child;
443*7ab27030SDavid du Colombier 	k = p->kidinfo;
444*7ab27030SDavid du Colombier 	frdims(k->rows, k->nrows, Dy(r), &h);
445*7ab27030SDavid du Colombier 	frdims(k->cols, k->ncols, Dx(r), &w);
446*7ab27030SDavid du Colombier 	for(i=0; i<k->nrows; i++){
447*7ab27030SDavid du Colombier 		x = r.min.x;
448*7ab27030SDavid du Colombier 		for(j=0; j<k->ncols; j++){
449*7ab27030SDavid du Colombier 			if(c->aborting)
450*7ab27030SDavid du Colombier 				return;
451*7ab27030SDavid du Colombier 			c->b = p->b;
452*7ab27030SDavid du Colombier 			c->all = Rect(x,y,x+w[j],y+h[i]);
453*7ab27030SDavid du Colombier 			c->w = p->w;
454*7ab27030SDavid du Colombier 			pagerender(c);
455*7ab27030SDavid du Colombier 			c = c->next;
456*7ab27030SDavid du Colombier 			x += w[j];
457*7ab27030SDavid du Colombier 		}
458*7ab27030SDavid du Colombier 		y += h[i];
459*7ab27030SDavid du Colombier 	}
460*7ab27030SDavid du Colombier 	free(w);
461*7ab27030SDavid du Colombier 	free(h);
462*7ab27030SDavid du Colombier }
463*7ab27030SDavid du Colombier 
464*7ab27030SDavid du Colombier static
465*7ab27030SDavid du Colombier void
pagerender1(Page * p)466*7ab27030SDavid du Colombier pagerender1(Page *p)
467*7ab27030SDavid du Colombier {
468*7ab27030SDavid du Colombier 	Rectangle r;
469*7ab27030SDavid du Colombier 
470*7ab27030SDavid du Colombier 	r = p->all;
471*7ab27030SDavid du Colombier 	p->hscrollr = r;
472*7ab27030SDavid du Colombier 	p->hscrollr.min.y = r.max.y-Scrollsize;
473*7ab27030SDavid du Colombier 	p->vscrollr = r;
474*7ab27030SDavid du Colombier 	p->vscrollr.max.x = r.min.x+Scrollsize;
475*7ab27030SDavid du Colombier 	r.max.y -= Scrollsize;
476*7ab27030SDavid du Colombier 	r.min.x += Scrollsize;
477*7ab27030SDavid du Colombier 	p->r = r;
478*7ab27030SDavid du Colombier 	p->vscrollr.max.y = r.max.y;
479*7ab27030SDavid du Colombier 	p->hscrollr.min.x = r.min.x;
480*7ab27030SDavid du Colombier 	laypage(p);
481*7ab27030SDavid du Colombier 	pageredraw(p);
482*7ab27030SDavid du Colombier }
483*7ab27030SDavid du Colombier 
484*7ab27030SDavid du Colombier void
pagerender(Page * p)485*7ab27030SDavid du Colombier pagerender(Page *p)
486*7ab27030SDavid du Colombier {
487*7ab27030SDavid du Colombier 	if(p->child && p->loading==FALSE)
488*7ab27030SDavid du Colombier 		renderchilds(p);
489*7ab27030SDavid du Colombier 	else if(p->doc)
490*7ab27030SDavid du Colombier 		pagerender1(p);
491*7ab27030SDavid du Colombier }
492*7ab27030SDavid du Colombier 
493*7ab27030SDavid du Colombier void
pageredraw(Page * p)494*7ab27030SDavid du Colombier pageredraw(Page *p)
495*7ab27030SDavid du Colombier {
496*7ab27030SDavid du Colombier 	Rectangle r;
497*7ab27030SDavid du Colombier 
498*7ab27030SDavid du Colombier 	r = p->lay->r;
499*7ab27030SDavid du Colombier 	if(Dx(r)==0 || Dy(r)==0){
500*7ab27030SDavid du Colombier 		draw(p->b, p->r, display->white, nil, ZP);
501*7ab27030SDavid du Colombier 		return;
502*7ab27030SDavid du Colombier 	}
503*7ab27030SDavid du Colombier 	if(tmp == nil)
504*7ab27030SDavid du Colombier 		tmpresize();
505*7ab27030SDavid du Colombier 
506*7ab27030SDavid du Colombier 	p->selecting = FALSE;
507*7ab27030SDavid du Colombier 	draw(tmp, tmp->r, getbg(p), nil, ZP);
508*7ab27030SDavid du Colombier 	laydraw(p, tmp, p->lay);
509*7ab27030SDavid du Colombier 	draw(p->b, p->r, tmp, nil, tmp->r.min);
510*7ab27030SDavid du Colombier 	r = p->vscrollr;
511*7ab27030SDavid du Colombier 	r.min.y = r.max.y;
512*7ab27030SDavid du Colombier 	r.max.y += Scrollsize;
513*7ab27030SDavid du Colombier 	draw(p->b, r, tagcols[HIGH], nil, ZP);
514*7ab27030SDavid du Colombier 	draw(p->b, insetrect(r, 1), tagcols[BACK], nil, ZP);
515*7ab27030SDavid du Colombier 	pagescrldraw(p);
516*7ab27030SDavid du Colombier }
517*7ab27030SDavid du Colombier 
518*7ab27030SDavid du Colombier static
519*7ab27030SDavid du Colombier void
pageselect1(Page * p)520*7ab27030SDavid du Colombier pageselect1(Page *p)	/* when called, button 1 is down */
521*7ab27030SDavid du Colombier {
522*7ab27030SDavid du Colombier 	Point mp, npos, opos;
523*7ab27030SDavid du Colombier 	int b, scrled, x, y;
524*7ab27030SDavid du Colombier 
525*7ab27030SDavid du Colombier 	b = mouse->buttons;
526*7ab27030SDavid du Colombier 	mp = mousectl->xy;
527*7ab27030SDavid du Colombier 	opos = getpt(p, mp);
528*7ab27030SDavid du Colombier 	do{
529*7ab27030SDavid du Colombier 		x = y = 0;
530*7ab27030SDavid du Colombier 		if(mp.x < p->r.min.x)
531*7ab27030SDavid du Colombier 			x -= p->r.min.x-mp.x;
532*7ab27030SDavid du Colombier 		else if(mp.x > p->r.max.x)
533*7ab27030SDavid du Colombier 			x += mp.x-p->r.max.x;
534*7ab27030SDavid du Colombier 		if(mp.y < p->r.min.y)
535*7ab27030SDavid du Colombier 			y -= (p->r.min.y-mp.y)*Panspeed;
536*7ab27030SDavid du Colombier 		else if(mp.y > p->r.max.y)
537*7ab27030SDavid du Colombier 			y += (mp.y-p->r.max.y)*Panspeed;
538*7ab27030SDavid du Colombier 
539*7ab27030SDavid du Colombier 		scrled = pagescrollxy(p, x, y);
540*7ab27030SDavid du Colombier 		npos = getpt(p, mp);
541*7ab27030SDavid du Colombier 		if(opos.y <  npos.y){
542*7ab27030SDavid du Colombier 			p->top = opos;
543*7ab27030SDavid du Colombier 			p->bot = npos;
544*7ab27030SDavid du Colombier 		}else{
545*7ab27030SDavid du Colombier 			p->top = npos;
546*7ab27030SDavid du Colombier 			p->bot = opos;
547*7ab27030SDavid du Colombier 		}
548*7ab27030SDavid du Colombier 		pageredraw(p);
549*7ab27030SDavid du Colombier 		if(scrled == TRUE)
550*7ab27030SDavid du Colombier 			scrsleep(100);
551*7ab27030SDavid du Colombier 		else
552*7ab27030SDavid du Colombier 			readmouse(mousectl);
553*7ab27030SDavid du Colombier 
554*7ab27030SDavid du Colombier 		mp = mousectl->xy;
555*7ab27030SDavid du Colombier 	}while(mousectl->buttons == b);
556*7ab27030SDavid du Colombier }
557*7ab27030SDavid du Colombier 
558*7ab27030SDavid du Colombier static Rune left1[] =  { L'{', L'[', L'(', L'<', L'«', 0 };
559*7ab27030SDavid du Colombier static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };
560*7ab27030SDavid du Colombier static Rune left2[] =  { L'\'', L'"', L'`', 0 };
561*7ab27030SDavid du Colombier 
562*7ab27030SDavid du Colombier static
563*7ab27030SDavid du Colombier Rune *left[] = {
564*7ab27030SDavid du Colombier 	left1,
565*7ab27030SDavid du Colombier 	left2,
566*7ab27030SDavid du Colombier 	nil
567*7ab27030SDavid du Colombier };
568*7ab27030SDavid du Colombier static
569*7ab27030SDavid du Colombier Rune *right[] = {
570*7ab27030SDavid du Colombier 	right1,
571*7ab27030SDavid du Colombier 	left2,
572*7ab27030SDavid du Colombier 	nil
573*7ab27030SDavid du Colombier };
574*7ab27030SDavid du Colombier 
575*7ab27030SDavid du Colombier void
pagedoubleclick(Page * p)576*7ab27030SDavid du Colombier pagedoubleclick(Page *p)
577*7ab27030SDavid du Colombier {
578*7ab27030SDavid du Colombier 	Point xy;
579*7ab27030SDavid du Colombier 	Line *l;
580*7ab27030SDavid du Colombier 	Box *b;
581*7ab27030SDavid du Colombier 
582*7ab27030SDavid du Colombier 	xy = getpt(p, mouse->xy);
583*7ab27030SDavid du Colombier 	l = linewhich(p->lay, xy);
584*7ab27030SDavid du Colombier 	if(l==nil || l->hastext==FALSE)
585*7ab27030SDavid du Colombier 		return;
586*7ab27030SDavid du Colombier 
587*7ab27030SDavid du Colombier 	if(xy.x<l->boxes->r.min.x && hasbrk(l->state)){	/* beginning of line? */
588*7ab27030SDavid du Colombier 		p->top = l->boxes->r.min;
589*7ab27030SDavid du Colombier 		if(l->next && !hasbrk(l->next->state)){
590*7ab27030SDavid du Colombier 			for(l=l->next; l->next!=nil; l=l->next)
591*7ab27030SDavid du Colombier 				if(hasbrk(l->next->state))
592*7ab27030SDavid du Colombier 					break;
593*7ab27030SDavid du Colombier 		}
594*7ab27030SDavid du Colombier 		p->bot = l->lastbox->r.max;;
595*7ab27030SDavid du Colombier 	}else if(xy.x>l->lastbox->r.max.x && hasbrk(l->next->state)){	/* end of line? */
596*7ab27030SDavid du Colombier 		p->bot = l->lastbox->r.max;
597*7ab27030SDavid du Colombier 		if(!hasbrk(l->state) && l->prev!=nil){
598*7ab27030SDavid du Colombier 			for(l=l->prev; l->prev!=nil; l=l->prev)
599*7ab27030SDavid du Colombier 				if(hasbrk(l->state))
600*7ab27030SDavid du Colombier 					break;
601*7ab27030SDavid du Colombier 		}
602*7ab27030SDavid du Colombier 		p->top = l->boxes->r.min;
603*7ab27030SDavid du Colombier 	}else{
604*7ab27030SDavid du Colombier 		b = pttobox(l, xy);
605*7ab27030SDavid du Colombier 		if(b!=nil && b->i->tag==Itexttag){
606*7ab27030SDavid du Colombier 			p->top = b->r.min;
607*7ab27030SDavid du Colombier 			p->bot = b->r.max;
608*7ab27030SDavid du Colombier 		}
609*7ab27030SDavid du Colombier 	}
610*7ab27030SDavid du Colombier 	p->top.y += 2;
611*7ab27030SDavid du Colombier 	p->bot.y -= 2;
612*7ab27030SDavid du Colombier 	pageredraw(p);
613*7ab27030SDavid du Colombier }
614*7ab27030SDavid du Colombier 
615*7ab27030SDavid du Colombier static uint clickmsec;
616*7ab27030SDavid du Colombier 
617*7ab27030SDavid du Colombier void
pageselect(Page * p)618*7ab27030SDavid du Colombier pageselect(Page *p)
619*7ab27030SDavid du Colombier {
620*7ab27030SDavid du Colombier 	int b, x, y;
621*7ab27030SDavid du Colombier 
622*7ab27030SDavid du Colombier 
623*7ab27030SDavid du Colombier 	selpage = p;
624*7ab27030SDavid du Colombier 	/*
625*7ab27030SDavid du Colombier 	 * To have double-clicking and chording, we double-click
626*7ab27030SDavid du Colombier 	 * immediately if it might make sense.
627*7ab27030SDavid du Colombier 	 */
628*7ab27030SDavid du Colombier 	b = mouse->buttons;
629*7ab27030SDavid du Colombier 	if(mouse->msec-clickmsec<500){
630*7ab27030SDavid du Colombier 		pagedoubleclick(p);
631*7ab27030SDavid du Colombier 		x = mouse->xy.x;
632*7ab27030SDavid du Colombier 		y = mouse->xy.y;
633*7ab27030SDavid du Colombier 		/* stay here until something interesting happens */
634*7ab27030SDavid du Colombier 		do
635*7ab27030SDavid du Colombier 			readmouse(mousectl);
636*7ab27030SDavid du Colombier 		while(mouse->buttons==b && abs(mouse->xy.x-x)<3 && abs(mouse->xy.y-y)<3);
637*7ab27030SDavid du Colombier 		mouse->xy.x = x;	/* in case we're calling pageselect1 */
638*7ab27030SDavid du Colombier 		mouse->xy.y = y;
639*7ab27030SDavid du Colombier 	}
640*7ab27030SDavid du Colombier 	if(mousectl->buttons == b)
641*7ab27030SDavid du Colombier 		pageselect1(p);
642*7ab27030SDavid du Colombier 
643*7ab27030SDavid du Colombier 	if(eqpt(p->top, p->bot)){
644*7ab27030SDavid du Colombier 		if(mouse->msec-clickmsec<500)
645*7ab27030SDavid du Colombier 			pagedoubleclick(p);
646*7ab27030SDavid du Colombier 		else
647*7ab27030SDavid du Colombier 			clickmsec = mouse->msec;
648*7ab27030SDavid du Colombier 	}
649*7ab27030SDavid du Colombier 	while(mouse->buttons){
650*7ab27030SDavid du Colombier 		mouse->msec = 0;
651*7ab27030SDavid du Colombier 		b = mouse->buttons;
652*7ab27030SDavid du Colombier 		if(b & 2)	/* snarf only */
653*7ab27030SDavid du Colombier 			cut(nil, nil, TRUE, FALSE, nil, 0);
654*7ab27030SDavid du Colombier 		while(mouse->buttons == b)
655*7ab27030SDavid du Colombier 			readmouse(mousectl);
656*7ab27030SDavid du Colombier 	}
657*7ab27030SDavid du Colombier }
658*7ab27030SDavid du Colombier 
659*7ab27030SDavid du Colombier Page *
pagewhich(Page * p,Point xy)660*7ab27030SDavid du Colombier pagewhich(Page *p, Point xy)
661*7ab27030SDavid du Colombier {
662*7ab27030SDavid du Colombier 	Page *c;
663*7ab27030SDavid du Colombier 
664*7ab27030SDavid du Colombier 	if(p->child == nil)
665*7ab27030SDavid du Colombier 		return p;
666*7ab27030SDavid du Colombier 
667*7ab27030SDavid du Colombier 	for(c=p->child; c!=nil; c=c->next)
668*7ab27030SDavid du Colombier 		if(ptinrect(xy, c->all))
669*7ab27030SDavid du Colombier 			return pagewhich(c, xy);
670*7ab27030SDavid du Colombier 
671*7ab27030SDavid du Colombier 	return nil;
672*7ab27030SDavid du Colombier }
673*7ab27030SDavid du Colombier 
674*7ab27030SDavid du Colombier void
pagemouse(Page * p,Point xy,int but)675*7ab27030SDavid du Colombier pagemouse(Page *p, Point xy, int but)
676*7ab27030SDavid du Colombier {
677*7ab27030SDavid du Colombier 	Box *b;
678*7ab27030SDavid du Colombier 
679*7ab27030SDavid du Colombier 	p = pagewhich(p, xy);
680*7ab27030SDavid du Colombier 	if(p == nil)
681*7ab27030SDavid du Colombier 		return;
682*7ab27030SDavid du Colombier 
683*7ab27030SDavid du Colombier 	if(pagerefresh(p))
684*7ab27030SDavid du Colombier 		return;
685*7ab27030SDavid du Colombier 
686*7ab27030SDavid du Colombier 	if(p->lay == nil)
687*7ab27030SDavid du Colombier 		return;
688*7ab27030SDavid du Colombier 
689*7ab27030SDavid du Colombier 	if(ptinrect(xy, p->vscrollr)){
690*7ab27030SDavid du Colombier 		pagescroll(p, but, FALSE);
691*7ab27030SDavid du Colombier 		return;
692*7ab27030SDavid du Colombier 	}
693*7ab27030SDavid du Colombier 	if(ptinrect(xy, p->hscrollr)){
694*7ab27030SDavid du Colombier 		pagescroll(p, but, TRUE);
695*7ab27030SDavid du Colombier 		return;
696*7ab27030SDavid du Colombier 	}
697*7ab27030SDavid du Colombier 	xy = getpt(p, xy);
698*7ab27030SDavid du Colombier 	b = boxwhich(p->lay, xy);
699*7ab27030SDavid du Colombier 	if(b && b->mouse)
700*7ab27030SDavid du Colombier 		b->mouse(b, p, but);
701*7ab27030SDavid du Colombier 	else if(but == 1)
702*7ab27030SDavid du Colombier 		pageselect(p);
703*7ab27030SDavid du Colombier }
704*7ab27030SDavid du Colombier 
705*7ab27030SDavid du Colombier void
pagetype(Page * p,Rune r,Point xy)706*7ab27030SDavid du Colombier pagetype(Page *p, Rune r, Point xy)
707*7ab27030SDavid du Colombier {
708*7ab27030SDavid du Colombier 	Box *b;
709*7ab27030SDavid du Colombier 	int x, y;
710*7ab27030SDavid du Colombier 
711*7ab27030SDavid du Colombier 	p = pagewhich(p, xy);
712*7ab27030SDavid du Colombier 	if(p == nil)
713*7ab27030SDavid du Colombier 		return;
714*7ab27030SDavid du Colombier 
715*7ab27030SDavid du Colombier 	if(pagerefresh(p))
716*7ab27030SDavid du Colombier 		return;
717*7ab27030SDavid du Colombier 
718*7ab27030SDavid du Colombier 	if(p->lay == nil)
719*7ab27030SDavid du Colombier 		return;
720*7ab27030SDavid du Colombier 
721*7ab27030SDavid du Colombier 	/* text field? */
722*7ab27030SDavid du Colombier 	xy = getpt(p, xy);
723*7ab27030SDavid du Colombier 	b = boxwhich(p->lay, xy);
724*7ab27030SDavid du Colombier 	if(b && b->key){
725*7ab27030SDavid du Colombier 		b->key(b, p, r);
726*7ab27030SDavid du Colombier 		return;
727*7ab27030SDavid du Colombier 	}
728*7ab27030SDavid du Colombier 	/* ^H: same as 'Back' */
729*7ab27030SDavid du Colombier 	if(r == 0x08){
730*7ab27030SDavid du Colombier 		wingohist(p->w, FALSE);
731*7ab27030SDavid du Colombier 		return;
732*7ab27030SDavid du Colombier 	}
733*7ab27030SDavid du Colombier 
734*7ab27030SDavid du Colombier 	x = 0;
735*7ab27030SDavid du Colombier 	y = 0;
736*7ab27030SDavid du Colombier 	switch(r){
737*7ab27030SDavid du Colombier 	case Kleft:
738*7ab27030SDavid du Colombier 		x -= Dx(p->r)/2;
739*7ab27030SDavid du Colombier 		break;
740*7ab27030SDavid du Colombier 	case Kright:
741*7ab27030SDavid du Colombier 		x += Dx(p->r)/2;
742*7ab27030SDavid du Colombier 		break;
743*7ab27030SDavid du Colombier 	case Kdown:
744*7ab27030SDavid du Colombier 	case Kscrollonedown:
745*7ab27030SDavid du Colombier 		y += Dy(p->r)/2;
746*7ab27030SDavid du Colombier 		break;
747*7ab27030SDavid du Colombier 	case Kpgdown:
748*7ab27030SDavid du Colombier 		y += Dy(p->r);
749*7ab27030SDavid du Colombier 		break;
750*7ab27030SDavid du Colombier 	case Kup:
751*7ab27030SDavid du Colombier 	case Kscrolloneup:
752*7ab27030SDavid du Colombier 		y -= Dy(p->r)/2;
753*7ab27030SDavid du Colombier 		break;
754*7ab27030SDavid du Colombier 	case Kpgup:
755*7ab27030SDavid du Colombier 		y -= Dy(p->r);
756*7ab27030SDavid du Colombier 		break;
757*7ab27030SDavid du Colombier 	case Khome:
758*7ab27030SDavid du Colombier 		y -= Dy(p->lay->r);	/* force p->pos.y = 0 */
759*7ab27030SDavid du Colombier 		break;
760*7ab27030SDavid du Colombier 	case Kend:
761*7ab27030SDavid du Colombier 		y = Dy(p->lay->r) - Dy(p->r);
762*7ab27030SDavid du Colombier 		break;
763*7ab27030SDavid du Colombier 	default:
764*7ab27030SDavid du Colombier 		return;
765*7ab27030SDavid du Colombier 	}
766*7ab27030SDavid du Colombier 	if(pagescrollxy(p, x, y))
767*7ab27030SDavid du Colombier 		pageredraw(p);
768*7ab27030SDavid du Colombier }
769*7ab27030SDavid du Colombier 
770*7ab27030SDavid du Colombier void
pagesnarf(Page * p)771*7ab27030SDavid du Colombier pagesnarf(Page *p)
772*7ab27030SDavid du Colombier {
773*7ab27030SDavid du Colombier 	Runestr rs;
774*7ab27030SDavid du Colombier 
775*7ab27030SDavid du Colombier 	memset(&rs, 0, sizeof(Runestr));
776*7ab27030SDavid du Colombier 	laysnarf(p, p->lay, &rs);
777*7ab27030SDavid du Colombier 	putsnarf(&rs);
778*7ab27030SDavid du Colombier 	closerunestr(&rs);
779*7ab27030SDavid du Colombier }
780*7ab27030SDavid du Colombier 
781*7ab27030SDavid du Colombier void
pagesetrefresh(Page * p)782*7ab27030SDavid du Colombier pagesetrefresh(Page *p)
783*7ab27030SDavid du Colombier {
784*7ab27030SDavid du Colombier 	Runestr rs;
785*7ab27030SDavid du Colombier 	Rune *s, *q, *t;
786*7ab27030SDavid du Colombier 	char *v;
787*7ab27030SDavid du Colombier 	int n;
788*7ab27030SDavid du Colombier 
789*7ab27030SDavid du Colombier 	if(!p->doc || !p->doc->refresh)
790*7ab27030SDavid du Colombier 		return;
791*7ab27030SDavid du Colombier 
792*7ab27030SDavid du Colombier 	s = p->doc->refresh;
793*7ab27030SDavid du Colombier 	q = runestrchr(s, L'=');
794*7ab27030SDavid du Colombier 	if(q == nil)
795*7ab27030SDavid du Colombier 		return;
796*7ab27030SDavid du Colombier 	q++;
797*7ab27030SDavid du Colombier 	if(!q)
798*7ab27030SDavid du Colombier 		return;
799*7ab27030SDavid du Colombier 	n = runestrlen(q);
800*7ab27030SDavid du Colombier 	if(*q == L'''){
801*7ab27030SDavid du Colombier 		q++;
802*7ab27030SDavid du Colombier 		n -= 2;
803*7ab27030SDavid du Colombier 	}
804*7ab27030SDavid du Colombier 	if(n <= 0)
805*7ab27030SDavid du Colombier 		return;
806*7ab27030SDavid du Colombier 	t = runesmprint("%.*S", n, q);
807*7ab27030SDavid du Colombier 	rs.r = urlcombine(getbase(p), t);
808*7ab27030SDavid du Colombier 	rs.nr = runestrlen(rs.r);
809*7ab27030SDavid du Colombier 	copyrunestr(&p->refresh.rs, &rs);
810*7ab27030SDavid du Colombier 	closerunestr(&rs);
811*7ab27030SDavid du Colombier 	free(t);
812*7ab27030SDavid du Colombier 
813*7ab27030SDavid du Colombier 	/* now the time */
814*7ab27030SDavid du Colombier 	q = runestrchr(s, L';');
815*7ab27030SDavid du Colombier 	if(q){
816*7ab27030SDavid du Colombier 		v = smprint("%.*S", (int)(q-s),  s);
817*7ab27030SDavid du Colombier 		p->refresh.t = atoi(v);
818*7ab27030SDavid du Colombier 		free(v);
819*7ab27030SDavid du Colombier 	}else
820*7ab27030SDavid du Colombier 		p->refresh.t = 1;
821*7ab27030SDavid du Colombier 
822*7ab27030SDavid du Colombier 	p->refresh.t += time(0);
823*7ab27030SDavid du Colombier }
824*7ab27030SDavid du Colombier 
825*7ab27030SDavid du Colombier int
826*7ab27030SDavid du Colombier pagerefresh(Page *p)
827*7ab27030SDavid du Colombier {
828*7ab27030SDavid du Colombier 	int t;
829*7ab27030SDavid du Colombier 
830*7ab27030SDavid du Colombier 	if(!p->refresh.t)
831*7ab27030SDavid du Colombier 		return 0;
832*7ab27030SDavid du Colombier 
833*7ab27030SDavid du Colombier 	t = p->refresh.t - time(0);
834*7ab27030SDavid du Colombier 	if(t > 0)
835*7ab27030SDavid du Colombier 		return 0;
836*7ab27030SDavid du Colombier 
837*7ab27030SDavid du Colombier 	pageget(p, &p->refresh.rs, nil, HGet, FALSE);
838*7ab27030SDavid du Colombier 	return 1;
839*7ab27030SDavid du Colombier }
840