xio.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <fcntl.h>
  6. #include <signal.h>
  7. #include <X11/Xlib.h>
  8. #include <X11/Xutil.h>
  9. #include <X11/Xatom.h>
  10. #define XK_MISCELLANY
  11. #define XK_LATIN1
  12. #include <X11/keysymdef.h>
  13. #include <sys/time.h>
  14. #include "vt.h"
  15. #include "misc.h"
  16. #include "dllist.h"
  17. #include "xio.h"
  18. #include "fdset.h"
  19. #include "lang.h"
  20. #include "icon.xbm"
  21. #include "font.h"
  22. #define WW (W*CW) /* pixel width of window */
  23. #define WH (H*CH) /* pixel hegiht of window */
  24. #define NO_SEL 999 /* sel_y1 value if no selection */
  25. #define SEL_MIN_TIME 500 /* anything shorter is a click */
  26. static struct dl_head dpys[1]; /* list of all displays */
  27. static void xio_timer(void *data, int fd);
  28. static void handle_event(struct xio *xio, int fd);
  29. static int timer_init(int argc, char **argv)
  30. {
  31. int p[2], timer_pid, i;
  32. if (pipe(p) == -1)
  33. return -1;
  34. signal(SIGPIPE, SIG_DFL);
  35. timer_pid = fork();
  36. if (timer_pid == -1)
  37. return -1;
  38. if (timer_pid > 0)
  39. {
  40. fdset_add_fd(fds, p[0], xio_timer, 0);
  41. close(p[1]);
  42. return 0;
  43. }
  44. close(p[0]);
  45. for (i = 0; i < 32; ++i)
  46. if (p[1] != i)
  47. close(i);
  48. memcpy(argv[0], "Timer", 6);
  49. for (;;)
  50. {
  51. usleep(300000);
  52. write(p[1], "*", 1);
  53. }
  54. }
  55. static int local_init(int argc, char **argv)
  56. {
  57. static int inited = 0;
  58. if (inited)
  59. return 0;
  60. if (timer_init(argc, argv) == -1)
  61. return -1;
  62. dl_init(dpys);
  63. inited = 1;
  64. return 0;
  65. }
  66. static int get_colors(struct xio *xio)
  67. {
  68. int i;
  69. XColor c;
  70. static short rgb[][3] =
  71. {
  72. { 0x0000,0x0000,0x0000 },
  73. { 0xffff,0x0000,0x0000 },
  74. { 0x0000,0xffff,0x0000 },
  75. { 0xffff,0xffff,0x0000 },
  76. { 0x0000,0x0000,0xffff },
  77. { 0xffff,0x0000,0xffff },
  78. { 0x0000,0xffff,0xffff },
  79. { 0xffff,0xffff,0xffff },
  80. { 0x7fff,0x7fff,0x7fff },
  81. { 0x7fff,0x0000,0x0000 },
  82. { 0x0000,0x7fff,0x0000 },
  83. { 0x7fff,0x7fff,0x0000 },
  84. { 0x0000,0x0000,0x7fff },
  85. { 0x7fff,0x0000,0x7fff },
  86. { 0x0000,0x7fff,0x7fff },
  87. { 0x3fff,0x3fff,0x3fff },
  88. };
  89. for (i = 0; i < 16; ++i)
  90. {
  91. c.red = rgb[i][0];
  92. c.green = rgb[i][1];
  93. c.blue = rgb[i][2];
  94. if (XAllocColor(xio->dpy, xio->cmap, &c) == 0)
  95. return -1;
  96. xio->color[i] = c.pixel;
  97. }
  98. return 0;
  99. }
  100. static int get_fonts(struct xio *xio)
  101. {
  102. GC gc;
  103. int i;
  104. unsigned char *font_bits;
  105. switch(latin1) {
  106. case LATIN1: font_bits=font1_bits; break;
  107. case LATIN2: font_bits=font2_bits; break;
  108. case KOI8: font_bits=font3_bits; break;
  109. case GREEK: font_bits=font4_bits; break;
  110. default: font_bits=font1_bits; break;
  111. }
  112. xio->font[0] = XCreateBitmapFromData(xio->dpy, xio->root,
  113. font_bits, font_width, font_height);
  114. xio->font[1] = XCreatePixmap(xio->dpy, xio->root,
  115. font_width, font_height*2, 1);
  116. gc = XCreateGC(xio->dpy, xio->font[0], 0, 0);
  117. for (i = 0; i < font_height; ++i)
  118. {
  119. XCopyArea(xio->dpy, xio->font[0], xio->font[1], gc, 0, i,
  120. font_width, 1, 0, i*2);
  121. XCopyArea(xio->dpy, xio->font[0], xio->font[1], gc, 0, i,
  122. font_width, 1, 0, i*2+1);
  123. }
  124. XFreeGC(xio->dpy, gc);
  125. return 0;
  126. }
  127. static void xlib_conn_watch(Display *dpy, void *fds, int fd, int open_flag, void *data)
  128. {
  129. if (open_flag)
  130. fdset_add_fd(fds, fd, XProcessInternalConnection, dpy);
  131. else
  132. fdset_del_fd(fds, fd);
  133. }
  134. struct xio * xio_open_dpy(char *dpy, int argc, char **argv)
  135. {
  136. XClassHint classhint[1];
  137. struct xio *xio;
  138. if (local_init(argc, argv) == -1)
  139. goto fail1;
  140. if (not(xio = malloc(sizeof(*xio))))
  141. goto fail1;
  142. if (not(xio->dpy = XOpenDisplay(dpy)))
  143. goto fail2;
  144. xio->fd = ConnectionNumber(xio->dpy);
  145. xio->argc = argc;
  146. xio->argv = argv;
  147. dl_init(xio->windows);
  148. xio->screen = DefaultScreen(xio->dpy);
  149. xio->depth = DefaultDepth(xio->dpy, xio->screen);
  150. xio->width = DisplayWidth(xio->dpy, xio->screen);
  151. xio->height = DisplayHeight(xio->dpy, xio->screen);
  152. xio->root = DefaultRootWindow(xio->dpy);
  153. xio->cmap = DefaultColormap(xio->dpy, xio->screen);
  154. xio->xa_del_win = XInternAtom(xio->dpy, "WM_DELETE_WINDOW", False);
  155. xio->xa_targets = XInternAtom(xio->dpy, "TARGETS", False);
  156. xio->xa_timestamp = XInternAtom(xio->dpy, "TIMESTAMP", False);
  157. xio->xa_multiple = XInternAtom(xio->dpy, "MULTIPLE", False);
  158. xio->xa_text = XInternAtom(xio->dpy, "TEXT", False);
  159. if (get_colors(xio) == -1)
  160. goto fail3;
  161. if (get_fonts(xio) == -1)
  162. goto fail3;
  163. if (fdset_add_fd(fds, xio->fd, handle_event, xio) == -1)
  164. goto fail3;
  165. XAddConnectionWatch(xio->dpy, PTR xlib_conn_watch, PTR fds);
  166. xio->icon = XCreateBitmapFromData(xio->dpy, xio->root,
  167. icon_bits, icon_width, icon_height);
  168. xio->group_leader = XCreateSimpleWindow(xio->dpy, xio->root,
  169. 0, 0, 1, 1, 0, 0, 0);
  170. XSetCommand(xio->dpy, xio->group_leader, xio->argv, xio->argc);
  171. classhint->res_name = "VTLeader";
  172. classhint->res_class = "AleVT";
  173. XSetClassHint(xio->dpy, xio->group_leader, classhint);
  174. dl_insert_first(dpys, xio->node);
  175. return xio;
  176. fail4:
  177. fdset_del_fd(fds, xio->fd);
  178. fail3:
  179. XCloseDisplay(xio->dpy);
  180. fail2:
  181. free(xio);
  182. fail1:
  183. return 0;
  184. }
  185. static void set_user_geometry(struct xio_win *xw, char *geom, XSizeHints *sh, int bwidth)
  186. {
  187. static int gravs[] = { NorthWestGravity, NorthEastGravity,
  188. SouthWestGravity, SouthEastGravity };
  189. int f, g = 0;
  190. f = XParseGeometry(geom, &sh->x, &sh->y, &sh->width, &sh->height);
  191. if (f & WidthValue)
  192. sh->width = sh->base_width + sh->width * sh->width_inc;
  193. if (f & HeightValue)
  194. sh->height = sh->base_height + sh->height * sh->height_inc;
  195. if (f & XNegative)
  196. g+=1, sh->x = xw->xio->width + sh->x - sh->width - bwidth;
  197. if (f & YNegative)
  198. g+=2, sh->y = xw->xio->height + sh->y - sh->height - bwidth;
  199. sh->width = bound(sh->min_width, sh->width, sh->max_width);
  200. sh->height = bound(sh->min_height, sh->height, sh->max_height);
  201. if (f & (WidthValue | HeightValue))
  202. sh->flags |= USSize;
  203. if (f & (XValue | YValue))
  204. sh->flags |= USPosition | PWinGravity;
  205. sh->win_gravity = gravs[g];
  206. }
  207. struct xio_win * xio_open_win(struct xio *xio, char *geom)
  208. {
  209. struct xio_win *xw;
  210. XSetWindowAttributes attr;
  211. XGCValues gcval;
  212. XSizeHints sizehint[1];
  213. XClassHint classhint[1];
  214. XWMHints wmhint[1];
  215. if (not(xw = malloc(sizeof(*xw))))
  216. goto fail1;
  217. xw->xio = xio;
  218. sizehint->flags = PSize | PBaseSize | PMinSize | PMaxSize | PResizeInc;
  219. sizehint->x = sizehint->y = 0;
  220. sizehint->width_inc = CW;
  221. sizehint->height_inc = CH;
  222. sizehint->base_width = 0;
  223. sizehint->base_height = 0;
  224. sizehint->min_width = 11*CW;
  225. sizehint->min_height = 1*CH;
  226. sizehint->max_width = sizehint->width = WW + CW;
  227. sizehint->max_height = sizehint->height = WH;
  228. set_user_geometry(xw, geom, sizehint, 1);
  229. attr.background_pixel = xio->color[0];
  230. attr.event_mask = KeyPressMask |
  231. ButtonPressMask|ButtonReleaseMask|Button1MotionMask |
  232. ExposureMask;
  233. xw->win = XCreateWindow(xio->dpy, xio->root,
  234. sizehint->x, sizehint->y, sizehint->width, sizehint->height, 1,
  235. CopyFromParent, CopyFromParent, CopyFromParent,
  236. CWBackPixel|CWEventMask, &attr);
  237. classhint->res_name = "VTPage";
  238. classhint->res_class = "AleVT";
  239. wmhint->flags = InputHint | StateHint | WindowGroupHint | IconPixmapHint;
  240. wmhint->input = True;
  241. wmhint->initial_state = NormalState; //IconicState;
  242. wmhint->window_group = xio->group_leader;
  243. wmhint->icon_pixmap = xio->icon;
  244. XSetWMProperties(xio->dpy, xw->win, 0,0, 0,0, sizehint, wmhint, classhint);
  245. XSetWMProtocols(xio->dpy, xw->win, &xio->xa_del_win, 1);
  246. xw->title[0] = 0;
  247. xio_title(xw, "AleVT"); // will be reset pretty soon
  248. gcval.graphics_exposures = False;
  249. xw->gc = XCreateGC(xio->dpy, xw->win, GCGraphicsExposures, &gcval);
  250. xw->tstamp = CurrentTime;
  251. xw->fg = xw->bg = -1; /* unknown colors */
  252. xw->curs_x = xw->curs_y = 999; // no cursor
  253. xw->sel_y1 = NO_SEL; /* no selection area */
  254. xw->sel_start_t = 0; /* no selection-drag active */
  255. xw->sel_set_t = 0; /* not selection owner */
  256. xw->sel_pixmap = 0; /* no selection pixmap yet */
  257. xio_clear_win(xw);
  258. xw->blink_on = xw->reveal = 0;
  259. xw->handler = 0;
  260. XMapWindow(xio->dpy, xw->win);
  261. dl_insert_first(xio->windows, xw->node);
  262. return xw;
  263. fail2:
  264. free(xw);
  265. fail1:
  266. return 0;
  267. }
  268. void xio_close_win(struct xio_win *xw, int dpy_too)
  269. {
  270. struct xio *xio = xw->xio;
  271. XDestroyWindow(xio->dpy, xw->win);
  272. dl_remove(xw->node);
  273. free(xw);
  274. if (dpy_too && dl_empty(xio->windows))
  275. xio_close_dpy(xio);
  276. }
  277. void xio_close_dpy(struct xio *xio)
  278. {
  279. while (not dl_empty(xio->windows))
  280. xio_close_win((struct xio_win *)xio->windows->first, 0);
  281. XDestroyWindow(xio->dpy, xio->group_leader);
  282. XRemoveConnectionWatch(xio->dpy, PTR xlib_conn_watch, PTR fds);
  283. fdset_del_fd(fds, xio->fd);
  284. dl_remove(xio->node);
  285. free(xio);
  286. }
  287. void xio_set_handler(struct xio_win *xw, void *handler, void *data)
  288. {
  289. xw->handler = handler;
  290. xw->data = data;
  291. }
  292. void xio_title(struct xio_win *xw, char *title)
  293. {
  294. char buf[sizeof(xw->title) + 32];
  295. if (strlen(title) >= sizeof(xw->title))
  296. return; //TODO: trimm...
  297. if (strcmp(xw->title, title) == 0)
  298. return;
  299. strcpy(xw->title, title);
  300. sprintf(buf, "AleVT " VERSION " %s", xw->title);
  301. XStoreName(xw->xio->dpy, xw->win, buf);
  302. XSetIconName(xw->xio->dpy, xw->win, xw->title);
  303. }
  304. void xio_clear_win(struct xio_win *xw)
  305. {
  306. memset(xw->ch, ' ', sizeof(xw->ch));
  307. xw->dheight = xw->blink = xw->concealed = 0;
  308. xw->hidden = xw->lhidden = 0;
  309. xw->modified = ALL_LINES;
  310. }
  311. void xio_put_line(struct xio_win *xw, int y, u8 *data)
  312. {
  313. u8 *p = xw->ch + y*W;
  314. u8 *ep = p + W;
  315. lbits yb = 1 << y;
  316. lbits x = xw->dheight;
  317. if (y < 0 || y >= H)
  318. return;
  319. if (memcmp(data, p, ep - p) == 0)
  320. return;
  321. xw->modified |= yb;
  322. xw->blink &= ~yb;
  323. xw->dheight &= ~yb;
  324. xw->concealed &= ~yb;
  325. while (p < ep)
  326. switch (*p++ = *data++)
  327. {
  328. case 0x08:
  329. xw->blink |= yb;
  330. break;
  331. case 0x0d:
  332. if (y < H-1)
  333. xw->dheight |= yb;
  334. break;
  335. case 0x18:
  336. xw->concealed |= yb;
  337. break;
  338. }
  339. if ((xw->dheight ^ x) & yb) // dheight has changed, recalc hidden
  340. {
  341. xw->hidden &= yb*2 - 1;
  342. for (; yb & ALL_LINES/2; yb *= 2)
  343. if (~xw->hidden & xw->dheight & yb)
  344. xw->hidden |= yb*2;
  345. }
  346. }
  347. void xio_put_str(struct xio_win *xw, int y, u8 *str)
  348. {
  349. u8 buf[W];
  350. int l;
  351. l = strlen(str);
  352. if (l < W)
  353. {
  354. memcpy(buf, str, l);
  355. memset(buf + l, ' ', W - l);
  356. }
  357. else
  358. memcpy(buf, str, W);
  359. xio_put_line(xw, y, buf);
  360. }
  361. static void dirty(struct xio_win *xw, int y1, int y2) // mark [y1,y2[ dirty
  362. {
  363. if (y1 >= 0 && y1 < H && y1 < y2)
  364. {
  365. if (y2 > H)
  366. y2 = H;
  367. if (xw->hidden & (1 << y1))
  368. y1--;
  369. while (y1 < y2)
  370. xw->modified |= 1 << y1++;
  371. }
  372. }
  373. int xio_get_line(struct xio_win *xw, int y, u8 *data)
  374. {
  375. if (y < 0 || y >= H)
  376. return -1;
  377. if (xw->hidden & (1 << y))
  378. y--;
  379. memcpy(data, xw->ch + y*W, 40);
  380. return 0;
  381. }
  382. void xio_set_cursor(struct xio_win *xw, int x, int y)
  383. {
  384. if (xw->curs_y >= 0 && xw->curs_y < H)
  385. dirty(xw, xw->curs_y, xw->curs_y + 1);
  386. if (x >= 0 && x < W && y >= 0 && y < H)
  387. dirty(xw, y, y + 1);
  388. else
  389. x = y = 999;
  390. xw->curs_x = x;
  391. xw->curs_y = y;
  392. }
  393. static inline void draw_char(struct xio_win *xw, Window win, int fg, int bg,
  394. int c, int dbl, int x, int y, int ry)
  395. {
  396. struct xio *xio = xw->xio;
  397. if (fg != xw->fg)
  398. XSetForeground(xio->dpy, xw->gc, xio->color[xw->fg = fg]);
  399. if (bg != xw->bg)
  400. XSetBackground(xio->dpy, xw->gc, xio->color[xw->bg = bg]);
  401. if (dbl)
  402. {
  403. XCopyPlane(xio->dpy, xio->font[1], win, xw->gc,
  404. c%32*CW, c/32*CH*2, CW, CH*2, x*CW, y*CH, 1);
  405. }
  406. else
  407. {
  408. XCopyPlane(xio->dpy, xio->font[0], win, xw->gc,
  409. c%32*CW, c/32*CH, CW, CH, x*CW, y*CH, 1);
  410. if (xw->dheight & (1<<ry))
  411. XCopyPlane(xio->dpy, xio->font[0], win, xw->gc,
  412. ' '%32*CW, ' '/32*CH, CW, CH, x*CW, y*CH+CH, 1);
  413. }
  414. }
  415. static void draw_cursor(struct xio_win *xw, int x, int y, int dbl)
  416. {
  417. struct xio *xio = xw->xio;
  418. if (xw->blink_on)
  419. XSetForeground(xio->dpy, xw->gc, xio->color[xw->fg = xw->bg ^ 8]);
  420. XDrawRectangle(xio->dpy, xw->win, xw->gc, x * CW, y * CH, CW-1,
  421. (dbl ? 2*CH : CH)-1);
  422. }
  423. void xio_update_win(struct xio_win *xw)
  424. {
  425. u8 *p = xw->ch;
  426. lbits yb, redraw;
  427. int x, y, c;
  428. if (xw->modified == 0)
  429. return;
  430. redraw = xw->modified; // all modified lines
  431. redraw |= xw->lhidden; // all previously hidden lines
  432. redraw &= ~xw->hidden;
  433. xw->lhidden = xw->hidden;
  434. xw->modified = 0;
  435. if (redraw == 0)
  436. return;
  437. for (yb = 1, y = 0; y < H; ++y, yb *= 2)
  438. if (redraw & yb)
  439. {
  440. int fg = 7, bg = 0, _fg, _bg;
  441. int dbl = 0, blk = 0, con = 0, gfx = 0, sep = 0, hld = 0;
  442. int last_ch = ' ';
  443. for (x = 0; x < W; ++x)
  444. {
  445. switch (c = *p++)
  446. {
  447. case 0x00 ... 0x07: /* alpha + foreground color */
  448. fg = c & 7;
  449. gfx = 0;
  450. con = 0;
  451. goto ctrl;
  452. case 0x08: /* flash */
  453. blk = not xw->blink_on;
  454. goto ctrl;
  455. case 0x09: /* steady */
  456. blk = 0;
  457. goto ctrl;
  458. case 0x0a: /* end box */
  459. case 0x0b: /* start box */
  460. goto ctrl;
  461. case 0x0c: /* normal height */
  462. dbl = 0;
  463. goto ctrl;
  464. case 0x0d: /* double height */
  465. dbl = y < H-1;
  466. goto ctrl;
  467. case 0x10 ... 0x17: /* graphics + foreground color */
  468. fg = c & 7;
  469. gfx = 1;
  470. con = 0;
  471. goto ctrl;
  472. case 0x18: /* conceal display */
  473. con = not xw->reveal;
  474. goto ctrl;
  475. case 0x19: /* contiguous graphics */
  476. sep = 0;
  477. goto ctrl;
  478. case 0x1a: /* separate graphics */
  479. sep = 1;
  480. goto ctrl;
  481. case 0x1c: /* black background */
  482. bg = 0;
  483. goto ctrl;
  484. case 0x1d: /* new background */
  485. bg = fg;
  486. goto ctrl;
  487. case 0x1e: /* hold graphics */
  488. hld = 1;
  489. goto ctrl;
  490. case 0x1f: /* release graphics */
  491. hld = 0;
  492. goto ctrl;
  493. case 0x0e: /* SO (reserved, double width) */
  494. case 0x0f: /* SI (reserved, double size) */
  495. c= ' '; break;
  496. case 0x1b: /* ESC (reserved) */
  497. c = ' ';
  498. break;
  499. ctrl:
  500. c = ' ';
  501. if (hld && gfx)
  502. c = last_ch;
  503. break;
  504. case 0x80 ... 0x9f: /* these aren't used */
  505. c = BAD_CHAR;
  506. break;
  507. default: /* mapped to selected font */
  508. break;
  509. }
  510. if (gfx && (c & 0xa0) == 0x20)
  511. {
  512. last_ch = c;
  513. c += (c & 0x40) ? 32 : -32;
  514. }
  515. _fg = fg;
  516. _bg = bg;
  517. if (blk)
  518. _fg |= 8;
  519. if (y >= xw->sel_y1 && y < xw->sel_y2 &&
  520. x >= xw->sel_x1 && x < xw->sel_x2)
  521. _bg |= 8;
  522. if (con)
  523. _fg = _bg;
  524. draw_char(xw, xw->win, _fg, _bg, c, dbl, x, y, y);
  525. if (y == xw->curs_y && x == xw->curs_x)
  526. draw_cursor(xw, xw->curs_x, xw->curs_y, dbl);
  527. if (xw->sel_pixmap && (_bg & 8))
  528. draw_char(xw, xw->sel_pixmap, con ? bg : fg, bg, c, dbl,
  529. x - xw->sel_x1, y - xw->sel_y1, y);
  530. }
  531. }
  532. else
  533. p += 40;
  534. }
  535. static void for_all_windows(void (*func)(struct xio_win *xw), struct xio_win *except)
  536. {
  537. struct xio *xio, *vtn;
  538. struct xio_win *xw, *vwn;
  539. for (xio = PTR dpys->first; vtn = PTR xio->node->next; xio = vtn)
  540. for (xw = PTR xio->windows->first; vwn = PTR xw->node->next; xw = vwn)
  541. if (xw != except)
  542. func(xw);
  543. }
  544. int xio_set_concealed(struct xio_win *xw, int on)
  545. {
  546. on = !!on;
  547. if (xw->reveal == on)
  548. return on;
  549. xw->reveal = on;
  550. xw->modified |= xw->concealed;
  551. return !on;
  552. }
  553. static void sel_set(struct xio_win *xw, int x1, int y1, int x2, int y2)
  554. {
  555. int t;
  556. x1 = bound(0, x1, W-1);
  557. y1 = bound(0, y1, H-1);
  558. x2 = bound(0, x2, W-1);
  559. y2 = bound(0, y2, H-1);
  560. if (x1 > x2)
  561. t = x1, x1 = x2, x2 = t;
  562. if (y1 > y2)
  563. t = y1, y1 = y2, y2 = t;
  564. dirty(xw, xw->sel_y1, xw->sel_y2);
  565. if (xw->hidden & (1 << y1))
  566. y1--;
  567. if (xw->hidden & (2 << y2))
  568. y2++;
  569. xw->sel_x1 = x1;
  570. xw->sel_y1 = y1;
  571. xw->sel_x2 = x2 + 1;
  572. xw->sel_y2 = y2 + 1;
  573. dirty(xw, xw->sel_y1, xw->sel_y2);
  574. }
  575. static void sel_abort(struct xio_win *xw)
  576. {
  577. if (xw->sel_set_t)
  578. XSetSelectionOwner(xw->xio->dpy, XA_PRIMARY, None, xw->sel_set_t);
  579. if (xw->sel_y1 != NO_SEL)
  580. dirty(xw, xw->sel_y1, xw->sel_y2);
  581. xw->sel_y1 = NO_SEL;
  582. xw->sel_set_t = 0;
  583. xw->sel_start_t = 0;
  584. }
  585. static void sel_start(struct xio_win *xw, int x, int y, Time t)
  586. {
  587. sel_abort(xw);
  588. xw->sel_start_x = x;
  589. xw->sel_start_y = y;
  590. xw->sel_start_t = t;
  591. }
  592. static void sel_move(struct xio_win *xw, int x, int y, Time t)
  593. {
  594. if (xw->sel_start_t == 0)
  595. return;
  596. if (xw->sel_y1 == NO_SEL)
  597. if (t - xw->sel_start_t < SEL_MIN_TIME)
  598. if (x == xw->sel_start_x)
  599. if (y == xw->sel_start_y)
  600. return;
  601. sel_set(xw, xw->sel_start_x, xw->sel_start_y, x, y);
  602. }
  603. static int sel_end(struct xio_win *xw, int x, int y, Time t)
  604. {
  605. sel_move(xw, x, y, t);
  606. xw->sel_start_t = 0;
  607. if (xw->sel_y1 == NO_SEL)
  608. return 0;
  609. for_all_windows(sel_abort, xw);
  610. XSetSelectionOwner(xw->xio->dpy, XA_PRIMARY, xw->win, t);
  611. if (XGetSelectionOwner(xw->xio->dpy, XA_PRIMARY) == xw->win)
  612. xw->sel_set_t = t;
  613. else
  614. sel_abort(xw);
  615. return 1;
  616. }
  617. static int sel_convert2ascii(struct xio_win *xw, u8 *buf)
  618. {
  619. u8 *d = buf;
  620. int x, y, nl = 0;
  621. for (y = xw->sel_y1; y < xw->sel_y2; y++)
  622. {
  623. u8 *s = xw->ch + y * W;
  624. int gfx = 0, con = 0;
  625. if (~xw->hidden & (1 << y))
  626. {
  627. for (x = 0; x < xw->sel_x2; ++x)
  628. {
  629. int ch, c = ' ';
  630. switch (ch = *s++)
  631. {
  632. case 0x00 ... 0x07:
  633. gfx = con = 0;
  634. break;
  635. case 0x10 ... 0x17:
  636. gfx = 1, con = 0;
  637. break;
  638. case 0x18:
  639. con = not xw->reveal;
  640. break;
  641. case 0xa0 ... 0xff:
  642. case 0x20 ... 0x7f:
  643. if (not con)
  644. if (gfx && ch != ' ' && (ch & 0xa0) == 0x20)
  645. c = '#';
  646. else if (ch == 0x7f)
  647. c = '*';
  648. else
  649. c = ch;
  650. break;
  651. }
  652. if (x >= xw->sel_x1)
  653. {
  654. if (nl)
  655. *d++ = '\n', nl = 0;
  656. *d++ = c;
  657. }
  658. }
  659. nl = 1;
  660. }
  661. }
  662. *d = 0; // not necessary
  663. return d - buf;
  664. }
  665. static Pixmap sel_convert2pixmap(struct xio_win *xw)
  666. {
  667. struct xio *xio = xw->xio;
  668. Pixmap pm;
  669. if (xw->sel_y1 == NO_SEL)
  670. return None;
  671. pm = XCreatePixmap(xio->dpy, xio->root, (xw->sel_x2 - xw->sel_x1) * CW,
  672. (xw->sel_y2 - xw->sel_y1) * CH,
  673. xio->depth);
  674. xw->sel_pixmap = pm;
  675. dirty(xw, xw->sel_y1, xw->sel_y2);
  676. xio_update_win(xw);
  677. xw->sel_pixmap = 0;
  678. return pm;
  679. }
  680. static int sel_do_conv(struct xio_win *xw, Window w, Atom type, Atom prop)
  681. {
  682. struct xio *xio = xw->xio;
  683. if (type == xio->xa_targets)
  684. {
  685. u32 atoms[6];
  686. atoms[0] = XA_STRING;
  687. atoms[1] = xio->xa_text;
  688. atoms[2] = XA_PIXMAP;
  689. atoms[3] = XA_COLORMAP;
  690. atoms[4] = xio->xa_multiple;
  691. atoms[5] = xio->xa_timestamp;
  692. XChangeProperty(xio->dpy, w, prop, type,
  693. 32, PropModeReplace, PTR atoms, NELEM(atoms));
  694. }
  695. else if (type == xio->xa_timestamp)
  696. {
  697. u32 t = xw->sel_set_t;
  698. XChangeProperty(xio->dpy, w, prop, type, 32, PropModeReplace, PTR &t, 1);
  699. }
  700. else if (type == XA_COLORMAP)
  701. {
  702. u32 t = xio->cmap;
  703. XChangeProperty(xio->dpy, w, prop, type, 32, PropModeReplace, PTR &t, 1);
  704. }
  705. else if (type == XA_STRING || type == xio->xa_text)
  706. {
  707. u8 buf[H * (W+1)];
  708. int len;
  709. len = sel_convert2ascii(xw, buf);
  710. XChangeProperty(xio->dpy, w, prop, type, 8, PropModeReplace, buf, len);
  711. }
  712. else if (type == XA_PIXMAP || type == XA_DRAWABLE)
  713. {
  714. Pixmap pm;
  715. pm = sel_convert2pixmap(xw);
  716. XChangeProperty(xio->dpy, w, prop, type, 32, PropModeReplace, PTR &pm, 1);
  717. }
  718. else if (type == xio->xa_multiple)
  719. {
  720. u32 *atoms, ty, fo, i;
  721. unsigned long n, b;
  722. if (prop != None)
  723. {
  724. if (Success == XGetWindowProperty(xio->dpy, w, prop, 0, 1024, 0,
  725. AnyPropertyType, PTR &ty, PTR &fo, &n, &b, PTR &atoms))
  726. {
  727. if (fo == 32 && n%2 == 0)
  728. {
  729. for (i = 0; i < n; i += 2)
  730. if (sel_do_conv(xw, w, atoms[i], atoms[i+1]) == None)
  731. atoms[i] = None;
  732. }
  733. XChangeProperty(xio->dpy, w, prop, type, 32, PropModeReplace,
  734. PTR atoms, n);
  735. XFree(atoms);
  736. }
  737. }
  738. }
  739. else
  740. return None;
  741. return prop;
  742. }
  743. static void sel_send(struct xio_win *xw, XSelectionRequestEvent *req)
  744. {
  745. XSelectionEvent ev[1];
  746. if (req->property == None)
  747. req->property = req->target;
  748. ev->type = SelectionNotify;
  749. ev->requestor = req->requestor;
  750. ev->selection = req->selection;
  751. ev->target = req->target;
  752. ev->property = sel_do_conv(xw, req->requestor, req->target, req->property);
  753. ev->time = req->time;
  754. XSendEvent(xw->xio->dpy, req->requestor, False, 0, PTR ev);
  755. }
  756. static void sel_retrieve(struct xio_win *xw, Window w, Atom prop, int del)
  757. {
  758. u8 *data;
  759. u32 ty, fo;
  760. unsigned long n, b;
  761. struct xio *xio = xw->xio;
  762. if (prop == None)
  763. return;
  764. if (Success == XGetWindowProperty(xio->dpy, w, prop, 0, 1024, del,
  765. AnyPropertyType, PTR &ty, PTR &fo, &n, &b, PTR &data))
  766. {
  767. if (fo == 8 && n != 0)
  768. {
  769. struct vt_event vtev[1];
  770. vtev->resource = xw;
  771. vtev->type = EV_SELECTION;
  772. vtev->i1 = n;
  773. vtev->p1 = data;
  774. xw->handler(xw->data, vtev);
  775. }
  776. XFree(data);
  777. }
  778. }
  779. void xio_cancel_selection(struct xio_win *xw)
  780. {
  781. sel_abort(xw);
  782. }
  783. void xio_query_selection(struct xio_win *xw)
  784. {
  785. struct xio *xio = xw->xio;
  786. if (XGetSelectionOwner(xio->dpy, XA_PRIMARY) == None)
  787. sel_retrieve(xw, xio->root, XA_CUT_BUFFER0, False);
  788. else
  789. {
  790. XDeleteProperty(xio->dpy, xw->win, XA_STRING);
  791. XConvertSelection(xio->dpy, XA_PRIMARY, XA_STRING,
  792. XA_STRING, xw->win, xw->tstamp);
  793. }
  794. }
  795. void xio_set_selection(struct xio_win *xw, int x1, int y1, int x2, int y2)
  796. {
  797. sel_start(xw, x1, y1, xw->tstamp - SEL_MIN_TIME);
  798. sel_end(xw, x2, y2, xw->tstamp);
  799. }
  800. static void handle_event(struct xio *xio, int fd)
  801. {
  802. struct xio_win *xw;
  803. struct vt_event vtev[1];
  804. XEvent ev[1];
  805. XNextEvent(xio->dpy, ev);
  806. for (xw = PTR xio->windows->first; xw->node->next; xw = PTR xw->node->next)
  807. if (xw->win == ev->xany.window)
  808. break;
  809. if (xw->node->next == 0)
  810. return;
  811. vtev->resource = xw;
  812. switch(ev->type)
  813. {
  814. case Expose:
  815. {
  816. int y1 = ev->xexpose.y / CH;
  817. int y2 = (ev->xexpose.y + ev->xexpose.height + CH-1) / CH;
  818. dirty(xw, y1, y2);
  819. break;
  820. }
  821. case ClientMessage:
  822. {
  823. vtev->type = EV_CLOSE;
  824. if (ev->xclient.format == 32)
  825. if ((Atom)ev->xclient.data.l[0] == xio->xa_del_win)
  826. xw->handler(xw->data, vtev);
  827. break;
  828. }
  829. case KeyPress:
  830. {
  831. unsigned char ch;
  832. KeySym k;
  833. xw->tstamp = ev->xkey.time;
  834. vtev->type = EV_KEY;
  835. vtev->i1 = 0;
  836. vtev->i2 = (ev->xkey.state & ShiftMask) != 0;
  837. if (XLookupString(&ev->xkey, &ch, 1, &k, 0))
  838. vtev->i1 = ch;
  839. else
  840. switch (k)
  841. {
  842. case XK_Left: vtev->i1 = KEY_LEFT; break;
  843. case XK_Right: vtev->i1 = KEY_RIGHT; break;
  844. case XK_Up: vtev->i1 = KEY_UP; break;
  845. case XK_Down: vtev->i1 = KEY_DOWN; break;
  846. case XK_Prior: vtev->i1 = KEY_PUP; break;
  847. case XK_Next: vtev->i1 = KEY_PDOWN; break;
  848. case XK_Delete: vtev->i1 = KEY_DEL; break;
  849. case XK_Insert: vtev->i1 = KEY_INS; break;
  850. case XK_F1: vtev->i1 = KEY_F(1); break;
  851. case XK_F2: vtev->i1 = KEY_F(2); break;
  852. case XK_F3: vtev->i1 = KEY_F(3); break;
  853. case XK_F4: vtev->i1 = KEY_F(4); break;
  854. case XK_F5: vtev->i1 = KEY_F(5); break;
  855. case XK_F6: vtev->i1 = KEY_F(6); break;
  856. case XK_F7: vtev->i1 = KEY_F(7); break;
  857. case XK_F8: vtev->i1 = KEY_F(8); break;
  858. case XK_F9: vtev->i1 = KEY_F(9); break;
  859. case XK_F10: vtev->i1 = KEY_F(10); break;
  860. case XK_F11: vtev->i1 = KEY_F(11); break;
  861. case XK_F12: vtev->i1 = KEY_F(12); break;
  862. }
  863. if (vtev->i1)
  864. xw->handler(xw->data, vtev);
  865. break;
  866. }
  867. case ButtonPress:
  868. {
  869. xw->tstamp = ev->xkey.time;
  870. ev->xbutton.x /= CW;
  871. ev->xbutton.y /= CH;
  872. if (ev->xbutton.button == Button1)
  873. sel_start(xw, ev->xbutton.x, ev->xbutton.y, ev->xbutton.time);
  874. break;
  875. }
  876. case MotionNotify:
  877. {
  878. xw->tstamp = ev->xkey.time;
  879. ev->xmotion.x /= CW;
  880. ev->xmotion.y /= CH;
  881. if (ev->xmotion.state & Button1Mask)
  882. sel_move(xw, ev->xmotion.x, ev->xmotion.y, ev->xmotion.time);
  883. break;
  884. }
  885. case ButtonRelease:
  886. {
  887. xw->tstamp = ev->xkey.time;
  888. ev->xbutton.x /= CW;
  889. ev->xbutton.y /= CH;
  890. if (ev->xbutton.button == Button1)
  891. if (sel_end(xw, ev->xbutton.x, ev->xbutton.y, ev->xbutton.time))
  892. break;
  893. vtev->type = EV_MOUSE;
  894. vtev->i1 = ev->xbutton.button;
  895. vtev->i2 = (ev->xbutton.state & ShiftMask) != 0;
  896. vtev->i3 = ev->xbutton.x;
  897. vtev->i4 = ev->xbutton.y;
  898. if (vtev->i3 >= 0 && vtev->i3 < W && vtev->i4 >= 0 && vtev->i4 < H)
  899. xw->handler(xw->data, vtev);
  900. break;
  901. }
  902. case SelectionClear:
  903. {
  904. // may be our own Owner=None due to sel_start
  905. if (xw->sel_set_t && ev->xselectionclear.time >= xw->sel_set_t)
  906. {
  907. xw->sel_set_t = 0; // no need to reset owner
  908. sel_abort(xw);
  909. }
  910. break;
  911. }
  912. case SelectionRequest:
  913. {
  914. sel_send(xw, &ev->xselectionrequest);
  915. break;
  916. }
  917. case SelectionNotify:
  918. {
  919. sel_retrieve(xw, ev->xselection.requestor, ev->xselection.property, True);
  920. break;
  921. }
  922. default:
  923. break;
  924. }
  925. }
  926. static void switch_blink_state(struct xio_win *xw)
  927. {
  928. xw->blink_on = !xw->blink_on;
  929. xw->modified |= xw->blink;
  930. dirty(xw, xw->curs_y, xw->curs_y + 1);
  931. }
  932. static void send_timer_event(struct xio_win *xw)
  933. {
  934. struct vt_event vtev[1];
  935. vtev->type = EV_TIMER;
  936. xw->handler(xw->data, vtev);
  937. }
  938. static void xio_timer(void *data, int fd)
  939. {
  940. char buf[64];
  941. read(fd, buf, sizeof(buf));
  942. for_all_windows(switch_blink_state, 0);
  943. for_all_windows(send_timer_event, 0);
  944. }
  945. void xio_event_loop(void)
  946. {
  947. struct xio *xio, *vtn;
  948. int f;
  949. while (not dl_empty(dpys))
  950. {
  951. do
  952. {
  953. for_all_windows(xio_update_win, 0);
  954. f = 0;
  955. for (xio = PTR dpys->first; vtn = PTR xio->node->next; xio = vtn)
  956. while (XPending(xio->dpy))
  957. {
  958. handle_event(xio, xio->fd);
  959. f++;
  960. }
  961. } while (f);
  962. fdset_select(fds, -1);
  963. }
  964. }