Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_fixcpp/sys/src/cmd/unix/drawterm/gui-x11/x11.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "lib.h"
3
#include "dat.h"
4
#include "fns.h"
5
#include "error.h"
6
 
7
#include <draw.h>
8
#include <memdraw.h>
9
#include <keyboard.h>
10
#include <cursor.h>
11
#include "screen.h"
12
 
13
#define argv0 "drawterm"
14
 
15
typedef struct Cursor Cursor;
16
 
17
#undef	long
18
#define	Font		XFont
19
#define	Screen	XScreen
20
#define	Display	XDisplay
21
#define	Cursor	XCursor
22
 
23
#include <X11/Xlib.h>
24
#include <X11/Xatom.h>
25
#include <X11/Xutil.h>
26
#include <X11/IntrinsicP.h>
27
#include <X11/StringDefs.h>
28
#include <X11/keysym.h>
29
#include "keysym2ucs.h"
30
 
31
#undef	Font
32
#undef	Screen
33
#undef	Display
34
#undef	Cursor
35
#define	long	int
36
 
37
/* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */
38
#define RGB2K(r,g,b)	((156763*(r)+307758*(g)+59769*(b))>>19)
39
 
40
enum
41
{
42
	PMundef	= ~0		/* undefined pixmap id */
43
};
44
 
45
/*
46
 * Structure pointed to by X field of Memimage
47
 */
48
typedef struct Xmem Xmem;
49
struct Xmem
50
{
51
	int	pmid;	/* pixmap id for screen ldepth instance */
52
	XImage *xi;	/* local image if we currenty have the data */
53
	int	dirty;
54
	Rectangle dirtyr;
55
	Rectangle r;
56
	uintptr pc;	/* who wrote into xi */
57
};
58
 
59
static int	xgcfillcolor;
60
static int	xgcfillcolor0;
61
static int	xgcsimplecolor0;
62
static int	xgcsimplepm0;
63
 
64
static	XDisplay*	xdisplay;	/* used holding draw lock */
65
static int				xtblbit;
66
static int 			plan9tox11[256]; /* Values for mapping between */
67
static int 			x11toplan9[256]; /* X11 and Plan 9 */
68
static	GC		xgcfill, xgccopy, xgcsimplesrc, xgczero, xgcreplsrc;
69
static	GC		xgcfill0, xgccopy0, xgcsimplesrc0, xgczero0, xgcreplsrc0;
70
static	ulong	xscreenchan;
71
static	Drawable	xscreenid;
72
static	Visual		*xvis;
73
 
74
static int xdraw(Memdrawparam*);
75
 
76
#define glenda_width 48
77
#define glenda_height 48
78
static unsigned short glenda_bits[] = {
79
   0xffff, 0xffff, 0xffff, 0xffff, 0xffe9, 0xffff, 0x7fff, 0xffae, 0xffff,
80
   0xffff, 0xffbe, 0xffff, 0x1fff, 0xff3f, 0xffff, 0xbfff, 0xfe6e, 0xffff,
81
   0xbbff, 0xfcce, 0xffff, 0xffff, 0xf98c, 0xffff, 0xe5ff, 0xf31b, 0xffff,
82
   0x87ff, 0xe617, 0xffff, 0x05ff, 0xdf37, 0xffff, 0x0fff, 0x7ffe, 0xffff,
83
   0x1bff, 0xfffc, 0xfffa, 0x37ff, 0xfffc, 0xfffb, 0xd7ff, 0xfffc, 0xfff7,
84
   0xcfff, 0xffff, 0xfff7, 0xcfff, 0xffff, 0xffef, 0xdfff, 0xffff, 0xffef,
85
   0xafff, 0xffff, 0xffdf, 0xefff, 0xffff, 0xfff3, 0xdfff, 0xefff, 0xffd3,
86
   0xdfff, 0xc7ff, 0xffdf, 0xefff, 0xefff, 0xffef, 0xcfff, 0xffff, 0xffcf,
87
   0xdfff, 0xffff, 0xffd9, 0x9fff, 0x7fff, 0xffd0, 0xbfff, 0xffff, 0xffd7,
88
   0x7fff, 0xbfff, 0xffd0, 0x3fff, 0x3fff, 0xffd9, 0x7fff, 0x3fff, 0xffcb,
89
   0x3fff, 0xffff, 0xffdc, 0x3fff, 0xffff, 0xffdf, 0x3fff, 0xffff, 0xff9f,
90
   0x3fff, 0xffff, 0xffdf, 0x8fff, 0xffff, 0xff9f, 0xa7ff, 0xffff, 0xffdf,
91
   0xe3ff, 0xffff, 0xffcf, 0xe9ff, 0xffff, 0xffcf, 0xf1ff, 0xffff, 0xffef,
92
   0xf3ff, 0xffff, 0xffe7, 0xf9ff, 0xffff, 0xffe7, 0x53ff, 0xffff, 0xffe1,
93
   0x07ff, 0x7ffc, 0xffc6, 0x17ff, 0xeff0, 0xffee, 0xffff, 0xc781, 0xffe5,
94
   0xffff, 0x8807, 0xffe0, 0xffff, 0x003f, 0xfff0, 0xffff, 0x1fff, 0xfffe
95
};
96
 
97
/*
98
 * Synchronize images between X bitmaps and in-memory bitmaps.
99
 */
100
static void
101
addrect(Rectangle *rp, Rectangle r)
102
{
103
	if(rp->min.x >= rp->max.x)
104
		*rp = r;
105
	else
106
		combinerect(rp, r);
107
}
108
 
109
static XImage*
110
getXdata(Memimage *m, Rectangle r)
111
{
112
	uchar *p;
113
	int x, y;
114
	Xmem *xm;
115
	Point xdelta, delta;
116
	Point tp;
117
 
118
 	xm = m->X;
119
 	if(xm == nil)
120
 		return nil;
121
 
122
	assert(xm != nil && xm->xi != nil);
123
 
124
 	if(xm->dirty == 0)
125
 		return xm->xi;
126
 
127
 	r = xm->dirtyr;
128
	if(Dx(r)==0 || Dy(r)==0)
129
		return xm->xi;
130
 
131
	delta = subpt(r.min, m->r.min);
132
	tp = xm->r.min;	/* avoid unaligned access on digital unix */
133
	xdelta = subpt(r.min, tp);
134
 
135
	XGetSubImage(xdisplay, xm->pmid, delta.x, delta.y, Dx(r), Dy(r),
136
		AllPlanes, ZPixmap, xm->xi, xdelta.x, xdelta.y);
137
 
138
	if(xtblbit && m->chan == CMAP8)
139
		for(y=r.min.y; y<r.max.y; y++)
140
			for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
141
				*p = x11toplan9[*p];
142
 
143
	xm->dirty = 0;
144
	xm->dirtyr = Rect(0,0,0,0);
145
	return xm->xi;
146
}
147
 
