xref: /plan9/sys/src/cmd/rio/rio.c (revision 144145943e440fe30c4e4512a0856f5e3d5ca4be)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <thread.h>
57dd7cddfSDavid du Colombier #include <cursor.h>
67dd7cddfSDavid du Colombier #include <mouse.h>
77dd7cddfSDavid du Colombier #include <keyboard.h>
87dd7cddfSDavid du Colombier #include <frame.h>
97dd7cddfSDavid du Colombier #include <auth.h>
107dd7cddfSDavid du Colombier #include <fcall.h>
117dd7cddfSDavid du Colombier #include <plumb.h>
127dd7cddfSDavid du Colombier #include "dat.h"
137dd7cddfSDavid du Colombier #include "fns.h"
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier /*
167dd7cddfSDavid du Colombier  *  WASHINGTON (AP) - The Food and Drug Administration warned
177dd7cddfSDavid du Colombier  * consumers Wednesday not to use ``Rio'' hair relaxer products
187dd7cddfSDavid du Colombier  * because they may cause severe hair loss or turn hair green....
197dd7cddfSDavid du Colombier  *    The FDA urged consumers who have experienced problems with Rio
207dd7cddfSDavid du Colombier  * to notify their local FDA office, local health department or the
217dd7cddfSDavid du Colombier  * company at 1‑800‑543‑3002.
227dd7cddfSDavid du Colombier  */
237dd7cddfSDavid du Colombier 
247dd7cddfSDavid du Colombier void		resize(void);
257dd7cddfSDavid du Colombier void		move(void);
267dd7cddfSDavid du Colombier void		delete(void);
277dd7cddfSDavid du Colombier void		hide(void);
287dd7cddfSDavid du Colombier void		unhide(int);
297dd7cddfSDavid du Colombier void		newtile(int);
307dd7cddfSDavid du Colombier Image	*sweep(void);
317dd7cddfSDavid du Colombier Image	*bandsize(Window*);
327dd7cddfSDavid du Colombier Image*	drag(Window*, Rectangle*);
337dd7cddfSDavid du Colombier void		refresh(Rectangle);
347dd7cddfSDavid du Colombier void		resized(void);
357dd7cddfSDavid du Colombier Channel	*exitchan;	/* chan(int) */
367dd7cddfSDavid du Colombier Channel	*winclosechan; /* chan(Window*); */
377dd7cddfSDavid du Colombier Rectangle	viewr;
387dd7cddfSDavid du Colombier int		threadrforkflag = 0;	/* should be RFENVG but that hides rio from plumber */
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier void	mousethread(void*);
417dd7cddfSDavid du Colombier void	keyboardthread(void*);
427dd7cddfSDavid du Colombier void winclosethread(void*);
437dd7cddfSDavid du Colombier void deletethread(void*);
447dd7cddfSDavid du Colombier void	initcmd(void*);
457dd7cddfSDavid du Colombier 
467dd7cddfSDavid du Colombier char		*fontname;
477dd7cddfSDavid du Colombier int		mainpid;
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier enum
507dd7cddfSDavid du Colombier {
517dd7cddfSDavid du Colombier 	New,
527dd7cddfSDavid du Colombier 	Reshape,
537dd7cddfSDavid du Colombier 	Move,
547dd7cddfSDavid du Colombier 	Delete,
557dd7cddfSDavid du Colombier 	Hide,
567dd7cddfSDavid du Colombier 	Exit,
577dd7cddfSDavid du Colombier };
587dd7cddfSDavid du Colombier 
597dd7cddfSDavid du Colombier enum
607dd7cddfSDavid du Colombier {
617dd7cddfSDavid du Colombier 	Cut,
627dd7cddfSDavid du Colombier 	Paste,
637dd7cddfSDavid du Colombier 	Snarf,
647dd7cddfSDavid du Colombier 	Plumb,
657dd7cddfSDavid du Colombier 	Send,
667dd7cddfSDavid du Colombier 	Scroll,
677dd7cddfSDavid du Colombier };
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier char		*menu2str[] = {
707dd7cddfSDavid du Colombier  [Cut]		"cut",
717dd7cddfSDavid du Colombier  [Paste]		"paste",
727dd7cddfSDavid du Colombier  [Snarf]		"snarf",
737dd7cddfSDavid du Colombier  [Plumb]		"plumb",
747dd7cddfSDavid du Colombier  [Send]		"send",
757dd7cddfSDavid du Colombier  [Scroll]		"scroll",
767dd7cddfSDavid du Colombier 			nil
777dd7cddfSDavid du Colombier };
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier Menu menu2 =
807dd7cddfSDavid du Colombier {
817dd7cddfSDavid du Colombier 	menu2str
827dd7cddfSDavid du Colombier };
837dd7cddfSDavid du Colombier 
847dd7cddfSDavid du Colombier int	Hidden = Exit+1;
857dd7cddfSDavid du Colombier 
867dd7cddfSDavid du Colombier char		*menu3str[100] = {
877dd7cddfSDavid du Colombier  [New]		"New",
887dd7cddfSDavid du Colombier  [Reshape]	"Resize",
897dd7cddfSDavid du Colombier  [Move]		"Move",
907dd7cddfSDavid du Colombier  [Delete]		"Delete",
917dd7cddfSDavid du Colombier  [Hide]		"Hide",
927dd7cddfSDavid du Colombier  [Exit]		"Exit",
937dd7cddfSDavid du Colombier 			nil
947dd7cddfSDavid du Colombier };
957dd7cddfSDavid du Colombier 
967dd7cddfSDavid du Colombier Menu menu3 =
977dd7cddfSDavid du Colombier {
987dd7cddfSDavid du Colombier 	menu3str
997dd7cddfSDavid du Colombier };
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier char *rcargv[] = { "rc", "-i", nil };
1027dd7cddfSDavid du Colombier 
1037dd7cddfSDavid du Colombier int errorshouldabort = 0;
1047dd7cddfSDavid du Colombier 
1057dd7cddfSDavid du Colombier void
1067dd7cddfSDavid du Colombier derror(Display*, char *errorstr)
1077dd7cddfSDavid du Colombier {
1087dd7cddfSDavid du Colombier 	error(errorstr);
1097dd7cddfSDavid du Colombier }
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier void
1127dd7cddfSDavid du Colombier threadmain(int argc, char *argv[])
1137dd7cddfSDavid du Colombier {
1147dd7cddfSDavid du Colombier 	char *initstr, *s;
1157dd7cddfSDavid du Colombier 	static void *arg[1];
1167dd7cddfSDavid du Colombier 	char buf[256];
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier 	if(strstr(argv[0], ".out") == nil){
1197dd7cddfSDavid du Colombier 		menu3str[Exit] = nil;
1207dd7cddfSDavid du Colombier 		Hidden--;
1217dd7cddfSDavid du Colombier 	}
1227dd7cddfSDavid du Colombier 	initstr = nil;
1237dd7cddfSDavid du Colombier 	maxtab = 0;
1247dd7cddfSDavid du Colombier 	ARGBEGIN{
1257dd7cddfSDavid du Colombier 	case 'f':
1267dd7cddfSDavid du Colombier 		fontname = ARGF();
1277dd7cddfSDavid du Colombier 		break;
1287dd7cddfSDavid du Colombier 	case 'i':
1297dd7cddfSDavid du Colombier 		initstr = ARGF();
1307dd7cddfSDavid du Colombier 		break;
1317dd7cddfSDavid du Colombier 	case 's':
1327dd7cddfSDavid du Colombier 		scrolling = TRUE;
1337dd7cddfSDavid du Colombier 		break;
1347dd7cddfSDavid du Colombier 	}ARGEND
1357dd7cddfSDavid du Colombier 
1367dd7cddfSDavid du Colombier 	mainpid = getpid();
1377dd7cddfSDavid du Colombier 	if(getwd(buf, sizeof buf) == nil)
1387dd7cddfSDavid du Colombier 		startdir = estrdup(".");
1397dd7cddfSDavid du Colombier 	else
1407dd7cddfSDavid du Colombier 		startdir = estrdup(buf);
1417dd7cddfSDavid du Colombier 	if(fontname == nil)
1427dd7cddfSDavid du Colombier 		fontname = getenv("font");
1437dd7cddfSDavid du Colombier 	if(fontname == nil)
1447dd7cddfSDavid du Colombier 		fontname = "/lib/font/bit/lucm/unicode.9.font";
1457dd7cddfSDavid du Colombier 	s = getenv("tabstop");
1467dd7cddfSDavid du Colombier 	if(s != nil)
1477dd7cddfSDavid du Colombier 		maxtab = strtol(s, nil, 0);
1487dd7cddfSDavid du Colombier 	if(maxtab == 0)
1497dd7cddfSDavid du Colombier 		maxtab = 4;
1507dd7cddfSDavid du Colombier 	/* check font before barging ahead */
1517dd7cddfSDavid du Colombier 	if(access(fontname, 0) < 0){
1527dd7cddfSDavid du Colombier 		threadprint(2, "rio: can't access %s: %r\n", fontname);
1537dd7cddfSDavid du Colombier 		exits("font open");
1547dd7cddfSDavid du Colombier 	}
1557dd7cddfSDavid du Colombier 	putenv("font", fontname);
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier 	snarffd = open("/dev/snarf", OREAD|OCEXEC);
1587dd7cddfSDavid du Colombier 
159*14414594SDavid du Colombier 	if(geninitdraw(nil, derror, nil, "rio", nil, Refnone) < 0){
160*14414594SDavid du Colombier 		threadprint(2, "rio: can't open display: %r\n");
161*14414594SDavid du Colombier 		exits("display open");
162*14414594SDavid du Colombier 	}
1637dd7cddfSDavid du Colombier 	iconinit();
1647dd7cddfSDavid du Colombier 	view = screen;
1657dd7cddfSDavid du Colombier 	viewr = view->r;
1667dd7cddfSDavid du Colombier 	mousectl = initmouse(nil, screen);
1677dd7cddfSDavid du Colombier 	if(mousectl == nil)
1687dd7cddfSDavid du Colombier 		error("can't find mouse");
1697dd7cddfSDavid du Colombier 	mouse = mousectl;
1707dd7cddfSDavid du Colombier 	keyboardctl = initkeyboard(nil);
1717dd7cddfSDavid du Colombier 	if(keyboardctl == nil)
1727dd7cddfSDavid du Colombier 		error("can't find keyboard");
1737dd7cddfSDavid du Colombier 	wscreen = allocscreen(screen, background, 0);
1747dd7cddfSDavid du Colombier 	if(wscreen == nil)
1757dd7cddfSDavid du Colombier 		error("can't allocate screen");
1767dd7cddfSDavid du Colombier 	draw(view, viewr, background, nil, ZP);
1777dd7cddfSDavid du Colombier 	flushimage(display, 1);
1787dd7cddfSDavid du Colombier 
1797dd7cddfSDavid du Colombier 	exitchan = chancreate(sizeof(int), 0);
1807dd7cddfSDavid du Colombier 	winclosechan = chancreate(sizeof(Window*), 0);
1817dd7cddfSDavid du Colombier 	deletechan = chancreate(sizeof(char*), 0);
1827dd7cddfSDavid du Colombier 
1837dd7cddfSDavid du Colombier 	timerinit();
1847dd7cddfSDavid du Colombier 	threadcreate(keyboardthread, nil, STACK);
1857dd7cddfSDavid du Colombier 	threadcreate(mousethread, nil, STACK);
1867dd7cddfSDavid du Colombier 	threadcreate(winclosethread, nil, STACK);
1877dd7cddfSDavid du Colombier 	threadcreate(deletethread, nil, STACK);
1887dd7cddfSDavid du Colombier 	filsys = filsysinit(xfidinit());
1897dd7cddfSDavid du Colombier 
1907dd7cddfSDavid du Colombier 	if(filsys == nil)
1917dd7cddfSDavid du Colombier 		fprint(2, "rio: can't create file system server: %r\n");
1927dd7cddfSDavid du Colombier 	else{
1937dd7cddfSDavid du Colombier 		errorshouldabort = 1;	/* suicide if there's trouble after this */
1947dd7cddfSDavid du Colombier 		if(initstr)
1957dd7cddfSDavid du Colombier 			proccreate(initcmd, initstr, STACK);
1967dd7cddfSDavid du Colombier 		notify(shutdown);/**/
1977dd7cddfSDavid du Colombier 		recv(exitchan, nil);
1987dd7cddfSDavid du Colombier 	}
1997dd7cddfSDavid du Colombier 	killprocs();
2007dd7cddfSDavid du Colombier 	threadexitsall(nil);
2017dd7cddfSDavid du Colombier }
2027dd7cddfSDavid du Colombier 
2037dd7cddfSDavid du Colombier /*
2047dd7cddfSDavid du Colombier  * /dev/snarf updates when the file is closed, so we must open our own
2057dd7cddfSDavid du Colombier  * fd here rather than use snarffd
2067dd7cddfSDavid du Colombier  */
2077dd7cddfSDavid du Colombier void
2087dd7cddfSDavid du Colombier putsnarf(void)
2097dd7cddfSDavid du Colombier {
2107dd7cddfSDavid du Colombier 	int fd, i, n;
2117dd7cddfSDavid du Colombier 
2127dd7cddfSDavid du Colombier 	if(snarffd<0 || nsnarf==0)
2137dd7cddfSDavid du Colombier 		return;
2147dd7cddfSDavid du Colombier 	fd = open("/dev/snarf", OWRITE);
2157dd7cddfSDavid du Colombier 	if(fd < 0)
2167dd7cddfSDavid du Colombier 		return;
2177dd7cddfSDavid du Colombier 	/* snarf buffer could be huge, so fprint will truncate; do it in blocks */
2187dd7cddfSDavid du Colombier 	for(i=0; i<nsnarf; i+=n){
2197dd7cddfSDavid du Colombier 		n = nsnarf-i;
2207dd7cddfSDavid du Colombier 		if(n >= 256)
2217dd7cddfSDavid du Colombier 			n = 256;
2227dd7cddfSDavid du Colombier 		if(threadprint(fd, "%.*S", n, snarf+i) < 0)
2237dd7cddfSDavid du Colombier 			break;
2247dd7cddfSDavid du Colombier 	}
2257dd7cddfSDavid du Colombier 	close(fd);
2267dd7cddfSDavid du Colombier }
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier void
2297dd7cddfSDavid du Colombier getsnarf(void)
2307dd7cddfSDavid du Colombier {
2317dd7cddfSDavid du Colombier 	int i, n, nb, nulls;
2327dd7cddfSDavid du Colombier 	char *sn, buf[1024];
2337dd7cddfSDavid du Colombier 
2347dd7cddfSDavid du Colombier 	if(snarffd < 0)
2357dd7cddfSDavid du Colombier 		return;
2367dd7cddfSDavid du Colombier 	sn = nil;
2377dd7cddfSDavid du Colombier 	i = 0;
2387dd7cddfSDavid du Colombier 	seek(snarffd, 0, 0);
2397dd7cddfSDavid du Colombier 	while((n = read(snarffd, buf, sizeof buf)) > 0){
2407dd7cddfSDavid du Colombier 		sn = erealloc(sn, i+n+1);
2417dd7cddfSDavid du Colombier 		memmove(sn+i, buf, n);
2427dd7cddfSDavid du Colombier 		i += n;
2437dd7cddfSDavid du Colombier 		sn[i] = 0;
2447dd7cddfSDavid du Colombier 	}
2457dd7cddfSDavid du Colombier 	if(i > 0){
2467dd7cddfSDavid du Colombier 		snarf = runerealloc(snarf, i+1);
2477dd7cddfSDavid du Colombier 		cvttorunes(sn, i, snarf, &nb, &nsnarf, &nulls);
2487dd7cddfSDavid du Colombier 		free(sn);
2497dd7cddfSDavid du Colombier 	}
2507dd7cddfSDavid du Colombier }
2517dd7cddfSDavid du Colombier 
2527dd7cddfSDavid du Colombier void
2537dd7cddfSDavid du Colombier initcmd(void *arg)
2547dd7cddfSDavid du Colombier {
2557dd7cddfSDavid du Colombier 	char *cmd;
2567dd7cddfSDavid du Colombier 
2577dd7cddfSDavid du Colombier 	cmd = arg;
2587dd7cddfSDavid du Colombier 	rfork(RFENVG|RFFDG|RFNOTEG|RFNAMEG);
2597dd7cddfSDavid du Colombier 	procexecl(nil, "/bin/rc", "rc", "-c", cmd, 0);
2607dd7cddfSDavid du Colombier 	threadprint(2, "rio: exec failed: %r\n");
2617dd7cddfSDavid du Colombier 	exits("exec");
2627dd7cddfSDavid du Colombier }
2637dd7cddfSDavid du Colombier 
2647dd7cddfSDavid du Colombier char *oknotes[] =
2657dd7cddfSDavid du Colombier {
2667dd7cddfSDavid du Colombier 	"delete",
2677dd7cddfSDavid du Colombier 	"hangup",
2687dd7cddfSDavid du Colombier 	"kill",
2697dd7cddfSDavid du Colombier 	"exit",
2707dd7cddfSDavid du Colombier 	"kilall",	/* used internally by thread library during shutdown */
2717dd7cddfSDavid du Colombier 	nil
2727dd7cddfSDavid du Colombier };
2737dd7cddfSDavid du Colombier 
2747dd7cddfSDavid du Colombier void
2757dd7cddfSDavid du Colombier shutdown1(void *, char *msg)
2767dd7cddfSDavid du Colombier {
2777dd7cddfSDavid du Colombier 	int i;
2787dd7cddfSDavid du Colombier 
2797dd7cddfSDavid du Colombier 	killprocs();
2807dd7cddfSDavid du Colombier 	for(i=0; oknotes[i]; i++)
2817dd7cddfSDavid du Colombier 		if(strncmp(oknotes[i], msg, strlen(oknotes[i])) == 0)
2827dd7cddfSDavid du Colombier 			threadexitsall(msg);
2837dd7cddfSDavid du Colombier 	threadprint(2, "rio %d: abort: %s\n", getpid(), msg);
2847dd7cddfSDavid du Colombier 	abort();
2857dd7cddfSDavid du Colombier 	exits(msg);
2867dd7cddfSDavid du Colombier }
2877dd7cddfSDavid du Colombier 
2887dd7cddfSDavid du Colombier void
2897dd7cddfSDavid du Colombier shutdown(void *a, char *msg)	/* extra call to get stack trace on 386 */
2907dd7cddfSDavid du Colombier {
2917dd7cddfSDavid du Colombier 	shutdown1(a, msg);
2927dd7cddfSDavid du Colombier }
2937dd7cddfSDavid du Colombier 
2947dd7cddfSDavid du Colombier void
2957dd7cddfSDavid du Colombier killprocs(void)
2967dd7cddfSDavid du Colombier {
2977dd7cddfSDavid du Colombier 	int i;
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier 	filsysclose(filsys);
3007dd7cddfSDavid du Colombier 	for(i=0; i<nwindow; i++)
3017dd7cddfSDavid du Colombier 		postnote(PNGROUP, window[i]->pid, "hangup");
3027dd7cddfSDavid du Colombier 	remove(srvpipe);
3037dd7cddfSDavid du Colombier 	remove(srvwctl);
3047dd7cddfSDavid du Colombier }
3057dd7cddfSDavid du Colombier 
3067dd7cddfSDavid du Colombier void
3077dd7cddfSDavid du Colombier keyboardthread(void*)
3087dd7cddfSDavid du Colombier {
3097dd7cddfSDavid du Colombier 	Rune buf[2][20], *rp;
3107dd7cddfSDavid du Colombier 	int n, i;
3117dd7cddfSDavid du Colombier 
3127dd7cddfSDavid du Colombier 	n = 0;
3137dd7cddfSDavid du Colombier 	for(;;){
3147dd7cddfSDavid du Colombier 		if(nelem(buf[0])!=20)threadprint(2, "NO");
3157dd7cddfSDavid du Colombier 		rp = buf[n];
3167dd7cddfSDavid du Colombier 		n = 1-n;
3177dd7cddfSDavid du Colombier 		recv(keyboardctl->c, rp);
3187dd7cddfSDavid du Colombier 		for(i=1; i<nelem(buf[0])-1; i++)
3197dd7cddfSDavid du Colombier 			if(nbrecv(keyboardctl->c, rp+i) <= 0)
3207dd7cddfSDavid du Colombier 				break;
3217dd7cddfSDavid du Colombier 		rp[i] = L'\0';
3227dd7cddfSDavid du Colombier 		if(input != nil)
3237dd7cddfSDavid du Colombier 			sendp(input->ck, rp);
3247dd7cddfSDavid du Colombier 	}
3257dd7cddfSDavid du Colombier }
3267dd7cddfSDavid du Colombier 
3277dd7cddfSDavid du Colombier int
3287dd7cddfSDavid du Colombier portion(int x, int lo, int hi)
3297dd7cddfSDavid du Colombier {
3307dd7cddfSDavid du Colombier 	x -= lo;
3317dd7cddfSDavid du Colombier 	hi -= lo;
3327dd7cddfSDavid du Colombier 	if(x < 20)
3337dd7cddfSDavid du Colombier 		return 0;
3347dd7cddfSDavid du Colombier 	if(x > hi-20)
3357dd7cddfSDavid du Colombier 		return 2;
3367dd7cddfSDavid du Colombier 	return 1;
3377dd7cddfSDavid du Colombier }
3387dd7cddfSDavid du Colombier 
3397dd7cddfSDavid du Colombier int
3407dd7cddfSDavid du Colombier whichcorner(Window *w, Point p)
3417dd7cddfSDavid du Colombier {
3427dd7cddfSDavid du Colombier 	int i, j;
3437dd7cddfSDavid du Colombier 
3447dd7cddfSDavid du Colombier 	i = portion(p.x, w->screenr.min.x, w->screenr.max.x);
3457dd7cddfSDavid du Colombier 	j = portion(p.y, w->screenr.min.y, w->screenr.max.y);
3467dd7cddfSDavid du Colombier 	return 3*j+i;
3477dd7cddfSDavid du Colombier }
3487dd7cddfSDavid du Colombier 
3497dd7cddfSDavid du Colombier void
3507dd7cddfSDavid du Colombier cornercursor(Window *w, Point p, int force)
3517dd7cddfSDavid du Colombier {
3527dd7cddfSDavid du Colombier 	if(w!=nil && winborder(w, p))
3537dd7cddfSDavid du Colombier 		riosetcursor(corners[whichcorner(w, p)], force);
3547dd7cddfSDavid du Colombier 	else
3557dd7cddfSDavid du Colombier 		wsetcursor(w, force);
3567dd7cddfSDavid du Colombier }
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier /* thread to allow fsysproc to synchronize window closing with main proc */
3597dd7cddfSDavid du Colombier void
3607dd7cddfSDavid du Colombier winclosethread(void*)
3617dd7cddfSDavid du Colombier {
3627dd7cddfSDavid du Colombier 	Window *w;
3637dd7cddfSDavid du Colombier 
3647dd7cddfSDavid du Colombier 	for(;;){
3657dd7cddfSDavid du Colombier 		w = recvp(winclosechan);
3667dd7cddfSDavid du Colombier 		wclose(w);
3677dd7cddfSDavid du Colombier 	}
3687dd7cddfSDavid du Colombier }
3697dd7cddfSDavid du Colombier 
3707dd7cddfSDavid du Colombier /* thread to make Deleted windows that the client still holds disappear offscreen after an interval */
3717dd7cddfSDavid du Colombier void
3727dd7cddfSDavid du Colombier deletethread(void*)
3737dd7cddfSDavid du Colombier {
3747dd7cddfSDavid du Colombier 	char *s;
3757dd7cddfSDavid du Colombier 	Image *i;
3767dd7cddfSDavid du Colombier 
3777dd7cddfSDavid du Colombier 	for(;;){
3787dd7cddfSDavid du Colombier 		s = recvp(deletechan);
3797dd7cddfSDavid du Colombier 		i = namedimage(display, s);
3807dd7cddfSDavid du Colombier 		if(i != nil){
3817dd7cddfSDavid du Colombier 			/* move it off-screen to hide it, since client is slow in letting it go */
3827dd7cddfSDavid du Colombier 			originwindow(i, i->r.min, view->r.max);
3837dd7cddfSDavid du Colombier 		}
3847dd7cddfSDavid du Colombier 		freeimage(i);
3857dd7cddfSDavid du Colombier 		free(s);
3867dd7cddfSDavid du Colombier 	}
3877dd7cddfSDavid du Colombier }
3887dd7cddfSDavid du Colombier 
3897dd7cddfSDavid du Colombier void
3907dd7cddfSDavid du Colombier deletetimeoutproc(void *v)
3917dd7cddfSDavid du Colombier {
3927dd7cddfSDavid du Colombier 	char *s;
3937dd7cddfSDavid du Colombier 
3947dd7cddfSDavid du Colombier 	s = estrdup(v);
3957dd7cddfSDavid du Colombier 	sleep(750);	/* remove window from screen after 3/4 of a second */
3967dd7cddfSDavid du Colombier 	sendp(deletechan, s);
3977dd7cddfSDavid du Colombier }
3987dd7cddfSDavid du Colombier 
3997dd7cddfSDavid du Colombier void
4007dd7cddfSDavid du Colombier mousethread(void*)
4017dd7cddfSDavid du Colombier {
4027dd7cddfSDavid du Colombier 	int sending, inside, scrolling, moving, band;
4037dd7cddfSDavid du Colombier 	Window *oin, *w;
4047dd7cddfSDavid du Colombier 	Image *i;
4057dd7cddfSDavid du Colombier 	Rectangle r;
4067dd7cddfSDavid du Colombier 	Point xy;
4077dd7cddfSDavid du Colombier 	Mouse tmp;
4087dd7cddfSDavid du Colombier 	enum {
4097dd7cddfSDavid du Colombier 		MReshape,
4107dd7cddfSDavid du Colombier 		MMouse,
4117dd7cddfSDavid du Colombier 		NALT
4127dd7cddfSDavid du Colombier 	};
4137dd7cddfSDavid du Colombier 	static Alt alts[NALT+1];
4147dd7cddfSDavid du Colombier 
4157dd7cddfSDavid du Colombier 	sending = FALSE;
4167dd7cddfSDavid du Colombier 	scrolling = FALSE;
4177dd7cddfSDavid du Colombier 	moving = FALSE;
4187dd7cddfSDavid du Colombier 
4197dd7cddfSDavid du Colombier 	alts[MReshape].c = mousectl->resizec;
4207dd7cddfSDavid du Colombier 	alts[MReshape].v = nil;
4217dd7cddfSDavid du Colombier 	alts[MReshape].op = CHANRCV;
4227dd7cddfSDavid du Colombier 	alts[MMouse].c = mousectl->c;
4237dd7cddfSDavid du Colombier 	alts[MMouse].v = &mousectl->Mouse;
4247dd7cddfSDavid du Colombier 	alts[MMouse].op = CHANRCV;
4257dd7cddfSDavid du Colombier 	alts[NALT].op = CHANEND;
4267dd7cddfSDavid du Colombier 
4277dd7cddfSDavid du Colombier 	for(;;)
4287dd7cddfSDavid du Colombier 	    switch(alt(alts)){
4297dd7cddfSDavid du Colombier 		case MReshape:
4307dd7cddfSDavid du Colombier 			resized();
4317dd7cddfSDavid du Colombier 			break;
4327dd7cddfSDavid du Colombier 		case MMouse:
4337dd7cddfSDavid du Colombier 		Again:
4347dd7cddfSDavid du Colombier 			if(input!=nil && input->i!=nil){
4357dd7cddfSDavid du Colombier 				/* convert to logical coordinates */
4367dd7cddfSDavid du Colombier 				xy.x = mouse->xy.x + (input->i->r.min.x-input->screenr.min.x);
4377dd7cddfSDavid du Colombier 				xy.y = mouse->xy.y + (input->i->r.min.y-input->screenr.min.y);
4387dd7cddfSDavid du Colombier 				inside = ptinrect(mouse->xy, insetrect(input->screenr, Selborder));
4397dd7cddfSDavid du Colombier 				if(input->mouseopen)
4407dd7cddfSDavid du Colombier 					scrolling = FALSE;
4417dd7cddfSDavid du Colombier 				else if(scrolling)
4427dd7cddfSDavid du Colombier 					scrolling = mouse->buttons;
4437dd7cddfSDavid du Colombier 				else
4447dd7cddfSDavid du Colombier 					scrolling = mouse->buttons && ptinrect(xy, input->scrollr);
4457dd7cddfSDavid du Colombier 				/* topped will be zero if window has been bottomed */
4467dd7cddfSDavid du Colombier 				if(sending == FALSE && !scrolling && winborder(input, mouse->xy) && input->topped>0){
4477dd7cddfSDavid du Colombier 					moving = TRUE;
4487dd7cddfSDavid du Colombier 				}else if(inside && (scrolling || input->mouseopen || (mouse->buttons&1)))
4497dd7cddfSDavid du Colombier 					sending = TRUE;
4507dd7cddfSDavid du Colombier 			}else
4517dd7cddfSDavid du Colombier 				sending = FALSE;
4527dd7cddfSDavid du Colombier 			if(sending){
4537dd7cddfSDavid du Colombier 				if(mouse->buttons == 0){
4547dd7cddfSDavid du Colombier 					cornercursor(input, mouse->xy, 0);
4557dd7cddfSDavid du Colombier 					sending = FALSE;
4567dd7cddfSDavid du Colombier 				}else
4577dd7cddfSDavid du Colombier 					wsetcursor(input, 0);
4587dd7cddfSDavid du Colombier 				tmp = mousectl->Mouse;
4597dd7cddfSDavid du Colombier 				tmp.xy = xy;
4607dd7cddfSDavid du Colombier 				send(input->mc.c, &tmp);
4617dd7cddfSDavid du Colombier 				continue;
4627dd7cddfSDavid du Colombier 			}
4637dd7cddfSDavid du Colombier 			w = wpointto(mouse->xy);
4647dd7cddfSDavid du Colombier 			/* change cursor if over anyone's border */
4657dd7cddfSDavid du Colombier 			if(w != nil)
4667dd7cddfSDavid du Colombier 				cornercursor(w, mouse->xy, 0);
4677dd7cddfSDavid du Colombier 			else
4687dd7cddfSDavid du Colombier 				riosetcursor(nil, 0);
4697dd7cddfSDavid du Colombier 			if(moving && (mouse->buttons&7)){
4707dd7cddfSDavid du Colombier 				oin = input;
4717dd7cddfSDavid du Colombier 				band = mouse->buttons & 3;
4727dd7cddfSDavid du Colombier 				sweeping = 1;
4737dd7cddfSDavid du Colombier 				if(band)
4747dd7cddfSDavid du Colombier 					i = bandsize(input);
4757dd7cddfSDavid du Colombier 				else
4767dd7cddfSDavid du Colombier 					i = drag(input, &r);
4777dd7cddfSDavid du Colombier 				sweeping = 0;
4787dd7cddfSDavid du Colombier 				if(i != nil){
4797dd7cddfSDavid du Colombier 					if(input == oin){
4807dd7cddfSDavid du Colombier 						if(band)
4817dd7cddfSDavid du Colombier 							wsendctlmesg(input, Reshaped, i->r, i);
4827dd7cddfSDavid du Colombier 						else
4837dd7cddfSDavid du Colombier 							wsendctlmesg(input, Moved, r, i);
4847dd7cddfSDavid du Colombier 						cornercursor(input, mouse->xy, 1);
4857dd7cddfSDavid du Colombier 					}else
4867dd7cddfSDavid du Colombier 						freeimage(i);
4877dd7cddfSDavid du Colombier 				}
4887dd7cddfSDavid du Colombier 			}
4897dd7cddfSDavid du Colombier 			if(w != nil)
4907dd7cddfSDavid du Colombier 				cornercursor(w, mouse->xy, 0);
4917dd7cddfSDavid du Colombier 			/* we're not sending the event, but if button is down maybe we should */
4927dd7cddfSDavid du Colombier 			if(mouse->buttons){
4937dd7cddfSDavid du Colombier 				/* w->topped will be zero if window has been bottomed */
4947dd7cddfSDavid du Colombier 				if(w==nil || (w==input && w->topped>0)){
4957dd7cddfSDavid du Colombier 					if(mouse->buttons & 1)
4967dd7cddfSDavid du Colombier 						;
4977dd7cddfSDavid du Colombier 					else if(mouse->buttons & 2){
4987dd7cddfSDavid du Colombier 						if(input && !input->mouseopen)
4997dd7cddfSDavid du Colombier 							button2menu(input);
5007dd7cddfSDavid du Colombier 					}else if(mouse->buttons & 4)
5017dd7cddfSDavid du Colombier 						button3menu();
5027dd7cddfSDavid du Colombier 				}else{
5037dd7cddfSDavid du Colombier 					/* if button 1 event in the window, top the window and wait for button up. */
5047dd7cddfSDavid du Colombier 					/* otherwise, top the window and pass the event on */
5057dd7cddfSDavid du Colombier 					if(wtop(mouse->xy) && (mouse->buttons!=1 || winborder(w, mouse->xy)))
5067dd7cddfSDavid du Colombier 						goto Again;
5077dd7cddfSDavid du Colombier 					goto Drain;
5087dd7cddfSDavid du Colombier 				}
5097dd7cddfSDavid du Colombier 			}
5107dd7cddfSDavid du Colombier 			moving = FALSE;
5117dd7cddfSDavid du Colombier 			break;
5127dd7cddfSDavid du Colombier 
5137dd7cddfSDavid du Colombier 		Drain:
5147dd7cddfSDavid du Colombier 			do
5157dd7cddfSDavid du Colombier 				readmouse(mousectl);
5167dd7cddfSDavid du Colombier 			while(mousectl->buttons);
5177dd7cddfSDavid du Colombier 			moving = FALSE;
5187dd7cddfSDavid du Colombier 			goto Again;	/* recalculate mouse position, cursor */
5197dd7cddfSDavid du Colombier 		}
5207dd7cddfSDavid du Colombier }
5217dd7cddfSDavid du Colombier 
5227dd7cddfSDavid du Colombier void
5237dd7cddfSDavid du Colombier resized(void)
5247dd7cddfSDavid du Colombier {
5257dd7cddfSDavid du Colombier 	Image *im;
5267dd7cddfSDavid du Colombier 	int i, j, ishidden;
5277dd7cddfSDavid du Colombier 	Rectangle r;
5287dd7cddfSDavid du Colombier 	Point o, n;
5297dd7cddfSDavid du Colombier 	Window *w;
5307dd7cddfSDavid du Colombier 
5317dd7cddfSDavid du Colombier 	if(getwindow(display, Refnone) < 0)
5327dd7cddfSDavid du Colombier 		error("failed to re-attach window");
5337dd7cddfSDavid du Colombier 	view = screen;
5347dd7cddfSDavid du Colombier 	freescreen(wscreen);
5357dd7cddfSDavid du Colombier 	wscreen = allocscreen(screen, background, 0);
5367dd7cddfSDavid du Colombier 	if(wscreen == nil)
5377dd7cddfSDavid du Colombier 		error("can't re-allocate screen");
5387dd7cddfSDavid du Colombier 	draw(view, view->r, background, nil, ZP);
5397dd7cddfSDavid du Colombier 	o = subpt(viewr.max, viewr.min);
5407dd7cddfSDavid du Colombier 	n = subpt(view->clipr.max, view->clipr.min);
5417dd7cddfSDavid du Colombier 	for(i=0; i<nwindow; i++){
5427dd7cddfSDavid du Colombier 		w = window[i];
5437dd7cddfSDavid du Colombier 		if(w->deleted)
5447dd7cddfSDavid du Colombier 			continue;
5457dd7cddfSDavid du Colombier 		r = rectsubpt(w->i->r, viewr.min);
5467dd7cddfSDavid du Colombier 		r.min.x = (r.min.x*n.x)/o.x;
5477dd7cddfSDavid du Colombier 		r.min.y = (r.min.y*n.y)/o.y;
5487dd7cddfSDavid du Colombier 		r.max.x = (r.max.x*n.x)/o.x;
5497dd7cddfSDavid du Colombier 		r.max.y = (r.max.y*n.y)/o.y;
5507dd7cddfSDavid du Colombier 		r = rectaddpt(r, screen->clipr.min);
5517dd7cddfSDavid du Colombier 		ishidden = 0;
5527dd7cddfSDavid du Colombier 		for(j=0; j<nhidden; j++)
5537dd7cddfSDavid du Colombier 			if(w == hidden[j]){
5547dd7cddfSDavid du Colombier 				ishidden = 1;
5557dd7cddfSDavid du Colombier 				break;
5567dd7cddfSDavid du Colombier 			}
5577dd7cddfSDavid du Colombier 		if(ishidden)
5587dd7cddfSDavid du Colombier 			im = allocimage(display, r, display->chan, 0, DWhite);
5597dd7cddfSDavid du Colombier 		else
5607dd7cddfSDavid du Colombier 			im = allocwindow(wscreen, r, Refbackup, DWhite);
5617dd7cddfSDavid du Colombier 		if(im)
5627dd7cddfSDavid du Colombier 			wsendctlmesg(w, Reshaped, r, im);
5637dd7cddfSDavid du Colombier 	}
5647dd7cddfSDavid du Colombier 	viewr = screen->r;
5657dd7cddfSDavid du Colombier 	flushimage(display, 1);}
5667dd7cddfSDavid du Colombier 
5677dd7cddfSDavid du Colombier void
5687dd7cddfSDavid du Colombier button3menu(void)
5697dd7cddfSDavid du Colombier {
5707dd7cddfSDavid du Colombier 	int i;
5717dd7cddfSDavid du Colombier 
5727dd7cddfSDavid du Colombier 	for(i=0; i<nhidden; i++)
5737dd7cddfSDavid du Colombier 		menu3str[i+Hidden] = hidden[i]->label;
5747dd7cddfSDavid du Colombier 	menu3str[i+Hidden] = nil;
5757dd7cddfSDavid du Colombier 
5767dd7cddfSDavid du Colombier 	sweeping = 1;
5777dd7cddfSDavid du Colombier 	/*BUG: MENUHIT SHOULD TAKE FONT, COLOR, ETC. */
5787dd7cddfSDavid du Colombier 	switch(i = menuhit(3, mousectl, &menu3, wscreen)){
5797dd7cddfSDavid du Colombier 	case -1:
5807dd7cddfSDavid du Colombier 		break;
5817dd7cddfSDavid du Colombier 	case New:
5827dd7cddfSDavid du Colombier 		new(sweep(), 0, nil, "/bin/rc", nil);
5837dd7cddfSDavid du Colombier 		break;
5847dd7cddfSDavid du Colombier 	case Reshape:
5857dd7cddfSDavid du Colombier 		resize();
5867dd7cddfSDavid du Colombier 		break;
5877dd7cddfSDavid du Colombier 	case Move:
5887dd7cddfSDavid du Colombier 		move();
5897dd7cddfSDavid du Colombier 		break;
5907dd7cddfSDavid du Colombier 	case Delete:
5917dd7cddfSDavid du Colombier 		delete();
5927dd7cddfSDavid du Colombier 		break;
5937dd7cddfSDavid du Colombier 	case Hide:
5947dd7cddfSDavid du Colombier 		hide();
5957dd7cddfSDavid du Colombier 		break;
5967dd7cddfSDavid du Colombier 	case Exit:
5977dd7cddfSDavid du Colombier 		if(Hidden > Exit){
5987dd7cddfSDavid du Colombier 			send(exitchan, nil);
5997dd7cddfSDavid du Colombier 			break;
6007dd7cddfSDavid du Colombier 		}
6017dd7cddfSDavid du Colombier 		/* else fall through */
6027dd7cddfSDavid du Colombier 	default:
6037dd7cddfSDavid du Colombier 		unhide(i);
6047dd7cddfSDavid du Colombier 		break;
6057dd7cddfSDavid du Colombier 	}
6067dd7cddfSDavid du Colombier 	sweeping = 0;
6077dd7cddfSDavid du Colombier }
6087dd7cddfSDavid du Colombier 
6097dd7cddfSDavid du Colombier void
6107dd7cddfSDavid du Colombier button2menu(Window *w)
6117dd7cddfSDavid du Colombier {
6127dd7cddfSDavid du Colombier 	if(w->deleted)
6137dd7cddfSDavid du Colombier 		return;
6147dd7cddfSDavid du Colombier 	incref(w);
6157dd7cddfSDavid du Colombier 	if(w->scrolling)
6167dd7cddfSDavid du Colombier 		menu2str[Scroll] = "noscroll";
6177dd7cddfSDavid du Colombier 	else
6187dd7cddfSDavid du Colombier 		menu2str[Scroll] = "scroll";
6197dd7cddfSDavid du Colombier 	switch(menuhit(2, mousectl, &menu2, wscreen)){
6207dd7cddfSDavid du Colombier 	case Cut:
6217dd7cddfSDavid du Colombier 		wsnarf(w);
6227dd7cddfSDavid du Colombier 		wcut(w);
6237dd7cddfSDavid du Colombier 		wscrdraw(w);
6247dd7cddfSDavid du Colombier 		break;
6257dd7cddfSDavid du Colombier 
6267dd7cddfSDavid du Colombier 	case Snarf:
6277dd7cddfSDavid du Colombier 		wsnarf(w);
6287dd7cddfSDavid du Colombier 		break;
6297dd7cddfSDavid du Colombier 
6307dd7cddfSDavid du Colombier 	case Paste:
6317dd7cddfSDavid du Colombier 		getsnarf();
6327dd7cddfSDavid du Colombier 		wpaste(w);
6337dd7cddfSDavid du Colombier 		wscrdraw(w);
6347dd7cddfSDavid du Colombier 		break;
6357dd7cddfSDavid du Colombier 
6367dd7cddfSDavid du Colombier 	case Plumb:
6377dd7cddfSDavid du Colombier 		wplumb(w);
6387dd7cddfSDavid du Colombier 		break;
6397dd7cddfSDavid du Colombier 
6407dd7cddfSDavid du Colombier 	case Send:
6417dd7cddfSDavid du Colombier 		getsnarf();
6427dd7cddfSDavid du Colombier 		wsnarf(w);
6437dd7cddfSDavid du Colombier 		if(nsnarf == 0)
6447dd7cddfSDavid du Colombier 			break;
6457dd7cddfSDavid du Colombier 		if(w->rawing){
6467dd7cddfSDavid du Colombier 			waddraw(w, snarf, nsnarf);
6477dd7cddfSDavid du Colombier 			if(snarf[nsnarf-1] != '\n')
6487dd7cddfSDavid du Colombier 				waddraw(w, L"\n", 1);
6497dd7cddfSDavid du Colombier 		}else{
6507dd7cddfSDavid du Colombier 			winsert(w, snarf, nsnarf, w->nr);
6517dd7cddfSDavid du Colombier 			if(snarf[nsnarf-1] != '\n')
6527dd7cddfSDavid du Colombier 				winsert(w, L"\n", 1, w->nr);
6537dd7cddfSDavid du Colombier 		}
6547dd7cddfSDavid du Colombier 		wsetselect(w, w->nr, w->nr);
6557dd7cddfSDavid du Colombier 		wshow(w, w->nr);
6567dd7cddfSDavid du Colombier 		break;
6577dd7cddfSDavid du Colombier 
6587dd7cddfSDavid du Colombier 	case Scroll:
6597dd7cddfSDavid du Colombier 		if(w->scrolling ^= 1)
6607dd7cddfSDavid du Colombier 			wshow(w, w->nr);
6617dd7cddfSDavid du Colombier 		break;
6627dd7cddfSDavid du Colombier 	}
6637dd7cddfSDavid du Colombier 	wclose(w);
6647dd7cddfSDavid du Colombier 	wsendctlmesg(w, Wakeup, ZR, nil);
6657dd7cddfSDavid du Colombier 	flushimage(display, 1);
6667dd7cddfSDavid du Colombier }
6677dd7cddfSDavid du Colombier 
6687dd7cddfSDavid du Colombier Point
6697dd7cddfSDavid du Colombier onscreen(Point p)
6707dd7cddfSDavid du Colombier {
6717dd7cddfSDavid du Colombier 	p.x = max(screen->clipr.min.x, p.x);
6727dd7cddfSDavid du Colombier 	p.x = min(screen->clipr.max.x, p.x);
6737dd7cddfSDavid du Colombier 	p.y = max(screen->clipr.min.y, p.y);
6747dd7cddfSDavid du Colombier 	p.y = min(screen->clipr.max.y, p.y);
6757dd7cddfSDavid du Colombier 	return p;
6767dd7cddfSDavid du Colombier }
6777dd7cddfSDavid du Colombier 
6787dd7cddfSDavid du Colombier Image*
6797dd7cddfSDavid du Colombier sweep(void)
6807dd7cddfSDavid du Colombier {
6817dd7cddfSDavid du Colombier 	Image *i, *oi;
6827dd7cddfSDavid du Colombier 	Rectangle r;
6837dd7cddfSDavid du Colombier 	Point p0, p;
6847dd7cddfSDavid du Colombier 
6857dd7cddfSDavid du Colombier 	i = nil;
6867dd7cddfSDavid du Colombier 	riosetcursor(&crosscursor, 1);
6877dd7cddfSDavid du Colombier 	while(mouse->buttons == 0)
6887dd7cddfSDavid du Colombier 		readmouse(mousectl);
6897dd7cddfSDavid du Colombier 	p0 = onscreen(mouse->xy);
6907dd7cddfSDavid du Colombier 	p = p0;
6917dd7cddfSDavid du Colombier 	r.min = p;
6927dd7cddfSDavid du Colombier 	r.max = p;
6937dd7cddfSDavid du Colombier 	oi = nil;
6947dd7cddfSDavid du Colombier 	while(mouse->buttons == 4){
6957dd7cddfSDavid du Colombier 		readmouse(mousectl);
6967dd7cddfSDavid du Colombier 		if(mouse->buttons != 4 && mouse->buttons != 0)
6977dd7cddfSDavid du Colombier 			break;
6987dd7cddfSDavid du Colombier 		if(!eqpt(mouse->xy, p)){
6997dd7cddfSDavid du Colombier 			p = onscreen(mouse->xy);
7007dd7cddfSDavid du Colombier 			r = canonrect(Rpt(p0, p));
7017dd7cddfSDavid du Colombier 			if(Dx(r)>5 && Dy(r)>5){
7027dd7cddfSDavid du Colombier 				i = allocwindow(wscreen, r, Refnone, 0xEEEEEEFF); /* grey */
7037dd7cddfSDavid du Colombier 				freeimage(oi);
7047dd7cddfSDavid du Colombier 				if(i == nil)
7057dd7cddfSDavid du Colombier 					goto Rescue;
7067dd7cddfSDavid du Colombier 				oi = i;
7077dd7cddfSDavid du Colombier 				border(i, r, Selborder, red, ZP);
7087dd7cddfSDavid du Colombier 				flushimage(display, 1);
7097dd7cddfSDavid du Colombier 			}
7107dd7cddfSDavid du Colombier 		}
7117dd7cddfSDavid du Colombier 	}
7127dd7cddfSDavid du Colombier 	if(mouse->buttons != 0)
7137dd7cddfSDavid du Colombier 		goto Rescue;
7147dd7cddfSDavid du Colombier 	if(i==nil || Dx(i->r)<100 || Dy(i->r)<3*font->height)
7157dd7cddfSDavid du Colombier 		goto Rescue;
7167dd7cddfSDavid du Colombier 	oi = i;
7177dd7cddfSDavid du Colombier 	i = allocwindow(wscreen, oi->r, Refbackup, DWhite);
7187dd7cddfSDavid du Colombier 	freeimage(oi);
7197dd7cddfSDavid du Colombier 	if(i == nil)
7207dd7cddfSDavid du Colombier 		goto Rescue;
7217dd7cddfSDavid du Colombier 	border(i, r, Selborder, red, ZP);
7227dd7cddfSDavid du Colombier 	cornercursor(input, mouse->xy, 1);
7237dd7cddfSDavid du Colombier 	return i;
7247dd7cddfSDavid du Colombier 
7257dd7cddfSDavid du Colombier  Rescue:
7267dd7cddfSDavid du Colombier 	freeimage(i);
7277dd7cddfSDavid du Colombier 	cornercursor(input, mouse->xy, 1);
7287dd7cddfSDavid du Colombier 	while(mouse->buttons)
7297dd7cddfSDavid du Colombier 		readmouse(mousectl);
7307dd7cddfSDavid du Colombier 	return nil;
7317dd7cddfSDavid du Colombier }
7327dd7cddfSDavid du Colombier 
7337dd7cddfSDavid du Colombier /*
7347dd7cddfSDavid du Colombier  * BUG: should interlock so applications don't change screen
7357dd7cddfSDavid du Colombier  * while tmp[] holds backing store
7367dd7cddfSDavid du Colombier  */
7377dd7cddfSDavid du Colombier Image*
7387dd7cddfSDavid du Colombier drag(Window *w, Rectangle *rp)
7397dd7cddfSDavid du Colombier {
7407dd7cddfSDavid du Colombier 	Image *i, *ni;
7417dd7cddfSDavid du Colombier 	Point p, op, d, dm, om;
7427dd7cddfSDavid du Colombier 	Rectangle r;
7437dd7cddfSDavid du Colombier 
7447dd7cddfSDavid du Colombier 	i = w->i;
7457dd7cddfSDavid du Colombier 	om = mouse->xy;
7467dd7cddfSDavid du Colombier 	riosetcursor(&boxcursor, 1);
7477dd7cddfSDavid du Colombier 	dm = subpt(mouse->xy, w->screenr.min);
7487dd7cddfSDavid du Colombier 	d = subpt(i->r.max, i->r.min);
7497dd7cddfSDavid du Colombier 	op = subpt(mouse->xy, dm);
7507dd7cddfSDavid du Colombier 	drawgetrect(Rect(op.x, op.y, op.x+d.x, op.y+d.y), 1);
7517dd7cddfSDavid du Colombier 	flushimage(display, 1);
7527dd7cddfSDavid du Colombier 	while(mouse->buttons == 4){
7537dd7cddfSDavid du Colombier 		p = subpt(mouse->xy, dm);
7547dd7cddfSDavid du Colombier 		if(!eqpt(p, op)){
7557dd7cddfSDavid du Colombier 			drawgetrect(Rect(op.x, op.y, op.x+d.x, op.y+d.y), 0);
7567dd7cddfSDavid du Colombier 			drawgetrect(Rect(p.x, p.y, p.x+d.x, p.y+d.y), 1);
7577dd7cddfSDavid du Colombier 			flushimage(display, 1);
7587dd7cddfSDavid du Colombier 			op = p;
7597dd7cddfSDavid du Colombier 		}
7607dd7cddfSDavid du Colombier 		readmouse(mousectl);
7617dd7cddfSDavid du Colombier 	}
7627dd7cddfSDavid du Colombier 	r = Rect(op.x, op.y, op.x+d.x, op.y+d.y);
7637dd7cddfSDavid du Colombier 	drawgetrect(r, 0);
7647dd7cddfSDavid du Colombier 	cornercursor(input, mouse->xy, 1);
7657dd7cddfSDavid du Colombier 	flushimage(display, 1);
7667dd7cddfSDavid du Colombier 	if(mouse->buttons!=0 || (ni=allocwindow(wscreen, r, Refbackup, DWhite))==nil){
7677dd7cddfSDavid du Colombier 		moveto(mousectl, om);
7687dd7cddfSDavid du Colombier 		while(mouse->buttons)
7697dd7cddfSDavid du Colombier 			readmouse(mousectl);
7707dd7cddfSDavid du Colombier 		*rp = Rect(0, 0, 0, 0);
7717dd7cddfSDavid du Colombier 		return nil;
7727dd7cddfSDavid du Colombier 	}
7737dd7cddfSDavid du Colombier 	draw(ni, ni->r, i, nil, i->r.min);
7747dd7cddfSDavid du Colombier 	*rp = r;
7757dd7cddfSDavid du Colombier 	return ni;
7767dd7cddfSDavid du Colombier }
7777dd7cddfSDavid du Colombier 
7787dd7cddfSDavid du Colombier Rectangle
7797dd7cddfSDavid du Colombier whichrect(Rectangle r, Point p, int which)
7807dd7cddfSDavid du Colombier {
7817dd7cddfSDavid du Colombier 	switch(which){
7827dd7cddfSDavid du Colombier 	case 0:	/* top left */
7837dd7cddfSDavid du Colombier 		r = Rect(p.x, p.y, r.max.x, r.max.y);
7847dd7cddfSDavid du Colombier 		break;
7857dd7cddfSDavid du Colombier 	case 2:	/* top right */
7867dd7cddfSDavid du Colombier 		r = Rect(r.min.x, p.y, p.x, r.max.y);
7877dd7cddfSDavid du Colombier 		break;
7887dd7cddfSDavid du Colombier 	case 6:	/* bottom left */
7897dd7cddfSDavid du Colombier 		r = Rect(p.x, r.min.y, r.max.x, p.y);
7907dd7cddfSDavid du Colombier 		break;
7917dd7cddfSDavid du Colombier 	case 8:	/* bottom right */
7927dd7cddfSDavid du Colombier 		r = Rect(r.min.x, r.min.y, p.x, p.y);
7937dd7cddfSDavid du Colombier 		break;
7947dd7cddfSDavid du Colombier 	case 1:	/* top edge */
7957dd7cddfSDavid du Colombier 		r = Rect(r.min.x, p.y, r.max.x, r.max.y);
7967dd7cddfSDavid du Colombier 		break;
7977dd7cddfSDavid du Colombier 	case 5:	/* right edge */
7987dd7cddfSDavid du Colombier 		r = Rect(r.min.x, r.min.y, p.x, r.max.y);
7997dd7cddfSDavid du Colombier 		break;
8007dd7cddfSDavid du Colombier 	case 7:	/* bottom edge */
8017dd7cddfSDavid du Colombier 		r = Rect(r.min.x, r.min.y, r.max.x, p.y);
8027dd7cddfSDavid du Colombier 		break;
8037dd7cddfSDavid du Colombier 	case 3:		/* left edge */
8047dd7cddfSDavid du Colombier 		r = Rect(p.x, r.min.y, r.max.x, r.max.y);
8057dd7cddfSDavid du Colombier 		break;
8067dd7cddfSDavid du Colombier 	}
8077dd7cddfSDavid du Colombier 	return canonrect(r);
8087dd7cddfSDavid du Colombier }
8097dd7cddfSDavid du Colombier 
8107dd7cddfSDavid du Colombier Image*
8117dd7cddfSDavid du Colombier bandsize(Window *w)
8127dd7cddfSDavid du Colombier {
8137dd7cddfSDavid du Colombier 	Image *i;
8147dd7cddfSDavid du Colombier 	Rectangle r, or;
8157dd7cddfSDavid du Colombier 	Point p, startp;
8167dd7cddfSDavid du Colombier 	int which, but;
8177dd7cddfSDavid du Colombier 
8187dd7cddfSDavid du Colombier 	p = mouse->xy;
8197dd7cddfSDavid du Colombier 	startp = p;
8207dd7cddfSDavid du Colombier 	which = whichcorner(w, p);
8217dd7cddfSDavid du Colombier 	r = whichrect(w->screenr, p, which);
8227dd7cddfSDavid du Colombier 	drawgetrect(r, 1);
8237dd7cddfSDavid du Colombier 	or = r;
8247dd7cddfSDavid du Colombier 	but = mouse->buttons;
8257dd7cddfSDavid du Colombier 	while(mouse->buttons == but){
8267dd7cddfSDavid du Colombier 		p = onscreen(mouse->xy);
8277dd7cddfSDavid du Colombier 		r = whichrect(w->screenr, p, which);
8287dd7cddfSDavid du Colombier 		if(!eqrect(r, or)){
8297dd7cddfSDavid du Colombier 			/* not too big, not too small, just right */
8307dd7cddfSDavid du Colombier 			if(Dx(r)<=Dx(viewr) && Dy(r)<=Dy(viewr)
8317dd7cddfSDavid du Colombier 			  && Dx(r)>=100 && Dy(r)>=3*font->height){
8327dd7cddfSDavid du Colombier 				drawgetrect(or, 0);
8337dd7cddfSDavid du Colombier 				drawgetrect(r, 1);
8347dd7cddfSDavid du Colombier 				flushimage(display, 1);
8357dd7cddfSDavid du Colombier 				or = r;
8367dd7cddfSDavid du Colombier 			}
8377dd7cddfSDavid du Colombier 		}
8387dd7cddfSDavid du Colombier 		readmouse(mousectl);
8397dd7cddfSDavid du Colombier 	}
8407dd7cddfSDavid du Colombier 	p = mouse->xy;
8417dd7cddfSDavid du Colombier 	drawgetrect(or, 0);
8427dd7cddfSDavid du Colombier 	flushimage(display, 1);
8437dd7cddfSDavid du Colombier 	wsetcursor(input, 1);
8447dd7cddfSDavid du Colombier 	if(mouse->buttons != 0 || Dx(or)<100 || Dy(or)<3*font->height){
8457dd7cddfSDavid du Colombier 		while(mouse->buttons)
8467dd7cddfSDavid du Colombier 			readmouse(mousectl);
8477dd7cddfSDavid du Colombier 		return nil;
8487dd7cddfSDavid du Colombier 	}
8497dd7cddfSDavid du Colombier 	if(abs(p.x-startp.x)+abs(p.y-startp.y) <= 1)
8507dd7cddfSDavid du Colombier 		return nil;
8517dd7cddfSDavid du Colombier 	i = allocwindow(wscreen, or, Refbackup, DWhite);
8527dd7cddfSDavid du Colombier 	if(i == nil)
8537dd7cddfSDavid du Colombier 		return nil;
8547dd7cddfSDavid du Colombier 	border(i, r, Selborder, red, ZP);
8557dd7cddfSDavid du Colombier 	return i;
8567dd7cddfSDavid du Colombier }
8577dd7cddfSDavid du Colombier 
8587dd7cddfSDavid du Colombier Window*
8597dd7cddfSDavid du Colombier pointto(int wait)
8607dd7cddfSDavid du Colombier {
8617dd7cddfSDavid du Colombier 	Window *w;
8627dd7cddfSDavid du Colombier 
8637dd7cddfSDavid du Colombier 	riosetcursor(&sightcursor, 1);
8647dd7cddfSDavid du Colombier 	while(mouse->buttons == 0)
8657dd7cddfSDavid du Colombier 		readmouse(mousectl);
8667dd7cddfSDavid du Colombier 	if(mouse->buttons == 4)
8677dd7cddfSDavid du Colombier 		w = wpointto(mouse->xy);
8687dd7cddfSDavid du Colombier 	else
8697dd7cddfSDavid du Colombier 		w = nil;
8707dd7cddfSDavid du Colombier 	if(wait)
871*14414594SDavid du Colombier 		while(mouse->buttons){
872*14414594SDavid du Colombier 			if(mouse->buttons!=4 && w !=nil){	/* cancel */
873*14414594SDavid du Colombier 				cornercursor(input, mouse->xy, 0);
874*14414594SDavid du Colombier 				w = nil;
875*14414594SDavid du Colombier 			}
8767dd7cddfSDavid du Colombier 			readmouse(mousectl);
877*14414594SDavid du Colombier 		}
8787dd7cddfSDavid du Colombier 	cornercursor(input, mouse->xy, 0);
8797dd7cddfSDavid du Colombier 	return w;
8807dd7cddfSDavid du Colombier }
8817dd7cddfSDavid du Colombier 
8827dd7cddfSDavid du Colombier void
8837dd7cddfSDavid du Colombier delete(void)
8847dd7cddfSDavid du Colombier {
8857dd7cddfSDavid du Colombier 	Window *w;
8867dd7cddfSDavid du Colombier 
8877dd7cddfSDavid du Colombier 	w = pointto(TRUE);
8887dd7cddfSDavid du Colombier 	if(w)
8897dd7cddfSDavid du Colombier 		wsendctlmesg(w, Deleted, ZR, nil);
8907dd7cddfSDavid du Colombier }
8917dd7cddfSDavid du Colombier 
8927dd7cddfSDavid du Colombier void
8937dd7cddfSDavid du Colombier resize(void)
8947dd7cddfSDavid du Colombier {
8957dd7cddfSDavid du Colombier 	Window *w;
8967dd7cddfSDavid du Colombier 	Image *i;
8977dd7cddfSDavid du Colombier 
8987dd7cddfSDavid du Colombier 	w = pointto(TRUE);
8997dd7cddfSDavid du Colombier 	if(w == nil)
9007dd7cddfSDavid du Colombier 		return;
9017dd7cddfSDavid du Colombier 	i = sweep();
9027dd7cddfSDavid du Colombier 	if(i)
9037dd7cddfSDavid du Colombier 		wsendctlmesg(w, Reshaped, i->r, i);
9047dd7cddfSDavid du Colombier }
9057dd7cddfSDavid du Colombier 
9067dd7cddfSDavid du Colombier void
9077dd7cddfSDavid du Colombier move(void)
9087dd7cddfSDavid du Colombier {
9097dd7cddfSDavid du Colombier 	Window *w;
9107dd7cddfSDavid du Colombier 	Image *i;
9117dd7cddfSDavid du Colombier 	Rectangle r;
9127dd7cddfSDavid du Colombier 
9137dd7cddfSDavid du Colombier 	w = pointto(FALSE);
9147dd7cddfSDavid du Colombier 	if(w == nil)
9157dd7cddfSDavid du Colombier 		return;
9167dd7cddfSDavid du Colombier 	i = drag(w, &r);
9177dd7cddfSDavid du Colombier 	if(i)
9187dd7cddfSDavid du Colombier 		wsendctlmesg(w, Moved, r, i);
9197dd7cddfSDavid du Colombier 	cornercursor(input, mouse->xy, 1);
9207dd7cddfSDavid du Colombier }
9217dd7cddfSDavid du Colombier 
9227dd7cddfSDavid du Colombier void
9237dd7cddfSDavid du Colombier hide(void)
9247dd7cddfSDavid du Colombier {
9257dd7cddfSDavid du Colombier 	Window *w;
9267dd7cddfSDavid du Colombier 	Image *i;
9277dd7cddfSDavid du Colombier 
9287dd7cddfSDavid du Colombier 	w = pointto(TRUE);
9297dd7cddfSDavid du Colombier 	if(w == nil)
9307dd7cddfSDavid du Colombier 		return;
9317dd7cddfSDavid du Colombier 	i = allocimage(display, w->screenr, w->i->chan, 0, DWhite);
9327dd7cddfSDavid du Colombier 	if(i){
9337dd7cddfSDavid du Colombier 		hidden[nhidden++] = w;
9347dd7cddfSDavid du Colombier 		wsendctlmesg(w, Reshaped, ZR, i);
9357dd7cddfSDavid du Colombier 	}
9367dd7cddfSDavid du Colombier }
9377dd7cddfSDavid du Colombier 
9387dd7cddfSDavid du Colombier void
9397dd7cddfSDavid du Colombier unhide(int h)
9407dd7cddfSDavid du Colombier {
9417dd7cddfSDavid du Colombier 	Window *w;
9427dd7cddfSDavid du Colombier 	Image *i;
9437dd7cddfSDavid du Colombier 
9447dd7cddfSDavid du Colombier 	h -= Hidden;
9457dd7cddfSDavid du Colombier 	w = hidden[h];
9467dd7cddfSDavid du Colombier 	if(w == nil)
9477dd7cddfSDavid du Colombier 		return;
9487dd7cddfSDavid du Colombier 	i = allocwindow(wscreen, w->i->r, Refbackup, DWhite);
9497dd7cddfSDavid du Colombier 	if(i == nil)
9507dd7cddfSDavid du Colombier 		return;
9517dd7cddfSDavid du Colombier 	if(i){
9527dd7cddfSDavid du Colombier 		--nhidden;
9537dd7cddfSDavid du Colombier 		memmove(hidden+h, hidden+h+1, (nhidden-h)*sizeof(Window*));
9547dd7cddfSDavid du Colombier 		wsendctlmesg(w, Reshaped, w->i->r, i);
9557dd7cddfSDavid du Colombier 	}
9567dd7cddfSDavid du Colombier }
9577dd7cddfSDavid du Colombier 
9587dd7cddfSDavid du Colombier Window*
9597dd7cddfSDavid du Colombier new(Image *i, int pid, char *dir, char *cmd, char **argv)
9607dd7cddfSDavid du Colombier {
9617dd7cddfSDavid du Colombier 	Window *w;
9627dd7cddfSDavid du Colombier 	Mousectl *mc;
9637dd7cddfSDavid du Colombier 	Channel *cm, *ck, *cctl, *cpid;
9647dd7cddfSDavid du Colombier 	void **arg;
9657dd7cddfSDavid du Colombier 
9667dd7cddfSDavid du Colombier 	if(i == nil)
9677dd7cddfSDavid du Colombier 		return nil;
9687dd7cddfSDavid du Colombier 	cm = chancreate(sizeof(Mouse), 0);
9697dd7cddfSDavid du Colombier 	ck = chancreate(sizeof(Rune*), 0);
9707dd7cddfSDavid du Colombier 	cctl = chancreate(sizeof(Wctlmesg), 4);
9717dd7cddfSDavid du Colombier 	cpid = chancreate(sizeof(int), 0);
9727dd7cddfSDavid du Colombier 	if(cm==nil || ck==nil || cctl==nil)
9737dd7cddfSDavid du Colombier 		error("new: channel alloc failed");
9747dd7cddfSDavid du Colombier 	mc = emalloc(sizeof(Mousectl));
9757dd7cddfSDavid du Colombier 	*mc = *mousectl;
9767dd7cddfSDavid du Colombier 	mc->image = i;
9777dd7cddfSDavid du Colombier 	mc->c = cm;
9787dd7cddfSDavid du Colombier 	w = wmk(i, mc, ck, cctl);
9797dd7cddfSDavid du Colombier 	window = erealloc(window, ++nwindow*sizeof(Window*));
9807dd7cddfSDavid du Colombier 	window[nwindow-1] = w;
9817dd7cddfSDavid du Colombier 	threadcreate(winctl, w, 8192);
9827dd7cddfSDavid du Colombier 	wcurrent(w);
9837dd7cddfSDavid du Colombier 	flushimage(display, 1);
9847dd7cddfSDavid du Colombier 	if(pid == 0){
9857dd7cddfSDavid du Colombier 		arg = emalloc(5*sizeof(void*));
9867dd7cddfSDavid du Colombier 		arg[0] = w;
9877dd7cddfSDavid du Colombier 		arg[1] = cpid;
9887dd7cddfSDavid du Colombier 		arg[2] = cmd;
9897dd7cddfSDavid du Colombier 		if(argv == nil)
9907dd7cddfSDavid du Colombier 			arg[3] = rcargv;
9917dd7cddfSDavid du Colombier 		else
9927dd7cddfSDavid du Colombier 			arg[3] = argv;
9937dd7cddfSDavid du Colombier 		arg[4] = dir;
9947dd7cddfSDavid du Colombier 		proccreate(winshell, arg, 8192);
9957dd7cddfSDavid du Colombier 		pid = recvul(cpid);
9967dd7cddfSDavid du Colombier 		free(arg);
9977dd7cddfSDavid du Colombier 	}
9987dd7cddfSDavid du Colombier 	wsetpid(w, pid);
9997dd7cddfSDavid du Colombier 	wsetname(w);
10007dd7cddfSDavid du Colombier 	free(cpid);
10017dd7cddfSDavid du Colombier 	return w;
10027dd7cddfSDavid du Colombier }
1003