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