xref: /plan9/sys/src/cmd/abaco/main.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 <mouse.h>
7*7ab27030SDavid du Colombier #include <keyboard.h>
8*7ab27030SDavid du Colombier #include <cursor.h>
9*7ab27030SDavid du Colombier #include <frame.h>
10*7ab27030SDavid du Colombier #include <regexp.h>
11*7ab27030SDavid du Colombier #include <plumb.h>
12*7ab27030SDavid du Colombier #include <html.h>
13*7ab27030SDavid du Colombier #include "dat.h"
14*7ab27030SDavid du Colombier #include "fns.h"
15*7ab27030SDavid du Colombier 
16*7ab27030SDavid du Colombier enum {
17*7ab27030SDavid du Colombier 	WPERCOL = 8,
18*7ab27030SDavid du Colombier };
19*7ab27030SDavid du Colombier void	mousethread(void *);
20*7ab27030SDavid du Colombier void	keyboardthread(void *);
21*7ab27030SDavid du Colombier void	iconinit(void);
22*7ab27030SDavid du Colombier void	plumbproc(void*);
23*7ab27030SDavid du Colombier 
24*7ab27030SDavid du Colombier Channel	*cexit;
25*7ab27030SDavid du Colombier Channel	*cplumb;
26*7ab27030SDavid du Colombier Mousectl *mousectl;
27*7ab27030SDavid du Colombier 
28*7ab27030SDavid du Colombier char *fontnames[2] = {
29*7ab27030SDavid du Colombier 	"/lib/font/bit/lucidasans/unicode.8.font",
30*7ab27030SDavid du Colombier 	"/lib/font/bit/lucidasans/passwd.6.font",
31*7ab27030SDavid du Colombier };
32*7ab27030SDavid du Colombier 
33*7ab27030SDavid du Colombier int	snarffd = -1;
34*7ab27030SDavid du Colombier int	mainpid;
35*7ab27030SDavid du Colombier int	plumbwebfd;
36*7ab27030SDavid du Colombier int	plumbsendfd ;
37*7ab27030SDavid du Colombier char	*webmountpt = "/mnt/web";
38*7ab27030SDavid du Colombier char	*charset = "iso-8859-1";
39*7ab27030SDavid du Colombier int	mainstacksize = STACK;
40*7ab27030SDavid du Colombier 
41*7ab27030SDavid du Colombier void	readpage(Column *, char *);
42*7ab27030SDavid du Colombier int	shutdown(void *, char *);
43*7ab27030SDavid du Colombier 
44*7ab27030SDavid du Colombier void
derror(Display *,char * s)45*7ab27030SDavid du Colombier derror(Display *, char *s)
46*7ab27030SDavid du Colombier {
47*7ab27030SDavid du Colombier 	error(s);
48*7ab27030SDavid du Colombier }
49*7ab27030SDavid du Colombier 
50*7ab27030SDavid du Colombier static void
usage(void)51*7ab27030SDavid du Colombier usage(void)
52*7ab27030SDavid du Colombier {
53*7ab27030SDavid du Colombier 	fprint(2, "usage: %s [-c ncol] [-m mtpt] [-t charset] [url...]\n",
54*7ab27030SDavid du Colombier 		argv0);
55*7ab27030SDavid du Colombier 	exits("usage");
56*7ab27030SDavid du Colombier }
57*7ab27030SDavid du Colombier 
58*7ab27030SDavid du Colombier void
threadmain(int argc,char * argv[])59*7ab27030SDavid du Colombier threadmain(int argc, char *argv[])
60*7ab27030SDavid du Colombier {
61*7ab27030SDavid du Colombier 	Column *c;
62*7ab27030SDavid du Colombier 	char buf[256];
63*7ab27030SDavid du Colombier 	int i, ncol;
64*7ab27030SDavid du Colombier 
65*7ab27030SDavid du Colombier 	rfork(RFENVG|RFNAMEG);
66*7ab27030SDavid du Colombier 
67*7ab27030SDavid du Colombier 	ncol = 1;
68*7ab27030SDavid du Colombier 	ARGBEGIN{
69*7ab27030SDavid du Colombier 	case 'c':
70*7ab27030SDavid du Colombier 		ncol = atoi(EARGF(usage()));
71*7ab27030SDavid du Colombier 		if(ncol <= 0)
72*7ab27030SDavid du Colombier 			usage();
73*7ab27030SDavid du Colombier 		break;
74*7ab27030SDavid du Colombier 	case 'm':
75*7ab27030SDavid du Colombier 		webmountpt = EARGF(usage());
76*7ab27030SDavid du Colombier 		break;
77*7ab27030SDavid du Colombier 	case 'p':
78*7ab27030SDavid du Colombier 		procstderr++;
79*7ab27030SDavid du Colombier 		break;
80*7ab27030SDavid du Colombier 	case 't':
81*7ab27030SDavid du Colombier 		charset = EARGF(usage());
82*7ab27030SDavid du Colombier 		break;
83*7ab27030SDavid du Colombier 	default:
84*7ab27030SDavid du Colombier 		usage();
85*7ab27030SDavid du Colombier 		break;
86*7ab27030SDavid du Colombier 	}ARGEND
87*7ab27030SDavid du Colombier 
88*7ab27030SDavid du Colombier 	snprint(buf, sizeof(buf), "%s/ctl", webmountpt);
89*7ab27030SDavid du Colombier 	webctlfd = open(buf, ORDWR);
90*7ab27030SDavid du Colombier 	if(webctlfd < 0)
91*7ab27030SDavid du Colombier 		sysfatal("can't initialize webfs: %r");
92*7ab27030SDavid du Colombier 
93*7ab27030SDavid du Colombier 	snarffd = open("/dev/snarf", OREAD|OCEXEC);
94*7ab27030SDavid du Colombier 
95*7ab27030SDavid du Colombier 	if(initdraw(derror, fontnames[0], "abaco") < 0)
96*7ab27030SDavid du Colombier 		sysfatal("can't open display: %r");
97*7ab27030SDavid du Colombier 	memimageinit();
98*7ab27030SDavid du Colombier 	iconinit();
99*7ab27030SDavid du Colombier 	timerinit();
100*7ab27030SDavid du Colombier 	initfontpaths();
101*7ab27030SDavid du Colombier 
102*7ab27030SDavid du Colombier 	cexit = chancreate(sizeof(int), 0);
103*7ab27030SDavid du Colombier 	crefresh = chancreate(sizeof(Page *), 0);
104*7ab27030SDavid du Colombier 	if(cexit==nil || crefresh==nil)
105*7ab27030SDavid du Colombier 		sysfatal("can't create initial channels: %r");
106*7ab27030SDavid du Colombier 
107*7ab27030SDavid du Colombier 	mousectl = initmouse(nil, screen);
108*7ab27030SDavid du Colombier 	if(mousectl == nil)
109*7ab27030SDavid du Colombier 		sysfatal("can't initialize mouse: %r");
110*7ab27030SDavid du Colombier 	mouse = mousectl;
111*7ab27030SDavid du Colombier 	keyboardctl = initkeyboard(nil);
112*7ab27030SDavid du Colombier 	if(keyboardctl == nil)
113*7ab27030SDavid du Colombier 		sysfatal("can't initialize keyboard: %r");
114*7ab27030SDavid du Colombier 	mainpid = getpid();
115*7ab27030SDavid du Colombier 	plumbwebfd = plumbopen("web", OREAD|OCEXEC);
116*7ab27030SDavid du Colombier 	if(plumbwebfd >= 0){
117*7ab27030SDavid du Colombier 		cplumb = chancreate(sizeof(Plumbmsg*), 0);
118*7ab27030SDavid du Colombier 		proccreate(plumbproc, nil, STACK);
119*7ab27030SDavid du Colombier 	}
120*7ab27030SDavid du Colombier 	plumbsendfd = plumbopen("send", OWRITE|OCEXEC);
121*7ab27030SDavid du Colombier 
122*7ab27030SDavid du Colombier 	rowinit(&row, screen->clipr);
123*7ab27030SDavid du Colombier 	for(i=0; i<ncol; i++){
124*7ab27030SDavid du Colombier 		c = rowadd(&row, nil, -1);
125*7ab27030SDavid du Colombier 		if(c==nil && i==0)
126*7ab27030SDavid du Colombier 			error("initializing columns");
127*7ab27030SDavid du Colombier 	}
128*7ab27030SDavid du Colombier 	c = row.col[row.ncol-1];
129*7ab27030SDavid du Colombier 	for(i=0; i<argc; i++)
130*7ab27030SDavid du Colombier 		if(i/WPERCOL >= row.ncol)
131*7ab27030SDavid du Colombier 			readpage(c, argv[i]);
132*7ab27030SDavid du Colombier 		else
133*7ab27030SDavid du Colombier 			readpage(row.col[i/WPERCOL], argv[i]);
134*7ab27030SDavid du Colombier 	flushimage(display, 1);
135*7ab27030SDavid du Colombier 	threadcreate(keyboardthread, nil, STACK);
136*7ab27030SDavid du Colombier 	threadcreate(mousethread, nil, STACK);
137*7ab27030SDavid du Colombier 
138*7ab27030SDavid du Colombier 	threadnotify(shutdown, 1);
139*7ab27030SDavid du Colombier 	recvul(cexit);
140*7ab27030SDavid du Colombier 	threadexitsall(nil);
141*7ab27030SDavid du Colombier }
142*7ab27030SDavid du Colombier 
143*7ab27030SDavid du Colombier void
readpage(Column * c,char * s)144*7ab27030SDavid du Colombier readpage(Column *c, char *s)
145*7ab27030SDavid du Colombier {
146*7ab27030SDavid du Colombier 	Window *w;
147*7ab27030SDavid du Colombier 	Runestr rs;
148*7ab27030SDavid du Colombier 
149*7ab27030SDavid du Colombier 	w = coladd(c, nil, nil, -1);
150*7ab27030SDavid du Colombier 	bytetorunestr(s, &rs);
151*7ab27030SDavid du Colombier 	pageget(&w->page, &rs, nil, HGet, TRUE);
152*7ab27030SDavid du Colombier 	closerunestr(&rs);
153*7ab27030SDavid du Colombier }
154*7ab27030SDavid du Colombier 
155*7ab27030SDavid du Colombier char *oknotes[] = {
156*7ab27030SDavid du Colombier 	"delete",
157*7ab27030SDavid du Colombier 	"hangup",
158*7ab27030SDavid du Colombier 	"kill",
159*7ab27030SDavid du Colombier 	"exit",
160*7ab27030SDavid du Colombier 	nil
161*7ab27030SDavid du Colombier };
162*7ab27030SDavid du Colombier 
163*7ab27030SDavid du Colombier int
shutdown(void *,char * msg)164*7ab27030SDavid du Colombier shutdown(void*, char *msg)
165*7ab27030SDavid du Colombier {
166*7ab27030SDavid du Colombier 	int i;
167*7ab27030SDavid du Colombier 
168*7ab27030SDavid du Colombier 	for(i=0; oknotes[i]; i++)
169*7ab27030SDavid du Colombier 		if(strncmp(oknotes[i], msg, strlen(oknotes[i])) == 0)
170*7ab27030SDavid du Colombier 			threadexitsall(msg);
171*7ab27030SDavid du Colombier 	print("abaco: %s\n", msg);
172*7ab27030SDavid du Colombier //	abort();
173*7ab27030SDavid du Colombier 	return 0;
174*7ab27030SDavid du Colombier }
175*7ab27030SDavid du Colombier 
176*7ab27030SDavid du Colombier void
plumbproc(void *)177*7ab27030SDavid du Colombier plumbproc(void *)
178*7ab27030SDavid du Colombier {
179*7ab27030SDavid du Colombier 	Plumbmsg *m;
180*7ab27030SDavid du Colombier 
181*7ab27030SDavid du Colombier 	threadsetname("plumbproc");
182*7ab27030SDavid du Colombier 	for(;;){
183*7ab27030SDavid du Colombier 		m = plumbrecv(plumbwebfd);
184*7ab27030SDavid du Colombier 		if(m == nil)
185*7ab27030SDavid du Colombier 			threadexits(nil);
186*7ab27030SDavid du Colombier 		sendp(cplumb, m);
187*7ab27030SDavid du Colombier 	}
188*7ab27030SDavid du Colombier }
189*7ab27030SDavid du Colombier 
190*7ab27030SDavid du Colombier enum { KTimer, KKey, NKALT, };
191*7ab27030SDavid du Colombier 
192*7ab27030SDavid du Colombier void
keyboardthread(void *)193*7ab27030SDavid du Colombier keyboardthread(void *)
194*7ab27030SDavid du Colombier {
195*7ab27030SDavid du Colombier 	Timer *timer;
196*7ab27030SDavid du Colombier 	Text *t;
197*7ab27030SDavid du Colombier 	Rune r;
198*7ab27030SDavid du Colombier 
199*7ab27030SDavid du Colombier 	static Alt alts[NKALT+1];
200*7ab27030SDavid du Colombier 
201*7ab27030SDavid du Colombier 	alts[KTimer].c = nil;
202*7ab27030SDavid du Colombier 	alts[KTimer].v = nil;
203*7ab27030SDavid du Colombier 	alts[KTimer].op = CHANNOP;
204*7ab27030SDavid du Colombier 	alts[KKey].c = keyboardctl->c;
205*7ab27030SDavid du Colombier 	alts[KKey].v = &r;
206*7ab27030SDavid du Colombier 	alts[KKey].op = CHANRCV;
207*7ab27030SDavid du Colombier 	alts[NKALT].op = CHANEND;
208*7ab27030SDavid du Colombier 
209*7ab27030SDavid du Colombier 	timer = nil;
210*7ab27030SDavid du Colombier 	threadsetname("keyboardthread");
211*7ab27030SDavid du Colombier 	for(;;){
212*7ab27030SDavid du Colombier 		switch(alt(alts)){
213*7ab27030SDavid du Colombier 		case KTimer:
214*7ab27030SDavid du Colombier 			timerstop(timer);
215*7ab27030SDavid du Colombier 			alts[KTimer].c = nil;
216*7ab27030SDavid du Colombier 			alts[KTimer].op = CHANNOP;
217*7ab27030SDavid du Colombier 			break;
218*7ab27030SDavid du Colombier 		case KKey:
219*7ab27030SDavid du Colombier 		casekeyboard:
220*7ab27030SDavid du Colombier 			typetext = rowwhich(&row, mouse->xy, r, TRUE);
221*7ab27030SDavid du Colombier 			t = typetext;
222*7ab27030SDavid du Colombier 			if(t!=nil && t->col!=nil &&
223*7ab27030SDavid du Colombier 			    !(r==Kdown || r==Kleft || r==Kright))
224*7ab27030SDavid du Colombier 				/* scrolling doesn't change activecol */
225*7ab27030SDavid du Colombier 				activecol = t->col;
226*7ab27030SDavid du Colombier 			if(timer != nil)
227*7ab27030SDavid du Colombier 				timercancel(timer);
228*7ab27030SDavid du Colombier 			if(t!=nil){
229*7ab27030SDavid du Colombier 				texttype(t, r);
230*7ab27030SDavid du Colombier 				timer = timerstart(500);
231*7ab27030SDavid du Colombier 				alts[KTimer].c = timer->c;
232*7ab27030SDavid du Colombier 				alts[KTimer].op = CHANRCV;
233*7ab27030SDavid du Colombier 			}else{
234*7ab27030SDavid du Colombier 				timer = nil;
235*7ab27030SDavid du Colombier 				alts[KTimer].c = nil;
236*7ab27030SDavid du Colombier 				alts[KTimer].op = CHANNOP;
237*7ab27030SDavid du Colombier 			}
238*7ab27030SDavid du Colombier 			if(nbrecv(keyboardctl->c, &r) > 0)
239*7ab27030SDavid du Colombier 				goto casekeyboard;
240*7ab27030SDavid du Colombier 			flushimage(display, 1);
241*7ab27030SDavid du Colombier 			break;
242*7ab27030SDavid du Colombier 		}
243*7ab27030SDavid du Colombier 	}
244*7ab27030SDavid du Colombier }
245*7ab27030SDavid du Colombier 
246*7ab27030SDavid du Colombier void
mousethread(void *)247*7ab27030SDavid du Colombier mousethread(void *)
248*7ab27030SDavid du Colombier {
249*7ab27030SDavid du Colombier 	Plumbmsg *pm;
250*7ab27030SDavid du Colombier 	Mouse m;
251*7ab27030SDavid du Colombier 	Text *t;
252*7ab27030SDavid du Colombier 	int but;
253*7ab27030SDavid du Colombier 	enum { MResize, MMouse, MPlumb, MRefresh, NMALT };
254*7ab27030SDavid du Colombier 	static Alt alts[NMALT+1];
255*7ab27030SDavid du Colombier 
256*7ab27030SDavid du Colombier 	threadsetname("mousethread");
257*7ab27030SDavid du Colombier 	alts[MResize].c = mousectl->resizec;
258*7ab27030SDavid du Colombier 	alts[MResize].v = nil;
259*7ab27030SDavid du Colombier 	alts[MResize].op = CHANRCV;
260*7ab27030SDavid du Colombier 	alts[MMouse].c = mousectl->c;
261*7ab27030SDavid du Colombier 	alts[MMouse].v = &mousectl->Mouse;
262*7ab27030SDavid du Colombier 	alts[MMouse].op = CHANRCV;
263*7ab27030SDavid du Colombier 	alts[MPlumb].c = cplumb;
264*7ab27030SDavid du Colombier 	alts[MPlumb].v = &pm;
265*7ab27030SDavid du Colombier 	alts[MPlumb].op = CHANRCV;
266*7ab27030SDavid du Colombier 	alts[MRefresh].c = crefresh;
267*7ab27030SDavid du Colombier 	alts[MRefresh].v = nil;
268*7ab27030SDavid du Colombier 	alts[MRefresh].op = CHANRCV;
269*7ab27030SDavid du Colombier 	if(cplumb == nil)
270*7ab27030SDavid du Colombier 		alts[MPlumb].op = CHANNOP;
271*7ab27030SDavid du Colombier 	alts[NMALT].op = CHANEND;
272*7ab27030SDavid du Colombier 
273*7ab27030SDavid du Colombier 	for(;;){
274*7ab27030SDavid du Colombier 		qlock(&row);
275*7ab27030SDavid du Colombier 		flushrefresh();
276*7ab27030SDavid du Colombier 		qunlock(&row);
277*7ab27030SDavid du Colombier 		flushimage(display, 1);
278*7ab27030SDavid du Colombier 		switch(alt(alts)){
279*7ab27030SDavid du Colombier 		case MResize:
280*7ab27030SDavid du Colombier 			if(getwindow(display, Refnone) < 0)
281*7ab27030SDavid du Colombier 				error("resized");
282*7ab27030SDavid du Colombier 			scrlresize();
283*7ab27030SDavid du Colombier 			tmpresize();
284*7ab27030SDavid du Colombier 			rowresize(&row, screen->clipr);
285*7ab27030SDavid du Colombier 			break;
286*7ab27030SDavid du Colombier 		case MPlumb:
287*7ab27030SDavid du Colombier 			plumblook(pm);
288*7ab27030SDavid du Colombier 			plumbfree(pm);
289*7ab27030SDavid du Colombier 			break;
290*7ab27030SDavid du Colombier 		case MRefresh:
291*7ab27030SDavid du Colombier 			break;
292*7ab27030SDavid du Colombier 		case MMouse:
293*7ab27030SDavid du Colombier 			m = mousectl->Mouse;
294*7ab27030SDavid du Colombier 			if(m.buttons == 0)
295*7ab27030SDavid du Colombier 				continue;
296*7ab27030SDavid du Colombier 
297*7ab27030SDavid du Colombier 			qlock(&row);
298*7ab27030SDavid du Colombier 			but = 0;
299*7ab27030SDavid du Colombier 			if(m.buttons == 1)
300*7ab27030SDavid du Colombier 				but = 1;
301*7ab27030SDavid du Colombier 			else if(m.buttons == 2)
302*7ab27030SDavid du Colombier 				but = 2;
303*7ab27030SDavid du Colombier 			else if(m.buttons == 4)
304*7ab27030SDavid du Colombier 				but = 3;
305*7ab27030SDavid du Colombier 
306*7ab27030SDavid du Colombier 			if(m.buttons & (8|16)){
307*7ab27030SDavid du Colombier 				if(m.buttons & 8)
308*7ab27030SDavid du Colombier 					but = Kscrolloneup;
309*7ab27030SDavid du Colombier 				else
310*7ab27030SDavid du Colombier 					but = Kscrollonedown;
311*7ab27030SDavid du Colombier 				rowwhich(&row, m.xy, but, TRUE);
312*7ab27030SDavid du Colombier 			}else	if(but){
313*7ab27030SDavid du Colombier 				t = rowwhich(&row, m.xy, but, FALSE);
314*7ab27030SDavid du Colombier 				if(t)
315*7ab27030SDavid du Colombier 					textmouse(t, m.xy, but);
316*7ab27030SDavid du Colombier 			}
317*7ab27030SDavid du Colombier 			qunlock(&row);
318*7ab27030SDavid du Colombier 			break;
319*7ab27030SDavid du Colombier 		}
320*7ab27030SDavid du Colombier 	}
321*7ab27030SDavid du Colombier }
322*7ab27030SDavid du Colombier 
323*7ab27030SDavid du Colombier Cursor boxcursor = {
324*7ab27030SDavid du Colombier 	{-7, -7},
325*7ab27030SDavid du Colombier 	{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
326*7ab27030SDavid du Colombier 	 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F,
327*7ab27030SDavid du Colombier 	 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF,
328*7ab27030SDavid du Colombier 	 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
329*7ab27030SDavid du Colombier 	{0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE,
330*7ab27030SDavid du Colombier 	 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
331*7ab27030SDavid du Colombier 	 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
332*7ab27030SDavid du Colombier 	 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00}
333*7ab27030SDavid du Colombier };
334*7ab27030SDavid du Colombier 
335*7ab27030SDavid du Colombier void
iconinit(void)336*7ab27030SDavid du Colombier iconinit(void)
337*7ab27030SDavid du Colombier {
338*7ab27030SDavid du Colombier 	Rectangle r;
339*7ab27030SDavid du Colombier 
340*7ab27030SDavid du Colombier 	/* Green */
341*7ab27030SDavid du Colombier 	tagcols[BACK] = allocimagemix(display, DPalegreen, DWhite);
342*7ab27030SDavid du Colombier 	if(tagcols[BACK] == nil)
343*7ab27030SDavid du Colombier 		error("allocimagemix");
344*7ab27030SDavid du Colombier 	tagcols[HIGH] = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkgreen);
345*7ab27030SDavid du Colombier 	tagcols[BORD] = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedgreen);
346*7ab27030SDavid du Colombier 	tagcols[TEXT] = display->black;
347*7ab27030SDavid du Colombier 	tagcols[HTEXT] = display->black;
348*7ab27030SDavid du Colombier 
349*7ab27030SDavid du Colombier 	/* Grey */
350*7ab27030SDavid du Colombier 	textcols[BACK] = display->white;
351*7ab27030SDavid du Colombier 	textcols[HIGH] = eallocimage(display, Rect(0,0,1,1), CMAP8,1, 0xCCCCCCFF);
352*7ab27030SDavid du Colombier 	textcols[BORD] = display->black;
353*7ab27030SDavid du Colombier 	textcols[TEXT] = display->black;
354*7ab27030SDavid du Colombier 	textcols[HTEXT] = display->black;
355*7ab27030SDavid du Colombier 
356*7ab27030SDavid du Colombier 	r = Rect(0, 0, Scrollsize+2, font->height+1);
357*7ab27030SDavid du Colombier 	button = eallocimage(display, r, screen->chan, 0, DNofill);
358*7ab27030SDavid du Colombier 	draw(button, r, tagcols[BACK], nil, r.min);
359*7ab27030SDavid du Colombier 	r.max.x -= 2;
360*7ab27030SDavid du Colombier 	border(button, r, 2, tagcols[BORD], ZP);
361*7ab27030SDavid du Colombier 
362*7ab27030SDavid du Colombier 	r = button->r;
363*7ab27030SDavid du Colombier 	colbutton = eallocimage(display, r, screen->chan, 0, 0x00994CFF);
364*7ab27030SDavid du Colombier 
365*7ab27030SDavid du Colombier 	but2col = eallocimage(display, Rect(0,0,1,2), screen->chan, 1, 0xAA0000FF);
366*7ab27030SDavid du Colombier 	but3col = eallocimage(display, Rect(0,0,1,2), screen->chan, 1, 0x444488FF);
367*7ab27030SDavid du Colombier 
368*7ab27030SDavid du Colombier 	passfont = openfont(display, fontnames[1]);
369*7ab27030SDavid du Colombier 	if(passfont == nil)
370*7ab27030SDavid du Colombier 		error("openfont");
371*7ab27030SDavid du Colombier }
372*7ab27030SDavid du Colombier 
373*7ab27030SDavid du Colombier /*
374*7ab27030SDavid du Colombier  * /dev/snarf updates when the file is closed, so we must open our own
375*7ab27030SDavid du Colombier  * fd here rather than use snarffd
376*7ab27030SDavid du Colombier  */
377*7ab27030SDavid du Colombier 
378*7ab27030SDavid du Colombier /*
379*7ab27030SDavid du Colombier  * rio truncates large snarf buffers, so this avoids using the
380*7ab27030SDavid du Colombier  * service if the string is huge
381*7ab27030SDavid du Colombier  */
382*7ab27030SDavid du Colombier 
383*7ab27030SDavid du Colombier enum
384*7ab27030SDavid du Colombier {
385*7ab27030SDavid du Colombier 	NSnarf = 1000,
386*7ab27030SDavid du Colombier 	MAXSNARF = 100*1024,
387*7ab27030SDavid du Colombier };
388*7ab27030SDavid du Colombier 
389*7ab27030SDavid du Colombier void
putsnarf(Runestr * rs)390*7ab27030SDavid du Colombier putsnarf(Runestr *rs)
391*7ab27030SDavid du Colombier {
392*7ab27030SDavid du Colombier 	int fd, i, n;
393*7ab27030SDavid du Colombier 
394*7ab27030SDavid du Colombier 	if(snarffd<0 || rs->nr==0)
395*7ab27030SDavid du Colombier 		return;
396*7ab27030SDavid du Colombier 	if(rs->nr > MAXSNARF)
397*7ab27030SDavid du Colombier 		return;
398*7ab27030SDavid du Colombier 	fd = open("/dev/snarf", OWRITE);
399*7ab27030SDavid du Colombier 	if(fd < 0)
400*7ab27030SDavid du Colombier 		return;
401*7ab27030SDavid du Colombier 	for(i=0; i<rs->nr; i+=n){
402*7ab27030SDavid du Colombier 		n = rs->nr-i;
403*7ab27030SDavid du Colombier 		if(n > NSnarf)
404*7ab27030SDavid du Colombier 			n =NSnarf;
405*7ab27030SDavid du Colombier 		if(fprint(fd, "%.*S", n, rs->r) < 0)
406*7ab27030SDavid du Colombier 			break;
407*7ab27030SDavid du Colombier 	}
408*7ab27030SDavid du Colombier 	close(fd);
409*7ab27030SDavid du Colombier }
410*7ab27030SDavid du Colombier 
411*7ab27030SDavid du Colombier void
getsnarf(Runestr * rs)412*7ab27030SDavid du Colombier getsnarf(Runestr *rs)
413*7ab27030SDavid du Colombier {
414*7ab27030SDavid du Colombier 	int i, n, nb, nulls;
415*7ab27030SDavid du Colombier 	char *sn, buf[BUFSIZE];
416*7ab27030SDavid du Colombier 
417*7ab27030SDavid du Colombier 	if(snarffd < 0)
418*7ab27030SDavid du Colombier 		return;
419*7ab27030SDavid du Colombier 	sn = nil;
420*7ab27030SDavid du Colombier 	i = 0;
421*7ab27030SDavid du Colombier 	seek(snarffd, 0, 0);
422*7ab27030SDavid du Colombier 	while((n=read(snarffd, buf, sizeof(buf))) > 0){
423*7ab27030SDavid du Colombier 		sn = erealloc(sn, i+n+1);
424*7ab27030SDavid du Colombier 		memmove(sn+i, buf, n);
425*7ab27030SDavid du Colombier 		i += n;
426*7ab27030SDavid du Colombier 		sn[i] = 0;
427*7ab27030SDavid du Colombier 	}
428*7ab27030SDavid du Colombier 	if(i > 0){
429*7ab27030SDavid du Colombier 		rs->r = runemalloc(i+1);
430*7ab27030SDavid du Colombier 		cvttorunes(sn, i, rs->r, &nb, &rs->nr, &nulls);
431*7ab27030SDavid du Colombier 		free(sn);
432*7ab27030SDavid du Colombier 	}
433*7ab27030SDavid du Colombier }
434