You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the Do What The Fuck You Want To
  10. * Public License, Version 2, as published by Sam Hocevar. See
  11. * http://sam.zoy.org/wtfpl/COPYING for more details.
  12. */
  13. /*
  14. * This file contains the libcaca X11 input and output driver
  15. */
  16. #include "config.h"
  17. #include "common.h"
  18. #if defined(USE_X11)
  19. #include <X11/Xlib.h>
  20. #include <X11/Xutil.h>
  21. #include <X11/keysym.h>
  22. #if defined(HAVE_X11_XKBLIB_H)
  23. # include <X11/XKBlib.h>
  24. #endif
  25. #include <stdio.h> /* BUFSIZ */
  26. #include <stdlib.h>
  27. #include "caca.h"
  28. #include "caca_internals.h"
  29. #include "cucul.h"
  30. #include "cucul_internals.h"
  31. /*
  32. * Local functions
  33. */
  34. static int x11_error_handler(Display *, XErrorEvent *);
  35. struct driver_private
  36. {
  37. Display *dpy;
  38. Window window;
  39. Pixmap pixmap;
  40. GC gc;
  41. long int event_mask;
  42. int font_width, font_height;
  43. int colors[4096];
  44. Font font;
  45. XFontStruct *font_struct;
  46. int font_offset;
  47. Cursor pointer;
  48. Atom wm_protocols;
  49. Atom wm_delete_window;
  50. #if defined(HAVE_X11_XKBLIB_H)
  51. Bool autorepeat;
  52. #endif
  53. };
  54. static int x11_init_graphics(caca_display_t *dp)
  55. {
  56. Colormap colormap;
  57. XSetWindowAttributes x11_winattr;
  58. int (*old_error_handler)(Display *, XErrorEvent *);
  59. char const *fonts[] = { NULL, "8x13bold", "fixed" }, **parser;
  60. char const *geometry;
  61. unsigned int width = dp->cv->width, height = dp->cv->height;
  62. int i;
  63. dp->drv.p = malloc(sizeof(struct driver_private));
  64. #if defined(HAVE_GETENV)
  65. geometry = getenv("CACA_GEOMETRY");
  66. if(geometry && *geometry)
  67. sscanf(geometry, "%ux%u", &width, &height);
  68. #endif
  69. _cucul_set_canvas_size(dp->cv, width ? width : 80, height ? height : 32);
  70. dp->drv.p->dpy = XOpenDisplay(NULL);
  71. if(dp->drv.p->dpy == NULL)
  72. return -1;
  73. #if defined(HAVE_GETENV)
  74. fonts[0] = getenv("CACA_FONT");
  75. if(fonts[0] && *fonts[0])
  76. parser = fonts;
  77. else
  78. #endif
  79. parser = fonts + 1;
  80. /* Ignore font errors */
  81. old_error_handler = XSetErrorHandler(x11_error_handler);
  82. /* Parse our font list */
  83. for( ; ; parser++)
  84. {
  85. if(!*parser)
  86. {
  87. XSetErrorHandler(old_error_handler);
  88. XCloseDisplay(dp->drv.p->dpy);
  89. return -1;
  90. }
  91. dp->drv.p->font = XLoadFont(dp->drv.p->dpy, *parser);
  92. if(!dp->drv.p->font)
  93. continue;
  94. dp->drv.p->font_struct = XQueryFont(dp->drv.p->dpy, dp->drv.p->font);
  95. if(!dp->drv.p->font_struct)
  96. {
  97. XUnloadFont(dp->drv.p->dpy, dp->drv.p->font);
  98. continue;
  99. }
  100. break;
  101. }
  102. /* Reset the default X11 error handler */
  103. XSetErrorHandler(old_error_handler);
  104. dp->drv.p->font_width = dp->drv.p->font_struct->max_bounds.width;
  105. dp->drv.p->font_height = dp->drv.p->font_struct->max_bounds.ascent
  106. + dp->drv.p->font_struct->max_bounds.descent;
  107. dp->drv.p->font_offset = dp->drv.p->font_struct->max_bounds.descent;
  108. colormap = DefaultColormap(dp->drv.p->dpy, DefaultScreen(dp->drv.p->dpy));
  109. for(i = 0x000; i < 0x1000; i++)
  110. {
  111. XColor color;
  112. color.red = ((i & 0xf00) >> 8) * 0x1111;
  113. color.green = ((i & 0x0f0) >> 4) * 0x1111;
  114. color.blue = (i & 0x00f) * 0x1111;
  115. XAllocColor(dp->drv.p->dpy, colormap, &color);
  116. dp->drv.p->colors[i] = color.pixel;
  117. }
  118. x11_winattr.backing_store = Always;
  119. x11_winattr.background_pixel = dp->drv.p->colors[0x000];
  120. x11_winattr.event_mask = ExposureMask | StructureNotifyMask;
  121. dp->drv.p->window =
  122. XCreateWindow(dp->drv.p->dpy, DefaultRootWindow(dp->drv.p->dpy), 0, 0,
  123. dp->cv->width * dp->drv.p->font_width,
  124. dp->cv->height * dp->drv.p->font_height,
  125. 0, 0, InputOutput, 0,
  126. CWBackingStore | CWBackPixel | CWEventMask,
  127. &x11_winattr);
  128. dp->drv.p->wm_protocols =
  129. XInternAtom(dp->drv.p->dpy, "WM_PROTOCOLS", True);
  130. dp->drv.p->wm_delete_window =
  131. XInternAtom(dp->drv.p->dpy, "WM_DELETE_WINDOW", True);
  132. if(dp->drv.p->wm_protocols != None && dp->drv.p->wm_delete_window != None)
  133. XSetWMProtocols(dp->drv.p->dpy, dp->drv.p->window,
  134. &dp->drv.p->wm_delete_window, 1);
  135. XStoreName(dp->drv.p->dpy, dp->drv.p->window, "caca for X");
  136. XSelectInput(dp->drv.p->dpy, dp->drv.p->window, StructureNotifyMask);
  137. XMapWindow(dp->drv.p->dpy, dp->drv.p->window);
  138. dp->drv.p->gc = XCreateGC(dp->drv.p->dpy, dp->drv.p->window, 0, NULL);
  139. XSetForeground(dp->drv.p->dpy, dp->drv.p->gc, dp->drv.p->colors[0x888]);
  140. XSetFont(dp->drv.p->dpy, dp->drv.p->gc, dp->drv.p->font);
  141. for(;;)
  142. {
  143. XEvent xevent;
  144. XNextEvent(dp->drv.p->dpy, &xevent);
  145. if (xevent.type == MapNotify)
  146. break;
  147. }
  148. #if defined(HAVE_X11_XKBLIB_H)
  149. /* Disable autorepeat */
  150. XkbSetDetectableAutoRepeat(dp->drv.p->dpy, True, &dp->drv.p->autorepeat);
  151. if(!dp->drv.p->autorepeat)
  152. XAutoRepeatOff(dp->drv.p->dpy);
  153. #endif
  154. dp->drv.p->event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask
  155. | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask
  156. | ExposureMask;
  157. XSelectInput(dp->drv.p->dpy, dp->drv.p->window, dp->drv.p->event_mask);
  158. XSync(dp->drv.p->dpy, False);
  159. dp->drv.p->pixmap = XCreatePixmap(dp->drv.p->dpy, dp->drv.p->window,
  160. dp->cv->width * dp->drv.p->font_width,
  161. dp->cv->height * dp->drv.p->font_height,
  162. DefaultDepth(dp->drv.p->dpy,
  163. DefaultScreen(dp->drv.p->dpy)));
  164. dp->drv.p->pointer = None;
  165. return 0;
  166. }
  167. static int x11_end_graphics(caca_display_t *dp)
  168. {
  169. XSync(dp->drv.p->dpy, False);
  170. #if defined(HAVE_X11_XKBLIB_H)
  171. if(!dp->drv.p->autorepeat)
  172. XAutoRepeatOn(dp->drv.p->dpy);
  173. #endif
  174. XFreePixmap(dp->drv.p->dpy, dp->drv.p->pixmap);
  175. XFreeFont(dp->drv.p->dpy, dp->drv.p->font_struct);
  176. XFreeGC(dp->drv.p->dpy, dp->drv.p->gc);
  177. XUnmapWindow(dp->drv.p->dpy, dp->drv.p->window);
  178. XDestroyWindow(dp->drv.p->dpy, dp->drv.p->window);
  179. XCloseDisplay(dp->drv.p->dpy);
  180. free(dp->drv.p);
  181. return 0;
  182. }
  183. static int x11_set_display_title(caca_display_t *dp, char const *title)
  184. {
  185. XStoreName(dp->drv.p->dpy, dp->drv.p->window, title);
  186. return 0;
  187. }
  188. static unsigned int x11_get_display_width(caca_display_t *dp)
  189. {
  190. return dp->cv->width * dp->drv.p->font_width;
  191. }
  192. static unsigned int x11_get_display_height(caca_display_t *dp)
  193. {
  194. return dp->cv->height * dp->drv.p->font_height;
  195. }
  196. static void x11_display(caca_display_t *dp)
  197. {
  198. unsigned int x, y, len;
  199. /* First draw the background colours. Splitting the process in two
  200. * loops like this is actually slightly faster. */
  201. for(y = 0; y < dp->cv->height; y++)
  202. {
  203. for(x = 0; x < dp->cv->width; x += len)
  204. {
  205. uint32_t *attrs = dp->cv->attrs + x + y * dp->cv->width;
  206. uint16_t bg = _cucul_attr_to_rgb12bg(*attrs);
  207. len = 1;
  208. while(x + len < dp->cv->width
  209. && _cucul_attr_to_rgb12bg(attrs[len]) == bg)
  210. len++;
  211. XSetForeground(dp->drv.p->dpy, dp->drv.p->gc,
  212. dp->drv.p->colors[bg]);
  213. XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap, dp->drv.p->gc,
  214. x * dp->drv.p->font_width, y * dp->drv.p->font_height,
  215. len * dp->drv.p->font_width, dp->drv.p->font_height);
  216. }
  217. }
  218. /* Then print the foreground characters */
  219. for(y = 0; y < dp->cv->height; y++)
  220. {
  221. unsigned int yoff = (y + 1) * dp->drv.p->font_height
  222. - dp->drv.p->font_offset;
  223. uint32_t *chars = dp->cv->chars + y * dp->cv->width;
  224. for(x = 0; x < dp->cv->width; x++, chars++)
  225. {
  226. uint32_t *attrs = dp->cv->attrs + x + y * dp->cv->width;
  227. /* Underline */
  228. if(*attrs & CUCUL_UNDERLINE)
  229. XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
  230. dp->drv.p->gc,
  231. x * dp->drv.p->font_width,
  232. (y + 1) * dp->drv.p->font_height - 1,
  233. dp->drv.p->font_width, 1);
  234. /* Skip spaces */
  235. if(*chars <= 0x00000020)
  236. continue;
  237. if(*chars == CUCUL_MAGIC_FULLWIDTH)
  238. continue;
  239. XSetForeground(dp->drv.p->dpy, dp->drv.p->gc,
  240. dp->drv.p->colors[_cucul_attr_to_rgb12fg(*attrs)]);
  241. /* Plain ASCII, no problem. */
  242. if(*chars > 0x00000020 && *chars < 0x00000080)
  243. {
  244. char ch = (uint8_t)*chars;
  245. XDrawString(dp->drv.p->dpy, dp->drv.p->pixmap, dp->drv.p->gc,
  246. x * dp->drv.p->font_width, yoff, &ch, 1);
  247. continue;
  248. }
  249. /* We want to be able to print a few special Unicode characters
  250. * such as the CP437 gradients and half blocks. For unknown
  251. * characters, just print '?'. */
  252. switch(*chars)
  253. {
  254. case 0x000000b7: /* · */
  255. XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
  256. dp->drv.p->gc,
  257. x * dp->drv.p->font_width
  258. + dp->drv.p->font_width / 2,
  259. y * dp->drv.p->font_height
  260. + dp->drv.p->font_height / 2, 2, 2);
  261. break;
  262. case 0x00002500: /* ─ */
  263. XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
  264. dp->drv.p->gc,
  265. x * dp->drv.p->font_width,
  266. y * dp->drv.p->font_height
  267. + dp->drv.p->font_height / 2 + 1,
  268. dp->drv.p->font_width, 1);
  269. break;
  270. case 0x00002580: /* ▀ */
  271. XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
  272. dp->drv.p->gc,
  273. x * dp->drv.p->font_width,
  274. y * dp->drv.p->font_height,
  275. dp->drv.p->font_width,
  276. dp->drv.p->font_height / 2);
  277. break;
  278. case 0x00002584: /* ▄ */
  279. XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
  280. dp->drv.p->gc,
  281. x * dp->drv.p->font_width,
  282. (y + 1) * dp->drv.p->font_height
  283. - dp->drv.p->font_height / 2,
  284. dp->drv.p->font_width,
  285. dp->drv.p->font_height / 2);
  286. break;
  287. case 0x00002588: /* █ */
  288. XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
  289. dp->drv.p->gc,
  290. x * dp->drv.p->font_width,
  291. y * dp->drv.p->font_height,
  292. dp->drv.p->font_width,
  293. dp->drv.p->font_height);
  294. break;
  295. case 0x0000258c: /* ▌ */
  296. XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
  297. dp->drv.p->gc,
  298. x * dp->drv.p->font_width,
  299. y * dp->drv.p->font_height,
  300. dp->drv.p->font_width / 2,
  301. dp->drv.p->font_height);
  302. break;
  303. case 0x00002590: /* ▐ */
  304. XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
  305. dp->drv.p->gc,
  306. (x + 1) * dp->drv.p->font_width
  307. - dp->drv.p->font_width / 2,
  308. y * dp->drv.p->font_height,
  309. dp->drv.p->font_width / 2,
  310. dp->drv.p->font_height);
  311. break;
  312. case 0x000025a0: /* ■ */
  313. XFillRectangle(dp->drv.p->dpy, dp->drv.p->pixmap,
  314. dp->drv.p->gc,
  315. x * dp->drv.p->font_width,
  316. y * dp->drv.p->font_height
  317. + dp->drv.p->font_height / 4,
  318. dp->drv.p->font_width,
  319. dp->drv.p->font_height / 2);
  320. break;
  321. case 0x00002593: /* ▓ */
  322. case 0x00002592: /* ▒ */
  323. case 0x00002591: /* ░ */
  324. {
  325. /* FIXME: this sucks utterly */
  326. int i, j, k = *chars - 0x00002591;
  327. for(j = dp->drv.p->font_height; j--; )
  328. for(i = dp->drv.p->font_width; i--; )
  329. {
  330. if(((i + 2 * (j & 1)) & 3) > k)
  331. continue;
  332. XDrawPoint(dp->drv.p->dpy, dp->drv.p->pixmap,
  333. dp->drv.p->gc,
  334. x * dp->drv.p->font_width + i,
  335. y * dp->drv.p->font_height + j);
  336. }
  337. break;
  338. }
  339. default:
  340. {
  341. char ch;
  342. ch = '?';
  343. XDrawString(dp->drv.p->dpy, dp->drv.p->pixmap,
  344. dp->drv.p->gc,
  345. x * dp->drv.p->font_width, yoff, &ch, 1);
  346. break;
  347. }
  348. }
  349. }
  350. }
  351. XCopyArea(dp->drv.p->dpy, dp->drv.p->pixmap, dp->drv.p->window,
  352. dp->drv.p->gc, 0, 0,
  353. dp->cv->width * dp->drv.p->font_width,
  354. dp->cv->height * dp->drv.p->font_height,
  355. 0, 0);
  356. XFlush(dp->drv.p->dpy);
  357. }
  358. static void x11_handle_resize(caca_display_t *dp)
  359. {
  360. Pixmap new_pixmap;
  361. new_pixmap = XCreatePixmap(dp->drv.p->dpy, dp->drv.p->window,
  362. dp->resize.w * dp->drv.p->font_width,
  363. dp->resize.h * dp->drv.p->font_height,
  364. DefaultDepth(dp->drv.p->dpy,
  365. DefaultScreen(dp->drv.p->dpy)));
  366. XCopyArea(dp->drv.p->dpy, dp->drv.p->pixmap, new_pixmap,
  367. dp->drv.p->gc, 0, 0,
  368. dp->resize.w * dp->drv.p->font_width,
  369. dp->resize.h * dp->drv.p->font_height, 0, 0);
  370. XFreePixmap(dp->drv.p->dpy, dp->drv.p->pixmap);
  371. dp->drv.p->pixmap = new_pixmap;
  372. }
  373. static int x11_get_event(caca_display_t *dp, caca_event_t *ev)
  374. {
  375. XEvent xevent;
  376. char key;
  377. while(XCheckWindowEvent(dp->drv.p->dpy, dp->drv.p->window,
  378. dp->drv.p->event_mask, &xevent) == True)
  379. {
  380. KeySym keysym;
  381. /* Expose event */
  382. if(xevent.type == Expose)
  383. {
  384. XCopyArea(dp->drv.p->dpy, dp->drv.p->pixmap,
  385. dp->drv.p->window, dp->drv.p->gc, 0, 0,
  386. dp->cv->width * dp->drv.p->font_width,
  387. dp->cv->height * dp->drv.p->font_height, 0, 0);
  388. continue;
  389. }
  390. /* Resize event */
  391. if(xevent.type == ConfigureNotify)
  392. {
  393. unsigned int w, h;
  394. w = (xevent.xconfigure.width + dp->drv.p->font_width / 3)
  395. / dp->drv.p->font_width;
  396. h = (xevent.xconfigure.height + dp->drv.p->font_height / 3)
  397. / dp->drv.p->font_height;
  398. if(!w || !h || (w == dp->cv->width && h == dp->cv->height))
  399. continue;
  400. dp->resize.w = w;
  401. dp->resize.h = h;
  402. dp->resize.resized = 1;
  403. continue;
  404. }
  405. /* Check for mouse motion events */
  406. if(xevent.type == MotionNotify)
  407. {
  408. unsigned int newx = xevent.xmotion.x / dp->drv.p->font_width;
  409. unsigned int newy = xevent.xmotion.y / dp->drv.p->font_height;
  410. if(newx >= dp->cv->width)
  411. newx = dp->cv->width - 1;
  412. if(newy >= dp->cv->height)
  413. newy = dp->cv->height - 1;
  414. if(dp->mouse.x == newx && dp->mouse.y == newy)
  415. continue;
  416. dp->mouse.x = newx;
  417. dp->mouse.y = newy;
  418. ev->type = CACA_EVENT_MOUSE_MOTION;
  419. ev->data.mouse.x = dp->mouse.x;
  420. ev->data.mouse.y = dp->mouse.y;
  421. return 1;
  422. }
  423. /* Check for mouse press and release events */
  424. if(xevent.type == ButtonPress)
  425. {
  426. ev->type = CACA_EVENT_MOUSE_PRESS;
  427. ev->data.mouse.button = ((XButtonEvent *)&xevent)->button;
  428. return 1;
  429. }
  430. if(xevent.type == ButtonRelease)
  431. {
  432. ev->type = CACA_EVENT_MOUSE_RELEASE;
  433. ev->data.mouse.button = ((XButtonEvent *)&xevent)->button;
  434. return 1;
  435. }
  436. /* Check for key press and release events */
  437. if(xevent.type == KeyPress)
  438. ev->type = CACA_EVENT_KEY_PRESS;
  439. else if(xevent.type == KeyRelease)
  440. ev->type = CACA_EVENT_KEY_RELEASE;
  441. else
  442. continue;
  443. if(XLookupString(&xevent.xkey, &key, 1, NULL, NULL))
  444. {
  445. ev->data.key.ch = key;
  446. ev->data.key.utf32 = key;
  447. ev->data.key.utf8[0] = key;
  448. ev->data.key.utf8[1] = '\0';
  449. return 1;
  450. }
  451. keysym = XKeycodeToKeysym(dp->drv.p->dpy, xevent.xkey.keycode, 0);
  452. switch(keysym)
  453. {
  454. case XK_F1: ev->data.key.ch = CACA_KEY_F1; break;
  455. case XK_F2: ev->data.key.ch = CACA_KEY_F2; break;
  456. case XK_F3: ev->data.key.ch = CACA_KEY_F3; break;
  457. case XK_F4: ev->data.key.ch = CACA_KEY_F4; break;
  458. case XK_F5: ev->data.key.ch = CACA_KEY_F5; break;
  459. case XK_F6: ev->data.key.ch = CACA_KEY_F6; break;
  460. case XK_F7: ev->data.key.ch = CACA_KEY_F7; break;
  461. case XK_F8: ev->data.key.ch = CACA_KEY_F8; break;
  462. case XK_F9: ev->data.key.ch = CACA_KEY_F9; break;
  463. case XK_F10: ev->data.key.ch = CACA_KEY_F10; break;
  464. case XK_F11: ev->data.key.ch = CACA_KEY_F11; break;
  465. case XK_F12: ev->data.key.ch = CACA_KEY_F12; break;
  466. case XK_F13: ev->data.key.ch = CACA_KEY_F13; break;
  467. case XK_F14: ev->data.key.ch = CACA_KEY_F14; break;
  468. case XK_F15: ev->data.key.ch = CACA_KEY_F15; break;
  469. case XK_Left: ev->data.key.ch = CACA_KEY_LEFT; break;
  470. case XK_Right: ev->data.key.ch = CACA_KEY_RIGHT; break;
  471. case XK_Up: ev->data.key.ch = CACA_KEY_UP; break;
  472. case XK_Down: ev->data.key.ch = CACA_KEY_DOWN; break;
  473. case XK_KP_Page_Up:
  474. case XK_Page_Up: ev->data.key.ch = CACA_KEY_PAGEUP; break;
  475. case XK_KP_Page_Down:
  476. case XK_Page_Down: ev->data.key.ch = CACA_KEY_PAGEDOWN; break;
  477. case XK_KP_Home:
  478. case XK_Home: ev->data.key.ch = CACA_KEY_HOME; break;
  479. case XK_KP_End:
  480. case XK_End: ev->data.key.ch = CACA_KEY_END; break;
  481. default: ev->type = CACA_EVENT_NONE; return 0;
  482. }
  483. ev->data.key.utf32 = 0;
  484. ev->data.key.utf8[0] = '\0';
  485. return 1;
  486. }
  487. while(XCheckTypedEvent(dp->drv.p->dpy, ClientMessage, &xevent))
  488. {
  489. if(xevent.xclient.message_type != dp->drv.p->wm_protocols)
  490. continue;
  491. if((Atom)xevent.xclient.data.l[0] == dp->drv.p->wm_delete_window)
  492. {
  493. ev->type = CACA_EVENT_QUIT;
  494. return 1;
  495. }
  496. }
  497. ev->type = CACA_EVENT_NONE;
  498. return 0;
  499. }
  500. static void x11_set_mouse(caca_display_t *dp, int flags)
  501. {
  502. Cursor no_ptr;
  503. Pixmap bm_no;
  504. XColor black, dummy;
  505. Colormap colormap;
  506. static char const empty[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  507. if(flags)
  508. {
  509. XDefineCursor(dp->drv.p->dpy,dp->drv.p->window, 0);
  510. return;
  511. }
  512. colormap = DefaultColormap(dp->drv.p->dpy, DefaultScreen(dp->drv.p->dpy));
  513. if(!XAllocNamedColor(dp->drv.p->dpy, colormap, "black", &black, &dummy))
  514. {
  515. return;
  516. }
  517. bm_no = XCreateBitmapFromData(dp->drv.p->dpy, dp->drv.p->window,
  518. empty, 8, 8);
  519. no_ptr = XCreatePixmapCursor(dp->drv.p->dpy, bm_no, bm_no,
  520. &black, &black, 0, 0);
  521. XDefineCursor(dp->drv.p->dpy, dp->drv.p->window, no_ptr);
  522. XFreeCursor(dp->drv.p->dpy, no_ptr);
  523. if(bm_no != None)
  524. XFreePixmap(dp->drv.p->dpy, bm_no);
  525. XFreeColors(dp->drv.p->dpy, colormap, &black.pixel, 1, 0);
  526. XSync(dp->drv.p->dpy, False);
  527. }
  528. /*
  529. * XXX: following functions are local
  530. */
  531. static int x11_error_handler(Display *dpy, XErrorEvent *xevent)
  532. {
  533. /* Ignore the error */
  534. return 0;
  535. }
  536. /*
  537. * Driver initialisation
  538. */
  539. int x11_install(caca_display_t *dp)
  540. {
  541. #if defined(HAVE_GETENV)
  542. if(!getenv("DISPLAY") || !*(getenv("DISPLAY")))
  543. return -1;
  544. #endif
  545. dp->drv.driver = CACA_DRIVER_X11;
  546. dp->drv.init_graphics = x11_init_graphics;
  547. dp->drv.end_graphics = x11_end_graphics;
  548. dp->drv.set_display_title = x11_set_display_title;
  549. dp->drv.get_display_width = x11_get_display_width;
  550. dp->drv.get_display_height = x11_get_display_height;
  551. dp->drv.display = x11_display;
  552. dp->drv.handle_resize = x11_handle_resize;
  553. dp->drv.get_event = x11_get_event;
  554. dp->drv.set_mouse = x11_set_mouse;
  555. return 0;
  556. }
  557. #endif /* USE_X11 */