Commit Diff


commit - 986b36bccd134726eea42f2cfabff2943d729ac4
commit + 16a709666981e77a00a88a87b286b586ac77ffdc
blob - a9ae96af920015cf6707dea61ee564803d850c7c
blob + 029f0aed6ed69f418900d5495e8e99cd31f6f57e
--- include/draw.h
+++ include/draw.h
@@ -219,7 +219,7 @@ struct RGB
  *
  * given char c, Subfont *f, Fontchar *i, and Point p, one says
  *	i = f->info+c;
- *	draw(b, Rect(p.x+i->left, p.y+i->top,
+ *	void(b, Rect(p.x+i->left, p.y+i->top,
  *		p.x+i->left+((i+1)->x-i->x), p.y+i->bottom),
  *		color, f->bits, Pt(i->x, i->top));
  *	p.x += i->width;
@@ -336,6 +336,7 @@ extern int	writeimage(int, Image*, int);
 extern Image*	namedimage(Display*, char*);
 extern int	nameimage(Image*, char*, int);
 extern Image* allocimagemix(Display*, u32int, u32int);
+extern int	drawsetlabel(Display*, char*);
 
 /*
  * Colors
@@ -529,3 +530,4 @@ void drawtopwindow(void);
  */
 int	_drawmsgread(Display*, void*, int);
 int	_drawmsgwrite(Display*, void*, int);
+int	_latin1(Rune*, int);
blob - 8e932ee3f6458f57c5c03b515708da8df8d494ee (mode 644)
blob + /dev/null
--- src/libdraw/Makefile
+++ /dev/null
@@ -1,123 +0,0 @@
-PLAN9=../..
-include $(PLAN9)/src/Makehdr
-
-LIB=libdraw.a
-
-OFILES=\
-	alloc.$O\
-	allocimagemix.$O\
-	arith.$O\
-	bezier.$O\
-	border.$O\
-	buildfont.$O\
-	bytesperline.$O\
-	chan.$O\
-	cloadimage.$O\
-	computil.$O\
-	creadimage.$O\
-	debug.$O\
-	defont.$O\
-	draw.$O\
-	drawrepl.$O\
-	egetrect.$O\
-	ellipse.$O\
-	emenuhit.$O\
-	font.$O\
-	freesubfont.$O\
-	getdefont.$O\
-	getrect.$O\
-	getsubfont.$O\
-	icossin.$O\
-	icossin2.$O\
-	init.$O\
-	line.$O\
-	loadimage.$O\
-	menuhit.$O\
-	mkfont.$O\
-	openfont.$O\
-	poly.$O\
-	readcolmap.$O\
-	readimage.$O\
-	readsubfont.$O\
-	rectclip.$O\
-	replclipr.$O\
-	rgb.$O\
-	string.$O\
-	stringbg.$O\
-	stringsubfont.$O\
-	stringwidth.$O\
-	subfont.$O\
-	subfontcache.$O\
-	subfontname.$O\
-	unloadimage.$O\
-	window.$O\
-	writecolmap.$O\
-	writeimage.$O\
-	writesubfont.$O\
-	md-alloc.$O\
-	md-arc.$O\
-	md-cload.$O\
-	md-cmap.$O\
-	md-cread.$O\
-	md-defont.$O\
-	md-draw.$O\
-	md-ellipse.$O\
-	md-fillpoly.$O\
-	md-hwdraw.$O\
-	md-iprint.$O\
-	md-line.$O\
-	md-load.$O\
-	md-openmemsubfont.$O\
-	md-poly.$O\
-	md-read.$O\
-	md-string.$O\
-	md-subfont.$O\
-	md-unload.$O\
-	md-write.$O\
-	ml-draw.$O\
-	ml-lalloc.$O\
-	ml-layerop.$O\
-	ml-ldelete.$O\
-	ml-lhide.$O\
-	ml-line.$O\
-	ml-load.$O\
-	ml-lorigin.$O\
-	ml-lsetrefresh.$O\
-	ml-ltofront.$O\
-	ml-ltorear.$O\
-	ml-unload.$O\
-	x11-alloc.$O\
-	x11-cload.$O\
-	x11-draw.$O\
-	x11-event.$O\
-	x11-fill.$O\
-	x11-get.$O\
-	x11-init.$O\
-	x11-itrans.$O\
-	x11-keyboard.$O\
-	x11-load.$O\
-	x11-mouse.$O\
-	x11-pixelbits.$O\
-	x11-unload.$O\
-	x11-wsys.$O\
-	devdraw.$O\
-	unix.$O\
-
-HFILES=\
-	$(PLAN9)/include/draw.h\
-	$(PLAN9)/include/memdraw.h\
-	$(PLAN9)/include/memlayer.h\
-	$(PLAN9)/include/event.h\
-	$(PLAN9)/include/cursor.h\
-	$(PLAN9)/include/mouse.h\
-	$(PLAN9)/include/keyboard.h\
-	x11-inc.h\
-	x11-memdraw.h\
-
-CFLAGS+=-I$(X11)/include
-
-include $(PLAN9)/src/Makesyslib
-
-test: test.o $(LIB)
-	gcc -o test test.o -L$(PLAN9) -ldraw -l9 -lfmt -lutf -L$(X11)/lib -lX11 -lm
-
blob - /dev/null
blob + f57345675373cb5b26182c8ef0601e145baded60 (mode 644)
--- /dev/null
+++ src/libdraw/latin1.c
@@ -0,0 +1,178 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+/*
+ * The code makes two assumptions: strlen(ld) is 1 or 2; latintab[i].ld can be a
+ * prefix of latintab[j].ld only when j<i.
+ */
+static struct cvlist
+{
+	char	*ld;		/* must be seen before using this conversion */
+	char	*si;		/* options for last input characters */
+	Rune	so[50];		/* the corresponding Rune for each si entry */
+} latintab[] = {
+	" ", " i",	{ 0x2423, 0x0131 },
+	"w", "kqrbnp", { 0x2654, 0x2655, 0x2656, 0x2657, 0x2658, 0x2659, },
+	"x", "O", { 0x2297, },
+	"f", "a", { 0x2200, },
+	"=", "V:=O<>", { 0x21D2, 0x2255, 0x2261, 0x229C, 0x22DC, 0x22DD, },
+	"V", "=", { 0x21D0, },
+	"7", "8", { 0x215E, },
+	"5", "68", { 0x215A, 0x215D, },
+	"4", "5", { 0x2158, },
+	"R", "R", { 0x211D, },
+	"Q", "Q", { 0x211A, },
+	"P", "P", { 0x2119, },
+	"C", "CAU", { 0x2102, 0x22C2, 0x22C3, },
+	"e", "nmsl", { 0x2013, 0x2014, 0x2205, 0x22EF, },
+	"b", "u0123456789+-=()kqrbnp", { 0x2022, 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x265A, 0x265B, 0x265C, 0x265D, 0x265E, 0x265F, },
+	"@e", "h", { 0x44D, },
+	"@\'", "\'", { 0x44A, },
+	"@s", "hc", { 0x448, 0x449, },
+	"@c", "h", { 0x447, },
+	"@t", "s", { 0x446, },
+	"@k", "h", { 0x445, },
+	"@z", "h", { 0x436, },
+	"@y", "euao", { 0x435, 0x44E, 0x44F, 0x451, },
+	"@E", "Hh", { 0x42D, 0x42D, },
+	"@S", "HhCc", { 0x428, 0x428, 0x429, 0x429, },
+	"@C", "Hh", { 0x427, 0x427, },
+	"@T", "Ss", { 0x426, 0x426, },
+	"@K", "Hh", { 0x425, 0x425, },
+	"@Z", "Hh", { 0x416, 0x416, },
+	"@@", "EZKSTYezksty\'", { 0x415, 0x417, 0x41A, 0x421, 0x422, 0x42B, 0x435, 0x437, 0x43A, 0x441, 0x442, 0x44B, 0x44C, },
+	"@Y", "OoEeUuAa", { 0x401, 0x401, 0x415, 0x415, 0x42E, 0x42E, 0x42F, 0x42F, },
+	"@", "ABVGDIJLMNOPRUFXabvgdijlmnoprufx", { 0x410, 0x411, 0x412, 0x413, 0x414, 0x418, 0x419, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F, 0x420, 0x423, 0x424, 0x425, 0x430, 0x431, 0x432, 0x433, 0x434, 0x438, 0x439, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F, 0x440, 0x443, 0x444, 0x445, },
+	"*", "ABGDEZYHIKLMNCOPRSTUFXQWabgdezyhiklmncoprstufxqw*", { 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39A, 0x39B, 0x39C, 0x39D, 0x39E, 0x39F, 0x3A0, 0x3A1, 0x3A3, 0x3A4, 0x3A5, 0x3A6, 0x3A7, 0x3A8, 0x3A9, 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7, 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, 0x3BF, 0x3C0, 0x3C1, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9, 0x2217, },
+	"G", "-", { 0x1E4, },
+	"N", "JjN", { 0x1CA, 0x1CB, 0x2115, },
+	"2", "-35", { 0x1BB, 0x2154, 0x2156, },
+	"z", "-", { 0x1B6, },
+	"Z", "-Z", { 0x1B5, 0x2124, },
+	"Y", "R", { 0x1A6, },
+	"h", "v-", { 0x195, 0x210F, },
+	"$*", "hfk", { 0x3D1, 0x3D5, 0x3F0, },
+	"$", "fVavgHILlpRBeEFMo", { 0x192, 0x1B2, 0x251, 0x28B, 0x210A, 0x210B, 0x2110, 0x2112, 0x2113, 0x2118, 0x211B, 0x212C, 0x212F, 0x2130, 0x2131, 0x2133, 0x2134, },
+	"t", "-smefu", { 0x167, 0x3C2, 0x2122, 0x2203, 0x2234, 0x22A2, },
+	"T", "-u", { 0x166, 0x22A8, },
+	"L", "-Jj&|", { 0x141, 0x1C7, 0x1C8, 0x22C0, 0x22C1, },
+	"i", "j-fsbp", { 0x133, 0x268, 0x221E, 0x222B, 0x2286, 0x2287, },
+	"I", "J-", { 0x132, 0x197, },
+	"H", "-H", { 0x126, 0x210D, },
+	"v\"", "Uu", { 0x1D9, 0x1DA, },
+	"v", "CcDdEeLlNnRrSsTtZzAaIiOoUuGgKkj", { 0x10C, 0x10D, 0x10E, 0x10F, 0x11A, 0x11B, 0x13D, 0x13E, 0x147, 0x148, 0x158, 0x159, 0x160, 0x161, 0x164, 0x165, 0x17D, 0x17E, 0x1CD, 0x1CE, 0x1CF, 0x1D0, 0x1D1, 0x1D2, 0x1D3, 0x1D4, 0x1E6, 0x1E7, 0x1E8, 0x1E9, 0x1F0, },
+	"u", "AEeGgIiOoUu-a", { 0x102, 0x114, 0x115, 0x11E, 0x11F, 0x12C, 0x12D, 0x14E, 0x14F, 0x16C, 0x16D, 0x289, 0x2191, },
+	":", "-=)", { 0xF7, 0x2254, 0x263A, },
+	"a", "ebn", { 0xE6, 0x2194, 0x2220, },
+	"/", "Oo", { 0xD8, 0xF8, },
+	"Dv", "Zz", { 0x1C4, 0x1C5, },
+	"D", "-e", { 0xD0, 0x2206, },
+	"A", "E", { 0xC6, },
+	"o", "AaeUuiO", { 0xC5, 0xE5, 0x153, 0x16E, 0x16F, 0x1A3, 0x229A, },
+	"~!", "=", { 0x2246, },
+	"~", "ANOanoIiUu-=~", { 0xC3, 0xD1, 0xD5, 0xE3, 0xF1, 0xF5, 0x128, 0x129, 0x168, 0x169, 0x2243, 0x2245, 0x2248, },
+	"^", "AEIOUaeiouCcGgHhJjSsWwYy", { 0xC2, 0xCA, 0xCE, 0xD4, 0xDB, 0xE2, 0xEA, 0xEE, 0xF4, 0xFB, 0x108, 0x109, 0x11C, 0x11D, 0x124, 0x125, 0x134, 0x135, 0x15C, 0x15D, 0x174, 0x175, 0x176, 0x177, },
+	"`\"", "Uu", { 0x1DB, 0x1DC, },
+	"`", "AEIOUaeiou", { 0xC0, 0xC8, 0xCC, 0xD2, 0xD9, 0xE0, 0xE8, 0xEC, 0xF2, 0xF9, },
+	"?", "?!", { 0xBF, 0x203D, },
+	"3", "458", { 0xBE, 0x2157, 0x215C, },
+	"1", "423568", { 0xBC, 0xBD, 0x2153, 0x2155, 0x2159, 0x215B, },
+	">!", "=~", { 0x2269, 0x22E7, },
+	">", ">=~<", { 0xBB, 0x2265, 0x2273, 0x2277, },
+	",", ",CcAaEeGgIiKkLlNnRrSsTtUuOo", { 0xB8, 0xC7, 0xE7, 0x104, 0x105, 0x118, 0x119, 0x122, 0x123, 0x12E, 0x12F, 0x136, 0x137, 0x13B, 0x13C, 0x145, 0x146, 0x156, 0x157, 0x15E, 0x15F, 0x162, 0x163, 0x172, 0x173, 0x1EA, 0x1EB, },
+	".", ".CcEeGgILlZzO", { 0xB7, 0x10A, 0x10B, 0x116, 0x117, 0x120, 0x121, 0x130, 0x13F, 0x140, 0x17B, 0x17C, 0x2299, },
+	"p", "gOdrt", { 0xB6, 0x2117, 0x2202, 0x220F, 0x221D, },
+	"m", "iuo", { 0xB5, 0xD7, 0x2208, },
+	"\'\"", "Uu", { 0x1D7, 0x1D8, },
+	"\'", "\'AEIOUYaeiouyCcgLlNnRrSsZz", { 0xB4, 0xC1, 0xC9, 0xCD, 0xD3, 0xDA, 0xDD, 0xE1, 0xE9, 0xED, 0xF3, 0xFA, 0xFD, 0x106, 0x107, 0x123, 0x139, 0x13A, 0x143, 0x144, 0x154, 0x155, 0x15A, 0x15B, 0x179, 0x17A, },
+	"+", "-O", { 0xB1, 0x2295, },
+	"dv", "z", { 0x1C6, },
+	"d", "e-zgda", { 0xB0, 0xF0, 0x2A3, 0x2020, 0x2021, 0x2193, },
+	"_,", "Oo", { 0x1EC, 0x1ED, },
+	"_.", "Aa", { 0x1E0, 0x1E1, },
+	"_\"", "UuAa", { 0x1D5, 0x1D6, 0x1DE, 0x1DF, },
+	"_", "_AaEeIiOoUu", { 0xAF, 0x100, 0x101, 0x112, 0x113, 0x12A, 0x12B, 0x14C, 0x14D, 0x16A, 0x16B, },
+	"r", "O\'\"", { 0xAE, 0x2019, 0x201D, },
+	"-*", "l", { 0x19B, },
+	"-", "-Dd:HLlTtbIZz2Ggiuh>+~O", { 0xAD, 0xD0, 0xF0, 0xF7, 0x126, 0x141, 0x142, 0x166, 0x167, 0x180, 0x197, 0x1B5, 0x1B6, 0x1BB, 0x1E4, 0x1E5, 0x268, 0x289, 0x210F, 0x2192, 0x2213, 0x2242, 0x2296, },
+	"n", "oj", { 0xAC, 0x1CC, },
+	"<!", "=~", { 0x2268, 0x22E6, },
+	"<", "<-=~>", { 0xAB, 0x2190, 0x2264, 0x2272, 0x2276, },
+	"s", "a231os0456789+-=()nturbp", { 0xAA, 0xB2, 0xB3, 0xB9, 0xBA, 0xDF, 0x2070, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F, 0x220D, 0x2211, 0x221A, 0x2282, 0x2283, },
+	"O", "crEIp+-x/.o*=", { 0xA9, 0xAE, 0x152, 0x1A2, 0x2117, 0x2295, 0x2296, 0x2297, 0x2298, 0x2299, 0x229A, 0x229B, 0x229C, },
+	"\"*", "IUiu", { 0x3AA, 0x3AB, 0x3CA, 0x3CB, },
+	"\"", "\"AEIOUaeiouyY", { 0xA8, 0xC4, 0xCB, 0xCF, 0xD6, 0xDC, 0xE4, 0xEB, 0xEF, 0xF6, 0xFC, 0xFF, 0x178, },
+	"S", "S", { 0xA7, },
+	"|", "|Pp", { 0xA6, 0xDE, 0xFE, },
+	"y", "$", { 0xA5, },
+	"g", "$-r", { 0xA4, 0x1E5, 0x2207, },
+	"l", "$-j\'\"&|z", { 0xA3, 0x142, 0x1C9, 0x2018, 0x201C, 0x2227, 0x2228, 0x22C4, },
+	"c", "$Oaug", { 0xA2, 0xA9, 0x2229, 0x222A, 0x2245, },
+	"!~", "-=~", { 0x2244, 0x2247, 0x2249, },
+	"!", "!?m=<>bp", { 0xA1, 0x203D, 0x2209, 0x2260, 0x226E, 0x226F, 0x2284, 0x2285, },
+	0, 0, { 0, }
+};
+
+/*
+ * Given 5 characters k[0]..k[4], find the rune or return -1 for failure.
+ */
+static long
+unicode(Rune *k)
+{
+	long i, c;
+
+	k++;	/* skip 'X' */
+	c = 0;
+	for(i=0; i<4; i++,k++){
+		c <<= 4;
+		if('0'<=*k && *k<='9')
+			c += *k-'0';
+		else if('a'<=*k && *k<='f')
+			c += 10 + *k-'a';
+		else if('A'<=*k && *k<='F')
+			c += 10 + *k-'A';
+		else
+			return -1;
+	}
+	return c;
+}
+
+/*
+ * Given n characters k[0]..k[n-1], find the corresponding rune or return -1 for
+ * failure, or something < -1 if n is too small.  In the latter case, the result
+ * is minus the required n.
+ */
+int
+_latin1(Rune *k, int n)
+{
+	struct cvlist *l;
+	int c;
+	char* p;
+
+	if(k[0] == 'X'){
+		if(n>=5)
+			return unicode(k);
+		else
+			return -5;
+	}
+	
+	for(l=latintab; l->ld!=0; l++)
+		if(k[0] == l->ld[0]){
+			if(n == 1)
+				return -2;
+			if(l->ld[1] == 0)
+				c = k[1];
+			else if(l->ld[1] != k[1])
+				continue;
+			else if(n == 2)
+				return -3;
+			else
+				c = k[2];
+			for(p=l->si; *p!=0; p++)
+				if(*p == c)
+					return l->so[p - l->si];
+			return -1;
+		}
+	return -1;
+}
blob - /dev/null
blob + 7c5e9371f6af4723e673e3ee935c02bc0deeb733 (mode 644)
--- /dev/null
+++ src/libdraw/mkfile
@@ -0,0 +1,124 @@
+PLAN9=../..
+<$PLAN9/src/mkhdr
+
+LIB=libdraw.a
+
+OFILES=\
+	alloc.$O\
+	allocimagemix.$O\
+	arith.$O\
+	bezier.$O\
+	border.$O\
+	buildfont.$O\
+	bytesperline.$O\
+	chan.$O\
+	cloadimage.$O\
+	computil.$O\
+	creadimage.$O\
+	debug.$O\
+	defont.$O\
+	draw.$O\
+	drawrepl.$O\
+	egetrect.$O\
+	ellipse.$O\
+	emenuhit.$O\
+	font.$O\
+	freesubfont.$O\
+	getdefont.$O\
+	getrect.$O\
+	getsubfont.$O\
+	icossin.$O\
+	icossin2.$O\
+	init.$O\
+	line.$O\
+	latin1.$O\
+	loadimage.$O\
+	menuhit.$O\
+	mkfont.$O\
+	openfont.$O\
+	poly.$O\
+	readcolmap.$O\
+	readimage.$O\
+	readsubfont.$O\
+	rectclip.$O\
+	replclipr.$O\
+	rgb.$O\
+	string.$O\
+	stringbg.$O\
+	stringsubfont.$O\
+	stringwidth.$O\
+	subfont.$O\
+	subfontcache.$O\
+	subfontname.$O\
+	unloadimage.$O\
+	window.$O\
+	writecolmap.$O\
+	writeimage.$O\
+	writesubfont.$O\
+	md-alloc.$O\
+	md-arc.$O\
+	md-cload.$O\
+	md-cmap.$O\
+	md-cread.$O\
+	md-defont.$O\
+	md-draw.$O\
+	md-ellipse.$O\
+	md-fillpoly.$O\
+	md-hwdraw.$O\
+	md-iprint.$O\
+	md-line.$O\
+	md-load.$O\
+	md-openmemsubfont.$O\
+	md-poly.$O\
+	md-read.$O\
+	md-string.$O\
+	md-subfont.$O\
+	md-unload.$O\
+	md-write.$O\
+	ml-draw.$O\
+	ml-lalloc.$O\
+	ml-layerop.$O\
+	ml-ldelete.$O\
+	ml-lhide.$O\
+	ml-line.$O\
+	ml-load.$O\
+	ml-lorigin.$O\
+	ml-lsetrefresh.$O\
+	ml-ltofront.$O\
+	ml-ltorear.$O\
+	ml-unload.$O\
+	x11-alloc.$O\
+	x11-cload.$O\
+	x11-draw.$O\
+	x11-event.$O\
+	x11-fill.$O\
+	x11-get.$O\
+	x11-init.$O\
+	x11-itrans.$O\
+	x11-keyboard.$O\
+	x11-load.$O\
+	x11-mouse.$O\
+	x11-pixelbits.$O\
+	x11-unload.$O\
+	x11-wsys.$O\
+	devdraw.$O\
+	unix.$O\
+
+HFILES=\
+	$PLAN9/include/draw.h\
+	$PLAN9/include/memdraw.h\
+	$PLAN9/include/memlayer.h\
+	$PLAN9/include/event.h\
+	$PLAN9/include/cursor.h\
+	$PLAN9/include/mouse.h\
+	$PLAN9/include/keyboard.h\
+	x11-inc.h\
+	x11-memdraw.h\
+
+CFLAGS=$CFLAGS -I$X11/include
+
+<$PLAN9/src/mksyslib
+
+test: test.o $LIB
+	gcc -o test test.o -L$PLAN9 -ldraw -l9 -lfmt -lutf -L$X11/lib -lX11 -lm
+
blob - 1361b42e285ef00cdbd0e28a62b1588e70616511
blob + 408eb4191aba4f1c8d5f257e4bb49d95b407eab6
--- src/libdraw/x11-event.c
+++ src/libdraw/x11-event.c
@@ -36,6 +36,7 @@ eflush(void)
 ulong
 eread(ulong keys, Event *e)
 {
+	int r;
 	ulong xmask;
 	XEvent xevent;
 
@@ -45,8 +46,13 @@ eread(ulong keys, Event *e)
 
 	if(keys&Emouse)
 		xmask |= MouseMask|StructureNotifyMask;
-	if(keys&Ekeyboard)
+	if(keys&Ekeyboard){
 		xmask |= KeyPressMask;
+		if((r = xtoplan9kbd(nil)) >= 0){
+			e->kbdc = r;
+			return Ekeyboard;
+		}
+	}
 
 	XSelectInput(_x.display, _x.drawable, xmask);
 again:
@@ -56,6 +62,10 @@ again:
 	case Expose:
 		xexpose(&xevent, _x.display);
 		goto again;
+	case DestroyNotify:
+		if(xdestroy(&xevent, _x.display))
+			postnote(PNGROUP, getpgrp(), "hangup");
+		goto again;
 	case ConfigureNotify:
 		if(xconfigure(&xevent, _x.display))
 			eresized(1);
@@ -63,7 +73,7 @@ again:
 	case ButtonPress:
 	case ButtonRelease:
 	case MotionNotify:
-		if(xtoplan9mouse(&xevent, &e->mouse) < 0)
+		if(xtoplan9mouse(_x.display, &xevent, &e->mouse) < 0)
 			goto again;
 		return Emouse;
 	case KeyPress:
@@ -126,7 +136,7 @@ ecanmouse(void)
 	eflush();
 again:
 	if(XCheckWindowEvent(_x.display, _x.drawable, MouseMask, &xe)){
-		if(xtoplan9mouse(&xe, &m) < 0)
+		if(xtoplan9mouse(_x.display, &xe, &m) < 0)
 			goto again;
 		XPutBackEvent(_x.display, &xe);
 		return 1;
@@ -138,8 +148,13 @@ int
 ecankbd(void)
 {
 	XEvent xe;
+	int r;
 
 	eflush();
+	if((r = xtoplan9kbd(nil)) >= 0){
+		xtoplan9kbd((XEvent*)-1);
+		return 1;
+	}
 again:
 	if(XCheckWindowEvent(_x.display, _x.drawable, KeyPressMask, &xe)){
 		if(xtoplan9kbd(&xe) == -1)
blob - 28f6ae4009c89b8dcb73e4f4991a313c6ba6f4f7
blob + e402dee28d0b8ae9ee607fd255b692ed00698c56
--- src/libdraw/x11-init.c
+++ src/libdraw/x11-init.c
@@ -100,6 +100,8 @@ getwindow(Display *d, int ref)
 {
 	Image *i;
 
+	if(_x.destroyed)
+		postnote(PNGROUP, getpgrp(), "hangup");
 	if(xreplacescreenimage() == 0)
 		return 0;
 	freeimage(d->screenimage);
@@ -124,7 +126,7 @@ static int
 xioerror(XDisplay *d)
 {
 	print("X I/O error\n");
-	exit(1);
+	abort();
 	return -1;
 }
 
@@ -365,6 +367,11 @@ xattach(char *label)
 	XFlush(_x.display);
 
 	/*
+	 * Look up clipboard atom.
+	 */
+	_x.clipboard = XInternAtom(_x.display, "CLIPBOARD", True);
+
+	/*
 	 * Lots of display connections for various procs.
 	 */
 	_x.kbdcon	= XOpenDisplay(NULL);
@@ -386,6 +393,46 @@ fprint(2, "%r\n");
 	 */
 	XCloseDisplay(_x.display);
 	return nil;
+}
+
+int
+drawsetlabel(Display *d, char *label)
+{
+	char *argv[2];
+	XClassHint classhint;
+	XTextProperty name;
+
+	/*
+	 * Label and other properties required by ICCCCM.
+	 */
+	memset(&name, 0, sizeof name);
+	if(label == nil)
+		label = "pjw-face-here";
+	name.value = (uchar*)label;
+	name.encoding = XA_STRING;
+	name.format = 8;
+	name.nitems = strlen(name.value);
+
+	memset(&classhint, 0, sizeof classhint);
+	classhint.res_name = label;
+	classhint.res_class = label;
+
+	argv[0] = label;
+	argv[1] = nil;
+
+	XSetWMProperties(
+		_x.display,	/* display */
+		_x.drawable,	/* window */
+		&name,		/* XA_WM_NAME property */
+		&name,		/* XA_WM_ICON_NAME property */
+		argv,		/* XA_WM_COMMAND */
+		1,		/* argc */
+		nil,		/* XA_WM_NORMAL_HINTS */
+		nil,		/* XA_WM_HINTS */
+		&classhint	/* XA_WM_CLASSHINTS */
+	);
+	XFlush(_x.display);
+	return 0;
 }
 
 /*
@@ -601,6 +648,19 @@ xexpose(XEvent *e, XDisplay *xd)
 		Dx(r), Dy(r), r.min.x, r.min.y);
 	XSync(xd, False);
 	qunlock(&_x.screenlock);
+}
+
+int
+xdestroy(XEvent *e, XDisplay *xd)
+{
+	XDestroyWindowEvent *xe;
+
+	xe = (XDestroyWindowEvent*)e;
+	if(xe->window == _x.drawable){
+		_x.destroyed = 1;
+		return 1;
+	}
+	return 0;
 }
 
 int
blob - 35fd31ea2a07675971e1e83da45b975e003357f6
blob + b4d9e6899a00ab0d7298d53d4e2589c9143ce72d
--- src/libdraw/x11-itrans.c
+++ src/libdraw/x11-itrans.c
@@ -11,8 +11,8 @@
 #include <keyboard.h>
 #include "x11-memdraw.h"
 
-int
-xtoplan9kbd(XEvent *e)
+static int
+_xtoplan9kbd(XEvent *e)
 {
 	int ind, k, md;
 
@@ -117,16 +117,82 @@ xtoplan9kbd(XEvent *e)
 	return k;
 }
 
+static Rune*
+xtoplan9latin1(XEvent *e)
+{
+	static Rune k[10];
+	static int alting, nk;
+	int n;
+	int r;
+
+	r = _xtoplan9kbd(e);
+	if(r < 0)
+		return nil;
+	if(alting){
+		k[nk++] = r;
+		n = _latin1(k, nk);
+		if(n > 0){
+			alting = 0;
+			k[0] = n;
+			k[1] = 0;
+			return k;
+		}
+		if(n == -1){
+			alting = 0;
+			k[nk] = 0;
+			return k;
+		}
+		/* n < -1, need more input */
+		return nil;
+	}else if(r == Kalt){
+		alting = 1;
+		nk = 0;
+		return nil;
+	}else{
+		k[0] = r;
+		k[1] = 0;
+		return k;
+	}
+}
+
 int
-xtoplan9mouse(XEvent *e, Mouse *m)
+xtoplan9kbd(XEvent *e)
 {
+	static Rune *r;
+
+	if(e == (XEvent*)-1){
+		assert(r);
+		r--;
+		return 0;
+	}
+	if(e)
+		r = xtoplan9latin1(e);
+	if(r && *r)
+		return *r++;
+	return -1;
+}
+
+int
+xtoplan9mouse(XDisplay *xd, XEvent *e, Mouse *m)
+{
 	int s;
 	XButtonEvent *be;
 	XMotionEvent *me;
+
+	if(_x.putsnarf != _x.assertsnarf){
+		_x.assertsnarf = _x.putsnarf;
+		XSetSelectionOwner(_x.mousecon, XA_PRIMARY, _x.drawable, CurrentTime);
+		if(_x.clipboard != None)
+			XSetSelectionOwner(_x.mousecon, _x.clipboard, _x.drawable, CurrentTime);
+		XFlush(xd);
+	}
 
 	switch(e->type){
 	case ButtonPress:
 		be = (XButtonEvent*)e;
+		/* Fake message, just sent to make us announce snarf. */
+		if(be->send_event && be->state==~0 && be->button==~0)
+			return -1;
 		/* BUG? on mac need to inherit these from elsewhere? */
 		m->xy.x = be->x;
 		m->xy.y = be->y;
@@ -265,34 +331,55 @@ char*
 xgetsnarf(XDisplay *xd)
 {
 	uchar *data, *xdata;
-	Atom type;
+	Atom clipboard, type, prop;
 	ulong len, lastlen, dummy;
 	int fmt, i;
 	XWindow w;
 
 	qlock(&clip.lk);
+	/*
+	 * Is there a primary selection (highlighted text in an xterm)?
+	 */
+	clipboard = XA_PRIMARY;
 	w = XGetSelectionOwner(xd, XA_PRIMARY);
 	if(w == _x.drawable){
+	mine:
 		data = (uchar*)strdup(clip.buf);
 		goto out;
 	}
+
+	/*
+	 * If not, is there a clipboard selection?
+	 */
+	if(w == None && _x.clipboard != None){
+		clipboard = _x.clipboard;
+		w = XGetSelectionOwner(xd, _x.clipboard);
+		if(w == _x.drawable)
+			goto mine;
+	}
+
+	/*
+	 * If not, give up.
+	 */
 	if(w == None){
 		data = nil;
 		goto out;
 	}
+		
 	/*
 	 * We should be waiting for SelectionNotify here, but it might never
-	 * come, and we have no way to time out.  Instead, we will zero the 
-	 * property, request our buddy to fill it in for us, and wait until
-	 * he's done.
+	 * come, and we have no way to time out.  Instead, we will clear
+	 * local property #1, request our buddy to fill it in for us, and poll
+	 * until he's done or we get tired of waiting.
 	 */
-	XChangeProperty(xd, _x.drawable, XA_PRIMARY, XA_STRING, 8, PropModeReplace, (uchar*)"", 0);
-	XConvertSelection(xd, XA_PRIMARY, XA_STRING, None, _x.drawable, CurrentTime);
+	prop = 1;
+	XChangeProperty(xd, _x.drawable, prop, XA_STRING, 8, PropModeReplace, (uchar*)"", 0);
+	XConvertSelection(xd, clipboard, XA_STRING, prop, _x.drawable, CurrentTime);
 	XFlush(xd);
 	lastlen = 0;
-	for(i=0; i<30; i++){
+	for(i=0; i<10 || (lastlen!=0 && i<30); i++){
 		usleep(100*1000);
-		XGetWindowProperty(xd, _x.drawable, XA_STRING, 0, 0, 0, AnyPropertyType,
+		XGetWindowProperty(xd, _x.drawable, prop, 0, 0, 0, AnyPropertyType,
 			&type, &fmt, &dummy, &len, &data);
 		if(lastlen == len && len > 0)
 			break;
@@ -304,7 +391,7 @@ xgetsnarf(XDisplay *xd)
 	}
 	/* get the property */
 	data = nil;
-	XGetWindowProperty(xd, _x.drawable, XA_STRING, 0, SnarfSize/4, 0, 
+	XGetWindowProperty(xd, _x.drawable, prop, 0, SnarfSize/sizeof(ulong), 0, 
 		AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
 	if(type != XA_STRING || len == 0){
 		if(xdata)
@@ -325,16 +412,25 @@ out:
 void
 xputsnarf(XDisplay *xd, char *data)
 {
+	XButtonEvent e;
+
 	if(strlen(data) >= SnarfSize)
 		return;
 	qlock(&clip.lk);
 	strcpy(clip.buf, data);
-	/*
-	 * BUG: This is wrong.  Instead, we should send an event to the
-	 * mouse connection telling it to call XSetSelectionOwner.
-	 */
-	XSetSelectionOwner(_x.mousecon, XA_PRIMARY, _x.drawable, CurrentTime);
+
+	/* leave note for mouse proc to assert selection ownership */
+	_x.putsnarf++;
+
+	/* send mouse a fake event so snarf is announced */
+	memset(&e, 0, sizeof e);
+	e.type = ButtonPress;
+	e.window = _x.drawable;
+	e.state = ~0;
+	e.button = ~0;
+	XSendEvent(xd, _x.drawable, True, ButtonPressMask, (XEvent*)&e);
 	XFlush(xd);
+
 	qunlock(&clip.lk);
 }
 
blob - 92b57814c987dd9e49e76ce9a33b158f1cf87ba7
blob + 443074e994b4c4c3aa1bda37854f6465bd26d297
--- src/libdraw/x11-keyboard.c
+++ src/libdraw/x11-keyboard.c
@@ -51,6 +51,10 @@ _ioproc(void *arg)
 				continue;
 			r = i;
 			send(kc->c, &r);
+			while((i=xtoplan9kbd(nil)) >= 0){
+				r = i;
+				send(kc->c, &r);
+			}
 			break;
 		}
 	}
blob - 514926da652cc0da5517f6032477c6b8b80e78d1
blob + 1b1012be7a2b42e472ac4c31388363c37f2c09ec
--- src/libdraw/x11-memdraw.h
+++ src/libdraw/x11-memdraw.h
@@ -64,6 +64,10 @@ struct Xprivate {
 	int		usetable;
 	XVisual		*vis;
 	u32int		white;
+	Atom		clipboard;
+	uint		putsnarf;
+	uint		assertsnarf;
+	int		destroyed;
 };
 
 extern Xprivate _x;
@@ -78,11 +82,12 @@ extern void	xputxdata(Memimage*, Rectangle);
 extern void	_initdisplaymemimage(Display*, Memimage*);
 
 struct Mouse;
-extern int	xtoplan9mouse(XEvent*, struct Mouse*);
+extern int	xtoplan9mouse(XDisplay*, XEvent*, struct Mouse*);
 extern int	xtoplan9kbd(XEvent*);
 extern void	xexpose(XEvent*, XDisplay*);
 extern int	xselect(XEvent*, XDisplay*);
 extern int	xconfigure(XEvent*, XDisplay*);
+extern int	xdestroy(XEvent*, XDisplay*);
 extern void	flushmemscreen(Rectangle);
 extern void	xmoveto(Point);
 struct Cursor;
blob - 6b5b3922af805dd27d62e48c3fbc6a513fdc2b48
blob + eae26788d834cb330f0def04e26418fbd7a0afb1
--- src/libdraw/x11-mouse.c
+++ src/libdraw/x11-mouse.c
@@ -66,6 +66,16 @@ _ioproc(void *arg)
 		case Expose:
 			xexpose(&xevent, _x.mousecon);
 			continue;
+		case DestroyNotify:
+			if(xdestroy(&xevent, _x.mousecon)){
+				/* drain it before sending */
+				/* apps that care can notice we sent a 0 */
+				/* otherwise we'll have getwindow send SIGHUP */
+				nbrecv(mc->resizec, 0);
+				nbrecv(mc->resizec, 0);
+				send(mc->resizec, 0);
+			}
+			continue;
 		case ConfigureNotify:
 			if(xconfigure(&xevent, _x.mousecon))
 				nbsend(mc->resizec, &one);
@@ -76,7 +86,7 @@ _ioproc(void *arg)
 		case ButtonPress:
 		case ButtonRelease:
 		case MotionNotify:
-			if(xtoplan9mouse(&xevent, &m) < 0)
+			if(xtoplan9mouse(_x.mousecon, &xevent, &m) < 0)
 				continue;
 			send(mc->c, &m);
 			/*