148
static void
149
putXdata(Memimage *m, Rectangle r)
150
{
151
	Xmem *xm;
152
	XImage *xi;
153
	GC g;
154
	Point xdelta, delta;
155
	Point tp;
156
	int x, y;
157
	uchar *p;
158
 
159
	xm = m->X;
160
	if(xm == nil)
161
		return;
162
 
163
	assert(xm != nil);
164
	assert(xm->xi != nil);
165
 
166
	xi = xm->xi;
167
 
168
	g = (m->chan == GREY1) ? xgccopy0 : xgccopy;
169
 
170
	delta = subpt(r.min, m->r.min);
171
	tp = xm->r.min;	/* avoid unaligned access on digital unix */
172
	xdelta = subpt(r.min, tp);
173
 
174
	if(xtblbit && m->chan == CMAP8)
175
		for(y=r.min.y; y<r.max.y; y++)
176
			for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
177
				*p = plan9tox11[*p];
178
 
179
	XPutImage(xdisplay, xm->pmid, g, xi, xdelta.x, xdelta.y, delta.x, delta.y, Dx(r), Dy(r));
180
 
181
	if(xtblbit && m->chan == CMAP8)
182
		for(y=r.min.y; y<r.max.y; y++)
183
			for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
184
				*p = x11toplan9[*p];
185
}
186
 
187
static void
188
dirtyXdata(Memimage *m, Rectangle r)
189
{
190
	Xmem *xm;
191
 
192
	if((xm = m->X) != nil){
193
		xm->dirty = 1;
194
		addrect(&xm->dirtyr, r);
195
	}
196
}
197
 
198
Memimage*
199
xallocmemimage(Rectangle r, ulong chan, int pmid)
200
{
201
	Memimage *m;
202
	Xmem *xm;
203
	XImage *xi;
204
	int offset;
205
	int d;
206
 
207
	m = _allocmemimage(r, chan);
208
	if(m == nil)
209
		return nil;
210
	if(chan != GREY1 && chan != xscreenchan)
211
		return m;
212
 
213
	d = m->depth;
214
	xm = mallocz(sizeof(Xmem), 1);
215
	if(pmid != PMundef)
216
		xm->pmid = pmid;
217
	else
218
		xm->pmid = XCreatePixmap(xdisplay, xscreenid, Dx(r), Dy(r), (d==32) ? 24 : d);
219
 
220
	if(m->depth == 24)
221
		offset = r.min.x&(4-1);
222
	else
223
		offset = r.min.x&(31/m->depth);
224
	r.min.x -= offset;
225
 
226
	assert(wordsperline(r, m->depth) <= m->width);
227
 
228
	xi = XCreateImage(xdisplay, xvis, m->depth==32?24:m->depth, ZPixmap, 0,
229
		(char*)m->data->bdata, Dx(r), Dy(r), 32, m->width*sizeof(ulong));
230
 
231
	if(xi == nil){
232
		_freememimage(m);
233
		return nil;
234
	}
235
 
236
	xm->xi = xi;
237
	xm->pc = getcallerpc(&r);
238
	xm->r = r;
239
 
240
	/*
241
	 * Set the parameters of the XImage so its memory looks exactly like a
242
	 * Memimage, so we can call _memimagedraw on the same data.  All frame
243
	 * buffers we've seen, and Plan 9's graphics code, require big-endian
244
	 * bits within bytes, but little endian byte order within pixels.
245
	 */
246
	xi->bitmap_unit = m->depth < 8 || m->depth == 24 ? 8 : m->depth;
247
	xi->byte_order = LSBFirst;
248
	xi->bitmap_bit_order = MSBFirst;
249
	xi->bitmap_pad = 32;
250
	xm->r = Rect(0,0,0,0);
251
	XInitImage(xi);
252
	XFlush(xdisplay);
253
 
254
	m->X = xm;
255
	return m;
256
}
257
 
258
void
259
xfillcolor(Memimage *m, Rectangle r, ulong v)
260
{
261
	GC gc;
262
	Xmem *dxm;
263
 
264
	dxm = m->X;
265
	assert(dxm != nil);
266
	r = rectsubpt(r, m->r.min);
267
 
268
	if(m->chan == GREY1){
269
		gc = xgcfill0;
270
		if(xgcfillcolor0 != v){
271
			XSetForeground(xdisplay, gc, v);
272
			xgcfillcolor0 = v;
273
		}
274
	}else{
275
		if(m->chan == CMAP8 && xtblbit)
276
			v = plan9tox11[v];
277
 
278
		gc = xgcfill;
279
		if(xgcfillcolor != v){
280
			XSetForeground(xdisplay, gc, v);
281
			xgcfillcolor = v;
282
		}
283
	}
284
	XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, Dx(r), Dy(r));
285
}
286
 
287
/*
288
 * Replacements for libmemdraw routines.
289
 * (They've been underscored.)
290
 */
291
Memimage*
292
allocmemimage(Rectangle r, ulong chan)
293
{
294
	return xallocmemimage(r, chan, PMundef);
295
}
296
 
297
void
298
freememimage(Memimage *m)
299
{
300
	Xmem *xm;
301
 
302
	if(m == nil)
303
		return;
304
 
305
	if(m->data->ref == 1){
306
		if((xm = m->X) != nil){
307
			if(xm->xi){
308
				xm->xi->data = nil;
309
				XFree(xm->xi);
310
			}
311
			XFreePixmap(xdisplay, xm->pmid);
312
			free(xm);
313
			m->X = nil;
314
		}
315
	}
316
	_freememimage(m);
317
}
318
 
319
void
320
memfillcolor(Memimage *m, ulong val)
321
{
322
	_memfillcolor(m, val);
323
	if(m->X){
324
		if((val & 0xFF) == 0xFF)
325
			xfillcolor(m, m->r, _rgbatoimg(m, val));
326
		else
327
			putXdata(m, m->r);
328
	}
329
}
330
 
331
int
332
loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
333
{
334
	int n;
335
 
336
	n = _loadmemimage(i, r, data, ndata);
337
	if(n > 0 && i->X)
338
		putXdata(i, r);
339
	return n;
340
}
341
 
342
int
343
cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
344
{
345
	int n;
346
 
347
	n = _cloadmemimage(i, r, data, ndata);
348
	if(n > 0 && i->X)
349
		putXdata(i, r);
350
	return n;
351
}
352
 
353
ulong
354
pixelbits(Memimage *m, Point p)
355
{
356
	if(m->X)
357
		getXdata(m, Rect(p.x, p.y, p.x+1, p.y+1));
358
	return _pixelbits(m, p);
359
}
360
 
361
void
362
memimageinit(void)
363
{
364
	static int didinit = 0;
365
 
366
	if(didinit)
367
		return;
368
 
369
	didinit = 1;
370
	_memimageinit();
371
 
372
	xfillcolor(memblack, memblack->r, 0);
373
	xfillcolor(memwhite, memwhite->r, 1);
374
}
375
 
376
void
377
memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op)
378
{
379
	Memdrawparam *par;
380
 
381
	if((par = _memimagedrawsetup(dst, r, src, sp, mask, mp, op)) == nil)
382
		return;
383
	_memimagedraw(par);
384
	if(!xdraw(par))
385
		putXdata(dst, par->r);
386
}
387
 
