Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <draw.h>
4
#include <cursor.h>
5
#include <event.h>
6
 
7
typedef struct	Slave Slave;
8
typedef struct	Ebuf Ebuf;
9
 
10
struct Slave
11
{
12
	int	pid;
13
	Ebuf	*head;		/* queue of messages for this descriptor */
14
	Ebuf	*tail;
15
	int	(*fn)(int, Event*, uchar*, int);
16
};
17
 
18
struct Ebuf
19
{
20
	Ebuf	*next;
21
	int	n;		/* number of bytes in buf */
22
	uchar	buf[EMAXMSG];
23
};
24
 
25
static	Slave	eslave[MAXSLAVE];
26
static	int	Skeyboard = -1;
27
static	int	Smouse = -1;
28
static	int	Stimer = -1;
29
static	int	logfid;
30
 
31
static	int	nslave;
32
static	int	parentpid;
33
static	int	epipe[2];
34
 
35
static	int	eforkslave(ulong);
36
static	void	extract(void);
37
static	void	ekill(void);
38
static	int	enote(void *, char *);
39
 
40
static	int	mousefd;
41
static	int	cursorfd;
42
 
43
static
44
Ebuf*
45
ebread(Slave *s)
46
{
47
	Ebuf *eb;
48
	Dir *d;
49
	ulong l;
50
 
51
	for(;;){
52
		d = dirfstat(epipe[0]);
53
		if(d == nil)
54
			drawerror(display, "events: eread stat error");
55
		l = d->length;
56
		free(d);
57
		if(s->head && l==0)
58
			break;
59
		extract();
60
	}
61
	eb = s->head;
62
	s->head = s->head->next;
63
	if(s->head == 0)
64
		s->tail = 0;
65
	return eb;
66
}
67
 
68
ulong
69
event(Event *e)
70
{
71
	return eread(~0UL, e);
72
}
73
 
74
ulong
75
eread(ulong keys, Event *e)
76
{
77
	Ebuf *eb;
78
	int i, id;
79
 
80
	if(keys == 0)
81
		return 0;
82
	for(;;){
83
		for(i=0; i<nslave; i++)
84
			if((keys & (1<<i)) && eslave[i].head){
85
				id = 1<<i;
86
				if(i == Smouse)
87
					e->mouse = emouse();
88
				else if(i == Skeyboard)
89
					e->kbdc = ekbd();
90
				else if(i == Stimer)
91
					eslave[i].head = 0;
92
				else{
93
					eb = ebread(&eslave[i]);
94
					e->n = eb->n;
95
					if(eslave[i].fn)
96
						id = (*eslave[i].fn)(id, e, eb->buf, eb->n);
97
					else
98
						memmove(e->data, eb->buf, eb->n);
99
					free(eb);
100
				}
101
				return id;
102
			}
103
		extract();
104
	}
105
}
106
 
107
int
108
ecanmouse(void)
109
{
110
	if(Smouse < 0)
111
		drawerror(display, "events: mouse not initialized");
112
	return ecanread(Emouse);
113
}
114
 
115
int
116
ecankbd(void)
117
{
118
	if(Skeyboard < 0)
119
		drawerror(display, "events: keyboard not initialzed");
120
	return ecanread(Ekeyboard);
121
}
122
 
123
int
124
ecanread(ulong keys)
125
{
126
	Dir *d;
127
	int i;
128
	ulong l;
129
 
130
	for(;;){
131
		for(i=0; i<nslave; i++)
132
			if((keys & (1<<i)) && eslave[i].head)
133
				return 1;
134
		d = dirfstat(epipe[0]);
135
		if(d == nil)
136
			drawerror(display, "events: ecanread stat error");
137
		l = d->length;
138
		free(d);
139
		if(l == 0)
140
			return 0;
141
		extract();
142
	}
143
}
144
 
145
ulong
146
estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int))
147
{
148
	char buf[EMAXMSG+1];
149
	int i, r;
150
 
151
	if(fd < 0)
152
		drawerror(display, "events: bad file descriptor");
153
	if(n <= 0 || n > EMAXMSG)
154
		n = EMAXMSG;
155
	i = eforkslave(key);
156
	if(i < MAXSLAVE){
157
		eslave[i].fn = fn;
158
		return 1<<i;
159
	}
160
	buf[0] = i - MAXSLAVE;
161
	while((r = read(fd, buf+1, n))>0)
162
		if(write(epipe[1], buf, r+1)!=r+1)
163
			break;
164
	buf[0] = MAXSLAVE;
165
	write(epipe[1], buf, 1);
166
	_exits(0);
167
	return 0;
168
}
169
 
170
ulong
171
estart(ulong key, int fd, int n)
172
{
173
	return estartfn(key, fd, n, nil);
174
}
175
 
