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.

graphics.c 39 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413
  1. /*
  2. * libcaca ASCII-Art library
  3. * Copyright (c) 2002, 2003 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  19. * 02111-1307 USA
  20. */
  21. /** \file graphics.c
  22. * \version \$Id$
  23. * \author Sam Hocevar <sam@zoy.org>
  24. * \brief Character drawing
  25. *
  26. * This file contains character and string drawing functions.
  27. */
  28. #include "config.h"
  29. #if defined(USE_SLANG)
  30. # if defined(HAVE_SLANG_SLANG_H)
  31. # include <slang/slang.h>
  32. # else
  33. # include <slang.h>
  34. # endif
  35. #endif
  36. #if defined(USE_NCURSES)
  37. # if defined(HAVE_NCURSES_H)
  38. # include <ncurses.h>
  39. # else
  40. # include <curses.h>
  41. # endif
  42. #endif
  43. #if defined(USE_CONIO)
  44. # include <conio.h>
  45. # if defined(SCREENUPDATE_IN_PC_H)
  46. # include <pc.h>
  47. # endif
  48. #endif
  49. #if defined(USE_X11)
  50. # include <X11/Xlib.h>
  51. # if defined(HAVE_X11_XKBLIB_H)
  52. # include <X11/XKBlib.h>
  53. # endif
  54. #endif
  55. #if defined(USE_WIN32)
  56. # include <windows.h>
  57. #endif
  58. #if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME)
  59. # include <inttypes.h>
  60. #else
  61. typedef unsigned char uint8_t;
  62. #endif
  63. #include <stdio.h> /* BUFSIZ */
  64. #include <string.h>
  65. #include <stdlib.h>
  66. #if defined(HAVE_UNISTD_H)
  67. # include <unistd.h>
  68. #endif
  69. #include <stdarg.h>
  70. #if defined(HAVE_SIGNAL_H)
  71. # include <signal.h>
  72. #endif
  73. #if defined(HAVE_SYS_IOCTL_H)
  74. # include <sys/ioctl.h>
  75. #endif
  76. #include "caca.h"
  77. #include "caca_internals.h"
  78. /*
  79. * Global variables
  80. */
  81. #if !defined(_DOXYGEN_SKIP_ME)
  82. unsigned int _caca_width = 0;
  83. unsigned int _caca_height = 0;
  84. int _caca_resize = 0;
  85. int _caca_resize_event = 0;
  86. #endif
  87. /*
  88. * Local variables
  89. */
  90. #if !defined(_DOXYGEN_SKIP_ME)
  91. static uint8_t *cache_char, *cache_attr;
  92. #endif
  93. #if defined(USE_NCURSES)
  94. static int ncurses_attr[16*16];
  95. #endif
  96. #if defined(USE_SLANG)
  97. /* Tables generated by test/optipal.c */
  98. static int const slang_palette[2*16*16] =
  99. {
  100. 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0,
  101. 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 0, 8,
  102. 8, 7, 7, 8, 15, 7, 7, 15, 15, 9, 9, 15, 1, 9, 9, 1,
  103. 7, 9, 9, 7, 8, 1, 1, 8, 0, 1, 15, 10, 10, 15, 2, 10,
  104. 10, 2, 7, 10, 10, 7, 8, 2, 2, 8, 0, 2, 15, 11, 11, 15,
  105. 3, 11, 11, 3, 7, 11, 11, 7, 8, 3, 3, 8, 0, 3, 15, 12,
  106. 12, 15, 4, 12, 12, 4, 7, 12, 12, 7, 8, 4, 4, 8, 0, 4,
  107. 15, 13, 13, 15, 5, 13, 13, 5, 7, 13, 13, 7, 8, 5, 5, 8,
  108. 0, 5, 15, 14, 14, 15, 6, 14, 14, 6, 7, 14, 14, 7, 8, 6,
  109. 6, 8, 0, 6, 4, 6, 6, 4, 12, 14, 14, 12, 6, 2, 2, 6,
  110. 14, 10, 10, 14, 2, 3, 3, 2, 10, 11, 11, 10, 3, 1, 1, 3,
  111. 11, 9, 9, 11, 1, 5, 5, 1, 9, 13, 13, 9, 5, 4, 4, 5,
  112. 13, 12, 12, 13, 4, 14, 6, 12, 12, 6, 14, 4, 6, 10, 2, 14,
  113. 14, 2, 10, 6, 2, 11, 3, 10, 10, 3, 11, 2, 3, 9, 1, 11,
  114. 11, 1, 9, 3, 1, 13, 5, 9, 9, 5, 13, 1, 5, 12, 4, 13,
  115. 13, 4, 12, 5, 0, 7, 0, 15, 15, 8, 8, 15, 15, 1, 7, 1,
  116. 1, 6, 2, 5, 3, 4, 4, 3, 5, 2, 6, 1, 0, 0, 1, 1,
  117. 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 2, 2, 3, 3,
  118. 4, 4, 5, 5, 6, 6, 7, 7, 14, 9, 1, 15, 8, 9, 8, 8,
  119. 9, 9, 1, 7, 0, 9, 9, 8, 6, 9, 13, 10, 2, 15, 8, 10,
  120. 7, 2, 15, 2, 2, 7, 0, 10, 10, 8, 5, 10, 12, 11, 3, 15,
  121. 8, 11, 7, 3, 15, 3, 3, 7, 0, 11, 11, 8, 4, 11, 11, 12,
  122. 4, 15, 8, 12, 7, 4, 15, 4, 4, 7, 0, 12, 12, 8, 3, 12,
  123. 10, 13, 5, 15, 8, 13, 7, 5, 15, 5, 5, 7, 0, 13, 13, 8,
  124. 2, 13, 9, 14, 6, 15, 8, 14, 7, 6, 15, 6, 6, 7, 0, 14,
  125. 14, 8, 1, 14, 5, 6, 2, 4, 13, 14, 10, 12, 4, 2, 3, 6,
  126. 12, 10, 11, 14, 6, 3, 1, 2, 14, 11, 9, 10, 2, 1, 5, 3,
  127. 10, 9, 13, 11, 3, 5, 4, 1, 11, 13, 12, 9, 1, 4, 6, 5,
  128. 9, 12, 14, 13, 5, 14, 2, 12, 13, 6, 10, 4, 4, 10, 3, 14,
  129. 12, 2, 11, 6, 6, 11, 1, 10, 14, 3, 9, 2, 2, 9, 5, 11,
  130. 10, 1, 13, 3, 3, 13, 4, 9, 11, 5, 12, 1, 1, 12, 6, 13,
  131. 9, 4, 14, 5, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15,
  132. };
  133. static int const slang_assoc[16*16] =
  134. {
  135. 134, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
  136. 28, 135, 214, 86, 219, 91, 133, 127, 26, 23, 240, 112, 245, 117, 141, 126,
  137. 37, 211, 142, 83, 206, 132, 78, 160, 35, 237, 32, 109, 232, 140, 104, 161,
  138. 46, 87, 82, 143, 131, 215, 210, 169, 44, 113, 108, 41, 139, 241, 236, 170,
  139. 55, 222, 203, 130, 144, 94, 75, 178, 53, 248, 229, 138, 50, 120, 101, 179,
  140. 64, 90, 129, 218, 95, 145, 223, 187, 62, 116, 137, 244, 121, 59, 249, 188,
  141. 73, 128, 79, 207, 74, 202, 146, 196, 71, 136, 105, 233, 100, 228, 68, 197,
  142. 122, 153, 162, 171, 180, 189, 198, 147, 16, 25, 34, 43, 52, 61, 70, 18,
  143. 15, 27, 36, 45, 54, 63, 72, 17, 151, 155, 164, 173, 182, 191, 200, 124,
  144. 154, 22, 238, 110, 243, 115, 156, 24, 150, 152, 216, 88, 221, 93, 148, 20,
  145. 163, 235, 31, 107, 230, 165, 102, 33, 159, 213, 250, 85, 208, 157, 80, 29,
  146. 172, 111, 106, 40, 174, 239, 234, 42, 168, 89, 84, 251, 166, 217, 212, 38,
  147. 181, 246, 227, 183, 49, 118, 99, 51, 177, 224, 205, 175, 252, 96, 77, 47,
  148. 190, 114, 192, 242, 119, 58, 247, 60, 186, 92, 184, 220, 97, 253, 225, 56,
  149. 199, 201, 103, 231, 98, 226, 67, 69, 195, 193, 81, 209, 76, 204, 254, 65,
  150. 123, 149, 158, 167, 176, 185, 194, 19, 125, 21, 30, 39, 48, 57, 66, 255,
  151. };
  152. #endif
  153. #if defined(USE_CONIO)
  154. static struct text_info conio_ti;
  155. static char *conio_screen;
  156. #endif
  157. #if defined(USE_X11) && !defined(_DOXYGEN_SKIP_ME)
  158. Display *x11_dpy;
  159. Window x11_window;
  160. Pixmap x11_pixmap;
  161. GC x11_gc;
  162. long int x11_event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask
  163. | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask
  164. | ExposureMask;
  165. int x11_font_width, x11_font_height;
  166. unsigned int x11_new_width, x11_new_height;
  167. static int x11_colors[16];
  168. static Font x11_font;
  169. static XFontStruct *x11_font_struct;
  170. static int x11_font_offset;
  171. #if defined(HAVE_X11_XKBLIB_H)
  172. static Bool x11_detect_autorepeat;
  173. #endif
  174. #endif
  175. #if defined(USE_WIN32)
  176. HANDLE win32_hin, win32_hout;
  177. static HANDLE win32_front, win32_back;
  178. static CHAR_INFO *win32_buffer;
  179. static int const win32_fg_palette[] =
  180. {
  181. 0,
  182. FOREGROUND_BLUE,
  183. FOREGROUND_GREEN,
  184. FOREGROUND_GREEN | FOREGROUND_BLUE,
  185. FOREGROUND_RED,
  186. FOREGROUND_RED | FOREGROUND_BLUE,
  187. FOREGROUND_RED | FOREGROUND_GREEN,
  188. FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
  189. FOREGROUND_INTENSITY,
  190. FOREGROUND_INTENSITY | FOREGROUND_BLUE,
  191. FOREGROUND_INTENSITY | FOREGROUND_GREEN,
  192. FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE,
  193. FOREGROUND_INTENSITY | FOREGROUND_RED,
  194. FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE,
  195. FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN,
  196. FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
  197. };
  198. static int const win32_bg_palette[] =
  199. {
  200. 0,
  201. BACKGROUND_BLUE,
  202. BACKGROUND_GREEN,
  203. BACKGROUND_GREEN | BACKGROUND_BLUE,
  204. BACKGROUND_RED,
  205. BACKGROUND_RED | BACKGROUND_BLUE,
  206. BACKGROUND_RED | BACKGROUND_GREEN,
  207. BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
  208. BACKGROUND_INTENSITY,
  209. BACKGROUND_INTENSITY | BACKGROUND_BLUE,
  210. BACKGROUND_INTENSITY | BACKGROUND_GREEN,
  211. BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE,
  212. BACKGROUND_INTENSITY | BACKGROUND_RED,
  213. BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE,
  214. BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN,
  215. BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
  216. };
  217. #endif
  218. static char *_caca_empty_line;
  219. static char *_caca_scratch_line;
  220. static unsigned int _caca_delay;
  221. static unsigned int _caca_rendertime;
  222. #if defined(OPTIMISE_SLANG_PALETTE)
  223. static int _caca_fgisbg = 0;
  224. #endif
  225. static enum caca_color _caca_fgcolor = CACA_COLOR_LIGHTGRAY;
  226. static enum caca_color _caca_bgcolor = CACA_COLOR_BLACK;
  227. /*
  228. * Local functions
  229. */
  230. static void caca_handle_resize(void);
  231. #if defined(USE_SLANG)
  232. static void slang_init_palette(void);
  233. #endif
  234. #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
  235. static RETSIGTYPE sigwinch_handler(int);
  236. #endif
  237. #if defined(USE_X11)
  238. static int x11_error_handler(Display *, XErrorEvent *);
  239. #endif
  240. /** \brief Set the default colour pair.
  241. *
  242. * This function sets the default colour pair. String functions such as
  243. * caca_printf() and graphical primitive functions such as caca_draw_line()
  244. * will use these colour pairs.
  245. *
  246. * \param fgcolor The requested foreground colour.
  247. * \param bgcolor The requested background colour.
  248. */
  249. void caca_set_color(enum caca_color fgcolor, enum caca_color bgcolor)
  250. {
  251. if(fgcolor < 0 || fgcolor > 15 || bgcolor < 0 || bgcolor > 15)
  252. return;
  253. _caca_fgcolor = fgcolor;
  254. _caca_bgcolor = bgcolor;
  255. switch(_caca_driver)
  256. {
  257. #if defined(USE_SLANG)
  258. case CACA_DRIVER_SLANG:
  259. #if defined(OPTIMISE_SLANG_PALETTE)
  260. /* If foreground == background, discard this colour pair. Functions
  261. * such as caca_putchar will print spaces instead of characters */
  262. if(fgcolor != bgcolor)
  263. _caca_fgisbg = 0;
  264. else
  265. {
  266. _caca_fgisbg = 1;
  267. if(fgcolor == CACA_COLOR_BLACK)
  268. fgcolor = CACA_COLOR_WHITE;
  269. else if(fgcolor == CACA_COLOR_WHITE
  270. || fgcolor <= CACA_COLOR_LIGHTGRAY)
  271. fgcolor = CACA_COLOR_BLACK;
  272. else
  273. fgcolor = CACA_COLOR_WHITE;
  274. }
  275. #endif
  276. #if defined(OPTIMISE_SLANG_PALETTE)
  277. SLsmg_set_color(slang_assoc[fgcolor + 16 * bgcolor]);
  278. #else
  279. SLsmg_set_color(fgcolor + 16 * bgcolor);
  280. #endif
  281. break;
  282. #endif
  283. #if defined(USE_NCURSES)
  284. case CACA_DRIVER_NCURSES:
  285. attrset(ncurses_attr[fgcolor + 16 * bgcolor]);
  286. break;
  287. #endif
  288. #if defined(USE_CONIO)
  289. case CACA_DRIVER_CONIO:
  290. textbackground(bgcolor);
  291. textcolor(fgcolor);
  292. break;
  293. #endif
  294. #if defined(USE_X11)
  295. case CACA_DRIVER_X11:
  296. /* Nothing to do */
  297. break;
  298. #endif
  299. #if defined(USE_WIN32)
  300. case CACA_DRIVER_WIN32:
  301. /* Nothing to do */
  302. break;
  303. #endif
  304. default:
  305. break;
  306. }
  307. }
  308. /** \brief Get the current foreground colour.
  309. *
  310. * This function returns the current foreground colour that was set with
  311. * caca_set_color().
  312. *
  313. * \return The current foreground colour.
  314. */
  315. enum caca_color caca_get_fg_color(void)
  316. {
  317. return _caca_fgcolor;
  318. }
  319. /** \brief Get the current background colour.
  320. *
  321. * This function returns the current background colour that was set with
  322. * caca_set_color().
  323. *
  324. * \return The current background colour.
  325. */
  326. enum caca_color caca_get_bg_color(void)
  327. {
  328. return _caca_bgcolor;
  329. }
  330. /** \brief Print a character.
  331. *
  332. * This function prints a character at the given coordinates, using the
  333. * default foreground and background values. If the coordinates are outside
  334. * the screen boundaries, nothing is printed.
  335. *
  336. * \param x X coordinate.
  337. * \param y Y coordinate.
  338. * \param c The character to print.
  339. */
  340. void caca_putchar(int x, int y, char c)
  341. {
  342. #if defined(USE_CONIO)
  343. char *data;
  344. #endif
  345. if(x < 0 || x >= (int)_caca_width ||
  346. y < 0 || y >= (int)_caca_height)
  347. return;
  348. cache_char[x + y * _caca_width] = c;
  349. cache_attr[x + y * _caca_width] = (_caca_bgcolor << 4) | _caca_fgcolor;
  350. switch(_caca_driver)
  351. {
  352. #if defined(USE_SLANG)
  353. case CACA_DRIVER_SLANG:
  354. SLsmg_gotorc(y, x);
  355. #if defined(OPTIMISE_SLANG_PALETTE)
  356. if(_caca_fgisbg)
  357. SLsmg_write_char(' ');
  358. else
  359. #endif
  360. SLsmg_write_char(c);
  361. break;
  362. #endif
  363. #if defined(USE_NCURSES)
  364. case CACA_DRIVER_NCURSES:
  365. move(y, x);
  366. addch(c);
  367. break;
  368. #endif
  369. #if defined(USE_CONIO)
  370. case CACA_DRIVER_CONIO:
  371. data = conio_screen + 2 * (x + y * _caca_width);
  372. data[0] = c;
  373. data[1] = (_caca_bgcolor << 4) | _caca_fgcolor;
  374. break;
  375. #endif
  376. #if defined(USE_X11)
  377. case CACA_DRIVER_X11:
  378. break;
  379. #endif
  380. #if defined(USE_WIN32)
  381. case CACA_DRIVER_WIN32:
  382. break;
  383. #endif
  384. default:
  385. break;
  386. }
  387. }
  388. /** \brief Print a string.
  389. *
  390. * This function prints a string at the given coordinates, using the
  391. * default foreground and background values. The coordinates may be outside
  392. * the screen boundaries (eg. a negative Y coordinate) and the string will
  393. * be cropped accordingly if it is too long.
  394. *
  395. * \param x X coordinate.
  396. * \param y Y coordinate.
  397. * \param s The string to print.
  398. */
  399. void caca_putstr(int x, int y, char const *s)
  400. {
  401. char *charbuf;
  402. char *attrbuf;
  403. char const *t;
  404. unsigned int len;
  405. if(y < 0 || y >= (int)_caca_height || x >= (int)_caca_width)
  406. return;
  407. len = strlen(s);
  408. if(x < 0)
  409. {
  410. if(len < (unsigned int)-x)
  411. return;
  412. len -= -x;
  413. s += -x;
  414. x = 0;
  415. }
  416. if(x + len >= _caca_width)
  417. {
  418. len = _caca_width - x;
  419. memcpy(_caca_scratch_line, s, len);
  420. _caca_scratch_line[len] = '\0';
  421. s = _caca_scratch_line;
  422. }
  423. charbuf = cache_char + x + y * _caca_width;
  424. attrbuf = cache_attr + x + y * _caca_width;
  425. t = s;
  426. while(*t)
  427. {
  428. *charbuf++ = *t++;
  429. *attrbuf++ = (_caca_bgcolor << 4) | _caca_fgcolor;
  430. }
  431. switch(_caca_driver)
  432. {
  433. #if defined(USE_SLANG)
  434. case CACA_DRIVER_SLANG:
  435. SLsmg_gotorc(y, x);
  436. #if defined(OPTIMISE_SLANG_PALETTE)
  437. if(_caca_fgisbg)
  438. SLsmg_write_string(_caca_empty_line + _caca_width - len);
  439. else
  440. #endif
  441. {
  442. union { char *ch; const char *constch; } u;
  443. u.constch = s;
  444. SLsmg_write_string(u.ch);
  445. }
  446. break;
  447. #endif
  448. #if defined(USE_NCURSES)
  449. case CACA_DRIVER_NCURSES:
  450. move(y, x);
  451. addstr(s);
  452. break;
  453. #endif
  454. #if defined(USE_CONIO)
  455. case CACA_DRIVER_CONIO:
  456. charbuf = conio_screen + 2 * (x + y * _caca_width);
  457. while(*s)
  458. {
  459. *charbuf++ = *s++;
  460. *charbuf++ = (_caca_bgcolor << 4) | _caca_fgcolor;
  461. }
  462. break;
  463. #endif
  464. #if defined(USE_X11)
  465. case CACA_DRIVER_X11:
  466. break;
  467. #endif
  468. #if defined(USE_WIN32)
  469. case CACA_DRIVER_WIN32:
  470. break;
  471. #endif
  472. default:
  473. break;
  474. }
  475. }
  476. /** \brief Format a string.
  477. *
  478. * This function formats a string at the given coordinates, using the
  479. * default foreground and background values. The coordinates may be outside
  480. * the screen boundaries (eg. a negative Y coordinate) and the string will
  481. * be cropped accordingly if it is too long. The syntax of the format
  482. * string is the same as for the C printf() function.
  483. *
  484. * \param x X coordinate.
  485. * \param y Y coordinate.
  486. * \param format The format string to print.
  487. * \param ... Arguments to the format string.
  488. */
  489. void caca_printf(int x, int y, char const *format, ...)
  490. {
  491. char tmp[BUFSIZ];
  492. char *buf = tmp;
  493. va_list args;
  494. if(y < 0 || y >= (int)_caca_height || x >= (int)_caca_width)
  495. return;
  496. if(_caca_width - x + 1 > BUFSIZ)
  497. buf = malloc(_caca_width - x + 1);
  498. va_start(args, format);
  499. #if defined(HAVE_VSNPRINTF)
  500. vsnprintf(buf, _caca_width - x + 1, format, args);
  501. #else
  502. vsprintf(buf, format, args);
  503. #endif
  504. buf[_caca_width - x] = '\0';
  505. va_end(args);
  506. caca_putstr(x, y, buf);
  507. if(buf != tmp)
  508. free(buf);
  509. }
  510. /** \brief Get the screen.
  511. *
  512. * This function fills a byte array with the character values.
  513. */
  514. void caca_get_screen(char *buffer)
  515. {
  516. unsigned int x, y;
  517. for(y = 0; y < _caca_height; y++)
  518. {
  519. for(x = 0; x < _caca_width; x++)
  520. {
  521. *buffer++ = cache_attr[x + y * _caca_width];
  522. *buffer++ = cache_char[x + y * _caca_width];
  523. }
  524. }
  525. }
  526. /** \brief Clear the screen.
  527. *
  528. * This function clears the screen using a black background.
  529. */
  530. void caca_clear(void)
  531. {
  532. enum caca_color oldfg = caca_get_fg_color();
  533. enum caca_color oldbg = caca_get_bg_color();
  534. int y = _caca_height;
  535. caca_set_color(CACA_COLOR_LIGHTGRAY, CACA_COLOR_BLACK);
  536. /* We could use SLsmg_cls() etc., but drawing empty lines is much faster */
  537. while(y--)
  538. caca_putstr(0, y, _caca_empty_line);
  539. caca_set_color(oldfg, oldbg);
  540. }
  541. #if !defined(_DOXYGEN_SKIP_ME)
  542. int _caca_init_graphics(void)
  543. {
  544. #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
  545. signal(SIGWINCH, sigwinch_handler);
  546. #endif
  547. #if defined(USE_SLANG)
  548. if(_caca_driver == CACA_DRIVER_SLANG)
  549. {
  550. slang_init_palette();
  551. /* Disable alt charset support so that we get a chance to have all
  552. * 256 colour pairs */
  553. SLtt_Has_Alt_Charset = 0;
  554. _caca_width = SLtt_Screen_Cols;
  555. _caca_height = SLtt_Screen_Rows;
  556. }
  557. else
  558. #endif
  559. #if defined(USE_NCURSES)
  560. if(_caca_driver == CACA_DRIVER_NCURSES)
  561. {
  562. static int curses_colors[] =
  563. {
  564. /* Standard curses colours */
  565. COLOR_BLACK,
  566. COLOR_BLUE,
  567. COLOR_GREEN,
  568. COLOR_CYAN,
  569. COLOR_RED,
  570. COLOR_MAGENTA,
  571. COLOR_YELLOW,
  572. COLOR_WHITE,
  573. /* Extra values for xterm-16color */
  574. COLOR_BLACK + 8,
  575. COLOR_BLUE + 8,
  576. COLOR_GREEN + 8,
  577. COLOR_CYAN + 8,
  578. COLOR_RED + 8,
  579. COLOR_MAGENTA + 8,
  580. COLOR_YELLOW + 8,
  581. COLOR_WHITE + 8
  582. };
  583. int fg, bg, max;
  584. /* Activate colour */
  585. start_color();
  586. /* If COLORS == 16, it means the terminal supports full bright colours
  587. * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
  588. * we can build 16*16 colour pairs.
  589. * If COLORS == 8, it means the terminal does not know about bright
  590. * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
  591. * and \e[5m). We can only build 8*8 colour pairs. */
  592. max = COLORS >= 16 ? 16 : 8;
  593. for(bg = 0; bg < max; bg++)
  594. for(fg = 0; fg < max; fg++)
  595. {
  596. /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
  597. * is light gray on black, since some terminals don't like
  598. * this colour pair to be redefined. */
  599. int col = ((max + 7 - fg) % max) + max * bg;
  600. init_pair(col, curses_colors[fg], curses_colors[bg]);
  601. ncurses_attr[fg + 16 * bg] = COLOR_PAIR(col);
  602. if(max == 8)
  603. {
  604. /* Bright fg on simple bg */
  605. ncurses_attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
  606. /* Simple fg on bright bg */
  607. ncurses_attr[fg + 16 * (bg + 8)] = A_BLINK
  608. | COLOR_PAIR(col);
  609. /* Bright fg on bright bg */
  610. ncurses_attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
  611. | COLOR_PAIR(col);
  612. }
  613. }
  614. _caca_width = COLS;
  615. _caca_height = LINES;
  616. }
  617. else
  618. #endif
  619. #if defined(USE_CONIO)
  620. if(_caca_driver == CACA_DRIVER_CONIO)
  621. {
  622. gettextinfo(&conio_ti);
  623. conio_screen = malloc(2 * conio_ti.screenwidth
  624. * conio_ti.screenheight * sizeof(char));
  625. if(conio_screen == NULL)
  626. return -1;
  627. # if defined(SCREENUPDATE_IN_PC_H)
  628. ScreenRetrieve(conio_screen);
  629. # else
  630. /* FIXME */
  631. # endif
  632. _caca_width = conio_ti.screenwidth;
  633. _caca_height = conio_ti.screenheight;
  634. }
  635. else
  636. #endif
  637. #if defined(USE_X11)
  638. if(_caca_driver == CACA_DRIVER_X11)
  639. {
  640. static int x11_palette[] =
  641. {
  642. /* Standard curses colours */
  643. 0x0, 0x0, 0x0,
  644. 0x0, 0x0, 0x8000,
  645. 0x0, 0x8000, 0x0,
  646. 0x0, 0x8000, 0x8000,
  647. 0x8000, 0x0, 0x0,
  648. 0x8000, 0x0, 0x8000,
  649. 0x8000, 0x8000, 0x0,
  650. 0x8000, 0x8000, 0x8000,
  651. /* Extra values for xterm-16color */
  652. 0x4000, 0x4000, 0x4000,
  653. 0x4000, 0x4000, 0xffff,
  654. 0x4000, 0xffff, 0x4000,
  655. 0x4000, 0xffff, 0xffff,
  656. 0xffff, 0x4000, 0x4000,
  657. 0xffff, 0x4000, 0xffff,
  658. 0xffff, 0xffff, 0x4000,
  659. 0xffff, 0xffff, 0xffff,
  660. };
  661. Colormap colormap;
  662. XSetWindowAttributes x11_winattr;
  663. int (*old_error_handler)(Display *, XErrorEvent *);
  664. char const *font_name = "8x13bold";
  665. int i;
  666. if(getenv("CACA_GEOMETRY") && *(getenv("CACA_GEOMETRY")))
  667. sscanf(getenv("CACA_GEOMETRY"),
  668. "%ux%u", &_caca_width, &_caca_height);
  669. if(!_caca_width)
  670. _caca_width = 80;
  671. if(!_caca_height)
  672. _caca_height = 32;
  673. x11_dpy = XOpenDisplay(NULL);
  674. if(x11_dpy == NULL)
  675. return -1;
  676. if(getenv("CACA_FONT") && *(getenv("CACA_FONT")))
  677. font_name = getenv("CACA_FONT");
  678. /* Ignore font errors */
  679. old_error_handler = XSetErrorHandler(x11_error_handler);
  680. x11_font = XLoadFont(x11_dpy, font_name);
  681. if(!x11_font)
  682. {
  683. XCloseDisplay(x11_dpy);
  684. return -1;
  685. }
  686. x11_font_struct = XQueryFont(x11_dpy, x11_font);
  687. if(!x11_font_struct)
  688. {
  689. XUnloadFont(x11_dpy, x11_font);
  690. XCloseDisplay(x11_dpy);
  691. return -1;
  692. }
  693. /* Reset the default X11 error handler */
  694. XSetErrorHandler(old_error_handler);
  695. x11_font_width = x11_font_struct->max_bounds.width;
  696. x11_font_height = x11_font_struct->max_bounds.ascent
  697. + x11_font_struct->max_bounds.descent;
  698. x11_font_offset = x11_font_struct->max_bounds.descent;
  699. colormap = DefaultColormap(x11_dpy, DefaultScreen(x11_dpy));
  700. for(i = 0; i < 16; i++)
  701. {
  702. XColor color;
  703. color.red = x11_palette[i * 3];
  704. color.green = x11_palette[i * 3 + 1];
  705. color.blue = x11_palette[i * 3 + 2];
  706. XAllocColor(x11_dpy, colormap, &color);
  707. x11_colors[i] = color.pixel;
  708. }
  709. x11_winattr.backing_store = Always;
  710. x11_winattr.background_pixel = x11_colors[0];
  711. x11_winattr.event_mask = ExposureMask | StructureNotifyMask;
  712. x11_window = XCreateWindow(x11_dpy, DefaultRootWindow(x11_dpy), 0, 0,
  713. _caca_width * x11_font_width,
  714. _caca_height * x11_font_height,
  715. 0, 0, InputOutput, 0,
  716. CWBackingStore | CWBackPixel | CWEventMask,
  717. &x11_winattr);
  718. XStoreName(x11_dpy, x11_window, "caca for X");
  719. XSelectInput(x11_dpy, x11_window, StructureNotifyMask);
  720. XMapWindow(x11_dpy, x11_window);
  721. x11_gc = XCreateGC(x11_dpy, x11_window, 0, NULL);
  722. XSetForeground(x11_dpy, x11_gc, x11_colors[15]);
  723. XSetFont(x11_dpy, x11_gc, x11_font);
  724. for(;;)
  725. {
  726. XEvent event;
  727. XNextEvent(x11_dpy, &event);
  728. if (event.type == MapNotify)
  729. break;
  730. }
  731. /* Disable autorepeat */
  732. #if defined(HAVE_X11_XKBLIB_H)
  733. XkbSetDetectableAutoRepeat(x11_dpy, True, &x11_detect_autorepeat);
  734. if(!x11_detect_autorepeat)
  735. XAutoRepeatOff(x11_dpy);
  736. #endif
  737. XSelectInput(x11_dpy, x11_window, x11_event_mask);
  738. XSync(x11_dpy, False);
  739. x11_pixmap = XCreatePixmap(x11_dpy, x11_window,
  740. _caca_width * x11_font_width,
  741. _caca_height * x11_font_height,
  742. DefaultDepth(x11_dpy,
  743. DefaultScreen(x11_dpy)));
  744. x11_new_width = x11_new_height = 0;
  745. }
  746. else
  747. #endif
  748. #if defined(USE_WIN32)
  749. if(_caca_driver == CACA_DRIVER_WIN32)
  750. {
  751. CONSOLE_CURSOR_INFO cci;
  752. CONSOLE_SCREEN_BUFFER_INFO csbi;
  753. COORD size;
  754. win32_front = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
  755. 0, NULL,
  756. CONSOLE_TEXTMODE_BUFFER, NULL);
  757. if(!win32_front || win32_front == INVALID_HANDLE_VALUE)
  758. return -1;
  759. win32_back = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
  760. 0, NULL,
  761. CONSOLE_TEXTMODE_BUFFER, NULL);
  762. if(!win32_back || win32_back == INVALID_HANDLE_VALUE)
  763. return -1;
  764. if(!GetConsoleScreenBufferInfo(win32_hout, &csbi))
  765. return -1;
  766. /* Sample code to get the biggest possible window */
  767. //size = GetLargestConsoleWindowSize(win32_hout);
  768. _caca_width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
  769. _caca_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
  770. size.X = _caca_width;
  771. size.Y = _caca_height;
  772. SetConsoleScreenBufferSize(win32_front, size);
  773. SetConsoleScreenBufferSize(win32_back, size);
  774. SetConsoleMode(win32_front, 0);
  775. SetConsoleMode(win32_back, 0);
  776. GetConsoleCursorInfo(win32_front, &cci);
  777. cci.dwSize = 0;
  778. cci.bVisible = FALSE;
  779. SetConsoleCursorInfo(win32_front, &cci);
  780. SetConsoleCursorInfo(win32_back, &cci);
  781. SetConsoleActiveScreenBuffer(win32_front);
  782. win32_buffer = malloc(_caca_width * _caca_height * sizeof(CHAR_INFO));
  783. if(win32_buffer == NULL)
  784. return -1;
  785. }
  786. else
  787. #endif
  788. {
  789. /* Dummy */
  790. }
  791. cache_char = malloc(_caca_width * _caca_height * sizeof(uint8_t));
  792. if(cache_char == NULL)
  793. return -1;
  794. cache_attr = malloc(_caca_width * _caca_height * sizeof(uint8_t));
  795. if(cache_attr == NULL)
  796. {
  797. free(cache_char);
  798. return -1;
  799. }
  800. memset(cache_char, 0, _caca_width * _caca_height * sizeof(uint8_t));
  801. memset(cache_attr, 0, _caca_width * _caca_height * sizeof(uint8_t));
  802. _caca_empty_line = malloc(_caca_width + 1);
  803. memset(_caca_empty_line, ' ', _caca_width);
  804. _caca_empty_line[_caca_width] = '\0';
  805. _caca_scratch_line = malloc(_caca_width + 1);
  806. _caca_delay = 0;
  807. _caca_rendertime = 0;
  808. return 0;
  809. }
  810. int _caca_end_graphics(void)
  811. {
  812. free(cache_char);
  813. free(cache_attr);
  814. #if defined(USE_SLANG)
  815. /* Nothing to do */
  816. #endif
  817. #if defined(USE_NCURSES)
  818. /* Nothing to do */
  819. #endif
  820. #if defined(USE_CONIO)
  821. if(_caca_driver == CACA_DRIVER_CONIO)
  822. {
  823. free(conio_screen);
  824. }
  825. else
  826. #endif
  827. #if defined(USE_X11)
  828. if(_caca_driver == CACA_DRIVER_X11)
  829. {
  830. XSync(x11_dpy, False);
  831. #if defined(HAVE_X11_XKBLIB_H)
  832. if(!x11_detect_autorepeat)
  833. XAutoRepeatOn(x11_dpy);
  834. #endif
  835. XFreePixmap(x11_dpy, x11_pixmap);
  836. XFreeFont(x11_dpy, x11_font_struct);
  837. XFreeGC(x11_dpy, x11_gc);
  838. XUnmapWindow(x11_dpy, x11_window);
  839. XDestroyWindow(x11_dpy, x11_window);
  840. XCloseDisplay(x11_dpy);
  841. }
  842. else
  843. #endif
  844. #if defined(USE_WIN32)
  845. if(_caca_driver == CACA_DRIVER_WIN32)
  846. {
  847. SetConsoleActiveScreenBuffer(win32_hout);
  848. CloseHandle(win32_back);
  849. CloseHandle(win32_front);
  850. }
  851. else
  852. #endif
  853. {
  854. /* Dummy */
  855. }
  856. free(_caca_empty_line);
  857. return 0;
  858. }
  859. #endif /* _DOXYGEN_SKIP_ME */
  860. /** \brief Set the window title.
  861. *
  862. * If libcaca runs in a window, try to change its title. This works with
  863. * the X11 and Win32 drivers.
  864. *
  865. * \param title The desired window title.
  866. * \return 0 upon success, a non-zero value if an error occurs.
  867. */
  868. int caca_set_window_title(char const *title)
  869. {
  870. #if defined(USE_X11)
  871. if(_caca_driver == CACA_DRIVER_X11)
  872. {
  873. XStoreName(x11_dpy, x11_window, title);
  874. }
  875. else
  876. #endif
  877. #if defined(USE_WIN32)
  878. if(_caca_driver == CACA_DRIVER_WIN32)
  879. {
  880. SetConsoleTitle(title);
  881. }
  882. else
  883. #endif
  884. {
  885. /* Not supported */
  886. return -1;
  887. }
  888. return 0;
  889. }
  890. /** \brief Get the window width.
  891. *
  892. * If libcaca runs in a window, get the usable window width. This value can
  893. * be used for aspect ratio calculation. If libcaca does not run in a window
  894. * or if there is no way to know the font size, assume a 6x10 font is being
  895. * used. Note that the units are not necessarily pixels.
  896. *
  897. * \return The window width.
  898. */
  899. unsigned int caca_get_window_width(void)
  900. {
  901. #if defined(USE_X11)
  902. if(_caca_driver == CACA_DRIVER_X11)
  903. {
  904. return _caca_width * x11_font_width;
  905. }
  906. else
  907. #endif
  908. #if defined(USE_WIN32)
  909. if(_caca_driver == CACA_DRIVER_WIN32)
  910. {
  911. /* FIXME */
  912. }
  913. else
  914. #endif
  915. {
  916. /* Dummy */
  917. }
  918. /* Fallback to a 6x10 font */
  919. return _caca_width * 6;
  920. }
  921. /** \brief Get the window height.
  922. *
  923. * If libcaca runs in a window, get the usable window height. This value can
  924. * be used for aspect ratio calculation. If libcaca does not run in a window
  925. * or if there is no way to know the font size, assume a 6x10 font is being
  926. * used. Note that the units are not necessarily pixels.
  927. *
  928. * \return The window height.
  929. */
  930. unsigned int caca_get_window_height(void)
  931. {
  932. #if defined(USE_X11)
  933. if(_caca_driver == CACA_DRIVER_X11)
  934. {
  935. return _caca_height * x11_font_height;
  936. }
  937. else
  938. #endif
  939. #if defined(USE_WIN32)
  940. if(_caca_driver == CACA_DRIVER_WIN32)
  941. {
  942. /* FIXME */
  943. }
  944. else
  945. #endif
  946. {
  947. /* Dummy */
  948. }
  949. /* Fallback to a 6x10 font */
  950. return _caca_height * 10;
  951. }
  952. /** \brief Set the refresh delay.
  953. *
  954. * This function sets the refresh delay in microseconds. The refresh delay
  955. * is used by caca_refresh() to achieve constant framerate. See the
  956. * caca_refresh() documentation for more details.
  957. *
  958. * If the argument is zero, constant framerate is disabled. This is the
  959. * default behaviour.
  960. *
  961. * \param usec The refresh delay in microseconds.
  962. */
  963. void caca_set_delay(unsigned int usec)
  964. {
  965. _caca_delay = usec;
  966. }
  967. /** \brief Get the average rendering time.
  968. *
  969. * This function returns the average rendering time, which is the average
  970. * measured time between two caca_refresh() calls, in microseconds. If
  971. * constant framerate was activated by calling caca_set_delay(), the average
  972. * rendering time will not be considerably shorter than the requested delay
  973. * even if the real rendering time was shorter.
  974. *
  975. * \return The render time in microseconds.
  976. */
  977. unsigned int caca_get_rendertime(void)
  978. {
  979. return _caca_rendertime;
  980. }
  981. /** \brief Flush pending changes and redraw the screen.
  982. *
  983. * This function flushes all graphical operations and prints them to the
  984. * screen. Nothing will show on the screen until caca_refresh() is
  985. * called.
  986. *
  987. * If caca_set_delay() was called with a non-zero value, caca_refresh()
  988. * will use that value to achieve constant framerate: if two consecutive
  989. * calls to caca_refresh() are within a time range shorter than the value
  990. * set with caca_set_delay(), the second call will wait a bit before
  991. * performing the screen refresh.
  992. */
  993. void caca_refresh(void)
  994. {
  995. #if !defined(_DOXYGEN_SKIP_ME)
  996. #define IDLE_USEC 10000
  997. #endif
  998. static struct caca_timer timer = CACA_TIMER_INITIALIZER;
  999. static int lastticks = 0;
  1000. int ticks = lastticks + _caca_getticks(&timer);
  1001. #if defined(USE_SLANG)
  1002. if(_caca_driver == CACA_DRIVER_SLANG)
  1003. {
  1004. SLsmg_refresh();
  1005. }
  1006. else
  1007. #endif
  1008. #if defined(USE_NCURSES)
  1009. if(_caca_driver == CACA_DRIVER_NCURSES)
  1010. {
  1011. refresh();
  1012. }
  1013. else
  1014. #endif
  1015. #if defined(USE_CONIO)
  1016. if(_caca_driver == CACA_DRIVER_CONIO)
  1017. {
  1018. # if defined(SCREENUPDATE_IN_PC_H)
  1019. ScreenUpdate(conio_screen);
  1020. # else
  1021. /* FIXME */
  1022. # endif
  1023. }
  1024. else
  1025. #endif
  1026. #if defined(USE_X11)
  1027. if(_caca_driver == CACA_DRIVER_X11)
  1028. {
  1029. unsigned int x, y, len;
  1030. /* First draw the background colours. Splitting the process in two
  1031. * loops like this is actually slightly faster. */
  1032. for(y = 0; y < _caca_height; y++)
  1033. {
  1034. for(x = 0; x < _caca_width; x += len)
  1035. {
  1036. uint8_t *attr = cache_attr + x + y * _caca_width;
  1037. len = 1;
  1038. while(x + len < _caca_width
  1039. && (attr[len] >> 4) == (attr[0] >> 4))
  1040. len++;
  1041. XSetForeground(x11_dpy, x11_gc, x11_colors[attr[0] >> 4]);
  1042. XFillRectangle(x11_dpy, x11_pixmap, x11_gc,
  1043. x * x11_font_width, y * x11_font_height,
  1044. len * x11_font_width, x11_font_height);
  1045. }
  1046. }
  1047. /* Then print the foreground characters */
  1048. for(y = 0; y < _caca_height; y++)
  1049. {
  1050. for(x = 0; x < _caca_width; x += len)
  1051. {
  1052. uint8_t *attr = cache_attr + x + y * _caca_width;
  1053. len = 1;
  1054. /* Skip spaces */
  1055. if(cache_char[x + y * _caca_width] == ' ')
  1056. continue;
  1057. while(x + len < _caca_width
  1058. && (attr[len] & 0xf) == (attr[0] & 0xf))
  1059. len++;
  1060. XSetForeground(x11_dpy, x11_gc, x11_colors[attr[0] & 0xf]);
  1061. XDrawString(x11_dpy, x11_pixmap, x11_gc, x * x11_font_width,
  1062. (y + 1) * x11_font_height - x11_font_offset,
  1063. cache_char + x + y * _caca_width, len);
  1064. }
  1065. }
  1066. XCopyArea(x11_dpy, x11_pixmap, x11_window, x11_gc, 0, 0,
  1067. _caca_width * x11_font_width, _caca_height * x11_font_height,
  1068. 0, 0);
  1069. XFlush(x11_dpy);
  1070. }
  1071. else
  1072. #endif
  1073. #if defined(USE_WIN32)
  1074. if(_caca_driver == CACA_DRIVER_WIN32)
  1075. {
  1076. COORD size, pos;
  1077. SMALL_RECT rect;
  1078. unsigned int i;
  1079. /* Render everything to our back buffer */
  1080. for(i = 0; i < _caca_width * _caca_height; i++)
  1081. {
  1082. win32_buffer[i].Char.AsciiChar = cache_char[i];
  1083. win32_buffer[i].Attributes = win32_fg_palette[cache_attr[i] & 0xf]
  1084. | win32_bg_palette[cache_attr[i] >> 4];
  1085. }
  1086. /* Blit the back buffer to the front buffer */
  1087. size.X = _caca_width;
  1088. size.Y = _caca_height;
  1089. pos.X = pos.Y = 0;
  1090. rect.Left = rect.Top = 0;
  1091. rect.Right = _caca_width - 1;
  1092. rect.Bottom = _caca_height - 1;
  1093. WriteConsoleOutput(win32_front, win32_buffer, size, pos, &rect);
  1094. }
  1095. else
  1096. #endif
  1097. {
  1098. /* Dummy */
  1099. }
  1100. if(_caca_resize)
  1101. {
  1102. _caca_resize = 0;
  1103. caca_handle_resize();
  1104. }
  1105. /* Wait until _caca_delay + time of last call */
  1106. ticks += _caca_getticks(&timer);
  1107. for(ticks += _caca_getticks(&timer);
  1108. ticks + IDLE_USEC < (int)_caca_delay;
  1109. ticks += _caca_getticks(&timer))
  1110. {
  1111. _caca_sleep(IDLE_USEC);
  1112. }
  1113. /* Update the sliding mean of the render time */
  1114. _caca_rendertime = (7 * _caca_rendertime + ticks) / 8;
  1115. lastticks = ticks - _caca_delay;
  1116. /* If we drifted too much, it's bad, bad, bad. */
  1117. if(lastticks > (int)_caca_delay)
  1118. lastticks = 0;
  1119. }
  1120. /*
  1121. * XXX: following functions are loca
  1122. */
  1123. static void caca_handle_resize(void)
  1124. {
  1125. unsigned int old_width = _caca_width;
  1126. unsigned int old_height = _caca_height;
  1127. #if defined(USE_SLANG)
  1128. if(_caca_driver == CACA_DRIVER_SLANG)
  1129. {
  1130. SLtt_get_screen_size();
  1131. _caca_width = SLtt_Screen_Cols;
  1132. _caca_height = SLtt_Screen_Rows;
  1133. if(_caca_width != old_width || _caca_height != old_height)
  1134. SLsmg_reinit_smg();
  1135. }
  1136. else
  1137. #endif
  1138. #if defined(USE_NCURSES)
  1139. if(_caca_driver == CACA_DRIVER_NCURSES)
  1140. {
  1141. struct winsize size;
  1142. if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0)
  1143. {
  1144. _caca_width = size.ws_col;
  1145. _caca_height = size.ws_row;
  1146. #if defined(HAVE_RESIZE_TERM)
  1147. resize_term(_caca_height, _caca_width);
  1148. #else
  1149. resizeterm(_caca_height, _caca_width);
  1150. #endif
  1151. wrefresh(curscr);
  1152. }
  1153. }
  1154. else
  1155. #endif
  1156. #if defined(USE_CONIO)
  1157. if(_caca_driver == CACA_DRIVER_CONIO)
  1158. {
  1159. }
  1160. else
  1161. #endif
  1162. #if defined(USE_X11)
  1163. if(_caca_driver == CACA_DRIVER_X11)
  1164. {
  1165. Pixmap new_pixmap;
  1166. _caca_width = x11_new_width;
  1167. _caca_height = x11_new_height;
  1168. new_pixmap = XCreatePixmap(x11_dpy, x11_window,
  1169. _caca_width * x11_font_width,
  1170. _caca_height * x11_font_height,
  1171. DefaultDepth(x11_dpy,
  1172. DefaultScreen(x11_dpy)));
  1173. XCopyArea(x11_dpy, x11_pixmap, new_pixmap, x11_gc, 0, 0,
  1174. old_width * x11_font_width, old_height * x11_font_height,
  1175. 0, 0);
  1176. XFreePixmap(x11_dpy, x11_pixmap);
  1177. x11_pixmap = new_pixmap;
  1178. }
  1179. else
  1180. #endif
  1181. #if defined(USE_WIN32)
  1182. if(_caca_driver == CACA_DRIVER_WIN32)
  1183. {
  1184. }
  1185. else
  1186. #endif
  1187. {
  1188. /* Dummy */
  1189. }
  1190. if(_caca_width != old_width || _caca_height != old_height)
  1191. {
  1192. free(cache_char);
  1193. free(cache_attr);
  1194. cache_char = malloc(_caca_width * _caca_height * sizeof(uint8_t));
  1195. memset(cache_char, 0, _caca_width * _caca_height * sizeof(uint8_t));
  1196. cache_attr = malloc(_caca_width * _caca_height * sizeof(uint8_t));
  1197. memset(cache_attr, 0, _caca_width * _caca_height * sizeof(uint8_t));
  1198. }
  1199. if(_caca_width != old_width)
  1200. {
  1201. free(_caca_empty_line);
  1202. _caca_empty_line = malloc(_caca_width + 1);
  1203. memset(_caca_empty_line, ' ', _caca_width);
  1204. _caca_empty_line[_caca_width] = '\0';
  1205. free(_caca_scratch_line);
  1206. _caca_scratch_line = malloc(_caca_width + 1);
  1207. }
  1208. }
  1209. #if defined(USE_SLANG)
  1210. static void slang_init_palette(void)
  1211. {
  1212. /* See SLang ref., 5.4.4. */
  1213. static char *slang_colors[16] =
  1214. {
  1215. /* Standard colours */
  1216. "black",
  1217. "blue",
  1218. "green",
  1219. "cyan",
  1220. "red",
  1221. "magenta",
  1222. "brown",
  1223. "lightgray",
  1224. /* Bright colours */
  1225. "gray",
  1226. "brightblue",
  1227. "brightgreen",
  1228. "brightcyan",
  1229. "brightred",
  1230. "brightmagenta",
  1231. "yellow",
  1232. "white",
  1233. };
  1234. #if defined(OPTIMISE_SLANG_PALETTE)
  1235. int i;
  1236. for(i = 0; i < 16 * 16; i++)
  1237. SLtt_set_color(i, NULL, slang_colors[slang_palette[i * 2]],
  1238. slang_colors[slang_palette[i * 2 + 1]]);
  1239. #else
  1240. int fg, bg;
  1241. for(bg = 0; bg < 16; bg++)
  1242. for(fg = 0; fg < 16; fg++)
  1243. {
  1244. int i = fg + 16 * bg;
  1245. SLtt_set_color(i, NULL, slang_colors[fg], slang_colors[bg]);
  1246. }
  1247. #endif
  1248. }
  1249. #endif /* USE_SLANG */
  1250. #if defined(USE_X11)
  1251. static int x11_error_handler(Display *dpy, XErrorEvent *event)
  1252. {
  1253. /* Ignore the error */
  1254. return 0;
  1255. }
  1256. #endif
  1257. #if defined(HAVE_SIGNAL) && (defined(USE_NCURSES) || defined(USE_SLANG))
  1258. static RETSIGTYPE sigwinch_handler(int sig)
  1259. {
  1260. _caca_resize_event = 1;
  1261. signal(SIGWINCH, sigwinch_handler);;
  1262. }
  1263. #endif