388
static int
389
xdraw(Memdrawparam *par)
390
{
391
	int dy, dx;
392
	unsigned m;
393
	Memimage *src, *dst, *mask;
394
	Xmem *dxm, *sxm, *mxm;
395
	GC gc;
396
	Rectangle r, sr, mr;
397
	ulong sdval;
398
 
399
	dx = Dx(par->r);
400
	dy = Dy(par->r);
401
	src = par->src;
402
	dst = par->dst;
403
	mask = par->mask;
404
	r = par->r;
405
	sr = par->sr;
406
	mr = par->mr;
407
	sdval = par->sdval;
408
 
409
	/*
410
	 * drawterm was distributed for years with
411
	 * "return 0;" right here.
412
	 * maybe we should give up on all this?
413
	 */
414
 
415
	if((dxm = dst->X) == nil)
416
		return 0;
417
 
418
	/*
419
	 * If we have an opaque mask and source is one opaque pixel we can convert to the
420
	 * destination format and just XFillRectangle.
421
	 */
422
	m = Simplesrc|Simplemask|Fullmask;
423
	if((par->state&m)==m){
424
		xfillcolor(dst, r, sdval);
425
		dirtyXdata(dst, par->r);
426
		return 1;
427
	}
428
 
429
	/*
430
	 * If no source alpha, an opaque mask, we can just copy the
431
	 * source onto the destination.  If the channels are the same and
432
	 * the source is not replicated, XCopyArea suffices.
433
	 */
434
	m = Simplemask|Fullmask;
435
	if((par->state&(m|Replsrc))==m && src->chan == dst->chan && src->X){
436
		sxm = src->X;
437
		r = rectsubpt(r, dst->r.min);		
438
		sr = rectsubpt(sr, src->r.min);
439
		if(dst->chan == GREY1)
440
			gc = xgccopy0;
441
		else
442
			gc = xgccopy;
443
		XCopyArea(xdisplay, sxm->pmid, dxm->pmid, gc, 
444
			sr.min.x, sr.min.y, dx, dy, r.min.x, r.min.y);
445
		dirtyXdata(dst, par->r);
446
		return 1;
447
	}
448
 
449
	/*
450
	 * If no source alpha, a 1-bit mask, and a simple source
451
	 * we can just copy through the mask onto the destination.
452
	 */
453
	if(dst->X && mask->X && !(mask->flags&Frepl)
454
	&& mask->chan == GREY1 && (par->state&Simplesrc)){
455
		Point p;
456
 
457
		mxm = mask->X;
458
		r = rectsubpt(r, dst->r.min);		
459
		mr = rectsubpt(mr, mask->r.min);
460
		p = subpt(r.min, mr.min);
461
		if(dst->chan == GREY1){
462
			gc = xgcsimplesrc0;
463
			if(xgcsimplecolor0 != sdval){
464
				XSetForeground(xdisplay, gc, sdval);
465
				xgcsimplecolor0 = sdval;
466
			}
467
			if(xgcsimplepm0 != mxm->pmid){
468
				XSetStipple(xdisplay, gc, mxm->pmid);
469
				xgcsimplepm0 = mxm->pmid;
470
			}
471
		}else{
472
		/* somehow this doesn't work on rob's mac 
473
			gc = xgcsimplesrc;
474
			if(dst->chan == CMAP8 && xtblbit)
475
				sdval = plan9tox11[sdval];
476
 
477
			if(xgcsimplecolor != sdval){
478
				XSetForeground(xdisplay, gc, sdval);
479
				xgcsimplecolor = sdval;
480
			}
481
			if(xgcsimplepm != mxm->pmid){
482
				XSetStipple(xdisplay, gc, mxm->pmid);
483
				xgcsimplepm = mxm->pmid;
484
			}
485
		*/
486
			return 0;
487
		}
488
		XSetTSOrigin(xdisplay, gc, p.x, p.y);
489
		XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, dx, dy);
490
		dirtyXdata(dst, par->r);
491
		return 1;
492
	}
493
	return 0;
494
}
495
 
496
/*
497
 * X11 window management and kernel hooks.
498
 * Oh, how I loathe this code!
499
 */
500
 
501
static XColor			map[256];	/* Plan 9 colormap array */
502
static XColor			map7[128];	/* Plan 9 colormap array */
503
static uchar			map7to8[128][2];
504
static Colormap		xcmap;		/* Default shared colormap  */
505
 
506
extern int mousequeue;
507
 
508
/* for copy/paste, lifted from plan9ports */
509
static Atom clipboard; 
510
static Atom utf8string;
511
static Atom targets;
512
static Atom text;
513
static Atom compoundtext;
514
 
515
static	Drawable	xdrawable;
516
static	void		xexpose(XEvent*);
517
static	void		xmouse(XEvent*);
518
static	void		xkeyboard(XEvent*);
519
static	void		xmapping(XEvent*);
520
static	void		xdestroy(XEvent*);
521
static	void		xselect(XEvent*, XDisplay*);
522
static	void		xproc(void*);
523
static	Memimage*		xinitscreen(void);
524
static	void		initmap(Window);
525
static	GC		creategc(Drawable);
526
static	void		graphicscmap(XColor*);
527
static	int		xscreendepth;
528
static	XDisplay*	xkmcon;	/* used only in xproc */
529
static	XDisplay*	xsnarfcon;	/* used holding clip.lk */
530
static	ulong		xblack;
531
static	ulong		xwhite;
532
 
533
static	int	putsnarf, assertsnarf;
534
 
535
	Memimage *gscreen;
536
	Screeninfo screen;
537
 
538
void
539
flushmemscreen(Rectangle r)
540
{
541
	assert(!drawcanqlock());
542
	if(r.min.x >= r.max.x || r.min.y >= r.max.y)
543
		return;
544
	XCopyArea(xdisplay, xscreenid, xdrawable, xgccopy, r.min.x, r.min.y, Dx(r), Dy(r), r.min.x, r.min.y);
545
	XFlush(xdisplay);
546
}
547
 
548
void
549
screeninit(void)
550
{
551
	_memmkcmap();
552
 
553
	gscreen = xinitscreen();
554
	kproc("xscreen", xproc, nil);
555
 
556
	memimageinit();
557
	terminit();
558
	drawqlock();
559
	flushmemscreen(gscreen->r);
560
	drawqunlock();
561
}
562
 
563
uchar*
564
attachscreen(Rectangle *r, ulong *chan, int *depth,
565
	int *width, int *softscreen, void **X)
566
{
567
	*r = gscreen->r;
568
	*chan = gscreen->chan;
569
	*depth = gscreen->depth;
570
	*width = gscreen->width;
571
	*X = gscreen->X;
572
	*softscreen = 1;
573
 
574
	return gscreen->data->bdata;
575
}
576
 
577
static int
578
revbyte(int b)
579
{
580
	int r;
581
 
582
	r = 0;
583
	r |= (b&0x01) << 7;
584
	r |= (b&0x02) << 5;
585
	r |= (b&0x04) << 3;
586
	r |= (b&0x08) << 1;
587
	r |= (b&0x10) >> 1;
588
	r |= (b&0x20) >> 3;
589
	r |= (b&0x40) >> 5;
590
	r |= (b&0x80) >> 7;
591
	return r;
592
}
593
 
594
void
595
mouseset(Point xy)
596
{
597
	drawqlock();
598
	XWarpPointer(xdisplay, None, xdrawable, 0, 0, 0, 0, xy.x, xy.y);
599
	XFlush(xdisplay);
600
	drawqunlock();
601
}
602
 
603
static XCursor xcursor;
604
 
