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.
 
 
 
 
 
 

442 lines
9.8 KiB

  1. /*
  2. * libcaca ASCII-Art library
  3. * Copyright (c) 2002-2006 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 Do What The Fuck You Want To
  8. * Public License, Version 2, as published by Sam Hocevar. See
  9. * http://sam.zoy.org/wtfpl/COPYING for more details.
  10. */
  11. /** \file caca.c
  12. * \version \$Id$
  13. * \author Sam Hocevar <sam@zoy.org>
  14. * \brief Main \e libcaca functions
  15. *
  16. * This file contains the main functions used by \e libcaca applications to
  17. * initialise the library, get the screen properties, set the framerate and
  18. * so on.
  19. */
  20. #include "config.h"
  21. #if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME)
  22. # include <inttypes.h>
  23. #else
  24. typedef unsigned char uint8_t;
  25. #endif
  26. #if defined(USE_SLANG)
  27. # if defined(HAVE_SLANG_SLANG_H)
  28. # include <slang/slang.h>
  29. # else
  30. # include <slang.h>
  31. # endif
  32. #endif
  33. #if defined(USE_NCURSES)
  34. # if defined(HAVE_NCURSES_H)
  35. # include <ncurses.h>
  36. # else
  37. # include <curses.h>
  38. # endif
  39. #endif
  40. #if defined(USE_CONIO)
  41. # include <dos.h>
  42. # include <conio.h>
  43. #endif
  44. #if defined(USE_X11)
  45. # include <X11/Xlib.h>
  46. #endif
  47. #if defined(USE_WIN32)
  48. # include <windows.h>
  49. #endif
  50. #if defined(USE_GL)
  51. # include <GL/gl.h>
  52. #endif
  53. #include <stdlib.h>
  54. #include <string.h>
  55. #include "cucul.h"
  56. #include "cucul_internals.h"
  57. #include "caca.h"
  58. #include "caca_internals.h"
  59. static void caca_init_driver(caca_t *kk);
  60. static void caca_init_terminal(caca_t *kk);
  61. #if defined(USE_NCURSES)
  62. static mmask_t oldmask;
  63. #endif
  64. #if defined(USE_WIN32)
  65. static CONSOLE_CURSOR_INFO cci;
  66. #endif
  67. caca_t * caca_attach(cucul_t * qq)
  68. {
  69. caca_t *kk = malloc(sizeof(caca_t));
  70. #if defined(USE_NCURSES)
  71. mmask_t newmask;
  72. #endif
  73. caca_init_driver(kk);
  74. if(kk->driver == CACA_DRIVER_NONE)
  75. return NULL;
  76. caca_init_terminal(kk);
  77. #if defined(USE_SLANG)
  78. if(kk->driver == CACA_DRIVER_SLANG)
  79. {
  80. /* Initialise slang library */
  81. SLsig_block_signals();
  82. SLtt_get_terminfo();
  83. if(SLkp_init() == -1)
  84. {
  85. SLsig_unblock_signals();
  86. return NULL;
  87. }
  88. SLang_init_tty(-1, 0, 1);
  89. if(SLsmg_init_smg() == -1)
  90. {
  91. SLsig_unblock_signals();
  92. return NULL;
  93. }
  94. SLsig_unblock_signals();
  95. SLsmg_cls();
  96. SLtt_set_cursor_visibility(0);
  97. SLkp_define_keysym("\e[M", 1001);
  98. SLtt_set_mouse_mode(1, 0);
  99. SLsmg_refresh();
  100. /* Disable scrolling so that hashmap scrolling optimization code
  101. * does not cause ugly refreshes due to slow terminals */
  102. SLtt_Term_Cannot_Scroll = 1;
  103. }
  104. else
  105. #endif
  106. #if defined(USE_NCURSES)
  107. if(kk->driver == CACA_DRIVER_NCURSES)
  108. {
  109. initscr();
  110. keypad(stdscr, TRUE);
  111. nonl();
  112. raw();
  113. noecho();
  114. nodelay(stdscr, TRUE);
  115. curs_set(0);
  116. /* Activate mouse */
  117. newmask = REPORT_MOUSE_POSITION | ALL_MOUSE_EVENTS;
  118. mousemask(newmask, &oldmask);
  119. mouseinterval(-1); /* No click emulation */
  120. /* Set the escape delay to a ridiculously low value */
  121. ESCDELAY = 10;
  122. }
  123. else
  124. #endif
  125. #if defined(USE_CONIO)
  126. if(kk->driver == CACA_DRIVER_CONIO)
  127. {
  128. _wscroll = 0;
  129. _setcursortype(_NOCURSOR);
  130. clrscr();
  131. }
  132. else
  133. #endif
  134. #if defined(USE_X11)
  135. if(kk->driver == CACA_DRIVER_X11)
  136. {
  137. /* Nothing to do */
  138. kk->x11.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask
  139. | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask
  140. | ExposureMask;
  141. }
  142. else
  143. #endif
  144. #if defined(USE_WIN32)
  145. if(kk->driver == CACA_DRIVER_WIN32)
  146. {
  147. /* This call is allowed to fail in case we already have a console */
  148. AllocConsole();
  149. kk->win32.hin = GetStdHandle(STD_INPUT_HANDLE);
  150. kk->win32.hout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
  151. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  152. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  153. if(kk->win32.hout == INVALID_HANDLE_VALUE)
  154. return NULL;
  155. GetConsoleCursorInfo(kk->win32.hout, &cci);
  156. cci.bVisible = FALSE;
  157. SetConsoleCursorInfo(kk->win32.hout, &cci);
  158. SetConsoleMode(kk->win32.hout, ENABLE_MOUSE_INPUT);
  159. }
  160. else
  161. #endif
  162. #if defined(USE_GL)
  163. if(kk->driver == CACA_DRIVER_GL)
  164. {
  165. /* Nothing to do */
  166. }
  167. else
  168. #endif
  169. {
  170. /* Dummy */
  171. }
  172. /* Initialise events stuff */
  173. kk->events.key_timer.last_sec = 0;
  174. kk->events.key_timer.last_usec = 0;
  175. kk->events.last_key_ticks = 0;
  176. kk->events.autorepeat_ticks = 0;
  177. kk->events.last_key = 0;
  178. qq->refcount++;
  179. kk->qq = qq;
  180. kk->timer.last_sec = 0;
  181. kk->timer.last_usec = 0;
  182. kk->lastticks = 0;
  183. kk->resize = 0;
  184. kk->resize_event = 0;
  185. if(_caca_init_graphics(kk))
  186. return NULL;
  187. return kk;
  188. }
  189. void caca_detach(caca_t *kk)
  190. {
  191. _caca_end_graphics(kk);
  192. #if defined(USE_SLANG)
  193. if(kk->driver == CACA_DRIVER_SLANG)
  194. {
  195. SLtt_set_mouse_mode(0, 0);
  196. SLtt_set_cursor_visibility(1);
  197. SLang_reset_tty();
  198. SLsmg_reset_smg();
  199. }
  200. else
  201. #endif
  202. #if defined(USE_NCURSES)
  203. if(kk->driver == CACA_DRIVER_NCURSES)
  204. {
  205. mousemask(oldmask, NULL);
  206. curs_set(1);
  207. noraw();
  208. endwin();
  209. }
  210. else
  211. #endif
  212. #if defined(USE_CONIO)
  213. if(kk->driver == CACA_DRIVER_CONIO)
  214. {
  215. _wscroll = 1;
  216. textcolor((enum COLORS)WHITE);
  217. textbackground((enum COLORS)BLACK);
  218. gotoxy(_caca_width, _caca_height);
  219. cputs("\r\n");
  220. _setcursortype(_NORMALCURSOR);
  221. }
  222. else
  223. #endif
  224. #if defined(USE_X11)
  225. if(kk->driver == CACA_DRIVER_X11)
  226. {
  227. /* Nothing to do */
  228. }
  229. else
  230. #endif
  231. #if defined(USE_WIN32)
  232. if(kk->driver == CACA_DRIVER_WIN32)
  233. {
  234. SetConsoleTextAttribute(kk->win32.hout, FOREGROUND_INTENSITY
  235. | FOREGROUND_RED
  236. | FOREGROUND_GREEN
  237. | FOREGROUND_BLUE);
  238. cci.bVisible = TRUE;
  239. SetConsoleCursorInfo(kk->win32.hout, &cci);
  240. CloseHandle(kk->win32.hout);
  241. }
  242. else
  243. #endif
  244. #if defined(USE_GL)
  245. if(kk->driver == CACA_DRIVER_GL)
  246. {
  247. /* Nothing to do */
  248. }
  249. else
  250. #endif
  251. {
  252. /* Dummy */
  253. }
  254. kk->qq->refcount--;
  255. free(kk);
  256. }
  257. /*
  258. * XXX: The following functions are local.
  259. */
  260. static void caca_init_driver(caca_t *kk)
  261. {
  262. #if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP)
  263. char *var = getenv("CACA_DRIVER");
  264. /* If the environment variable was set, use it */
  265. if(var && *var)
  266. {
  267. #if defined(USE_WIN32)
  268. if(!strcasecmp(var, "win32"))
  269. kk->driver = CACA_DRIVER_WIN32;
  270. else
  271. #endif
  272. #if defined(USE_CONIO)
  273. if(!strcasecmp(var, "conio"))
  274. kk->driver = CACA_DRIVER_CONIO;
  275. else
  276. #endif
  277. #if defined(USE_X11)
  278. if(!strcasecmp(var, "x11"))
  279. kk->driver = CACA_DRIVER_X11;
  280. else
  281. #endif
  282. #if defined(USE_GL)
  283. if(!strcasecmp(var, "gl"))
  284. kk->driver = CACA_DRIVER_GL;
  285. else
  286. #endif
  287. #if defined(USE_SLANG)
  288. if(!strcasecmp(var, "slang"))
  289. kk->driver = CACA_DRIVER_SLANG;
  290. else
  291. #endif
  292. #if defined(USE_NCURSES)
  293. if(!strcasecmp(var, "ncurses"))
  294. kk->driver = CACA_DRIVER_NCURSES;
  295. else
  296. #endif
  297. kk->driver = CACA_DRIVER_NONE;
  298. return;
  299. }
  300. #endif
  301. #if defined(USE_WIN32)
  302. kk->driver = CACA_DRIVER_WIN32;
  303. return;
  304. #endif
  305. #if defined(USE_CONIO)
  306. kk->driver = CACA_DRIVER_CONIO;
  307. return;
  308. #endif
  309. #if defined(USE_X11)
  310. #if defined(HAVE_GETENV)
  311. if(getenv("DISPLAY") && *(getenv("DISPLAY")))
  312. #endif
  313. {
  314. kk->driver = CACA_DRIVER_X11;
  315. return;
  316. }
  317. #endif
  318. #if defined(USE_GL)
  319. #if defined(HAVE_GETENV) && defined(GLUT_XLIB_IMPLEMENTATION)
  320. if(getenv("DISPLAY") && *(getenv("DISPLAY")))
  321. #endif
  322. {
  323. kk->driver = CACA_DRIVER_GL;
  324. return;
  325. }
  326. #endif
  327. #if defined(USE_SLANG)
  328. kk->driver = CACA_DRIVER_SLANG;
  329. return;
  330. #endif
  331. #if defined(USE_NCURSES)
  332. kk->driver = CACA_DRIVER_NCURSES;
  333. return;
  334. #endif
  335. kk->driver = CACA_DRIVER_NONE;
  336. return;
  337. }
  338. static void caca_init_terminal(caca_t *kk)
  339. {
  340. #if defined(HAVE_GETENV) && defined(HAVE_PUTENV) && \
  341. (defined(USE_SLANG) || defined(USE_NCURSES))
  342. char *term, *colorterm, *other;
  343. #endif
  344. #if defined(USE_SLANG)
  345. if(kk->driver != CACA_DRIVER_SLANG)
  346. #endif
  347. #if defined(USE_NCURSES)
  348. if(kk->driver != CACA_DRIVER_NCURSES)
  349. #endif
  350. return;
  351. #if defined(HAVE_GETENV) && defined(HAVE_PUTENV) && \
  352. (defined(USE_SLANG) || defined(USE_NCURSES))
  353. term = getenv("TERM");
  354. colorterm = getenv("COLORTERM");
  355. if(term && !strcmp(term, "xterm"))
  356. {
  357. /* If we are using gnome-terminal, it's really a 16 colour terminal */
  358. if(colorterm && !strcmp(colorterm, "gnome-terminal"))
  359. {
  360. #if defined(USE_NCURSES)
  361. if(kk->driver == CACA_DRIVER_NCURSES)
  362. {
  363. SCREEN *screen;
  364. screen = newterm("xterm-16color", stdout, stdin);
  365. if(screen == NULL)
  366. return;
  367. endwin();
  368. }
  369. #endif
  370. (void)putenv("TERM=xterm-16color");
  371. return;
  372. }
  373. /* Ditto if we are using Konsole */
  374. other = getenv("KONSOLE_DCOP_SESSION");
  375. if(other)
  376. {
  377. #if defined(USE_NCURSES)
  378. if(kk->driver == CACA_DRIVER_NCURSES)
  379. {
  380. SCREEN *screen;
  381. screen = newterm("xterm-16color", stdout, stdin);
  382. if(screen == NULL)
  383. return;
  384. endwin();
  385. }
  386. #endif
  387. (void)putenv("TERM=xterm-16color");
  388. return;
  389. }
  390. }
  391. #endif
  392. }