xref: /plan9/sys/src/libdraw/mouse.c (revision 223a035810d484657ee1a815f68faa8211009d6d)
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
moveto(Mousectl * m,Point pt)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
closemouse(Mousectl * mc)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
readmouse(Mousectl * mc)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
_ioproc(void * arg)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*
initmouse(char * file,Image * i)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 	if (t == nil) {
112 		close(mc->mfd);
113 		free(mc);
114 		return nil;
115 	}
116 	strcpy(t, file);
117 	sl = utfrrune(t, '/');
118 	if(sl)
119 		strcpy(sl, "/cursor");
120 	else
121 		strcpy(t, "/dev/cursor");
122 	mc->cfd = open(t, ORDWR|OCEXEC);
123 	free(t);
124 	mc->image = i;
125 	mc->c = chancreate(sizeof(Mouse), 0);
126 	mc->resizec = chancreate(sizeof(int), 2);
127 	proccreate(_ioproc, mc, 4096);
128 	return mc;
129 }
130 
131 void
setcursor(Mousectl * mc,Cursor * c)132 setcursor(Mousectl *mc, Cursor *c)
133 {
134 	char curs[2*4+2*2*16];
135 
136 	if(c == nil)
137 		write(mc->cfd, curs, 0);
138 	else{
139 		BPLONG(curs+0*4, c->offset.x);
140 		BPLONG(curs+1*4, c->offset.y);
141 		memmove(curs+2*4, c->clr, 2*2*16);
142 		write(mc->cfd, curs, sizeof curs);
143 	}
144 }
145