123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include "u.h"
- #include "lib.h"
- #include "dat.h"
- #include "fns.h"
- #include "error.h"
- #include <draw.h>
- #include <memdraw.h>
- #include <keyboard.h>
- #include <cursor.h>
- #include "screen.h"
- #define argv0 "drawterm"
- typedef struct Cursor Cursor;
- #undef long
- #define Font XFont
- #define Screen XScreen
- #define Display XDisplay
- #define Cursor XCursor
- #include <X11/Xlib.h>
- #include <X11/Xatom.h>
- #include <X11/Xutil.h>
- #include <X11/IntrinsicP.h>
- #include <X11/StringDefs.h>
- #include <X11/keysym.h>
- #include "keysym2ucs.h"
- #undef Font
- #undef Screen
- #undef Display
- #undef Cursor
- #define long int
- /* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */
- #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
- enum
- {
- PMundef = ~0 /* undefined pixmap id */
- };
- /*
- * Structure pointed to by X field of Memimage
- */
- typedef struct Xmem Xmem;
- struct Xmem
- {
- int pmid; /* pixmap id for screen ldepth instance */
- XImage *xi; /* local image if we currenty have the data */
- int dirty;
- Rectangle dirtyr;
- Rectangle r;
- uintptr pc; /* who wrote into xi */
- };
- static int xgcfillcolor;
- static int xgcfillcolor0;
- static int xgcsimplecolor0;
- static int xgcsimplepm0;
- static XDisplay* xdisplay; /* used holding draw lock */
- static int xtblbit;
- static int plan9tox11[256]; /* Values for mapping between */
- static int x11toplan9[256]; /* X11 and Plan 9 */
- static GC xgcfill, xgccopy, xgcsimplesrc, xgczero, xgcreplsrc;
- static GC xgcfill0, xgccopy0, xgcsimplesrc0, xgczero0, xgcreplsrc0;
- static uint32_t xscreenchan;
- static Drawable xscreenid;
- static Visual *xvis;
- static int xdraw(Memdrawparam*);
- #define glenda_width 48
- #define glenda_height 48
- static unsigned short glenda_bits[] = {
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffe9, 0xffff, 0x7fff, 0xffae, 0xffff,
- 0xffff, 0xffbe, 0xffff, 0x1fff, 0xff3f, 0xffff, 0xbfff, 0xfe6e, 0xffff,
- 0xbbff, 0xfcce, 0xffff, 0xffff, 0xf98c, 0xffff, 0xe5ff, 0xf31b, 0xffff,
- 0x87ff, 0xe617, 0xffff, 0x05ff, 0xdf37, 0xffff, 0x0fff, 0x7ffe, 0xffff,
- 0x1bff, 0xfffc, 0xfffa, 0x37ff, 0xfffc, 0xfffb, 0xd7ff, 0xfffc, 0xfff7,
- 0xcfff, 0xffff, 0xfff7, 0xcfff, 0xffff, 0xffef, 0xdfff, 0xffff, 0xffef,
- 0xafff, 0xffff, 0xffdf, 0xefff, 0xffff, 0xfff3, 0xdfff, 0xefff, 0xffd3,
- 0xdfff, 0xc7ff, 0xffdf, 0xefff, 0xefff, 0xffef, 0xcfff, 0xffff, 0xffcf,
- 0xdfff, 0xffff, 0xffd9, 0x9fff, 0x7fff, 0xffd0, 0xbfff, 0xffff, 0xffd7,
- 0x7fff, 0xbfff, 0xffd0, 0x3fff, 0x3fff, 0xffd9, 0x7fff, 0x3fff, 0xffcb,
- 0x3fff, 0xffff, 0xffdc, 0x3fff, 0xffff, 0xffdf, 0x3fff, 0xffff, 0xff9f,
- 0x3fff, 0xffff, 0xffdf, 0x8fff, 0xffff, 0xff9f, 0xa7ff, 0xffff, 0xffdf,
- 0xe3ff, 0xffff, 0xffcf, 0xe9ff, 0xffff, 0xffcf, 0xf1ff, 0xffff, 0xffef,
- 0xf3ff, 0xffff, 0xffe7, 0xf9ff, 0xffff, 0xffe7, 0x53ff, 0xffff, 0xffe1,
- 0x07ff, 0x7ffc, 0xffc6, 0x17ff, 0xeff0, 0xffee, 0xffff, 0xc781, 0xffe5,
- 0xffff, 0x8807, 0xffe0, 0xffff, 0x003f, 0xfff0, 0xffff, 0x1fff, 0xfffe
- };
- /*
- * Synchronize images between X bitmaps and in-memory bitmaps.
- */
- static void
- addrect(Rectangle *rp, Rectangle r)
- {
- if(rp->min.x >= rp->max.x)
- *rp = r;
- else
- combinerect(rp, r);
- }
- static XImage*
- getXdata(Memimage *m, Rectangle r)
- {
- uint8_t *p;
- int x, y;
- Xmem *xm;
- Point xdelta, delta;
- Point tp;
- xm = m->X;
- if(xm == nil)
- return nil;
-
- assert(xm != nil && xm->xi != nil);
-
- if(xm->dirty == 0)
- return xm->xi;
-
- r = xm->dirtyr;
- if(Dx(r)==0 || Dy(r)==0)
- return xm->xi;
- delta = subpt(r.min, m->r.min);
- tp = xm->r.min; /* avoid unaligned access on digital unix */
- xdelta = subpt(r.min, tp);
-
- XGetSubImage(xdisplay, xm->pmid, delta.x, delta.y, Dx(r), Dy(r),
- AllPlanes, ZPixmap, xm->xi, xdelta.x, xdelta.y);
-
- if(xtblbit && m->chan == CMAP8)
- for(y=r.min.y; y<r.max.y; y++)
- for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
- *p = x11toplan9[*p];
-
- xm->dirty = 0;
- xm->dirtyr = Rect(0,0,0,0);
- return xm->xi;
- }
- static void
- putXdata(Memimage *m, Rectangle r)
- {
- Xmem *xm;
- XImage *xi;
- GC g;
- Point xdelta, delta;
- Point tp;
- int x, y;
- uint8_t *p;
- xm = m->X;
- if(xm == nil)
- return;
-
- assert(xm != nil);
- assert(xm->xi != nil);
- xi = xm->xi;
- g = (m->chan == GREY1) ? xgccopy0 : xgccopy;
- delta = subpt(r.min, m->r.min);
- tp = xm->r.min; /* avoid unaligned access on digital unix */
- xdelta = subpt(r.min, tp);
-
- if(xtblbit && m->chan == CMAP8)
- for(y=r.min.y; y<r.max.y; y++)
- for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
- *p = plan9tox11[*p];
-
- XPutImage(xdisplay, xm->pmid, g, xi, xdelta.x, xdelta.y, delta.x, delta.y, Dx(r), Dy(r));
- if(xtblbit && m->chan == CMAP8)
- for(y=r.min.y; y<r.max.y; y++)
- for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
- *p = x11toplan9[*p];
- }
- static void
- dirtyXdata(Memimage *m, Rectangle r)
- {
- Xmem *xm;
-
- if((xm = m->X) != nil){
- xm->dirty = 1;
- addrect(&xm->dirtyr, r);
- }
- }
- Memimage*
- xallocmemimage(Rectangle r, uint32_t chan, int pmid)
- {
- Memimage *m;
- Xmem *xm;
- XImage *xi;
- int offset;
- int d;
-
- m = _allocmemimage(r, chan);
- if(m == nil)
- return nil;
- if(chan != GREY1 && chan != xscreenchan)
- return m;
- d = m->depth;
- xm = mallocz(sizeof(Xmem), 1);
- if(pmid != PMundef)
- xm->pmid = pmid;
- else
- xm->pmid = XCreatePixmap(xdisplay, xscreenid, Dx(r), Dy(r), (d==32) ? 24 : d);
-
- if(m->depth == 24)
- offset = r.min.x&(4-1);
- else
- offset = r.min.x&(31/m->depth);
- r.min.x -= offset;
-
- assert(wordsperline(r, m->depth) <= m->width);
- xi = XCreateImage(xdisplay, xvis, m->depth==32?24:m->depth, ZPixmap, 0,
- (char*)m->data->bdata, Dx(r), Dy(r), 32,
- m->width*sizeof(uint32_t));
-
- if(xi == nil){
- _freememimage(m);
- return nil;
- }
- xm->xi = xi;
- xm->pc = getcallerpc();
- xm->r = r;
-
- /*
- * Set the parameters of the XImage so its memory looks exactly like a
- * Memimage, so we can call _memimagedraw on the same data. All frame
- * buffers we've seen, and Plan 9's graphics code, require big-endian
- * bits within bytes, but little endian byte order within pixels.
- */
- xi->bitmap_unit = m->depth < 8 || m->depth == 24 ? 8 : m->depth;
- xi->byte_order = LSBFirst;
- xi->bitmap_bit_order = MSBFirst;
- xi->bitmap_pad = 32;
- xm->r = Rect(0,0,0,0);
- XInitImage(xi);
- XFlush(xdisplay);
- m->X = xm;
- return m;
- }
- void
- xfillcolor(Memimage *m, Rectangle r, uint32_t v)
- {
- GC gc;
- Xmem *dxm;
- dxm = m->X;
- assert(dxm != nil);
- r = rectsubpt(r, m->r.min);
-
- if(m->chan == GREY1){
- gc = xgcfill0;
- if(xgcfillcolor0 != v){
- XSetForeground(xdisplay, gc, v);
- xgcfillcolor0 = v;
- }
- }else{
- if(m->chan == CMAP8 && xtblbit)
- v = plan9tox11[v];
-
- gc = xgcfill;
- if(xgcfillcolor != v){
- XSetForeground(xdisplay, gc, v);
- xgcfillcolor = v;
- }
- }
- XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, Dx(r), Dy(r));
- }
- /*
- * Replacements for libmemdraw routines.
- * (They've been underscored.)
- */
- Memimage*
- allocmemimage(Rectangle r, uint32_t chan)
- {
- return xallocmemimage(r, chan, PMundef);
- }
- void
- freememimage(Memimage *m)
- {
- Xmem *xm;
-
- if(m == nil)
- return;
-
- if(m->data->ref == 1){
- if((xm = m->X) != nil){
- if(xm->xi){
- xm->xi->data = nil;
- XFree(xm->xi);
- }
- XFreePixmap(xdisplay, xm->pmid);
- free(xm);
- m->X = nil;
- }
- }
- _freememimage(m);
- }
- void
- memfillcolor(Memimage *m, uint32_t val)
- {
- _memfillcolor(m, val);
- if(m->X){
- if((val & 0xFF) == 0xFF)
- xfillcolor(m, m->r, _rgbatoimg(m, val));
- else
- putXdata(m, m->r);
- }
- }
- int
- loadmemimage(Memimage *i, Rectangle r, uint8_t *data, int ndata)
- {
- int n;
- n = _loadmemimage(i, r, data, ndata);
- if(n > 0 && i->X)
- putXdata(i, r);
- return n;
- }
- int
- cloadmemimage(Memimage *i, Rectangle r, uint8_t *data, int ndata)
- {
- int n;
- n = _cloadmemimage(i, r, data, ndata);
- if(n > 0 && i->X)
- putXdata(i, r);
- return n;
- }
- uint32_t
- pixelbits(Memimage *m, Point p)
- {
- if(m->X)
- getXdata(m, Rect(p.x, p.y, p.x+1, p.y+1));
- return _pixelbits(m, p);
- }
- void
- memimageinit(void)
- {
- static int didinit = 0;
-
- if(didinit)
- return;
- didinit = 1;
- _memimageinit();
-
- xfillcolor(memblack, memblack->r, 0);
- xfillcolor(memwhite, memwhite->r, 1);
- }
- void
- memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op)
- {
- Memdrawparam *par;
-
- if((par = _memimagedrawsetup(dst, r, src, sp, mask, mp, op)) == nil)
- return;
- _memimagedraw(par);
- if(!xdraw(par))
- putXdata(dst, par->r);
- }
- static int
- xdraw(Memdrawparam *par)
- {
- int dy, dx;
- unsigned m;
- Memimage *src, *dst, *mask;
- Xmem *dxm, *sxm, *mxm;
- GC gc;
- Rectangle r, sr, mr;
- uint32_t sdval;
- dx = Dx(par->r);
- dy = Dy(par->r);
- src = par->src;
- dst = par->dst;
- mask = par->mask;
- r = par->r;
- sr = par->sr;
- mr = par->mr;
- sdval = par->sdval;
- /*
- * drawterm was distributed for years with
- * "return 0;" right here.
- * maybe we should give up on all this?
- */
- if((dxm = dst->X) == nil)
- return 0;
- /*
- * If we have an opaque mask and source is one opaque pixel we can convert to the
- * destination format and just XFillRectangle.
- */
- m = Simplesrc|Simplemask|Fullmask;
- if((par->state&m)==m){
- xfillcolor(dst, r, sdval);
- dirtyXdata(dst, par->r);
- return 1;
- }
- /*
- * If no source alpha, an opaque mask, we can just copy the
- * source onto the destination. If the channels are the same and
- * the source is not replicated, XCopyArea suffices.
- */
- m = Simplemask|Fullmask;
- if((par->state&(m|Replsrc))==m && src->chan == dst->chan && src->X){
- sxm = src->X;
- r = rectsubpt(r, dst->r.min);
- sr = rectsubpt(sr, src->r.min);
- if(dst->chan == GREY1)
- gc = xgccopy0;
- else
- gc = xgccopy;
- XCopyArea(xdisplay, sxm->pmid, dxm->pmid, gc,
- sr.min.x, sr.min.y, dx, dy, r.min.x, r.min.y);
- dirtyXdata(dst, par->r);
- return 1;
- }
-
- /*
- * If no source alpha, a 1-bit mask, and a simple source
- * we can just copy through the mask onto the destination.
- */
- if(dst->X && mask->X && !(mask->flags&Frepl)
- && mask->chan == GREY1 && (par->state&Simplesrc)){
- Point p;
- mxm = mask->X;
- r = rectsubpt(r, dst->r.min);
- mr = rectsubpt(mr, mask->r.min);
- p = subpt(r.min, mr.min);
- if(dst->chan == GREY1){
- gc = xgcsimplesrc0;
- if(xgcsimplecolor0 != sdval){
- XSetForeground(xdisplay, gc, sdval);
- xgcsimplecolor0 = sdval;
- }
- if(xgcsimplepm0 != mxm->pmid){
- XSetStipple(xdisplay, gc, mxm->pmid);
- xgcsimplepm0 = mxm->pmid;
- }
- }else{
- /* somehow this doesn't work on rob's mac
- gc = xgcsimplesrc;
- if(dst->chan == CMAP8 && xtblbit)
- sdval = plan9tox11[sdval];
-
- if(xgcsimplecolor != sdval){
- XSetForeground(xdisplay, gc, sdval);
- xgcsimplecolor = sdval;
- }
- if(xgcsimplepm != mxm->pmid){
- XSetStipple(xdisplay, gc, mxm->pmid);
- xgcsimplepm = mxm->pmid;
- }
- */
- return 0;
- }
- XSetTSOrigin(xdisplay, gc, p.x, p.y);
- XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, dx, dy);
- dirtyXdata(dst, par->r);
- return 1;
- }
- return 0;
- }
- /*
- * X11 window management and kernel hooks.
- * Oh, how I loathe this code!
- */
- static XColor map[256]; /* Plan 9 colormap array */
- static XColor map7[128]; /* Plan 9 colormap array */
- static uint8_t map7to8[128][2];
- static Colormap xcmap; /* Default shared colormap */
- extern int mousequeue;
- /* for copy/paste, lifted from plan9ports */
- static Atom clipboard;
- static Atom utf8string;
- static Atom targets;
- static Atom text;
- static Atom compoundtext;
- static Drawable xdrawable;
- static void xexpose(XEvent*);
- static void xmouse(XEvent*);
- static void xkeyboard(XEvent*);
- static void xmapping(XEvent*);
- static void xdestroy(XEvent*);
- static void xselect(XEvent*, XDisplay*);
- static void xproc(void*);
- static Memimage* xinitscreen(void);
- static void initmap(Window);
- static GC creategc(Drawable);
- static void graphicscmap(XColor*);
- static int xscreendepth;
- static XDisplay* xkmcon; /* used only in xproc */
- static XDisplay* xsnarfcon; /* used holding clip.lk */
- static uint32_t xblack;
- static uint32_t xwhite;
- static int putsnarf, assertsnarf;
- Memimage *gscreen;
- Screeninfo screen;
- void
- flushmemscreen(Rectangle r)
- {
- assert(!drawcanqlock());
- if(r.min.x >= r.max.x || r.min.y >= r.max.y)
- return;
- XCopyArea(xdisplay, xscreenid, xdrawable, xgccopy, r.min.x, r.min.y, Dx(r), Dy(r), r.min.x, r.min.y);
- XFlush(xdisplay);
- }
- void
- screeninit(void)
- {
- _memmkcmap();
- gscreen = xinitscreen();
- kproc("xscreen", xproc, nil);
- memimageinit();
- terminit();
- drawqlock();
- flushmemscreen(gscreen->r);
- drawqunlock();
- }
- uint8_t*
- attachscreen(Rectangle *r, uint32_t *chan, int *depth,
- int *width, int *softscreen, void **X)
- {
- *r = gscreen->r;
- *chan = gscreen->chan;
- *depth = gscreen->depth;
- *width = gscreen->width;
- *X = gscreen->X;
- *softscreen = 1;
- return gscreen->data->bdata;
- }
- static int
- revbyte(int b)
- {
- int r;
- r = 0;
- r |= (b&0x01) << 7;
- r |= (b&0x02) << 5;
- r |= (b&0x04) << 3;
- r |= (b&0x08) << 1;
- r |= (b&0x10) >> 1;
- r |= (b&0x20) >> 3;
- r |= (b&0x40) >> 5;
- r |= (b&0x80) >> 7;
- return r;
- }
- void
- mouseset(Point xy)
- {
- drawqlock();
- XWarpPointer(xdisplay, None, xdrawable, 0, 0, 0, 0, xy.x, xy.y);
- XFlush(xdisplay);
- drawqunlock();
- }
- static XCursor xcursor;
- void
- setcursor(void)
- {
- XCursor xc;
- XColor fg, bg;
- Pixmap xsrc, xmask;
- int i;
- uint8_t src[2*16], mask[2*16];
- for(i=0; i<2*16; i++){
- src[i] = revbyte(cursor.set[i]);
- mask[i] = revbyte(cursor.set[i] | cursor.clr[i]);
- }
- drawqlock();
- fg = map[0];
- bg = map[255];
- xsrc = XCreateBitmapFromData(xdisplay, xdrawable, (char*)src, 16,
- 16);
- xmask = XCreateBitmapFromData(xdisplay, xdrawable, (char*)mask, 16,
- 16);
- xc = XCreatePixmapCursor(xdisplay, xsrc, xmask, &fg, &bg, -cursor.offset.x, -cursor.offset.y);
- if(xc != 0) {
- XDefineCursor(xdisplay, xdrawable, xc);
- if(xcursor != 0)
- XFreeCursor(xdisplay, xcursor);
- xcursor = xc;
- }
- XFreePixmap(xdisplay, xsrc);
- XFreePixmap(xdisplay, xmask);
- XFlush(xdisplay);
- drawqunlock();
- }
- void
- cursorarrow(void)
- {
- drawqlock();
- if(xcursor != 0){
- XFreeCursor(xdisplay, xcursor);
- xcursor = 0;
- }
- XUndefineCursor(xdisplay, xdrawable);
- XFlush(xdisplay);
- drawqunlock();
- }
- static void
- xproc(void *arg)
- {
- uint32_t mask;
- XEvent event;
- mask = KeyPressMask|
- ButtonPressMask|
- ButtonReleaseMask|
- PointerMotionMask|
- Button1MotionMask|
- Button2MotionMask|
- Button3MotionMask|
- Button4MotionMask|
- Button5MotionMask|
- ExposureMask|
- StructureNotifyMask;
- XSelectInput(xkmcon, xdrawable, mask);
- for(;;) {
- //XWindowEvent(xkmcon, xdrawable, mask, &event);
- XNextEvent(xkmcon, &event);
- xselect(&event, xkmcon);
- xkeyboard(&event);
- xmouse(&event);
- xexpose(&event);
- xmapping(&event);
- xdestroy(&event);
- }
- }
- static int
- shutup(XDisplay *d, XErrorEvent *e)
- {
- char buf[200];
- iprint("X error: error code=%d, request_code=%d, minor=%d\n", e->error_code, e->request_code, e->minor_code);
- XGetErrorText(d, e->error_code, buf, sizeof(buf));
- iprint("%s\n", buf);
- USED(d);
- USED(e);
- return 0;
- }
- static int
- panicshutup(XDisplay *d)
- {
- panic("x error");
- return -1;
- }
- static Memimage*
- xinitscreen(void)
- {
- Memimage *gscreen;
- int i, xsize, ysize, pmid;
- char *argv[2];
- char *disp_val;
- Window rootwin;
- Rectangle r;
- XWMHints hints;
- XScreen *screen;
- XVisualInfo xvi;
- int rootscreennum;
- XTextProperty name;
- XClassHint classhints;
- XSizeHints normalhints;
- XSetWindowAttributes attrs;
- XPixmapFormatValues *pfmt;
- int n;
- Pixmap icon_pixmap;
- xscreenid = 0;
- xdrawable = 0;
- xdisplay = XOpenDisplay(NULL);
- if(xdisplay == 0){
- iprint("xinitscreen: XOpenDisplay: %r [DISPLAY=%s]\n",
- getenv("DISPLAY"));
- exit(0);
- }
- XSetErrorHandler(shutup);
- XSetIOErrorHandler(panicshutup);
- rootscreennum = DefaultScreen(xdisplay);
- rootwin = DefaultRootWindow(xdisplay);
-
- xscreendepth = DefaultDepth(xdisplay, rootscreennum);
- if(XMatchVisualInfo(xdisplay, rootscreennum, 16, TrueColor, &xvi)
- || XMatchVisualInfo(xdisplay, rootscreennum, 16, DirectColor, &xvi)){
- xvis = xvi.visual;
- xscreendepth = 16;
- xtblbit = 1;
- }
- else if(XMatchVisualInfo(xdisplay, rootscreennum, 24, TrueColor, &xvi)
- || XMatchVisualInfo(xdisplay, rootscreennum, 24, DirectColor, &xvi)){
- xvis = xvi.visual;
- xscreendepth = 24;
- xtblbit = 1;
- }
- else if(XMatchVisualInfo(xdisplay, rootscreennum, 8, PseudoColor, &xvi)
- || XMatchVisualInfo(xdisplay, rootscreennum, 8, StaticColor, &xvi)){
- if(xscreendepth > 8)
- panic("drawterm: can't deal with colormapped depth %d screens\n", xscreendepth);
- xvis = xvi.visual;
- xscreendepth = 8;
- }
- else{
- if(xscreendepth != 8)
- panic("drawterm: can't deal with depth %d screens\n", xscreendepth);
- xvis = DefaultVisual(xdisplay, rootscreennum);
- }
- /*
- * xscreendepth is only the number of significant pixel bits,
- * not the total. We need to walk the display list to find
- * how many actual bits are being used per pixel.
- */
- xscreenchan = 0; /* not a valid channel */
- pfmt = XListPixmapFormats(xdisplay, &n);
- for(i=0; i<n; i++){
- if(pfmt[i].depth == xscreendepth){
- switch(pfmt[i].bits_per_pixel){
- case 1: /* untested */
- xscreenchan = GREY1;
- break;
- case 2: /* untested */
- xscreenchan = GREY2;
- break;
- case 4: /* untested */
- xscreenchan = GREY4;
- break;
- case 8:
- xscreenchan = CMAP8;
- break;
- case 16: /* uses 16 rather than 15, empirically. */
- xscreenchan = RGB16;
- break;
- case 24: /* untested (impossible?) */
- xscreenchan = RGB24;
- break;
- case 32:
- xscreenchan = CHAN4(CIgnore, 8, CRed, 8, CGreen, 8, CBlue, 8);
- break;
- }
- }
- }
- if(xscreenchan == 0)
- panic("drawterm: unknown screen pixel format\n");
-
- screen = DefaultScreenOfDisplay(xdisplay);
- xcmap = DefaultColormapOfScreen(screen);
- if(xvis->class != StaticColor){
- graphicscmap(map);
- initmap(rootwin);
- }
- r.min = ZP;
- r.max.x = WidthOfScreen(screen);
- r.max.y = HeightOfScreen(screen);
- xsize = Dx(r)*3/4;
- ysize = Dy(r)*3/4;
-
- attrs.colormap = xcmap;
- attrs.background_pixel = 0;
- attrs.border_pixel = 0;
- /* attrs.override_redirect = 1;*/ /* WM leave me alone! |CWOverrideRedirect */
- xdrawable = XCreateWindow(xdisplay, rootwin, 0, 0, xsize, ysize, 0,
- xscreendepth, InputOutput, xvis, CWBackPixel|CWBorderPixel|CWColormap, &attrs);
- /* load the given bitmap data and create an X pixmap containing it. */
- icon_pixmap = XCreateBitmapFromData(xdisplay,
- rootwin, (char *)glenda_bits,
- glenda_width, glenda_height);
- /*
- * set up property as required by ICCCM
- */
- name.value = (uint8_t*)"drawterm";
- name.encoding = XA_STRING;
- name.format = 8;
- name.nitems = strlen((char*)name.value);
- normalhints.flags = USSize|PMaxSize;
- normalhints.max_width = Dx(r);
- normalhints.max_height = Dy(r);
- normalhints.width = xsize;
- normalhints.height = ysize;
- hints.flags = IconPixmapHint |InputHint|StateHint;
- hints.input = 1;
- hints.initial_state = NormalState;
- hints.icon_pixmap = icon_pixmap;
- classhints.res_name = "drawterm";
- classhints.res_class = "Drawterm";
- argv[0] = "drawterm";
- argv[1] = nil;
- XSetWMProperties(xdisplay, xdrawable,
- &name, /* XA_WM_NAME property for ICCCM */
- &name, /* XA_WM_ICON_NAME */
- argv, /* XA_WM_COMMAND */
- 1, /* argc */
- &normalhints, /* XA_WM_NORMAL_HINTS */
- &hints, /* XA_WM_HINTS */
- &classhints); /* XA_WM_CLASS */
- XFlush(xdisplay);
-
- /*
- * put the window on the screen
- */
- XMapWindow(xdisplay, xdrawable);
- XFlush(xdisplay);
- xscreenid = XCreatePixmap(xdisplay, xdrawable, Dx(r), Dy(r), xscreendepth);
- gscreen = xallocmemimage(r, xscreenchan, xscreenid);
-
- xgcfill = creategc(xscreenid);
- XSetFillStyle(xdisplay, xgcfill, FillSolid);
- xgccopy = creategc(xscreenid);
- xgcsimplesrc = creategc(xscreenid);
- XSetFillStyle(xdisplay, xgcsimplesrc, FillStippled);
- xgczero = creategc(xscreenid);
- xgcreplsrc = creategc(xscreenid);
- XSetFillStyle(xdisplay, xgcreplsrc, FillTiled);
- pmid = XCreatePixmap(xdisplay, xdrawable, 1, 1, 1);
- xgcfill0 = creategc(pmid);
- XSetForeground(xdisplay, xgcfill0, 0);
- XSetFillStyle(xdisplay, xgcfill0, FillSolid);
- xgccopy0 = creategc(pmid);
- xgcsimplesrc0 = creategc(pmid);
- XSetFillStyle(xdisplay, xgcsimplesrc0, FillStippled);
- xgczero0 = creategc(pmid);
- xgcreplsrc0 = creategc(pmid);
- XSetFillStyle(xdisplay, xgcreplsrc0, FillTiled);
- XFreePixmap(xdisplay, pmid);
- XSetForeground(xdisplay, xgccopy, plan9tox11[0]);
- XFillRectangle(xdisplay, xscreenid, xgccopy, 0, 0, xsize, ysize);
- xkmcon = XOpenDisplay(NULL);
- if(xkmcon == 0){
- disp_val = getenv("DISPLAY");
- if(disp_val == 0)
- disp_val = "not set";
- iprint("drawterm: open %r, DISPLAY is %s\n", disp_val);
- exit(0);
- }
- xsnarfcon = XOpenDisplay(NULL);
- if(xsnarfcon == 0){
- disp_val = getenv("DISPLAY");
- if(disp_val == 0)
- disp_val = "not set";
- iprint("drawterm: open %r, DISPLAY is %s\n", disp_val);
- exit(0);
- }
- clipboard = XInternAtom(xkmcon, "CLIPBOARD", False);
- utf8string = XInternAtom(xkmcon, "UTF8_STRING", False);
- targets = XInternAtom(xkmcon, "TARGETS", False);
- text = XInternAtom(xkmcon, "TEXT", False);
- compoundtext = XInternAtom(xkmcon, "COMPOUND_TEXT", False);
- xblack = screen->black_pixel;
- xwhite = screen->white_pixel;
- return gscreen;
- }
- static void
- graphicscmap(XColor *map)
- {
- int r, g, b, cr, cg, cb, v, num, den, idx, v7, idx7;
- for(r=0; r!=4; r++) {
- for(g = 0; g != 4; g++) {
- for(b = 0; b!=4; b++) {
- for(v = 0; v!=4; v++) {
- den=r;
- if(g > den)
- den=g;
- if(b > den)
- den=b;
- /* divide check -- pick grey shades */
- if(den==0)
- cr=cg=cb=v*17;
- else {
- num=17*(4*den+v);
- cr=r*num/den;
- cg=g*num/den;
- cb=b*num/den;
- }
- idx = r*64 + v*16 + ((g*4 + b + v - r) & 15);
- map[idx].red = cr*0x0101;
- map[idx].green = cg*0x0101;
- map[idx].blue = cb*0x0101;
- map[idx].pixel = idx;
- map[idx].flags = DoRed|DoGreen|DoBlue;
- v7 = v >> 1;
- idx7 = r*32 + v7*16 + g*4 + b;
- if((v & 1) == v7){
- map7to8[idx7][0] = idx;
- if(den == 0) { /* divide check -- pick grey shades */
- cr = ((255.0/7.0)*v7)+0.5;
- cg = cr;
- cb = cr;
- }
- else {
- num=17*15*(4*den+v7*2)/14;
- cr=r*num/den;
- cg=g*num/den;
- cb=b*num/den;
- }
- map7[idx7].red = cr*0x0101;
- map7[idx7].green = cg*0x0101;
- map7[idx7].blue = cb*0x0101;
- map7[idx7].pixel = idx7;
- map7[idx7].flags = DoRed|DoGreen|DoBlue;
- }
- else
- map7to8[idx7][1] = idx;
- }
- }
- }
- }
- }
- /*
- * Initialize and install the drawterm colormap as a private colormap for this
- * application. Drawterm gets the best colors here when it has the cursor focus.
- */
- static void
- initmap(Window w)
- {
- XColor c;
- int i;
- uint32_t p, pp;
- char buf[30];
- if(xscreendepth <= 1)
- return;
- if(xscreendepth >= 24) {
- /* The pixel value returned from XGetPixel needs to
- * be converted to RGB so we can call rgb2cmap()
- * to translate between 24 bit X and our color. Unfortunately,
- * the return value appears to be display server endian
- * dependant. Therefore, we run some heuristics to later
- * determine how to mask the int value correctly.
- * Yeah, I know we can look at xvis->byte_order but
- * some displays say MSB even though they run on LSB.
- * Besides, this is more anal.
- */
- if(xscreendepth != DefaultDepth(xdisplay, DefaultScreen(xdisplay)))
- xcmap = XCreateColormap(xdisplay, w, xvis, AllocNone);
- c = map[19];
- /* find out index into colormap for our RGB */
- if(!XAllocColor(xdisplay, xcmap, &c))
- panic("drawterm: screen-x11 can't alloc color");
- p = c.pixel;
- pp = rgb2cmap((p>>16)&0xff,(p>>8)&0xff,p&0xff);
- if(pp!=map[19].pixel) {
- /* check if endian is other way */
- pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff);
- if(pp!=map[19].pixel)
- panic("cannot detect x server byte order");
- switch(xscreenchan){
- case RGB24:
- xscreenchan = BGR24;
- break;
- case XRGB32:
- xscreenchan = XBGR32;
- break;
- default:
- panic("don't know how to byteswap channel %s",
- chantostr(buf, xscreenchan));
- break;
- }
- }
- } else if(xvis->class == TrueColor || xvis->class == DirectColor) {
- } else if(xvis->class == PseudoColor) {
- if(xtblbit == 0){
- xcmap = XCreateColormap(xdisplay, w, xvis, AllocAll);
- XStoreColors(xdisplay, xcmap, map, 256);
- for(i = 0; i < 256; i++) {
- plan9tox11[i] = i;
- x11toplan9[i] = i;
- }
- }
- else {
- for(i = 0; i < 128; i++) {
- c = map7[i];
- if(!XAllocColor(xdisplay, xcmap, &c)) {
- iprint("drawterm: can't alloc colors in default map, don't use -7\n");
- exit(0);
- }
- plan9tox11[map7to8[i][0]] = c.pixel;
- plan9tox11[map7to8[i][1]] = c.pixel;
- x11toplan9[c.pixel] = map7to8[i][0];
- }
- }
- }
- else
- panic("drawterm: unsupported visual class %d\n", xvis->class);
- }
- static void
- xdestroy(XEvent *e)
- {
- XDestroyWindowEvent *xe;
- if(e->type != DestroyNotify)
- return;
- xe = (XDestroyWindowEvent*)e;
- if(xe->window == xdrawable)
- exit(0);
- }
- static void
- xmapping(XEvent *e)
- {
- XMappingEvent *xe;
- if(e->type != MappingNotify)
- return;
- xe = (XMappingEvent*)e;
- USED(xe);
- }
- /*
- * Disable generation of GraphicsExpose/NoExpose events in the GC.
- */
- static GC
- creategc(Drawable d)
- {
- XGCValues gcv;
- gcv.function = GXcopy;
- gcv.graphics_exposures = False;
- return XCreateGC(xdisplay, d, GCFunction|GCGraphicsExposures, &gcv);
- }
- static void
- xexpose(XEvent *e)
- {
- Rectangle r;
- XExposeEvent *xe;
- if(e->type != Expose)
- return;
- xe = (XExposeEvent*)e;
- r.min.x = xe->x;
- r.min.y = xe->y;
- r.max.x = xe->x + xe->width;
- r.max.y = xe->y + xe->height;
- drawflushr(r);
- }
- static void
- xkeyboard(XEvent *e)
- {
- KeySym k;
- /*
- * I tried using XtGetActionKeysym, but it didn't seem to
- * do case conversion properly
- * (at least, with Xterminal servers and R4 intrinsics)
- */
- if(e->xany.type != KeyPress)
- return;
- XLookupString((XKeyEvent*)e, NULL, 0, &k, NULL);
- if(k == XK_Multi_key || k == NoSymbol)
- return;
- if(k&0xFF00){
- switch(k){
- case XK_BackSpace:
- case XK_Tab:
- case XK_Escape:
- case XK_Delete:
- case XK_KP_0:
- case XK_KP_1:
- case XK_KP_2:
- case XK_KP_3:
- case XK_KP_4:
- case XK_KP_5:
- case XK_KP_6:
- case XK_KP_7:
- case XK_KP_8:
- case XK_KP_9:
- case XK_KP_Divide:
- case XK_KP_Multiply:
- case XK_KP_Subtract:
- case XK_KP_Add:
- case XK_KP_Decimal:
- k &= 0x7F;
- break;
- case XK_Linefeed:
- k = '\r';
- break;
- case XK_KP_Space:
- k = ' ';
- break;
- case XK_Home:
- case XK_KP_Home:
- k = Khome;
- break;
- case XK_Left:
- case XK_KP_Left:
- k = Kleft;
- break;
- case XK_Up:
- case XK_KP_Up:
- k = Kup;
- break;
- case XK_Down:
- case XK_KP_Down:
- k = Kdown;
- break;
- case XK_Right:
- case XK_KP_Right:
- k = Kright;
- break;
- case XK_Page_Down:
- case XK_KP_Page_Down:
- k = Kpgdown;
- break;
- case XK_End:
- case XK_KP_End:
- k = Kend;
- break;
- case XK_Page_Up:
- case XK_KP_Page_Up:
- k = Kpgup;
- break;
- case XK_Insert:
- case XK_KP_Insert:
- k = Kins;
- break;
- case XK_KP_Enter:
- case XK_Return:
- k = '\n';
- break;
- case XK_Alt_L:
- case XK_Alt_R:
- k = Kalt;
- break;
- case XK_F1:
- case XK_F2:
- case XK_F3:
- case XK_F4:
- case XK_F5:
- case XK_F6:
- case XK_F7:
- case XK_F8:
- case XK_F9:
- case XK_F10:
- case XK_F11:
- case XK_F12:
- k = KF|(k - XK_F1 + 1);
- break;
- case XK_Shift_L:
- case XK_Shift_R:
- case XK_Control_L:
- case XK_Control_R:
- case XK_Caps_Lock:
- case XK_Shift_Lock:
- case XK_Meta_L:
- case XK_Meta_R:
- case XK_Super_L:
- case XK_Super_R:
- case XK_Hyper_L:
- case XK_Hyper_R:
- return;
- default: /* not ISO-1 or tty control */
- if(k>0xff){
- k = keysym2ucs(k); /* supplied by X */
- if(k == -1)
- return;
- }
- break;
- }
- }
- /* Compensate for servers that call a minus a hyphen */
- if(k == XK_hyphen)
- k = XK_minus;
- /* Do control mapping ourselves if translator doesn't */
- if(e->xkey.state&ControlMask && k != Kalt)
- k &= 0x9f;
- if(k == NoSymbol) {
- return;
- }
- kbdputc(kbdq, k);
- }
- static void
- xmouse(XEvent *e)
- {
- Mousestate ms;
- int i, s;
- XButtonEvent *be;
- XMotionEvent *me;
- if(putsnarf != assertsnarf){
- assertsnarf = putsnarf;
- XSetSelectionOwner(xkmcon, XA_PRIMARY, xdrawable, CurrentTime);
- if(clipboard != None)
- XSetSelectionOwner(xkmcon, clipboard, xdrawable, CurrentTime);
- XFlush(xkmcon);
- }
- switch(e->type){
- case ButtonPress:
- be = (XButtonEvent *)e;
- /*
- * Fake message, just sent to make us announce snarf.
- * Apparently state and button are 16 and 8 bits on
- * the wire, since they are truncated by the time they
- * get to us.
- */
- if(be->send_event
- && (~be->state&0xFFFF)==0
- && (~be->button&0xFF)==0)
- return;
- ms.xy.x = be->x;
- ms.xy.y = be->y;
- s = be->state;
- ms.msec = be->time;
- switch(be->button){
- case 1:
- s |= Button1Mask;
- break;
- case 2:
- s |= Button2Mask;
- break;
- case 3:
- s |= Button3Mask;
- break;
- case 4:
- s |= Button4Mask;
- break;
- case 5:
- s |= Button5Mask;
- break;
- }
- break;
- case ButtonRelease:
- be = (XButtonEvent *)e;
- ms.xy.x = be->x;
- ms.xy.y = be->y;
- ms.msec = be->time;
- s = be->state;
- switch(be->button){
- case 1:
- s &= ~Button1Mask;
- break;
- case 2:
- s &= ~Button2Mask;
- break;
- case 3:
- s &= ~Button3Mask;
- break;
- case 4:
- s &= ~Button4Mask;
- break;
- case 5:
- s &= ~Button5Mask;
- break;
- }
- break;
- case MotionNotify:
- me = (XMotionEvent *)e;
- s = me->state;
- ms.xy.x = me->x;
- ms.xy.y = me->y;
- ms.msec = me->time;
- break;
- default:
- return;
- }
- ms.buttons = 0;
- if(s & Button1Mask)
- ms.buttons |= 1;
- if(s & Button2Mask)
- ms.buttons |= 2;
- if(s & Button3Mask)
- ms.buttons |= 4;
- if(s & Button4Mask)
- ms.buttons |= 8;
- if(s & Button5Mask)
- ms.buttons |= 16;
- lock(&mouse.lk);
- i = mouse.wi;
- if(mousequeue) {
- if(i == mouse.ri || mouse.lastb != ms.buttons || mouse.trans) {
- mouse.wi = (i+1)%Mousequeue;
- if(mouse.wi == mouse.ri)
- mouse.ri = (mouse.ri+1)%Mousequeue;
- mouse.trans = mouse.lastb != ms.buttons;
- } else {
- i = (i-1+Mousequeue)%Mousequeue;
- }
- } else {
- mouse.wi = (i+1)%Mousequeue;
- mouse.ri = i;
- }
- mouse.queue[i] = ms;
- mouse.lastb = ms.buttons;
- unlock(&mouse.lk);
- wakeup(&mouse.r);
- }
- void
- getcolor(uint32_t i, uint32_t *r, uint32_t *g, uint32_t *b)
- {
- uint32_t v;
-
- v = cmap2rgb(i);
- *r = (v>>16)&0xFF;
- *g = (v>>8)&0xFF;
- *b = v&0xFF;
- }
- void
- setcolor(uint32_t i, uint32_t r, uint32_t g, uint32_t b)
- {
- /* no-op */
- }
- int
- atlocalconsole(void)
- {
- char *p, *q;
- char buf[128];
- p = getenv("DRAWTERM_ATLOCALCONSOLE");
- if(p && atoi(p) == 1)
- return 1;
- p = getenv("DISPLAY");
- if(p == nil)
- return 0;
- /* extract host part */
- q = strchr(p, ':');
- if(q == nil)
- return 0;
- *q = 0;
- if(strcmp(p, "") == 0)
- return 1;
- /* try to match against system name (i.e. for ssh) */
- if(gethostname(buf, sizeof buf) == 0){
- if(strcmp(p, buf) == 0)
- return 1;
- if(strncmp(p, buf, strlen(p)) == 0 && buf[strlen(p)]=='.')
- return 1;
- }
- return 0;
- }
- /*
- * Cut and paste. Just couldn't stand to make this simple...
- */
- typedef struct Clip Clip;
- struct Clip
- {
- char buf[SnarfSize];
- QLock lk;
- };
- Clip clip;
- #undef long /* sic */
- #undef ulong
- static char*
- _xgetsnarf(XDisplay *xd)
- {
- uint8_t *data, *xdata;
- Atom clipboard, type, prop;
- unsigned long lastlen;
- unsigned long dummy, len;
- int fmt, i;
- Window w;
- qlock(&clip.lk);
- /*
- * Have we snarfed recently and the X server hasn't caught up?
- */
- if(putsnarf != assertsnarf)
- goto mine;
- /*
- * Is there a primary selection (highlighted text in an xterm)?
- */
- clipboard = XA_PRIMARY;
- w = XGetSelectionOwner(xd, XA_PRIMARY);
- if(w == xdrawable){
- mine:
- data = (uint8_t*)strdup(clip.buf);
- goto out;
- }
- /*
- * If not, is there a clipboard selection?
- */
- if(w == None && clipboard != None){
- clipboard = clipboard;
- w = XGetSelectionOwner(xd, clipboard);
- if(w == xdrawable)
- 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 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.
- *
- * We should try to go for utf8string instead of XA_STRING,
- * but that would add to the polling.
- */
- prop = 1;
- XChangeProperty(xd, xdrawable, prop, XA_STRING, 8, PropModeReplace,
- (uint8_t*)"", 0);
- XConvertSelection(xd, clipboard, XA_STRING, prop, xdrawable, CurrentTime);
- XFlush(xd);
- lastlen = 0;
- for(i=0; i<10 || (lastlen!=0 && i<30); i++){
- usleep(100*1000);
- XGetWindowProperty(xd, xdrawable, prop, 0, 0, 0, AnyPropertyType,
- &type, &fmt, &dummy, &len, &data);
- if(lastlen == len && len > 0)
- break;
- lastlen = len;
- }
- if(i == 10){
- data = nil;
- goto out;
- }
- /* get the property */
- data = nil;
- XGetWindowProperty(xd, xdrawable, prop, 0, SnarfSize/sizeof(unsigned long), 0,
- AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
- if((type != XA_STRING && type != utf8string) || len == 0){
- if(xdata)
- XFree(xdata);
- data = nil;
- }else{
- if(xdata){
- data = (uint8_t*)strdup((char*)xdata);
- XFree(xdata);
- }else
- data = nil;
- }
- out:
- qunlock(&clip.lk);
- return (char*)data;
- }
- static void
- _xputsnarf(XDisplay *xd, char *data)
- {
- XButtonEvent e;
- if(strlen(data) >= SnarfSize)
- return;
- qlock(&clip.lk);
- strcpy(clip.buf, data);
- /* leave note for mouse proc to assert selection ownership */
- putsnarf++;
- /* send mouse a fake event so snarf is announced */
- memset(&e, 0, sizeof e);
- e.type = ButtonPress;
- e.window = xdrawable;
- e.state = ~0;
- e.button = ~0;
- XSendEvent(xd, xdrawable, True, ButtonPressMask, (XEvent*)&e);
- XFlush(xd);
- qunlock(&clip.lk);
- }
- static void
- xselect(XEvent *e, XDisplay *xd)
- {
- char *name;
- XEvent r;
- XSelectionRequestEvent *xe;
- Atom a[4];
- if(e->xany.type != SelectionRequest)
- return;
- memset(&r, 0, sizeof r);
- xe = (XSelectionRequestEvent*)e;
- if(0) iprint("xselect target=%d requestor=%d property=%d selection=%d\n",
- xe->target, xe->requestor, xe->property, xe->selection);
- r.xselection.property = xe->property;
- if(xe->target == targets){
- a[0] = XA_STRING;
- a[1] = utf8string;
- a[2] = text;
- a[3] = compoundtext;
- XChangeProperty(xd, xe->requestor, xe->property, XA_ATOM,
- 32, PropModeReplace, (uint8_t*)a, sizeof a);
- }else if(xe->target == XA_STRING || xe->target == utf8string || xe->target == text || xe->target == compoundtext){
- text:
- /* if the target is STRING we're supposed to reply with Latin1 XXX */
- qlock(&clip.lk);
- XChangeProperty(xd, xe->requestor, xe->property, xe->target,
- 8, PropModeReplace, (uint8_t*)clip.buf,
- strlen(clip.buf));
- qunlock(&clip.lk);
- }else{
- name = XGetAtomName(xd, xe->target);
- if(name == nil)
- iprint("XGetAtomName %d failed\n", xe->target);
- if(name){
- if(strcmp(name, "TIMESTAMP") == 0){
- /* nothing */
- }else if(strncmp(name, "image/", 6) == 0){
- /* nothing */
- }else if(strcmp(name, "text/html") == 0){
- /* nothing */
- }else if(strcmp(name, "text/plain") == 0 || strcmp(name, "text/plain;charset=UTF-8") == 0){
- goto text;
- }else
- iprint("%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)xe->target);
- }
- r.xselection.property = None;
- }
- r.xselection.display = xe->display;
- /* r.xselection.property filled above */
- r.xselection.target = xe->target;
- r.xselection.type = SelectionNotify;
- r.xselection.requestor = xe->requestor;
- r.xselection.time = xe->time;
- r.xselection.send_event = True;
- r.xselection.selection = xe->selection;
- XSendEvent(xd, xe->requestor, False, 0, &r);
- XFlush(xd);
- }
- char*
- clipread(void)
- {
- return _xgetsnarf(xsnarfcon);
- }
- int
- clipwrite(char *buf)
- {
- _xputsnarf(xsnarfcon, buf);
- return 0;
- }
|