18 const char *termprog = "9term";
29 void derror(Display*, char*);
30 void mousethread(void*);
31 void keyboardthread(void*);
32 void winclosethread(void*);
33 void deletethread(void*);
34 void rcoutputproc(void*);
35 void rcinputproc(void*);
36 void hangupnote(void*, char*);
37 void resizethread(void*);
38 void servedevtext(void);
40 int errorshouldabort = 0;
46 fprint(2, "usage: 9term [-s] [-f font] [-W winsize] [cmd ...]\n");
47 threadexitsall("usage");
51 threadmaybackground(void)
57 threadmain(int argc, char *argv[])
63 _wantfocuschanges = 1;
74 fontname = EARGF(usage());
82 case 'w': /* started from rio or 9wm */
86 winsize = EARGF(usage());
91 putenv("font", fontname);
93 p = getenv("tabstop");
95 p = getenv("TABSTOP");
97 maxtab = strtoul(p, 0, 0);
104 if(initdraw(derror, fontname, "9term") < 0)
105 sysfatal("initdraw: %r");
108 noteenable("sys: child");
110 mousectl = initmouse(nil, screen);
112 error("cannot find mouse");
113 keyboardctl = initkeyboard(nil);
114 if(keyboardctl == nil)
115 error("cannot find keyboard");
116 mouse = &mousectl->m;
118 winclosechan = chancreate(sizeof(Window*), 0);
119 deletechan = chancreate(sizeof(char*), 0);
123 rcpid = rcstart(argc, argv, &rcfd, &sfd);
124 w = new(screen, FALSE, scrolling, rcpid, ".", nil, nil);
126 threadcreate(keyboardthread, nil, STACK);
127 threadcreate(mousethread, nil, STACK);
128 threadcreate(resizethread, nil, STACK);
130 proccreate(rcoutputproc, nil, STACK);
131 proccreate(rcinputproc, nil, STACK);
135 derror(Display *d, char *errorstr)
142 hangupnote(void *a, char *msg)
144 if(getpid() != mainpid)
146 if(strcmp(msg, "hangup") == 0){
147 postnote(PNPROC, rcpid, "hangup");
150 if(strstr(msg, "child")){
154 n = awaitnohang(buf, sizeof buf-1);
157 if(atoi(buf) == rcpid)
166 keyboardthread(void *v)
168 Rune buf[2][20], *rp;
172 threadsetname("keyboardthread");
177 recv(keyboardctl->c, rp);
178 for(i=1; i<nelem(buf[0])-1; i++)
179 if(nbrecv(keyboardctl->c, rp+i) <= 0)
187 resizethread(void *v)
194 p = stringsize(display->defaultfont, "0");
196 updatewinsize(Dy(screen->r)/p.y, (Dx(screen->r)-Scrollwid-2)/p.x,
197 Dx(screen->r), Dy(screen->r));
198 wresize(w, screen, 0);
199 flushimage(display, 1);
200 if(recv(mousectl->resizec, nil) != 1)
202 if(getwindow(display, Refnone) < 0)
203 sysfatal("can't reattach to window");
216 threadsetname("mousethread");
217 while(readmouse(mousectl) >= 0){
221 if(mouse->buttons == 0)
229 if((mouse->buttons&(1|8|16)) || ptinrect(mouse->xy, w->scrollr)){
232 }else if(mouse->buttons&2)
240 wborder(Window *w, int type)
251 new(Image *i, int hideit, int scrollit, int pid, char *dir, char *cmd, char **argv)
255 Channel *cm, *ck, *cctl;
259 cm = chancreate(sizeof(Mouse), 0);
260 ck = chancreate(sizeof(Rune*), 0);
261 cctl = chancreate(sizeof(Wctlmesg), 4);
262 if(cm==nil || ck==nil || cctl==nil)
263 error("new: channel alloc failed");
264 mc = emalloc(sizeof(Mousectl));
268 w = wmk(i, mc, ck, cctl, scrollit);
269 free(mc); /* wmk copies *mc */
270 window = erealloc(window, ++nwindow*sizeof(Window*));
271 window[nwindow-1] = w;
273 hidden[nhidden++] = w;
276 threadcreate(winctl, w, STACK);
279 flushimage(display, 1);
283 w->dir = estrdup(dir);
288 * Button 2 menu. Extra entry for always cook
321 Rune newline[] = { '\n' };
324 button2menu(Window *w)
330 menu2str[Scroll] = "noscroll";
332 menu2str[Scroll] = "scroll";
334 menu2str[Cook] = "nocook";
336 menu2str[Cook] = "cook";
338 switch(menuhit(2, mousectl, &menu2, wscreen)){
369 waddraw(w, snarf, nsnarf);
370 if(snarf[nsnarf-1]!='\n' && snarf[nsnarf-1]!='\004')
371 waddraw(w, newline, 1);
373 winsert(w, snarf, nsnarf, w->nr);
374 if(snarf[nsnarf-1]!='\n' && snarf[nsnarf-1]!='\004')
375 winsert(w, newline, 1, w->nr);
377 wsetselect(w, w->nr, w->nr);
382 if(w->scrolling ^= 1)
390 wsendctlmesg(w, Wakeup, ZR, nil);
391 flushimage(display, 1);
397 return !cooked && !isecho(sfd);
404 int label(Rune*, int);
407 rcoutputproc(void *arg)
409 int i, cnt, n, nb, nr;
410 static char data[9000];
418 /* XXX Let typing have a go -- maybe there's a rubout waiting. */
420 n = read(rcfd, data+cnt, sizeof data-cnt);
423 fprint(2, "9term: rc read error: %r\n");
424 threadexitsall("eof on rc output");
426 n = echocancel(data+cnt, n);
431 cvttorunes(data, cnt-UTFmax, r, &nb, &nr, nil);
432 /* approach end of buffer */
433 while(fullrune(data+nb, cnt-nb)){
434 nb += chartorune(&r[nr], data+nb);
439 memmove(data, data+nb, cnt-nb);
446 recv(w->conswrite, &cwm);
454 winterrupt(Window *w)
459 rubout[0] = getintr(sfd);
460 write(rcfd, rubout, 1);
470 * Process in-band messages about window title changes.
471 * The messages are of the form:
475 * where xxx is the new directory. This format was chosen
476 * because it changes the label on xterm windows.
479 label(Rune *sr, int n)
481 Rune *sl, *el, *er, *r;
485 for(r=er-1; r>=sr; r--)
492 for(sl=el-3; sl>=sr; sl--)
493 if(sl[0]=='\033' && sl[1]==']' && sl[2]==';')
498 dir = smprint("%.*S", (el-1)-(sl+3), sl+3);
500 if(strcmp(dir, "*9term-hold+") == 0) {
503 flushimage(display, 1);
511 /* remove trailing /-sysname if present */
512 p = strrchr(dir, '/');
513 if(p && *(p+1) == '-'){
519 runemove(sl, el, er-el);
525 rcinputproc(void *arg)
527 static char data[9000];
533 recv(w->consread, &crm);
538 pair.ns = sizeof data;
543 echoed(pair.s, pair.ns);
544 if(write(rcfd, pair.s, pair.ns) < 0)
550 * Snarf buffer - rio uses runes internally
557 s = smprint("%.*S", nsnarf, snarf);
575 snarf = runemalloc(n);
576 cvttorunes(s, n, snarf, &nb, &nsnarf, &nulls);
581 * Clumsy hack to make " and "" work.
582 * Then again, what's not a clumsy hack here in Unix land?
589 void listenproc(void*);
590 void textproc(void*);
593 removethesocket(void)
596 if(remove(thesocket) < 0)
597 fprint(2, "remove %s: %r\n", thesocket);
605 snprint(buf, sizeof buf, "unix!/tmp/9term-text.%d", getpid());
607 if((afd = announce(buf, adir)) < 0){
608 putenv("text9term", "");
612 putenv("text9term", buf);
613 proccreate(listenproc, nil, STACK);
614 strcpy(thesocket, buf+5);
615 atexit(removethesocket);
619 listenproc(void *arg)
624 threadsetname("listen %s", thesocket);
627 fd = listen(adir, dir);
632 proccreate(textproc, (void*)(uintptr)fd, STACK);
639 int fd, i, x, n, end;
641 char buf[4096], *p, *ep;
643 threadsetname("textproc");
651 end = w->org+w->nr; /* avoid possible output loop */
653 if(i >= end || ep-p < UTFmax){
654 for(x=0; x<p-buf; x+=n)
655 if((n = write(fd, buf+x, (p-x)-buf)) <= 0)
668 p += runetochar(p, &r);