wind.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698
  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. _frredraw(w, w->Frame.r.min, w->cols[TEXT], nil);
  672. if(w == input){
  673. wborder(w, Selborder);
  674. wsetcursor(w, 0);
  675. }else
  676. wborder(w, Unselborder);
  677. }
  678. int
  679. wbswidth(Window *w, Rune c)
  680. {
  681. uint q, eq, stop;
  682. Rune r;
  683. int skipping;
  684. /* there is known to be at least one character to erase */
  685. if(c == 0x08) /* ^H: erase character */
  686. return 1;
  687. q = w->q0;
  688. stop = 0;
  689. if(q > w->qh)
  690. stop = w->qh;
  691. skipping = TRUE;
  692. while(q > stop){
  693. r = w->r[q-1];
  694. if(r == '\n'){ /* eat at most one more character */
  695. if(q == w->q0) /* eat the newline */
  696. --q;
  697. break;
  698. }
  699. if(c == 0x17){
  700. eq = isalnum(r);
  701. if(eq && skipping) /* found one; stop skipping */
  702. skipping = FALSE;
  703. else if(!eq && !skipping)
  704. break;
  705. }
  706. --q;
  707. }
  708. return w->q0-q;
  709. }
  710. void
  711. wsnarf(Window *w)
  712. {
  713. if(w->q1 == w->q0)
  714. return;
  715. nsnarf = w->q1-w->q0;
  716. snarf = runerealloc(snarf, nsnarf);
  717. snarfversion++; /* maybe modified by parent */
  718. runemove(snarf, w->r+w->q0, nsnarf);
  719. putsnarf();
  720. }
  721. void
  722. wcut(Window *w)
  723. {
  724. if(w->q1 == w->q0)
  725. return;
  726. wdelete(w, w->q0, w->q1);
  727. wsetselect(w, w->q0, w->q0);
  728. }
  729. void
  730. wpaste(Window *w)
  731. {
  732. uint q0;
  733. if(nsnarf == 0)
  734. return;
  735. wcut(w);
  736. q0 = w->q0;
  737. if(w->rawing && q0==w->nr){
  738. waddraw(w, snarf, nsnarf);
  739. wsetselect(w, q0, q0);
  740. }else{
  741. q0 = winsert(w, snarf, nsnarf, w->q0);
  742. wsetselect(w, q0, q0+nsnarf);
  743. }
  744. }
  745. void
  746. wplumb(Window *w)
  747. {
  748. Plumbmsg *m;
  749. static int fd = -2;
  750. char buf[32];
  751. uint p0, p1;
  752. Cursor *c;
  753. if(fd == -2)
  754. fd = plumbopen("send", OWRITE|OCEXEC);
  755. if(fd < 0)
  756. return;
  757. m = emalloc(sizeof(Plumbmsg));
  758. m->src = estrdup("rio");
  759. m->dst = nil;
  760. m->wdir = estrdup(w->dir);
  761. m->type = estrdup("text");
  762. p0 = w->q0;
  763. p1 = w->q1;
  764. if(w->q1 > w->q0)
  765. m->attr = nil;
  766. else{
  767. while(p0>0 && w->r[p0-1]!=' ' && w->r[p0-1]!='\t' && w->r[p0-1]!='\n')
  768. p0--;
  769. while(p1<w->nr && w->r[p1]!=' ' && w->r[p1]!='\t' && w->r[p1]!='\n')
  770. p1++;
  771. sprint(buf, "click=%d", w->q0-p0);
  772. m->attr = plumbunpackattr(buf);
  773. }
  774. if(p1-p0 > messagesize-1024){
  775. plumbfree(m);
  776. return; /* too large for 9P */
  777. }
  778. m->data = runetobyte(w->r+p0, p1-p0, &m->ndata);
  779. if(plumbsend(fd, m) < 0){
  780. c = lastcursor;
  781. riosetcursor(&query, 1);
  782. sleep(300);
  783. riosetcursor(c, 1);
  784. }
  785. plumbfree(m);
  786. }
  787. int
  788. winborder(Window *w, Point xy)
  789. {
  790. return ptinrect(xy, w->screenr) && !ptinrect(xy, insetrect(w->screenr, Selborder));
  791. }
  792. void
  793. wmousectl(Window *w)
  794. {
  795. int but;
  796. if(w->mc.buttons == 1)
  797. but = 1;
  798. else if(w->mc.buttons == 2)
  799. but = 2;
  800. else if(w->mc.buttons == 4)
  801. but = 3;
  802. else{
  803. if(w->mc.buttons == 8)
  804. wkeyctl(w, Kscrolloneup);
  805. if(w->mc.buttons == 16)
  806. wkeyctl(w, Kscrollonedown);
  807. return;
  808. }
  809. incref(w); /* hold up window while we track */
  810. if(w->deleted)
  811. goto Return;
  812. if(ptinrect(w->mc.xy, w->scrollr)){
  813. if(but)
  814. wscroll(w, but);
  815. goto Return;
  816. }
  817. if(but == 1)
  818. wselect(w);
  819. /* else all is handled by main process */
  820. Return:
  821. wclose(w);
  822. }
  823. void
  824. wdelete(Window *w, uint q0, uint q1)
  825. {
  826. uint n, p0, p1;
  827. n = q1-q0;
  828. if(n == 0)
  829. return;
  830. runemove(w->r+q0, w->r+q1, w->nr-q1);
  831. w->nr -= n;
  832. if(q0 < w->q0)
  833. w->q0 -= min(n, w->q0-q0);
  834. if(q0 < w->q1)
  835. w->q1 -= min(n, w->q1-q0);
  836. if(q1 < w->qh)
  837. w->qh -= n;
  838. else if(q0 < w->qh)
  839. w->qh = q0;
  840. if(q1 <= w->org)
  841. w->org -= n;
  842. else if(q0 < w->org+w->nchars){
  843. p1 = q1 - w->org;
  844. if(p1 > w->nchars)
  845. p1 = w->nchars;
  846. if(q0 < w->org){
  847. w->org = q0;
  848. p0 = 0;
  849. }else
  850. p0 = q0 - w->org;
  851. frdelete(w, p0, p1);
  852. wfill(w);
  853. }
  854. }
  855. static Window *clickwin;
  856. static uint clickmsec;
  857. static Window *selectwin;
  858. static uint selectq;
  859. /*
  860. * called from frame library
  861. */
  862. void
  863. framescroll(Frame *f, int dl)
  864. {
  865. if(f != &selectwin->Frame)
  866. error("frameselect not right frame");
  867. wframescroll(selectwin, dl);
  868. }
  869. void
  870. wframescroll(Window *w, int dl)
  871. {
  872. uint q0;
  873. if(dl == 0){
  874. wscrsleep(w, 100);
  875. return;
  876. }
  877. if(dl < 0){
  878. q0 = wbacknl(w, w->org, -dl);
  879. if(selectq > w->org+w->p0)
  880. wsetselect(w, w->org+w->p0, selectq);
  881. else
  882. wsetselect(w, selectq, w->org+w->p0);
  883. }else{
  884. if(w->org+w->nchars == w->nr)
  885. return;
  886. q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+dl*w->font->height));
  887. if(selectq >= w->org+w->p1)
  888. wsetselect(w, w->org+w->p1, selectq);
  889. else
  890. wsetselect(w, selectq, w->org+w->p1);
  891. }
  892. wsetorigin(w, q0, TRUE);
  893. }
  894. void
  895. wselect(Window *w)
  896. {
  897. uint q0, q1;
  898. int b, x, y, first;
  899. first = 1;
  900. selectwin = w;
  901. /*
  902. * Double-click immediately if it might make sense.
  903. */
  904. b = w->mc.buttons;
  905. q0 = w->q0;
  906. q1 = w->q1;
  907. selectq = w->org+frcharofpt(w, w->mc.xy);
  908. if(clickwin==w && w->mc.msec-clickmsec<500)
  909. if(q0==q1 && selectq==w->q0){
  910. wdoubleclick(w, &q0, &q1);
  911. wsetselect(w, q0, q1);
  912. flushimage(display, 1);
  913. x = w->mc.xy.x;
  914. y = w->mc.xy.y;
  915. /* stay here until something interesting happens */
  916. do
  917. readmouse(&w->mc);
  918. while(w->mc.buttons==b && abs(w->mc.xy.x-x)<3 && abs(w->mc.xy.y-y)<3);
  919. w->mc.xy.x = x; /* in case we're calling frselect */
  920. w->mc.xy.y = y;
  921. q0 = w->q0; /* may have changed */
  922. q1 = w->q1;
  923. selectq = q0;
  924. }
  925. if(w->mc.buttons == b){
  926. w->scroll = framescroll;
  927. frselect(w, &w->mc);
  928. /* horrible botch: while asleep, may have lost selection altogether */
  929. if(selectq > w->nr)
  930. selectq = w->org + w->p0;
  931. w->Frame.scroll = nil;
  932. if(selectq < w->org)
  933. q0 = selectq;
  934. else
  935. q0 = w->org + w->p0;
  936. if(selectq > w->org+w->nchars)
  937. q1 = selectq;
  938. else
  939. q1 = w->org+w->p1;
  940. }
  941. if(q0 == q1){
  942. if(q0==w->q0 && clickwin==w && w->mc.msec-clickmsec<500){
  943. wdoubleclick(w, &q0, &q1);
  944. clickwin = nil;
  945. }else{
  946. clickwin = w;
  947. clickmsec = w->mc.msec;
  948. }
  949. }else
  950. clickwin = nil;
  951. wsetselect(w, q0, q1);
  952. flushimage(display, 1);
  953. while(w->mc.buttons){
  954. w->mc.msec = 0;
  955. b = w->mc.buttons;
  956. if(b & 6){
  957. if(b & 2){
  958. wsnarf(w);
  959. wcut(w);
  960. }else{
  961. if(first){
  962. first = 0;
  963. getsnarf();
  964. }
  965. wpaste(w);
  966. }
  967. }
  968. wscrdraw(w);
  969. flushimage(display, 1);
  970. while(w->mc.buttons == b)
  971. readmouse(&w->mc);
  972. clickwin = nil;
  973. }
  974. }
  975. void
  976. wsendctlmesg(Window *w, int type, Rectangle r, Image *image)
  977. {
  978. Wctlmesg wcm;
  979. wcm.type = type;
  980. wcm.r = r;
  981. wcm.image = image;
  982. send(w->cctl, &wcm);
  983. }
  984. int
  985. wctlmesg(Window *w, int m, Rectangle r, Image *i)
  986. {
  987. char buf[64];
  988. switch(m){
  989. default:
  990. error("unknown control message");
  991. break;
  992. case Wakeup:
  993. break;
  994. case Moved:
  995. case Reshaped:
  996. if(w->deleted){
  997. freeimage(i);
  998. break;
  999. }
  1000. w->screenr = r;
  1001. strcpy(buf, w->name);
  1002. wresize(w, i, m==Moved);
  1003. w->wctlready = 1;
  1004. proccreate(deletetimeoutproc, estrdup(buf), 4096);
  1005. if(Dx(r) > 0){
  1006. if(w != input)
  1007. wcurrent(w);
  1008. }else if(w == input)
  1009. wcurrent(nil);
  1010. flushimage(display, 1);
  1011. break;
  1012. case Refresh:
  1013. if(w->deleted || Dx(w->screenr)<=0 || !rectclip(&r, w->i->r))
  1014. break;
  1015. if(!w->mouseopen)
  1016. wrefresh(w, r);
  1017. flushimage(display, 1);
  1018. break;
  1019. case Movemouse:
  1020. if(sweeping || !ptinrect(r.min, w->i->r))
  1021. break;
  1022. wmovemouse(w, r.min);
  1023. case Rawon:
  1024. break;
  1025. case Rawoff:
  1026. if(w->deleted)
  1027. break;
  1028. while(w->nraw > 0){
  1029. wkeyctl(w, w->raw[0]);
  1030. --w->nraw;
  1031. runemove(w->raw, w->raw+1, w->nraw);
  1032. }
  1033. break;
  1034. case Holdon:
  1035. case Holdoff:
  1036. if(w->deleted)
  1037. break;
  1038. wrepaint(w);
  1039. flushimage(display, 1);
  1040. break;
  1041. case Deleted:
  1042. if(w->deleted)
  1043. break;
  1044. write(w->notefd, "hangup", 6);
  1045. proccreate(deletetimeoutproc, estrdup(w->name), 4096);
  1046. wclosewin(w);
  1047. break;
  1048. case Exited:
  1049. frclear(w, TRUE);
  1050. close(w->notefd);
  1051. chanfree(w->mc.c);
  1052. chanfree(w->ck);
  1053. chanfree(w->cctl);
  1054. chanfree(w->conswrite);
  1055. chanfree(w->consread);
  1056. chanfree(w->mouseread);
  1057. chanfree(w->wctlread);
  1058. free(w->raw);
  1059. free(w->r);
  1060. free(w->dir);
  1061. free(w->label);
  1062. free(w);
  1063. break;
  1064. }
  1065. return m;
  1066. }
  1067. /*
  1068. * Convert back to physical coordinates
  1069. */
  1070. void
  1071. wmovemouse(Window *w, Point p)
  1072. {
  1073. p.x += w->screenr.min.x-w->i->r.min.x;
  1074. p.y += w->screenr.min.y-w->i->r.min.y;
  1075. moveto(mousectl, p);
  1076. }
  1077. void
  1078. wborder(Window *w, int type)
  1079. {
  1080. Image *col;
  1081. if(w->i == nil)
  1082. return;
  1083. if(w->holding){
  1084. if(type == Selborder)
  1085. col = holdcol;
  1086. else
  1087. col = paleholdcol;
  1088. }else{
  1089. if(type == Selborder)
  1090. col = titlecol;
  1091. else
  1092. col = lighttitlecol;
  1093. }
  1094. border(w->i, w->i->r, Selborder, col, ZP);
  1095. }
  1096. Window*
  1097. wpointto(Point pt)
  1098. {
  1099. int i;
  1100. Window *v, *w;
  1101. w = nil;
  1102. for(i=0; i<nwindow; i++){
  1103. v = window[i];
  1104. if(ptinrect(pt, v->screenr))
  1105. if(!v->deleted)
  1106. if(w==nil || v->topped>w->topped)
  1107. w = v;
  1108. }
  1109. return w;
  1110. }
  1111. void
  1112. wcurrent(Window *w)
  1113. {
  1114. Window *oi;
  1115. if(wkeyboard!=nil && w==wkeyboard)
  1116. return;
  1117. oi = input;
  1118. input = w;
  1119. if(oi!=w && oi!=nil)
  1120. wrepaint(oi);
  1121. if(w !=nil){
  1122. wrepaint(w);
  1123. wsetcursor(w, 0);
  1124. }
  1125. if(w != oi){
  1126. if(oi){
  1127. oi->wctlready = 1;
  1128. wsendctlmesg(oi, Wakeup, ZR, nil);
  1129. }
  1130. if(w){
  1131. w->wctlready = 1;
  1132. wsendctlmesg(w, Wakeup, ZR, nil);
  1133. }
  1134. }
  1135. }
  1136. void
  1137. wsetcursor(Window *w, int force)
  1138. {
  1139. Cursor *p;
  1140. if(w==nil || /*w!=input || */ w->i==nil || Dx(w->screenr)<=0)
  1141. p = nil;
  1142. else if(wpointto(mouse->xy) == w){
  1143. p = w->cursorp;
  1144. if(p==nil && w->holding)
  1145. p = &whitearrow;
  1146. }else
  1147. p = nil;
  1148. if(!menuing)
  1149. riosetcursor(p, force && !menuing);
  1150. }
  1151. void
  1152. riosetcursor(Cursor *p, int force)
  1153. {
  1154. if(!force && p==lastcursor)
  1155. return;
  1156. setcursor(mousectl, p);
  1157. lastcursor = p;
  1158. }
  1159. Window*
  1160. wtop(Point pt)
  1161. {
  1162. Window *w;
  1163. w = wpointto(pt);
  1164. if(w){
  1165. if(w->topped == topped)
  1166. return nil;
  1167. topwindow(w->i);
  1168. wcurrent(w);
  1169. flushimage(display, 1);
  1170. w->topped = ++topped;
  1171. }
  1172. return w;
  1173. }
  1174. void
  1175. wtopme(Window *w)
  1176. {
  1177. if(w!=nil && w->i!=nil && !w->deleted && w->topped!=topped){
  1178. topwindow(w->i);
  1179. flushimage(display, 1);
  1180. w->topped = ++ topped;
  1181. }
  1182. }
  1183. void
  1184. wbottomme(Window *w)
  1185. {
  1186. if(w!=nil && w->i!=nil && !w->deleted){
  1187. bottomwindow(w->i);
  1188. flushimage(display, 1);
  1189. w->topped = - ++topped;
  1190. }
  1191. }
  1192. Window*
  1193. wlookid(int id)
  1194. {
  1195. int i;
  1196. for(i=0; i<nwindow; i++)
  1197. if(window[i]->id == id)
  1198. return window[i];
  1199. return nil;
  1200. }
  1201. void
  1202. wclosewin(Window *w)
  1203. {
  1204. Rectangle r;
  1205. int i;
  1206. w->deleted = TRUE;
  1207. if(w == input){
  1208. input = nil;
  1209. wsetcursor(w, 0);
  1210. }
  1211. if(w == wkeyboard)
  1212. wkeyboard = nil;
  1213. for(i=0; i<nhidden; i++)
  1214. if(hidden[i] == w){
  1215. --nhidden;
  1216. memmove(hidden+i, hidden+i+1, (nhidden-i)*sizeof(hidden[0]));
  1217. break;
  1218. }
  1219. for(i=0; i<nwindow; i++)
  1220. if(window[i] == w){
  1221. --nwindow;
  1222. memmove(window+i, window+i+1, (nwindow-i)*sizeof(Window*));
  1223. w->deleted = TRUE;
  1224. r = w->i->r;
  1225. /* move it off-screen to hide it, in case client is slow in letting it go */
  1226. MOVEIT originwindow(w->i, r.min, view->r.max);
  1227. freeimage(w->i);
  1228. w->i = nil;
  1229. return;
  1230. }
  1231. error("unknown window in closewin");
  1232. }
  1233. void
  1234. wsetpid(Window *w, int pid, int dolabel)
  1235. {
  1236. char buf[128];
  1237. int fd;
  1238. w->pid = pid;
  1239. if(dolabel){
  1240. sprint(buf, "rc %d", pid);
  1241. free(w->label);
  1242. w->label = estrdup(buf);
  1243. }
  1244. sprint(buf, "/proc/%d/notepg", pid);
  1245. fd = open(buf, OWRITE|OCEXEC);
  1246. if(w->notefd > 0)
  1247. close(w->notefd);
  1248. w->notefd = fd;
  1249. }
  1250. void
  1251. winshell(void *args)
  1252. {
  1253. Window *w;
  1254. Channel *pidc;
  1255. void **arg;
  1256. char *cmd, *dir;
  1257. char **argv;
  1258. arg = args;
  1259. w = arg[0];
  1260. pidc = arg[1];
  1261. cmd = arg[2];
  1262. argv = arg[3];
  1263. dir = arg[4];
  1264. rfork(RFNAMEG|RFFDG|RFENVG);
  1265. if(filsysmount(filsys, w->id) < 0){
  1266. fprint(2, "mount failed: %r\n");
  1267. sendul(pidc, 0);
  1268. threadexits("mount failed");
  1269. }
  1270. close(0);
  1271. if(open("/dev/cons", OREAD) < 0){
  1272. fprint(2, "can't open /dev/cons: %r\n");
  1273. sendul(pidc, 0);
  1274. threadexits("/dev/cons");
  1275. }
  1276. close(1);
  1277. if(open("/dev/cons", OWRITE) < 0){
  1278. fprint(2, "can't open /dev/cons: %r\n");
  1279. sendul(pidc, 0);
  1280. threadexits("open"); /* BUG? was terminate() */
  1281. }
  1282. if(wclose(w) == 0){ /* remove extra ref hanging from creation */
  1283. notify(nil);
  1284. dup(1, 2);
  1285. if(dir)
  1286. chdir(dir);
  1287. procexec(pidc, cmd, argv);
  1288. _exits("exec failed");
  1289. }
  1290. }
  1291. static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 };
  1292. static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };
  1293. static Rune left2[] = { L'\n', 0 };
  1294. static Rune left3[] = { L'\'', L'"', L'`', 0 };
  1295. Rune *left[] = {
  1296. left1,
  1297. left2,
  1298. left3,
  1299. nil
  1300. };
  1301. Rune *right[] = {
  1302. right1,
  1303. left2,
  1304. left3,
  1305. nil
  1306. };
  1307. void
  1308. wdoubleclick(Window *w, uint *q0, uint *q1)
  1309. {
  1310. int c, i;
  1311. Rune *r, *l, *p;
  1312. uint q;
  1313. for(i=0; left[i]!=nil; i++){
  1314. q = *q0;
  1315. l = left[i];
  1316. r = right[i];
  1317. /* try matching character to left, looking right */
  1318. if(q == 0)
  1319. c = '\n';
  1320. else
  1321. c = w->r[q-1];
  1322. p = strrune(l, c);
  1323. if(p != nil){
  1324. if(wclickmatch(w, c, r[p-l], 1, &q))
  1325. *q1 = q-(c!='\n');
  1326. return;
  1327. }
  1328. /* try matching character to right, looking left */
  1329. if(q == w->nr)
  1330. c = '\n';
  1331. else
  1332. c = w->r[q];
  1333. p = strrune(r, c);
  1334. if(p != nil){
  1335. if(wclickmatch(w, c, l[p-r], -1, &q)){
  1336. *q1 = *q0+(*q0<w->nr && c=='\n');
  1337. *q0 = q;
  1338. if(c!='\n' || q!=0 || w->r[0]=='\n')
  1339. (*q0)++;
  1340. }
  1341. return;
  1342. }
  1343. }
  1344. /* try filling out word to right */
  1345. while(*q1<w->nr && isalnum(w->r[*q1]))
  1346. (*q1)++;
  1347. /* try filling out word to left */
  1348. while(*q0>0 && isalnum(w->r[*q0-1]))
  1349. (*q0)--;
  1350. }
  1351. int
  1352. wclickmatch(Window *w, int cl, int cr, int dir, uint *q)
  1353. {
  1354. Rune c;
  1355. int nest;
  1356. nest = 1;
  1357. for(;;){
  1358. if(dir > 0){
  1359. if(*q == w->nr)
  1360. break;
  1361. c = w->r[*q];
  1362. (*q)++;
  1363. }else{
  1364. if(*q == 0)
  1365. break;
  1366. (*q)--;
  1367. c = w->r[*q];
  1368. }
  1369. if(c == cr){
  1370. if(--nest==0)
  1371. return 1;
  1372. }else if(c == cl)
  1373. nest++;
  1374. }
  1375. return cl=='\n' && nest==1;
  1376. }
  1377. uint
  1378. wbacknl(Window *w, uint p, uint n)
  1379. {
  1380. int i, j;
  1381. /* look for start of this line if n==0 */
  1382. if(n==0 && p>0 && w->r[p-1]!='\n')
  1383. n = 1;
  1384. i = n;
  1385. while(i-->0 && p>0){
  1386. --p; /* it's at a newline now; back over it */
  1387. if(p == 0)
  1388. break;
  1389. /* at 128 chars, call it a line anyway */
  1390. for(j=128; --j>0 && p>0; p--)
  1391. if(w->r[p-1]=='\n')
  1392. break;
  1393. }
  1394. return p;
  1395. }
  1396. void
  1397. wshow(Window *w, uint q0)
  1398. {
  1399. int qe;
  1400. int nl;
  1401. uint q;
  1402. qe = w->org+w->nchars;
  1403. if(w->org<=q0 && (q0<qe || (q0==qe && qe==w->nr)))
  1404. wscrdraw(w);
  1405. else{
  1406. nl = 4*w->maxlines/5;
  1407. q = wbacknl(w, q0, nl);
  1408. /* avoid going backwards if trying to go forwards - long lines! */
  1409. if(!(q0>w->org && q<w->org))
  1410. wsetorigin(w, q, TRUE);
  1411. while(q0 > w->org+w->nchars)
  1412. wsetorigin(w, w->org+1, FALSE);
  1413. }
  1414. }
  1415. void
  1416. wsetorigin(Window *w, uint org, int exact)
  1417. {
  1418. int i, a, fixup;
  1419. Rune *r;
  1420. uint n;
  1421. if(org>0 && !exact){
  1422. /* org is an estimate of the char posn; find a newline */
  1423. /* don't try harder than 256 chars */
  1424. for(i=0; i<256 && org<w->nr; i++){
  1425. if(w->r[org] == '\n'){
  1426. org++;
  1427. break;
  1428. }
  1429. org++;
  1430. }
  1431. }
  1432. a = org-w->org;
  1433. fixup = 0;
  1434. if(a>=0 && a<w->nchars){
  1435. frdelete(w, 0, a);
  1436. fixup = 1; /* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */
  1437. }else if(a<0 && -a<w->nchars){
  1438. n = w->org - org;
  1439. r = runemalloc(n);
  1440. runemove(r, w->r+org, n);
  1441. frinsert(w, r, r+n, 0);
  1442. free(r);
  1443. }else
  1444. frdelete(w, 0, w->nchars);
  1445. w->org = org;
  1446. wfill(w);
  1447. wscrdraw(w);
  1448. wsetselect(w, w->q0, w->q1);
  1449. if(fixup && w->p1 > w->p0)
  1450. frdrawsel(w, frptofchar(w, w->p1-1), w->p1-1, w->p1, 1);
  1451. }
  1452. void
  1453. wsetselect(Window *w, uint q0, uint q1)
  1454. {
  1455. int p0, p1;
  1456. /* w->p0 and w->p1 are always right; w->q0 and w->q1 may be off */
  1457. w->q0 = q0;
  1458. w->q1 = q1;
  1459. /* compute desired p0,p1 from q0,q1 */
  1460. p0 = q0-w->org;
  1461. p1 = q1-w->org;
  1462. if(p0 < 0)
  1463. p0 = 0;
  1464. if(p1 < 0)
  1465. p1 = 0;
  1466. if(p0 > w->nchars)
  1467. p0 = w->nchars;
  1468. if(p1 > w->nchars)
  1469. p1 = w->nchars;
  1470. if(p0==w->p0 && p1==w->p1)
  1471. return;
  1472. /* screen disagrees with desired selection */
  1473. if(w->p1<=p0 || p1<=w->p0 || p0==p1 || w->p1==w->p0){
  1474. /* no overlap or too easy to bother trying */
  1475. frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 0);
  1476. frdrawsel(w, frptofchar(w, p0), p0, p1, 1);
  1477. goto Return;
  1478. }
  1479. /* overlap; avoid unnecessary painting */
  1480. if(p0 < w->p0){
  1481. /* extend selection backwards */
  1482. frdrawsel(w, frptofchar(w, p0), p0, w->p0, 1);
  1483. }else if(p0 > w->p0){
  1484. /* trim first part of selection */
  1485. frdrawsel(w, frptofchar(w, w->p0), w->p0, p0, 0);
  1486. }
  1487. if(p1 > w->p1){
  1488. /* extend selection forwards */
  1489. frdrawsel(w, frptofchar(w, w->p1), w->p1, p1, 1);
  1490. }else if(p1 < w->p1){
  1491. /* trim last part of selection */
  1492. frdrawsel(w, frptofchar(w, p1), p1, w->p1, 0);
  1493. }
  1494. Return:
  1495. w->p0 = p0;
  1496. w->p1 = p1;
  1497. }
  1498. uint
  1499. winsert(Window *w, Rune *r, int n, uint q0)
  1500. {
  1501. uint m;
  1502. if(n == 0)
  1503. return q0;
  1504. if(w->nr+n>HiWater && q0>=w->org && q0>=w->qh){
  1505. m = min(HiWater-LoWater, min(w->org, w->qh));
  1506. w->org -= m;
  1507. w->qh -= m;
  1508. if(w->q0 > m)
  1509. w->q0 -= m;
  1510. else
  1511. w->q0 = 0;
  1512. if(w->q1 > m)
  1513. w->q1 -= m;
  1514. else
  1515. w->q1 = 0;
  1516. w->nr -= m;
  1517. runemove(w->r, w->r+m, w->nr);
  1518. q0 -= m;
  1519. }
  1520. if(w->nr+n > w->maxr){
  1521. /*
  1522. * Minimize realloc breakage:
  1523. * Allocate at least MinWater
  1524. * Double allocation size each time
  1525. * But don't go much above HiWater
  1526. */
  1527. m = max(min(2*(w->nr+n), HiWater), w->nr+n)+MinWater;
  1528. if(m > HiWater)
  1529. m = max(HiWater+MinWater, w->nr+n);
  1530. if(m > w->maxr){
  1531. w->r = runerealloc(w->r, m);
  1532. w->maxr = m;
  1533. }
  1534. }
  1535. runemove(w->r+q0+n, w->r+q0, w->nr-q0);
  1536. runemove(w->r+q0, r, n);
  1537. w->nr += n;
  1538. /* if output touches, advance selection, not qh; works best for keyboard and output */
  1539. if(q0 <= w->q1)
  1540. w->q1 += n;
  1541. if(q0 <= w->q0)
  1542. w->q0 += n;
  1543. if(q0 < w->qh)
  1544. w->qh += n;
  1545. if(q0 < w->org)
  1546. w->org += n;
  1547. else if(q0 <= w->org+w->nchars)
  1548. frinsert(w, r, r+n, q0-w->org);
  1549. return q0;
  1550. }
  1551. void
  1552. wfill(Window *w)
  1553. {
  1554. Rune *rp;
  1555. int i, n, m, nl;
  1556. if(w->lastlinefull)
  1557. return;
  1558. rp = malloc(messagesize);
  1559. do{
  1560. n = w->nr-(w->org+w->nchars);
  1561. if(n == 0)
  1562. break;
  1563. if(n > 2000) /* educated guess at reasonable amount */
  1564. n = 2000;
  1565. runemove(rp, w->r+(w->org+w->nchars), n);
  1566. /*
  1567. * it's expensive to frinsert more than we need, so
  1568. * count newlines.
  1569. */
  1570. nl = w->maxlines-w->nlines;
  1571. m = 0;
  1572. for(i=0; i<n; ){
  1573. if(rp[i++] == '\n'){
  1574. m++;
  1575. if(m >= nl)
  1576. break;
  1577. }
  1578. }
  1579. frinsert(w, rp, rp+i, w->nchars);
  1580. }while(w->lastlinefull == FALSE);
  1581. free(rp);
  1582. }
  1583. char*
  1584. wcontents(Window *w, int *ip)
  1585. {
  1586. return runetobyte(w->r, w->nr, ip);
  1587. }