20 for(i=0; i<nwindow; i++)
21 if(window[i]->id == id)
33 for(i=0; i<nwindow; i++){
35 if(ptinrect(pt, v->screenr))
36 if(w==nil || v->topped>w->topped)
47 if(w!=nil && w->i!=nil && w->topped!=topped){
50 flushimage(display, 1);
57 if(w!=nil && w->i!=nil){
58 w->topped = - ++topped;
60 flushimage(display, 1);
74 wsendctlmesg(w, Topped, ZR, nil);
92 c = chancreate(sizeof(Window*), 0);
93 wsendctlmesg(input, Repaint, ZR, c);
94 sendp(c, w); /* send the new input */
95 wclose(recvp(c)); /* release old input */
100 wuncurrent(Window *w)
104 if(input == nil || w != input)
106 c = chancreate(sizeof(Window*), 0);
107 wsendctlmesg(w, Repaint, ZR, c);
113 static Cursor *lastcursor;
116 riosetcursor(Cursor *p)
120 setcursor(mousectl, p);
125 wsetcursor(Window *w, int force)
129 if(menuing || sweeping || (w!=input && wpointto(mouse->xy)!=w))
135 if(p==nil && w->holding)
138 if(p && force) /* force cursor reload */
144 waddraw(Window *w, Rune *r, int nr)
146 w->raw = runerealloc(w->raw, w->nraw+nr);
147 runemove(w->raw+w->nraw, r, nr);
153 HiWater = 640000, /* max size of history */
154 LoWater = 400000, /* min size of history after max'ed */
155 MinWater = 20000, /* room to leave available when reallocating */
159 winsert(Window *w, Rune *r, int n, uint q0)
165 if(w->nr+n>HiWater && q0>=w->org && q0>=w->qh){
166 m = min(HiWater-LoWater, min(w->org, w->qh));
178 runemove(w->r, w->r+m, w->nr);
181 if(w->nr+n > w->maxr){
183 * Minimize realloc breakage:
184 * Allocate at least MinWater
185 * Double allocation size each time
186 * But don't go much above HiWater
188 m = max(min(2*(w->nr+n), HiWater), w->nr+n)+MinWater;
190 m = max(HiWater+MinWater, w->nr+n);
192 w->r = runerealloc(w->r, m);
196 runemove(w->r+q0+n, w->r+q0, w->nr-q0);
197 runemove(w->r+q0, r, n);
199 /* if output touches, advance selection, not qh; works best for keyboard and output */
208 else if(q0 <= w->org+w->nchars)
209 frinsert(w, r, r+n, q0-w->org);
219 while(w->lastlinefull == FALSE){
220 n = w->nr-(w->org+w->nchars);
223 if(n > 2000) /* educated guess at reasonable amount */
225 rp = w->r+(w->org+w->nchars);
228 * it's expensive to frinsert more than we need, so
231 nl = w->maxlines-w->nlines;
240 frinsert(w, rp, rp+i, w->nchars);
245 wsetselect(Window *w, uint q0, uint q1)
249 /* w->p0 and w->p1 are always right; w->q0 and w->q1 may be off */
252 /* compute desired p0,p1 from q0,q1 */
263 if(p0==w->p0 && p1==w->p1)
265 /* screen disagrees with desired selection */
266 if(w->p1<=p0 || p1<=w->p0 || p0==p1 || w->p1==w->p0){
267 /* no overlap or too easy to bother trying */
268 frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 0);
269 frdrawsel(w, frptofchar(w, p0), p0, p1, 1);
272 /* overlap; avoid unnecessary painting */
274 /* extend selection backwards */
275 frdrawsel(w, frptofchar(w, p0), p0, w->p0, 1);
276 }else if(p0 > w->p0){
277 /* trim first part of selection */
278 frdrawsel(w, frptofchar(w, w->p0), w->p0, p0, 0);
281 /* extend selection forwards */
282 frdrawsel(w, frptofchar(w, w->p1), w->p1, p1, 1);
283 }else if(p1 < w->p1){
284 /* trim last part of selection */
285 frdrawsel(w, frptofchar(w, p1), p1, w->p1, 0);
294 wborder(Window *w, int type)
301 if(type == Selborder)
306 if(type == Selborder)
311 border(w->i, w->i->r, Selborder, col, ZP);
315 wsetcols(Window *w, int topped)
319 w->cols[TEXT] = holdcol;
321 w->cols[TEXT] = lightholdcol;
324 w->cols[TEXT] = cols[TEXT];
326 w->cols[TEXT] = paletextcol;
335 n = snprint(w->name, sizeof(w->name)-2, "window.%d.%d", w->id, w->namecount++);
336 for(i='A'; i<='Z'; i++){
337 if(nameimage(w->i, w->name, 1) > 0)
339 errstr(err, sizeof err);
340 if(strcmp(err, "image name in use") != 0)
346 fprint(2, "rio: setname failed: %s\n", err);
350 wresize(Window *w, Image *i)
356 r = insetrect(i->r, Selborder+1);
358 w->scrollr.max.x = r.min.x+Scrollwid;
360 r.min.x += Scrollwid+Scrollgap;
362 frinit(w, r, w->font, w->i, cols);
363 wsetcols(w, w == input);
364 w->maxtab = maxtab*stringwidth(w->font, "0");
365 if(!w->mouseopen || !w->winnameread){
366 r = insetrect(w->i->r, Selborder);
367 draw(w->i, r, cols[BACK], nil, w->entire.min);
369 wsetselect(w, w->q0, w->q1);
373 wborder(w, Selborder);
375 wborder(w, Unselborder);
376 flushimage(display, 1);
378 w->topped = ++topped;
380 w->winnameread = FALSE;
381 w->mc.buttons = 0; /* avoid re-triggering clicks on resize */
389 wsetcols(w, w == input);
390 if(!w->mouseopen || !w->winnameread)
393 wborder(w, Selborder);
395 wborder(w, Unselborder);
404 wborder(w, Selborder);
406 wborder(w, Unselborder);
407 r = insetrect(w->i->r, Selborder);
408 draw(w->i, r, w->cols[BACK], nil, w->entire.min);
412 frdrawsel(w, frptofchar(w, 0), 0, w->p0, 0);
413 if(w->p1 < w->nchars)
414 frdrawsel(w, frptofchar(w, w->p1), w->p1, w->nchars, 0);
415 frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 1);
421 * Need to do this in a separate proc because if process we're interrupting
422 * is dying and trying to print tombstone, kernel is blocked holding p->debug lock.
425 interruptproc(void *v)
430 write(*notefd, "interrupt", 9);
435 typedef struct Completejob Completejob;
444 completeproc(void *arg)
450 threadsetname("namecomplete %s", job->dir);
452 c = complete(job->dir, job->str);
453 if(c != nil && sendp(job->win->complete, c) <= 0)
464 windfilewidth(Window *w, uint q0, int oneelement)
472 if(r<=' ' || r=='=' || r=='^' || r=='(' || r=='{')
474 if(oneelement && r=='/')
482 namecomplete(Window *w)
489 /* control-f: filename completion; works back to white space or / */
490 if(w->q0<w->nr && w->r[w->q0]>' ') /* must be at end of word */
492 nstr = windfilewidth(w, w->q0, TRUE);
493 str = w->r+(w->q0-nstr);
494 npath = windfilewidth(w, w->q0-nstr, FALSE);
495 path = w->r+(w->q0-nstr-npath);
497 /* is path rooted? if not, we need to make it relative to window path */
498 if(npath>0 && path[0]=='/')
499 dir = runetobyte(path, npath, &npath);
501 if(strcmp(w->dir, "") == 0)
505 dir = smprint("%s/%.*S", root, npath, path);
510 /* run in background, winctl will collect the result on w->complete chan */
511 job = emalloc(sizeof *job);
512 job->str = runetobyte(str, nstr, &nstr);
513 job->dir = cleanname(dir);
516 proccreate(completeproc, job, STACK);
520 showcandidates(Window *w, Completion *c)
530 s = "[no matches in ";
534 fmtprint(&f, "%s%d files]\n", s, c->nfile);
536 fmtprint(&f, "%s", s);
537 for(i=0; i<c->nfile; i++){
540 fmtprint(&f, "%s", c->filename[i]);
544 rp = runefmtstrflush(&f);
547 /* place text at beginning of line before cursor and host point */
548 qline = min(w->qh, w->q0);
549 while(qline>0 && w->r[qline-1] != '\n')
553 /* advance host point to avoid readback */
554 w->qh = winsert(w, rp, nr, qline)+nr;
556 winsert(w, rp, nr, qline);
562 wbswidth(Window *w, Rune c)
568 /* there is known to be at least one character to erase */
569 if(c == 0x08) /* ^H: erase character */
578 if(r == '\n'){ /* eat at most one more character */
579 if(q == w->q0) /* eat the newline */
585 if(eq && skipping) /* found one; stop skipping */
587 else if(!eq && !skipping)
596 wsetorigin(Window *w, uint org, int exact)
603 /* org is an estimate of the char posn; find a newline */
604 /* don't try harder than 256 chars */
605 for(i=0; i<256 && org<w->nr; i++){
606 if(w->r[org] == '\n'){
615 if(a>=0 && a<w->nchars){
617 fixup = 1; /* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */
618 }else if(a<0 && -a<w->nchars){
621 frinsert(w, r, r+n, 0);
623 frdelete(w, 0, w->nchars);
627 wsetselect(w, w->q0, w->q1);
628 if(fixup && w->p1 > w->p0)
629 frdrawsel(w, frptofchar(w, w->p1-1), w->p1-1, w->p1, 1);
633 wbacknl(Window *w, uint p, uint n)
637 /* look for start of this line if n==0 */
638 if(n==0 && p>0 && w->r[p-1]!='\n')
642 --p; /* it's at a newline now; back over it */
645 /* at 128 chars, call it a line anyway */
646 for(j=128; --j>0 && p>0; p--)
654 wcontents(Window *w, int *ip)
656 return runetobyte(w->r, w->nr, ip);
660 wshow(Window *w, uint q0)
666 qe = w->org+w->nchars;
667 if(w->org<=q0 && (q0<qe || (q0==qe && qe==w->nr)))
670 nl = 4*w->maxlines/5;
671 q = wbacknl(w, q0, nl);
672 /* avoid going backwards if trying to go forwards - long lines! */
673 if(!(q0>w->org && q<w->org))
674 wsetorigin(w, q, TRUE);
675 while(q0 > w->org+w->nchars)
676 wsetorigin(w, w->org+1, FALSE);
685 nsnarf = w->q1-w->q0;
686 snarf = runerealloc(snarf, nsnarf);
687 snarfversion++; /* maybe modified by parent */
688 runemove(snarf, w->r+w->q0, nsnarf);
700 waddraw(w, snarf, nsnarf);
701 if(snarf[nsnarf-1]!='\n' && snarf[nsnarf-1]!='\004')
702 waddraw(w, L"\n", 1);
704 winsert(w, snarf, nsnarf, w->nr);
705 if(snarf[nsnarf-1]!='\n' && snarf[nsnarf-1]!='\004')
706 winsert(w, L"\n", 1, w->nr);
708 wsetselect(w, w->nr, w->nr);
713 wdelete(Window *w, uint q0, uint q1)
720 runemove(w->r+q0, w->r+q1, w->nr-q1);
723 w->q0 -= min(n, w->q0-q0);
725 w->q1 -= min(n, w->q1-q0);
732 else if(q0 < w->org+w->nchars){
751 wdelete(w, w->q0, w->q1);
752 wsetselect(w, w->q0, w->q0);
764 if(w->rawing && q0==w->nr){
765 waddraw(w, snarf, nsnarf);
766 wsetselect(w, q0, q0);
768 q0 = winsert(w, snarf, nsnarf, w->q0);
769 wsetselect(w, q0, q0+nsnarf);
787 while(runestrncmp(w->r+w->q0, w->r+i, n) != 0){
794 wsetselect(w, i, i+n);
808 fd = plumbopen("send", OWRITE|OCEXEC);
811 m = emalloc(sizeof(Plumbmsg));
812 m->src = estrdup("rio");
814 m->wdir = estrdup(w->dir);
815 m->type = estrdup("text");
821 while(p0>0 && w->r[p0-1]!=' ' && w->r[p0-1]!='\t' && w->r[p0-1]!='\n')
823 while(p1<w->nr && w->r[p1]!=' ' && w->r[p1]!='\t' && w->r[p1]!='\n')
825 snprint(buf, sizeof(buf), "click=%d", w->q0-p0);
826 m->attr = plumbunpackattr(buf);
828 if(p1-p0 > messagesize-1024){
830 return; /* too large for 9P */
832 m->data = runetobyte(w->r+p0, p1-p0, &m->ndata);
833 if(plumbsend(fd, m) < 0){
835 riosetcursor(&query);
843 wkeyctl(Window *w, Rune r)
862 /* navigation keys work only when mouse and kbd is not open */
866 n = shiftdown ? 1 : w->maxlines/3;
869 n = mousescrollsize(w->maxlines);
876 q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+n*w->font->height));
877 wsetorigin(w, q0, TRUE);
880 n = shiftdown ? 1 : w->maxlines/3;
883 n = mousescrollsize(w->maxlines);
890 q0 = wbacknl(w, w->org, n);
891 wsetorigin(w, q0, TRUE);
896 wsetselect(w, q0, q0);
903 wsetselect(w, q1, q1);
917 case Ksoh: /* ^A: beginning of line */
918 if(w->q0==0 || w->q0==w->qh || w->r[w->q0-1]=='\n')
920 nb = wbswidth(w, 0x15 /* ^U */);
921 wsetselect(w, w->q0-nb, w->q0-nb);
924 case Kenq: /* ^E: end of line */
926 while(q0 < w->nr && w->r[q0]!='\n')
928 wsetselect(w, q0, q0);
931 case Kstx: /* ^B: output point */
932 wsetselect(w, w->qh, w->qh);
936 if(w->rawing && (w->q0==w->nr || w->mouseopen)){
940 if(r==Kesc || (w->holding && r==Kdel)){ /* toggle hold */
945 wsetcursor(w, FALSE);
955 case Kdel: /* send interrupt */
960 notefd = emalloc(sizeof(int));
961 *notefd = dup(w->notefd, -1);
962 proccreate(interruptproc, notefd, 4096);
964 case Kack: /* ^F: file name completion */
965 case Kins: /* Insert: file name completion */
968 case Kbs: /* ^H: erase character */
969 case Knack: /* ^U: erase line */
970 case Ketb: /* ^W: erase word */
971 if(w->q0==0 || w->q0==w->qh)
981 wdelete(w, q0, q0+nb);
982 wsetselect(w, q0, q0);
986 /* otherwise ordinary character; just insert */
988 q0 = winsert(w, &r, 1, q0);
992 static Window *clickwin;
993 static uint clickmsec;
994 static Point clickpt;
995 static uint clickcount;
996 static Window *selectwin;
1000 wframescroll(Window *w, int dl)
1009 q0 = wbacknl(w, w->org, -dl);
1010 if(selectq > w->org+w->p0)
1011 wsetselect(w, w->org+w->p0, selectq);
1013 wsetselect(w, selectq, w->org+w->p0);
1015 if(w->org+w->nchars == w->nr)
1017 q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+dl*w->font->height));
1018 if(selectq >= w->org+w->p1)
1019 wsetselect(w, w->org+w->p1, selectq);
1021 wsetselect(w, selectq, w->org+w->p1);
1023 wsetorigin(w, q0, TRUE);
1027 * called from frame library
1030 framescroll(Frame *f, int dl)
1032 if(f != &selectwin->Frame)
1033 error("frameselect not right frame");
1034 wframescroll(selectwin, dl);
1037 static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 };
1038 static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };
1039 static Rune left2[] = { L'\n', 0 };
1040 static Rune left3[] = { L'\'', L'"', L'`', 0 };
1042 static Rune *left[] = {
1048 static Rune *right[] = {
1056 wclickmatch(Window *w, int cl, int cr, int dir, uint *q)
1080 return cl=='\n' && nest==1;
1084 inmode(Rune r, int mode)
1086 return (mode == 1) ? isalnum(r) : r && !isspace(r);
1090 wstretchsel(Window *w, uint pt, uint *q0, uint *q1, int mode)
1098 for(i=0; left[i]!=nil; i++){
1102 /* try matching character to left, looking right */
1109 if(wclickmatch(w, c, r[p-l], 1, &q))
1113 /* try matching character to right, looking left */
1120 if(wclickmatch(w, c, l[p-r], -1, &q)){
1121 *q1 = *q0+(*q0<w->nr && c=='\n');
1123 if(c!='\n' || q!=0 || w->r[0]=='\n')
1129 /* try filling out word to right */
1130 while(*q1<w->nr && inmode(w->r[*q1], mode))
1132 /* try filling out word to left */
1133 while(*q0>0 && inmode(w->r[*q0-1], mode))
1141 int b, x, y, dx, dy, mode, first;
1146 * Double-click immediately if it might make sense.
1151 dx = abs(clickpt.x - w->mc.xy.x);
1152 dy = abs(clickpt.y - w->mc.xy.y);
1154 selectq = w->org+frcharofpt(w, w->mc.xy);
1156 if(w->mc.msec-clickmsec >= 500 || clickwin != w || clickcount > 3 || dx > 3 || dy > 3)
1158 if(clickwin == w && clickcount >= 1 && w->mc.msec-clickmsec < 500){
1159 mode = (clickcount > 2) ? 2 : clickcount;
1160 wstretchsel(w, selectq, &q0, &q1, mode);
1161 wsetselect(w, q0, q1);
1164 /* stay here until something interesting happens */
1167 dx = abs(w->mc.xy.x-x);
1168 dy = abs(w->mc.xy.y-y);
1169 if(w->mc.buttons != b || dx >= 3 && dy >= 3)
1172 clickmsec = w->mc.msec;
1174 w->mc.xy.x = x; /* in case we're calling frselect */
1176 q0 = w->q0; /* may have changed */
1178 selectq = w->org+frcharofpt(w, w->mc.xy);
1180 if(w->mc.buttons == b && clickcount == 0){
1181 w->scroll = framescroll;
1182 frselect(w, &w->mc);
1183 /* horrible botch: while asleep, may have lost selection altogether */
1185 selectq = w->org + w->p0;
1186 w->Frame.scroll = nil;
1187 if(selectq < w->org)
1190 q0 = w->org + w->p0;
1191 if(selectq > w->org+w->nchars)
1197 mode = (clickcount > 2) ? 2 : clickcount;
1198 if(q0==w->q0 && clickwin==w && w->mc.msec-clickmsec<500)
1199 wstretchsel(w, selectq, &q0, &q1, mode);
1202 clickmsec = w->mc.msec;
1204 wsetselect(w, q0, q1);
1205 while(w->mc.buttons){
1221 while(w->mc.buttons == b)
1223 if(w->mc.msec-clickmsec >= 500)
1229 * Convert back to physical coordinates
1232 wmovemouse(Window *w, Point p)
1234 if(w != input || menuing || sweeping)
1236 p.x += w->screenr.min.x-w->i->r.min.x;
1237 p.y += w->screenr.min.y-w->i->r.min.y;
1238 moveto(mousectl, p);
1243 wmk(Image *i, Mousectl *mc, Channel *ck, Channel *cctl, int scrolling)
1250 w = emalloc(sizeof(Window));
1252 r = insetrect(i->r, Selborder+1);
1258 w->conswrite = chancreate(sizeof(Conswritemesg), 0);
1259 w->consread = chancreate(sizeof(Consreadmesg), 0);
1260 w->kbdread = chancreate(sizeof(Consreadmesg), 0);
1261 w->mouseread = chancreate(sizeof(Mousereadmesg), 0);
1262 w->wctlread = chancreate(sizeof(Consreadmesg), 0);
1263 w->complete = chancreate(sizeof(Completion*), 0);
1264 w->gone = chancreate(sizeof(char*), 0);
1266 w->scrollr.max.x = r.min.x+Scrollwid;
1268 r.min.x += Scrollwid+Scrollgap;
1269 frinit(w, r, font, i, cols);
1270 w->maxtab = maxtab*stringwidth(font, "0");
1271 w->topped = ++topped;
1274 w->scrolling = scrolling;
1275 w->dir = estrdup(startdir);
1276 w->label = estrdup("<unnamed>");
1277 r = insetrect(w->i->r, Selborder);
1278 draw(w->i, r, cols[BACK], nil, w->entire.min);
1279 wborder(w, Selborder);
1281 incref(w); /* ref will be removed after mounting; avoids delete before ready to be deleted */
1286 wclosewin(Window *w)
1292 /* move it off-screen to hide it, in case client is slow in letting it go */
1293 originwindow(i, i->r.min, view->r.max);
1311 for(i=0; i<nhidden; i++)
1314 memmove(hidden+i, hidden+i+1, (nhidden-i)*sizeof(hidden[0]));
1317 for(i=0; i<nwindow; i++)
1320 memmove(window+i, window+i+1, (nwindow-i)*sizeof(window[0]));
1334 error("negative ref count");
1336 wsendctlmesg(w, Exited, ZR, nil);
1341 wsendctlmesg(Window *w, int type, Rectangle r, void *p)
1348 send(w->cctl, &wcm);
1352 wctlmesg(Window *w, int m, Rectangle r, void *p)
1358 error("unknown control message");
1370 wsetcursor(w, FALSE);
1376 wsetcursor(w, FALSE);
1377 /* fall thrugh for redraw after input change */
1380 /* sync with input change from wcurrent()/wuncurrent() */
1384 /* when we lost input, release mouse buttons */
1393 if(w->i==nil || Dx(w->screenr)<=0)
1396 flushimage(display, 1);
1399 if(w->i==nil || Dx(w->screenr)<=0)
1402 flushimage(display, 1);
1405 if(w->i==nil || Dx(w->screenr)<=0 || !ptinrect(r.min, w->i->r))
1407 wmovemouse(w, r.min);
1412 wkeyctl(w, w->raw[0]);
1414 runemove(w->raw, w->raw+1, w->nraw);
1421 wsetcursor(w, FALSE);
1423 flushimage(display, 1);
1426 wdelete(w, 0, w->nr);
1431 write(w->notefd, "hangup", 6);
1433 flushimage(display, 1);
1438 flushimage(display, 1);
1444 chanfree(w->conswrite);
1445 chanfree(w->consread);
1446 chanfree(w->mouseread);
1447 chanfree(w->wctlread);
1448 chanfree(w->kbdread);
1449 chanfree(w->complete);
1462 wmousectl(Window *w)
1469 if(w->mc.buttons == 1<<(but-1))
1473 incref(w); /* hold up window while we track */
1475 if(shiftdown && but > 3)
1476 wkeyctl(w, but == 4 ? Kscrolloneup : Kscrollonedown);
1477 else if(ptinrect(w->mc.xy, w->scrollr) || (but > 3))
1490 int nr, nb, c, wid, i, npart, initial, lastb;
1491 char *s, *t, part[3];
1494 enum { WKbd, WKbdread, WMouse, WMouseread, WCtl, WCwrite, WCread, WWread, WComplete, Wgone, NWALT };
1502 char *kbdq[32], *kbds;
1506 threadsetname("winctl-id%d", w->id);
1508 mrm.cm = chancreate(sizeof(Mouse), 0);
1509 crm.c1 = chancreate(sizeof(Stringpair), 0);
1510 crm.c2 = chancreate(sizeof(Stringpair), 0);
1511 cwm.cw = chancreate(sizeof(Stringpair), 0);
1513 alts[WKbd].c = w->ck;
1514 alts[WKbd].v = &kbds;
1515 alts[WKbd].op = CHANRCV;
1516 alts[WKbdread].c = w->kbdread;
1517 alts[WKbdread].v = &crm;
1518 alts[WKbdread].op = CHANSND;
1519 alts[WMouse].c = w->mc.c;
1520 alts[WMouse].v = &w->mc.Mouse;
1521 alts[WMouse].op = CHANRCV;
1522 alts[WMouseread].c = w->mouseread;
1523 alts[WMouseread].v = &mrm;
1524 alts[WMouseread].op = CHANSND;
1525 alts[WCtl].c = w->cctl;
1526 alts[WCtl].v = &wcm;
1527 alts[WCtl].op = CHANRCV;
1528 alts[WCwrite].c = w->conswrite;
1529 alts[WCwrite].v = &cwm;
1530 alts[WCwrite].op = CHANSND;
1531 alts[WCread].c = w->consread;
1532 alts[WCread].v = &crm;
1533 alts[WCread].op = CHANSND;
1534 alts[WWread].c = w->wctlread;
1535 alts[WWread].v = &crm;
1536 alts[WWread].op = CHANSND;
1537 alts[WComplete].c = w->complete;
1538 alts[WComplete].v = &cr;
1539 alts[WComplete].op = CHANRCV;
1540 alts[Wgone].c = w->gone;
1541 alts[Wgone].v = "window deleted";
1542 alts[Wgone].op = CHANNOP;
1543 alts[NWALT].op = CHANEND;
1550 /* window deleted */
1551 alts[Wgone].op = CHANSND;
1553 alts[WKbdread].op = CHANNOP;
1554 alts[WMouseread].op = CHANNOP;
1555 alts[WCwrite].op = CHANNOP;
1556 alts[WWread].op = CHANNOP;
1557 alts[WCread].op = CHANNOP;
1559 alts[WKbdread].op = (w->kbdopen && kbdqw != kbdqr) ?
1561 alts[WMouseread].op = (w->mouseopen && w->mouse.counter != w->mouse.lastcounter) ?
1563 alts[WCwrite].op = w->scrolling || w->mouseopen || (w->qh <= w->org+w->nchars) ?
1565 alts[WWread].op = w->wctlready ?
1567 /* this code depends on NL and EOT fitting in a single byte */
1568 /* kind of expensive for each loop; worth precomputing? */
1570 alts[WCread].op = CHANNOP;
1571 else if(npart || (w->rawing && w->nraw>0))
1572 alts[WCread].op = CHANSND;
1574 alts[WCread].op = CHANNOP;
1575 for(i=w->qh; i<w->nr; i++){
1577 if(c=='\n' || c=='\004'){
1578 alts[WCread].op = CHANSND;
1586 if(kbdqw - kbdqr < nelem(kbdq))
1587 kbdq[kbdqw++ % nelem(kbdq)] = kbds;
1592 while(kbdqr != kbdqw){
1593 kbds = kbdq[kbdqr++ % nelem(kbdq)];
1595 chartorune(&r, kbds+1);
1603 recv(crm.c1, &pair);
1605 while(kbdqr != kbdqw){
1606 kbds = kbdq[kbdqr % nelem(kbdq)];
1610 memmove((char*)pair.s + nb, kbds, i);
1616 send(crm.c2, &pair);
1622 /* queue click events */
1623 if(!w->mouse.qfull && lastb != w->mc.buttons) { /* add to ring */
1624 mp = &w->mouse.queue[w->mouse.wi];
1625 if(++w->mouse.wi == nelem(w->mouse.queue))
1627 if(w->mouse.wi == w->mouse.ri)
1628 w->mouse.qfull = TRUE;
1630 mp->counter = w->mouse.counter;
1631 lastb = w->mc.buttons;
1637 /* send a queued event or, if the queue is empty, the current state */
1638 /* if the queue has filled, we discard all the events it contained. */
1639 /* the intent is to discard frantic clicking by the user during long latencies. */
1640 w->mouse.qfull = FALSE;
1641 if(w->mouse.wi != w->mouse.ri) {
1642 m = w->mouse.queue[w->mouse.ri];
1643 if(++w->mouse.ri == nelem(w->mouse.queue))
1646 m = (Mousestate){w->mc.Mouse, w->mouse.counter};
1648 w->mouse.lastcounter = m.counter;
1649 send(mrm.cm, &m.Mouse);
1652 if(wctlmesg(w, wcm.type, wcm.r, wcm.p) == Exited){
1653 while(kbdqr != kbdqw)
1654 free(kbdq[kbdqr++ % nelem(kbdq)]);
1663 recv(cwm.cw, &pair);
1683 wdelete(w, qh, qh+initial);
1689 w->qh = winsert(w, rp, nr, w->qh)+nr;
1690 if(w->scrolling || w->mouseopen)
1692 wsetselect(w, w->q0, w->q1);
1697 recv(crm.c1, &pair);
1703 memmove(t, part, i);
1704 while(i<nb && (w->qh<w->nr || w->nraw>0)){
1706 wid = runetochar(t+i, &w->raw[0]);
1708 runemove(w->raw, w->raw+1, w->nraw);
1710 wid = runetochar(t+i, &w->r[w->qh++]);
1711 c = t[i]; /* knows break characters fit in a byte */
1713 if(!w->rawing && (c == '\n' || c=='\004')){
1719 if(i==nb && w->qh<w->nr && w->r[w->qh]=='\004')
1723 memmove(part, t+nb, npart);
1728 send(crm.c2, &pair);
1732 recv(crm.c1, &pair);
1733 s = Dx(w->screenr) > 0 ? "visible" : "hidden";
1737 pair.ns = snprint(pair.s, pair.ns+1, "%11d %11d %11d %11d %11s %11s ",
1738 w->i->r.min.x, w->i->r.min.y, w->i->r.max.x, w->i->r.max.y, t, s);
1739 send(crm.c2, &pair);
1744 showcandidates(w, cr);
1746 rp = runesmprint("%s", cr->string);
1748 nr = runestrlen(rp);
1750 q0 = winsert(w, rp, nr, q0);
1759 if(w->i!=nil && Dx(w->screenr) > 0 && display->bufp > display->buf)
1760 flushimage(display, 1);
1765 wsetpid(Window *w, int pid, int dolabel)
1775 snprint(buf, sizeof(buf), "rc %lud", (ulong)pid);
1777 w->label = estrdup(buf);
1779 snprint(buf, sizeof(buf), "/proc/%lud/notepg", (ulong)pid);
1780 w->notefd = open(buf, OWRITE|OCEXEC);
1787 winshell(void *args)
1801 rfork(RFNAMEG|RFFDG|RFENVG);
1802 if(filsysmount(filsys, w->id) < 0){
1803 fprint(2, "mount failed: %r\n");
1805 threadexits("mount failed");
1808 if(open("/dev/cons", OREAD) < 0){
1809 fprint(2, "can't open /dev/cons: %r\n");
1811 threadexits("/dev/cons");
1814 if(open("/dev/cons", OWRITE) < 0){
1815 fprint(2, "can't open /dev/cons: %r\n");
1817 threadexits("open"); /* BUG? was terminate() */
1819 if(wclose(w) == 0){ /* remove extra ref hanging from creation */
1824 procexec(pidc, cmd, argv);
1825 _exits("exec failed");