Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

18 лет назад
18 лет назад
18 лет назад
19 лет назад
19 лет назад
18 лет назад
18 лет назад
18 лет назад
19 лет назад
19 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This library is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. /*
  15. * This file contains the main functions used by \e libcaca applications to
  16. * initialise the library, get the screen properties, set the framerate and
  17. * so on.
  18. */
  19. #include "config.h"
  20. #include "common.h"
  21. #if !defined(__KERNEL__)
  22. # include <stdlib.h>
  23. # include <string.h>
  24. # include <stdio.h>
  25. # if defined(USE_PLUGINS)
  26. # if defined(HAVE_DLFCN_H)
  27. # include <dlfcn.h>
  28. # endif
  29. # endif
  30. #endif
  31. #include "cucul.h"
  32. #include "caca.h"
  33. #include "caca_internals.h"
  34. #if defined(USE_PLUGINS)
  35. # define gl_install(p) caca_plugin_install(p, "gl")
  36. # define x11_install(p) caca_plugin_install(p, "x11")
  37. #endif
  38. static int caca_can_resize(caca_display_t *);
  39. static int caca_install_driver(caca_display_t *, char const *);
  40. static int caca_uninstall_driver(caca_display_t *);
  41. static int caca_select_driver(caca_display_t *, char const *);
  42. #if defined(USE_PLUGINS)
  43. static int caca_plugin_install(char const *, caca_display_t *);
  44. #endif
  45. /** \brief Attach a caca graphical context to a cucul canvas.
  46. *
  47. * Create a graphical context using device-dependent features (ncurses for
  48. * terminals, an X11 window, a DOS command window...) that attaches to a
  49. * libcucul canvas. Everything that gets drawn in the libcucul canvas can
  50. * then be displayed by the libcaca driver.
  51. *
  52. * If no cucul canvas is provided, a new one is created. Its handle can be
  53. * retrieved using caca_get_canvas() and it is automatically destroyed when
  54. * caca_free_display() is called.
  55. *
  56. * See also caca_create_display_with_driver().
  57. *
  58. * If an error occurs, NULL is returned and \b errno is set accordingly:
  59. * - \c ENOMEM Not enough memory.
  60. * - \c ENODEV Graphical device could not be initialised.
  61. *
  62. * \param cv The cucul canvas or NULL to create a canvas automatically.
  63. * \return The caca graphical context or NULL if an error occurred.
  64. */
  65. caca_display_t * caca_create_display(cucul_canvas_t *cv)
  66. {
  67. return caca_create_display_with_driver(cv, NULL);
  68. }
  69. /** \brief Attach a specific caca graphical context to a cucul canvas.
  70. *
  71. * Create a graphical context using device-dependent features (ncurses for
  72. * terminals, an X11 window, a DOS command window...) that attaches to a
  73. * libcucul canvas. Everything that gets drawn in the libcucul canvas can
  74. * then be displayed by the libcaca driver.
  75. *
  76. * If no cucul canvas is provided, a new one is created. Its handle can be
  77. * retrieved using caca_get_canvas() and it is automatically destroyed when
  78. * caca_free_display() is called.
  79. *
  80. * If no driver name is provided, \e libcaca will try to autodetect the best
  81. * output driver it can.
  82. *
  83. * See also caca_create_display().
  84. *
  85. * If an error occurs, NULL is returned and \b errno is set accordingly:
  86. * - \c ENOMEM Not enough memory.
  87. * - \c ENODEV Graphical device could not be initialised.
  88. *
  89. * \param cv The cucul canvas or NULL to create a canvas automatically.
  90. * \param driver A string describing the desired output driver or NULL to
  91. * choose the best driver automatically.
  92. * \return The caca graphical context or NULL if an error occurred.
  93. */
  94. caca_display_t * caca_create_display_with_driver(cucul_canvas_t *cv,
  95. char const *driver)
  96. {
  97. caca_display_t *dp = malloc(sizeof(caca_display_t));
  98. if(!dp)
  99. {
  100. seterrno(ENOMEM);
  101. return NULL;
  102. }
  103. if((dp->autorelease = (cv == NULL)))
  104. {
  105. cv = cucul_create_canvas(0, 0);
  106. }
  107. dp->cv = cv;
  108. if(cucul_manage_canvas(cv, (int (*)(void *))caca_can_resize, (void *)dp))
  109. {
  110. if(dp->autorelease)
  111. cucul_free_canvas(dp->cv);
  112. free(dp);
  113. seterrno(EBUSY);
  114. return NULL;
  115. }
  116. if(caca_install_driver(dp, driver))
  117. {
  118. cucul_unmanage_canvas(cv, (int (*)(void *))caca_can_resize, (void *)dp);
  119. if(dp->autorelease)
  120. cucul_free_canvas(dp->cv);
  121. free(dp);
  122. seterrno(ENODEV);
  123. return NULL;
  124. }
  125. return dp;
  126. }
  127. /** \brief Get available display drivers
  128. *
  129. * Return a list of available display drivers. The list is a NULL-terminated
  130. * array of strings, interleaving a string containing the internal value for
  131. * the display driver, and a string containing the natural language
  132. * description for that driver.
  133. *
  134. * This function never fails.
  135. *
  136. * \param dp Display object.
  137. * \return An array of strings.
  138. */
  139. char const * const * caca_get_display_driver_list(void)
  140. {
  141. static char const * const list[] =
  142. {
  143. #if defined(USE_COCOA)
  144. "cocoa", "Mac OS X Cocoa",
  145. #endif
  146. #if defined(USE_WIN32)
  147. "win32", "Windows console",
  148. #endif
  149. #if defined(USE_CONIO)
  150. "conio", "MS-DOS conio",
  151. #endif
  152. #if defined(USE_X11)
  153. "x11", "X11 graphical window",
  154. #endif
  155. #if defined(USE_GL)
  156. "gl", "OpenGL window",
  157. #endif
  158. #if defined(USE_SLANG)
  159. "slang", "S-Lang console library",
  160. #endif
  161. #if defined(USE_NCURSES)
  162. "ncurses", "ncurses console library",
  163. #endif
  164. #if defined(USE_VGA)
  165. "vga", "direct VGA memory",
  166. #endif
  167. #if !defined(__KERNEL__)
  168. "raw", "raw libcaca output",
  169. #endif
  170. NULL, NULL
  171. };
  172. return list;
  173. }
  174. /** \brief Return a caca graphical context's current output driver.
  175. *
  176. * Return the given display's current output driver.
  177. *
  178. * This function never fails.
  179. *
  180. * \param dp The caca display.
  181. * \return A static string.
  182. */
  183. char const * caca_get_display_driver(caca_display_t *dp)
  184. {
  185. return dp->drv.driver;
  186. }
  187. /** \brief Set the output driver.
  188. *
  189. * Dynamically change the given display's output driver.
  190. *
  191. * FIXME: decide what to do in case of failure
  192. *
  193. * \param dp The caca display.
  194. * \param driver A string describing the desired output driver or NULL to
  195. * choose the best driver automatically.
  196. * \return 0 in case of success, -1 if an error occurred.
  197. */
  198. int caca_set_display_driver(caca_display_t *dp, char const *driver)
  199. {
  200. caca_uninstall_driver(dp);
  201. if(caca_install_driver(dp, driver))
  202. {
  203. seterrno(ENODEV);
  204. return -1;
  205. }
  206. return 0;
  207. }
  208. /** \brief Detach a caca graphical context from a cucul backend context.
  209. *
  210. * Detach a graphical context from its cucul backend and destroy it. The
  211. * libcucul canvas continues to exist and other graphical contexts can be
  212. * attached to it afterwards.
  213. *
  214. * If the cucul canvas was automatically created by caca_create_display(),
  215. * it is automatically destroyed and any handle to it becomes invalid.
  216. *
  217. * This function never fails.
  218. *
  219. * \param dp The libcaca graphical context.
  220. * \return This function always returns 0.
  221. */
  222. int caca_free_display(caca_display_t *dp)
  223. {
  224. caca_uninstall_driver(dp);
  225. cucul_unmanage_canvas(dp->cv, (int (*)(void *))caca_can_resize, (void *)dp);
  226. if(dp->autorelease)
  227. cucul_free_canvas(dp->cv);
  228. free(dp);
  229. return 0;
  230. }
  231. /** \brief Get the canvas attached to a caca graphical context.
  232. *
  233. * Return a handle on the \e cucul_canvas_t object that was either attached
  234. * or created by caca_create_display().
  235. *
  236. * This function never fails.
  237. *
  238. * \param dp The libcaca graphical context.
  239. * \return The libcucul canvas.
  240. */
  241. cucul_canvas_t * caca_get_canvas(caca_display_t *dp)
  242. {
  243. return dp->cv;
  244. }
  245. /** \brief Return the \e libcaca version.
  246. *
  247. * Return a read-only string with the \e libcaca version information.
  248. *
  249. * This function never fails.
  250. *
  251. * \return The \e libcaca version information.
  252. */
  253. char const * caca_get_version(void)
  254. {
  255. return VERSION;
  256. }
  257. /*
  258. * XXX: The following functions are local.
  259. */
  260. static int caca_can_resize(caca_display_t *dp)
  261. {
  262. return dp->resize.allow;
  263. }
  264. static int caca_install_driver(caca_display_t *dp, char const *driver)
  265. {
  266. #if defined(USE_PLUGINS)
  267. dp->plugin = NULL;
  268. #endif
  269. if(caca_select_driver(dp, driver))
  270. {
  271. #if defined(USE_PLUGINS)
  272. if(dp->plugin)
  273. dlclose(dp->plugin);
  274. #endif
  275. return -1;
  276. }
  277. if(dp->drv.init_graphics(dp))
  278. {
  279. #if defined(USE_PLUGINS)
  280. if(dp->plugin)
  281. dlclose(dp->plugin);
  282. #endif
  283. return -1;
  284. }
  285. /* Graphics stuff */
  286. dp->delay = 0;
  287. dp->rendertime = 0;
  288. /* Events stuff */
  289. #if defined(USE_SLANG) || defined(USE_NCURSES)
  290. dp->events.key_timer.last_sec = 0;
  291. dp->events.key_timer.last_usec = 0;
  292. dp->events.last_key_ticks = 0;
  293. dp->events.autorepeat_ticks = 0;
  294. dp->events.last_key_event.type = CACA_EVENT_NONE;
  295. #endif
  296. #if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) || defined(USE_GL)
  297. dp->events.queue = 0;
  298. #endif
  299. dp->timer.last_sec = 0;
  300. dp->timer.last_usec = 0;
  301. dp->lastticks = 0;
  302. /* Mouse position */
  303. dp->mouse.x = cucul_get_canvas_width(dp->cv) / 2;
  304. dp->mouse.y = cucul_get_canvas_height(dp->cv) / 2;
  305. /* Resize events */
  306. dp->resize.resized = 0;
  307. dp->resize.allow = 0;
  308. return 0;
  309. }
  310. static int caca_uninstall_driver(caca_display_t *dp)
  311. {
  312. dp->drv.end_graphics(dp);
  313. #if defined(USE_PLUGINS)
  314. if(dp->plugin)
  315. dlclose(dp->plugin);
  316. #endif
  317. return 0;
  318. }
  319. static int caca_select_driver(caca_display_t *dp, char const *driver)
  320. {
  321. char const *var = driver;
  322. #if defined(HAVE_GETENV)
  323. if(!var)
  324. var = getenv("CACA_DRIVER");
  325. #endif
  326. #if defined(HAVE_STRCASECMP)
  327. /* If the environment variable was set, use it */
  328. if(var && *var)
  329. {
  330. #if defined(USE_COCOA)
  331. if(!strcasecmp(var, "cocoa")) return cocoa_install(dp);
  332. #endif
  333. #if defined(USE_WIN32)
  334. if(!strcasecmp(var, "win32")) return win32_install(dp);
  335. #endif
  336. #if defined(USE_CONIO)
  337. if(!strcasecmp(var, "conio")) return conio_install(dp);
  338. #endif
  339. #if defined(USE_X11)
  340. if(!strcasecmp(var, "x11")) return x11_install(dp);
  341. #endif
  342. #if defined(USE_GL)
  343. if(!strcasecmp(var, "gl")) return gl_install(dp);
  344. #endif
  345. #if !defined(__KERNEL__)
  346. if(!strcasecmp(var, "raw")) return raw_install(dp);
  347. #endif
  348. #if defined(USE_SLANG)
  349. if(!strcasecmp(var, "slang")) return slang_install(dp);
  350. #endif
  351. #if defined(USE_NCURSES)
  352. if(!strcasecmp(var, "ncurses")) return ncurses_install(dp);
  353. #endif
  354. #if defined(USE_VGA)
  355. if(!strcasecmp(var, "vga")) return vga_install(dp);
  356. #endif
  357. return -1;
  358. }
  359. #endif
  360. #if defined(USE_COCOA)
  361. if(cocoa_install(dp) == 0) return 0;
  362. #endif
  363. #if defined(USE_WIN32)
  364. if(win32_install(dp) == 0) return 0;
  365. #endif
  366. #if defined(USE_CONIO)
  367. if(conio_install(dp) == 0) return 0;
  368. #endif
  369. #if defined(USE_VGA)
  370. if(vga_install(dp) == 0) return 0;
  371. #endif
  372. #if defined(USE_X11)
  373. if(x11_install(dp) == 0) return 0;
  374. #endif
  375. #if defined(USE_GL)
  376. if(gl_install(dp) == 0) return 0;
  377. #endif
  378. /* ncurses has a higher priority than slang because it has better colour
  379. * support across terminal types, despite being slightly slower. */
  380. #if defined(USE_NCURSES)
  381. if(ncurses_install(dp) == 0) return 0;
  382. #endif
  383. #if defined(USE_SLANG)
  384. if(slang_install(dp) == 0) return 0;
  385. #endif
  386. return -1;
  387. }
  388. #if defined(USE_PLUGINS)
  389. static int caca_plugin_install(caca_display_t *dp, char const *driver)
  390. {
  391. char buf[512];
  392. int (*sym) (caca_display_t *);
  393. sprintf(buf, "%s/lib%s_plugin.so", PLUGINDIR, driver);
  394. dp->plugin = dlopen(buf, RTLD_NOW);
  395. if(!dp->plugin)
  396. {
  397. sprintf(buf, "lib%s_plugin.so", driver);
  398. dp->plugin = dlopen(buf, RTLD_NOW);
  399. if(!dp->plugin)
  400. return -1;
  401. }
  402. sprintf(buf, "%s_install", driver);
  403. sym = dlsym(dp->plugin, buf);
  404. if(!sym)
  405. {
  406. dlclose(dp->plugin);
  407. return -1;
  408. }
  409. return sym(dp);
  410. }
  411. #endif