x11.c 35 KB

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