URI: 
       tAdd drawsetlabel(Display*, char*). Turn window destruction into "hangup" note. Fix (?) snarf buffer management. Add latin1 keyboard translation. - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 16a709666981e77a00a88a87b286b586ac77ffdc
   DIR parent 986b36bccd134726eea42f2cfabff2943d729ac4
  HTML Author: rsc <devnull@localhost>
       Date:   Sun, 23 Nov 2003 18:15:43 +0000
       
       Add drawsetlabel(Display*, char*).
       Turn window destruction into "hangup" note.
       Fix (?) snarf buffer management.
       Add latin1 keyboard translation.
       
       Diffstat:
         M include/draw.h                      |       4 +++-
         D src/libdraw/Makefile                |     123 -------------------------------
         A src/libdraw/latin1.c                |     178 +++++++++++++++++++++++++++++++
         A src/libdraw/mkfile                  |     124 +++++++++++++++++++++++++++++++
         M src/libdraw/x11-event.c             |      21 ++++++++++++++++++---
         M src/libdraw/x11-init.c              |      62 ++++++++++++++++++++++++++++++-
         M src/libdraw/x11-itrans.c            |     130 +++++++++++++++++++++++++++----
         M src/libdraw/x11-keyboard.c          |       4 ++++
         M src/libdraw/x11-memdraw.h           |       7 ++++++-
         M src/libdraw/x11-mouse.c             |      12 +++++++++++-
       
       10 files changed, 518 insertions(+), 147 deletions(-)
       ---
   DIR diff --git a/include/draw.h b/include/draw.h
       t@@ -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;
       t@@ -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
       t@@ -529,3 +530,4 @@ void drawtopwindow(void);
         */
        int        _drawmsgread(Display*, void*, int);
        int        _drawmsgwrite(Display*, void*, int);
       +int        _latin1(Rune*, int);
   DIR diff --git a/src/libdraw/Makefile b/src/libdraw/Makefile
       t@@ -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
       -
   DIR diff --git a/src/libdraw/latin1.c b/src/libdraw/latin1.c
       t@@ -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;
       +}
   DIR diff --git a/src/libdraw/mkfile b/src/libdraw/mkfile
       t@@ -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
       +
   DIR diff --git a/src/libdraw/x11-event.c b/src/libdraw/x11-event.c
       t@@ -36,6 +36,7 @@ eflush(void)
        ulong
        eread(ulong keys, Event *e)
        {
       +        int r;
                ulong xmask;
                XEvent xevent;
        
       t@@ -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:
       t@@ -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);
       t@@ -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:
       t@@ -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;
       t@@ -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)
   DIR diff --git a/src/libdraw/x11-init.c b/src/libdraw/x11-init.c
       t@@ -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);
       t@@ -124,7 +126,7 @@ static int
        xioerror(XDisplay *d)
        {
                print("X I/O error\n");
       -        exit(1);
       +        abort();
                return -1;
        }
        
       t@@ -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);
       t@@ -388,6 +395,46 @@ fprint(2, "%r\n");
                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;
       +}
       +
        /*
         * Create a GC with a particular fill style and XXX.
         * Disable generation of GraphicsExpose/NoExpose events in the GC.
       t@@ -604,6 +651,19 @@ xexpose(XEvent *e, XDisplay *xd)
        }
        
        int
       +xdestroy(XEvent *e, XDisplay *xd)
       +{
       +        XDestroyWindowEvent *xe;
       +
       +        xe = (XDestroyWindowEvent*)e;
       +        if(xe->window == _x.drawable){
       +                _x.destroyed = 1;
       +                return 1;
       +        }
       +        return 0;
       +}
       +
       +int
        xconfigure(XEvent *e, XDisplay *xd)
        {
                Rectangle r;
   DIR diff --git a/src/libdraw/x11-itrans.c b/src/libdraw/x11-itrans.c
       t@@ -11,8 +11,8 @@
        #include <keyboard.h>
        #include "x11-memdraw.h"
        
       -int
       -xtoplan9kbd(XEvent *e)
       +static int
       +_xtoplan9kbd(XEvent *e)
        {
                int ind, k, md;
        
       t@@ -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
       +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(XEvent *e, Mouse *m)
       +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;
       t@@ -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;
       t@@ -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)
       t@@ -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);
        }
        
   DIR diff --git a/src/libdraw/x11-keyboard.c b/src/libdraw/x11-keyboard.c
       t@@ -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;
                        }
                }
   DIR diff --git a/src/libdraw/x11-memdraw.h b/src/libdraw/x11-memdraw.h
       t@@ -64,6 +64,10 @@ struct Xprivate {
                int                usetable;
                XVisual                *vis;
                u32int                white;
       +        Atom                clipboard;
       +        uint                putsnarf;
       +        uint                assertsnarf;
       +        int                destroyed;
        };
        
        extern Xprivate _x;
       t@@ -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;
   DIR diff --git a/src/libdraw/x11-mouse.c b/src/libdraw/x11-mouse.c
       t@@ -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);
       t@@ -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);
                                /*