xref: /plan9-contrib/sys/src/libdraw/mouse.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
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 
8 void
9 moveto(Mousectl *m, Point pt)
10 {
11 	fprint(m->mfd, "m%d %d", pt.x, pt.y);
12 	m->xy = pt;
13 }
14 
15 void
16 closemouse(Mousectl *mc)
17 {
18 	if(mc == nil)
19 		return;
20 
21 	postnote(PNPROC, mc->pid, "kill");
22 
23 	do; while(nbrecv(mc->c, &mc->Mouse) > 0);
24 
25 	close(mc->mfd);
26 	close(mc->cfd);
27 	free(mc->file);
28 	free(mc->c);
29 	free(mc->resizec);
30 	free(mc);
31 }
32 
33 int
34 readmouse(Mousectl *mc)
35 {
36 	if(mc->image)
37 		flushimage(mc->image->display, 1);
38 	if(recv(mc->c, &mc->Mouse) < 0){
39 		fprint(2, "readmouse: %r\n");
40 		return -1;
41 	}
42 	return 0;
43 }
44 
45 static
46 void
47 _ioproc(void *arg)
48 {
49 	int n, nerr, one;
50 	char buf[1+5*12];
51 	Mouse m;
52 	Mousectl *mc;
53 
54 	mc = arg;
55 	threadsetname("mouseproc");
56 	one = 1;
57 	memset(&m, 0, sizeof m);
58 	mc->pid = getpid();
59 	nerr = 0;
60 	for(;;){
61 		n = read(mc->mfd, buf, sizeof buf);
62 		if(n != 1+4*12){
63 			yield();	/* if error is due to exiting, we'll exit here */
64 			fprint(2, "mouse: bad count %d not 49: %r\n", n);
65 			if(n<0 || ++nerr>10)
66 				threadexits("read error");
67 			continue;
68 		}
69 		nerr = 0;
70 		switch(buf[0]){
71 		case 'r':
72 			send(mc->resizec, &one);
73 			/* fall through */
74 		case 'm':
75 			m.xy.x = atoi(buf+1+0*12);
76 			m.xy.y = atoi(buf+1+1*12);
77 			m.buttons = atoi(buf+1+2*12);
78 			m.msec = atoi(buf+1+3*12);
79 			send(mc->c, &m);
80 			/*
81 			 * mc->Mouse is updated after send so it doesn't have wrong value if we block during send.
82 			 * This means that programs should receive into mc->Mouse (see readmouse() above) if
83 			 * they want full synchrony.
84 			 */
85 			mc->Mouse = m;
86 			break;
87 		}
88 	}
89 }
90 
91 Mousectl*
92 initmouse(char *file, Image *i)
93 {
94 	Mousectl *mc;
95 	char *t, *sl;
96 
97 	mc = mallocz(sizeof(Mousectl), 1);
98 	if(file == nil)
99 		file = "/dev/mouse";
100 	mc->file = strdup(file);
101 	mc->mfd = open(file, ORDWR|OCEXEC);
102 	if(mc->mfd<0 && strcmp(file, "/dev/mouse")==0){
103 		bind("#m", "/dev", MAFTER);
104 		mc->mfd = open(file, ORDWR|OCEXEC);
105 	}
106 	if(mc->mfd < 0){
107 		free(mc);
108 		return nil;
109 	}
110 	t = malloc(strlen(file)+16);
111 	strcpy(t, file);
112 	sl = utfrrune(t, '/');
113 	if(sl)
114 		strcpy(sl, "/cursor");
115 	else
116 		strcpy(t, "/dev/cursor");
117 	mc->cfd = open(t, ORDWR|OCEXEC);
118 	free(t);
119 	mc->image = i;
120 	mc->c = chancreate(sizeof(Mouse), 0);
121 	mc->resizec = chancreate(sizeof(int), 2);
122 	proccreate(_ioproc, mc, 4096);
123 	return mc;
124 }
125 
126 void
127 setcursor(Mousectl *mc, Cursor *c)
128 {
129 	char curs[2*4+2*2*16];
130 
131 	if(c == nil)
132 		write(mc->cfd, curs, 0);
133 	else{
134 		BPLONG(curs+0*4, c->offset.x);
135 		BPLONG(curs+1*4, c->offset.y);
136 		memmove(curs+2*4, c->clr, 2*2*16);
137 		write(mc->cfd, curs, sizeof curs);
138 	}
139 }
140