605
void
606
setcursor(void)
607
{
608
	XCursor xc;
609
	XColor fg, bg;
610
	Pixmap xsrc, xmask;
611
	int i;
612
	uchar src[2*16], mask[2*16];
613
 
614
	for(i=0; i<2*16; i++){
615
		src[i] = revbyte(cursor.set[i]);
616
		mask[i] = revbyte(cursor.set[i] | cursor.clr[i]);
617
	}
618
 
619
	drawqlock();
620
	fg = map[0];
621
	bg = map[255];
622
	xsrc = XCreateBitmapFromData(xdisplay, xdrawable, (char*)src, 16, 16);
623
	xmask = XCreateBitmapFromData(xdisplay, xdrawable, (char*)mask, 16, 16);
624
	xc = XCreatePixmapCursor(xdisplay, xsrc, xmask, &fg, &bg, -cursor.offset.x, -cursor.offset.y);
625
	if(xc != 0) {
626
		XDefineCursor(xdisplay, xdrawable, xc);
627
		if(xcursor != 0)
628
			XFreeCursor(xdisplay, xcursor);
629
		xcursor = xc;
630
	}
631
	XFreePixmap(xdisplay, xsrc);
632
	XFreePixmap(xdisplay, xmask);
633
	XFlush(xdisplay);
634
	drawqunlock();
635
}
636
 
637
void
638
cursorarrow(void)
639
{
640
	drawqlock();
641
	if(xcursor != 0){
642
		XFreeCursor(xdisplay, xcursor);
643
		xcursor = 0;
644
	}
645
	XUndefineCursor(xdisplay, xdrawable);
646
	XFlush(xdisplay);
647
	drawqunlock();
648
}
649
 
650
static void
651
xproc(void *arg)
652
{
653
	ulong mask;
654
	XEvent event;
655
 
656
	mask = 	KeyPressMask|
657
		ButtonPressMask|
658
		ButtonReleaseMask|
659
		PointerMotionMask|
660
		Button1MotionMask|
661
		Button2MotionMask|
662
		Button3MotionMask|
663
		Button4MotionMask|
664
		Button5MotionMask|
665
		ExposureMask|
666
		StructureNotifyMask;
667
 
668
	XSelectInput(xkmcon, xdrawable, mask);
669
	for(;;) {
670
		//XWindowEvent(xkmcon, xdrawable, mask, &event);
671
		XNextEvent(xkmcon, &event);
672
		xselect(&event, xkmcon);
673
		xkeyboard(&event);
674
		xmouse(&event);
675
		xexpose(&event);
676
		xmapping(&event);
677
		xdestroy(&event);
678
	}
679
}
680
 
681
static int
682
shutup(XDisplay *d, XErrorEvent *e)
683
{
684
	char buf[200];
685
	iprint("X error: error code=%d, request_code=%d, minor=%d\n", e->error_code, e->request_code, e->minor_code);
686
	XGetErrorText(d, e->error_code, buf, sizeof(buf));
687
	iprint("%s\n", buf);
688
	USED(d);
689
	USED(e);
690
	return 0;
691
}
692
 
693
static int
694
panicshutup(XDisplay *d)
695
{
696
	panic("x error");
697
	return -1;
698
}
699
 
