wind.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <thread.h>
  5. #include <cursor.h>
  6. #include <mouse.h>
  7. #include <keyboard.h>
  8. #include <frame.h>
  9. #include <fcall.h>
  10. #include <plumb.h>
  11. #include <complete.h>
  12. #include "dat.h"
  13. #include "fns.h"
  14. #define MOVEIT if(0)
  15. enum
  16. {
  17. HiWater = 640000, /* max size of history */
  18. LoWater = 400000, /* min size of history after max'ed */
  19. MinWater = 20000, /* room to leave available when reallocating */
  20. };
  21. static int topped;
  22. static int id;
  23. static Image *cols[NCOL];
  24. static Image *grey;
  25. static Image *darkgrey;
  26. static Cursor *lastcursor;
  27. static Image *titlecol;
  28. static Image *lighttitlecol;
  29. static Image *holdcol;
  30. static Image *lightholdcol;
  31. static Image *paleholdcol;
  32. Window*
  33. wmk(Image *i, Mousectl *mc, Channel *ck, Channel *cctl, int scrolling)
  34. {
  35. Window *w;
  36. Rectangle r;
  37. if(cols[0] == nil){
  38. /* greys are multiples of 0x11111100+0xFF, 14* being palest */
  39. grey = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
  40. darkgrey = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x666666FF);
  41. cols[BACK] = display->white;
  42. cols[HIGH] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
  43. cols[BORD] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x999999FF);
  44. cols[TEXT] = display->black;
  45. cols[HTEXT] = display->black;
  46. titlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreygreen);
  47. lighttitlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreygreen);
  48. holdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DMedblue);
  49. lightholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreyblue);
  50. paleholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreyblue);
  51. }
  52. w = emalloc(sizeof(Window));
  53. w->screenr = i->r;
  54. r = insetrect(i->r, Selborder+1);
  55. w->i = i;
  56. w->mc = *mc;
  57. w->ck = ck;
  58. w->cctl = cctl;
  59. w->cursorp = nil;
  60. w->conswrite = chancreate(sizeof(Conswritemesg), 0);
  61. w->consread = chancreate(sizeof(Consreadmesg), 0);
  62. w->mouseread = chancreate(sizeof(Mousereadmesg), 0);
  63. w->wctlread = chancreate(sizeof(Consreadmesg), 0);
  64. w->scrollr = r;
  65. w->scrollr.max.x = r.min.x+Scrollwid;
  66. w->lastsr = ZR;
  67. r.min.x += Scrollwid+Scrollgap;
  68. frinit(w, r, font, i, cols);
  69. w->maxtab = maxtab*stringwidth(font, "0");
  70. w->topped = ++topped;
  71. w->id = ++id;
  72. w->notefd = -1;
  73. w->scrolling = scrolling;
  74. w->dir = estrdup(startdir);
  75. w->label = estrdup("<unnamed>");
  76. r = insetrect(w->i->r, Selborder);
  77. draw(w->i, r, cols[BACK], nil, w->entire.min);
  78. wborder(w, Selborder);
  79. wscrdraw(w);
  80. incref(w); /* ref will be removed after mounting; avoids delete before ready to be deleted */
  81. return w;
  82. }
  83. void
  84. wsetname(Window *w)
  85. {
  86. int i, n;
  87. char err[ERRMAX];
  88. n = sprint(w->name, "window.%d.%d", w->id, w->namecount++);
  89. for(i='A'; i<='Z'; i++){
  90. if(nameimage(w->i, w->name, 1) > 0)
  91. return;
  92. errstr(err, sizeof err);
  93. if(strcmp(err, "image name in use") != 0)
  94. break;
  95. w->name[n] = i;
  96. w->name[n+1] = 0;
  97. }
  98. w->name[0] = 0;
  99. fprint(2, "rio: setname failed: %s\n", err);
  100. }
  101. void
  102. wresize(Window *w, Image *i, int move)
  103. {
  104. Rectangle r, or;
  105. or = w->i->r;
  106. if(move || (Dx(or)==Dx(i->r) && Dy(or)==Dy(i->r)))
  107. draw(i, i->r, w->i, nil, w->i->r.min);
  108. freeimage(w->i);
  109. w->i = i;
  110. wsetname(w);
  111. w->mc.image = i;
  112. r = insetrect(i->r, Selborder+1);
  113. w->scrollr = r;
  114. w->scrollr.max.x = r.min.x+Scrollwid;
  115. w->lastsr = ZR;
  116. r.min.x += Scrollwid+Scrollgap;
  117. if(move)
  118. frsetrects(w, r, w->i);
  119. else{
  120. frclear(w, FALSE);
  121. frinit(w, r, w->font, w->i, cols);
  122. wsetcols(w);
  123. w->maxtab = maxtab*stringwidth(w->font, "0");
  124. r = insetrect(w->i->r, Selborder);
  125. draw(w->i, r, cols[BACK], nil, w->entire.min);
  126. wfill(w);
  127. wsetselect(w, w->q0, w->q1);
  128. wscrdraw(w);
  129. }
  130. wborder(w, Selborder);
  131. w->topped = ++topped;
  132. w->resized = TRUE;
  133. w->mouse.counter++;
  134. }
  135. void
  136. wrefresh(Window *w, Rectangle)
  137. {
  138. /* BUG: rectangle is ignored */
  139. if(w == input)
  140. wborder(w, Selborder);
  141. else
  142. wborder(w, Unselborder);
  143. if(w->mouseopen)
  144. return;
  145. draw(w->i, insetrect(w->i->r, Borderwidth), w->cols[BACK], nil, w->i->r.min);
  146. w->ticked = 0;
  147. if(w->p0 > 0)
  148. frdrawsel(w, frptofchar(w, 0), 0, w->p0, 0);
  149. if(w->p1 < w->nchars)
  150. frdrawsel(w, frptofchar(w, w->p1), w->p1, w->nchars, 0);
  151. frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 1);
  152. w->lastsr = ZR;
  153. wscrdraw(w);
  154. }
  155. int
  156. wclose(Window *w)
  157. {
  158. int i;
  159. i = decref(w);
  160. if(i > 0)
  161. return 0;
  162. if(i < 0)
  163. error("negative ref count");
  164. if(!w->deleted)
  165. wclosewin(w);
  166. wsendctlmesg(w, Exited, ZR, nil);
  167. return 1;
  168. }
  169. void
  170. winctl(void *arg)
  171. {
  172. Rune *rp, *bp, *tp, *up, *kbdr;
  173. uint qh;
  174. int nr, nb, c, wid, i, npart, initial, lastb;
  175. char *s, *t, part[3];
  176. Window *w;
  177. Mousestate *mp, m;
  178. enum { WKey, WMouse, WMouseread, WCtl, WCwrite, WCread, WWread, NWALT };
  179. Alt alts[NWALT+1];
  180. Mousereadmesg mrm;
  181. Conswritemesg cwm;
  182. Consreadmesg crm;
  183. Consreadmesg cwrm;
  184. Stringpair pair;
  185. Wctlmesg wcm;
  186. char buf[4*12+1];
  187. w = arg;
  188. snprint(buf, sizeof buf, "winctl-id%d", w->id);
  189. threadsetname(buf);
  190. mrm.cm = chancreate(sizeof(Mouse), 0);
  191. cwm.cw = chancreate(sizeof(Stringpair), 0);
  192. crm.c1 = chancreate(sizeof(Stringpair), 0);
  193. crm.c2 = chancreate(sizeof(Stringpair), 0);
  194. cwrm.c1 = chancreate(sizeof(Stringpair), 0);
  195. cwrm.c2 = chancreate(sizeof(Stringpair), 0);
  196. alts[WKey].c = w->ck;
  197. alts[WKey].v = &kbdr;
  198. alts[WKey].op = CHANRCV;
  199. alts[WMouse].c = w->mc.c;
  200. alts[WMouse].v = &w->mc.Mouse;
  201. alts[WMouse].op = CHANRCV;
  202. alts[WMouseread].c = w->mouseread;
  203. alts[WMouseread].v = &mrm;
  204. alts[WMouseread].op = CHANSND;
  205. alts[WCtl].c = w->cctl;
  206. alts[WCtl].v = &wcm;
  207. alts[WCtl].op = CHANRCV;
  208. alts[WCwrite].c = w->conswrite;
  209. alts[WCwrite].v = &cwm;
  210. alts[WCwrite].op = CHANSND;
  211. alts[WCread].c = w->consread;
  212. alts[WCread].v = &crm;
  213. alts[WCread].op = CHANSND;
  214. alts[WWread].c = w->wctlread;
  215. alts[WWread].v = &cwrm;
  216. alts[WWread].op = CHANSND;
  217. alts[NWALT].op = CHANEND;
  218. npart = 0;
  219. lastb = -1;
  220. for(;;){
  221. if(w->mouseopen && w->mouse.counter != w->mouse.lastcounter)
  222. alts[WMouseread].op = CHANSND;
  223. else
  224. alts[WMouseread].op = CHANNOP;
  225. if(!w->scrolling && !w->mouseopen && w->qh>w->org+w->nchars)
  226. alts[WCwrite].op = CHANNOP;
  227. else
  228. alts[WCwrite].op = CHANSND;
  229. if(w->deleted || !w->wctlready)
  230. alts[WWread].op = CHANNOP;
  231. else
  232. alts[WWread].op = CHANSND;
  233. /* this code depends on NL and EOT fitting in a single byte */
  234. /* kind of expensive for each loop; worth precomputing? */
  235. if(w->holding)
  236. alts[WCread].op = CHANNOP;
  237. else if(npart || (w->rawing && w->nraw>0))
  238. alts[WCread].op = CHANSND;
  239. else{
  240. alts[WCread].op = CHANNOP;
  241. for(i=w->qh; i<w->nr; i++){
  242. c = w->r[i];
  243. if(c=='\n' || c=='\004'){
  244. alts[WCread].op = CHANSND;
  245. break;
  246. }
  247. }
  248. }
  249. switch(alt(alts)){
  250. case WKey:
  251. for(i=0; kbdr[i]!=L'\0'; i++)
  252. wkeyctl(w, kbdr[i]);
  253. // wkeyctl(w, r);
  254. /// while(nbrecv(w->ck, &r))
  255. // wkeyctl(w, r);
  256. break;
  257. case WMouse:
  258. if(w->mouseopen) {
  259. w->mouse.counter++;
  260. /* queue click events */
  261. if(!w->mouse.qfull && lastb != w->mc.buttons) { /* add to ring */
  262. mp = &w->mouse.queue[w->mouse.wi];
  263. if(++w->mouse.wi == nelem(w->mouse.queue))
  264. w->mouse.wi = 0;
  265. if(w->mouse.wi == w->mouse.ri)
  266. w->mouse.qfull = TRUE;
  267. mp->Mouse = w->mc;
  268. mp->counter = w->mouse.counter;
  269. lastb = w->mc.buttons;
  270. }
  271. } else
  272. wmousectl(w);
  273. break;
  274. case WMouseread:
  275. /* send a queued event or, if the queue is empty, the current state */
  276. /* if the queue has filled, we discard all the events it contained. */
  277. /* the intent is to discard frantic clicking by the user during long latencies. */
  278. w->mouse.qfull = FALSE;
  279. if(w->mouse.wi != w->mouse.ri) {
  280. m = w->mouse.queue[w->mouse.ri];
  281. if(++w->mouse.ri == nelem(w->mouse.queue))
  282. w->mouse.ri = 0;
  283. } else
  284. m = (Mousestate){w->mc.Mouse, w->mouse.counter};
  285. w->mouse.lastcounter = m.counter;
  286. send(mrm.cm, &m.Mouse);
  287. continue;
  288. case WCtl:
  289. if(wctlmesg(w, wcm.type, wcm.r, wcm.image) == Exited){
  290. chanfree(crm.c1);
  291. chanfree(crm.c2);
  292. chanfree(mrm.cm);
  293. chanfree(cwm.cw);
  294. chanfree(cwrm.c1);
  295. chanfree(cwrm.c2);
  296. threadexits(nil);
  297. }
  298. continue;
  299. case WCwrite:
  300. recv(cwm.cw, &pair);
  301. rp = pair.s;
  302. nr = pair.ns;
  303. bp = rp;
  304. for(i=0; i<nr; i++)
  305. if(*bp++ == '\b'){
  306. --bp;
  307. initial = 0;
  308. tp = runemalloc(nr);
  309. runemove(tp, rp, i);
  310. up = tp+i;
  311. for(; i<nr; i++){
  312. *up = *bp++;
  313. if(*up == '\b')
  314. if(up == tp)
  315. initial++;
  316. else
  317. --up;
  318. else
  319. up++;
  320. }
  321. if(initial){
  322. if(initial > w->qh)
  323. initial = w->qh;
  324. qh = w->qh-initial;
  325. wdelete(w, qh, qh+initial);
  326. w->qh = qh;
  327. }
  328. free(rp);
  329. rp = tp;
  330. nr = up-tp;
  331. rp[nr] = 0;
  332. break;
  333. }
  334. w->qh = winsert(w, rp, nr, w->qh)+nr;
  335. if(w->scrolling || w->mouseopen)
  336. wshow(w, w->qh);
  337. wsetselect(w, w->q0, w->q1);
  338. wscrdraw(w);
  339. free(rp);
  340. break;
  341. case WCread:
  342. recv(crm.c1, &pair);
  343. t = pair.s;
  344. nb = pair.ns;
  345. i = npart;
  346. npart = 0;
  347. if(i)
  348. memmove(t, part, i);
  349. while(i<nb && (w->qh<w->nr || w->nraw>0)){
  350. if(w->qh == w->nr){
  351. wid = runetochar(t+i, &w->raw[0]);
  352. w->nraw--;
  353. runemove(w->raw, w->raw+1, w->nraw);
  354. }else
  355. wid = runetochar(t+i, &w->r[w->qh++]);
  356. c = t[i]; /* knows break characters fit in a byte */
  357. i += wid;
  358. if(!w->rawing && (c == '\n' || c=='\004')){
  359. if(c == '\004')
  360. i--;
  361. break;
  362. }
  363. }
  364. if(i==nb && w->qh<w->nr && w->r[w->qh]=='\004')
  365. w->qh++;
  366. if(i > nb){
  367. npart = i-nb;
  368. memmove(part, t+nb, npart);
  369. i = nb;
  370. }
  371. pair.s = t;
  372. pair.ns = i;
  373. send(crm.c2, &pair);
  374. continue;
  375. case WWread:
  376. w->wctlready = 0;
  377. recv(cwrm.c1, &pair);
  378. if(w->deleted || w->i==nil)
  379. pair.ns = sprint(pair.s, "");
  380. else{
  381. s = "visible";
  382. for(i=0; i<nhidden; i++)
  383. if(hidden[i] == w){
  384. s = "hidden";
  385. break;
  386. }
  387. t = "notcurrent";
  388. if(w == input)
  389. t = "current";
  390. pair.ns = snprint(pair.s, pair.ns, "%11d %11d %11d %11d %s %s ",
  391. w->i->r.min.x, w->i->r.min.y, w->i->r.max.x, w->i->r.max.y, t, s);
  392. }
  393. send(cwrm.c2, &pair);
  394. continue;
  395. }
  396. if(!w->deleted)
  397. flushimage(display, 1);
  398. }
  399. }
  400. void
  401. waddraw(Window *w, Rune *r, int nr)
  402. {
  403. w->raw = runerealloc(w->raw, w->nraw+nr);
  404. runemove(w->raw+w->nraw, r, nr);
  405. w->nraw += nr;
  406. }
  407. /*
  408. * Need to do this in a separate proc because if process we're interrupting
  409. * is dying and trying to print tombstone, kernel is blocked holding p->debug lock.
  410. */
  411. void
  412. interruptproc(void *v)
  413. {
  414. int *notefd;
  415. notefd = v;
  416. write(*notefd, "interrupt", 9);
  417. free(notefd);
  418. }
  419. int
  420. windfilewidth(Window *w, uint q0, int oneelement)
  421. {
  422. uint q;
  423. Rune r;
  424. q = q0;
  425. while(q > 0){
  426. r = w->r[q-1];
  427. if(r<=' ')
  428. break;
  429. if(oneelement && r=='/')
  430. break;
  431. --q;
  432. }
  433. return q0-q;
  434. }
  435. void
  436. showcandidates(Window *w, Completion *c)
  437. {
  438. int i;
  439. Fmt f;
  440. Rune *rp;
  441. uint nr, qline, q0;
  442. char *s;
  443. runefmtstrinit(&f);
  444. if (c->nmatch == 0)
  445. s = "[no matches in ";
  446. else
  447. s = "[";
  448. if(c->nfile > 32)
  449. fmtprint(&f, "%s%d files]\n", s, c->nfile);
  450. else{
  451. fmtprint(&f, "%s", s);
  452. for(i=0; i<c->nfile; i++){
  453. if(i > 0)
  454. fmtprint(&f, " ");
  455. fmtprint(&f, "%s", c->filename[i]);
  456. }
  457. fmtprint(&f, "]\n");
  458. }
  459. /* place text at beginning of line before host point */
  460. qline = w->qh;
  461. while(qline>0 && w->r[qline-1] != '\n')
  462. qline--;
  463. rp = runefmtstrflush(&f);
  464. nr = runestrlen(rp);
  465. q0 = w->q0;
  466. q0 += winsert(w, rp, runestrlen(rp), qline) - qline;
  467. free(rp);
  468. wsetselect(w, q0+nr, q0+nr);
  469. }
  470. Rune*
  471. namecomplete(Window *w)
  472. {
  473. int nstr, npath;
  474. Rune *rp, *path, *str;
  475. Completion *c;
  476. char *s, *dir, *root;
  477. /* control-f: filename completion; works back to white space or / */
  478. if(w->q0<w->nr && w->r[w->q0]>' ') /* must be at end of word */
  479. return nil;
  480. nstr = windfilewidth(w, w->q0, TRUE);
  481. str = runemalloc(nstr);
  482. runemove(str, w->r+(w->q0-nstr), nstr);
  483. npath = windfilewidth(w, w->q0-nstr, FALSE);
  484. path = runemalloc(npath);
  485. runemove(path, w->r+(w->q0-nstr-npath), npath);
  486. rp = nil;
  487. /* is path rooted? if not, we need to make it relative to window path */
  488. if(npath>0 && path[0]=='/'){
  489. dir = malloc(UTFmax*npath+1);
  490. sprint(dir, "%.*S", npath, path);
  491. }else{
  492. if(strcmp(w->dir, "") == 0)
  493. root = ".";
  494. else
  495. root = w->dir;
  496. dir = malloc(strlen(root)+1+UTFmax*npath+1);
  497. sprint(dir, "%s/%.*S", root, npath, path);
  498. }
  499. dir = cleanname(dir);
  500. s = smprint("%.*S", nstr, str);
  501. c = complete(dir, s);
  502. free(s);
  503. if(c == nil)
  504. goto Return;
  505. if(!c->advance)
  506. showcandidates(w, c);
  507. if(c->advance)
  508. rp = runesmprint("%s", c->string);
  509. Return:
  510. freecompletion(c);
  511. free(dir);
  512. free(path);
  513. free(str);
  514. return rp;
  515. }
  516. void
  517. wkeyctl(Window *w, Rune r)
  518. {
  519. uint q0 ,q1;
  520. int n, nb, nr;
  521. Rune *rp;
  522. int *notefd;
  523. if(r == 0)
  524. return;
  525. if(w->deleted)
  526. return;
  527. /* navigation keys work only when mouse is not open */
  528. if(!w->mouseopen)
  529. switch(r){
  530. case Kdown:
  531. n = w->maxlines/3;
  532. goto case_Down;
  533. case Kscrollonedown:
  534. n = mousescrollsize(w->maxlines);
  535. if(n <= 0)
  536. n = 1;
  537. goto case_Down;
  538. case Kpgdown:
  539. n = 2*w->maxlines/3;
  540. case_Down:
  541. q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+n*w->font->height));
  542. wsetorigin(w, q0, TRUE);
  543. return;
  544. case Kup:
  545. n = w->maxlines/3;
  546. goto case_Up;
  547. case Kscrolloneup:
  548. n = mousescrollsize(w->maxlines);
  549. if(n <= 0)
  550. n = 1;
  551. goto case_Up;
  552. case Kpgup:
  553. n = 2*w->maxlines/3;
  554. case_Up:
  555. q0 = wbacknl(w, w->org, n);
  556. wsetorigin(w, q0, TRUE);
  557. return;
  558. case Kleft:
  559. if(w->q0 > 0){
  560. q0 = w->q0-1;
  561. wsetselect(w, q0, q0);
  562. wshow(w, q0);
  563. }
  564. return;
  565. case Kright:
  566. if(w->q1 < w->nr){
  567. q1 = w->q1+1;
  568. wsetselect(w, q1, q1);
  569. wshow(w, q1);
  570. }
  571. return;
  572. case Khome:
  573. wshow(w, 0);
  574. return;
  575. case Kend:
  576. wshow(w, w->nr);
  577. return;
  578. case 0x01: /* ^A: beginning of line */
  579. if(w->q0==0 || w->q0==w->qh || w->r[w->q0-1]=='\n')
  580. return;
  581. nb = wbswidth(w, 0x15 /* ^U */);
  582. wsetselect(w, w->q0-nb, w->q0-nb);
  583. wshow(w, w->q0);
  584. return;
  585. case 0x05: /* ^E: end of line */
  586. q0 = w->q0;
  587. while(q0 < w->nr && w->r[q0]!='\n')
  588. q0++;
  589. wsetselect(w, q0, q0);
  590. wshow(w, w->q0);
  591. return;
  592. }
  593. if(w->rawing && (w->q0==w->nr || w->mouseopen)){
  594. waddraw(w, &r, 1);
  595. return;
  596. }
  597. if(r==0x1B || (w->holding && r==0x7F)){ /* toggle hold */
  598. if(w->holding)
  599. --w->holding;
  600. else
  601. w->holding++;
  602. wrepaint(w);
  603. if(r == 0x1B)
  604. return;
  605. }
  606. if(r != 0x7F){
  607. wsnarf(w);
  608. wcut(w);
  609. }
  610. switch(r){
  611. case 0x7F: /* send interrupt */
  612. w->qh = w->nr;
  613. wshow(w, w->qh);
  614. notefd = emalloc(sizeof(int));
  615. *notefd = w->notefd;
  616. proccreate(interruptproc, notefd, 4096);
  617. return;
  618. case 0x06: /* ^F: file name completion */
  619. case Kins: /* Insert: file name completion */
  620. rp = namecomplete(w);
  621. if(rp == nil)
  622. return;
  623. nr = runestrlen(rp);
  624. q0 = w->q0;
  625. q0 = winsert(w, rp, nr, q0);
  626. wshow(w, q0+nr);
  627. free(rp);
  628. return;
  629. case 0x08: /* ^H: erase character */
  630. case 0x15: /* ^U: erase line */
  631. case 0x17: /* ^W: erase word */
  632. if(w->q0==0 || w->q0==w->qh)
  633. return;
  634. nb = wbswidth(w, r);
  635. q1 = w->q0;
  636. q0 = q1-nb;
  637. if(q0 < w->org){
  638. q0 = w->org;
  639. nb = q1-q0;
  640. }
  641. if(nb > 0){
  642. wdelete(w, q0, q0+nb);
  643. wsetselect(w, q0, q0);
  644. }
  645. return;
  646. }
  647. /* otherwise ordinary character; just insert */
  648. q0 = w->q0;
  649. q0 = winsert(w, &r, 1, q0);
  650. wshow(w, q0+1);
  651. }
  652. void
  653. wsetcols(Window *w)
  654. {
  655. if(w->holding)
  656. if(w == input)
  657. w->cols[TEXT] = w->cols[HTEXT] = holdcol;
  658. else
  659. w->cols[TEXT] = w->cols[HTEXT] = lightholdcol;
  660. else
  661. if(w == input)
  662. w->cols[TEXT] = w->cols[HTEXT] = display->black;
  663. else
  664. w->cols[TEXT] = w->cols[HTEXT] = darkgrey;
  665. }
  666. void
  667. wrepaint(Window *w)
  668. {
  669. wsetcols(w);
  670. if(!w->mouseopen){
  671. if(font->maxdepth > 1)
  672. draw(w->Frame.b, w->Frame.r, cols[BACK], nil, ZP);
  673. _frredraw(w, w->Frame.r.min);
  674. }
  675. if(w == input){
  676. wborder(w, Selborder);
  677. wsetcursor(w, 0);
  678. }else
  679. wborder(w, Unselborder);
  680. }
  681. int
  682. wbswidth(Window *w, Rune c)
  683. {
  684. uint q, eq, stop;
  685. Rune r;
  686. int skipping;
  687. /* there is known to be at least one character to erase */
  688. if(c == 0x08) /* ^H: erase character */
  689. return 1;
  690. q = w->q0;
  691. stop = 0;
  692. if(q > w->qh)
  693. stop = w->qh;
  694. skipping = TRUE;
  695. while(q > stop){
  696. r = w->r[q-1];
  697. if(r == '\n'){ /* eat at most one more character */
  698. if(q == w->q0) /* eat the newline */
  699. --q;
  700. break;
  701. }
  702. if(c == 0x17){
  703. eq = isalnum(r);
  704. if(eq && skipping) /* found one; stop skipping */
  705. skipping = FALSE;
  706. else if(!eq && !skipping)
  707. break;
  708. }
  709. --q;
  710. }
  711. return w->q0-q;
  712. }
  713. void
  714. wsnarf(Window *w)
  715. {
  716. if(w->q1 == w->q0)
  717. return;
  718. nsnarf = w->q1-w->q0;
  719. snarf = runerealloc(snarf, nsnarf);
  720. snarfversion++; /* maybe modified by parent */
  721. runemove(snarf, w->r+w->q0, nsnarf);
  722. putsnarf();
  723. }
  724. void
  725. wcut(Window *w)
  726. {
  727. if(w->q1 == w->q0)
  728. return;
  729. wdelete(w, w->q0, w->q1);
  730. wsetselect(w, w->q0, w->q0);
  731. }
  732. void
  733. wpaste(Window *w)
  734. {
  735. uint q0;
  736. if(nsnarf == 0)
  737. return;
  738. wcut(w);
  739. q0 = w->q0;
  740. if(w->rawing && q0==w->nr){
  741. waddraw(w, snarf, nsnarf);
  742. wsetselect(w, q0, q0);
  743. }else{
  744. q0 = winsert(w, snarf, nsnarf, w->q0);
  745. wsetselect(w, q0, q0+nsnarf);
  746. }
  747. }
  748. void
  749. wplumb(Window *w)
  750. {
  751. Plumbmsg *m;
  752. static int fd = -2;
  753. char buf[32];
  754. uint p0, p1;
  755. Cursor *c;
  756. if(fd == -2)
  757. fd = plumbopen("send", OWRITE|OCEXEC);
  758. if(fd < 0)
  759. return;
  760. m = emalloc(sizeof(Plumbmsg));
  761. m->src = estrdup("rio");
  762. m->dst = nil;
  763. m->wdir = estrdup(w->dir);
  764. m->type = estrdup("text");
  765. p0 = w->q0;
  766. p1 = w->q1;
  767. if(w->q1 > w->q0)
  768. m->attr = nil;
  769. else{
  770. while(p0>0 && w->r[p0-1]!=' ' && w->r[p0-1]!='\t' && w->r[p0-1]!='\n')
  771. p0--;
  772. while(p1<w->nr && w->r[p1]!=' ' && w->r[p1]!='\t' && w->r[p1]!='\n')
  773. p1++;
  774. sprint(buf, "click=%d", w->q0-p0);
  775. m->attr = plumbunpackattr(buf);
  776. }
  777. if(p1-p0 > messagesize-1024){
  778. plumbfree(m);
  779. return; /* too large for 9P */
  780. }
  781. m->data = runetobyte(w->r+p0, p1-p0, &m->ndata);
  782. if(plumbsend(fd, m) < 0){
  783. c = lastcursor;
  784. riosetcursor(&query, 1);
  785. sleep(300);
  786. riosetcursor(c, 1);
  787. }
  788. plumbfree(m);
  789. }
  790. int
  791. winborder(Window *w, Point xy)
  792. {
  793. return ptinrect(xy, w->screenr) && !ptinrect(xy, insetrect(w->screenr, Selborder));
  794. }
  795. void
  796. wmousectl(Window *w)
  797. {
  798. int but;
  799. if(w->mc.buttons == 1)
  800. but = 1;
  801. else if(w->mc.buttons == 2)
  802. but = 2;
  803. else if(w->mc.buttons == 4)
  804. but = 3;
  805. else{
  806. if(w->mc.buttons == 8)
  807. wkeyctl(w, Kscrolloneup);
  808. if(w->mc.buttons == 16)
  809. wkeyctl(w, Kscrollonedown);
  810. return;
  811. }
  812. incref(w); /* hold up window while we track */
  813. if(w->deleted)
  814. goto Return;
  815. if(ptinrect(w->mc.xy, w->scrollr)){
  816. if(but)
  817. wscroll(w, but);
  818. goto Return;
  819. }
  820. if(but == 1)
  821. wselect(w);
  822. /* else all is handled by main process */
  823. Return:
  824. wclose(w);
  825. }
  826. void
  827. wdelete(Window *w, uint q0, uint q1)
  828. {
  829. uint n, p0, p1;
  830. n = q1-q0;
  831. if(n == 0)
  832. return;
  833. runemove(w->r+q0, w->r+q1, w->nr-q1);
  834. w->nr -= n;
  835. if(q0 < w->q0)
  836. w->q0 -= min(n, w->q0-q0);
  837. if(q0 < w->q1)
  838. w->q1 -= min(n, w->q1-q0);
  839. if(q1 < w->qh)
  840. w->qh -= n;
  841. else if(q0 < w->qh)
  842. w->qh = q0;
  843. if(q1 <= w->org)
  844. w->org -= n;
  845. else if(q0 < w->org+w->nchars){
  846. p1 = q1 - w->org;
  847. if(p1 > w->nchars)
  848. p1 = w->nchars;
  849. if(q0 < w->org){
  850. w->org = q0;
  851. p0 = 0;
  852. }else
  853. p0 = q0 - w->org;
  854. frdelete(w, p0, p1);
  855. wfill(w);
  856. }
  857. }
  858. static Window *clickwin;
  859. static uint clickmsec;
  860. static Window *selectwin;
  861. static uint selectq;
  862. /*
  863. * called from frame library
  864. */
  865. void
  866. framescroll(Frame *f, int dl)
  867. {
  868. if(f != &selectwin->Frame)
  869. error("frameselect not right frame");
  870. wframescroll(selectwin, dl);
  871. }
  872. void
  873. wframescroll(Window *w, int dl)
  874. {
  875. uint q0;
  876. if(dl == 0){
  877. wscrsleep(w, 100);
  878. return;
  879. }
  880. if(dl < 0){
  881. q0 = wbacknl(w, w->org, -dl);
  882. if(selectq > w->org+w->p0)
  883. wsetselect(w, w->org+w->p0, selectq);
  884. else
  885. wsetselect(w, selectq, w->org+w->p0);
  886. }else{
  887. if(w->org+w->nchars == w->nr)
  888. return;
  889. q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+dl*w->font->height));
  890. if(selectq >= w->org+w->p1)
  891. wsetselect(w, w->org+w->p1, selectq);
  892. else
  893. wsetselect(w, selectq, w->org+w->p1);
  894. }
  895. wsetorigin(w, q0, TRUE);
  896. }
  897. void
  898. wselect(Window *w)
  899. {
  900. uint q0, q1;
  901. int b, x, y, first;
  902. first = 1;
  903. selectwin = w;
  904. /*
  905. * Double-click immediately if it might make sense.
  906. */
  907. b = w->mc.buttons;
  908. q0 = w->q0;
  909. q1 = w->q1;
  910. selectq = w->org+frcharofpt(w, w->mc.xy);
  911. if(clickwin==w && w->mc.msec-clickmsec<500)
  912. if(q0==q1 && selectq==w->q0){
  913. wdoubleclick(w, &q0, &q1);
  914. wsetselect(w, q0, q1);
  915. flushimage(display, 1);
  916. x = w->mc.xy.x;
  917. y = w->mc.xy.y;
  918. /* stay here until something interesting happens */
  919. do
  920. readmouse(&w->mc);
  921. while(w->mc.buttons==b && abs(w->mc.xy.x-x)<3 && abs(w->mc.xy.y-y)<3);
  922. w->mc.xy.x = x; /* in case we're calling frselect */
  923. w->mc.xy.y = y;
  924. q0 = w->q0; /* may have changed */
  925. q1 = w->q1;
  926. selectq = q0;
  927. }
  928. if(w->mc.buttons == b){
  929. w->scroll = framescroll;
  930. frselect(w, &w->mc);
  931. /* horrible botch: while asleep, may have lost selection altogether */
  932. if(selectq > w->nr)
  933. selectq = w->org + w->p0;
  934. w->Frame.scroll = nil;
  935. if(selectq < w->org)
  936. q0 = selectq;
  937. else
  938. q0 = w->org + w->p0;
  939. if(selectq > w->org+w->nchars)
  940. q1 = selectq;
  941. else
  942. q1 = w->org+w->p1;
  943. }
  944. if(q0 == q1){
  945. if(q0==w->q0 && clickwin==w && w->mc.msec-clickmsec<500){
  946. wdoubleclick(w, &q0, &q1);
  947. clickwin = nil;
  948. }else{
  949. clickwin = w;
  950. clickmsec = w->mc.msec;
  951. }
  952. }else
  953. clickwin = nil;
  954. wsetselect(w, q0, q1);
  955. flushimage(display, 1);
  956. while(w->mc.buttons){
  957. w->mc.msec = 0;
  958. b = w->mc.buttons;
  959. if(b & 6){
  960. if(b & 2){
  961. wsnarf(w);
  962. wcut(w);
  963. }else{
  964. if(first){
  965. first = 0;
  966. getsnarf();
  967. }
  968. wpaste(w);
  969. }
  970. }
  971. wscrdraw(w);
  972. flushimage(display, 1);
  973. while(w->mc.buttons == b)
  974. readmouse(&w->mc);
  975. clickwin = nil;
  976. }
  977. }
  978. void
  979. wsendctlmesg(Window *w, int type, Rectangle r, Image *image)
  980. {
  981. Wctlmesg wcm;
  982. wcm.type = type;
  983. wcm.r = r;
  984. wcm.image = image;
  985. send(w->cctl, &wcm);
  986. }
  987. int
  988. wctlmesg(Window *w, int m, Rectangle r, Image *i)
  989. {
  990. char buf[64];
  991. switch(m){
  992. default:
  993. error("unknown control message");
  994. break;
  995. case Wakeup:
  996. break;
  997. case Moved:
  998. case Reshaped:
  999. if(w->deleted){
  1000. freeimage(i);
  1001. break;
  1002. }
  1003. w->screenr = r;
  1004. strcpy(buf, w->name);
  1005. wresize(w, i, m==Moved);
  1006. w->wctlready = 1;
  1007. proccreate(deletetimeoutproc, estrdup(buf), 4096);
  1008. if(Dx(r) > 0){
  1009. if(w != input)
  1010. wcurrent(w);
  1011. }else if(w == input)
  1012. wcurrent(nil);
  1013. flushimage(display, 1);
  1014. break;
  1015. case Refresh:
  1016. if(w->deleted || Dx(w->screenr)<=0 || !rectclip(&r, w->i->r))
  1017. break;
  1018. if(!w->mouseopen)
  1019. wrefresh(w, r);
  1020. flushimage(display, 1);
  1021. break;
  1022. case Movemouse:
  1023. if(sweeping || !ptinrect(r.min, w->i->r))
  1024. break;
  1025. wmovemouse(w, r.min);
  1026. case Rawon:
  1027. break;
  1028. case Rawoff:
  1029. if(w->deleted)
  1030. break;
  1031. while(w->nraw > 0){
  1032. wkeyctl(w, w->raw[0]);
  1033. --w->nraw;
  1034. runemove(w->raw, w->raw+1, w->nraw);
  1035. }
  1036. break;
  1037. case Holdon:
  1038. case Holdoff:
  1039. if(w->deleted)
  1040. break;
  1041. wrepaint(w);
  1042. flushimage(display, 1);
  1043. break;
  1044. case Deleted:
  1045. if(w->deleted)
  1046. break;
  1047. write(w->notefd, "hangup", 6);
  1048. proccreate(deletetimeoutproc, estrdup(w->name), 4096);
  1049. wclosewin(w);
  1050. break;
  1051. case Exited:
  1052. frclear(w, TRUE);
  1053. close(w->notefd);
  1054. chanfree(w->mc.c);
  1055. chanfree(w->ck);
  1056. chanfree(w->cctl);
  1057. chanfree(w->conswrite);
  1058. chanfree(w->consread);
  1059. chanfree(w->mouseread);
  1060. chanfree(w->wctlread);
  1061. free(w->raw);
  1062. free(w->r);
  1063. free(w->dir);
  1064. free(w->label);
  1065. free(w);
  1066. break;
  1067. }
  1068. return m;
  1069. }
  1070. /*
  1071. * Convert back to physical coordinates
  1072. */
  1073. void
  1074. wmovemouse(Window *w, Point p)
  1075. {
  1076. p.x += w->screenr.min.x-w->i->r.min.x;
  1077. p.y += w->screenr.min.y-w->i->r.min.y;
  1078. moveto(mousectl, p);
  1079. }
  1080. void
  1081. wborder(Window *w, int type)
  1082. {
  1083. Image *col;
  1084. if(w->i == nil)
  1085. return;
  1086. if(w->holding){
  1087. if(type == Selborder)
  1088. col = holdcol;
  1089. else
  1090. col = paleholdcol;
  1091. }else{
  1092. if(type == Selborder)
  1093. col = titlecol;
  1094. else
  1095. col = lighttitlecol;
  1096. }
  1097. border(w->i, w->i->r, Selborder, col, ZP);
  1098. }
  1099. Window*
  1100. wpointto(Point pt)
  1101. {
  1102. int i;
  1103. Window *v, *w;
  1104. w = nil;
  1105. for(i=0; i<nwindow; i++){
  1106. v = window[i];
  1107. if(ptinrect(pt, v->screenr))
  1108. if(!v->deleted)
  1109. if(w==nil || v->topped>w->topped)
  1110. w = v;
  1111. }
  1112. return w;
  1113. }
  1114. void
  1115. wcurrent(Window *w)
  1116. {
  1117. Window *oi;
  1118. if(wkeyboard!=nil && w==wkeyboard)
  1119. return;
  1120. oi = input;
  1121. input = w;
  1122. if(oi!=w && oi!=nil)
  1123. wrepaint(oi);
  1124. if(w !=nil){
  1125. wrepaint(w);
  1126. wsetcursor(w, 0);
  1127. }
  1128. if(w != oi){
  1129. if(oi){
  1130. oi->wctlready = 1;
  1131. wsendctlmesg(oi, Wakeup, ZR, nil);
  1132. }
  1133. if(w){
  1134. w->wctlready = 1;
  1135. wsendctlmesg(w, Wakeup, ZR, nil);
  1136. }
  1137. }
  1138. }
  1139. void
  1140. wsetcursor(Window *w, int force)
  1141. {
  1142. Cursor *p;
  1143. if(w==nil || /*w!=input || */ w->i==nil || Dx(w->screenr)<=0)
  1144. p = nil;
  1145. else if(wpointto(mouse->xy) == w){
  1146. p = w->cursorp;
  1147. if(p==nil && w->holding)
  1148. p = &whitearrow;
  1149. }else
  1150. p = nil;
  1151. if(!menuing)
  1152. riosetcursor(p, force && !menuing);
  1153. }
  1154. void
  1155. riosetcursor(Cursor *p, int force)
  1156. {
  1157. if(!force && p==lastcursor)
  1158. return;
  1159. setcursor(mousectl, p);
  1160. lastcursor = p;
  1161. }
  1162. Window*
  1163. wtop(Point pt)
  1164. {
  1165. Window *w;
  1166. w = wpointto(pt);
  1167. if(w){
  1168. if(w->topped == topped)
  1169. return nil;
  1170. topwindow(w->i);
  1171. wcurrent(w);
  1172. flushimage(display, 1);
  1173. w->topped = ++topped;
  1174. }
  1175. return w;
  1176. }
  1177. void
  1178. wtopme(Window *w)
  1179. {
  1180. if(w!=nil && w->i!=nil && !w->deleted && w->topped!=topped){
  1181. topwindow(w->i);
  1182. flushimage(display, 1);
  1183. w->topped = ++ topped;
  1184. }
  1185. }
  1186. void
  1187. wbottomme(Window *w)
  1188. {
  1189. if(w!=nil && w->i!=nil && !w->deleted){
  1190. bottomwindow(w->i);
  1191. flushimage(display, 1);
  1192. w->topped = - ++topped;
  1193. }
  1194. }
  1195. Window*
  1196. wlookid(int id)
  1197. {
  1198. int i;
  1199. for(i=0; i<nwindow; i++)
  1200. if(window[i]->id == id)
  1201. return window[i];
  1202. return nil;
  1203. }
  1204. void
  1205. wclosewin(Window *w)
  1206. {
  1207. Rectangle r;
  1208. int i;
  1209. w->deleted = TRUE;
  1210. if(w == input){
  1211. input = nil;
  1212. wsetcursor(w, 0);
  1213. }
  1214. if(w == wkeyboard)
  1215. wkeyboard = nil;
  1216. for(i=0; i<nhidden; i++)
  1217. if(hidden[i] == w){
  1218. --nhidden;
  1219. memmove(hidden+i, hidden+i+1, (nhidden-i)*sizeof(hidden[0]));
  1220. break;
  1221. }
  1222. for(i=0; i<nwindow; i++)
  1223. if(window[i] == w){
  1224. --nwindow;
  1225. memmove(window+i, window+i+1, (nwindow-i)*sizeof(Window*));
  1226. w->deleted = TRUE;
  1227. r = w->i->r;
  1228. /* move it off-screen to hide it, in case client is slow in letting it go */
  1229. MOVEIT originwindow(w->i, r.min, view->r.max);
  1230. freeimage(w->i);
  1231. w->i = nil;
  1232. return;
  1233. }
  1234. error("unknown window in closewin");
  1235. }
  1236. void
  1237. wsetpid(Window *w, int pid, int dolabel)
  1238. {
  1239. char buf[128];
  1240. int fd;
  1241. w->pid = pid;
  1242. if(dolabel){
  1243. sprint(buf, "rc %d", pid);
  1244. free(w->label);
  1245. w->label = estrdup(buf);
  1246. }
  1247. sprint(buf, "/proc/%d/notepg", pid);
  1248. fd = open(buf, OWRITE|OCEXEC);
  1249. if(w->notefd > 0)
  1250. close(w->notefd);
  1251. w->notefd = fd;
  1252. }
  1253. void
  1254. winshell(void *args)
  1255. {
  1256. Window *w;
  1257. Channel *pidc;
  1258. void **arg;
  1259. char *cmd, *dir;
  1260. char **argv;
  1261. arg = args;
  1262. w = arg[0];
  1263. pidc = arg[1];
  1264. cmd = arg[2];
  1265. argv = arg[3];
  1266. dir = arg[4];
  1267. rfork(RFNAMEG|RFFDG|RFENVG);
  1268. if(filsysmount(filsys, w->id) < 0){
  1269. fprint(2, "mount failed: %r\n");
  1270. sendul(pidc, 0);
  1271. threadexits("mount failed");
  1272. }
  1273. close(0);
  1274. if(open("/dev/cons", OREAD) < 0){
  1275. fprint(2, "can't open /dev/cons: %r\n");
  1276. sendul(pidc, 0);
  1277. threadexits("/dev/cons");
  1278. }
  1279. close(1);
  1280. if(open("/dev/cons", OWRITE) < 0){
  1281. fprint(2, "can't open /dev/cons: %r\n");
  1282. sendul(pidc, 0);
  1283. threadexits("open"); /* BUG? was terminate() */
  1284. }
  1285. if(wclose(w) == 0){ /* remove extra ref hanging from creation */
  1286. notify(nil);
  1287. dup(1, 2);
  1288. if(dir)
  1289. chdir(dir);
  1290. procexec(pidc, cmd, argv);
  1291. _exits("exec failed");
  1292. }
  1293. }
  1294. static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 };
  1295. static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };
  1296. static Rune left2[] = { L'\n', 0 };
  1297. static Rune left3[] = { L'\'', L'"', L'`', 0 };
  1298. Rune *left[] = {
  1299. left1,
  1300. left2,
  1301. left3,
  1302. nil
  1303. };
  1304. Rune *right[] = {
  1305. right1,
  1306. left2,
  1307. left3,
  1308. nil
  1309. };
  1310. void
  1311. wdoubleclick(Window *w, uint *q0, uint *q1)
  1312. {
  1313. int c, i;
  1314. Rune *r, *l, *p;
  1315. uint q;
  1316. for(i=0; left[i]!=nil; i++){
  1317. q = *q0;
  1318. l = left[i];
  1319. r = right[i];
  1320. /* try matching character to left, looking right */
  1321. if(q == 0)
  1322. c = '\n';
  1323. else
  1324. c = w->r[q-1];
  1325. p = strrune(l, c);
  1326. if(p != nil){
  1327. if(wclickmatch(w, c, r[p-l], 1, &q))
  1328. *q1 = q-(c!='\n');
  1329. return;
  1330. }
  1331. /* try matching character to right, looking left */
  1332. if(q == w->nr)
  1333. c = '\n';
  1334. else
  1335. c = w->r[q];
  1336. p = strrune(r, c);
  1337. if(p != nil){
  1338. if(wclickmatch(w, c, l[p-r], -1, &q)){
  1339. *q1 = *q0+(*q0<w->nr && c=='\n');
  1340. *q0 = q;
  1341. if(c!='\n' || q!=0 || w->r[0]=='\n')
  1342. (*q0)++;
  1343. }
  1344. return;
  1345. }
  1346. }
  1347. /* try filling out word to right */
  1348. while(*q1<w->nr && isalnum(w->r[*q1]))
  1349. (*q1)++;
  1350. /* try filling out word to left */
  1351. while(*q0>0 && isalnum(w->r[*q0-1]))
  1352. (*q0)--;
  1353. }
  1354. int
  1355. wclickmatch(Window *w, int cl, int cr, int dir, uint *q)
  1356. {
  1357. Rune c;
  1358. int nest;
  1359. nest = 1;
  1360. for(;;){
  1361. if(dir > 0){
  1362. if(*q == w->nr)
  1363. break;
  1364. c = w->r[*q];
  1365. (*q)++;
  1366. }else{
  1367. if(*q == 0)
  1368. break;
  1369. (*q)--;
  1370. c = w->r[*q];
  1371. }
  1372. if(c == cr){
  1373. if(--nest==0)
  1374. return 1;
  1375. }else if(c == cl)
  1376. nest++;
  1377. }
  1378. return cl=='\n' && nest==1;
  1379. }
  1380. uint
  1381. wbacknl(Window *w, uint p, uint n)
  1382. {
  1383. int i, j;
  1384. /* look for start of this line if n==0 */
  1385. if(n==0 && p>0 && w->r[p-1]!='\n')
  1386. n = 1;
  1387. i = n;
  1388. while(i-->0 && p>0){
  1389. --p; /* it's at a newline now; back over it */
  1390. if(p == 0)
  1391. break;
  1392. /* at 128 chars, call it a line anyway */
  1393. for(j=128; --j>0 && p>0; p--)
  1394. if(w->r[p-1]=='\n')
  1395. break;
  1396. }
  1397. return p;
  1398. }
  1399. void
  1400. wshow(Window *w, uint q0)
  1401. {
  1402. int qe;
  1403. int nl;
  1404. uint q;
  1405. qe = w->org+w->nchars;
  1406. if(w->org<=q0 && (q0<qe || (q0==qe && qe==w->nr)))
  1407. wscrdraw(w);
  1408. else{
  1409. nl = 4*w->maxlines/5;
  1410. q = wbacknl(w, q0, nl);
  1411. /* avoid going backwards if trying to go forwards - long lines! */
  1412. if(!(q0>w->org && q<w->org))
  1413. wsetorigin(w, q, TRUE);
  1414. while(q0 > w->org+w->nchars)
  1415. wsetorigin(w, w->org+1, FALSE);
  1416. }
  1417. }
  1418. void
  1419. wsetorigin(Window *w, uint org, int exact)
  1420. {
  1421. int i, a, fixup;
  1422. Rune *r;
  1423. uint n;
  1424. if(org>0 && !exact){
  1425. /* org is an estimate of the char posn; find a newline */
  1426. /* don't try harder than 256 chars */
  1427. for(i=0; i<256 && org<w->nr; i++){
  1428. if(w->r[org] == '\n'){
  1429. org++;
  1430. break;
  1431. }
  1432. org++;
  1433. }
  1434. }
  1435. a = org-w->org;
  1436. fixup = 0;
  1437. if(a>=0 && a<w->nchars){
  1438. frdelete(w, 0, a);
  1439. fixup = 1; /* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */
  1440. }else if(a<0 && -a<w->nchars){
  1441. n = w->org - org;
  1442. r = runemalloc(n);
  1443. runemove(r, w->r+org, n);
  1444. frinsert(w, r, r+n, 0);
  1445. free(r);
  1446. }else
  1447. frdelete(w, 0, w->nchars);
  1448. w->org = org;
  1449. wfill(w);
  1450. wscrdraw(w);
  1451. wsetselect(w, w->q0, w->q1);
  1452. if(fixup && w->p1 > w->p0)
  1453. frdrawsel(w, frptofchar(w, w->p1-1), w->p1-1, w->p1, 1);
  1454. }
  1455. void
  1456. wsetselect(Window *w, uint q0, uint q1)
  1457. {
  1458. int p0, p1;
  1459. /* w->p0 and w->p1 are always right; w->q0 and w->q1 may be off */
  1460. w->q0 = q0;
  1461. w->q1 = q1;
  1462. /* compute desired p0,p1 from q0,q1 */
  1463. p0 = q0-w->org;
  1464. p1 = q1-w->org;
  1465. if(p0 < 0)
  1466. p0 = 0;
  1467. if(p1 < 0)
  1468. p1 = 0;
  1469. if(p0 > w->nchars)
  1470. p0 = w->nchars;
  1471. if(p1 > w->nchars)
  1472. p1 = w->nchars;
  1473. if(p0==w->p0 && p1==w->p1)
  1474. return;
  1475. /* screen disagrees with desired selection */
  1476. if(w->p1<=p0 || p1<=w->p0 || p0==p1 || w->p1==w->p0){
  1477. /* no overlap or too easy to bother trying */
  1478. frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 0);
  1479. frdrawsel(w, frptofchar(w, p0), p0, p1, 1);
  1480. goto Return;
  1481. }
  1482. /* overlap; avoid unnecessary painting */
  1483. if(p0 < w->p0){
  1484. /* extend selection backwards */
  1485. frdrawsel(w, frptofchar(w, p0), p0, w->p0, 1);
  1486. }else if(p0 > w->p0){
  1487. /* trim first part of selection */
  1488. frdrawsel(w, frptofchar(w, w->p0), w->p0, p0, 0);
  1489. }
  1490. if(p1 > w->p1){
  1491. /* extend selection forwards */
  1492. frdrawsel(w, frptofchar(w, w->p1), w->p1, p1, 1);
  1493. }else if(p1 < w->p1){
  1494. /* trim last part of selection */
  1495. frdrawsel(w, frptofchar(w, p1), p1, w->p1, 0);
  1496. }
  1497. Return:
  1498. w->p0 = p0;
  1499. w->p1 = p1;
  1500. }
  1501. uint
  1502. winsert(Window *w, Rune *r, int n, uint q0)
  1503. {
  1504. uint m;
  1505. if(n == 0)
  1506. return q0;
  1507. if(w->nr+n>HiWater && q0>=w->org && q0>=w->qh){
  1508. m = min(HiWater-LoWater, min(w->org, w->qh));
  1509. w->org -= m;
  1510. w->qh -= m;
  1511. if(w->q0 > m)
  1512. w->q0 -= m;
  1513. else
  1514. w->q0 = 0;
  1515. if(w->q1 > m)
  1516. w->q1 -= m;
  1517. else
  1518. w->q1 = 0;
  1519. w->nr -= m;
  1520. runemove(w->r, w->r+m, w->nr);
  1521. q0 -= m;
  1522. }
  1523. if(w->nr+n > w->maxr){
  1524. /*
  1525. * Minimize realloc breakage:
  1526. * Allocate at least MinWater
  1527. * Double allocation size each time
  1528. * But don't go much above HiWater
  1529. */
  1530. m = max(min(2*(w->nr+n), HiWater), w->nr+n)+MinWater;
  1531. if(m > HiWater)
  1532. m = max(HiWater+MinWater, w->nr+n);
  1533. if(m > w->maxr){
  1534. w->r = runerealloc(w->r, m);
  1535. w->maxr = m;
  1536. }
  1537. }
  1538. runemove(w->r+q0+n, w->r+q0, w->nr-q0);
  1539. runemove(w->r+q0, r, n);
  1540. w->nr += n;
  1541. /* if output touches, advance selection, not qh; works best for keyboard and output */
  1542. if(q0 <= w->q1)
  1543. w->q1 += n;
  1544. if(q0 <= w->q0)
  1545. w->q0 += n;
  1546. if(q0 < w->qh)
  1547. w->qh += n;
  1548. if(q0 < w->org)
  1549. w->org += n;
  1550. else if(q0 <= w->org+w->nchars)
  1551. frinsert(w, r, r+n, q0-w->org);
  1552. return q0;
  1553. }
  1554. void
  1555. wfill(Window *w)
  1556. {
  1557. Rune *rp;
  1558. int i, n, m, nl;
  1559. if(w->lastlinefull)
  1560. return;
  1561. rp = malloc(messagesize);
  1562. do{
  1563. n = w->nr-(w->org+w->nchars);
  1564. if(n == 0)
  1565. break;
  1566. if(n > 2000) /* educated guess at reasonable amount */
  1567. n = 2000;
  1568. runemove(rp, w->r+(w->org+w->nchars), n);
  1569. /*
  1570. * it's expensive to frinsert more than we need, so
  1571. * count newlines.
  1572. */
  1573. nl = w->maxlines-w->nlines;
  1574. m = 0;
  1575. for(i=0; i<n; ){
  1576. if(rp[i++] == '\n'){
  1577. m++;
  1578. if(m >= nl)
  1579. break;
  1580. }
  1581. }
  1582. frinsert(w, rp, rp+i, w->nchars);
  1583. }while(w->lastlinefull == FALSE);
  1584. free(rp);
  1585. }
  1586. char*
  1587. wcontents(Window *w, int *ip)
  1588. {
  1589. return runetobyte(w->r, w->nr, ip);
  1590. }