1779 lines · 33.6 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <cursor.h>#include <mouse.h>#include <keyboard.h>#include <frame.h>#include <fcall.h>#include <plumb.h>#include <complete.h>#include "dat.h"#include "fns.h" enum{	HiWater	= 640000,	/* max size of history */	LoWater	= 400000,	/* min size of history after max'ed */	MinWater	= 20000,	/* room to leave available when reallocating */}; static	int	topped;static	int	id;static	Cursor	*lastcursor; Window*wmk(Image *i, Mousectl *mc, Channel *ck, Channel *cctl, int scrolling){	Window *w;	Rectangle r; 	w = emalloc(sizeof(Window));	w->screenr = i->r;	r = insetrect(i->r, Selborder+1);	w->i = i;	w->mc = *mc;	w->ck = ck;	w->cctl = cctl;	w->cursorp = nil;	w->conswrite = chancreate(sizeof(Conswritemesg), 0);	w->consread =  chancreate(sizeof(Consreadmesg), 0);	w->kbdread =  chancreate(sizeof(Consreadmesg), 0);	w->mouseread =  chancreate(sizeof(Mousereadmesg), 0);	w->wctlread =  chancreate(sizeof(Consreadmesg), 0);	w->complete = chancreate(sizeof(Completion*), 0);	w->gone = chancreate(sizeof(char*), 0);	w->scrollr = r;	w->scrollr.max.x = r.min.x+Scrollwid;	w->lastsr = ZR;	r.min.x += Scrollwid+Scrollgap;	frinit(w, r, font, i, cols);	w->maxtab = maxtab*stringwidth(font, "0");	w->topped = ++topped;	w->id = ++id;	w->notefd = -1;	w->scrolling = scrolling;	w->dir = estrdup(startdir);	w->label = estrdup("<unnamed>");	r = insetrect(w->i->r, Selborder);	draw(w->i, r, cols[BACK], nil, w->entire.min);	wborder(w, Selborder);	wscrdraw(w);	incref(w);	/* ref will be removed after mounting; avoids delete before ready to be deleted */	return w;} voidwsetname(Window *w){	int i, n;	char err[ERRMAX];		n = snprint(w->name, sizeof(w->name)-2, "window.%d.%d", w->id, w->namecount++);	for(i='A'; i<='Z'; i++){		if(nameimage(w->i, w->name, 1) > 0)			return;		errstr(err, sizeof err);		if(strcmp(err, "image name in use") != 0)			break;		w->name[n] = i;		w->name[n+1] = 0;	}	w->name[0] = 0;	fprint(2, "rio: setname failed: %s\n", err);} voidwresize(Window *w, Image *i){	Rectangle r; 	wclosewin(w);	w->i = i;	w->mc.image = i;	r = insetrect(i->r, Selborder+1);	w->scrollr = r;	w->scrollr.max.x = r.min.x+Scrollwid;	w->lastsr = ZR;	r.min.x += Scrollwid+Scrollgap;	frclear(w, FALSE);	frinit(w, r, w->font, w->i, cols);	wsetcols(w, 1);	w->maxtab = maxtab*stringwidth(w->font, "0");	r = insetrect(w->i->r, Selborder);	draw(w->i, r, cols[BACK], nil, w->entire.min);	wfill(w);	wsetselect(w, w->q0, w->q1);	wscrdraw(w);	wborder(w, Selborder);	flushimage(display, 1);	wsetname(w);	w->topped = ++topped;	w->resized = TRUE;	w->mouse.counter++;	w->wctlready = 1;} voidwrefresh(Window *w){	Rectangle r; 	if(w == input)		wborder(w, Selborder);	else		wborder(w, Unselborder);	r = insetrect(w->i->r, Selborder);	draw(w->i, r, w->cols[BACK], nil, w->entire.min);	w->ticked = 0;	if(w->p0 > 0)		frdrawsel(w, frptofchar(w, 0), 0, w->p0, 0);	if(w->p1 < w->nchars)		frdrawsel(w, frptofchar(w, w->p1), w->p1, w->nchars, 0);	frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 1);	w->lastsr = ZR;	wscrdraw(w);} intwclose(Window *w){	int i; 	i = decref(w);	if(i > 0)		return 0;	if(i < 0)		error("negative ref count");	wclunk(w);	wsendctlmesg(w, Exited, ZR, nil);	return 1;} voidshowcandidates(Window *, Completion *); voidwinctl(void *arg){	Rune *rp, *up, r;	uint qh, q0;	int nr, nb, c, wid, i, npart, initial, lastb;	char *s, *t, part[3];	Window *w;	Mousestate *mp, m;	enum { WKbd, WKbdread, WMouse, WMouseread, WCtl, WCwrite, WCread, WWread, WComplete, Wgone, NWALT };	Alt alts[NWALT+1];	Consreadmesg crm;	Mousereadmesg mrm;	Conswritemesg cwm;	Stringpair pair;	Wctlmesg wcm;	Completion *cr;	char *kbdq[32], *kbds;	uint kbdqr, kbdqw; 	w = arg;	threadsetname("winctl-id%d", w->id); 	mrm.cm = chancreate(sizeof(Mouse), 0);	crm.c1 = chancreate(sizeof(Stringpair), 0);	crm.c2 = chancreate(sizeof(Stringpair), 0);	cwm.cw = chancreate(sizeof(Stringpair), 0);		alts[WKbd].c = w->ck;	alts[WKbd].v = &kbds;	alts[WKbd].op = CHANRCV;	alts[WKbdread].c = w->kbdread;	alts[WKbdread].v = &crm;	alts[WKbdread].op = CHANSND;	alts[WMouse].c = w->mc.c;	alts[WMouse].v = &w->mc.Mouse;	alts[WMouse].op = CHANRCV;	alts[WMouseread].c = w->mouseread;	alts[WMouseread].v = &mrm;	alts[WMouseread].op = CHANSND;	alts[WCtl].c = w->cctl;	alts[WCtl].v = &wcm;	alts[WCtl].op = CHANRCV;	alts[WCwrite].c = w->conswrite;	alts[WCwrite].v = &cwm;	alts[WCwrite].op = CHANSND;	alts[WCread].c = w->consread;	alts[WCread].v = &crm;	alts[WCread].op = CHANSND;	alts[WWread].c = w->wctlread;	alts[WWread].v = &crm;	alts[WWread].op = CHANSND;	alts[WComplete].c = w->complete;	alts[WComplete].v = &cr;	alts[WComplete].op = CHANRCV;	alts[Wgone].c = w->gone;	alts[Wgone].v = "window deleted";	alts[Wgone].op = CHANNOP;	alts[NWALT].op = CHANEND; 	kbdqr = kbdqw = 0;	npart = 0;	lastb = -1;	for(;;){		if(w->i==nil){			/* window deleted */			alts[Wgone].op = CHANSND; 			alts[WKbdread].op = CHANNOP;			alts[WMouseread].op = CHANNOP;			alts[WCwrite].op = CHANNOP;			alts[WWread].op = CHANNOP;			alts[WCread].op = CHANNOP;		} else {			alts[WKbdread].op = (w->kbdopen && kbdqw != kbdqr) ?				CHANSND : CHANNOP;			alts[WMouseread].op = (w->mouseopen && w->mouse.counter != w->mouse.lastcounter) ? 				CHANSND : CHANNOP;			alts[WCwrite].op = w->scrolling || w->mouseopen || (w->qh <= w->org+w->nchars) ?				CHANSND : CHANNOP;			alts[WWread].op = w->wctlready ?				CHANSND : CHANNOP;			/* this code depends on NL and EOT fitting in a single byte */			/* kind of expensive for each loop; worth precomputing? */			if(w->holding)				alts[WCread].op = CHANNOP;			else if(npart || (w->rawing && w->nraw>0))				alts[WCread].op = CHANSND;			else{				alts[WCread].op = CHANNOP;				for(i=w->qh; i<w->nr; i++){					c = w->r[i];					if(c=='\n' || c=='\004'){						alts[WCread].op = CHANSND;						break;					}				}			}		}		switch(alt(alts)){		case WKbd:			if(kbdqw - kbdqr < nelem(kbdq))				kbdq[kbdqw++ % nelem(kbdq)] = kbds;			else				free(kbds);			if(w->kbdopen)				continue;			while(kbdqr != kbdqw){				kbds = kbdq[kbdqr++ % nelem(kbdq)];				if(*kbds == 'c'){					chartorune(&r, kbds+1);					if(r)						wkeyctl(w, r);				}				free(kbds);			}			break;		case WKbdread:			recv(crm.c1, &pair);			nb = 0;			while(kbdqr != kbdqw){				kbds = kbdq[kbdqr % nelem(kbdq)];				i = strlen(kbds)+1;				if(nb+i > pair.ns)					break;				memmove((char*)pair.s + nb, kbds, i);				free(kbds);				nb += i;				kbdqr++;			}			pair.ns = nb;			send(crm.c2, &pair);			continue;		case WMouse:			if(w->mouseopen) {				w->mouse.counter++; 				/* queue click events */				if(!w->mouse.qfull && lastb != w->mc.buttons) {	/* add to ring */					mp = &w->mouse.queue[w->mouse.wi];					if(++w->mouse.wi == nelem(w->mouse.queue))						w->mouse.wi = 0;					if(w->mouse.wi == w->mouse.ri)						w->mouse.qfull = TRUE;					mp->Mouse = w->mc;					mp->counter = w->mouse.counter;					lastb = w->mc.buttons;				}			} else				wmousectl(w);			break;		case WMouseread:			/* send a queued event or, if the queue is empty, the current state */			/* if the queue has filled, we discard all the events it contained. */			/* the intent is to discard frantic clicking by the user during long latencies. */			w->mouse.qfull = FALSE;			if(w->mouse.wi != w->mouse.ri) {				m = w->mouse.queue[w->mouse.ri];				if(++w->mouse.ri == nelem(w->mouse.queue))					w->mouse.ri = 0;			} else				m = (Mousestate){w->mc.Mouse, w->mouse.counter}; 			w->mouse.lastcounter = m.counter;			send(mrm.cm, &m.Mouse);			continue;		case WCtl:			if(wctlmesg(w, wcm.type, wcm.r, wcm.p) == Exited){				while(kbdqr != kbdqw)					free(kbdq[kbdqr++ % nelem(kbdq)]);				chanfree(crm.c1);				chanfree(crm.c2);				chanfree(mrm.cm);				chanfree(cwm.cw);				threadexits(nil);			}			continue;		case WCwrite:			recv(cwm.cw, &pair);			rp = pair.s;			nr = pair.ns;			for(i=0; i<nr; i++)				if(rp[i] == '\b'){					up = rp+i;					initial = 0;					for(; i<nr; i++){						if(rp[i] == '\b'){							if(up == rp)								initial++;							else								up--;						}else							*up++ = rp[i];					}					if(initial){						if(initial > w->qh)							initial = w->qh;						qh = w->qh-initial;						wdelete(w, qh, qh+initial);						w->qh = qh;					}					nr = up - rp;					break;				}			w->qh = winsert(w, rp, nr, w->qh)+nr;			if(w->scrolling || w->mouseopen)				wshow(w, w->qh);			wsetselect(w, w->q0, w->q1);			wscrdraw(w);			free(rp);			break;		case WCread:			recv(crm.c1, &pair);			t = pair.s;			nb = pair.ns;			i = npart;			npart = 0;			if(i)				memmove(t, part, i);			while(i<nb && (w->qh<w->nr || w->nraw>0)){				if(w->qh == w->nr){					wid = runetochar(t+i, &w->raw[0]);					w->nraw--;					runemove(w->raw, w->raw+1, w->nraw);				}else					wid = runetochar(t+i, &w->r[w->qh++]);				c = t[i];	/* knows break characters fit in a byte */				i += wid;				if(!w->rawing && (c == '\n' || c=='\004')){					if(c == '\004')						i--;					break;				}			}			if(i==nb && w->qh<w->nr && w->r[w->qh]=='\004')				w->qh++;			if(i > nb){				npart = i-nb;				memmove(part, t+nb, npart);				i = nb;			}			pair.s = t;			pair.ns = i;			send(crm.c2, &pair);			continue;		case WWread:			w->wctlready = 0;			recv(crm.c1, &pair);			s = Dx(w->screenr) > 0 ? "visible" : "hidden";			t = "notcurrent";			if(w == input)				t = "current";			pair.ns = snprint(pair.s, pair.ns, "%11d %11d %11d %11d %s %s ",				w->i->r.min.x, w->i->r.min.y, w->i->r.max.x, w->i->r.max.y, t, s);			send(crm.c2, &pair);			continue;		case WComplete:			if(w->i!=nil){				if(!cr->advance)					showcandidates(w, cr);				if(cr->advance){					rp = runesmprint("%s", cr->string);					if(rp){						nr = runestrlen(rp);						q0 = w->q0;						q0 = winsert(w, rp, nr, q0);						wshow(w, q0+nr);						free(rp);					}				}			}			freecompletion(cr);			break;		}		if(w->i!=nil && Dx(w->screenr) > 0 && display->bufp > display->buf)			flushimage(display, 1);	}} voidwaddraw(Window *w, Rune *r, int nr){	w->raw = runerealloc(w->raw, w->nraw+nr);	runemove(w->raw+w->nraw, r, nr);	w->nraw += nr;} /* * Need to do this in a separate proc because if process we're interrupting * is dying and trying to print tombstone, kernel is blocked holding p->debug lock. */voidinterruptproc(void *v){	int *notefd; 	notefd = v;	write(*notefd, "interrupt", 9);	close(*notefd);	free(notefd);} intwindfilewidth(Window *w, uint q0, int oneelement){	uint q;	Rune r; 	q = q0;	while(q > 0){		r = w->r[q-1];		if(r<=' ' || r=='=' || r=='^' || r=='(' || r=='{')			break;		if(oneelement && r=='/')			break;		--q;	}	return q0-q;} voidshowcandidates(Window *w, Completion *c){	int i;	Fmt f;	Rune *rp;	uint nr, qline;	char *s; 	runefmtstrinit(&f);	if (c->nmatch == 0)		s = "[no matches in ";	else		s = "[";	if(c->nfile > 32)		fmtprint(&f, "%s%d files]\n", s, c->nfile);	else{		fmtprint(&f, "%s", s);		for(i=0; i<c->nfile; i++){			if(i > 0)				fmtprint(&f, " ");			fmtprint(&f, "%s", c->filename[i]);		}		fmtprint(&f, "]\n");

Lines 1–500 of 1779.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t