700
static Memimage*
701
xinitscreen(void)
702
{
703
	Memimage *gscreen;
704
	int i, xsize, ysize, pmid;
705
	char *argv[2];
706
	char *disp_val;
707
	Window rootwin;
708
	Rectangle r;
709
	XWMHints hints;
710
	XScreen *screen;
711
	XVisualInfo xvi;
712
	int rootscreennum;
713
	XTextProperty name;
714
	XClassHint classhints;
715
	XSizeHints normalhints;
716
	XSetWindowAttributes attrs;
717
	XPixmapFormatValues *pfmt;
718
	int n;
719
	Pixmap icon_pixmap;
720
 
721
	xscreenid = 0;
722
	xdrawable = 0;
723
 
724
	xdisplay = XOpenDisplay(NULL);
725
	if(xdisplay == 0){
726
		iprint("xinitscreen: XOpenDisplay: %r [DISPLAY=%s]\n",
727
			getenv("DISPLAY"));
728
		exit(0);
729
	}
730
 
731
	XSetErrorHandler(shutup);
732
	XSetIOErrorHandler(panicshutup);
733
	rootscreennum = DefaultScreen(xdisplay);
734
	rootwin = DefaultRootWindow(xdisplay);
735
 
736
	xscreendepth = DefaultDepth(xdisplay, rootscreennum);
737
	if(XMatchVisualInfo(xdisplay, rootscreennum, 16, TrueColor, &xvi)
738
	|| XMatchVisualInfo(xdisplay, rootscreennum, 16, DirectColor, &xvi)){
739
		xvis = xvi.visual;
740
		xscreendepth = 16;
741
		xtblbit = 1;
742
	}
743
	else if(XMatchVisualInfo(xdisplay, rootscreennum, 24, TrueColor, &xvi)
744
	|| XMatchVisualInfo(xdisplay, rootscreennum, 24, DirectColor, &xvi)){
745
		xvis = xvi.visual;
746
		xscreendepth = 24;
747
		xtblbit = 1;
748
	}
749
	else if(XMatchVisualInfo(xdisplay, rootscreennum, 8, PseudoColor, &xvi)
750
	|| XMatchVisualInfo(xdisplay, rootscreennum, 8, StaticColor, &xvi)){
751
		if(xscreendepth > 8)
752
			panic("drawterm: can't deal with colormapped depth %d screens\n", xscreendepth);
753
		xvis = xvi.visual;
754
		xscreendepth = 8;
755
	}
756
	else{
757
		if(xscreendepth != 8)
758
			panic("drawterm: can't deal with depth %d screens\n", xscreendepth);
759
		xvis = DefaultVisual(xdisplay, rootscreennum);
760
	}
761
 
762
	/*
763
	 * xscreendepth is only the number of significant pixel bits,
764
	 * not the total.  We need to walk the display list to find
765
	 * how many actual bits are being used per pixel.
766
	 */
767
	xscreenchan = 0; /* not a valid channel */
768
	pfmt = XListPixmapFormats(xdisplay, &n);
769
	for(i=0; i<n; i++){
770
		if(pfmt[i].depth == xscreendepth){
771
			switch(pfmt[i].bits_per_pixel){
772
			case 1:	/* untested */
773
				xscreenchan = GREY1;
774
				break;
775
			case 2:	/* untested */
776
				xscreenchan = GREY2;
777
				break;
778
			case 4:	/* untested */
779
				xscreenchan = GREY4;
780
				break;
781
			case 8:
782
				xscreenchan = CMAP8;
783
				break;
784
			case 16: /* uses 16 rather than 15, empirically. */
785
				xscreenchan = RGB16;
786
				break;
787
			case 24: /* untested (impossible?) */
788
				xscreenchan = RGB24;
789
				break;
790
			case 32:
791
				xscreenchan = CHAN4(CIgnore, 8, CRed, 8, CGreen, 8, CBlue, 8);
792
				break;
793
			}
794
		}
795
	}
796
	if(xscreenchan == 0)
797
		panic("drawterm: unknown screen pixel format\n");
798
 
799
	screen = DefaultScreenOfDisplay(xdisplay);
800
	xcmap = DefaultColormapOfScreen(screen);
801
 
802
	if(xvis->class != StaticColor){
803
		graphicscmap(map);
804
		initmap(rootwin);
805
	}
806
 
807
	r.min = ZP;
808
	r.max.x = WidthOfScreen(screen);
809
	r.max.y = HeightOfScreen(screen);
810
 
811
	xsize = Dx(r)*3/4;
812
	ysize = Dy(r)*3/4;
813
 
814
	attrs.colormap = xcmap;
815
	attrs.background_pixel = 0;
816
	attrs.border_pixel = 0;
817
	/* attrs.override_redirect = 1;*/ /* WM leave me alone! |CWOverrideRedirect */
818
	xdrawable = XCreateWindow(xdisplay, rootwin, 0, 0, xsize, ysize, 0, 
819
		xscreendepth, InputOutput, xvis, CWBackPixel|CWBorderPixel|CWColormap, &attrs);
820
 
821
	/* load the given bitmap data and create an X pixmap containing it. */
822
	icon_pixmap = XCreateBitmapFromData(xdisplay,
823
		rootwin, (char *)glenda_bits,
824
		glenda_width, glenda_height);
825
 
826
	/*
827
	 * set up property as required by ICCCM
828
	 */
829
	name.value = (uchar*)"drawterm";
830
	name.encoding = XA_STRING;
831
	name.format = 8;
832
	name.nitems = strlen((char*)name.value);
833
	normalhints.flags = USSize|PMaxSize;
834
	normalhints.max_width = Dx(r);
835
	normalhints.max_height = Dy(r);
836
	normalhints.width = xsize;
837
	normalhints.height = ysize;
838
	hints.flags = IconPixmapHint |InputHint|StateHint;
839
	hints.input = 1;
840
	hints.initial_state = NormalState;
841
	hints.icon_pixmap = icon_pixmap;
842
 
843
	classhints.res_name = "drawterm";
844
	classhints.res_class = "Drawterm";
845
	argv[0] = "drawterm";
846
	argv[1] = nil;
847
	XSetWMProperties(xdisplay, xdrawable,
848
		&name,			/* XA_WM_NAME property for ICCCM */
849
		&name,			/* XA_WM_ICON_NAME */
850
		argv,			/* XA_WM_COMMAND */
851
		1,			/* argc */
852
		&normalhints,		/* XA_WM_NORMAL_HINTS */
853
		&hints,			/* XA_WM_HINTS */
854
		&classhints);		/* XA_WM_CLASS */
855
	XFlush(xdisplay);
856
 
857
	/*
858
	 * put the window on the screen
859
	 */
860
	XMapWindow(xdisplay, xdrawable);
861
	XFlush(xdisplay);
862
 
863
	xscreenid = XCreatePixmap(xdisplay, xdrawable, Dx(r), Dy(r), xscreendepth);
864
	gscreen = xallocmemimage(r, xscreenchan, xscreenid);
865
 
866
	xgcfill = creategc(xscreenid);
867
	XSetFillStyle(xdisplay, xgcfill, FillSolid);
868
	xgccopy = creategc(xscreenid);
869
	xgcsimplesrc = creategc(xscreenid);
870
	XSetFillStyle(xdisplay, xgcsimplesrc, FillStippled);
871
	xgczero = creategc(xscreenid);
872
	xgcreplsrc = creategc(xscreenid);
873
	XSetFillStyle(xdisplay, xgcreplsrc, FillTiled);
874
 
875
	pmid = XCreatePixmap(xdisplay, xdrawable, 1, 1, 1);
876
	xgcfill0 = creategc(pmid);
877
	XSetForeground(xdisplay, xgcfill0, 0);
878
	XSetFillStyle(xdisplay, xgcfill0, FillSolid);
879
	xgccopy0 = creategc(pmid);
880
	xgcsimplesrc0 = creategc(pmid);
881
	XSetFillStyle(xdisplay, xgcsimplesrc0, FillStippled);
882
	xgczero0 = creategc(pmid);
883
	xgcreplsrc0 = creategc(pmid);
884
	XSetFillStyle(xdisplay, xgcreplsrc0, FillTiled);
885
	XFreePixmap(xdisplay, pmid);
886
 
887
	XSetForeground(xdisplay, xgccopy, plan9tox11[0]);
888
	XFillRectangle(xdisplay, xscreenid, xgccopy, 0, 0, xsize, ysize);
889
 
890
	xkmcon = XOpenDisplay(NULL);
891
	if(xkmcon == 0){
892
		disp_val = getenv("DISPLAY");
893
		if(disp_val == 0)
894
			disp_val = "not set";
895
		iprint("drawterm: open %r, DISPLAY is %s\n", disp_val);
896
		exit(0);
897
	}
898
	xsnarfcon = XOpenDisplay(NULL);
899
	if(xsnarfcon == 0){
900
		disp_val = getenv("DISPLAY");
901
		if(disp_val == 0)
902
			disp_val = "not set";
903
		iprint("drawterm: open %r, DISPLAY is %s\n", disp_val);
904
		exit(0);
905
	}
906
 
907
	clipboard = XInternAtom(xkmcon, "CLIPBOARD", False);
908
	utf8string = XInternAtom(xkmcon, "UTF8_STRING", False);
909
	targets = XInternAtom(xkmcon, "TARGETS", False);
910
	text = XInternAtom(xkmcon, "TEXT", False);
911
	compoundtext = XInternAtom(xkmcon, "COMPOUND_TEXT", False);
912
 
913
	xblack = screen->black_pixel;
914
	xwhite = screen->white_pixel;
915
	return gscreen;
916
}
917
 
918
static void
919
graphicscmap(XColor *map)
920
{
921
	int r, g, b, cr, cg, cb, v, num, den, idx, v7, idx7;
922
 
923
	for(r=0; r!=4; r++) {
924
		for(g = 0; g != 4; g++) {
925
			for(b = 0; b!=4; b++) {
926
				for(v = 0; v!=4; v++) {
927
					den=r;
928
					if(g > den)
929
						den=g;
930
					if(b > den)
931
						den=b;
932
					/* divide check -- pick grey shades */
933
					if(den==0)
934
						cr=cg=cb=v*17;
935
					else {
936
						num=17*(4*den+v);
937
						cr=r*num/den;
938
						cg=g*num/den;
939
						cb=b*num/den;
940
					}
941
					idx = r*64 + v*16 + ((g*4 + b + v - r) & 15);
942
					map[idx].red = cr*0x0101;
943
					map[idx].green = cg*0x0101;
944
					map[idx].blue = cb*0x0101;
945
					map[idx].pixel = idx;
946
					map[idx].flags = DoRed|DoGreen|DoBlue;
947
 
948
					v7 = v >> 1;
949
					idx7 = r*32 + v7*16 + g*4 + b;
950
					if((v & 1) == v7){
951
						map7to8[idx7][0] = idx;
952
						if(den == 0) { 		/* divide check -- pick grey shades */
953
							cr = ((255.0/7.0)*v7)+0.5;
954
							cg = cr;
955
							cb = cr;
956
						}
957
						else {
958
							num=17*15*(4*den+v7*2)/14;
959
							cr=r*num/den;
960
							cg=g*num/den;
961
							cb=b*num/den;
962
						}
963
						map7[idx7].red = cr*0x0101;
964
						map7[idx7].green = cg*0x0101;
965
						map7[idx7].blue = cb*0x0101;
966
						map7[idx7].pixel = idx7;
967
						map7[idx7].flags = DoRed|DoGreen|DoBlue;
968
					}
969
					else
970
						map7to8[idx7][1] = idx;
971
				}
972
			}
973
		}
974
	}
975
}
976
 
977
/*
978
 * Initialize and install the drawterm colormap as a private colormap for this
979
 * application.  Drawterm gets the best colors here when it has the cursor focus.
980
 */  
