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.
 
 
 
 
 
 

243 lines
5.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 driver_ncurses.c
  12. * \version \$Id$
  13. * \author Sam Hocevar <sam@zoy.org>
  14. * \brief Ncurses driver
  15. *
  16. * This file contains the libcaca Ncurses input and output driver
  17. */
  18. #include "config.h"
  19. #if defined(USE_NCURSES)
  20. #if defined(HAVE_NCURSES_H)
  21. # include <ncurses.h>
  22. #else
  23. # include <curses.h>
  24. #endif
  25. #include <stdio.h> /* BUFSIZ */
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #if defined(HAVE_UNISTD_H)
  29. # include <unistd.h>
  30. #endif
  31. #include <stdarg.h>
  32. #if defined(HAVE_SIGNAL_H)
  33. # include <signal.h>
  34. #endif
  35. #if defined(HAVE_SYS_IOCTL_H)
  36. # include <sys/ioctl.h>
  37. #endif
  38. #include "caca.h"
  39. #include "caca_internals.h"
  40. #include "cucul.h"
  41. #include "cucul_internals.h"
  42. /*
  43. * Local functions
  44. */
  45. #if defined(HAVE_SIGNAL)
  46. static RETSIGTYPE sigwinch_handler(int);
  47. static caca_t *sigwinch_kk; /* FIXME: we ought to get rid of this */
  48. #endif
  49. static int ncurses_init_graphics(caca_t *kk)
  50. {
  51. static int curses_colors[] =
  52. {
  53. /* Standard curses colours */
  54. COLOR_BLACK,
  55. COLOR_BLUE,
  56. COLOR_GREEN,
  57. COLOR_CYAN,
  58. COLOR_RED,
  59. COLOR_MAGENTA,
  60. COLOR_YELLOW,
  61. COLOR_WHITE,
  62. /* Extra values for xterm-16color */
  63. COLOR_BLACK + 8,
  64. COLOR_BLUE + 8,
  65. COLOR_GREEN + 8,
  66. COLOR_CYAN + 8,
  67. COLOR_RED + 8,
  68. COLOR_MAGENTA + 8,
  69. COLOR_YELLOW + 8,
  70. COLOR_WHITE + 8
  71. };
  72. mmask_t newmask;
  73. int fg, bg, max;
  74. #if defined(HAVE_SIGNAL)
  75. sigwinch_kk = kk;
  76. signal(SIGWINCH, sigwinch_handler);
  77. #endif
  78. initscr();
  79. keypad(stdscr, TRUE);
  80. nonl();
  81. raw();
  82. noecho();
  83. nodelay(stdscr, TRUE);
  84. curs_set(0);
  85. /* Activate mouse */
  86. newmask = REPORT_MOUSE_POSITION | ALL_MOUSE_EVENTS;
  87. mousemask(newmask, &kk->ncurses.oldmask);
  88. mouseinterval(-1); /* No click emulation */
  89. /* Set the escape delay to a ridiculously low value */
  90. ESCDELAY = 10;
  91. /* Activate colour */
  92. start_color();
  93. /* If COLORS == 16, it means the terminal supports full bright colours
  94. * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
  95. * we can build 16*16 colour pairs.
  96. * If COLORS == 8, it means the terminal does not know about bright
  97. * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
  98. * and \e[5m). We can only build 8*8 colour pairs. */
  99. max = COLORS >= 16 ? 16 : 8;
  100. for(bg = 0; bg < max; bg++)
  101. for(fg = 0; fg < max; fg++)
  102. {
  103. /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
  104. * is light gray on black. Some terminals don't like this
  105. * colour pair to be redefined. */
  106. int col = ((max + 7 - fg) % max) + max * bg;
  107. init_pair(col, curses_colors[fg], curses_colors[bg]);
  108. kk->ncurses.attr[fg + 16 * bg] = COLOR_PAIR(col);
  109. if(max == 8)
  110. {
  111. /* Bright fg on simple bg */
  112. kk->ncurses.attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
  113. /* Simple fg on bright bg */
  114. kk->ncurses.attr[fg + 16 * (bg + 8)] = A_BLINK
  115. | COLOR_PAIR(col);
  116. /* Bright fg on bright bg */
  117. kk->ncurses.attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
  118. | COLOR_PAIR(col);
  119. }
  120. }
  121. cucul_set_size(kk->qq, COLS, LINES);
  122. return 0;
  123. }
  124. static int ncurses_end_graphics(caca_t *kk)
  125. {
  126. mousemask(kk->ncurses.oldmask, NULL);
  127. curs_set(1);
  128. noraw();
  129. endwin();
  130. return 0;
  131. }
  132. static int ncurses_set_window_title(caca_t *kk, char const *title)
  133. {
  134. return 0;
  135. }
  136. static unsigned int ncurses_get_window_width(caca_t *kk)
  137. {
  138. /* Fallback to a 6x10 font */
  139. return kk->qq->width * 6;
  140. }
  141. static unsigned int ncurses_get_window_height(caca_t *kk)
  142. {
  143. /* Fallback to a 6x10 font */
  144. return kk->qq->height * 10;
  145. }
  146. static void ncurses_display(caca_t *kk)
  147. {
  148. int x, y;
  149. uint8_t *attr = kk->qq->attr;
  150. uint32_t *chars = kk->qq->chars;
  151. for(y = 0; y < (int)kk->qq->height; y++)
  152. {
  153. move(y, 0);
  154. for(x = kk->qq->width; x--; )
  155. {
  156. attrset(kk->ncurses.attr[*attr++]);
  157. addch(*chars++ & 0x7f);
  158. }
  159. }
  160. refresh();
  161. }
  162. static void ncurses_handle_resize(caca_t *kk, unsigned int *new_width,
  163. unsigned int *new_height)
  164. {
  165. struct winsize size;
  166. *new_width = kk->qq->width;
  167. *new_height = kk->qq->height;
  168. if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0)
  169. {
  170. *new_width = size.ws_col;
  171. *new_height = size.ws_row;
  172. #if defined(HAVE_RESIZE_TERM)
  173. resize_term(*new_height, *new_width);
  174. #else
  175. resizeterm(*new_height, *new_width);
  176. #endif
  177. wrefresh(curscr);
  178. }
  179. }
  180. /*
  181. * XXX: following functions are local
  182. */
  183. #if defined(HAVE_SIGNAL)
  184. static RETSIGTYPE sigwinch_handler(int sig)
  185. {
  186. sigwinch_kk->resize_event = 1;
  187. signal(SIGWINCH, sigwinch_handler);;
  188. }
  189. #endif
  190. /*
  191. * Driver initialisation
  192. */
  193. void ncurses_init_driver(caca_t *kk)
  194. {
  195. kk->driver.driver = CACA_DRIVER_NCURSES;
  196. kk->driver.init_graphics = ncurses_init_graphics;
  197. kk->driver.end_graphics = ncurses_end_graphics;
  198. kk->driver.set_window_title = ncurses_set_window_title;
  199. kk->driver.get_window_width = ncurses_get_window_width;
  200. kk->driver.get_window_height = ncurses_get_window_height;
  201. kk->driver.display = ncurses_display;
  202. kk->driver.handle_resize = ncurses_handle_resize;
  203. }
  204. #endif /* USE_NCURSES */