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