981
static void 
982
initmap(Window w)
983
{
984
	XColor c;
985
	int i;
986
	ulong p, pp;
987
	char buf[30];
988
 
989
	if(xscreendepth <= 1)
990
		return;
991
 
992
	if(xscreendepth >= 24) {
993
		/* The pixel value returned from XGetPixel needs to
994
		 * be converted to RGB so we can call rgb2cmap()
995
		 * to translate between 24 bit X and our color. Unfortunately,
996
		 * the return value appears to be display server endian 
997
		 * dependant. Therefore, we run some heuristics to later
998
		 * determine how to mask the int value correctly.
999
		 * Yeah, I know we can look at xvis->byte_order but 
1000
		 * some displays say MSB even though they run on LSB.
1001
		 * Besides, this is more anal.
1002
		 */
1003
		if(xscreendepth != DefaultDepth(xdisplay, DefaultScreen(xdisplay)))
1004
			xcmap = XCreateColormap(xdisplay, w, xvis, AllocNone);
1005
 
1006
		c = map[19];
1007
		/* find out index into colormap for our RGB */
1008
		if(!XAllocColor(xdisplay, xcmap, &c))
1009
			panic("drawterm: screen-x11 can't alloc color");
1010
 
1011
		p  = c.pixel;
1012
		pp = rgb2cmap((p>>16)&0xff,(p>>8)&0xff,p&0xff);
1013
		if(pp!=map[19].pixel) {
1014
			/* check if endian is other way */
1015
			pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff);
1016
			if(pp!=map[19].pixel)
1017
				panic("cannot detect x server byte order");
1018
			switch(xscreenchan){
1019
			case RGB24:
1020
				xscreenchan = BGR24;
1021
				break;
1022
			case XRGB32:
1023
				xscreenchan = XBGR32;
1024
				break;
1025
			default:
1026
				panic("don't know how to byteswap channel %s", 
1027
					chantostr(buf, xscreenchan));
1028
				break;
1029
			}
1030
		}
1031
	} else if(xvis->class == TrueColor || xvis->class == DirectColor) {
1032
	} else if(xvis->class == PseudoColor) {
1033
		if(xtblbit == 0){
1034
			xcmap = XCreateColormap(xdisplay, w, xvis, AllocAll); 
1035
			XStoreColors(xdisplay, xcmap, map, 256);
1036
			for(i = 0; i < 256; i++) {
1037
				plan9tox11[i] = i;
1038
				x11toplan9[i] = i;
1039
			}
1040
		}
1041
		else {
1042
			for(i = 0; i < 128; i++) {
1043
				c = map7[i];
1044
				if(!XAllocColor(xdisplay, xcmap, &c)) {
1045
					iprint("drawterm: can't alloc colors in default map, don't use -7\n");
1046
					exit(0);
1047
				}
1048
				plan9tox11[map7to8[i][0]] = c.pixel;
1049
				plan9tox11[map7to8[i][1]] = c.pixel;
1050
				x11toplan9[c.pixel] = map7to8[i][0];
1051
			}
1052
		}
1053
	}
1054
	else
1055
		panic("drawterm: unsupported visual class %d\n", xvis->class);
1056
}
1057
 
1058
static void
1059
xdestroy(XEvent *e)
1060
{
1061
	XDestroyWindowEvent *xe;
1062
	if(e->type != DestroyNotify)
1063
		return;
1064
	xe = (XDestroyWindowEvent*)e;
1065
	if(xe->window == xdrawable)
1066
		exit(0);
1067
}
1068
 
1069
static void
1070
xmapping(XEvent *e)
1071
{
1072
	XMappingEvent *xe;
1073
 
1074
	if(e->type != MappingNotify)
1075
		return;
1076
	xe = (XMappingEvent*)e;
1077
	USED(xe);
1078
}
1079
 
1080
 
1081
/*
1082
 * Disable generation of GraphicsExpose/NoExpose events in the GC.
1083
 */
1084
static GC
1085
creategc(Drawable d)
1086
{
1087
	XGCValues gcv;
1088
 
1089
	gcv.function = GXcopy;
1090
	gcv.graphics_exposures = False;
1091
	return XCreateGC(xdisplay, d, GCFunction|GCGraphicsExposures, &gcv);
1092
}
1093
 
1094
static void
1095
xexpose(XEvent *e)
1096
{
1097
	Rectangle r;
1098
	XExposeEvent *xe;
1099
 
1100
	if(e->type != Expose)
1101
		return;
1102
	xe = (XExposeEvent*)e;
1103
	r.min.x = xe->x;
1104
	r.min.y = xe->y;
1105
	r.max.x = xe->x + xe->width;
1106
	r.max.y = xe->y + xe->height;
1107
	drawflushr(r);
1108
}
1109
 
1110
static void
1111
xkeyboard(XEvent *e)
1112
{
1113
	KeySym k;
1114
 
1115
	/*
1116
	 * I tried using XtGetActionKeysym, but it didn't seem to
1117
	 * do case conversion properly
1118
	 * (at least, with Xterminal servers and R4 intrinsics)
1119
	 */
1120
	if(e->xany.type != KeyPress)
1121
		return;
1122
 
1123
 
1124
	XLookupString((XKeyEvent*)e, NULL, 0, &k, NULL);
1125
 
1126
	if(k == XK_Multi_key || k == NoSymbol)
1127
		return;
1128
	if(k&0xFF00){
1129
		switch(k){
1130
		case XK_BackSpace:
1131
		case XK_Tab:
1132
		case XK_Escape:
1133
		case XK_Delete:
1134
		case XK_KP_0:
1135
		case XK_KP_1:
1136
		case XK_KP_2:
1137
		case XK_KP_3:
1138
		case XK_KP_4:
1139
		case XK_KP_5:
1140
		case XK_KP_6:
1141
		case XK_KP_7:
1142
		case XK_KP_8:
1143
		case XK_KP_9:
1144
		case XK_KP_Divide:
1145
		case XK_KP_Multiply:
1146
		case XK_KP_Subtract:
1147
		case XK_KP_Add:
1148
		case XK_KP_Decimal:
1149
			k &= 0x7F;
1150
			break;
1151
		case XK_Linefeed:
1152
			k = '\r';
1153
			break;
1154
		case XK_KP_Space:
1155
			k = ' ';
1156
			break;
1157
		case XK_Home:
1158
		case XK_KP_Home:
1159
			k = Khome;
1160
			break;
1161
		case XK_Left:
1162
		case XK_KP_Left:
1163
			k = Kleft;
1164
			break;
1165
		case XK_Up:
1166
		case XK_KP_Up:
1167
			k = Kup;
1168
			break;
1169
		case XK_Down:
1170
		case XK_KP_Down:
1171
			k = Kdown;
1172
			break;
1173
		case XK_Right:
1174
		case XK_KP_Right:
1175
			k = Kright;
1176
			break;
1177
		case XK_Page_Down:
1178
		case XK_KP_Page_Down:
1179
			k = Kpgdown;
1180
			break;
1181
		case XK_End:
1182
		case XK_KP_End:
1183
			k = Kend;
1184
			break;
1185
		case XK_Page_Up:	
1186
		case XK_KP_Page_Up:
1187
			k = Kpgup;
1188
			break;
1189
		case XK_Insert:
1190
		case XK_KP_Insert:
1191
			k = Kins;
1192
			break;
1193
		case XK_KP_Enter:
1194
		case XK_Return:
1195
			k = '\n';
1196
			break;
1197
		case XK_Alt_L:
1198
		case XK_Alt_R:
1199
			k = Kalt;
1200
			break;
1201
		case XK_F1:
1202
		case XK_F2:
1203
		case XK_F3:
1204
		case XK_F4:
1205
		case XK_F5:
1206
		case XK_F6:
1207
		case XK_F7:
1208
		case XK_F8:
1209
		case XK_F9:
1210
		case XK_F10:
1211
		case XK_F11:
1212
		case XK_F12:
1213
			k = KF|(k - XK_F1 + 1);
1214
			break;
1215
		case XK_Shift_L:
1216
		case XK_Shift_R:
1217
		case XK_Control_L:
1218
		case XK_Control_R:
1219
		case XK_Caps_Lock:
1220
		case XK_Shift_Lock:
1221
 
1222
		case XK_Meta_L:
1223
		case XK_Meta_R:
1224
		case XK_Super_L:
1225
		case XK_Super_R:
1226
		case XK_Hyper_L:
1227
		case XK_Hyper_R:
1228
			return;
1229
		default:		/* not ISO-1 or tty control */
1230
  			if(k>0xff){
1231
				k = keysym2ucs(k); /* supplied by X */
1232
				if(k == -1)
1233
					return;
1234
			}
1235
			break;
1236
		}
1237
	}
1238
 
1239
	/* Compensate for servers that call a minus a hyphen */
1240
	if(k == XK_hyphen)
1241
		k = XK_minus;
1242
	/* Do control mapping ourselves if translator doesn't */
1243
	if(e->xkey.state&ControlMask && k != Kalt)
1244
		k &= 0x9f;
1245
	if(k == NoSymbol) {
1246
		return;
1247
	}
1248
 
1249
	kbdputc(kbdq, k);
1250
}
1251
 
