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