Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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