1252
static void
1253
xmouse(XEvent *e)
1254
{
1255
	Mousestate ms;
1256
	int i, s;
1257
	XButtonEvent *be;
1258
	XMotionEvent *me;
1259
 
1260
	if(putsnarf != assertsnarf){
1261
		assertsnarf = putsnarf;
1262
		XSetSelectionOwner(xkmcon, XA_PRIMARY, xdrawable, CurrentTime);
1263
		if(clipboard != None)
1264
			XSetSelectionOwner(xkmcon, clipboard, xdrawable, CurrentTime);
1265
		XFlush(xkmcon);
1266
	}
1267
 
1268
	switch(e->type){
1269
	case ButtonPress:
1270
		be = (XButtonEvent *)e;
1271
		/* 
1272
		 * Fake message, just sent to make us announce snarf.
1273
		 * Apparently state and button are 16 and 8 bits on
1274
		 * the wire, since they are truncated by the time they
1275
		 * get to us.
1276
		 */
1277
		if(be->send_event
1278
		&& (~be->state&0xFFFF)==0
1279
		&& (~be->button&0xFF)==0)
1280
			return;
1281
		ms.xy.x = be->x;
1282
		ms.xy.y = be->y;
1283
		s = be->state;
1284
		ms.msec = be->time;
1285
		switch(be->button){
1286
		case 1:
1287
			s |= Button1Mask;
1288
			break;
1289
		case 2:
1290
			s |= Button2Mask;
1291
			break;
1292
		case 3:
1293
			s |= Button3Mask;
1294
			break;
1295
		case 4:
1296
			s |= Button4Mask;
1297
			break;
1298
		case 5:
1299
			s |= Button5Mask;
1300
			break;
1301
		}
1302
		break;
1303
	case ButtonRelease:
1304
		be = (XButtonEvent *)e;
1305
		ms.xy.x = be->x;
1306
		ms.xy.y = be->y;
1307
		ms.msec = be->time;
1308
		s = be->state;
1309
		switch(be->button){
1310
		case 1:
1311
			s &= ~Button1Mask;
1312
			break;
1313
		case 2:
1314
			s &= ~Button2Mask;
1315
			break;
1316
		case 3:
1317
			s &= ~Button3Mask;
1318
			break;
1319
		case 4:
1320
			s &= ~Button4Mask;
1321
			break;
1322
		case 5:
1323
			s &= ~Button5Mask;
1324
			break;
1325
		}
1326
		break;
1327
	case MotionNotify:
1328
		me = (XMotionEvent *)e;
1329
		s = me->state;
1330
		ms.xy.x = me->x;
1331
		ms.xy.y = me->y;
1332
		ms.msec = me->time;
1333
		break;
1334
	default:
1335
		return;
1336
	}
1337
 
1338
	ms.buttons = 0;
1339
	if(s & Button1Mask)
1340
		ms.buttons |= 1;
1341
	if(s & Button2Mask)
1342
		ms.buttons |= 2;
1343
	if(s & Button3Mask)
1344
		ms.buttons |= 4;
1345
	if(s & Button4Mask)
1346
		ms.buttons |= 8;
1347
	if(s & Button5Mask)
1348
		ms.buttons |= 16;
1349
 
1350
	lock(&mouse.lk);
1351
	i = mouse.wi;
1352
	if(mousequeue) {
1353
		if(i == mouse.ri || mouse.lastb != ms.buttons || mouse.trans) {
1354
			mouse.wi = (i+1)%Mousequeue;
1355
			if(mouse.wi == mouse.ri)
1356
				mouse.ri = (mouse.ri+1)%Mousequeue;
1357
			mouse.trans = mouse.lastb != ms.buttons;
1358
		} else {
1359
			i = (i-1+Mousequeue)%Mousequeue;
1360
		}
1361
	} else {
1362
		mouse.wi = (i+1)%Mousequeue;
1363
		mouse.ri = i;
1364
	}
1365
	mouse.queue[i] = ms;
1366
	mouse.lastb = ms.buttons;
1367
	unlock(&mouse.lk);
1368
	wakeup(&mouse.r);
1369
}
1370
 
1371
void
1372
getcolor(ulong i, ulong *r, ulong *g, ulong *b)
1373
{
1374
	ulong v;
1375
 
1376
	v = cmap2rgb(i);
1377
	*r = (v>>16)&0xFF;
1378
	*g = (v>>8)&0xFF;
1379
	*b = v&0xFF;
1380
}
1381
 
1382
void
1383
setcolor(ulong i, ulong r, ulong g, ulong b)
1384
{
1385
	/* no-op */
1386
}
1387
 
1388
int
1389
atlocalconsole(void)
1390
{
1391
	char *p, *q;
1392
	char buf[128];
1393
 
1394
	p = getenv("DRAWTERM_ATLOCALCONSOLE");
1395
	if(p && atoi(p) == 1)
1396
		return 1;
1397
 
1398
	p = getenv("DISPLAY");
1399
	if(p == nil)
1400
		return 0;
1401
 
1402
	/* extract host part */
1403
	q = strchr(p, ':');
1404
	if(q == nil)
1405
		return 0;
1406
	*q = 0;
1407
 
1408
	if(strcmp(p, "") == 0)
1409
		return 1;
1410
 
1411
	/* try to match against system name (i.e. for ssh) */
1412
	if(gethostname(buf, sizeof buf) == 0){
1413
		if(strcmp(p, buf) == 0)
1414
			return 1;
1415
		if(strncmp(p, buf, strlen(p)) == 0 && buf[strlen(p)]=='.')
1416
			return 1;
1417
	}
1418
 
1419
	return 0;
1420
}
1421
 
1422
/*
1423
 * Cut and paste.  Just couldn't stand to make this simple...
1424
 */
1425
 