176
ulong
177
etimer(ulong key, int n)
178
{
179
	char t[2];
180
 
181
	if(Stimer != -1)
182
		drawerror(display, "events: timer started twice");
183
	Stimer = eforkslave(key);
184
	if(Stimer < MAXSLAVE)
185
		return 1<<Stimer;
186
	if(n <= 0)
187
		n = 1000;
188
	t[0] = t[1] = Stimer - MAXSLAVE;
189
	do
190
		sleep(n);
191
	while(write(epipe[1], t, 2) == 2);
192
	t[0] = MAXSLAVE;
193
	write(epipe[1], t, 1);
194
	_exits(0);
195
	return 0;
196
}
197
 
198
static void
199
ekeyslave(int fd)
200
{
201
	Rune r;
202
	char t[3], k[10];
203
	int kr, kn, w;
204
 
205
	if(eforkslave(Ekeyboard) < MAXSLAVE)
206
		return;
207
	kn = 0;
208
	t[0] = Skeyboard;
209
	for(;;){
210
		while(!fullrune(k, kn)){
211
			kr = read(fd, k+kn, sizeof k - kn);
212
			if(kr <= 0)
213
				goto breakout;
214
			kn += kr;
215
		}
216
		w = chartorune(&r, k);
217
		kn -= w;
218
		memmove(k, &k[w], kn);
219
		t[1] = r;
220
		t[2] = r>>8;
221
		if(write(epipe[1], t, 3) != 3)
222
			break;
223
	}
224
breakout:;
225
	t[0] = MAXSLAVE;
226
	write(epipe[1], t, 1);
227
	_exits(0);
228
}
229
 
230
void
231
einit(ulong keys)
232
{
233
	int ctl, fd;
234
	char buf[256];
235
 
236
	parentpid = getpid();
237
	if(pipe(epipe) < 0)
238
		drawerror(display, "events: einit pipe");
239
	atexit(ekill);
240
	atnotify(enote, 1);
241
	snprint(buf, sizeof buf, "%s/mouse", display->devdir);
242
	mousefd = open(buf, ORDWR|OCEXEC);
243
	if(mousefd < 0)
244
		drawerror(display, "einit: can't open mouse\n");
245
	snprint(buf, sizeof buf, "%s/cursor", display->devdir);
246
	cursorfd = open(buf, ORDWR|OCEXEC);
247
	if(cursorfd < 0)
248
		drawerror(display, "einit: can't open cursor\n");
249
	if(keys&Ekeyboard){
250
		snprint(buf, sizeof buf, "%s/cons", display->devdir);
251
		fd = open(buf, OREAD);
252
		if(fd < 0)
253
			drawerror(display, "events: can't open console");
254
		snprint(buf, sizeof buf, "%s/consctl", display->devdir);
255
		ctl = open("/dev/consctl", OWRITE|OCEXEC);
256
		if(ctl < 0)
257
			drawerror(display, "events: can't open consctl");
258
		write(ctl, "rawon", 5);
259
		for(Skeyboard=0; Ekeyboard & ~(1<<Skeyboard); Skeyboard++)
260
			;
261
		ekeyslave(fd);
262
	}
263
	if(keys&Emouse){
264
		estart(Emouse, mousefd, 1+4*12);
265
		for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++)
266
			;
267
	}
268
}
269
 
270
static void
271
extract(void)
272
{
273
	Slave *s;
274
	Ebuf *eb;
275
	int i, n;
276
	uchar ebuf[EMAXMSG+1];
277
 
278
	/* avoid generating a message if there's nothing to show. */
279
	/* this test isn't perfect, though; could do flushimage(display, 0) then call extract */
280
	/* also: make sure we don't interfere if we're multiprocessing the display */
281
	if(display->locking){
282
		/* if locking is being done by program, this means it can't depend on automatic flush in emouse() etc. */
283
		if(canqlock(&display->qlock)){
284
			if(display->bufp > display->buf)
285
				flushimage(display, 1);
286
			unlockdisplay(display);
287
		}
288
	}else
289
		if(display->bufp > display->buf)
290
			flushimage(display, 1);
291
loop:
292
	if((n=read(epipe[0], ebuf, EMAXMSG+1)) < 0
293
	|| ebuf[0] >= MAXSLAVE)
294
		drawerror(display, "eof on event pipe");
295
	if(n == 0)
296
		goto loop;
297
	i = ebuf[0];
298
	if(i >= nslave || n <= 1)
299
		drawerror(display, "events: protocol error: short read");
300
	s = &eslave[i];
301
	if(i == Stimer){
302
		s->head = (Ebuf *)1;
303
		return;
304
	}
305
	if(i == Skeyboard && n != 3)
306
		drawerror(display, "events: protocol error: keyboard");
307
	if(i == Smouse){
308
		if(n < 1+1+2*12)
309
			drawerror(display, "events: protocol error: mouse");
310
		if(ebuf[1] == 'r')
311
			eresized(1);
312
		/* squash extraneous mouse events */
313
		if((eb=s->tail) && memcmp(eb->buf+1+2*12, ebuf+1+1+2*12, 12)==0){
314
			memmove(eb->buf, &ebuf[1], n - 1);
315
			return;
316
		}
317
	}
318
	/* try to save space by only allocating as much buffer as we need */
319
	eb = malloc(sizeof(*eb) - sizeof(eb->buf) + n - 1);
320
	if(eb == 0)
321
		drawerror(display, "events: protocol error 4");
322
	eb->n = n - 1;
323
	memmove(eb->buf, &ebuf[1], n - 1);
324
	eb->next = 0;
325
	if(s->head)
326
		s->tail = s->tail->next = eb;
327
	else
328
		s->head = s->tail = eb;
329
}
330
 
