| #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 "dat.h" | 
 | #include "fns.h" | 
 |  | 
 | static Image *scrtmp; | 
 |  | 
 | static | 
 | void | 
 | scrtemps(void) | 
 | { | 
 | 	int h; | 
 |  | 
 | 	if(scrtmp) | 
 | 		return; | 
 | 	h = BIG*Dy(screen->r); | 
 | 	scrtmp = allocimage(display, Rect(0, 0, 32, h), screen->chan, 0, DWhite); | 
 | 	if(scrtmp == nil) | 
 | 		error("scrtemps"); | 
 | } | 
 |  | 
 | void | 
 | freescrtemps(void) | 
 | { | 
 | 	freeimage(scrtmp); | 
 | 	scrtmp = nil; | 
 | } | 
 |  | 
 | static | 
 | Rectangle | 
 | scrpos(Rectangle r, uint p0, uint p1, uint tot) | 
 | { | 
 | 	Rectangle q; | 
 | 	int h; | 
 |  | 
 | 	q = r; | 
 | 	h = q.max.y-q.min.y; | 
 | 	if(tot == 0) | 
 | 		return q; | 
 | 	if(tot > 1024*1024){ | 
 | 		tot>>=10; | 
 | 		p0>>=10; | 
 | 		p1>>=10; | 
 | 	} | 
 | 	if(p0 > 0) | 
 | 		q.min.y += h*p0/tot; | 
 | 	if(p1 < tot) | 
 | 		q.max.y -= h*(tot-p1)/tot; | 
 | 	if(q.max.y < q.min.y+2){ | 
 | 		if(q.min.y+2 <= r.max.y) | 
 | 			q.max.y = q.min.y+2; | 
 | 		else | 
 | 			q.min.y = q.max.y-2; | 
 | 	} | 
 | 	return q; | 
 | } | 
 |  | 
 | void | 
 | wscrdraw(Window *w) | 
 | { | 
 | 	Rectangle r, r1, r2; | 
 | 	Image *b; | 
 |  | 
 | 	scrtemps(); | 
 | 	if(w->i == nil) | 
 | 		error("scrdraw"); | 
 | 	r = w->scrollr; | 
 | 	b = scrtmp; | 
 | 	r1 = r; | 
 | 	r1.min.x = 0; | 
 | 	r1.max.x = Dx(r); | 
 | 	r2 = scrpos(r1, w->org, w->org+w->f.nchars, w->nr); | 
 | 	if(!eqrect(r2, w->lastsr)){ | 
 | 		w->lastsr = r2; | 
 | 		/* move r1, r2 to (0,0) to avoid clipping */ | 
 | 		r2 = rectsubpt(r2, r1.min); | 
 | 		r1 = rectsubpt(r1, r1.min); | 
 | 		draw(b, r1, w->f.cols[BORD], nil, ZP); | 
 | 		draw(b, r2, w->f.cols[BACK], nil, ZP); | 
 | 		r2.min.x = r2.max.x-1; | 
 | 		draw(b, r2, w->f.cols[BORD], nil, ZP); | 
 | 		draw(w->i, r, b, nil, Pt(0, r1.min.y)); | 
 | 	} | 
 | } | 
 |  | 
 | void | 
 | wscrsleep(Window *w, uint dt) | 
 | { | 
 | 	Timer	*timer; | 
 | 	int y, b; | 
 | 	static Alt alts[3]; | 
 |  | 
 | 	timer = timerstart(dt); | 
 | 	y = w->mc.m.xy.y; | 
 | 	b = w->mc.m.buttons; | 
 | 	alts[0].c = timer->c; | 
 | 	alts[0].v = nil; | 
 | 	alts[0].op = CHANRCV; | 
 | 	alts[1].c = w->mc.c; | 
 | 	alts[1].v = &w->mc.m; | 
 | 	alts[1].op = CHANRCV; | 
 | 	alts[2].op = CHANEND; | 
 | 	for(;;) | 
 | 		switch(alt(alts)){ | 
 | 		case 0: | 
 | 			timerstop(timer); | 
 | 			return; | 
 | 		case 1: | 
 | 			if(abs(w->mc.m.xy.y-y)>2 || w->mc.m.buttons!=b){ | 
 | 				timercancel(timer); | 
 | 				return; | 
 | 			} | 
 | 			break; | 
 | 		} | 
 | } | 
 |  | 
 | void | 
 | wscroll(Window *w, int but) | 
 | { | 
 | 	uint p0, oldp0; | 
 | 	Rectangle s; | 
 | 	int x, y, my, h, first; | 
 |  | 
 | 	s = insetrect(w->scrollr, 1); | 
 | 	h = s.max.y-s.min.y; | 
 | 	x = (s.min.x+s.max.x)/2; | 
 | 	oldp0 = ~0; | 
 | 	first = TRUE; | 
 | 	do{ | 
 | 		flushimage(display, 1); | 
 | 		if(w->mc.m.xy.x<s.min.x || s.max.x<=w->mc.m.xy.x){ | 
 | 			readmouse(&w->mc); | 
 | 		}else{ | 
 | 			my = w->mc.m.xy.y; | 
 | 			if(my < s.min.y) | 
 | 				my = s.min.y; | 
 | 			if(my >= s.max.y) | 
 | 				my = s.max.y; | 
 | 			if(!eqpt(w->mc.m.xy, Pt(x, my))){ | 
 | 				wmovemouse(w, Pt(x, my)); | 
 | 				readmouse(&w->mc);		/* absorb event generated by moveto() */ | 
 | 			} | 
 | 			if(but == 2){ | 
 | 				y = my; | 
 | 				if(y > s.max.y-2) | 
 | 					y = s.max.y-2; | 
 | 				if(w->nr > 1024*1024) | 
 | 					p0 = ((w->nr>>10)*(y-s.min.y)/h)<<10; | 
 | 				else | 
 | 					p0 = w->nr*(y-s.min.y)/h; | 
 | 				if(oldp0 != p0) | 
 | 					wsetorigin(w, p0, FALSE); | 
 | 				oldp0 = p0; | 
 | 				readmouse(&w->mc); | 
 | 				continue; | 
 | 			} | 
 | 			if(but == 1) | 
 | 				p0 = wbacknl(w, w->org, (my-s.min.y)/w->f.font->height); | 
 | 			else | 
 | 				p0 = w->org+frcharofpt(&w->f, Pt(s.max.x, my)); | 
 | 			if(oldp0 != p0) | 
 | 				wsetorigin(w, p0, TRUE); | 
 | 			oldp0 = p0; | 
 | 			/* debounce */ | 
 | 			if(first){ | 
 | 				flushimage(display, 1); | 
 | 				sleep(200); | 
 | 				nbrecv(w->mc.c, &w->mc.m); | 
 | 				first = FALSE; | 
 | 			} | 
 | 			wscrsleep(w, 100); | 
 | 		} | 
 | 	}while(w->mc.m.buttons & (1<<(but-1))); | 
 | 	while(w->mc.m.buttons) | 
 | 		readmouse(&w->mc); | 
 | } |