1426
typedef struct Clip Clip;
1427
struct Clip
1428
{
1429
	char buf[SnarfSize];
1430
	QLock lk;
1431
};
1432
Clip clip;
1433
 
1434
#undef long	/* sic */
1435
#undef ulong
1436
 
1437
static char*
1438
_xgetsnarf(XDisplay *xd)
1439
{
1440
	uchar *data, *xdata;
1441
	Atom clipboard, type, prop;
1442
	unsigned long lastlen;
1443
	unsigned long dummy, len;
1444
	int fmt, i;
1445
	Window w;
1446
 
1447
	qlock(&clip.lk);
1448
	/*
1449
	 * Have we snarfed recently and the X server hasn't caught up?
1450
	 */
1451
	if(putsnarf != assertsnarf)
1452
		goto mine;
1453
 
1454
	/*
1455
	 * Is there a primary selection (highlighted text in an xterm)?
1456
	 */
1457
	clipboard = XA_PRIMARY;
1458
	w = XGetSelectionOwner(xd, XA_PRIMARY);
1459
	if(w == xdrawable){
1460
	mine:
1461
		data = (uchar*)strdup(clip.buf);
1462
		goto out;
1463
	}
1464
 
1465
	/*
1466
	 * If not, is there a clipboard selection?
1467
	 */
1468
	if(w == None && clipboard != None){
1469
		clipboard = clipboard;
1470
		w = XGetSelectionOwner(xd, clipboard);
1471
		if(w == xdrawable)
1472
			goto mine;
1473
	}
1474
 
1475
	/*
1476
	 * If not, give up.
1477
	 */
1478
	if(w == None){
1479
		data = nil;
1480
		goto out;
1481
	}
1482
 
1483
	/*
1484
	 * We should be waiting for SelectionNotify here, but it might never
1485
	 * come, and we have no way to time out.  Instead, we will clear
1486
	 * local property #1, request our buddy to fill it in for us, and poll
1487
	 * until he's done or we get tired of waiting.
1488
	 *
1489
	 * We should try to go for utf8string instead of XA_STRING,
1490
	 * but that would add to the polling.
1491
	 */
1492
	prop = 1;
1493
	XChangeProperty(xd, xdrawable, prop, XA_STRING, 8, PropModeReplace, (uchar*)"", 0);
1494
	XConvertSelection(xd, clipboard, XA_STRING, prop, xdrawable, CurrentTime);
1495
	XFlush(xd);
1496
	lastlen = 0;
1497
	for(i=0; i<10 || (lastlen!=0 && i<30); i++){
1498
		usleep(100*1000);
1499
		XGetWindowProperty(xd, xdrawable, prop, 0, 0, 0, AnyPropertyType,
1500
			&type, &fmt, &dummy, &len, &data);
1501
		if(lastlen == len && len > 0)
1502
			break;
1503
		lastlen = len;
1504
	}
1505
	if(i == 10){
1506
		data = nil;
1507
		goto out;
1508
	}
1509
	/* get the property */
1510
	data = nil;
1511
	XGetWindowProperty(xd, xdrawable, prop, 0, SnarfSize/sizeof(unsigned long), 0, 
1512
		AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
1513
	if((type != XA_STRING && type != utf8string) || len == 0){
1514
		if(xdata)
1515
			XFree(xdata);
1516
		data = nil;
1517
	}else{
1518
		if(xdata){
1519
			data = (uchar*)strdup((char*)xdata);
1520
			XFree(xdata);
1521
		}else
1522
			data = nil;
1523
	}
1524
out:
1525
	qunlock(&clip.lk);
1526
	return (char*)data;
1527
}
1528
 
1529
static void
1530
_xputsnarf(XDisplay *xd, char *data)
1531
{
1532
	XButtonEvent e;
1533
 
1534
	if(strlen(data) >= SnarfSize)
1535
		return;
1536
	qlock(&clip.lk);
1537
	strcpy(clip.buf, data);
1538
 
1539
	/* leave note for mouse proc to assert selection ownership */
1540
	putsnarf++;
1541
 
1542
	/* send mouse a fake event so snarf is announced */
1543
	memset(&e, 0, sizeof e);
1544
	e.type = ButtonPress;
1545
	e.window = xdrawable;
1546
	e.state = ~0;
1547
	e.button = ~0;
1548
	XSendEvent(xd, xdrawable, True, ButtonPressMask, (XEvent*)&e);
1549
	XFlush(xd);
1550
	qunlock(&clip.lk);
1551
}
1552
 
1553
static void
1554
xselect(XEvent *e, XDisplay *xd)
1555
{
1556
	char *name;
1557
	XEvent r;
1558
	XSelectionRequestEvent *xe;
1559
	Atom a[4];
1560
 
1561
	if(e->xany.type != SelectionRequest)
1562
		return;
1563
 
1564
	memset(&r, 0, sizeof r);
1565
	xe = (XSelectionRequestEvent*)e;
1566
if(0) iprint("xselect target=%d requestor=%d property=%d selection=%d\n",
1567
	xe->target, xe->requestor, xe->property, xe->selection);
1568
	r.xselection.property = xe->property;
1569
	if(xe->target == targets){
1570
		a[0] = XA_STRING;
1571
		a[1] = utf8string;
1572
		a[2] = text;
1573
		a[3] = compoundtext;
1574
 
1575
		XChangeProperty(xd, xe->requestor, xe->property, XA_ATOM,
1576
			32, PropModeReplace, (uchar*)a, sizeof a);
1577
	}else if(xe->target == XA_STRING || xe->target == utf8string || xe->target == text || xe->target == compoundtext){
1578
	text:
1579
		/* if the target is STRING we're supposed to reply with Latin1 XXX */
1580
		qlock(&clip.lk);
1581
		XChangeProperty(xd, xe->requestor, xe->property, xe->target,
1582
			8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));
1583
		qunlock(&clip.lk);
1584
	}else{
1585
		name = XGetAtomName(xd, xe->target);
1586
		if(name == nil)
1587
			iprint("XGetAtomName %d failed\n", xe->target);
1588
		if(name){
1589
			if(strcmp(name, "TIMESTAMP") == 0){
1590
				/* nothing */
1591
			}else if(strncmp(name, "image/", 6) == 0){
1592
				/* nothing */
1593
			}else if(strcmp(name, "text/html") == 0){
1594
				/* nothing */
1595
			}else if(strcmp(name, "text/plain") == 0 || strcmp(name, "text/plain;charset=UTF-8") == 0){
1596
				goto text;
1597
			}else
1598
				iprint("%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)xe->target);
1599
		}
1600
		r.xselection.property = None;
1601
	}
1602
 
1603
	r.xselection.display = xe->display;
1604
	/* r.xselection.property filled above */
1605
	r.xselection.target = xe->target;
1606
	r.xselection.type = SelectionNotify;
1607
	r.xselection.requestor = xe->requestor;
1608
	r.xselection.time = xe->time;
1609
	r.xselection.send_event = True;
1610
	r.xselection.selection = xe->selection;
1611
	XSendEvent(xd, xe->requestor, False, 0, &r);
1612
	XFlush(xd);
1613
}
1614
 
1615
char*
1616
clipread(void)
1617
{
1618
	return _xgetsnarf(xsnarfcon);
1619
}
1620
 
1621
int
1622
clipwrite(char *buf)
1623
{
1624
	_xputsnarf(xsnarfcon, buf);
1625
	return 0;
1626
}
1627