331
static int
332
eforkslave(ulong key)
333
{
334
	int i, pid;
335
 
336
	for(i=0; i<MAXSLAVE; i++)
337
		if((key & ~(1<<i)) == 0 && eslave[i].pid == 0){
338
			if(nslave <= i)
339
				nslave = i + 1;
340
			/*
341
			 * share the file descriptors so the last child
342
			 * out closes all connections to the window server.
343
			 */
344
			switch(pid = rfork(RFPROC)){
345
			case 0:
346
				return MAXSLAVE+i;
347
			case -1:
348
				fprint(2, "events: fork error\n");
349
				exits("fork");
350
			}
351
			eslave[i].pid = pid;
352
			eslave[i].head = eslave[i].tail = 0;
353
			return i;
354
		}
355
	drawerror(display, "events: bad slave assignment");
356
	return 0;
357
}
358
 
359
static int
360
enote(void *v, char *s)
361
{
362
	char t[1];
363
	int i, pid;
364
 
365
	USED(v, s);
366
	pid = getpid();
367
	if(pid != parentpid){
368
		for(i=0; i<nslave; i++){
369
			if(pid == eslave[i].pid){
370
				t[0] = MAXSLAVE;
371
				write(epipe[1], t, 1);
372
				break;
373
			}
374
		}
375
		return 0;
376
	}
377
	close(epipe[0]);
378
	epipe[0] = -1;
379
	close(epipe[1]);
380
	epipe[1] = -1;
381
	for(i=0; i<nslave; i++){
382
		if(pid == eslave[i].pid)
383
			continue;	/* don't kill myself */
384
		postnote(PNPROC, eslave[i].pid, "die");
385
	}
386
	return 0;
387
}
388
 
389
static void
390
ekill(void)
391
{
392
	enote(0, 0);
393
}
394
 
395
Mouse
396
emouse(void)
397
{
398
	Mouse m;
399
	Ebuf *eb;
400
	static but[2];
401
	int b;
402
 
403
	if(Smouse < 0)
404
		drawerror(display, "events: mouse not initialized");
405
	eb = ebread(&eslave[Smouse]);
406
	m.xy.x = atoi((char*)eb->buf+1+0*12);
407
	m.xy.y = atoi((char*)eb->buf+1+1*12);
408
	b = atoi((char*)eb->buf+1+2*12);
409
	m.buttons = b;
410
	m.msec = atoi((char*)eb->buf+1+3*12);
411
	if (logfid)
412
		fprint(logfid, "b: %d xy: %P\n", m.buttons, m.xy);
413
	free(eb);
414
	return m;
415
}
416
 
417
int
418
ekbd(void)
419
{
420
	Ebuf *eb;
421
	int c;
422
 
423
	if(Skeyboard < 0)
424
		drawerror(display, "events: keyboard not initialzed");
425
	eb = ebread(&eslave[Skeyboard]);
426
	c = eb->buf[0] + (eb->buf[1]<<8);
427
	free(eb);
428
	return c;
429
}
430
 
431
void
432
emoveto(Point pt)
433
{
434
	char buf[2*12+2];
435
	int n;
436
 
437
	n = sprint(buf, "m%d %d", pt.x, pt.y);
438
	write(mousefd, buf, n);
439
}
440
 
441
void
442
esetcursor(Cursor *c)
443
{
444
	uchar curs[2*4+2*2*16];
445
 
446
	if(c == 0)
447
		write(cursorfd, curs, 0);
448
	else{
449
		BPLONG(curs+0*4, c->offset.x);
450
		BPLONG(curs+1*4, c->offset.y);
451
		memmove(curs+2*4, c->clr, 2*2*16);
452
		write(cursorfd, curs, sizeof curs);
453
	}
454
}
455
 
456
int
457
ereadmouse(Mouse *m)
458
{
459
	int n;
460
	char buf[128];
461
 
462
	do{
463
		n = read(mousefd, buf, sizeof(buf));
464
		if(n < 0)	/* probably interrupted */
465
			return -1;
466
		n = eatomouse(m, buf, n);
467
	}while(n == 0);
468
	return n;
469
}
470
 
471
int
472
eatomouse(Mouse *m, char *buf, int n)
473
{
474
	if(n != 1+4*12){
475
		werrstr("atomouse: bad count");
476
		return -1;
477
	}
478
 
479
	if(buf[0] == 'r')
480
		eresized(1);
481
	m->xy.x = atoi(buf+1+0*12);
482
	m->xy.y = atoi(buf+1+1*12);
483
	m->buttons = atoi(buf+1+2*12);
484
	m->msec = atoi(buf+1+3*12);
485
	return n;
486
}