"Fossies" - the Fresh Open Source Software Archive

Member "libcaca-0.99.beta20/caca/driver/ncurses.c" (19 Oct 2021, 22270 Bytes) of package /linux/privat/libcaca-0.99.beta20.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ncurses.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.99.beta19_vs_0.99.beta20.

    1 /*
    2  *  libcaca     Colour ASCII-Art library
    3  *  Copyright © 2002—2021 Sam Hocevar <sam@hocevar.net>
    4  *              2007 Ben Wiley Sittler <bsittler@gmail.com>
    5  *              All Rights Reserved
    6  *
    7  *  This library is free software. It comes without any warranty, to
    8  *  the extent permitted by applicable law. You can redistribute it
    9  *  and/or modify it under the terms of the Do What the Fuck You Want
   10  *  to Public License, Version 2, as published by Sam Hocevar. See
   11  *  http://www.wtfpl.net/ for more details.
   12  */
   13 
   14 /*
   15  *  This file contains the libcaca Ncurses input and output driver
   16  */
   17 
   18 #include "config.h"
   19 
   20 #if defined USE_NCURSES
   21 
   22 #if defined HAVE_NCURSESW_NCURSES_H
   23 #   include <ncursesw/ncurses.h>
   24 #elif defined HAVE_NCURSES_NCURSES_H
   25 #   include <ncurses/ncurses.h>
   26 #elif defined HAVE_NCURSES_H
   27 #   include <ncurses.h>
   28 #else
   29 #   include <curses.h>
   30 #endif
   31 
   32 #include <stdlib.h>
   33 #include <string.h>
   34 
   35 #if defined HAVE_UNISTD_H
   36 #   include <unistd.h>
   37 #endif
   38 #if defined HAVE_SIGNAL_H
   39 #   include <signal.h>
   40 #endif
   41 #if defined HAVE_SYS_IOCTL_H
   42 #   include <sys/ioctl.h>
   43 #endif
   44 #if defined HAVE_LOCALE_H
   45 #   include <locale.h>
   46 #endif
   47 #if defined HAVE_TERMIOS_H
   48 #   include <termios.h>
   49 #endif
   50 
   51 #include "caca.h"
   52 #include "caca_internals.h"
   53 
   54 /*
   55  * Emulation for missing ACS_* in older curses
   56  */
   57 
   58 #ifndef ACS_BLOCK
   59 #define ACS_BLOCK '#'
   60 #endif
   61 
   62 #ifndef ACS_BOARD
   63 #define ACS_BOARD '#'
   64 #endif
   65 
   66 #ifndef ACS_BTEE
   67 #define ACS_BTEE '+'
   68 #endif
   69 
   70 #ifndef ACS_BULLET
   71 #define ACS_BULLET '.'
   72 #endif
   73 
   74 #ifndef ACS_CKBOARD
   75 #define ACS_CKBOARD ':'
   76 #endif
   77 
   78 #ifndef ACS_DARROW
   79 #define ACS_DARROW 'v'
   80 #endif
   81 
   82 #ifndef ACS_DEGREE
   83 #define ACS_DEGREE '\''
   84 #endif
   85 
   86 #ifndef ACS_DIAMOND
   87 #define ACS_DIAMOND '+'
   88 #endif
   89 
   90 #ifndef ACS_GEQUAL
   91 #define ACS_GEQUAL '>'
   92 #endif
   93 
   94 #ifndef ACS_HLINE
   95 #define ACS_HLINE '-'
   96 #endif
   97 
   98 #ifndef ACS_LANTERN
   99 #define ACS_LANTERN '#'
  100 #endif
  101 
  102 #ifndef ACS_LARROW
  103 #define ACS_LARROW '<'
  104 #endif
  105 
  106 #ifndef ACS_LEQUAL
  107 #define ACS_LEQUAL '<'
  108 #endif
  109 
  110 #ifndef ACS_LLCORNER
  111 #define ACS_LLCORNER '+'
  112 #endif
  113 
  114 #ifndef ACS_LRCORNER
  115 #define ACS_LRCORNER '+'
  116 #endif
  117 
  118 #ifndef ACS_LTEE
  119 #define ACS_LTEE '+'
  120 #endif
  121 
  122 #ifndef ACS_NEQUAL
  123 #define ACS_NEQUAL '!'
  124 #endif
  125 
  126 #ifndef ACS_PI
  127 #define ACS_PI '*'
  128 #endif
  129 
  130 #ifndef ACS_STERLING
  131 #define ACS_STERLING 'f'
  132 #endif
  133 
  134 #ifndef ACS_PLMINUS
  135 #define ACS_PLMINUS '#'
  136 #endif
  137 
  138 #ifndef ACS_PLUS
  139 #define ACS_PLUS '+'
  140 #endif
  141 
  142 #ifndef ACS_RARROW
  143 #define ACS_RARROW '>'
  144 #endif
  145 
  146 #ifndef ACS_RTEE
  147 #define ACS_RTEE '+'
  148 #endif
  149 
  150 #ifndef ACS_S1
  151 #define ACS_S1 '-'
  152 #endif
  153 
  154 #ifndef ACS_S3
  155 #define ACS_S3 '-'
  156 #endif
  157 
  158 #ifndef ACS_S7
  159 #define ACS_S7 '-'
  160 #endif
  161 
  162 #ifndef ACS_S9
  163 #define ACS_S9 '-'
  164 #endif
  165 
  166 #ifndef ACS_TTEE
  167 #define ACS_TTEE '+'
  168 #endif
  169 
  170 #ifndef ACS_UARROW
  171 #define ACS_UARROW '^'
  172 #endif
  173 
  174 #ifndef ACS_ULCORNER
  175 #define ACS_ULCORNER '+'
  176 #endif
  177 
  178 #ifndef ACS_URCORNER
  179 #define ACS_URCORNER '+'
  180 #endif
  181 
  182 #ifndef ACS_VLINE
  183 #define ACS_VLINE '|'
  184 #endif
  185 
  186 /*
  187  * Local functions
  188  */
  189 
  190 #if defined HAVE_SIGNAL
  191 static void sigwinch_handler(int);
  192 static caca_display_t *sigwinch_d; /* FIXME: we ought to get rid of this */
  193 #endif
  194 #if defined HAVE_GETENV && defined HAVE_PUTENV
  195 static void ncurses_install_terminal(caca_display_t *);
  196 static void ncurses_uninstall_terminal(caca_display_t *);
  197 #endif
  198 static void ncurses_write_utf32(uint32_t);
  199 
  200 struct driver_private
  201 {
  202     int attr[16*16];
  203     mmask_t oldmask;
  204     char *term;
  205 };
  206 
  207 static int ncurses_init_graphics(caca_display_t *dp)
  208 {
  209     static int curses_colors[] =
  210     {
  211         /* Standard curses colours */
  212         COLOR_BLACK,
  213         COLOR_BLUE,
  214         COLOR_GREEN,
  215         COLOR_CYAN,
  216         COLOR_RED,
  217         COLOR_MAGENTA,
  218         COLOR_YELLOW,
  219         COLOR_WHITE,
  220         /* Extra values for xterm-16color */
  221         COLOR_BLACK + 8,
  222         COLOR_BLUE + 8,
  223         COLOR_GREEN + 8,
  224         COLOR_CYAN + 8,
  225         COLOR_RED + 8,
  226         COLOR_MAGENTA + 8,
  227         COLOR_YELLOW + 8,
  228         COLOR_WHITE + 8
  229     };
  230 
  231 #if defined HAVE_LOCALE_H
  232     char const *old_locale;
  233 #endif
  234     mmask_t newmask;
  235     int fg, bg, max;
  236 
  237     dp->drv.p = malloc(sizeof(struct driver_private));
  238 
  239 #if defined HAVE_GETENV && defined HAVE_PUTENV
  240     ncurses_install_terminal(dp);
  241 #endif
  242 
  243 #if defined HAVE_SIGNAL
  244     sigwinch_d = dp;
  245     signal(SIGWINCH, sigwinch_handler);
  246 #endif
  247 
  248     _caca_set_term_title("caca for ncurses");
  249 
  250 #if defined HAVE_LOCALE_H
  251     old_locale = setlocale(LC_CTYPE, "");
  252 #endif
  253     initscr();
  254 #if defined HAVE_LOCALE_H
  255     setlocale(LC_CTYPE, old_locale);
  256 #endif
  257 
  258     keypad(stdscr, TRUE);
  259     nonl();
  260     raw();
  261     noecho();
  262     nodelay(stdscr, TRUE);
  263     curs_set(0);
  264 
  265     /* Activate mouse */
  266     newmask = REPORT_MOUSE_POSITION | ALL_MOUSE_EVENTS;
  267     mousemask(newmask, &dp->drv.p->oldmask);
  268     mouseinterval(-1); /* No click emulation */
  269 
  270     /* Set the escape delay to a ridiculously low value */
  271 #if defined set_escdelay
  272     set_escdelay(10);
  273 #else
  274     ESCDELAY = 10;
  275 #endif
  276 
  277     /* Activate colour */
  278     start_color();
  279 
  280     /* If COLORS == 16, it means the terminal supports full bright colours
  281      * using setab and setaf (will use \e[90m \e[91m etc. for colours >= 8),
  282      * we can build 16*16 colour pairs.
  283      * If COLORS == 8, it means the terminal does not know about bright
  284      * colours and we need to get them through A_BOLD and A_BLINK (\e[1m
  285      * and \e[5m). We can only build 8*8 colour pairs. */
  286     max = COLORS >= 16 ? 16 : 8;
  287 
  288     for(bg = 0; bg < max; bg++)
  289         for(fg = 0; fg < max; fg++)
  290         {
  291             /* Use ((max + 7 - fg) % max) instead of fg so that colour 0
  292              * is light gray on black. Some terminals don't like this
  293              * colour pair to be redefined. */
  294             int col = ((max + 7 - fg) % max) + max * bg;
  295             init_pair(col, curses_colors[fg], curses_colors[bg]);
  296             dp->drv.p->attr[fg + 16 * bg] = COLOR_PAIR(col);
  297 
  298             if(max == 8)
  299             {
  300                 /* Bright fg on simple bg */
  301                 dp->drv.p->attr[fg + 8 + 16 * bg] = A_BOLD | COLOR_PAIR(col);
  302                 /* Simple fg on bright bg */
  303                 dp->drv.p->attr[fg + 16 * (bg + 8)] = A_BLINK
  304                                                     | COLOR_PAIR(col);
  305                 /* Bright fg on bright bg */
  306                 dp->drv.p->attr[fg + 8 + 16 * (bg + 8)] = A_BLINK | A_BOLD
  307                                                         | COLOR_PAIR(col);
  308             }
  309         }
  310 
  311     caca_add_dirty_rect(dp->cv, 0, 0, dp->cv->width, dp->cv->height);
  312     dp->resize.allow = 1;
  313     caca_set_canvas_size(dp->cv, COLS, LINES);
  314     dp->resize.allow = 0;
  315 
  316     return 0;
  317 }
  318 
  319 static int ncurses_end_graphics(caca_display_t *dp)
  320 {
  321     _caca_set_term_title("");
  322     mousemask(dp->drv.p->oldmask, NULL);
  323     curs_set(1);
  324     noraw();
  325     endwin();
  326 
  327 #if defined HAVE_GETENV && defined HAVE_PUTENV
  328     ncurses_uninstall_terminal(dp);
  329 #endif
  330 
  331     free(dp->drv.p);
  332 
  333     return 0;
  334 }
  335 
  336 static int ncurses_set_display_title(caca_display_t *dp, char const *title)
  337 {
  338     _caca_set_term_title(title);
  339 
  340     return 0;
  341 }
  342 
  343 static int ncurses_get_display_width(caca_display_t const *dp)
  344 {
  345     /* Fallback to a 6x10 font */
  346     return caca_get_canvas_width(dp->cv) * 6;
  347 }
  348 
  349 static int ncurses_get_display_height(caca_display_t const *dp)
  350 {
  351     /* Fallback to a 6x10 font */
  352     return caca_get_canvas_height(dp->cv) * 10;
  353 }
  354 
  355 static void ncurses_display(caca_display_t *dp)
  356 {
  357     int x, y, i;
  358 
  359     for(i = 0; i < caca_get_dirty_rect_count(dp->cv); i++)
  360     {
  361         uint32_t const *cvchars, *cvattrs;
  362         int dx, dy, dw, dh;
  363 
  364         caca_get_dirty_rect(dp->cv, i, &dx, &dy, &dw, &dh);
  365 
  366         cvchars = caca_get_canvas_chars(dp->cv) + dx + dy * dp->cv->width;
  367         cvattrs = caca_get_canvas_attrs(dp->cv) + dx + dy * dp->cv->width;
  368 
  369         for(y = dy; y < dy + dh; y++)
  370         {
  371             move(y, dx);
  372             for(x = dx; x < dx + dw; x++)
  373             {
  374                 uint32_t attr = *cvattrs++;
  375 
  376                 (void)attrset(dp->drv.p->attr[caca_attr_to_ansi(attr)]);
  377                 if(attr & CACA_BOLD)
  378                     attron(A_BOLD);
  379                 if(attr & CACA_BLINK)
  380                     attron(A_BLINK);
  381                 if(attr & CACA_UNDERLINE)
  382                     attron(A_UNDERLINE);
  383 
  384                 ncurses_write_utf32(*cvchars++);
  385             }
  386 
  387             cvchars += dp->cv->width - dw;
  388             cvattrs += dp->cv->width - dw;
  389         }
  390     }
  391 
  392     x = caca_wherex(dp->cv);
  393     y = caca_wherey(dp->cv);
  394     move(y, x);
  395 
  396     refresh();
  397 }
  398 
  399 static void ncurses_handle_resize(caca_display_t *dp)
  400 {
  401     struct winsize size;
  402 
  403 #if defined HAVE_SYS_IOCTL_H
  404     if(ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0)
  405     {
  406         dp->resize.w = size.ws_col;
  407         dp->resize.h = size.ws_row;
  408 #if defined HAVE_RESIZE_TERM
  409         resize_term(dp->resize.h, dp->resize.w);
  410 #else
  411         resizeterm(dp->resize.h, dp->resize.w);
  412 #endif
  413         wrefresh(curscr);
  414         return;
  415     }
  416 #endif
  417 
  418     /* Fallback */
  419     dp->resize.w = caca_get_canvas_width(dp->cv);
  420     dp->resize.h = caca_get_canvas_height(dp->cv);
  421 }
  422 
  423 static int ncurses_get_event(caca_display_t *dp, caca_privevent_t *ev)
  424 {
  425     int intkey;
  426 
  427     intkey = getch();
  428     if(intkey == ERR)
  429     {
  430         ev->type = CACA_EVENT_NONE;
  431         return 0;
  432     }
  433 
  434     if(intkey < 0x7f)
  435     {
  436         ev->type = CACA_EVENT_KEY_PRESS;
  437         ev->data.key.ch = intkey;
  438         ev->data.key.utf32 = intkey;
  439         ev->data.key.utf8[0] = intkey;
  440         ev->data.key.utf8[1] = '\0';
  441         return 1;
  442     }
  443 
  444     /* If the key was UTF-8, parse the whole sequence */
  445     if(intkey >= 0x80 && intkey < 0x100)
  446     {
  447         int keys[7]; /* Necessary for ungetch(); */
  448         char utf8[7];
  449         uint32_t utf32;
  450         size_t i, bytes = 0;
  451 
  452         keys[0] = intkey;
  453         utf8[0] = intkey;
  454 
  455         for(i = 1; i < 6; i++)
  456         {
  457             keys[i] = getch();
  458             utf8[i] = (unsigned char)keys[i];
  459         }
  460 
  461         utf8[i] = '\0';
  462         utf32 = caca_utf8_to_utf32(utf8, &bytes);
  463 
  464         while(i > bytes)
  465             ungetch(keys[--i]);
  466 
  467         if(bytes)
  468         {
  469             ev->type = CACA_EVENT_KEY_PRESS;
  470             ev->data.key.ch = 0;
  471             ev->data.key.utf32 = utf32;
  472             strcpy(ev->data.key.utf8, utf8);
  473             return 1;
  474         }
  475     }
  476 
  477     if(intkey == KEY_MOUSE)
  478     {
  479         MEVENT mevent;
  480         getmouse(&mevent);
  481 
  482         switch(mevent.bstate)
  483         {
  484 #define PRESS(x) ev->data.mouse.button = x; \
  485                  ev->type = CACA_EVENT_MOUSE_PRESS; _push_event(dp, ev)
  486 #define RELEASE(x) ev->data.mouse.button = x; \
  487                    ev->type = CACA_EVENT_MOUSE_RELEASE; _push_event(dp, ev)
  488 #define CLICK(x) PRESS(x); RELEASE(x)
  489             case BUTTON1_PRESSED: PRESS(1); break;
  490             case BUTTON1_RELEASED: RELEASE(1); break;
  491             case BUTTON1_CLICKED: CLICK(1); break;
  492             case BUTTON1_DOUBLE_CLICKED: CLICK(1); CLICK(1); break;
  493             case BUTTON1_TRIPLE_CLICKED: CLICK(1); CLICK(1); CLICK(1); break;
  494 #if defined BUTTON1_RESERVED_EVENT
  495             case BUTTON1_RESERVED_EVENT: break;
  496 #endif
  497 
  498             case BUTTON2_PRESSED: PRESS(2); break;
  499             case BUTTON2_RELEASED: RELEASE(2); break;
  500             case BUTTON2_CLICKED: CLICK(2); break;
  501             case BUTTON2_DOUBLE_CLICKED: CLICK(2); CLICK(2); break;
  502             case BUTTON2_TRIPLE_CLICKED: CLICK(2); CLICK(2); CLICK(2); break;
  503 #if defined BUTTON2_RESERVED_EVENT
  504             case BUTTON2_RESERVED_EVENT: break;
  505 #endif
  506 
  507             case BUTTON3_PRESSED: PRESS(3); break;
  508             case BUTTON3_RELEASED: RELEASE(3); break;
  509             case BUTTON3_CLICKED: CLICK(3); break;
  510             case BUTTON3_DOUBLE_CLICKED: CLICK(3); CLICK(3); break;
  511             case BUTTON3_TRIPLE_CLICKED: CLICK(3); CLICK(3); CLICK(3); break;
  512 #if defined BUTTON3_RESERVED_EVENT
  513             case BUTTON3_RESERVED_EVENT: break;
  514 #endif
  515 
  516             case BUTTON4_PRESSED: PRESS(4); break;
  517             case BUTTON4_RELEASED: RELEASE(4); break;
  518             case BUTTON4_CLICKED: CLICK(4); break;
  519             case BUTTON4_DOUBLE_CLICKED: CLICK(4); CLICK(4); break;
  520             case BUTTON4_TRIPLE_CLICKED: CLICK(4); CLICK(4); CLICK(4); break;
  521 #if defined BUTTON4_RESERVED_EVENT
  522             case BUTTON4_RESERVED_EVENT: break;
  523 #endif
  524 
  525             default:
  526                 break;
  527 #undef PRESS
  528 #undef RELEASE
  529 #undef CLICK
  530         }
  531 
  532         if(dp->mouse.x == mevent.x && dp->mouse.y == mevent.y)
  533             return _pop_event(dp, ev);
  534 
  535         dp->mouse.x = mevent.x;
  536         dp->mouse.y = mevent.y;
  537 
  538         ev->type = CACA_EVENT_MOUSE_MOTION;
  539         ev->data.mouse.x = dp->mouse.x;
  540         ev->data.mouse.y = dp->mouse.y;
  541         return 1;
  542     }
  543 
  544     switch(intkey)
  545     {
  546         case KEY_UP: ev->data.key.ch = CACA_KEY_UP; break;
  547         case KEY_DOWN: ev->data.key.ch = CACA_KEY_DOWN; break;
  548         case KEY_LEFT: ev->data.key.ch = CACA_KEY_LEFT; break;
  549         case KEY_RIGHT: ev->data.key.ch = CACA_KEY_RIGHT; break;
  550 
  551         case KEY_IC: ev->data.key.ch = CACA_KEY_INSERT; break;
  552         case KEY_DC: ev->data.key.ch = CACA_KEY_DELETE; break;
  553         case 0x7f:
  554         case KEY_BACKSPACE: ev->data.key.ch = CACA_KEY_BACKSPACE; break;
  555         case KEY_HOME: ev->data.key.ch = CACA_KEY_HOME; break;
  556         case KEY_END: ev->data.key.ch = CACA_KEY_END; break;
  557         case KEY_PPAGE: ev->data.key.ch = CACA_KEY_PAGEUP; break;
  558         case KEY_NPAGE: ev->data.key.ch = CACA_KEY_PAGEDOWN; break;
  559 
  560         case KEY_F(1): ev->data.key.ch = CACA_KEY_F1; break;
  561         case KEY_F(2): ev->data.key.ch = CACA_KEY_F2; break;
  562         case KEY_F(3): ev->data.key.ch = CACA_KEY_F3; break;
  563         case KEY_F(4): ev->data.key.ch = CACA_KEY_F4; break;
  564         case KEY_F(5): ev->data.key.ch = CACA_KEY_F5; break;
  565         case KEY_F(6): ev->data.key.ch = CACA_KEY_F6; break;
  566         case KEY_F(7): ev->data.key.ch = CACA_KEY_F7; break;
  567         case KEY_F(8): ev->data.key.ch = CACA_KEY_F8; break;
  568         case KEY_F(9): ev->data.key.ch = CACA_KEY_F9; break;
  569         case KEY_F(10): ev->data.key.ch = CACA_KEY_F10; break;
  570         case KEY_F(11): ev->data.key.ch = CACA_KEY_F11; break;
  571         case KEY_F(12): ev->data.key.ch = CACA_KEY_F12; break;
  572 
  573         default:
  574             /* Unknown key */
  575             ev->type = CACA_EVENT_NONE; return 0;
  576     }
  577 
  578     ev->type = CACA_EVENT_KEY_PRESS;
  579     ev->data.key.utf32 = 0;
  580     ev->data.key.utf8[0] = '\0';
  581     return 1;
  582 }
  583 
  584 static void ncurses_set_cursor(caca_display_t *dp, int flags)
  585 {
  586     if (!flags)
  587         curs_set(0);
  588     else if (curs_set(2) == ERR)
  589         curs_set(1);
  590 }
  591 
  592 /*
  593  * XXX: following functions are local
  594  */
  595 
  596 #if defined HAVE_SIGNAL
  597 static void sigwinch_handler(int sig)
  598 {
  599     sigwinch_d->resize.resized = 1;
  600 
  601     signal(SIGWINCH, sigwinch_handler);
  602 }
  603 #endif
  604 
  605 #if defined HAVE_GETENV && defined HAVE_PUTENV
  606 static void ncurses_install_terminal(caca_display_t *dp)
  607 {
  608     char *term, *colorterm;
  609 
  610     dp->drv.p->term = NULL;
  611 
  612     term = getenv("TERM");
  613     colorterm = getenv("COLORTERM");
  614 
  615     if(!term || strcmp(term, "xterm"))
  616         return;
  617 
  618     /* If we are using gnome-terminal, it's really a 16 colour terminal.
  619      * Ditto if we are using xfce4-terminal, or Konsole. */
  620     if((colorterm && (!strcmp(colorterm, "gnome-terminal")
  621                        || !strcmp(colorterm, "Terminal")))
  622          || getenv("KONSOLE_DCOP_SESSION"))
  623     {
  624         SCREEN *screen;
  625         screen = newterm("xterm-16color", stdout, stdin);
  626         if(screen == NULL)
  627             return;
  628         endwin();
  629         (void)putenv("TERM=xterm-16color");
  630         dp->drv.p->term = strdup(term);
  631         return;
  632     }
  633 }
  634 
  635 static void ncurses_uninstall_terminal(caca_display_t *dp)
  636 {
  637     /* Needs to be persistent because we use putenv() */
  638     static char termenv[1024];
  639 
  640     if(!dp->drv.p->term)
  641         return;
  642 
  643     snprintf(termenv, 1023, "TERM=%s", dp->drv.p->term);
  644     free(dp->drv.p->term);
  645     (void)putenv(termenv);
  646 }
  647 #endif
  648 
  649 static void ncurses_write_utf32(uint32_t ch)
  650 {
  651 #if defined HAVE_NCURSESW_NCURSES_H
  652     char buf[10];
  653     int bytes;
  654 #endif
  655 
  656     if(ch == CACA_MAGIC_FULLWIDTH)
  657         return;
  658 
  659 #if defined HAVE_NCURSESW_NCURSES_H
  660     bytes = caca_utf32_to_utf8(buf, ch);
  661     buf[bytes] = '\0';
  662     addstr(buf);
  663 #else
  664     if(ch < 0x80)
  665     {
  666         addch(ch);
  667     }
  668     else
  669     {
  670         chtype cch;
  671         chtype cch2;
  672 
  673         cch = '?';
  674         cch2 = ' ';
  675         if ((ch > 0x0000ff00) && (ch < 0x0000ff5f))
  676         {
  677             cch = ch - 0x0000ff00 + ' ';
  678         }
  679         switch (ch)
  680         {
  681         case 0x000000a0: /* <nbsp> */
  682         case 0x00003000: /*   */
  683             cch = ' ';
  684             break;
  685         case 0x000000a3: /* £ */
  686             cch = ACS_STERLING;
  687             break;
  688         case 0x000000b0: /* ° */
  689             cch = ACS_DEGREE;
  690             break;
  691         case 0x000000b1: /* ± */
  692             cch = ACS_PLMINUS;
  693             break;
  694         case 0x000000b7: /* · */
  695         case 0x00002219: /* ∙ */
  696         case 0x000030fb: /* ・ */
  697             cch = ACS_BULLET;
  698             break;
  699         case 0x000003c0: /* π */
  700             cch = ACS_PI;
  701             break;
  702         case 0x00002018: /* ‘ */
  703         case 0x00002019: /* ’ */
  704             cch = '\'';
  705             break;
  706         case 0x0000201c: /* “ */
  707         case 0x0000201d: /* ” */
  708             cch = '"';
  709             break;
  710         case 0x00002190: /* ← */
  711             cch = ACS_LARROW;
  712             break;
  713         case 0x00002191: /* ↑ */
  714             cch = ACS_UARROW;
  715             break;
  716         case 0x00002192: /* → */
  717             cch = ACS_RARROW;
  718             break;
  719         case 0x00002193: /* ↓ */
  720             cch = ACS_DARROW;
  721             break;
  722         case 0x00002260: /* ≠ */
  723             cch = ACS_NEQUAL;
  724             break;
  725         case 0x00002261: /* ≡ */
  726             cch = '=';
  727             break;
  728         case 0x00002264: /* ≤ */
  729             cch = ACS_LEQUAL;
  730             break;
  731         case 0x00002265: /* ≥ */
  732             cch = ACS_GEQUAL;
  733             break;
  734         case 0x000023ba: /* ⎺ */
  735             cch = ACS_S1;
  736             cch2 = cch;
  737             break;
  738         case 0x000023bb: /* ⎻ */
  739             cch = ACS_S3;
  740             cch2 = cch;
  741             break;
  742         case 0x000023bc: /* ⎼ */
  743             cch = ACS_S7;
  744             cch2 = cch;
  745             break;
  746         case 0x000023bd: /* ⎽ */
  747             cch = ACS_S9;
  748             cch2 = cch;
  749             break;
  750         case 0x00002500: /* ─ */
  751         case 0x00002550: /* ═ */
  752             cch = ACS_HLINE;
  753             cch2 = cch;
  754             break;
  755         case 0x00002502: /* │ */
  756         case 0x00002551: /* ║ */
  757             cch = ACS_VLINE;
  758             break;
  759         case 0x0000250c: /* ┌ */
  760         case 0x00002552: /* ╒ */
  761         case 0x00002553: /* ╓ */
  762         case 0x00002554: /* ╔ */
  763             cch = ACS_ULCORNER;
  764             cch2 = ACS_HLINE;
  765             break;
  766         case 0x00002510: /* ┐ */
  767         case 0x00002555: /* ╕ */
  768         case 0x00002556: /* ╖ */
  769         case 0x00002557: /* ╗ */
  770             cch = ACS_URCORNER;
  771             break;
  772         case 0x00002514: /* └ */
  773         case 0x00002558: /* ╘ */
  774         case 0x00002559: /* ╙ */
  775         case 0x0000255a: /* ╚ */
  776             cch = ACS_LLCORNER;
  777             cch2 = ACS_HLINE;
  778             break;
  779         case 0x00002518: /* ┘ */
  780         case 0x0000255b: /* ╛ */
  781         case 0x0000255c: /* ╜ */
  782         case 0x0000255d: /* ╝ */
  783             cch = ACS_LRCORNER;
  784             break;
  785         case 0x0000251c: /* ├ */
  786         case 0x0000255e: /* ╞ */
  787         case 0x0000255f: /* ╟ */
  788         case 0x00002560: /* ╠ */
  789             cch = ACS_LTEE;
  790             cch2 = ACS_HLINE;
  791             break;
  792         case 0x00002524: /* ┤ */
  793         case 0x00002561: /* ╡ */
  794         case 0x00002562: /* ╢ */
  795         case 0x00002563: /* ╣ */
  796             cch = ACS_RTEE;
  797             break;
  798         case 0x0000252c: /* ┬ */
  799         case 0x00002564: /* ╤ */
  800         case 0x00002565: /* ╥ */
  801         case 0x00002566: /* ╦ */
  802             cch = ACS_TTEE;
  803             cch2 = ACS_HLINE;
  804             break;
  805         case 0x00002534: /* ┴ */
  806         case 0x00002567: /* ╧ */
  807         case 0x00002568: /* ╨ */
  808         case 0x00002569: /* ╩ */
  809             cch = ACS_BTEE;
  810             cch2 = ACS_HLINE;
  811             break;
  812         case 0x0000253c: /* ┼ */
  813         case 0x0000256a: /* ╪ */
  814         case 0x0000256b: /* ╫ */
  815         case 0x0000256c: /* ╬ */
  816             cch = ACS_PLUS;
  817             cch2 = ACS_HLINE;
  818             break;
  819         case 0x00002591: /* ░ */
  820             cch = ACS_BOARD;
  821             cch2 = cch;
  822             break;
  823         case 0x00002592: /* ▒ */
  824         case 0x00002593: /* ▓ */
  825             cch = ACS_CKBOARD;
  826             cch2 = cch;
  827             break;
  828         case 0x00002580: /* ▀ */
  829         case 0x00002584: /* ▄ */
  830         case 0x00002588: /* █ */
  831         case 0x0000258c: /* ▌ */
  832         case 0x00002590: /* ▐ */
  833         case 0x000025a0: /* ■ */
  834         case 0x000025ac: /* ▬ */
  835         case 0x000025ae: /* ▮ */
  836             cch = ACS_BLOCK;
  837             cch2 = cch;
  838             break;
  839         case 0x000025c6: /* ◆ */
  840         case 0x00002666: /* ♦ */
  841             cch = ACS_DIAMOND;
  842             break;
  843         case 0x00002022: /* • */
  844         case 0x000025cb: /* ○ */
  845         case 0x000025cf: /* ● */
  846         case 0x00002603: /* ☃ */
  847         case 0x0000263c: /* ☼ */
  848             cch = ACS_LANTERN;
  849             break;
  850         case 0x0000301c: /* 〜 */
  851             cch = '~';
  852             break;
  853         }
  854         addch(cch);
  855         if(caca_utf32_is_fullwidth(ch))
  856         {
  857             addch(cch2);
  858         }
  859     }
  860 #endif
  861 }
  862 
  863 /*
  864  * Driver initialisation
  865  */
  866 
  867 int ncurses_install(caca_display_t *dp)
  868 {
  869     dp->drv.id = CACA_DRIVER_NCURSES;
  870     dp->drv.driver = "ncurses";
  871 
  872     dp->drv.init_graphics = ncurses_init_graphics;
  873     dp->drv.end_graphics = ncurses_end_graphics;
  874     dp->drv.set_display_title = ncurses_set_display_title;
  875     dp->drv.get_display_width = ncurses_get_display_width;
  876     dp->drv.get_display_height = ncurses_get_display_height;
  877     dp->drv.display = ncurses_display;
  878     dp->drv.handle_resize = ncurses_handle_resize;
  879     dp->drv.get_event = ncurses_get_event;
  880     dp->drv.set_mouse = NULL;
  881     dp->drv.set_cursor = ncurses_set_cursor;
  882 
  883     return 0;
  884 }
  885 
  886 #endif /* USE_NCURSES */
  887