acme.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <draw.h>
  12. #include <thread.h>
  13. #include <cursor.h>
  14. #include <mouse.h>
  15. #include <keyboard.h>
  16. #include <frame.h>
  17. #include <fcall.h>
  18. #include <plumb.h>
  19. #include "dat.h"
  20. #include "fns.h"
  21. /* for generating syms in mkfile only: */
  22. #include <bio.h>
  23. #include "edit.h"
  24. void mousethread(void*);
  25. void keyboardthread(void*);
  26. void waitthread(void*);
  27. void xfidallocthread(void*);
  28. void newwindowthread(void*);
  29. void plumbproc(void*);
  30. Reffont **fontcache;
  31. int nfontcache;
  32. char wdir[512] = ".";
  33. Reffont *reffonts[2];
  34. int snarffd = -1;
  35. int mainpid;
  36. int plumbsendfd;
  37. int plumbeditfd;
  38. enum{
  39. NSnarf = 1000 /* less than 1024, I/O buffer size */
  40. };
  41. Rune snarfrune[NSnarf+1];
  42. char *fontnames[2] =
  43. {
  44. "/lib/font/bit/lucidasans/euro.8.font",
  45. "/lib/font/bit/lucm/unicode.9.font"
  46. };
  47. Command *command;
  48. void acmeerrorinit(void);
  49. void readfile(Column*, char*);
  50. int shutdown(void*, char*);
  51. void
  52. derror(Display*d, char *errorstr)
  53. {
  54. error(errorstr);
  55. }
  56. void
  57. threadmain(int argc, char *argv[])
  58. {
  59. int i;
  60. char *p, *loadfile;
  61. char buf[256];
  62. Column *c;
  63. int ncol;
  64. Display *d;
  65. //
  66. rfork(RFENVG|RFNAMEG);
  67. ncol = -1;
  68. loadfile = nil;
  69. ARGBEGIN{
  70. case 'a':
  71. globalautoindent = TRUE;
  72. break;
  73. case 'b':
  74. bartflag = TRUE;
  75. break;
  76. case 'c':
  77. p = ARGF();
  78. if(p == nil)
  79. goto Usage;
  80. ncol = atoi(p);
  81. if(ncol <= 0)
  82. goto Usage;
  83. break;
  84. case 'f':
  85. fontnames[0] = ARGF();
  86. if(fontnames[0] == nil)
  87. goto Usage;
  88. break;
  89. case 'F':
  90. fontnames[1] = ARGF();
  91. if(fontnames[1] == nil)
  92. goto Usage;
  93. break;
  94. case 'l':
  95. loadfile = ARGF();
  96. if(loadfile == nil)
  97. goto Usage;
  98. break;
  99. default:
  100. Usage:
  101. fprint(2, "usage: acme [-ab] [-c ncol] [-f font] [-F fixedfont] [-l loadfile | file...]\n");
  102. exits("usage");
  103. }ARGEND
  104. fontnames[0] = estrdup(fontnames[0]);
  105. fontnames[1] = estrdup(fontnames[1]);
  106. quotefmtinstall();
  107. cputype = getenv("cputype");
  108. objtype = getenv("objtype");
  109. home = getenv("home");
  110. p = getenv("tabstop");
  111. if(p != nil){
  112. maxtab = strtoul(p, nil, 0);
  113. free(p);
  114. }
  115. if(maxtab == 0)
  116. maxtab = 4;
  117. if(loadfile)
  118. rowloadfonts(loadfile);
  119. putenv("font", fontnames[0]);
  120. snarffd = open("/dev/snarf", OREAD|OCEXEC);
  121. if(cputype){
  122. sprint(buf, "/acme/bin/%s", cputype);
  123. bind(buf, "/bin", MBEFORE);
  124. }
  125. bind("/acme/bin", "/bin", MBEFORE);
  126. getwd(wdir, sizeof wdir);
  127. if(geninitdraw(nil, derror, fontnames[0], "acme", nil, Refnone) < 0){
  128. fprint(2, "acme: can't open display: %r\n");
  129. exits("geninitdraw");
  130. }
  131. d = display;
  132. font = d->defaultfont;
  133. reffont.f = font;
  134. reffonts[0] = &reffont;
  135. incref(&reffont.Ref); /* one to hold up 'font' variable */
  136. incref(&reffont.Ref); /* one to hold up reffonts[0] */
  137. fontcache = emalloc(sizeof(Reffont*));
  138. nfontcache = 1;
  139. fontcache[0] = &reffont;
  140. iconinit();
  141. timerinit();
  142. rxinit();
  143. cwait = threadwaitchan();
  144. ccommand = chancreate(sizeof(Command**), 0);
  145. ckill = chancreate(sizeof(Rune*), 0);
  146. cxfidalloc = chancreate(sizeof(Xfid*), 0);
  147. cxfidfree = chancreate(sizeof(Xfid*), 0);
  148. cnewwindow = chancreate(sizeof(Channel*), 0);
  149. cerr = chancreate(sizeof(char*), 0);
  150. cedit = chancreate(sizeof(int), 0);
  151. cexit = chancreate(sizeof(int), 0);
  152. cwarn = chancreate(sizeof(void*), 1);
  153. if(cwait==nil || ccommand==nil || ckill==nil || cxfidalloc==nil || cxfidfree==nil || cerr==nil || cexit==nil || cwarn==nil){
  154. fprint(2, "acme: can't create initial channels: %r\n");
  155. exits("channels");
  156. }
  157. mousectl = initmouse(nil, screen);
  158. if(mousectl == nil){
  159. fprint(2, "acme: can't initialize mouse: %r\n");
  160. exits("mouse");
  161. }
  162. mouse = (Mouse *)mousectl;
  163. keyboardctl = initkeyboard(nil);
  164. if(keyboardctl == nil){
  165. fprint(2, "acme: can't initialize keyboard: %r\n");
  166. exits("keyboard");
  167. }
  168. mainpid = getpid();
  169. plumbeditfd = plumbopen("edit", OREAD|OCEXEC);
  170. if(plumbeditfd >= 0){
  171. cplumb = chancreate(sizeof(Plumbmsg*), 0);
  172. proccreate(plumbproc, nil, STACK);
  173. }
  174. plumbsendfd = plumbopen("send", OWRITE|OCEXEC);
  175. fsysinit();
  176. #define WPERCOL 8
  177. disk = diskinit();
  178. if(!loadfile || !rowload(&row, loadfile, TRUE)){
  179. rowinit(&row, screen->clipr);
  180. if(ncol < 0){
  181. if(argc == 0)
  182. ncol = 2;
  183. else{
  184. ncol = (argc+(WPERCOL-1))/WPERCOL;
  185. if(ncol < 2)
  186. ncol = 2;
  187. }
  188. }
  189. if(ncol == 0)
  190. ncol = 2;
  191. for(i=0; i<ncol; i++){
  192. c = rowadd(&row, nil, -1);
  193. if(c==nil && i==0)
  194. error("initializing columns");
  195. }
  196. c = row.col[row.ncol-1];
  197. if(argc == 0)
  198. readfile(c, wdir);
  199. else
  200. for(i=0; i<argc; i++){
  201. p = utfrrune(argv[i], '/');
  202. if((p!=nil && strcmp(p, "/guide")==0) || i/WPERCOL>=row.ncol)
  203. readfile(c, argv[i]);
  204. else
  205. readfile(row.col[i/WPERCOL], argv[i]);
  206. }
  207. }
  208. flushimage(display, 1);
  209. acmeerrorinit();
  210. threadcreate(keyboardthread, nil, STACK);
  211. threadcreate(mousethread, nil, STACK);
  212. threadcreate(waitthread, nil, STACK);
  213. threadcreate(xfidallocthread, nil, STACK);
  214. threadcreate(newwindowthread, nil, STACK);
  215. threadnotify(shutdown, 1);
  216. recvul(cexit);
  217. killprocs();
  218. threadexitsall(nil);
  219. }
  220. void
  221. readfile(Column *c, char *s)
  222. {
  223. Window *w;
  224. Rune rb[256];
  225. int nb, nr;
  226. Runestr rs;
  227. w = coladd(c, nil, nil, -1);
  228. cvttorunes(s, strlen(s), rb, &nb, &nr, nil);
  229. rs = cleanrname((Runestr){rb, nr});
  230. winsetname(w, rs.r, rs.nr);
  231. textload(&w->body, 0, s, 1);
  232. w->body.file->mod = FALSE;
  233. w->dirty = FALSE;
  234. winsettag(w);
  235. textscrdraw(&w->body);
  236. textsetselect(&w->tag, w->tag.file->Buffer.nc, w->tag.file->Buffer.nc);
  237. xfidlog(w, "new");
  238. }
  239. char *oknotes[] ={
  240. "delete",
  241. "hangup",
  242. "kill",
  243. "exit",
  244. nil
  245. };
  246. int dumping;
  247. int
  248. shutdown(void*v, char *msg)
  249. {
  250. int i;
  251. killprocs();
  252. if(!dumping && strcmp(msg, "kill")!=0 && strcmp(msg, "exit")!=0 && getpid()==mainpid){
  253. dumping = TRUE;
  254. rowdump(&row, nil);
  255. }
  256. for(i=0; oknotes[i]; i++)
  257. if(strncmp(oknotes[i], msg, strlen(oknotes[i])) == 0)
  258. threadexitsall(msg);
  259. print("acme: %s\n", msg);
  260. abort();
  261. return 0;
  262. }
  263. void
  264. killprocs(void)
  265. {
  266. Command *c;
  267. fsysclose();
  268. // if(display)
  269. // flushimage(display, 1);
  270. for(c=command; c; c=c->next)
  271. postnote(PNGROUP, c->pid, "hangup");
  272. remove(acmeerrorfile);
  273. }
  274. static int errorfd;
  275. void
  276. acmeerrorproc(void *v)
  277. {
  278. char *buf;
  279. int n;
  280. threadsetname("acmeerrorproc");
  281. buf = emalloc(8192+1);
  282. while((n=read(errorfd, buf, 8192)) >= 0){
  283. buf[n] = '\0';
  284. sendp(cerr, estrdup(buf));
  285. }
  286. }
  287. void
  288. acmeerrorinit(void)
  289. {
  290. int fd, pfd[2];
  291. char buf[64];
  292. if(pipe(pfd) < 0)
  293. error("can't create pipe");
  294. sprint(acmeerrorfile, "/srv/acme.%s.%d", getuser(), mainpid);
  295. fd = create(acmeerrorfile, OWRITE, 0666);
  296. if(fd < 0){
  297. remove(acmeerrorfile);
  298. fd = create(acmeerrorfile, OWRITE, 0666);
  299. if(fd < 0)
  300. error("can't create acmeerror file");
  301. }
  302. sprint(buf, "%d", pfd[0]);
  303. write(fd, buf, strlen(buf));
  304. close(fd);
  305. /* reopen pfd[1] close on exec */
  306. sprint(buf, "/fd/%d", pfd[1]);
  307. errorfd = open(buf, OREAD|OCEXEC);
  308. if(errorfd < 0)
  309. error("can't re-open acmeerror file");
  310. close(pfd[1]);
  311. close(pfd[0]);
  312. proccreate(acmeerrorproc, nil, STACK);
  313. }
  314. void
  315. plumbproc(void *v)
  316. {
  317. Plumbmsg *m;
  318. threadsetname("plumbproc");
  319. for(;;){
  320. m = plumbrecv(plumbeditfd);
  321. if(m == nil)
  322. threadexits(nil);
  323. sendp(cplumb, m);
  324. }
  325. }
  326. void
  327. keyboardthread(void *v)
  328. {
  329. Rune r;
  330. Timer *timer;
  331. Text *t;
  332. enum { KTimer, KKey, NKALT };
  333. static Alt alts[NKALT+1];
  334. alts[KTimer].c = nil;
  335. alts[KTimer].v = nil;
  336. alts[KTimer].op = CHANNOP;
  337. alts[KKey].c = keyboardctl->c;
  338. alts[KKey].v = &r;
  339. alts[KKey].op = CHANRCV;
  340. alts[NKALT].op = CHANEND;
  341. timer = nil;
  342. typetext = nil;
  343. threadsetname("keyboardthread");
  344. for(;;){
  345. switch(alt(alts)){
  346. case KTimer:
  347. timerstop(timer);
  348. t = typetext;
  349. if(t!=nil && t->what==Tag){
  350. winlock(t->w, 'K');
  351. wincommit(t->w, t);
  352. winunlock(t->w);
  353. flushimage(display, 1);
  354. }
  355. alts[KTimer].c = nil;
  356. alts[KTimer].op = CHANNOP;
  357. break;
  358. case KKey:
  359. casekeyboard:
  360. typetext = rowtype(&row, r, mouse->xy);
  361. t = typetext;
  362. if(t!=nil && t->col!=nil && !(r==Kdown || r==Kleft || r==Kright)) /* scrolling doesn't change activecol */
  363. activecol = t->col;
  364. if(t!=nil && t->w!=nil)
  365. t->w->body.file->curtext = &t->w->body;
  366. if(timer != nil)
  367. timercancel(timer);
  368. if(t!=nil && t->what==Tag) {
  369. timer = timerstart(500);
  370. alts[KTimer].c = timer->c;
  371. alts[KTimer].op = CHANRCV;
  372. }else{
  373. timer = nil;
  374. alts[KTimer].c = nil;
  375. alts[KTimer].op = CHANNOP;
  376. }
  377. if(nbrecv(keyboardctl->c, &r) > 0)
  378. goto casekeyboard;
  379. flushimage(display, 1);
  380. break;
  381. }
  382. }
  383. }
  384. void
  385. mousethread(void *v)
  386. {
  387. Text *t, *argt;
  388. int but;
  389. u32 q0, q1;
  390. Window *w;
  391. Plumbmsg *pm;
  392. Mouse m;
  393. char *act;
  394. enum { MResize, MMouse, MPlumb, MWarnings, NMALT };
  395. static Alt alts[NMALT+1];
  396. threadsetname("mousethread");
  397. alts[MResize].c = mousectl->resizec;
  398. alts[MResize].v = nil;
  399. alts[MResize].op = CHANRCV;
  400. alts[MMouse].c = mousectl->c;
  401. alts[MMouse].v = (Mouse *)mousectl;
  402. alts[MMouse].op = CHANRCV;
  403. alts[MPlumb].c = cplumb;
  404. alts[MPlumb].v = &pm;
  405. alts[MPlumb].op = CHANRCV;
  406. alts[MWarnings].c = cwarn;
  407. alts[MWarnings].v = nil;
  408. alts[MWarnings].op = CHANRCV;
  409. if(cplumb == nil)
  410. alts[MPlumb].op = CHANNOP;
  411. alts[NMALT].op = CHANEND;
  412. for(;;){
  413. qlock(&row.QLock);
  414. flushwarnings();
  415. qunlock(&row.QLock);
  416. flushimage(display, 1);
  417. switch(alt(alts)){
  418. case MResize:
  419. if(getwindow(display, Refnone) < 0)
  420. error("attach to window");
  421. scrlresize();
  422. rowresize(&row, screen->clipr);
  423. break;
  424. case MPlumb:
  425. if(strcmp(pm->type, "text") == 0){
  426. act = plumblookup(pm->attr, "action");
  427. if(act==nil || strcmp(act, "showfile")==0)
  428. plumblook(pm);
  429. else if(strcmp(act, "showdata")==0)
  430. plumbshow(pm);
  431. }
  432. plumbfree(pm);
  433. break;
  434. case MWarnings:
  435. break;
  436. case MMouse:
  437. /*
  438. * Make a copy so decisions are consistent; mousectl changes
  439. * underfoot. Can't just receive into m because this introduces
  440. * another race; see /sys/src/libdraw/mouse.c.
  441. */
  442. m = *(Mouse *)mousectl;
  443. qlock(&row.QLock);
  444. t = rowwhich(&row, m.xy);
  445. if((t!=mousetext && t!=nil && t->w!=nil) &&
  446. (mousetext==nil || mousetext->w==nil || t->w->id!=mousetext->w->id)) {
  447. xfidlog(t->w, "focus");
  448. }
  449. if(t!=mousetext && mousetext!=nil && mousetext->w!=nil){
  450. winlock(mousetext->w, 'M');
  451. mousetext->eq0 = ~0;
  452. wincommit(mousetext->w, mousetext);
  453. winunlock(mousetext->w);
  454. }
  455. mousetext = t;
  456. if(t == nil)
  457. goto Continue;
  458. w = t->w;
  459. if(t==nil || m.buttons==0)
  460. goto Continue;
  461. but = 0;
  462. if(m.buttons == 1)
  463. but = 1;
  464. else if(m.buttons == 2)
  465. but = 2;
  466. else if(m.buttons == 4)
  467. but = 3;
  468. barttext = t;
  469. if(t->what==Body && ptinrect(m.xy, t->scrollr)){
  470. if(but){
  471. winlock(w, 'M');
  472. t->eq0 = ~0;
  473. textscroll(t, but);
  474. winunlock(w);
  475. }
  476. goto Continue;
  477. }
  478. /* scroll buttons, wheels, etc. */
  479. if(t->what==Body && w != nil && (m.buttons & (8|16))){
  480. if(m.buttons & 8)
  481. but = Kscrolloneup;
  482. else
  483. but = Kscrollonedown;
  484. winlock(w, 'M');
  485. t->eq0 = ~0;
  486. texttype(t, but);
  487. winunlock(w);
  488. goto Continue;
  489. }
  490. if(ptinrect(m.xy, t->scrollr)){
  491. if(but){
  492. if(t->what == Columntag)
  493. rowdragcol(&row, t->col, but);
  494. else if(t->what == Tag){
  495. coldragwin(t->col, t->w, but);
  496. if(t->w)
  497. barttext = &t->w->body;
  498. }
  499. if(t->col)
  500. activecol = t->col;
  501. }
  502. goto Continue;
  503. }
  504. if(m.buttons){
  505. if(w)
  506. winlock(w, 'M');
  507. t->eq0 = ~0;
  508. if(w)
  509. wincommit(w, t);
  510. else
  511. textcommit(t, TRUE);
  512. if(m.buttons & 1){
  513. textselect(t);
  514. if(w)
  515. winsettag(w);
  516. argtext = t;
  517. seltext = t;
  518. if(t->col)
  519. activecol = t->col; /* button 1 only */
  520. if(t->w!=nil && t==&t->w->body)
  521. activewin = t->w;
  522. }else if(m.buttons & 2){
  523. if(textselect2(t, &q0, &q1, &argt))
  524. execute(t, q0, q1, FALSE, argt);
  525. }else if(m.buttons & 4){
  526. if(textselect3(t, &q0, &q1))
  527. look3(t, q0, q1, FALSE);
  528. }
  529. if(w)
  530. winunlock(w);
  531. goto Continue;
  532. }
  533. Continue:
  534. qunlock(&row.QLock);
  535. break;
  536. }
  537. }
  538. }
  539. /*
  540. * There is a race between process exiting and our finding out it was ever created.
  541. * This structure keeps a list of processes that have exited we haven't heard of.
  542. */
  543. typedef struct Pid Pid;
  544. struct Pid
  545. {
  546. int pid;
  547. char msg[ERRMAX];
  548. Pid *next;
  549. };
  550. void
  551. waitthread(void *v)
  552. {
  553. Waitmsg *w;
  554. Command *c, *lc;
  555. u32 pid;
  556. int found, ncmd;
  557. Rune *cmd;
  558. char *err;
  559. Text *t;
  560. Pid *pids, *p, *lastp;
  561. enum { WErr, WKill, WWait, WCmd, NWALT };
  562. Alt alts[NWALT+1];
  563. threadsetname("waitthread");
  564. pids = nil;
  565. alts[WErr].c = cerr;
  566. alts[WErr].v = &err;
  567. alts[WErr].op = CHANRCV;
  568. alts[WKill].c = ckill;
  569. alts[WKill].v = &cmd;
  570. alts[WKill].op = CHANRCV;
  571. alts[WWait].c = cwait;
  572. alts[WWait].v = &w;
  573. alts[WWait].op = CHANRCV;
  574. alts[WCmd].c = ccommand;
  575. alts[WCmd].v = &c;
  576. alts[WCmd].op = CHANRCV;
  577. alts[NWALT].op = CHANEND;
  578. command = nil;
  579. for(;;){
  580. switch(alt(alts)){
  581. case WErr:
  582. qlock(&row.QLock);
  583. warning(nil, "%s", err);
  584. free(err);
  585. flushimage(display, 1);
  586. qunlock(&row.QLock);
  587. break;
  588. case WKill:
  589. found = FALSE;
  590. ncmd = runestrlen(cmd);
  591. for(c=command; c; c=c->next){
  592. /* -1 for blank */
  593. if(runeeq(c->name, c->nname-1, cmd, ncmd) == TRUE){
  594. if(postnote(PNGROUP, c->pid, "kill") < 0)
  595. warning(nil, "kill %S: %r\n", cmd);
  596. found = TRUE;
  597. }
  598. }
  599. if(!found)
  600. warning(nil, "Kill: no process %S\n", cmd);
  601. free(cmd);
  602. break;
  603. case WWait:
  604. pid = w->pid;
  605. lc = nil;
  606. for(c=command; c; c=c->next){
  607. if(c->pid == pid){
  608. if(lc)
  609. lc->next = c->next;
  610. else
  611. command = c->next;
  612. break;
  613. }
  614. lc = c;
  615. }
  616. qlock(&row.QLock);
  617. t = &row.tag;
  618. textcommit(t, TRUE);
  619. if(c == nil){
  620. /* helper processes use this exit status */
  621. if(strncmp(w->msg, "libthread", 9) != 0){
  622. p = emalloc(sizeof(Pid));
  623. p->pid = pid;
  624. strncpy(p->msg, w->msg, sizeof(p->msg));
  625. p->next = pids;
  626. pids = p;
  627. }
  628. }else{
  629. if(search(t, c->name, c->nname)){
  630. textdelete(t, t->q0, t->q1, TRUE);
  631. textsetselect(t, 0, 0);
  632. }
  633. if(w->msg[0])
  634. warning(c->md, "%s\n", w->msg);
  635. flushimage(display, 1);
  636. }
  637. qunlock(&row.QLock);
  638. free(w);
  639. Freecmd:
  640. if(c){
  641. if(c->iseditcmd)
  642. sendul(cedit, 0);
  643. free(c->text);
  644. free(c->name);
  645. fsysdelid(c->md);
  646. free(c);
  647. }
  648. break;
  649. case WCmd:
  650. /* has this command already exited? */
  651. lastp = nil;
  652. for(p=pids; p!=nil; p=p->next){
  653. if(p->pid == c->pid){
  654. if(p->msg[0])
  655. warning(c->md, "%s\n", p->msg);
  656. if(lastp == nil)
  657. pids = p->next;
  658. else
  659. lastp->next = p->next;
  660. free(p);
  661. goto Freecmd;
  662. }
  663. lastp = p;
  664. }
  665. c->next = command;
  666. command = c;
  667. qlock(&row.QLock);
  668. t = &row.tag;
  669. textcommit(t, TRUE);
  670. textinsert(t, 0, c->name, c->nname, TRUE);
  671. textsetselect(t, 0, 0);
  672. flushimage(display, 1);
  673. qunlock(&row.QLock);
  674. break;
  675. }
  676. }
  677. }
  678. void
  679. xfidallocthread(void*v)
  680. {
  681. Xfid *xfree, *x;
  682. enum { Alloc, Free, N };
  683. static Alt alts[N+1];
  684. threadsetname("xfidallocthread");
  685. alts[Alloc].c = cxfidalloc;
  686. alts[Alloc].v = nil;
  687. alts[Alloc].op = CHANRCV;
  688. alts[Free].c = cxfidfree;
  689. alts[Free].v = &x;
  690. alts[Free].op = CHANRCV;
  691. alts[N].op = CHANEND;
  692. xfree = nil;
  693. for(;;){
  694. switch(alt(alts)){
  695. case Alloc:
  696. x = xfree;
  697. if(x)
  698. xfree = x->next;
  699. else{
  700. x = emalloc(sizeof(Xfid));
  701. x->c = chancreate(sizeof(void(*)(Xfid*)), 0);
  702. x->arg = x;
  703. threadcreate(xfidctl, x->arg, STACK);
  704. }
  705. sendp(cxfidalloc, x);
  706. break;
  707. case Free:
  708. x->next = xfree;
  709. xfree = x;
  710. break;
  711. }
  712. }
  713. }
  714. /* this thread, in the main proc, allows fsysproc to get a window made without doing graphics */
  715. void
  716. newwindowthread(void*v)
  717. {
  718. Window *w;
  719. threadsetname("newwindowthread");
  720. for(;;){
  721. /* only fsysproc is talking to us, so synchronization is trivial */
  722. recvp(cnewwindow);
  723. w = makenewwindow(nil);
  724. winsettag(w);
  725. xfidlog(w, "new");
  726. sendp(cnewwindow, w);
  727. }
  728. }
  729. Reffont*
  730. rfget(int fix, int save, int setfont, char *name)
  731. {
  732. Reffont *r;
  733. Font *f;
  734. int i;
  735. r = nil;
  736. if(name == nil){
  737. name = fontnames[fix];
  738. r = reffonts[fix];
  739. }
  740. if(r == nil){
  741. for(i=0; i<nfontcache; i++)
  742. if(strcmp(name, fontcache[i]->f->name) == 0){
  743. r = fontcache[i];
  744. goto Found;
  745. }
  746. f = openfont(display, name);
  747. if(f == nil){
  748. warning(nil, "can't open font file %s: %r\n", name);
  749. return nil;
  750. }
  751. r = emalloc(sizeof(Reffont));
  752. r->f = f;
  753. fontcache = erealloc(fontcache, (nfontcache+1)*sizeof(Reffont*));
  754. fontcache[nfontcache++] = r;
  755. }
  756. Found:
  757. if(save){
  758. incref(&r->Ref);
  759. if(reffonts[fix])
  760. rfclose(reffonts[fix]);
  761. reffonts[fix] = r;
  762. if(name != fontnames[fix]){
  763. free(fontnames[fix]);
  764. fontnames[fix] = estrdup(name);
  765. }
  766. }
  767. if(setfont){
  768. reffont.f = r->f;
  769. incref(&r->Ref);
  770. rfclose(reffonts[0]);
  771. font = r->f;
  772. reffonts[0] = r;
  773. incref(&r->Ref);
  774. iconinit();
  775. }
  776. incref(&r->Ref);
  777. return r;
  778. }
  779. void
  780. rfclose(Reffont *r)
  781. {
  782. int i;
  783. if(decref(&r->Ref) == 0){
  784. for(i=0; i<nfontcache; i++)
  785. if(r == fontcache[i])
  786. break;
  787. if(i >= nfontcache)
  788. warning(nil, "internal error: can't find font in cache\n");
  789. else{
  790. nfontcache--;
  791. memmove(fontcache+i, fontcache+i+1, (nfontcache-i)*sizeof(Reffont*));
  792. }
  793. freefont(r->f);
  794. free(r);
  795. }
  796. }
  797. Cursor boxcursor = {
  798. {-7, -7},
  799. {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  800. 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F,
  801. 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF,
  802. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
  803. {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE,
  804. 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
  805. 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
  806. 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00}
  807. };
  808. void
  809. iconinit(void)
  810. {
  811. Rectangle r;
  812. Image *tmp;
  813. /* Blue */
  814. tagcols[BACK] = allocimagemix(display, DPalebluegreen, DWhite);
  815. tagcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen);
  816. tagcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue);
  817. tagcols[TEXT] = display->black;
  818. tagcols[HTEXT] = display->black;
  819. /* Yellow */
  820. textcols[BACK] = allocimagemix(display, DPaleyellow, DWhite);
  821. textcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow);
  822. textcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DYellowgreen);
  823. textcols[TEXT] = display->black;
  824. textcols[HTEXT] = display->black;
  825. if(button){
  826. freeimage(button);
  827. freeimage(modbutton);
  828. freeimage(colbutton);
  829. }
  830. r = Rect(0, 0, Scrollwid+2, font->height+1);
  831. button = allocimage(display, r, screen->chan, 0, DNofill);
  832. draw(button, r, tagcols[BACK], nil, r.min);
  833. r.max.x -= 2;
  834. border(button, r, 2, tagcols[BORD], ZP);
  835. r = button->r;
  836. modbutton = allocimage(display, r, screen->chan, 0, DNofill);
  837. draw(modbutton, r, tagcols[BACK], nil, r.min);
  838. r.max.x -= 2;
  839. border(modbutton, r, 2, tagcols[BORD], ZP);
  840. r = insetrect(r, 2);
  841. tmp = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedblue);
  842. draw(modbutton, r, tmp, nil, ZP);
  843. freeimage(tmp);
  844. r = button->r;
  845. colbutton = allocimage(display, r, screen->chan, 0, DPurpleblue);
  846. but2col = allocimage(display, r, screen->chan, 1, 0xAA0000FF);
  847. but3col = allocimage(display, r, screen->chan, 1, 0x006600FF);
  848. }
  849. /*
  850. * /dev/snarf updates when the file is closed, so we must open our own
  851. * fd here rather than use snarffd
  852. */
  853. /* rio truncates larges snarf buffers, so this avoids using the
  854. * service if the string is huge */
  855. #define MAXSNARF 100*1024
  856. void
  857. putsnarf(void)
  858. {
  859. int fd, i, n;
  860. if(snarffd<0 || snarfbuf.nc==0)
  861. return;
  862. if(snarfbuf.nc > MAXSNARF)
  863. return;
  864. fd = open("/dev/snarf", OWRITE);
  865. if(fd < 0)
  866. return;
  867. for(i=0; i<snarfbuf.nc; i+=n){
  868. n = snarfbuf.nc-i;
  869. if(n >= NSnarf)
  870. n = NSnarf;
  871. bufread(&snarfbuf, i, snarfrune, n);
  872. if(fprint(fd, "%.*S", n, snarfrune) < 0)
  873. break;
  874. }
  875. close(fd);
  876. }
  877. void
  878. getsnarf()
  879. {
  880. int nulls;
  881. if(snarfbuf.nc > MAXSNARF)
  882. return;
  883. if(snarffd < 0)
  884. return;
  885. seek(snarffd, 0, 0);
  886. bufreset(&snarfbuf);
  887. bufload(&snarfbuf, 0, snarffd, &nulls);
  888. }