wind.c 32 KB

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